qboolean NPC_FaceEntity( gentity_t *ent, qboolean doPitch ) { vec3_t entPos; //Get the positions CalcEntitySpot( ent, SPOT_HEAD_LEAN, entPos ); return NPC_FacePosition( entPos, doPitch ); }
//////////////////////////////////////////////////////////////////////////////////////// // Tactics // // This function is called right after Update() // If returns true, Jedi and Seeker AI not used for movement // //////////////////////////////////////////////////////////////////////////////////////// bool Boba_Tactics() { if (!NPC->enemy) { return false; } // Think About Changing Tactics //------------------------------ if (TIMER_Done(NPC, "Boba_TacticsSelect")) { Boba_TacticsSelect(); } // These Tactics Require Seeker & Jedi Movement //---------------------------------------------- if (!NPCInfo->localState || NPCInfo->localState==BTS_RIFLE || NPCInfo->localState==BTS_MISSILE) { return false; } // Flame Thrower - Locked In Place //--------------------------------- if (NPCInfo->localState==BTS_FLAMETHROW) { Boba_DoFlameThrower( NPC ); } // Sniper - Move Around, And Take Shots //-------------------------------------- else if (NPCInfo->localState==BTS_SNIPER) { Boba_DoSniper( NPC ); } // Ambush Wait //------------ else if (NPCInfo->localState==BTS_AMBUSHWAIT) { Boba_DoAmbushWait( NPC ); } NPC_FacePosition( NPC->enemy->currentOrigin, qtrue); NPC_UpdateAngles(qtrue, qtrue); return true; // Do Not Use Normal Jedi Or Seeker Movement }
//[CoOp] qboolean NPC_Jumping() {//checks to see if we're jumping if ( NPCInfo->jumpTime ) { if(NPC->client->ps.groundEntityNum != ENTITYNUM_NONE) /* RAFIXME - not exactly sure how to do this. if ( !(NPC->client->ps.pm_flags & PMF_JUMPING )//forceJumpZStart ) && !(NPC->client->ps.pm_flags&PMF_TRIGGER_PUSHED)) */ {//landed NPCInfo->jumpTime = 0; } else { NPC_FacePosition(NPCInfo->jumpDest, qtrue); return qtrue; } } return qfalse; }
//[SPPortComplete] qboolean NPC_JumpBackingUp() {//check for and back up before a large jump if we're supposed to. if (NPCInfo->jumpBackupTime) { if (level.time<NPCInfo->jumpBackupTime) { /* RAFIXME - impliment nav code. STEER::Activate(NPC); STEER::Flee(NPC, NPCInfo->jumpDest); STEER::DeActivate(NPC, &ucmd); */ NPC_FacePosition(NPCInfo->jumpDest, qtrue); NPC_UpdateAngles( qfalse, qtrue ); return qtrue; } NPCInfo->jumpBackupTime = 0; return NPC_TryJump(); } return qfalse; }
bool Boba_Flee() { bool EnemyRecentlySeen = ((level.time - NPCInfo->enemyLastSeenTime)<10000); bool ReachedEscapePoint = (Distance(level.combatPoints[NPCInfo->combatPoint].origin, NPC->currentOrigin)<50.0f); bool HasBeenGoneEnough = (level.time>NPCInfo->surrenderTime || (level.time - NPCInfo->enemyLastSeenTime)>400000); // Is It Time To Come Back For Some More? //---------------------------------------- if (!EnemyRecentlySeen || ReachedEscapePoint) { NPC->svFlags |= SVF_NOCLIENT; if (HasBeenGoneEnough) { if ((level.time - NPCInfo->enemyLastSeenTime)>400000) { Boba_Printf(" Gone Too Long, Attempting Respawn"); } if (Boba_Respawn()) { return true; } } else if (ReachedEscapePoint && (NPCInfo->surrenderTime - level.time)>3000) { if (TIMER_Done(NPC, "SpookPlayerTimer")) { vec3_t testDirection; TIMER_Set(NPC, "SpookPlayerTimer", Q_irand(2000, 10000)); switch(Q_irand(0, 1)) { case 0: Boba_Printf("SPOOK: Dust"); Boba_DustFallNear(NPC->enemy->currentOrigin, Q_irand(1,2)); break; case 1: Boba_Printf("SPOOK: Footsteps"); testDirection[0] = (random() * 0.5f) - 1.0f; testDirection[0] += (testDirection[0]>0.0f)?(0.5f):(-0.5f); testDirection[1] = (random() * 0.5f) - 1.0f; testDirection[1] += (testDirection[1]>0.0f)?(0.5f):(-0.5f); testDirection[2] = 1.0f; VectorMA(NPC->enemy->currentOrigin, 400.0f, testDirection, BobaFootStepLoc); BobaFootStepCount = Q_irand(3,8); break; } } if (BobaFootStepCount && TIMER_Done(NPC, "BobaFootStepFakeTimer")) { TIMER_Set(NPC, "BobaFootStepFakeTimer", Q_irand(300, 800)); BobaFootStepCount --; G_SoundAtSpot(BobaFootStepLoc, G_SoundIndex(va("sound/player/footsteps/boot%d", Q_irand(1,4))), qtrue); } if (TIMER_Done(NPC, "ResampleEnemyDirection") && NPC->enemy->resultspeed>10.0f) { TIMER_Set(NPC, "ResampleEnemyDirection", Q_irand(500, 1000)); AverageEnemyDirectionSamples ++; vec3_t moveDir; VectorCopy(NPC->enemy->client->ps.velocity, moveDir); VectorNormalize(moveDir); VectorAdd(AverageEnemyDirection, moveDir, AverageEnemyDirection); } if (g_bobaDebug->integer && AverageEnemyDirectionSamples) { vec3_t endPos; VectorMA(NPC->enemy->currentOrigin, 500.0f / (float)AverageEnemyDirectionSamples, AverageEnemyDirection, endPos); CG_DrawEdge(NPC->enemy->currentOrigin, endPos, EDGE_IMPACT_POSSIBLE); } } } else { NPCInfo->surrenderTime += 100; } // Finish The Flame Thrower First... //----------------------------------- if (NPCInfo->aiFlags&NPCAI_FLAMETHROW) { Boba_DoFlameThrower( NPC ); NPC_FacePosition( NPC->enemy->currentOrigin, qtrue); NPC_UpdateAngles(qtrue, qtrue); return true; } bool IsOnAPath = !!NPC_MoveToGoal(qtrue); if (!ReachedEscapePoint && NPCInfo->aiFlags&NPCAI_BLOCKED && NPC->client->moveType!=MT_FLYSWIM && ((level.time - NPCInfo->blockedDebounceTime)>1000) ) { if (!Boba_CanSeeEnemy(NPC) && Distance(NPC->currentOrigin, level.combatPoints[NPCInfo->combatPoint].origin)<200) { Boba_Printf("BLOCKED: Just Teleporting There"); G_SetOrigin(NPC, level.combatPoints[NPCInfo->combatPoint].origin); } else { Boba_Printf("BLOCKED: Attempting Jump"); if (IsOnAPath) { if (NPC_TryJump(NPCInfo->blockedTargetPosition)) { } else { Boba_Printf(" Failed"); } } else if (EnemyRecentlySeen) { if (NPC_TryJump(NPCInfo->enemyLastSeenLocation)) { } else { Boba_Printf(" Failed"); } } } } NPC_UpdateAngles( qtrue, qtrue ); return true; }