All Entity objects can use their GoalManager to allow high-level AI features.
Movement related features in the GoalManager require that the Entity has a StandardBase brain added.
For each goal that starts with Add, there is also a version starting with Push.
this:GetGoalManager():AddSay("Happy birthday...", C_FACING_NONE);
this:GetGoalManager():AddSay("..to you.", C_FACING_NONE);
//if we stopped now, it would sing these.
//Let's use Push to move something to the top of the stack, to happen before everything that is already there.
this:GetGoalManager():PushSay("I will now sing a song for you.", C_FACING_NONE);
In this example, the character would first say “I will sing a song for you”, and then would sing the song.
Internally, every sub goal added is actually a GoalManager that allows more goals to be added ‘under’ it.
A hierarchical tree of goals can be created.
Complex sub goals like AddApproach may create their own sub-goals to complete what is required.
In many cases it makes sense to add, track, and remove goals as a named group of actions, AddNewGoal (or PushNewGoal) allows you to do this by adding a custom named dummy goal designed to hold others.
Activate “Display->Show Entity Goal And AI Data” from the main editor menu to see the Goal hierarchy in real-time as the game is played.
The goal in yellow text “has focus”.
nil AddDelay(number delayMS)
Waits the specified amount of time before continuing to the next action/goal.
If this action is interrupted, the amount of time waited is saved, and continued when it is resumed.
delayMS | How long we should wait, in milliseconds. (1000 = one second) |
nil AddMoveToPosition(Map map, Vector2 vPos)
Causes the Entity to move to the specified map and position using the pathfinding system.
If there is no door/warp to get to the specified Map, this will fail.
map | a Map object of the map we want to be on. |
vPos | A Vector2 object containing the location to move to. |
nil AddApproach(number entityID, number distance)
Causes the owner Entity to move to (or near) the position of the entity ID sent using the pathfinding system.
Will go through doors, around obstacles as needed.
When a distance is set, the Entity will locate a position with a line-of-sight to the target the requested distance away, perfect for getting ready to talk to things/characters.
entityID | an ID of an existing entity anywhere in the world. |
distance | How far we want to stand from the target. Use a number, or one of the C_DISTANCE_CONSTANTS. |
nil AddApproachAndSay(string msg, number entityID, number distance)
Like AddApproach but also says a line of text, while facing the entityID sent.
//walk through doors, through mazes, wherever the entity named Tad is, face him and say hi.
this:GetGoalManager():AddApproachAndSay("Hi Tad.", GetEntityIDByName("Tad"), C_DISTANCE_TALK);
msg | What the Entity should say. (internally, the TextManager is used to say it) |
entityID | An ID of an existing entity anywhere in the world. |
distance | How far we want to stand from the target. Use a number, or one of the C_DISTANCE_CONSTANTS. |
nil AddSay(string msg, number entToFaceID, (optional) number delayMS)
Causes the owner Entity to say something, while looking a certain direction.
//Say "Where is Jim" without changing our direction
this:GetGoalManager():AndSay("Where is Jim?", C_FACING_NONE);
//Look to the north
this:GetGoalManager():AndSay("Hello, north", C_FACING_UP);
//Look to the south
this:GetGoalManager():AndSay("Hello, south", C_FACING_DOWN);
//Look at wherever Jim is, and make the text stay on screen for 10 seconds with
//the optional delayMS parm
this:GetGoalManager():AndSay("Hello, Jiiiiim!", entityIDForJim, 10000);
msg | What the Entity should say. (internally, the TextManager is used to say it) |
entToFaceID | an entityID, or one of the C_FACING_CONSTANTS. |
delayMS | (optional) If specified, this sets how long the text should stay on the screen. (normally, the TextManager decides, based on length) |
nil AddSayByID(string msg, number entityIDToTalk, number entToFaceID, (optional) number delayMS)
Like AddSay but lets you specify which Entity talks instead of assuming it’s the owner entity. This is useful to orchestrate complex conversations with only one GoalManager controlling everything.
//make a conversation with three people happen using only one guy's GoalManager
local gandolfID = GetEntityIDByName("Gandolf")
local frodoID = GetEntityIDByName("Frodo")
local legolasID = this:GetID(); //let's assume this entity is Legolas, although it could be any other
//make gandolf speak to Legolas
this:GetGoalManager():AndSayByID("NEVER do that again.", gandolfID, legolasID);
//legolas replies to gandalf
this:GetGoalManager():AndSayByID("What are you talking about? Do what?!", legolasID, gandolfID);
//make frodo speak to Legolas
this:GetGoalManager():AndSayByID(
"He's talking about using that shield as a damn surfboard! Ruined the movie!", frodoID, legolasID);
msg | What the Entity should say. (internally, the TextManager is used to say it) |
entToFaceID | an entityID, or one of the C_FACING_CONSTANTS. |
delayMS | (optional) If specified, this sets how long the text should stay on the screen. (normally, the TextManager decides, based on length) |
nil AddRunScriptString(string msg)
This lets you run any piece of lua code in owner Entity’s namespace.
You can use it to call a function, change a variable, or anything else.
The string is not parsed until the time of execution.
//run this Entity's function called "WonderAround()"
this:GetGoalManager():AddRunScriptString("WonderAround()");
//Change our name, notice to use quotes inside the quotes, we have to use \".
local someText = "this:SetName(\"Dillweed\");";
//let's change our color too
someText = someText + "this:SetBaseColor(Color(255,0,0,255));";
//actually send the string to the goal manager
this:GetGoalManager():AddRunScriptString(someText);
msg | The lua string you want to run. As always, no size limits. |
GoalManager AddNewGoal(string goalName)
Adds a new subgoal with the desired name and returns a handle to the created goal, allowing you to populate it. Think of goal as an empty folder that is ready to handle more commands/goals.
When a goal has “focus” it will run all items in it sequentially until empty, then delete itself, unless it is the “Base”.
//create a new goal. If we wanted to interrupts what they are doing now, we should
//use PushNewGoal instead of AddNewGoal.
local goal = this:GetGoalManager():AddNewGoal("CleanPlayerBed");
//look at the player while telling him we'll do it
goal:AddSay("Fine, I'll go clean the bad.", g_playerID);
//figure out the entity ID of the bed we want to clean
local bedID = GetEntityIDByName("Hol_Inn_BedPlayer");
//walk up to the bed, and say we're cleaning
goal:AddApproachAndSay("<cleaning>",bedID , C_DISTANCE_CLOSE);
goalName | The name you’d like the new goal to have, can be anything. “Kill Tad” or “GetFoodAndEat” for instance. This name will show up in the game when “Show goal info” is activated. |
A GoalManager connected to the new goal.
nil RemoveAllSubgoals()
Deletes all goals and subgoals under this GoalManager.
This will cause it to delete itself, unless it is the “Base” GoalManager of this entity.
boolean IsGoalActiveByName(string goalName)
goalName | The name of the goal you probably added with AddNewGoal or PushNewGoal. |
True if a goal by this name exists somewhere in the hierarchy of this GoalManager.
GoalManager GetActiveGoal()
Returns the GoalManager object connected to the active goal. If nil, no goal is currently active. (Ie, the base is the only thing active)
A GoalManager of the active goal or nil if no goal is active.
number GetGoalCountByName()
goalName | The name of a goal(s) you probably added with AddNewGoal or PushNewGoal. |
The number of Goals with this name under this GoalManager.
GoalManager GetGoalByName(string goalName)
Allows you to grab a goal object by name.
A GoalManager of the goal with this name, or nil if nothing is found.