/* ============ AICast_Sight ============ */ void AICast_Sight( gentity_t *ent, gentity_t *other, int lastSight ) { cast_state_t *cs, *ocs; cs = AICast_GetCastState( ent->s.number ); ocs = AICast_GetCastState( other->s.number ); // // call the sightfunc for this cast, so we can play associated sounds, or do any character-specific things // if ( cs->sightfunc ) { // factor in the reaction time if ( AICast_EntityVisible( cs, other->s.number, qfalse ) ) { cs->sightfunc( ent, other, lastSight ); } } if ( other->aiName && other->health <= 0 ) { // they died since we last saw them if ( ocs->deathTime > lastSight ) { if ( !AICast_SameTeam( cs, other->s.number ) ) { AICast_ScriptEvent( cs, "enemysightcorpse", other->aiName ); } else if ( !( cs->castScriptStatus.scriptFlags & SFL_FRIENDLYSIGHTCORPSE_TRIGGERED ) ) { cs->castScriptStatus.scriptFlags |= SFL_FRIENDLYSIGHTCORPSE_TRIGGERED; AICast_ScriptEvent( cs, "friendlysightcorpse", "" ); } } // if this is the first time, call the sight script event } else if ( !lastSight && other->aiName ) { if ( !AICast_SameTeam( cs, other->s.number ) ) { // disabled.. triggered when entering combat mode //AICast_ScriptEvent( cs, "enemysight", other->aiName ); } else { AICast_ScriptEvent( cs, "sight", other->aiName ); } } }
/* ================ AICast_EvaluatePmove Avoidance after the event (leaders instruct AI's to get out the way, AI's instruct other non-moving AI's to get out the way) ================ */ void AICast_EvaluatePmove( int clientnum, pmove_t *pm ) { cast_state_t *cs, *ocs; int i, ent; bot_goal_t ogoal; //vec3_t pos, dir; cs = AICast_GetCastState( clientnum ); // make sure we are using the right AAS data for this entity (one's that don't get set will default to the player's AAS data) trap_AAS_SetCurrentWorld( cs->aasWorldIndex ); // NOTE: this is only enabled for real clients, so their followers get out of their way //if (cs->bs) // return; // look through the touchent's to see if we've bumped into something we should avoid, or react to for ( i = 0; i < pm->numtouch; i++ ) { // mark the time, so they can deal with the obstruction in their own think functions cs->blockedTime = level.time; if ( pm->touchents[i] == pm->ps->groundEntityNum ) { continue; } // if they are an AI Cast, inform them of our disposition, and hope that they are reasonable // enough to assist us in our desire to move beyond our current position if ( pm->touchents[i] < aicast_maxclients ) { if ( !AICast_EntityVisible( cs, pm->touchents[i], qtrue ) ) { continue; } // if we are inspecting the body, abort if we touch anything if ( cs->bs && cs->bs->enemy >= 0 && g_entities[cs->bs->enemy].health <= 0 ) { cs->bs->enemy = -1; } // anything we touch, should see us AICast_UpdateVisibility( &g_entities[pm->touchents[i]], &g_entities[cs->entityNum], qfalse, qtrue ); ocs = AICast_GetCastState( pm->touchents[i] ); if ( ( ocs->bs ) && ( !( ocs->aiFlags & AIFL_NOAVOID ) ) && ( ( ocs->leaderNum == cs->entityNum ) || ( VectorLength( ocs->bs->velocity ) < 5 ) ) && ( ocs->obstructingTime < ( level.time + 100 ) ) ) { // if they are moving away from us already, let them go if ( VectorLength( ocs->bs->cur_ps.velocity ) > 10 ) { vec3_t v1, v2; VectorSubtract( ocs->bs->origin, g_entities[clientnum].client->ps.velocity, v2 ); VectorNormalize( v2 ); VectorNormalize2( ocs->bs->cur_ps.velocity, v1 ); if ( DotProduct( v1, v2 ) > 0.0 ) { continue; } } if ( ocs->leaderNum >= 0 ) { VectorCopy( g_entities[ocs->leaderNum].r.currentOrigin, ogoal.origin ); ogoal.areanum = BotPointAreaNum( ogoal.origin ); ogoal.entitynum = ocs->leaderNum; if ( ocs->bs && AICast_GetAvoid( ocs, &ogoal, ocs->obstructingPos, qfalse, cs->entityNum ) ) { // give them time to move somewhere else ocs->obstructingTime = level.time + 1000; } } else { if ( ocs->bs && AICast_GetAvoid( ocs, NULL, ocs->obstructingPos, qfalse, cs->entityNum ) ) { // give them time to move somewhere else ocs->obstructingTime = level.time + 1000; } } } } else if ( cs->bs ) { // if we are blocked by a brush entity, see if we can activate it ent = pm->touchents[i]; if ( g_entities[ent].s.modelindex > 0 && g_entities[ent].s.eType == ET_MOVER ) { //find the bsp entity which should be activated in order to remove //the blocking entity if ( !g_entities[ent].isProp && Q_stricmp( g_entities[ent].classname, "func_static" ) && Q_stricmp( g_entities[ent].classname, "func_button" ) && Q_stricmp( g_entities[ent].classname, "func_tram" ) ) { G_Activate( &g_entities[ent], &g_entities[cs->entityNum] ); } } } } }
/* ================ AIFunc_WarriorZombieDefense ================ */ char *AIFunc_WarriorZombieDefense( cast_state_t *cs ) { gentity_t *ent, *enemy; vec3_t enemyDir, vec; float dist; ent = &g_entities[cs->entityNum]; if ( !( ent->flags & FL_DEFENSE_GUARD ) ) { if ( cs->weaponFireTimes[cs->bs->weaponnum] < level.time - 100 ) { return AIFunc_DefaultStart( cs ); } return NULL; } if ( cs->bs->enemy < 0 ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } enemy = &g_entities[cs->bs->enemy]; if ( cs->thinkFuncChangeTime < level.time - 1500 ) { // if we cant see them if ( !AICast_EntityVisible( cs, cs->bs->enemy, qtrue ) ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // if our enemy isn't using a dangerous weapon if ( enemy->client->ps.weapon < WP_LUGER || enemy->client->ps.weapon > WP_CROSS ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // if our enemy isn't looking right at us, abort VectorSubtract( ent->client->ps.origin, enemy->client->ps.origin, vec ); dist = VectorNormalize( vec ); if ( dist > 512 ) { dist = 512; } AngleVectors( enemy->client->ps.viewangles, enemyDir, NULL, NULL ); if ( DotProduct( vec, enemyDir ) < ( 0.98 - 0.2 * ( dist / 512 ) ) ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } } cs->weaponFireTimes[cs->bs->weaponnum] = level.time; if ( !ent->client->ps.torsoTimer ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // face them AICast_AimAtEnemy( cs ); // crouching position, use smaller bounding box trap_EA_Crouch( cs->bs->client ); return NULL; }