lib/gamefic/plot.rb in gamefic-1.7.0 vs lib/gamefic/plot.rb in gamefic-2.0.0

- old
+ new

@@ -1,133 +1,113 @@ -require 'gamefic/tester' -require 'gamefic/source' -require 'gamefic/script' require 'gamefic/query' module Gamefic - + # A plot controls the game narrative and manages the world model. + # Authors typically build plots through scripts that are executed in a + # special container called a stage. All of the elements that compose the + # narrative (characters, locations, scenes, etc.) reside in the stage's + # scope. Game engines use the plot to receive game data and process user + # input. + # class Plot - autoload :Scenes, 'gamefic/plot/scenes' - autoload :Commands, 'gamefic/plot/commands' - autoload :Entities, 'gamefic/plot/entities' - autoload :Articles, 'gamefic/plot/articles' - autoload :YouMount, 'gamefic/plot/you_mount' autoload :Snapshot, 'gamefic/plot/snapshot' autoload :Darkroom, 'gamefic/plot/darkroom' autoload :Host, 'gamefic/plot/host' - autoload :Players, 'gamefic/plot/players' - autoload :Playbook, 'gamefic/plot/playbook' - autoload :Callbacks, 'gamefic/plot/callbacks' - autoload :Theater, 'gamefic/plot/theater' - attr_reader :commands, :imported_scripts, :source + # @return [Hash] + attr_reader :metadata - # TODO: Metadata could use better protection - attr_accessor :metadata - include Theater - include Gamefic, Tester, Players, Scenes, Commands, Entities - include Articles, YouMount, Snapshot, Host, Callbacks + include World + include Scriptable + # @!parse extend Scriptable::ClassMethods + include Snapshot + include Host - # @param source [Source::Base] - def initialize(source = nil) - @source = source || Source::Text.new({}) - @working_scripts = [] - @imported_scripts = [] - @running = false - post_initialize + # @param structure [Gamefic::Structure] + # @param metadata [Hash] + def initialize metadata: {} + Gamefic::Index.clear + @metadata = metadata + run_scripts + mark_static_entities + Gamefic::Index.stick end def player_class cls = nil @player_class = cls unless cls.nil? - @player_class + @player_class ||= Gamefic::Actor end - # @return [Gamefic::Plot::Playbook] - def playbook - @playbook ||= Gamefic::Plot::Playbook.new - end - - def running? - @running - end - - # Get an Array of all scripts that have been imported into the Plot. - # - # @return [Array<Script>] The imported scripts - def imported_scripts - @imported_scripts ||= [] - end - - def post_initialize - # TODO: Should this method be required by extended classes? - end - # Get an Array of the Plot's current Syntaxes. # # @return [Array<Syntax>] def syntaxes playbook.syntaxes end - + # Prepare the Plot for the next turn of gameplay. - # This method is typically called by the Engine that manages game execution. + # This method is typically called by the Engine that manages game + # execution. + # def ready playbook.freeze - @running = true - # Call the initial state to make sure it's set - initial_state call_ready call_player_ready - p_subplots.each { |s| s.ready } + subplots.each { |s| s.ready } + players.each do |p| + p.state.replace( + p.scene.state + .merge({ + messages: p.messages, + last_prompt: p.last_prompt, + last_input: p.last_input + }) + .merge(p.state) + ) + p.output.replace(p.state) + p.state.clear + end end - + # Update the Plot's current turn of gameplay. - # This method is typically called by the Engine that manages game execution. + # This method is typically called by the Engine that manages game + # execution. + # def update entities.each { |e| e.flush } call_before_player_update - p_players.each { |p| + players.each do |p| p.performed nil + next unless p.scene + p.last_input = p.queue.last + p.last_prompt = p.scene.prompt p.scene.update - } - p_entities.each { |e| e.update } + if p.scene.is_a?(Scene::Conclusion) + player_conclude_procs.each do |proc| + proc.call p + end + end + end call_player_update call_update - p_subplots.each { |s| s.update unless s.concluded? } - p_subplots.delete_if { |s| s.concluded? } + subplots.each { |s| s.update unless s.concluded? } + subplots.delete_if { |s| s.concluded? } end - def tell entities, message, refresh = false + # Send a message to a group of entities. + # + # @param entities [Array<Entity>] + # @param message [String] + def tell entities, message entities.each { |entity| - entity.tell message, refresh + entity.tell message } end - - # Load a script into the current Plot. - # This method is similar to Kernel#require, except that the script is - # evaluated within the Plot's context via #stage. - # - # @param path [String] The path to the script being evaluated - # @return [Boolean] true if the script was loaded by this call or false if it was already loaded. - def script path - imported_script = source.export(path) - if imported_script.nil? - raise LoadError.new("cannot load script -- #{path}") - end - if !@working_scripts.include?(imported_script) and !imported_scripts.include?(imported_script) - @working_scripts.push imported_script - # @hack Arguments need to be in different order if source returns proc - if imported_script.read.kind_of?(Proc) - stage &imported_script.read - else - stage imported_script.read, imported_script.absolute_path - end - @working_scripts.pop - imported_scripts.push imported_script - true - else - false - end - end end +end +module Gamefic + # @yieldself [Gamefic::Plot] + def self.script &block + Gamefic::Plot.script &block + end end