public static edict_t PickFirst(edict_t self) { if (!PlayerTrail.trail_active) { return(null); } var marker = PlayerTrail.trail_head; for (var n = PlayerTrail.TRAIL_LENGTH; n > 0; n--) { if (PlayerTrail.trail[marker].timestamp <= self.monsterinfo.trail_time) { marker = PlayerTrail.NEXT(marker); } else { break; } } if (GameUtil.visible(self, PlayerTrail.trail[marker])) { return(PlayerTrail.trail[marker]); } if (GameUtil.visible(self, PlayerTrail.trail[PlayerTrail.PREV(marker)])) { return(PlayerTrail.trail[PlayerTrail.PREV(marker)]); } return(PlayerTrail.trail[marker]); }
public static void M_ReactToDamage(edict_t targ, edict_t attacker) { if (null != attacker.client && 0 != (attacker.svflags & Defines.SVF_MONSTER)) { return; } if (attacker == targ || attacker == targ.enemy) { return; } // if we are a good guy monster and our attacker is a player // or another good guy, do not get mad at them if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) { if (attacker.client != null || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0) { return; } } // we now know that we are not both good guys // if attacker is a client, get mad at them because he's good and we're // not if (attacker.client != null) { targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET; // this can only happen in coop (both new and old enemies are // clients) // only switch if can't see the current enemy if (targ.enemy != null && targ.enemy.client != null) { if (GameUtil.visible(targ, targ.enemy)) { targ.oldenemy = attacker; return; } targ.oldenemy = targ.enemy; } targ.enemy = attacker; if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) { GameUtil.FoundTarget(targ); } return; } // it's the same base (walk/swim/fly) type and a different classname and // it's not a tank // (they spray too much), get mad at them if ((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM)) && !targ.classname.Equals(attacker.classname) && !attacker.classname.Equals("monster_tank") && !attacker.classname.Equals("monster_supertank") && !attacker.classname.Equals("monster_makron") && !attacker.classname.Equals("monster_jorg")) { if (targ.enemy != null && targ.enemy.client != null) { targ.oldenemy = targ.enemy; } targ.enemy = attacker; if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) { GameUtil.FoundTarget(targ); } } // if they *meant* to shoot us, then shoot back else if (attacker.enemy == targ) { if (targ.enemy != null && targ.enemy.client != null) { targ.oldenemy = targ.enemy; } targ.enemy = attacker; if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) { GameUtil.FoundTarget(targ); } } // otherwise get mad at whoever they are mad at (help our buddy) unless // it is us! else if (attacker.enemy != null && attacker.enemy != targ) { if (targ.enemy != null && targ.enemy.client != null) { targ.oldenemy = targ.enemy; } targ.enemy = attacker.enemy; if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) { GameUtil.FoundTarget(targ); } } }
/** * Decides if we're going to attack or do something else used by ai_run and * ai_stand. * * .enemy Will be world if not currently angry at anyone. * * .movetarget The next path spot to walk toward. If .enemy, ignore * .movetarget. When an enemy is killed, the monster will try to return to * it's path. * * .hunt_time Set to time + something when the player is in sight, but * movement straight for him is blocked. This causes the monster to use wall * following code for movement direction instead of sighting on the player. * * .ideal_yaw A yaw angle of the intended direction, which will be turned * towards at up to 45 deg / state. If the enemy is in view and hunt_time is * not active, this will be the exact line towards the enemy. * * .pausetime A monster will leave it's stand state and head towards it's * .movetarget when time > .pausetime. * * walkmove(angle, speed) primitive is all or nothing */ public static bool ai_checkattack(edict_t self, float dist) { float[] temp = { 0, 0, 0 }; bool hesDeadJim; // this causes monsters to run blindly to the combat point w/o firing if (self.goalentity != null) { if ((self.monsterinfo.aiflags & Defines.AI_COMBAT_POINT) != 0) { return(false); } if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) { if (GameBase.level.time - self.enemy.teleport_time > 5.0) { if (self.goalentity == self.enemy) { if (self.movetarget != null) { self.goalentity = self.movetarget; } else { self.goalentity = null; } } self.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET; if ((self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND) != 0) { self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); } } else { self.show_hostile = (int)GameBase.level.time + 1; return(false); } } } GameAI.enemy_vis = false; // see if the enemy is dead hesDeadJim = false; if (null == self.enemy || !self.enemy.inuse) { hesDeadJim = true; } else if ((self.monsterinfo.aiflags & Defines.AI_MEDIC) != 0) { if (self.enemy.health > 0) { hesDeadJim = true; self.monsterinfo.aiflags &= ~Defines.AI_MEDIC; } } else { if ((self.monsterinfo.aiflags & Defines.AI_BRUTAL) != 0) { if (self.enemy.health <= -80) { hesDeadJim = true; } } else { if (self.enemy.health <= 0) { hesDeadJim = true; } } } if (hesDeadJim) { self.enemy = null; // FIXME: look all around for other targets if (self.oldenemy != null && self.oldenemy.health > 0) { self.enemy = self.oldenemy; self.oldenemy = null; GameAI.HuntTarget(self); } else { if (self.movetarget != null) { self.goalentity = self.movetarget; self.monsterinfo.walk.think(self); } else { // we need the pausetime otherwise the stand code // will just revert to walking with no target and // the monsters will wonder around aimlessly trying // to hunt the world entity self.monsterinfo.pausetime = GameBase.level.time + 100000000; self.monsterinfo.stand.think(self); } return(true); } } self.show_hostile = (int)GameBase.level.time + 1; // wake up other // monsters check knowledge of enemy GameAI.enemy_vis = GameUtil.visible(self, self.enemy); if (GameAI.enemy_vis) { self.monsterinfo.search_time = GameBase.level.time + 5; Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting); } GameAI.enemy_infront = GameUtil.infront(self, self.enemy); GameAI.enemy_range = GameUtil.range(self, self.enemy); Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp); GameAI.enemy_yaw = Math3D.vectoyaw(temp); // JDC self.ideal_yaw = enemy_yaw; if (self.monsterinfo.attack_state == Defines.AS_MISSILE) { GameAI.ai_run_missile(self); return(true); } if (self.monsterinfo.attack_state == Defines.AS_MELEE) { GameAI.ai_run_melee(self); return(true); } // if enemy is not currently visible, we will never attack if (!GameAI.enemy_vis) { return(false); } return(self.monsterinfo.checkattack.think(self)); }