4 A monster is in fight mode if it thinks it can effectively attack its
7 When it decides it can't attack, it goes into hunt mode.
11 void SUB_AttackFinished (float normal)
13 self.cnt = 0; // refire count for nightmare
15 ATTACK_FINISHED(self) = time + normal;
18 float CanDamage(entity targ, entity inflictor)
20 if (targ.movetype == MOVETYPE_PUSH)
22 traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
23 if (trace_fraction == 1)
25 if (trace_ent == targ)
30 traceline(inflictor.origin, targ.origin, TRUE, self);
31 if (trace_fraction == 1)
33 traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
34 if (trace_fraction == 1)
36 traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
37 if (trace_fraction == 1)
39 traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
40 if (trace_fraction == 1)
42 traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
43 if (trace_fraction == 1)
49 float(float v) anglemod;
51 void(vector dest) ChooseTurn;
59 //=============================================================================
65 The player is in view, so decide to move or launch an attack
66 Returns FALSE if movement should continue
69 float() GenericCheckAttack =
79 if (vlen(targ.origin - self.origin) > 5000) // long traces are slow
82 // see if any entities are in the way of the shot
83 spot1 = self.origin + self.view_ofs;
84 spot2 = targ.origin + targ.view_ofs;
86 traceline (spot1, spot2, FALSE, self);
88 if (trace_ent != targ)
89 return FALSE; // don't have a clear shot
91 if (trace_inopen && trace_inwater)
92 return FALSE; // sight line crossed contents
94 if (enemy_range == RANGE_MELEE)
104 if (time < ATTACK_FINISHED(self))
107 if (!self.th_missile)
110 if (enemy_range == RANGE_FAR)
113 if (enemy_range == RANGE_MELEE)
116 ATTACK_FINISHED(self) = 0;
118 else if (enemy_range == RANGE_NEAR)
125 else if (enemy_range == RANGE_MID)
135 if (random () < chance)
136 if (self.th_missile ())
138 SUB_AttackFinished (2*random());
150 Stay facing the enemy
155 self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
163 The monster is in a melee attack, so get as close as possible to .enemy
166 float (entity targ) visible;
167 float(entity targ) infront;
168 float(entity targ) range;
170 void(float d) ai_charge =
175 movetogoal (d); // done in C code...
178 void() ai_charge_side =
185 // aim to the left of the enemy for a flyby
187 self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
190 makevectors (self.angles);
191 dtemp = self.enemy.origin - 30*v_right;
192 heading = vectoyaw(dtemp - self.origin);
194 walkmove(heading, 20);
212 return; // removed before stroke
214 delta = self.enemy.origin - self.origin;
216 if (vlen(delta) > 60)
219 ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
220 ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
221 ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
222 traceline(self.origin, self.enemy.origin, FALSE, self);
224 Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); // TODO add force to monster melee attacks?
228 void() ai_melee_side =
236 return; // removed before stroke
240 delta = self.enemy.origin - self.origin;
242 if (vlen(delta) > 60)
244 if (!CanDamage (self.enemy, self))
246 ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
247 ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
248 ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
249 traceline(self.origin, self.enemy.origin, FALSE, self);
250 Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0');