void NPC_BehaviorSet_Charmed( int bState ) { switch( bState ) { case BS_FOLLOW_LEADER://# 40: Follow your leader and shoot any enemies you come across NPC_BSFollowLeader(); break; case BS_REMOVE: NPC_BSRemove(); break; case BS_SEARCH: //# 43: Using current waypoint as a base, search the immediate branches of waypoints for enemies NPC_BSSearch(); break; case BS_WANDER: //# 46: Wander down random waypoint paths NPC_BSWander(); break; case BS_FLEE: NPC_BSFlee(); break; default: case BS_DEFAULT://whatever NPC_BSDefault(); break; } }
void NPC_BehaviorSet_Default( int bState ) { switch( bState ) { case BS_ADVANCE_FIGHT://head toward captureGoal, shoot anything that gets in the way NPC_BSAdvanceFight (); break; case BS_SLEEP://Follow a path, looking for enemies NPC_BSSleep (); break; case BS_FOLLOW_LEADER://# 40: Follow your leader and shoot any enemies you come across NPC_BSFollowLeader(); break; case BS_JUMP: //41: Face navgoal and jump to it. NPC_BSJump(); break; case BS_REMOVE: NPC_BSRemove(); break; case BS_SEARCH: //# 43: Using current waypoint as a base, search the immediate branches of waypoints for enemies NPC_BSSearch(); break; case BS_NOCLIP: NPC_BSNoClip(); break; case BS_WANDER: //# 46: Wander down random waypoint paths NPC_BSWander(); break; case BS_FLEE: NPC_BSFlee(); break; case BS_WAIT: NPC_BSWait(); break; case BS_CINEMATIC: NPC_BSCinematic(); break; default: case BS_DEFAULT://whatever NPC_BSDefault(); break; } }
void NPC_BSCivilian_Default( int bState ) { if ( NPC->enemy && NPC->s.weapon == WP_NONE && NPC_CheckSurrender() ) {//surrendering, do nothing } else if ( NPC->enemy && NPC->s.weapon == WP_NONE && bState != BS_HUNT_AND_KILL && !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) {//if in battle and have no weapon, run away, fixme: when in BS_HUNT_AND_KILL, they just stand there if ( !NPCInfo->goalEntity || bState != BS_FLEE //not fleeing || ( NPC_BSFlee()//have reached our flee goal && NPC->enemy//still have enemy (NPC_BSFlee checks enemy and can clear it) && DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ) < 16384 )//enemy within 128 ) {//run away! NPC_StartFlee( NPC->enemy, NPC->enemy->currentOrigin, AEL_DANGER_GREAT, 5000, 10000 ); } } else {//not surrendering //FIXME: if unarmed and a jawa/ugnuaght, constantly look for enemies/players to run away from? //FIXME: if we have a weapon and an enemy, set out playerTeam to the opposite of our enemy..??? NPC_BehaviorSet_Default(bState); } if ( !VectorCompare( NPC->client->ps.moveDir, vec3_origin ) ) {//moving if ( NPC->client->ps.legsAnim == BOTH_COWER1 ) {//stop cowering anim on legs NPC->client->ps.legsAnimTimer = 0; } } }
void NPC_RunBehavior( int team, int bState ) { qboolean dontSetAim = qfalse; if (NPC->s.NPC_class == CLASS_VEHICLE && NPC->m_pVehicle) { //vehicles don't do AI! return; } if ( bState == BS_CINEMATIC ) { NPC_BSCinematic(); } else if ( NPC->client->ps.weapon == WP_EMPLACED_GUN ) { NPC_BSEmplaced(); NPC_CheckCharmed(); return; } else if ( NPC->client->ps.weapon == WP_SABER ) {//jedi NPC_BehaviorSet_Jedi( bState ); dontSetAim = qtrue; } else if ( NPC->client->NPC_class == CLASS_WAMPA ) {//wampa NPC_BSWampa_Default(); } else if ( NPC->client->NPC_class == CLASS_RANCOR ) {//rancor NPC_BehaviorSet_Rancor( bState ); } else if ( NPC->client->NPC_class == CLASS_REMOTE ) { NPC_BehaviorSet_Remote( bState ); } else if ( NPC->client->NPC_class == CLASS_SEEKER ) { NPC_BehaviorSet_Seeker( bState ); } else if ( NPC->client->NPC_class == CLASS_BOBAFETT ) {//bounty hunter if ( Boba_Flying( NPC ) ) { NPC_BehaviorSet_Seeker(bState); } else { NPC_BehaviorSet_Jedi( bState ); } dontSetAim = qtrue; } else if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH ) {//being forced to march NPC_BSDefault(); } else { switch( team ) { // case NPCTEAM_SCAVENGERS: // case NPCTEAM_IMPERIAL: // case NPCTEAM_KLINGON: // case NPCTEAM_HIROGEN: // case NPCTEAM_MALON: // not sure if TEAM_ENEMY is appropriate here, I think I should be using NPC_class to check for behavior - dmv case NPCTEAM_ENEMY: // special cases for enemy droids switch( NPC->client->NPC_class) { case CLASS_ATST: NPC_BehaviorSet_ATST( bState ); return; case CLASS_PROBE: NPC_BehaviorSet_ImperialProbe(bState); return; case CLASS_REMOTE: NPC_BehaviorSet_Remote( bState ); return; case CLASS_SENTRY: NPC_BehaviorSet_Sentry(bState); return; case CLASS_INTERROGATOR: NPC_BehaviorSet_Interrogator( bState ); return; case CLASS_MINEMONSTER: NPC_BehaviorSet_MineMonster( bState ); return; case CLASS_HOWLER: NPC_BehaviorSet_Howler( bState ); return; case CLASS_MARK1: NPC_BehaviorSet_Mark1( bState ); return; case CLASS_MARK2: NPC_BehaviorSet_Mark2( bState ); return; case CLASS_GALAKMECH: NPC_BSGM_Default(); return; default: break; } if ( NPC->enemy && NPC->s.weapon == WP_NONE && bState != BS_HUNT_AND_KILL && !trap->ICARUS_TaskIDPending( (sharedEntity_t *)NPC, TID_MOVE_NAV ) ) {//if in battle and have no weapon, run away, fixme: when in BS_HUNT_AND_KILL, they just stand there if ( bState != BS_FLEE ) { NPC_StartFlee( NPC->enemy, &NPC->enemy->r.currentOrigin, AEL_DANGER_GREAT, 5000, 10000 ); } else { NPC_BSFlee(); } return; } if ( NPC->client->ps.weapon == WP_SABER ) {//special melee exception NPC_BehaviorSet_Default( bState ); return; } if ( NPC->client->ps.weapon == WP_DISRUPTOR && (NPCInfo->scriptFlags & SCF_ALT_FIRE) ) {//a sniper NPC_BehaviorSet_Sniper( bState ); return; } if ( NPC->client->ps.weapon == WP_THERMAL || NPC->client->ps.weapon == WP_STUN_BATON )//FIXME: separate AI for melee fighters {//a grenadier NPC_BehaviorSet_Grenadier( bState ); return; } if ( NPC_CheckSurrender() ) { return; } NPC_BehaviorSet_Stormtrooper( bState ); break; case NPCTEAM_NEUTRAL: // special cases for enemy droids if ( NPC->client->NPC_class == CLASS_PROTOCOL || NPC->client->NPC_class == CLASS_UGNAUGHT || NPC->client->NPC_class == CLASS_JAWA) { NPC_BehaviorSet_Default(bState); } else if ( NPC->client->NPC_class == CLASS_VEHICLE ) { // TODO: Add vehicle behaviors here. NPC_UpdateAngles( qtrue, qtrue );//just face our spawn angles for now } else { // Just one of the average droids NPC_BehaviorSet_Droid( bState ); } break; default: if ( NPC->client->NPC_class == CLASS_SEEKER ) { NPC_BehaviorSet_Seeker(bState); } else { if ( NPCInfo->charmedTime > level.time ) { NPC_BehaviorSet_Charmed( bState ); } else { NPC_BehaviorSet_Default( bState ); } NPC_CheckCharmed(); dontSetAim = qtrue; } break; } } }
/* ------------------------- NPC_BSHowler_Default ------------------------- */ void NPC_BSHowler_Default( void ) { if ( NPC->client->ps.legsAnim != BOTH_GESTURE1 ) { NPC->count = 0; } //FIXME: if in jump, do damage in front and maybe knock them down? if ( !TIMER_Done( NPC, "attacking" ) ) { if ( NPC->enemy ) { //NPC_FaceEnemy( qfalse ); Howler_Attack( Distance( NPC->enemy->currentOrigin, NPC->currentOrigin ) ); } else { //NPC_UpdateAngles( qfalse, qtrue ); Howler_Attack( 0.0f ); } NPC_UpdateAngles( qfalse, qtrue ); return; } if ( NPC->enemy ) { if ( NPCInfo->stats.aggression > 0 ) { if ( TIMER_Done( NPC, "aggressionDecay" ) ) { NPCInfo->stats.aggression--; TIMER_Set( NPC, "aggressionDecay", 500 ); } } if ( !TIMER_Done( NPC, "flee" ) && NPC_BSFlee() ) //this can clear ENEMY {//successfully trying to run away return; } if ( NPC->enemy == NULL) { NPC_UpdateAngles( qfalse, qtrue ); return; } if ( NPCInfo->localState == LSTATE_FLEE ) {//we were fleeing, now done (either timer ran out or we cannot flee anymore if ( NPC_ClearLOS( NPC->enemy ) ) {//if enemy is still around, go berzerk NPCInfo->localState = LSTATE_BERZERK; } else {//otherwise, lick our wounds? NPCInfo->localState = LSTATE_CLEAR; TIMER_Set( NPC, "standing", Q_irand( 3000, 10000 ) ); } } else if ( NPCInfo->localState == LSTATE_BERZERK ) {//go nuts! } else if ( NPCInfo->stats.aggression >= Q_irand( 75, 125 ) ) {//that's it, go nuts! NPCInfo->localState = LSTATE_BERZERK; } else if ( !TIMER_Done( NPC, "retreating" ) ) {//trying to back off NPC_FaceEnemy( qtrue ); if ( NPC->client->ps.speed > NPCInfo->stats.walkSpeed ) { NPC->client->ps.speed = NPCInfo->stats.walkSpeed; } ucmd.buttons |= BUTTON_WALKING; if ( Distance( NPC->enemy->currentOrigin, NPC->currentOrigin ) < HOWLER_RETREAT_DIST ) {//enemy is close vec3_t moveDir; AngleVectors( NPC->currentAngles, moveDir, NULL, NULL ); VectorScale( moveDir, -1, moveDir ); if ( !NAV_DirSafe( NPC, moveDir, 8 ) ) {//enemy is backing me up against a wall or ledge! Start to get really mad! NPCInfo->stats.aggression += 2; } else {//back off ucmd.forwardmove = -127; } //enemy won't leave me alone, get mad... NPCInfo->stats.aggression++; } return; } else if ( TIMER_Done( NPC, "standing" ) ) {//not standing around if ( !(NPCInfo->last_ucmd.forwardmove) && !(NPCInfo->last_ucmd.rightmove) ) {//stood last frame if ( TIMER_Done( NPC, "walking" ) && TIMER_Done( NPC, "running" ) ) {//not walking or running if ( Q_irand( 0, 2 ) ) {//run for a while TIMER_Set( NPC, "walking", Q_irand( 4000, 8000 ) ); } else {//walk for a bit TIMER_Set( NPC, "running", Q_irand( 2500, 5000 ) ); } } } else if ( (NPCInfo->last_ucmd.buttons&BUTTON_WALKING) ) {//walked last frame if ( TIMER_Done( NPC, "walking" ) ) {//just finished walking if ( Q_irand( 0, 5 ) || DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin ) < MAX_DISTANCE_SQR ) {//run for a while TIMER_Set( NPC, "running", Q_irand( 4000, 20000 ) ); } else {//stand for a bit TIMER_Set( NPC, "standing", Q_irand( 2000, 6000 ) ); } } } else {//ran last frame if ( TIMER_Done( NPC, "running" ) ) {//just finished running if ( Q_irand( 0, 8 ) || DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin ) < MAX_DISTANCE_SQR ) {//walk for a while TIMER_Set( NPC, "walking", Q_irand( 3000, 10000 ) ); } else {//stand for a bit TIMER_Set( NPC, "standing", Q_irand( 2000, 6000 ) ); } } } } if ( NPC_ValidEnemy( NPC->enemy ) == qfalse ) { TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) ) {//it's been a while since the enemy died, or enemy is completely gone, get bored with him NPC->enemy = NULL; Howler_Patrol(); NPC_UpdateAngles( qtrue, qtrue ); return; } } if ( TIMER_Done( NPC, "lookForNewEnemy" ) ) { gentity_t *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy? NPC->enemy = NULL; gentity_t *newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse ); NPC->enemy = sav_enemy; if ( newEnemy && newEnemy != sav_enemy ) {//picked up a new enemy! NPC->lastEnemy = NPC->enemy; G_SetEnemy( NPC, newEnemy ); if ( NPC->enemy != NPC->lastEnemy ) {//clear this so that we only sniff the player the first time we pick them up NPC->useDebounceTime = 0; } //hold this one for at least 5-15 seconds TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) ); } else {//look again in 2-5 secs TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) ); } } Howler_Combat(); if ( TIMER_Done( NPC, "speaking" ) ) { if ( !TIMER_Done( NPC, "standing" ) || !TIMER_Done( NPC, "retreating" )) { G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/idle_hiss%d.mp3", Q_irand( 1, 2 ) ) ); } else if ( !TIMER_Done( NPC, "walking" ) || NPCInfo->localState == LSTATE_FLEE ) { G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_talk%d.mp3", Q_irand( 1, 5 ) ) ); } else { G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_yell%d.mp3", Q_irand( 1, 5 ) ) ); } if ( NPCInfo->localState == LSTATE_BERZERK || NPCInfo->localState == LSTATE_FLEE ) { TIMER_Set( NPC, "speaking", Q_irand( 1000, 4000 ) ); } else { TIMER_Set( NPC, "speaking", Q_irand( 3000, 8000 ) ); } } return; } else { if ( TIMER_Done( NPC, "speaking" ) ) { if ( !Q_irand( 0, 3 ) ) { G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/idle_hiss%d.mp3", Q_irand( 1, 2 ) ) ); } else { G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_talk%d.mp3", Q_irand( 1, 5 ) ) ); } TIMER_Set( NPC, "speaking", Q_irand( 4000, 12000 ) ); } if ( NPCInfo->stats.aggression > 0 ) { if ( TIMER_Done( NPC, "aggressionDecay" ) ) { NPCInfo->stats.aggression--; TIMER_Set( NPC, "aggressionDecay", 200 ); } } if ( TIMER_Done( NPC, "standing" ) ) {//not standing around if ( !(NPCInfo->last_ucmd.forwardmove) && !(NPCInfo->last_ucmd.rightmove) ) {//stood last frame if ( TIMER_Done( NPC, "walking" ) && TIMER_Done( NPC, "running" ) ) {//not walking or running if ( NPCInfo->goalEntity ) {//have somewhere to go if ( Q_irand( 0, 2 ) ) {//walk for a while TIMER_Set( NPC, "walking", Q_irand( 3000, 10000 ) ); } else {//run for a bit TIMER_Set( NPC, "running", Q_irand( 2500, 5000 ) ); } } } } else if ( (NPCInfo->last_ucmd.buttons&BUTTON_WALKING) ) {//walked last frame if ( TIMER_Done( NPC, "walking" ) ) {//just finished walking if ( Q_irand( 0, 3 ) ) {//run for a while TIMER_Set( NPC, "running", Q_irand( 3000, 6000 ) ); } else {//stand for a bit TIMER_Set( NPC, "standing", Q_irand( 2500, 5000 ) ); } } } else {//ran last frame if ( TIMER_Done( NPC, "running" ) ) {//just finished running if ( Q_irand( 0, 2 ) ) {//walk for a while TIMER_Set( NPC, "walking", Q_irand( 6000, 15000 ) ); } else {//stand for a bit TIMER_Set( NPC, "standing", Q_irand( 4000, 6000 ) ); } } } } if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES ) { Howler_Patrol(); } else { Howler_Idle(); } } NPC_UpdateAngles( qfalse, qtrue ); }