/* ============= ai_run The monster has an enemy it is trying to kill ============= */ void ai_run( float dist ) { vec3_t tmpv; if ( k_bloodfest ) { if ( (int)self->s.v.flags & FL_SWIM ) { dist *= 5; // let fish swim faster in bloodfest mode. } else if ( self->bloodfest_boss ) { dist *= 2; // let boss move faster } } movedist = dist; // see if the enemy is dead if ( ISDEAD( PROG_TO_EDICT( self->s.v.enemy ) ) || ( (int)PROG_TO_EDICT( self->s.v.enemy )->s.v.flags & FL_NOTARGET ) ) { self->s.v.enemy = EDICT_TO_PROG( world ); // FIXME: look all around for other targets if ( self->oldenemy && ISLIVE( self->oldenemy ) && !( (int)self->oldenemy->s.v.flags & FL_NOTARGET ) ) { self->s.v.enemy = EDICT_TO_PROG( self->oldenemy ); HuntTarget (); } else { if ( !self->movetarget || self->movetarget == world ) { if ( self->th_stand ) self->th_stand(); } else { if ( self->th_walk ) self->th_walk(); } return; } } self->show_hostile = g_globalvars.time + 1; // wake up other monsters // check knowledge of enemy enemy_vis = visible( PROG_TO_EDICT( self->s.v.enemy ) ); if ( enemy_vis ) self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds // look for other coop players if ( coop && self->search_time < g_globalvars.time ) { if ( FindTarget() ) { // this is fix for too frequent enemy sighting, required for bloodfest mode. if ( !visible( PROG_TO_EDICT( self->s.v.enemy ) ) ) { self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds } return; } } enemy_infront = infront( PROG_TO_EDICT( self->s.v.enemy ) ); enemy_range = range( PROG_TO_EDICT( self->s.v.enemy ) ); VectorSubtract( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, self->s.v.origin, tmpv); enemy_yaw = vectoyaw( tmpv ); if ( self->attack_state == AS_MISSILE ) { //dprint ("ai_run_missile\n"); ai_run_missile(); return; } if ( self->attack_state == AS_MELEE ) { //dprint ("ai_run_melee\n"); ai_run_melee(); return; } if ( CheckAnyAttack() ) return; // beginning an attack if ( self->attack_state == AS_SLIDING ) { ai_run_slide(); return; } // head straight in movetogoal( dist ); // done in C code... }
/* ============= ai_run The monster has an enemy it is trying to kill ============= */ void ai_run (edict_t *self, float dist) { vec3_t v; edict_t *tempgoal; edict_t *save; bool newcourse; edict_t *marker; float d1, d2; trace_t tr; vec3_t v_forward, v_right; float left, center, right; vec3_t left_target, right_target; // if we're going to a combat point, just proceed if (self->monsterinfo.aiflags & AI_COMBAT_POINT) { M_MoveToGoal (self, dist); return; } if (self->monsterinfo.aiflags & AI_SOUND_TARGET) { VectorSubtract (self->s.origin, self->enemy->s.origin, v); if (VectorLength(v) < 64) { self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND); self->monsterinfo.stand (self); return; } M_MoveToGoal (self, dist); if (!FindTarget (self)) return; } if (ai_checkattack (self, dist)) return; if (self->monsterinfo.attack_state == AS_SLIDING) { ai_run_slide (self, dist); return; } if (enemy_vis) { M_MoveToGoal (self, dist); self->monsterinfo.aiflags &= ~AI_LOST_SIGHT; VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting); self->monsterinfo.trail_time = level.time; return; } #ifdef AI_FIXME // coop will change to another enemy if visible if (coop->integer) { // FIXME: insane guys get mad with this, which causes crashes! if (FindTarget (self)) return; } #endif if ((self->monsterinfo.search_time) && (level.time > (self->monsterinfo.search_time + 20000))) { M_MoveToGoal (self, dist); self->monsterinfo.search_time = 0; return; } save = self->goalentity; tempgoal = G_Spawn(); self->goalentity = tempgoal; newcourse = false; if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT)) { // just lost sight of the player, decide where to go first self->monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN); self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP); newcourse = true; } if (self->monsterinfo.aiflags & AI_PURSUE_NEXT) { self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT; // give ourself more time since we got this far self->monsterinfo.search_time = level.time + 5000; if (self->monsterinfo.aiflags & AI_PURSUE_TEMP) { self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP; marker = NULL; VectorCopy (self->monsterinfo.saved_goal, self->monsterinfo.last_sighting); newcourse = true; } else if (self->monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN) { self->monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN; marker = G_PlayerTrail_PickFirst (self); } else { marker = G_PlayerTrail_PickNext (self); } if (marker) { VectorCopy (marker->s.origin, self->monsterinfo.last_sighting); self->monsterinfo.trail_time = marker->timeStamp; self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW]; newcourse = true; } } VectorSubtract (self->s.origin, self->monsterinfo.last_sighting, v); d1 = VectorLength(v); if (d1 <= dist) { self->monsterinfo.aiflags |= AI_PURSUE_NEXT; dist = d1; } VectorCopy (self->monsterinfo.last_sighting, self->goalentity->s.origin); if (newcourse) { G_Trace (&tr, self->s.origin, self->r.mins, self->r.maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID); if (tr.fraction < 1) { VectorSubtract (self->goalentity->s.origin, self->s.origin, v); d1 = VectorLength(v); center = tr.fraction; d2 = d1 * ((center+1)/2); self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v); AngleVectors(self->s.angles, v_forward, v_right, NULL); VectorSet(v, d2, -16, 0); G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target); G_Trace (&tr, self->s.origin, self->r.mins, self->r.maxs, left_target, self, MASK_PLAYERSOLID); left = tr.fraction; VectorSet(v, d2, 16, 0); G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target); G_Trace (&tr, self->s.origin, self->r.mins, self->r.maxs, right_target, self, MASK_PLAYERSOLID); right = tr.fraction; center = (d1*center)/d2; if (left >= center && left > right) { if (left < 1) { VectorSet(v, d2 * left * 0.5, -16, 0); G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target); } VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal); self->monsterinfo.aiflags |= AI_PURSUE_TEMP; VectorCopy (left_target, self->goalentity->s.origin); VectorCopy (left_target, self->monsterinfo.last_sighting); VectorSubtract (self->goalentity->s.origin, self->s.origin, v); self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v); } else if (right >= center && right > left) { if (right < 1) { VectorSet(v, d2 * right * 0.5, 16, 0); G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target); } VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal); self->monsterinfo.aiflags |= AI_PURSUE_TEMP; VectorCopy (right_target, self->goalentity->s.origin); VectorCopy (right_target, self->monsterinfo.last_sighting); VectorSubtract (self->goalentity->s.origin, self->s.origin, v); self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v); } } } M_MoveToGoal (self, dist); G_FreeEdict(tempgoal); if (self) self->goalentity = save; }