class Demiurge::ActionItem

A Demiurge::ActionItem keeps track of actions from Ruby code blocks and implements the Demiurge DSL for action code, including inside World Files.

@since 0.0.1

Constants

Legal keys to pass to ActionItem#register_actions' hash @since 0.0.1

Public Class Methods

new(name, engine, state) click to toggle source

Constructor. Set up ActionItem-specific things like EveryXTicks actions.

@param name [String] The registered StateItem name @param engine [Demiurge::Engine] The Engine this item is part of @param state [Hash] The state hash for this item @return [void] @since 0.0.1

Calls superclass method Demiurge::StateItem::new
# File lib/demiurge/action_item.rb, line 15
def initialize(name, engine, state)
  super # Set @name and @engine and @state
  @every_x_ticks_intention = ActionItemInternal::EveryXTicksIntention.new(engine, name)
  nil
end

Public Instance Methods

__state_internal() click to toggle source

An internal function that provides the object's internal state to an action block via a Runner class.

@return [Hash] The internal state of this item for use in DSL action blocks @api private @since 0.0.1

# File lib/demiurge/action_item.rb, line 88
def __state_internal
  @state
end
finished_init() click to toggle source

Callback to be called from the Engine when all items are loaded.

@return [void] @since 0.0.1

# File lib/demiurge/action_item.rb, line 25
def finished_init
  loc = self.location
  loc.move_item_inside(self) unless loc.nil?
  nil
end
get_action(action_name) click to toggle source

Get the action hash structure for a given action name. This is normally done to verify that a specific action name exists at all.

@param action_name [String] The action name to query @return [Hash, nil] A hash of information about the action, or nil if the action doesn't exist @since 0.0.1

# File lib/demiurge/action_item.rb, line 181
def get_action(action_name)
  action = @engine.action_for_item(@name, action_name)
  if !action && state["parent"]
    # Do we have a parent and no action definition yet? If so, defer to the parent.
    action = @engine.item_by_name(state["parent"]).get_action(action_name)
  end
  action
end
get_actions_with_tags(tags) click to toggle source

Return all actions which have the given String tags specified for them.

@param tags [Array<String>] An array of tags the returned actions should match @return [Array<Hash>] An array of action structures. The “name” field of each gives the action name @since 0.0.1

# File lib/demiurge/action_item.rb, line 195
def get_actions_with_tags(tags)
  tags = [tags].flatten # Allow calling with a single tag string
  @actions = []
  @engine.actions_for_item(@name).each do |action_name, action_struct|
    # I'm sure there's some more clever way to check if the action contains all these tags...
    if (tags - (action_struct["tags"] || [])).empty?
      @actions.push action_struct
    end
  end
  @actions
end
intentions_for_next_step() click to toggle source

Get this item's intentions for the next tick.

@return [Array<Demiurge::Intention>] An array of intentions for next tick @since 0.0.1

# File lib/demiurge/action_item.rb, line 96
def intentions_for_next_step
  everies = @state["everies"]
  return [] if everies.nil? || everies.empty?
  [@every_x_ticks_intention]
end
location() click to toggle source

Get the location StateItem where this item is located.

@return [Demiurge::StateItem, nil] The location's StateItem, or nil if this item has no location @since 0.0.1

# File lib/demiurge/action_item.rb, line 46
def location
  ln = location_name
  return nil if ln == "" || ln == nil
  @engine.item_by_name(location_name)
end
location_name() click to toggle source

Get the name of this item's location. This is compatible with complex positions, and removes any sub-location suffix, if there is one.

@return [String, nil] The location name where this item exists, or nil if it has no location @since 0.0.1

# File lib/demiurge/action_item.rb, line 37
def location_name
  pos = @state["position"]
  pos ? pos.split("#",2)[0] : nil
end
position() click to toggle source

A Position can be simply a location (“here's a room-type object and you're in it”) or something more specific, such as a specific coordinate within a room. In general, a Position consists of a location's unique item name, optionally followed by an optional pound sign (“#”) and zone-specific additional coordinates.

@return [String, nil] This item's position, or nil if it has no location.

# File lib/demiurge/action_item.rb, line 60
def position
  @state["position"]
end
register_actions(action_hash) click to toggle source

This method is called by (among other things) define_action to specify things about an action. It's how to specify the action's code, how busy it makes an agent when it occurs, what Runner to use with it, and any appropriate String tags. While it can be called multiple times to specify different things about a single action, it must not be called with the same information. So the block can only be specified once, “busy” can only be specified once and so on.

This means that if an action's block is given implicitly by something like an every_X_ticks declaration, it can use define_action to set “busy” or “engine_code”. But it can't define a different block of code to run with define_action.

@param action_hash [Hash] Specify something or everything about an action by its name. @option action_hash [String] name The name of the action, which is required. @option action_hash [Proc] block The block of code for the action itself @return void @since 0.0.1

# File lib/demiurge/action_item.rb, line 125
def register_actions(action_hash)
  @engine.register_actions_by_item_and_action_name(@name => action_hash)
end
run_action(action_name, *args, current_intention: nil) click to toggle source

This is a raw, low-level way to execute an action of an ActionItem. It doesn't wait for Intentions. It doesn't send extra notifications. It doesn't offer or give a chance to cancel the action. It just runs.

@param action_name [String] The name of the action to run. Must already be registered. @param args [Array] Additional arguments to pass to the action's code block @param current_intention [nil, Intention] Current intention being executed, if any. This is used for to cancel an intention, if necessary @return [void] @since 0.0.1

# File lib/demiurge/action_item.rb, line 139
def run_action(action_name, *args, current_intention: nil)
  action = get_action(action_name)
  raise ::Demiurge::Errors::NoSuchActionError.new("No such action as #{action_name.inspect} for #{@name.inspect}!",
                                                  "item" => self.name, "action" => action_name,
                                                  execution_context: @engine.execution_context) unless action
  block = action["block"]
  raise ::Demiurge::Errors::NoSuchActionError.new("Action was never defined for #{action_name.inspect} of object #{@name.inspect}!",
                                                  "item" => self.name, "action" => action_name,
                                                  execution_context: @engine.execution_context) unless block

  runner_constructor_args = {}
  if action["engine_code"]
    block_runner_type = ActionItemInternal::EngineBlockRunner
  elsif self.agent?
    block_runner_type = ActionItemInternal::AgentBlockRunner
    runner_constructor_args[:current_intention] = current_intention
  else
    block_runner_type = ActionItemInternal::ActionItemBlockRunner
    runner_constructor_args[:current_intention] = current_intention
  end
  # TODO: can we save block runners between actions?
  block_runner = block_runner_type.new(self, **runner_constructor_args)
  begin
    @engine.push_context("running_action" => action_name, "running_action_item" => @name) do
      block_runner.instance_exec(*args, &block)
    end
  rescue
    #STDERR.puts "#{$!.message}\n#{$!.backtrace.join("\n")}"
    raise ::Demiurge::Errors::BadScriptError.new("Script error of type #{$!.class} with message: #{$!.message}",
                                                 { "runner type": block_runner_type.to_s, "action" => action_name, },
                                                 execution_context: @engine.execution_context);
  end
  nil
end
zone() click to toggle source

Get the StateItem of the Zone where this item is located. This may be different from its “home” Zone.

@return [StateItem, nil] This item's Zone's StateItem, or nil in the very unusual case that it has no current Zone.

# File lib/demiurge/action_item.rb, line 68
def zone
  zn = zone_name
  zn ? @engine.item_by_name(zn) : nil
end
zone_name() click to toggle source

Get the Zone name for this StateItem's current location, which may be different from its “home” Zone.

@return [String, nil] This item's Zone's name, or nil in the very unusual case that it has no current Zone.

# File lib/demiurge/action_item.rb, line 77
def zone_name
  l = location
  l ? l.zone_name : state["zone"]
end