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_BSFlee( void ) {//FIXME: keep checking for danger if ( TIMER_Done( NPC, "flee" ) && NPCInfo->tempBehavior == BS_FLEE ) { NPCInfo->tempBehavior = BS_DEFAULT; NPCInfo->squadState = SQUAD_IDLE; //FIXME: should we set some timer to make him stay in this spot for a bit, //so he doesn't just suddenly turn around and come back at the enemy? //OR, just stop running toward goal for last second or so of flee? } if ( NPC_CheckSurrender() ) { return; } gentity_t *goal = NPCInfo->goalEntity; if ( !goal ) { goal = NPCInfo->lastGoalEntity; if ( !goal ) {//???!!! goal = NPCInfo->tempGoal; } } if ( goal ) { qboolean reverseCourse = qtrue; //FIXME: if no weapon, find one and run to pick it up? //Let's try to find a waypoint that gets me away from this thing if ( NPC->waypoint == WAYPOINT_NONE ) { NPC->waypoint = NAV_GetNearestNode( NPC, NPC->lastWaypoint ); } if ( NPC->waypoint != WAYPOINT_NONE ) { int numEdges = navigator.GetNodeNumEdges( NPC->waypoint ); if ( numEdges != WAYPOINT_NONE ) { vec3_t dangerDir; int nextWp; VectorSubtract( NPCInfo->investigateGoal, NPC->currentOrigin, dangerDir ); VectorNormalize( dangerDir ); for ( int branchNum = 0; branchNum < numEdges; branchNum++ ) { vec3_t branchPos, runDir; nextWp = navigator.GetNodeEdge( NPC->waypoint, branchNum ); navigator.GetNodePosition( nextWp, branchPos ); VectorSubtract( branchPos, NPC->currentOrigin, runDir ); VectorNormalize( runDir ); if ( DotProduct( runDir, dangerDir ) > Q_flrand( 0, 0.5 ) ) {//don't run toward danger continue; } //FIXME: don't want to ping-pong back and forth NPC_SetMoveGoal( NPC, branchPos, 0, qtrue ); reverseCourse = qfalse; break; } } } qboolean moved = NPC_MoveToGoal( qfalse );//qtrue? (do try to move straight to (away from) goal) if ( NPC->s.weapon == WP_NONE && (moved == qfalse || reverseCourse) ) {//No weapon and no escape route... Just cower? Need anim. NPC_Surrender(); NPC_UpdateAngles( qtrue, qtrue ); return; } //If our move failed, then just run straight away from our goal //FIXME: We really shouldn't do this. if ( moved == qfalse ) { vec3_t dir; float dist; if ( reverseCourse ) { VectorSubtract( NPC->currentOrigin, goal->currentOrigin, dir ); } else { VectorSubtract( goal->currentOrigin, NPC->currentOrigin, dir ); } NPCInfo->distToGoal = dist = VectorNormalize( dir ); NPCInfo->desiredYaw = vectoyaw( dir ); NPCInfo->desiredPitch = 0; ucmd.forwardmove = 127; } else if ( reverseCourse ) { //ucmd.forwardmove *= -1; //ucmd.rightmove *= -1; //VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir ); NPCInfo->desiredYaw *= -1; } //FIXME: can stop after a safe distance? ucmd.upmove = 0; ucmd.buttons &= ~BUTTON_WALKING; //FIXME: what do we do once we've gotten to our goal? } NPC_UpdateAngles( qtrue, qtrue ); NPC_CheckGetNewWeapon(); }
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; } } }