Task: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
m (Added see also)
 
(16 intermediate revisions by 7 users not shown)
Line 1: Line 1:
A Task is a logical step in a [[Schedules|Schedule]], it can be seen as a sequential set of steps the NPC must take in order to accomplish a schedule.
{{npc tut}}
{{Seealso|For community tasks, see [[Valve Developer Community:Tasks]]}}


custom tasks may be added to your NPC by first declaring a new enum.
A '''Task''' is an action that an NPC can perform. [[Schedule]]s will run a list of tasks. Keep tasks as atomic as possible; don't squeeze two distinct actions into the same one.


<pre>
== Creating a task ==
 
Custom tasks are added by first declaring a new enum value.
 
<source lang=cpp>
enum  
enum  
{
{
TASK_JUMP = LAST_SHARED_TASK,
TASK_JUMP = LAST_SHARED_TASK,
        TASK_FIND_DODGE_DIRECTION,
TASK_FIND_DODGE_DIRECTION,  
LAST_MY_NPC_TASK,
};
};
</pre>
</source>


Then you would need to add the tasks in your custom schedule in the order you wish them to execute, notice <code>TASK_FIND_DODGE_DIRECTION</code> has been given a value of 3, you can pass data through with your tasks and use them when the task logic is executed.
After that, the task itself should be declared like this:


<pre>
<source lang=cpp>
AI_BEGIN_CUSTOM_NPC( npc_custom, CNPC_Custom )
AI_BEGIN_CUSTOM_NPC( npc_custom, CNPC_Custom )
DEFINE_SCHEDULE
DECLARE_TASK( TASK_FIND_DODGE_DIRECTION )
(
AI_END_CUSTOM_NPC()
SCHED_DODGE_ENEMY_FIRE,
</source>


" Tasks"
Then you add the tasks in your custom schedule in the order you want them to execute. See [[Schedule]] for more details on the following code:
" TASK_FIND_DODGE_DIRECTION 3"
" TASK_JUMP 0"
""
" Interrupts"
        "              COND_LIGHT_DAMAGE"
);


<source lang=cpp>
AI_BEGIN_CUSTOM_NPC( npc_custom, CNPC_Custom )
DEFINE_SCHEDULE
(
SCHED_DODGE_ENEMY_FIRE,
" Tasks"
" TASK_FIND_DODGE_DIRECTION 3"
" TASK_JUMP 0"
""
" Interrupts"
      " COND_LIGHT_DAMAGE"
)
AI_END_CUSTOM_NPC()
AI_END_CUSTOM_NPC()
</pre>
</source>


We need to also provide some logic that will be executed for each task, we can do this by overriding the method <code>StartTask( const Task_t *pTask )</code> and <code>RunTask( const Task_t *pTask )</code>of CAI_BaseNPC. As mentioned you can grab the data passed through with the task in these methods by using <code>pTask->flTaskData</code>. An example is shown below.
== Task logic ==


<pre>
Now that everything is set up it's finally time ''to write some actual AI code''.
void CNPC_Custom :StartTask( const Task_t *pTask )
 
* Tasks are initiated from <code>StartTask(Task_t *pTask)</code>, which should take the form of a <code>[[W:Switch statement#Examples|switch]]</code> statement that evaluates <code>pTask->iTask</code>. {{note|Remember to have a <code>default</code> case that falls back on <code>BaseClass::StartTask()</code>.}}
* Each task has an associated [[float]] value, <code>pTask->flTaskData</code>, which can be used to change its outcome.
* When the current task is complete, call <code>TaskComplete()</code>. The schedule will move on to the next task.
* If the current task has failed, call <code>TaskFail()</code> with an error message. A new schedule will be selected.
 
=== Example ===
 
This code makes the NPC play the <code>ACT_MP_JUMP</code> [[activity]] endlessly.
 
<source lang=cpp>
void CNewNPC::StartTask( const Task_t *pTask )
{
{
switch ( pTask->iTask )
switch (pTask->iTask)
{
{
case TASK_FIND_DODGE_DIRECTION:
case TASK_MYCUSTOMTASK:
{
if (FindGestureLayer(ACT_MP_JUMP) == -1)
if(!FindBestDodgeDirection(pTask->flTaskData))
AddGesture(ACT_MP_JUMP);
                        {
TaskComplete();
                              TaskFail( "TASK_FIND_DODGE_DIRECTION: Unable to find suitable dodge direction\n" );
                        }
                        else
                        {
                              TaskComplete();
                        }
}
break;
break;


case TASK_JUMP:
default:
{
BaseClass::StartTask( pTask );
Jump();
}
break;
 
default:
{
BaseClass::StartTask( pTask );
}
}
}
}
}
</pre>
</source>
 
==Default Task List==
TASK_INVALID
 
TASK_RESET_ACTIVITY: Forces the activity to reset.
 
TASK_WAIT: Waits for the specified number of seconds.
 
TASK_ANNOUNCE_ATTACK: Make announce attack sound
TASK_WAIT_FACE_ENEMY: Waits for the specified number of seconds. Will constantly turn to face the enemy while waiting.
TASK_WAIT_FACE_ENEMY_RANDOM: Waits up to the specified number of seconds. Will constantly turn to : face the enemy while waiting.
 
TASK_WAIT_PVS: Wait until the player enters the same PVS as this character.
TASK_SUGGEST_STATE: DON'T use this it needs to go away.
 
TASK_TARGET_PLAYER: Set m_hTargetEnt to nearest player
 
TASK_SCRIPT_WALK_TO_TARGET: Walk to m_hTargetEnt's location
 
TASK_SCRIPT_RUN_TO_TARGET: Run to m_hTargetEnt's location
 
TASK_SCRIPT_CUSTOM_MOVE_TO_TARGET: Move to m_hTargetEnt's location using the activity specified by m_hCine->m_iszCustomMove.
 
TASK_MOVE_TO_TARGET_RANGE: Move to within specified range of m_hTargetEnt
 
TASK_MOVE_AWAY_PATH: Path that moves the character a few steps forward of where it is.
 
TASK_GET_PATH_AWAY_FROM_BEST_SOUND
:
TASK_SET_GOAL Set the implied goal for TASK_GET_PATH_TO_GOAL
 
TASK_GET_PATH_TO_GOAL: Get the path to the goal specified by TASK_SET_GOAL
 
TASK_GET_PATH_TO_ENEMY: Path to the enemy's location. Even if the enemy is unseen!
 
TASK_GET_PATH_TO_ENEMY_LKP: Path to the last place this character saw the enemy
 
TASK_GET_CHASE_PATH_TO_ENEMY: Path to the enemy's location or path to a LOS with the enemy's last known position depending on range
 
TASK_GET_PATH_TO_ENEMY_LKP_LOS: Path to a LOS with the enemy's last known position
 
TASK_GET_PATH_TO_ENEMY_CORPSE: Path to the dead enemy's carcass.
 
TASK_GET_PATH_TO_PLAYER: Path to the player's origin
 
TASK_GET_PATH_TO_ENEMY_LOS: Path to node with line of sight to enemy
 
TASK_GET_PATH_TO_RANGE_ENEMY_LKP_LOS: Path to the within shot range of last place this character saw the enemy
 
TASK_GET_PATH_TO_TARGET: Build a path to m_hTargetEnt
 
TASK_GET_PATH_TO_TARGET_WEAPON: Allow a little slop and allow for some Z offset (like the target is a gun on a table).
 
TASK_GET_PATH_TO_HINTNODE: Path to nodes(m_pHintNode)
 
TASK_STORE_LASTPOSITION: Store current position for later reference
 
TASK_CLEAR_LASTPOSITION: Clear stored position
 
TASK_STORE_POSITION_IN_SAVEPOSITION: Store current position for later reference
 
TASK_STORE_BESTSOUND_IN_SAVEPOSITION: Store best sound position for later reference
 
TASK_STORE_BESTSOUND_REACTORIGIN_IN_SAVEPOSITION
 
TASK_STORE_ENEMY_POSITION_IN_SAVEPOSITION: Store current enemy position in saveposition
 
TASK_GET_PATH_TO_COMMAND_GOAL: Move to the goal specified by the player in command mode.
 
TASK_MARK_COMMAND_GOAL_POS
 
TASK_CLEAR_COMMAND_GOAL
 
TASK_GET_PATH_TO_LASTPOSITION: Path to last position (Last position must be stored with TASK_STORE_LAST_POSITION)
 
TASK_GET_PATH_TO_SAVEPOSITION: Path to saved position (Save position must by set in code or by a task)
 
TASK_GET_PATH_TO_SAVEPOSITION_LOS: Path to location that has line of sight to saved position (Save position must by set in code or by a task)
 
TASK_GET_PATH_TO_RANDOM_NODE: Path to random node
 
TASK_GET_PATH_TO_BESTSOUND: Path to source of loudest heard sound that I care about
 
TASK_GET_PATH_TO_BESTSCENT: Path to source of the strongest scend that I care about
 
TASK_RUN_PATH: Run the current path
 
TASK_WALK_PATH: Walk the current path
 
TASK_WALK_PATH_TIMED: Walk the current path for a specified number of seconds
 
TASK_WALK_PATH_WITHIN_DIST: Walk the current path until you are x units from the goal.
 
TASK_WALK_PATH_FOR_UNITS: Walk the current path until for x units
 
TASK_RUN_PATH_FLEE: Run the current path until you are x units from the goal.
 
TASK_RUN_PATH_TIMED: Run the current path for a specified number of seconds
 
TASK_RUN_PATH_FOR_UNITS: Run the current path until for x units
 
TASK_RUN_PATH_WITHIN_DIST: Run the current path until you are x units from the goal.
 
TASK_STRAFE_PATH: Walk the current path sideways (must be supported by animation)
 
TASK_CLEAR_MOVE_WAIT: Clear m_flMoveWaitFinished (timer that inhibits movement)
 
TASK_SMALL_FLINCH: Decide on the appropriate small flinch animation and play it.
 
TASK_BIG_FLINCH: Decide on the appropriate big flinch animation and play it.
 
TASK_FACE_IDEAL: Turn to face ideal yaw
 
TASK_FACE_REASONABLE: Find an interesting direction to face. Don't face into walls corners if you can help it.
 
TASK_FACE_PATH: Turn to face the way I should walk or run
 
TASK_FACE_PLAYER: Turn to face a player
 
TASK_FACE_ENEMY: Turn to face the enemy
 
TASK_FACE_HINTNODE: Turn to face nodes(m_pHintNode)
 
TASK_PLAY_HINT_ACTIVITY: Play activity associate with the current hint
 
TASK_FACE_TARGET: Turn to face m_hTargetEnt
 
TASK_FACE_LASTPOSITION: Turn to face stored last position (last position must be stored first!)
 
TASK_FACE_SAVEPOSITION: Turn to face stored save position (save position must be stored first!)
 
TASK_SET_IDEAL_YAW_TO_CURRENT: Set the current facing to be the ideal
 
TASK_RANGE_ATTACK1: Attack the enemy (should be facing the enemy)
 
TASK_RANGE_ATTACK2: Attack the enemy (should be facing the enemy)
 
TASK_MELEE_ATTACK1: Attack the enemy (should be facing the enemy)
 
TASK_MELEE_ATTACK2: Attack the enemy (should be facing the enemy)
 
TASK_RELOAD: Reload weapon
 
TASK_SPECIAL_ATTACK1: Execute special attack (user-defined)
 
TASK_SPECIAL_ATTACK2: Execute special attack (user-defined)
 
TASK_FIND_HINTNODE
 
TASK_FIND_LOCK_HINTNODE
 
TASK_CLEAR_HINTNODE
 
TASK_LOCK_HINTNODE: Claim m_pHintNode exclusively for this NPC.
 
TASK_SOUND_ANGRY: Emit an angry sound
 
TASK_SOUND_DEATH: Emit a dying sound
 
TASK_SOUND_IDLE: Emit an idle sound
 
TASK_SOUND_WAKE: Emit a sound because you are pissed off because you just saw someone you don't like
 
TASK_SOUND_PAIN: Emit a pain sound
 
TASK_SOUND_DIE: Emit a death sound
 
TASK_SPEAK_SENTENCE: Speak a sentence
 
TASK_WAIT_FOR_SPEAK_FINISH: Wait for the current sentence I'm speaking to finish
 
TASK_SET_ACTIVITY: Set current animation activity to the specified activity
 
TASK_SET_SCHEDULE: Immediately change to a schedule of the specified type
 
TASK_SET_FAIL_SCHEDULE: Set the specified schedule to execute if the current schedule fails.
 
TASK_SET_TOLERANCE_DISTANCE: How close to route goal do I need to get
 
TASK_SET_ROUTE_SEARCH_TIME: How many seconds should I spend search for a route
 
TASK_CLEAR_FAIL_SCHEDULE: Return to use of default fail schedule
 
TASK_PLAY_SEQUENCE: Play the specified animation sequence before continuing
 
TASK_PLAY_PRIVATE_SEQUENCE: Play the specified private animation sequence before continuing
 
TASK_PLAY_PRIVATE_SEQUENCE_FACE_ENEMY: Turn to face the enemy while playing specified animation sequence
 
TASK_PLAY_SEQUENCE_FACE_ENEMY
 
TASK_PLAY_SEQUENCE_FACE_TARGET
 
 
TASK_FIND_COVER_FROM_BEST_SOUND: tries lateral cover first then node cover
 
TASK_FIND_COVER_FROM_ENEMY: tries lateral cover first then node cover
 
TASK_FIND_LATERAL_COVER_FROM_ENEMY: Find a place to hide from the enemy somewhere on either side of me
 
TASK_FIND_BACKAWAY_FROM_SAVEPOSITION: Find a place further from the saved position
 
TASK_FIND_NODE_COVER_FROM_ENEMY: Fine a place to hide from the enemy anywhere. Use the node system.
 
TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: Find a place to hide from the enemy that's within the specified distance
 
TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: data for this one is there MINIMUM aceptable distance to the cover.
 
TASK_FIND_COVER_FROM_ORIGIN: Find a place to go that can't see to where I am now.
 
TASK_DIE: Unhook from the AI system.
 
TASK_WAIT_FOR_SCRIPT: Wait until scripted sequence plays
 
TASK_PUSH_SCRIPT_ARRIVAL_ACTIVITY: Play scripted sequence animation
 
TASK_PLAY_SCRIPT: Play scripted sequence animation
 
TASK_PLAY_SCRIPT_POST_IDLE: Play scripted sequence animation
 
TASK_ENABLE_SCRIPT: Play scripted sequence animation
 
TASK_PLANT_ON_SCRIPT: Play scripted sequence animation
 
TASK_FACE_SCRIPT: Play scripted sequence animation
 
TASK_PLAY_SCENE: Wait for scene to complete
 
TASK_WAIT_RANDOM: Wait for 0 to specified number of seconds
 
TASK_WAIT_INDEFINITE: Wait forever (until this schedule is interrupted)
 
TASK_STOP_MOVING
 
TASK_TURN_LEFT: Turn left the specified number of degrees
 
TASK_TURN_RIGHT: Turn right the specified number of degrees
 
TASK_REMEMBER: Remember the specified piece of data
 
TASK_FORGET: Forget the specified piece of data
TASK_WAIT_FOR_MOVEMENT: Wait until current movement is complete.
 
TASK_WAIT_FOR_MOVEMENT_STEP: Wait until a single-step movement is complete.
 
TASK_WAIT_UNTIL_NO_DANGER_SOUND: Wait until I can't hear any danger sound.
 
TASK_WEAPON_FIND: Pick up new weapons
 
TASK_WEAPON_PICKUP: Pick up new weapons
 
TASK_WEAPON_RUN_PATH: run to weapon but break if someone else picks it up


TASK_WEAPON_CREATE
=== Navigation ===


TASK_ITEM_PICKUP
{{todo}}


TASK_ITEM_RUN_PATH
=== Animation ===


TASK_USE_SMALL_HULL: Use small hull for tight navigation
* [[Animating a model]]


TASK_FALL_TO_GROUND: wait until you are on ground
=== Combat ===


TASK_WANDER: Wander for a specfied amound of time
{{todo}}


TASK_FREEZE
=== Speech ===


TASK_GATHER_CONDITIONS: regather conditions at the start of a schedule (all conditions are cleared between schedules)
* [[Response System]]
* [[Speech semaphore]]
* [[Choreography creation]]


TASK_IGNORE_OLD_ENEMIES: Require an enemy be seen after the task is run to be considered a candidate enemy
== See also ==


TASK_DEBUG_BREAK
* [[Shared tasks]]


TASK_ADD_HEALTH: Add a specified amount of health to this NPC
{{navbar|Creating a schedule|Creating an NPC|Giving an NPC Memory}}
[[Category:AI Programming]]

Latest revision as of 10:24, 9 May 2023

See also:  For community tasks, see Valve Developer Community:Tasks

A Task is an action that an NPC can perform. Schedules will run a list of tasks. Keep tasks as atomic as possible; don't squeeze two distinct actions into the same one.

Creating a task

Custom tasks are added by first declaring a new enum value.

enum 
{
	TASK_JUMP = LAST_SHARED_TASK,
	TASK_FIND_DODGE_DIRECTION, 
	LAST_MY_NPC_TASK,
};

After that, the task itself should be declared like this:

AI_BEGIN_CUSTOM_NPC( npc_custom, CNPC_Custom )
	DECLARE_TASK( TASK_FIND_DODGE_DIRECTION )
AI_END_CUSTOM_NPC()

Then you add the tasks in your custom schedule in the order you want them to execute. See Schedule for more details on the following code:

AI_BEGIN_CUSTOM_NPC( npc_custom, CNPC_Custom )
	DEFINE_SCHEDULE
	(
		SCHED_DODGE_ENEMY_FIRE,

		"	Tasks"
		"		TASK_FIND_DODGE_DIRECTION	3"
		"		TASK_JUMP	0"
		""
		"	Interrupts"
       	"		COND_LIGHT_DAMAGE"
	)
AI_END_CUSTOM_NPC()

Task logic

Now that everything is set up it's finally time to write some actual AI code.

  • Tasks are initiated from StartTask(Task_t *pTask), which should take the form of a switch statement that evaluates pTask->iTask.
    Note.pngNote:Remember to have a default case that falls back on BaseClass::StartTask().
  • Each task has an associated float value, pTask->flTaskData, which can be used to change its outcome.
  • When the current task is complete, call TaskComplete(). The schedule will move on to the next task.
  • If the current task has failed, call TaskFail() with an error message. A new schedule will be selected.

Example

This code makes the NPC play the ACT_MP_JUMP activity endlessly.

void CNewNPC::StartTask( const Task_t *pTask )
{
	switch (pTask->iTask)
	{
	case TASK_MYCUSTOMTASK:
		if (FindGestureLayer(ACT_MP_JUMP) == -1)
			AddGesture(ACT_MP_JUMP);
		TaskComplete();
		break;

	default:
		BaseClass::StartTask( pTask );
	}
}

Navigation

[Todo]

Animation

Combat

[Todo]

Speech

See also