You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1242 lines
25 KiB
1242 lines
25 KiB
/*** |
|
* |
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved. |
|
* |
|
* This product contains software technology licensed from Id |
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. |
|
* All Rights Reserved. |
|
* |
|
* This source code contains proprietary and confidential information of |
|
* Valve LLC and its suppliers. Access to this code is restricted to |
|
* persons who have executed a written SDK license with Valve. Any access, |
|
* use or distribution of this code by or to any unlicensed person is illegal. |
|
* |
|
****/ |
|
//========================================================= |
|
// Default behaviors. |
|
//========================================================= |
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "monsters.h" |
|
#include "schedule.h" |
|
#include "defaultai.h" |
|
#include "soundent.h" |
|
#include "nodes.h" |
|
#include "scripted.h" |
|
|
|
//========================================================= |
|
// Fail |
|
//========================================================= |
|
Task_t tlFail[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT, (float)2 }, |
|
{ TASK_WAIT_PVS, (float)0 }, |
|
}; |
|
|
|
Schedule_t slFail[] = |
|
{ |
|
{ |
|
tlFail, |
|
ARRAYSIZE( tlFail ), |
|
bits_COND_CAN_ATTACK, |
|
0, |
|
"Fail" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Idle Schedules |
|
//========================================================= |
|
Task_t tlIdleStand1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT, (float)5 }, // repick IDLESTAND every five seconds. gives us a chance to pick an active idle, fidget, etc. |
|
}; |
|
|
|
Schedule_t slIdleStand[] = |
|
{ |
|
{ |
|
tlIdleStand1, |
|
ARRAYSIZE( tlIdleStand1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_SEE_FEAR | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_HEAR_SOUND | |
|
bits_COND_SMELL_FOOD | |
|
bits_COND_SMELL | |
|
bits_COND_PROVOKED, |
|
|
|
bits_SOUND_COMBAT |// sound flags |
|
bits_SOUND_WORLD | |
|
bits_SOUND_PLAYER | |
|
bits_SOUND_DANGER | |
|
|
|
bits_SOUND_MEAT |// scents |
|
bits_SOUND_CARCASS | |
|
bits_SOUND_GARBAGE, |
|
"IdleStand" |
|
}, |
|
}; |
|
|
|
Schedule_t slIdleTrigger[] = |
|
{ |
|
{ |
|
tlIdleStand1, |
|
ARRAYSIZE( tlIdleStand1 ), |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE, |
|
0, |
|
"Idle Trigger" |
|
}, |
|
}; |
|
|
|
Task_t tlIdleWalk1[] = |
|
{ |
|
{ TASK_WALK_PATH, (float)9999 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slIdleWalk[] = |
|
{ |
|
{ |
|
tlIdleWalk1, |
|
ARRAYSIZE( tlIdleWalk1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_HEAR_SOUND | |
|
bits_COND_SMELL_FOOD | |
|
bits_COND_SMELL | |
|
bits_COND_PROVOKED, |
|
|
|
bits_SOUND_COMBAT |// sound flags |
|
|
|
bits_SOUND_MEAT |// scents |
|
bits_SOUND_CARCASS | |
|
bits_SOUND_GARBAGE, |
|
"Idle Walk" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Ambush - monster stands in place and waits for a new |
|
// enemy, or chance to attack an existing enemy. |
|
//========================================================= |
|
Task_t tlAmbush[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT_INDEFINITE, (float)0 }, |
|
}; |
|
|
|
Schedule_t slAmbush[] = |
|
{ |
|
{ |
|
tlAmbush, |
|
ARRAYSIZE( tlAmbush ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_PROVOKED, |
|
0, |
|
"Ambush" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// ActiveIdle schedule - !!!BUGBUG - if this schedule doesn't |
|
// complete on its own, the monster's HintNode will not be |
|
// cleared, and the rest of the monster's group will avoid |
|
// that node because they think the group member that was |
|
// previously interrupted is still using that node to active |
|
// idle. |
|
///========================================================= |
|
Task_t tlActiveIdle[] = |
|
{ |
|
{ TASK_FIND_HINTNODE, (float)0 }, |
|
{ TASK_GET_PATH_TO_HINTNODE, (float)0 }, |
|
{ TASK_STORE_LASTPOSITION, (float)0 }, |
|
{ TASK_WALK_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_FACE_HINTNODE, (float)0 }, |
|
{ TASK_PLAY_ACTIVE_IDLE, (float)0 }, |
|
{ TASK_GET_PATH_TO_LASTPOSITION, (float)0 }, |
|
{ TASK_WALK_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_CLEAR_LASTPOSITION, (float)0 }, |
|
{ TASK_CLEAR_HINTNODE, (float)0 }, |
|
}; |
|
|
|
Schedule_t slActiveIdle[] = |
|
{ |
|
{ |
|
tlActiveIdle, |
|
ARRAYSIZE( tlActiveIdle ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_PROVOKED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_COMBAT | |
|
bits_SOUND_WORLD | |
|
bits_SOUND_PLAYER | |
|
bits_SOUND_DANGER, |
|
"Active Idle" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// Wake Schedules |
|
//========================================================= |
|
Task_t tlWakeAngry1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_SOUND_WAKE, (float)0 }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
}; |
|
|
|
Schedule_t slWakeAngry[] = |
|
{ |
|
{ |
|
tlWakeAngry1, |
|
ARRAYSIZE( tlWakeAngry1 ), |
|
0, |
|
0, |
|
"Wake Angry" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// AlertFace Schedules |
|
//========================================================= |
|
Task_t tlAlertFace1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
}; |
|
|
|
Schedule_t slAlertFace[] = |
|
{ |
|
{ |
|
tlAlertFace1, |
|
ARRAYSIZE( tlAlertFace1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_SEE_FEAR | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_PROVOKED, |
|
0, |
|
"Alert Face" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// AlertSmallFlinch Schedule - shot, but didn't see attacker, |
|
// flinch then face |
|
//========================================================= |
|
Task_t tlAlertSmallFlinch[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, |
|
{ TASK_SMALL_FLINCH, (float)0 }, |
|
{ TASK_SET_SCHEDULE, (float)SCHED_ALERT_FACE }, |
|
}; |
|
|
|
Schedule_t slAlertSmallFlinch[] = |
|
{ |
|
{ |
|
tlAlertSmallFlinch, |
|
ARRAYSIZE( tlAlertSmallFlinch ), |
|
0, |
|
0, |
|
"Alert Small Flinch" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// AlertIdle Schedules |
|
//========================================================= |
|
Task_t tlAlertStand1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT, (float)20 }, |
|
{ TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, |
|
}; |
|
|
|
Schedule_t slAlertStand[] = |
|
{ |
|
{ |
|
tlAlertStand1, |
|
ARRAYSIZE( tlAlertStand1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_SEE_ENEMY | |
|
bits_COND_SEE_FEAR | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_PROVOKED | |
|
bits_COND_SMELL | |
|
bits_COND_SMELL_FOOD | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_COMBAT |// sound flags |
|
bits_SOUND_WORLD | |
|
bits_SOUND_PLAYER | |
|
bits_SOUND_DANGER | |
|
bits_SOUND_MEAT |// scent flags |
|
bits_SOUND_CARCASS | |
|
bits_SOUND_GARBAGE, |
|
"Alert Stand" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// InvestigateSound - sends a monster to the location of the |
|
// sound that was just heard, to check things out. |
|
//========================================================= |
|
Task_t tlInvestigateSound[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_STORE_LASTPOSITION, (float)0 }, |
|
{ TASK_GET_PATH_TO_BESTSOUND, (float)0 }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
{ TASK_WALK_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_IDLE }, |
|
{ TASK_WAIT, (float)10 }, |
|
{ TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, |
|
{ TASK_WALK_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_CLEAR_LASTPOSITION, (float)0 }, |
|
}; |
|
|
|
Schedule_t slInvestigateSound[] = |
|
{ |
|
{ |
|
tlInvestigateSound, |
|
ARRAYSIZE( tlInvestigateSound ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_SEE_FEAR | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"InvestigateSound" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// CombatIdle Schedule |
|
//========================================================= |
|
Task_t tlCombatStand1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT_INDEFINITE, (float)0 }, |
|
}; |
|
|
|
Schedule_t slCombatStand[] = |
|
{ |
|
{ |
|
tlCombatStand1, |
|
ARRAYSIZE( tlCombatStand1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_CAN_ATTACK, |
|
0, |
|
"Combat Stand" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// CombatFace Schedule |
|
//========================================================= |
|
Task_t tlCombatFace1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
}; |
|
|
|
Schedule_t slCombatFace[] = |
|
{ |
|
{ |
|
tlCombatFace1, |
|
ARRAYSIZE( tlCombatFace1 ), |
|
bits_COND_CAN_ATTACK | |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD, |
|
0, |
|
"Combat Face" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Standoff schedule. Used in combat when a monster is |
|
// hiding in cover or the enemy has moved out of sight. |
|
// Should we look around in this schedule? |
|
//========================================================= |
|
Task_t tlStandoff[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE }, |
|
{ TASK_WAIT_FACE_ENEMY, (float)2 }, |
|
}; |
|
|
|
Schedule_t slStandoff[] = |
|
{ |
|
{ |
|
tlStandoff, |
|
ARRAYSIZE( tlStandoff ), |
|
bits_COND_CAN_RANGE_ATTACK1 | |
|
bits_COND_CAN_RANGE_ATTACK2 | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Standoff" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// Arm weapon (draw gun) |
|
//========================================================= |
|
Task_t tlArmWeapon[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_ARM } |
|
}; |
|
|
|
Schedule_t slArmWeapon[] = |
|
{ |
|
{ |
|
tlArmWeapon, |
|
ARRAYSIZE( tlArmWeapon ), |
|
0, |
|
0, |
|
"Arm Weapon" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// reload schedule |
|
//========================================================= |
|
Task_t tlReload[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, |
|
}; |
|
|
|
Schedule_t slReload[] = |
|
{ |
|
{ |
|
tlReload, |
|
ARRAYSIZE( tlReload ), |
|
bits_COND_HEAVY_DAMAGE, |
|
0, |
|
"Reload" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// Attack Schedules |
|
//========================================================= |
|
|
|
// primary range attack |
|
Task_t tlRangeAttack1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_RANGE_ATTACK1, (float)0 }, |
|
}; |
|
|
|
Schedule_t slRangeAttack1[] = |
|
{ |
|
{ |
|
tlRangeAttack1, |
|
ARRAYSIZE( tlRangeAttack1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED | |
|
bits_COND_NO_AMMO_LOADED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Range Attack1" |
|
}, |
|
}; |
|
|
|
// secondary range attack |
|
Task_t tlRangeAttack2[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_RANGE_ATTACK2, (float)0 }, |
|
}; |
|
|
|
Schedule_t slRangeAttack2[] = |
|
{ |
|
{ |
|
tlRangeAttack2, |
|
ARRAYSIZE( tlRangeAttack2 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Range Attack2" |
|
}, |
|
}; |
|
|
|
// primary melee attack |
|
Task_t tlPrimaryMeleeAttack1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_MELEE_ATTACK1, (float)0 }, |
|
}; |
|
|
|
Schedule_t slPrimaryMeleeAttack[] = |
|
{ |
|
{ |
|
tlPrimaryMeleeAttack1, |
|
ARRAYSIZE( tlPrimaryMeleeAttack1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED, |
|
0, |
|
"Primary Melee Attack" |
|
}, |
|
}; |
|
|
|
// secondary melee attack |
|
Task_t tlSecondaryMeleeAttack1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_MELEE_ATTACK2, (float)0}, |
|
}; |
|
|
|
Schedule_t slSecondaryMeleeAttack[] = |
|
{ |
|
{ |
|
tlSecondaryMeleeAttack1, |
|
ARRAYSIZE( tlSecondaryMeleeAttack1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED, |
|
0, |
|
"Secondary Melee Attack" |
|
}, |
|
}; |
|
|
|
// special attack1 |
|
Task_t tlSpecialAttack1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_SPECIAL_ATTACK1, (float)0 }, |
|
}; |
|
|
|
Schedule_t slSpecialAttack1[] = |
|
{ |
|
{ |
|
tlSpecialAttack1, |
|
ARRAYSIZE( tlSpecialAttack1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED | |
|
bits_COND_NO_AMMO_LOADED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Special Attack1" |
|
}, |
|
}; |
|
|
|
// special attack2 |
|
Task_t tlSpecialAttack2[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_SPECIAL_ATTACK2, (float)0 }, |
|
}; |
|
|
|
Schedule_t slSpecialAttack2[] = |
|
{ |
|
{ |
|
tlSpecialAttack2, |
|
ARRAYSIZE( tlSpecialAttack2 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_ENEMY_DEAD | |
|
bits_COND_LIGHT_DAMAGE | |
|
bits_COND_HEAVY_DAMAGE | |
|
bits_COND_ENEMY_OCCLUDED | |
|
bits_COND_NO_AMMO_LOADED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Special Attack2" |
|
}, |
|
}; |
|
|
|
// Chase enemy schedule |
|
Task_t tlChaseEnemy1[] = |
|
{ |
|
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED }, |
|
{ TASK_GET_PATH_TO_ENEMY, (float)0 }, |
|
{ TASK_RUN_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slChaseEnemy[] = |
|
{ |
|
{ |
|
tlChaseEnemy1, |
|
ARRAYSIZE( tlChaseEnemy1 ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_CAN_RANGE_ATTACK1 | |
|
bits_COND_CAN_MELEE_ATTACK1 | |
|
bits_COND_CAN_RANGE_ATTACK2 | |
|
bits_COND_CAN_MELEE_ATTACK2 | |
|
bits_COND_TASK_FAILED | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"Chase Enemy" |
|
}, |
|
}; |
|
|
|
|
|
// Chase enemy failure schedule |
|
Task_t tlChaseEnemyFailed[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_WAIT, (float)0.2 }, |
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 }, |
|
{ TASK_RUN_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, |
|
//{ TASK_TURN_LEFT, (float)179 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_WAIT, (float)1 }, |
|
}; |
|
|
|
Schedule_t slChaseEnemyFailed[] = |
|
{ |
|
{ |
|
tlChaseEnemyFailed, |
|
ARRAYSIZE( tlChaseEnemyFailed ), |
|
bits_COND_NEW_ENEMY | |
|
bits_COND_CAN_RANGE_ATTACK1 | |
|
bits_COND_CAN_MELEE_ATTACK1 | |
|
bits_COND_CAN_RANGE_ATTACK2 | |
|
bits_COND_CAN_MELEE_ATTACK2 | |
|
bits_COND_HEAR_SOUND, |
|
bits_SOUND_DANGER, |
|
"tlChaseEnemyFailed" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// small flinch, played when minor damage is taken. |
|
//========================================================= |
|
Task_t tlSmallFlinch[] = |
|
{ |
|
{ TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SMALL_FLINCH, 0 }, |
|
}; |
|
|
|
Schedule_t slSmallFlinch[] = |
|
{ |
|
{ |
|
tlSmallFlinch, |
|
ARRAYSIZE( tlSmallFlinch ), |
|
0, |
|
0, |
|
"Small Flinch" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Die! |
|
//========================================================= |
|
Task_t tlDie1[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_SOUND_DIE, (float)0 }, |
|
{ TASK_DIE, (float)0 }, |
|
}; |
|
|
|
Schedule_t slDie[] = |
|
{ |
|
{ |
|
tlDie1, |
|
ARRAYSIZE( tlDie1 ), |
|
0, |
|
0, |
|
"Die" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Victory Dance |
|
//========================================================= |
|
Task_t tlVictoryDance[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, |
|
{ TASK_WAIT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slVictoryDance[] = |
|
{ |
|
{ |
|
tlVictoryDance, |
|
ARRAYSIZE( tlVictoryDance ), |
|
0, |
|
0, |
|
"Victory Dance" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// BarnacleVictimGrab - barnacle tongue just hit the monster, |
|
// so play a hit animation, then play a cycling pull animation |
|
// as the creature is hoisting the monster. |
|
//========================================================= |
|
Task_t tlBarnacleVictimGrab[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_HIT }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_BARNACLE_PULL }, |
|
{ TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. |
|
}; |
|
|
|
Schedule_t slBarnacleVictimGrab[] = |
|
{ |
|
{ |
|
tlBarnacleVictimGrab, |
|
ARRAYSIZE( tlBarnacleVictimGrab ), |
|
0, |
|
0, |
|
"Barnacle Victim" |
|
} |
|
}; |
|
|
|
//========================================================= |
|
// BarnacleVictimChomp - barnacle has pulled the prey to its |
|
// mouth. Victim should play the BARNCLE_CHOMP animation |
|
// once, then loop the BARNACLE_CHEW animation indefinitely |
|
//========================================================= |
|
Task_t tlBarnacleVictimChomp[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_CHOMP }, |
|
{ TASK_SET_ACTIVITY, (float)ACT_BARNACLE_CHEW }, |
|
{ TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. |
|
}; |
|
|
|
Schedule_t slBarnacleVictimChomp[] = |
|
{ |
|
{ |
|
tlBarnacleVictimChomp, |
|
ARRAYSIZE( tlBarnacleVictimChomp ), |
|
0, |
|
0, |
|
"Barnacle Chomp" |
|
} |
|
}; |
|
|
|
// Universal Error Schedule |
|
Task_t tlError[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_WAIT_INDEFINITE, (float)0 }, |
|
}; |
|
|
|
Schedule_t slError[] = |
|
{ |
|
{ |
|
tlError, |
|
ARRAYSIZE( tlError ), |
|
0, |
|
0, |
|
"Error" |
|
}, |
|
}; |
|
|
|
//LRC |
|
Task_t tlScriptedTeleport[] = |
|
{ |
|
{ TASK_PLANT_ON_SCRIPT, (float)0 }, |
|
{ TASK_WAIT_FOR_SCRIPT, (float)0 }, |
|
{ TASK_PLAY_SCRIPT, (float)0 }, |
|
{ TASK_END_SCRIPT, (float)0 }, |
|
}; |
|
|
|
//LRC |
|
Schedule_t slTeleportToScript[] = |
|
{ |
|
{ |
|
tlScriptedTeleport, |
|
ARRAYSIZE ( tlScriptedTeleport ), |
|
SCRIPT_BREAK_CONDITIONS, |
|
0, |
|
"TeleportToScript" |
|
}, |
|
}; |
|
|
|
Task_t tlScriptedWalk[] = |
|
{ |
|
{ TASK_WALK_TO_SCRIPT, (float)TARGET_MOVE_SCRIPTED }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_PLANT_ON_SCRIPT, (float)0 }, |
|
{ TASK_FACE_SCRIPT, (float)0 }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
{ TASK_ENABLE_SCRIPT, (float)0 }, |
|
{ TASK_WAIT_FOR_SCRIPT, (float)0 }, |
|
{ TASK_PLAY_SCRIPT, (float)0 }, |
|
{ TASK_END_SCRIPT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slWalkToScript[] = |
|
{ |
|
{ |
|
tlScriptedWalk, |
|
ARRAYSIZE( tlScriptedWalk ), |
|
SCRIPT_BREAK_CONDITIONS, |
|
0, |
|
"WalkToScript" |
|
}, |
|
}; |
|
|
|
Task_t tlScriptedRun[] = |
|
{ |
|
{ TASK_RUN_TO_SCRIPT, (float)TARGET_MOVE_SCRIPTED }, |
|
{ TASK_WAIT_FOR_MOVEMENT,(float)0 }, |
|
{ TASK_PLANT_ON_SCRIPT, (float)0 }, |
|
{ TASK_FACE_SCRIPT, (float)0 }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
{ TASK_ENABLE_SCRIPT, (float)0 }, |
|
{ TASK_WAIT_FOR_SCRIPT, (float)0 }, |
|
{ TASK_PLAY_SCRIPT, (float)0 }, |
|
{ TASK_END_SCRIPT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slRunToScript[] = |
|
{ |
|
{ |
|
tlScriptedRun, |
|
ARRAYSIZE( tlScriptedRun ), |
|
SCRIPT_BREAK_CONDITIONS, |
|
0, |
|
"RunToScript" |
|
}, |
|
}; |
|
|
|
Task_t tlScriptedWait[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
// { TASK_ENABLE_SCRIPT, (float)0 }, |
|
{ TASK_WAIT_FOR_SCRIPT, (float)0 }, |
|
{ TASK_PLAY_SCRIPT, (float)0 }, |
|
{ TASK_END_SCRIPT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slWaitScript[] = |
|
{ |
|
{ |
|
tlScriptedWait, |
|
ARRAYSIZE( tlScriptedWait ), |
|
SCRIPT_BREAK_CONDITIONS, |
|
0, |
|
"WaitForScript" |
|
}, |
|
}; |
|
|
|
Task_t tlScriptedFace[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_FACE_SCRIPT, (float)0 }, |
|
{ TASK_FACE_IDEAL, (float)0 }, |
|
{ TASK_WAIT_FOR_SCRIPT, (float)0 }, |
|
{ TASK_PLAY_SCRIPT, (float)0 }, |
|
{ TASK_END_SCRIPT, (float)0 }, |
|
}; |
|
|
|
Schedule_t slFaceScript[] = |
|
{ |
|
{ |
|
tlScriptedFace, |
|
ARRAYSIZE( tlScriptedFace ), |
|
SCRIPT_BREAK_CONDITIONS, |
|
0, |
|
"FaceScript" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Cower - this is what is usually done when attempts |
|
// to escape danger fail. |
|
//========================================================= |
|
Task_t tlCower[] = |
|
{ |
|
{ TASK_STOP_MOVING, 0 }, |
|
{ TASK_PLAY_SEQUENCE, (float)ACT_COWER }, |
|
}; |
|
|
|
Schedule_t slCower[] = |
|
{ |
|
{ |
|
tlCower, |
|
ARRAYSIZE( tlCower ), |
|
0, |
|
0, |
|
"Cower" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// move away from where you're currently standing. |
|
//========================================================= |
|
Task_t tlTakeCoverFromOrigin[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_FIND_COVER_FROM_ORIGIN, (float)0 }, |
|
{ TASK_RUN_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, |
|
{ TASK_TURN_LEFT, (float)179 }, |
|
}; |
|
|
|
Schedule_t slTakeCoverFromOrigin[] = |
|
{ |
|
{ |
|
tlTakeCoverFromOrigin, |
|
ARRAYSIZE( tlTakeCoverFromOrigin ), |
|
bits_COND_NEW_ENEMY, |
|
0, |
|
"TakeCoverFromOrigin" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// hide from the loudest sound source |
|
//========================================================= |
|
Task_t tlTakeCoverFromBestSound[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, |
|
{ TASK_RUN_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, |
|
{ TASK_TURN_LEFT, (float)179 }, |
|
}; |
|
|
|
Schedule_t slTakeCoverFromBestSound[] = |
|
{ |
|
{ |
|
tlTakeCoverFromBestSound, |
|
ARRAYSIZE( tlTakeCoverFromBestSound ), |
|
bits_COND_NEW_ENEMY, |
|
0, |
|
"TakeCoverFromBestSound" |
|
}, |
|
}; |
|
|
|
//========================================================= |
|
// Take cover from enemy! Tries lateral cover before node |
|
// cover! |
|
//========================================================= |
|
Task_t tlTakeCoverFromEnemy[] = |
|
{ |
|
{ TASK_STOP_MOVING, (float)0 }, |
|
{ TASK_WAIT, (float)0.2 }, |
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 }, |
|
{ TASK_RUN_PATH, (float)0 }, |
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 }, |
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, |
|
//{ TASK_TURN_LEFT, (float)179 }, |
|
{ TASK_FACE_ENEMY, (float)0 }, |
|
{ TASK_WAIT, (float)1 }, |
|
}; |
|
|
|
Schedule_t slTakeCoverFromEnemy[] = |
|
{ |
|
{ |
|
tlTakeCoverFromEnemy, |
|
ARRAYSIZE( tlTakeCoverFromEnemy ), |
|
bits_COND_NEW_ENEMY, |
|
0, |
|
"tlTakeCoverFromEnemy" |
|
}, |
|
}; |
|
|
|
Schedule_t *CBaseMonster::m_scheduleList[] = |
|
{ |
|
slIdleStand, |
|
slIdleTrigger, |
|
slIdleWalk, |
|
slAmbush, |
|
slActiveIdle, |
|
slWakeAngry, |
|
slAlertFace, |
|
slAlertSmallFlinch, |
|
slAlertStand, |
|
slInvestigateSound, |
|
slCombatStand, |
|
slCombatFace, |
|
slStandoff, |
|
slArmWeapon, |
|
slReload, |
|
slRangeAttack1, |
|
slRangeAttack2, |
|
slPrimaryMeleeAttack, |
|
slSecondaryMeleeAttack, |
|
slSpecialAttack1, |
|
slSpecialAttack2, |
|
slChaseEnemy, |
|
slChaseEnemyFailed, |
|
slSmallFlinch, |
|
slDie, |
|
slVictoryDance, |
|
slBarnacleVictimGrab, |
|
slBarnacleVictimChomp, |
|
slError, |
|
slWalkToScript, |
|
slRunToScript, |
|
slWaitScript, |
|
slFaceScript, |
|
slCower, |
|
slTakeCoverFromOrigin, |
|
slTakeCoverFromBestSound, |
|
slTakeCoverFromEnemy, |
|
slFail |
|
}; |
|
|
|
Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) |
|
{ |
|
return ScheduleInList( pName, m_scheduleList, ARRAYSIZE( m_scheduleList ) ); |
|
} |
|
|
|
Schedule_t *CBaseMonster::ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) |
|
{ |
|
int i; |
|
|
|
if( !pName ) |
|
{ |
|
ALERT( at_console, "%s set to unnamed schedule!\n", STRING( pev->classname ) ); |
|
return NULL; |
|
} |
|
|
|
for( i = 0; i < listCount; i++ ) |
|
{ |
|
if( !pList[i]->pName ) |
|
{ |
|
ALERT( at_console, "Unnamed schedule!\n" ); |
|
continue; |
|
} |
|
if( stricmp( pName, pList[i]->pName ) == 0 ) |
|
return pList[i]; |
|
} |
|
return NULL; |
|
} |
|
|
|
//========================================================= |
|
// GetScheduleOfType - returns a pointer to one of the |
|
// monster's available schedules of the indicated type. |
|
//========================================================= |
|
Schedule_t* CBaseMonster::GetScheduleOfType( int Type ) |
|
{ |
|
//ALERT( at_console, "Sched Type:%d\n", Type ); |
|
switch( Type ) |
|
{ |
|
// This is the schedule for scripted sequences AND scripted AI. // LRC- And scripted actions, too. |
|
case SCHED_AISCRIPT: |
|
{ |
|
// ALERT(at_console, "Doing AISCRIPT\n"); |
|
ASSERT( m_pCine != NULL ); |
|
if( !m_pCine ) |
|
{ |
|
ALERT( at_aiconsole, "Script failed for %s\n", STRING( pev->classname ) ); |
|
CineCleanup(); |
|
return GetScheduleOfType( SCHED_IDLE_STAND ); |
|
} |
|
//else |
|
// ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING( pev->classname ) ); |
|
|
|
switch( m_pCine->m_fMoveTo ) |
|
{ |
|
case 0: |
|
return slWaitScript; |
|
case 4: case 6: |
|
return slTeleportToScript; |
|
case 1: |
|
return slWalkToScript; |
|
case 2: |
|
return slRunToScript; |
|
case 5: |
|
return slFaceScript; |
|
} |
|
break; |
|
} |
|
case SCHED_IDLE_STAND: |
|
{ |
|
if( RANDOM_LONG( 0, 14 ) == 0 && FCanActiveIdle() ) |
|
{ |
|
return &slActiveIdle[0]; |
|
} |
|
|
|
return &slIdleStand[0]; |
|
} |
|
case SCHED_IDLE_WALK: |
|
{ |
|
return &slIdleWalk[0]; |
|
} |
|
case SCHED_WAIT_TRIGGER: |
|
{ |
|
return &slIdleTrigger[0]; |
|
} |
|
case SCHED_WAKE_ANGRY: |
|
{ |
|
return &slWakeAngry[0]; |
|
} |
|
case SCHED_ALERT_FACE: |
|
{ |
|
return &slAlertFace[0]; |
|
} |
|
case SCHED_ALERT_STAND: |
|
{ |
|
return &slAlertStand[0]; |
|
} |
|
case SCHED_COMBAT_STAND: |
|
{ |
|
return &slCombatStand[0]; |
|
} |
|
case SCHED_COMBAT_FACE: |
|
{ |
|
return &slCombatFace[0]; |
|
} |
|
case SCHED_CHASE_ENEMY: |
|
{ |
|
return &slChaseEnemy[0]; |
|
} |
|
case SCHED_CHASE_ENEMY_FAILED: |
|
{ |
|
return &slFail[0]; |
|
} |
|
case SCHED_SMALL_FLINCH: |
|
{ |
|
return &slSmallFlinch[0]; |
|
} |
|
case SCHED_ALERT_SMALL_FLINCH: |
|
{ |
|
return &slAlertSmallFlinch[0]; |
|
} |
|
case SCHED_RELOAD: |
|
{ |
|
return &slReload[0]; |
|
} |
|
case SCHED_ARM_WEAPON: |
|
{ |
|
return &slArmWeapon[0]; |
|
} |
|
case SCHED_STANDOFF: |
|
{ |
|
return &slStandoff[0]; |
|
} |
|
case SCHED_RANGE_ATTACK1: |
|
{ |
|
return &slRangeAttack1[0]; |
|
} |
|
case SCHED_RANGE_ATTACK2: |
|
{ |
|
return &slRangeAttack2[0]; |
|
} |
|
case SCHED_MELEE_ATTACK1: |
|
{ |
|
return &slPrimaryMeleeAttack[0]; |
|
} |
|
case SCHED_MELEE_ATTACK2: |
|
{ |
|
return &slSecondaryMeleeAttack[0]; |
|
} |
|
case SCHED_SPECIAL_ATTACK1: |
|
{ |
|
return &slSpecialAttack1[0]; |
|
} |
|
case SCHED_SPECIAL_ATTACK2: |
|
{ |
|
return &slSpecialAttack2[0]; |
|
} |
|
case SCHED_TAKE_COVER_FROM_BEST_SOUND: |
|
{ |
|
return &slTakeCoverFromBestSound[0]; |
|
} |
|
case SCHED_TAKE_COVER_FROM_ENEMY: |
|
{ |
|
return &slTakeCoverFromEnemy[0]; |
|
} |
|
case SCHED_COWER: |
|
{ |
|
return &slCower[0]; |
|
} |
|
case SCHED_AMBUSH: |
|
{ |
|
return &slAmbush[0]; |
|
} |
|
case SCHED_BARNACLE_VICTIM_GRAB: |
|
{ |
|
return &slBarnacleVictimGrab[0]; |
|
} |
|
case SCHED_BARNACLE_VICTIM_CHOMP: |
|
{ |
|
return &slBarnacleVictimChomp[0]; |
|
} |
|
case SCHED_INVESTIGATE_SOUND: |
|
{ |
|
return &slInvestigateSound[0]; |
|
} |
|
case SCHED_DIE: |
|
{ |
|
return &slDie[0]; |
|
} |
|
case SCHED_TAKE_COVER_FROM_ORIGIN: |
|
{ |
|
return &slTakeCoverFromOrigin[0]; |
|
} |
|
case SCHED_VICTORY_DANCE: |
|
{ |
|
return &slVictoryDance[0]; |
|
} |
|
case SCHED_FAIL: |
|
{ |
|
return slFail; |
|
} |
|
default: |
|
{ |
|
ALERT( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); |
|
|
|
return &slIdleStand[0]; |
|
break; |
|
} |
|
} |
|
|
|
return NULL; |
|
}
|
|
|