lib/gamefic/active.rb in gamefic-3.0.0 vs lib/gamefic/active.rb in gamefic-3.1.0

- old
+ new

@@ -19,10 +19,13 @@ # turn. # # @return [Active::Cue, nil] attr_reader :next_cue + # @return [String, nil] + attr_reader :last_input + # @return [Symbol, nil] def next_scene next_cue&.scene end @@ -46,32 +49,41 @@ # @return [Array<String>] def queue @queue ||= [] end - # A hash of data that will be sent to the user. The output is typically - # sent after a scene has started and before the user is prompted for input. + # Data that will be sent to the user. The output is typically sent after a + # scene has started and before the user is prompted for input. # - # @return [Hash] + # The output object attached to the actor is always frozen. Authors should + # use on_player_output blocks to modify output to be sent to the user. + # + # @return [Props::Output] def output - @output ||= {} + @output ||= Props::Output.new.freeze end + # The output from the previous turn. + # + # @return [Props::Output] + def last_output + @last_output ||= output + end + # Perform a command. # # The command's action will be executed immediately, regardless of the # entity's state. # # @example Send a command as a string # character.perform "take the key" # # @param command [String] - # @return [void] + # @return [Action, nil] def perform(command) dispatchers.push Dispatcher.dispatch(self, command) - dispatchers.last.execute - dispatchers.pop + dispatchers.last.execute.tap { dispatchers.pop } end # Quietly perform a command. # This method executes the command exactly as #perform does, except it # buffers the resulting output instead of sending it to messages. @@ -93,15 +105,14 @@ # @example # character.execute :take, @key # # @param verb [Symbol] # @param params [Array] - # @return [Gamefic::Action] + # @return [Action, nil] def execute(verb, *params) dispatchers.push Dispatcher.dispatch_from_params(self, verb, params) - dispatchers.last.execute - dispatchers.pop + dispatchers.last.execute.tap { dispatchers.pop } end # Proceed to the next Action in the current stack. # This method is typically used in Action blocks to cascade through # multiple implementations of the same verb. @@ -123,13 +134,13 @@ # else # actor.proceed # Execute the previous implementation # end # end # - # @return [void] + # @return [Action, nil] def proceed - dispatchers.last&.proceed&.execute + dispatchers.last&.proceed end # Cue a scene to start in the next turn. # # @raise [ArgumentError] if the scene is not valid @@ -144,21 +155,26 @@ @next_cue = Cue.new(scene, **context) end alias prepare cue + # @return [void] def start_take ensure_cue @last_cue = @next_cue cue :default_scene @props = Take.start(self, @last_cue) + @last_output = self.output + @output = @props.output.dup.freeze end + # @return [void] def finish_take return unless @last_cue Take.finish(self, @last_cue, @props) + @last_input = @props.input end # Restart the scene from the most recent cue. # # @return [Cue, nil] @@ -173,10 +189,11 @@ # # @raise [ArgumentError] if the requested scene is not a conclusion # # @param new_scene [Symbol] # @oaram context [Hash] Additional scene data + # @return [Cue] def conclude scene, **context cue scene, **context available = epic.select_scene(scene) raise ArgumentError, "`#{scene}` is not a conclusion" unless available.conclusion? @@ -184,10 +201,10 @@ end # True if the actor is ready to leave the game. # def concluding? - epic.empty? || (@last_cue && epic.conclusion?(@last_cue.scene)) + epic.empty? || @props&.scene&.type == 'Conclusion' end def accessible? false end