lib/gamefic/active/cue.rb
# frozen_string_literal: true module Gamefic module Active # The object that actors use to perform a scene. # class Cue # @return [Actor] attr_reader :actor # @return [Class<Scene::Base>, Symbol] attr_reader :key # @return [Narrative] attr_reader :narrative # @return [Hash] attr_reader :context # @return [Props::Default, nil] attr_reader :props # @param actor [Actor] # @param key [Class<Scene::Base>, Symbol] # @param narrative [Narrative] def initialize actor, key, narrative, **context @actor = actor @key = key @narrative = narrative @context = context end # @return [void] def start @props = scene.start prepare_output actor.rotate_cue end # @return [void] def finish props&.enter(actor.queue.shift&.strip) scene.finish end # @return [Props::Output] def output props&.output.clone.freeze || Props::Output::EMPTY end # @return [Cue] def restart Cue.new(actor, key, narrative, **context) end def type scene&.type end def to_s scene.to_s end # @return [void] def prepare props.output.merge!({ scene: scene.to_hash, prompt: props.prompt, messages: actor.flush, queue: actor.queue }) actor.narratives.player_output_blocks.each { |block| block.call actor, props.output } end # @return [Scene::Base] def scene # @note This method always returns a new instance. Scenes identified # by symbolic keys can be instances of anonymous classes that cannot # be serialized, so memoizing them breaks snapshots. narrative&.prepare(key, actor, props, **context) || try_unblocked_class || raise("Failed to cue #{key.inspect} in #{narrative.inspect}") end private # @return [Scene::Base] def try_unblocked_class return unless key.is_a?(Class) && key <= Scene::Base Gamefic.logger.warn "Cueing scene #{key} without narrative" unless narrative key.new(actor, narrative, props, **context) end # @return [void] def prepare_output props.output.last_input = actor.last_cue&.props&.input props.output.last_prompt = actor.last_cue&.props&.prompt end end end end