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