class Demiurge::Agent
Agents correspond roughly to “mobiles” in many games. An agent isn't particularly different from other Demiurge
objects, but it's useful to have some helper classes for things like pathfinding. Also, humans expect agents to have some finite ability to perform actions over time, so it's nice to regulate how much an agent can get done and how “busy” it is. This keeps an AI agent from just queueing up 30 move intentions and crossing the room in a single tick, for instance. It does not keep that same AI from having an intentional 30-square move that works in a single tick, but it slows the rate of actions. Agents get a single “real” intention, unlike, say, rooms, which can have lots going on at once.
@since 0.0.1
Public Class Methods
Demiurge::ActionItem::new
# File lib/demiurge/agent.rb, line 18 def initialize(*args) super state["queued_actions"] ||= [] state["queue_number"] ||= 0 end
Public Instance Methods
Any queued actions waiting to occur will be discarded.
@return [void] @since 0.0.1
# File lib/demiurge/agent.rb, line 103 def clear_intention_queue state.delete "queued_actions" nil end
Demiurge::ActionItem#finished_init
# File lib/demiurge/agent.rb, line 24 def finished_init super @agent_maintenance = AgentInternal::AgentMaintenanceIntention.new(engine, @name) state["busy"] ||= 0 # By default, start out idle. end
Calculate the agent's intentions for the following tick. These Intentions can potentially trigger other Intentions.
@return [Array<Intention>] The Intentions for the (first part of the) following tick. @since 0.0.1
Demiurge::ActionItem#intentions_for_next_step
# File lib/demiurge/agent.rb, line 77 def intentions_for_next_step agent_action = AgentInternal::AgentActionIntention.new(@name, engine) super + [@agent_maintenance, agent_action] end
This method will move the agent and notify about that change. It doesn't use an intention or an agent's action queue, and it doesn't wait for a tick to happen. It just does it. The method does handle exits and generally allows the location to respond. But it's assumed that the offer cycle, if it needs to happen, has happened already.
@param pos [String] A position string to move to @param options [Hash] A hash of how to do the movement; Demiurge
doesn't internally use this hash, but your World Files or display library may do so @return [void] @since 0.0.1
# File lib/demiurge/agent.rb, line 49 def move_to_position(pos, options = {}) old_pos = self.position old_loc = self.location_name old_zone_name = self.zone_name expected_new_loc = pos.split("#")[0] if expected_new_loc == old_loc self.location.item_change_position(self, old_pos, pos) else # This also handles zone changes. self.location.item_change_location(self, old_pos, pos) end # We're not guaranteed to wind up where we expected, so get the # new location *after* item_change_location or # item_change_position. new_loc = self.location_name @engine.send_notification({ old_position: old_pos, old_location: old_loc, new_position: self.position, new_location: new_loc }, type: Demiurge::Notifications::MoveFrom, zone: old_zone_name, location: old_loc, actor: @name, include_context: true) @engine.send_notification({ old_position: old_pos, old_location: old_loc, new_position: self.position, new_location: new_loc, options: options }, type: Demiurge::Notifications::MoveTo, zone: self.zone_name, location: self.location_name, actor: @name, include_context: true) end
Queue an action to be run after previous actions are complete, and when the agent is no longer busy from taking them. The action queue entry is assigned a unique-per-agent queue number, which is returned from this action.
@param action_name [String] The name of the action to take when possible @param args [Array] Additional arguments to pass to the action's code block @return [Integer] Returns the queue number for this action - note that queue numbers are only unique per-agent @since 0.0.1
# File lib/demiurge/agent.rb, line 91 def queue_action(action_name, *args) raise ::Demiurge::Errors::NoSuchActionError.new("Not an action: #{action_name.inspect}!", { "action_name" => action_name }, execution_context: @engine.execution_context) unless get_action(action_name) state["queue_number"] += 1 state["queued_actions"].push([action_name, args, state["queue_number"]]) state["queue_number"] end