/* void NPC_HailSquadMate (gentity_t *squadMate) FIXME: they should know who the hail came form so they know who to respond to if it's unfinished FIXME: Should we queue up multiple hails? Or only respond to last one? */ void NPC_HailSquadMate (gentity_t *self, gentity_t *squadMate) { if(squadMate->NPC->aiFlags & NPCAI_AWAITING_COMM) {//Already hailed them //FIXME: Make sure you were last one to hail them before doing this? NPC_SetSayState(squadMate, self, Q_irand(SAY_BADHAIL1, SAY_BADHAIL4)); squadMate->NPC->commWaitTime = level.time + COMM_WAIT_TIME; } else { squadMate->NPC->aiFlags |= NPCAI_AWAITING_COMM; squadMate->NPC->commWaitTime = level.time + COMM_WAIT_TIME; } }
void NPC_RecieveCommand(gentity_t *commander, gentity_t *self, int command, const char *extra) { gentity_t *commTarg = NULL; gentity_t *next; if(extra && extra[0]) {//Find target of command, if we can //next = Munro;//Munro is a global pointer to the player? next = &g_entities[0]; while(next->client->follower)//This is the linked list of your followers... { next = next->client->follower; if(Q_stricmp(extra, next->script_targetname) == 0) {//Found the person we're hailing commTarg = next; break; } } } switch(command) { case CMD_REGROUP: //Get back into normal BS_FORMATION bState self->NPC->behaviorState = BS_FORMATION; //Set a position? Only if don't have one? How would we choose? //Should we have a func that finds which unfilled position you're closest to??? break; case CMD_GUARD: //Go into BS_STAND_GUARD bState self->NPC->behaviorState = BS_STAND_GUARD; break; case CMD_RETREAT: //Find farthest path point from enemy that is in PVS of leader and head there (BS_FORMATION) //set FPOS to FPOS_NONE??? How do we know when to regroup? Wait for manual command? if(self->enemy && self->NPC->iSquadPathIndex!=-1) { NPC_BuildSquadPointDistances( self, self->enemy->currentOrigin, &squadPaths[self->NPC->iSquadPathIndex], WAYPOINT_NONE ); } else {//If no squadpath, should we find some other way to retreat? goto cannot_comply; } break; case CMD_COVER: if(commTarg == NULL) { goto cannot_comply; } //self->NPC->behaviorState = BS_COVER; self->NPC->coverTarg = commTarg; break; case CMD_ESCORT: if(commTarg == NULL) { goto cannot_comply; } //self->NPC->behaviorState = BS_COVER; self->NPC->coverTarg = commTarg; break; case CMD_UNKNOWN: //TempBState- turn to player and say "copy that again, sir?" or "I didn't quite get that" or "what?" or "I think I got some interference, can you repeat that?" NPC_SetSayState(self, commander, Q_irand(SAY_BADCOMM1, SAY_BADCOMM4)); return; break; } //Say "copy" or "yes sir" or "okay" or "gotcha" or "right" NPC_SetSayState(self, commander, Q_irand(SAY_ACKCOMM1, SAY_ACKCOMM4)); return; cannot_comply: //say "can't do that, sir!" or "no way" or something NPC_SetSayState(self, commander, Q_irand(SAY_REFCOMM1, SAY_REFCOMM4)); }
void NPC_HandleAIFlags (void) { //FIXME: make these flags checks a function call like NPC_CheckAIFlagsAndTimers if ( NPCInfo->aiFlags & NPCAI_LOST ) {//Print that you need help! //FIXME: shouldn't remove this just yet if cg_draw needs it NPCInfo->aiFlags &= ~NPCAI_LOST; /* if ( showWaypoints ) { Q3_DebugPrint(WL_WARNING, "%s can't navigate to target %s (my wp: %d, goal wp: %d)\n", NPC->targetname, NPCInfo->goalEntity->targetname, NPC->waypoint, NPCInfo->goalEntity->waypoint ); } */ if ( NPCInfo->goalEntity && NPCInfo->goalEntity == NPC->enemy ) {//We can't nav to our enemy //Drop enemy and see if we should search for him NPC_LostEnemyDecideChase(); } } if ( NPCInfo->aiFlags & NPCAI_AWAITING_COMM ) { if(NPCInfo->commWaitTime < level.time) { //FIXME: we shouldn't assume team_leader, we should remember who sent this hail! NPC_SetSayState(NPC, NPC->client->team_leader, Q_irand(SAY_BADHAIL1, SAY_BADHAIL4)); NPCInfo->aiFlags &= ~NPCAI_AWAITING_COMM; } } /* NPCInfo->canShove = qfalse; //flag never gets set in current nav implementation if (NPCInfo->aiFlags & NPCAI_BLOCKED) { NPCInfo->consecutiveBlockedMoves++; NPCInfo->blockedDebounceTime = level.time + 1000;//Remember you were blocked for a whole second //If totally blocked, should we see if we can jump the obstacle? if(NPCInfo->blockingEntNum == ENTITYNUM_WORLD)//WORLD {//Can't go anywhere G_ActivateBehavior( NPC, BSET_STUCK); //If you're in formation, what do we do here? } else { gentity_t *blocker = &g_entities[NPCInfo->blockingEntNum]; if( NPCInfo->consecutiveBlockedMoves > 10 ) {//Okay, shove them out of the way! if(NPCInfo->shoveCount > 3) {//Already tried shoving 4 times, just stand here NPCInfo->canShove = qfalse; } else { NPCInfo->canShove = qtrue; } } if(blocker->client && blocker->client->playerTeam == NPC->client->playerTeam) {//Should we ask it to get out of the way? //FIXME: NPC_SetSayBState(NPC, blocker, Q_irand(SAY_MOVEIT1, SAY_MOVEIT4);// ? if(NPCInfo->blockedSpeechDebounceTime < level.time) { if ( NPC->behaviorSet[BSET_BLOCKED] ) { G_ActivateBehavior( NPC, BSET_BLOCKED); } else { G_AddVoiceEvent( NPC, Q_irand(EV_BLOCKED1, EV_BLOCKED3), 0 ); } #ifdef _DEBUG //gi.Printf( "%s: 'Hey, %s, move it!'\n", NPC->targetname, blocker->targetname ); #endif //NPCInfo->blockedSpeechDebounceTime = level.time + 10000;//FIXME: make a define //Ok, need to make it get out of the way... } } else if((blocker->client || blocker->takedamage) && blocker->health > 0 && blocker->health < 200 ) {//Attack it!? Set enemy and temp behavior? Hmm... //Careful, what if it's explosive? G_SetEnemy( NPC, blocker ); if( NPCInfo->consecutiveBlockedMoves == 30 ) {//Blocked for three seconds straight G_ActivateBehavior( NPC, BSET_BLOCKED); } } } } else if(NPCInfo->blockedDebounceTime < level.time) {//Only clear if haven't been blocked for a whole second NPCInfo->consecutiveBlockedMoves = 0; NPCInfo->shoveCount = 0; } if(NPCInfo->shoveDebounce < level.time) {//We have shoved for 1 second at least NPCInfo->lastShoveDir = 0.0f; } //NAV_ClearBlockedInfo(NPC); */ //MRJ Request: if ( NPCInfo->aiFlags & NPCAI_GREET_ALLIES && !NPC->enemy )//what if "enemy" is the greetEnt? {//If no enemy, look for teammates to greet //FIXME: don't say hi to the same guy over and over again. if ( NPCInfo->greetingDebounceTime < level.time ) {//Has been at least 2 seconds since we greeted last if ( !NPCInfo->greetEnt ) {//Find a teammate whom I'm facing and who is facing me and within 128 NPCInfo->greetEnt = NPC_PickAlly( qtrue, 128, qtrue, qtrue ); } if ( NPCInfo->greetEnt && !Q_irand(0, 5) ) {//Start greeting someone qboolean greeted = qfalse; //TODO: If have a greetscript, run that instead? //FIXME: make them greet back? if( !Q_irand( 0, 2 ) ) {//Play gesture anim (press gesture button?) greeted = qtrue; NPC_SetAnim( NPC, SETANIM_TORSO, Q_irand( BOTH_GESTURE1, BOTH_GESTURE3 ), SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD ); //NOTE: play full-body gesture if not moving? } if( !Q_irand( 0, 2 ) ) {//Play random voice greeting sound greeted = qtrue; //FIXME: need NPC sound sets G_AddVoiceEvent( NPC, Q_irand(EV_GREET1, EV_GREET3), 2000 ); } if( !Q_irand( 0, 1 ) ) {//set looktarget to them for a second or two greeted = qtrue; NPC_TempLookTarget( NPC, NPCInfo->greetEnt->s.number, 1000, 3000 ); } if ( greeted ) {//Did at least one of the things above //Don't greet again for 2 - 4 seconds NPCInfo->greetingDebounceTime = level.time + Q_irand( 2000, 4000 ); NPCInfo->greetEnt = NULL; } } } } }