1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 /*
21 ==============================================================================
22
23 flyer
24
25 ==============================================================================
26 */
27
28 #include "g_local.h"
29 #include "m_flyer.h"
30
31 qboolean visible (edict_t *self, edict_t *other);
32
33 static int nextmove; // Used for start/stop frames
34
35 static int sound_sight;
36 static int sound_idle;
37 static int sound_pain1;
38 static int sound_pain2;
39 static int sound_slash;
40 static int sound_sproing;
41 static int sound_die;
42
43
44 void flyer_check_melee(edict_t *self);
45 void flyer_loop_melee (edict_t *self);
46 void flyer_melee (edict_t *self);
47 void flyer_setstart (edict_t *self);
48 void flyer_stand (edict_t *self);
49 void flyer_nextmove (edict_t *self);
50
51
flyer_sight(edict_t * self,edict_t * other)52 void flyer_sight (edict_t *self, edict_t *other)
53 {
54 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
55 }
56
flyer_idle(edict_t * self)57 void flyer_idle (edict_t *self)
58 {
59 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
60 }
61
flyer_pop_blades(edict_t * self)62 void flyer_pop_blades (edict_t *self)
63 {
64 gi.sound (self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0);
65 }
66
67
68 mframe_t flyer_frames_stand [] =
69 {
70 ai_stand, 0, NULL,
71 ai_stand, 0, NULL,
72 ai_stand, 0, NULL,
73 ai_stand, 0, NULL,
74 ai_stand, 0, NULL,
75 ai_stand, 0, NULL,
76 ai_stand, 0, NULL,
77 ai_stand, 0, NULL,
78 ai_stand, 0, NULL,
79 ai_stand, 0, NULL,
80 ai_stand, 0, NULL,
81 ai_stand, 0, NULL,
82 ai_stand, 0, NULL,
83 ai_stand, 0, NULL,
84 ai_stand, 0, NULL,
85 ai_stand, 0, NULL,
86 ai_stand, 0, NULL,
87 ai_stand, 0, NULL,
88 ai_stand, 0, NULL,
89 ai_stand, 0, NULL,
90 ai_stand, 0, NULL,
91 ai_stand, 0, NULL,
92 ai_stand, 0, NULL,
93 ai_stand, 0, NULL,
94 ai_stand, 0, NULL,
95 ai_stand, 0, NULL,
96 ai_stand, 0, NULL,
97 ai_stand, 0, NULL,
98 ai_stand, 0, NULL,
99 ai_stand, 0, NULL,
100 ai_stand, 0, NULL,
101 ai_stand, 0, NULL,
102 ai_stand, 0, NULL,
103 ai_stand, 0, NULL,
104 ai_stand, 0, NULL,
105 ai_stand, 0, NULL,
106 ai_stand, 0, NULL,
107 ai_stand, 0, NULL,
108 ai_stand, 0, NULL,
109 ai_stand, 0, NULL,
110 ai_stand, 0, NULL,
111 ai_stand, 0, NULL,
112 ai_stand, 0, NULL,
113 ai_stand, 0, NULL,
114 ai_stand, 0, NULL
115 };
116 mmove_t flyer_move_stand = {FRAME_stand01, FRAME_stand45, flyer_frames_stand, NULL};
117
118
119 mframe_t flyer_frames_walk [] =
120 {
121 ai_walk, 5, NULL,
122 ai_walk, 5, NULL,
123 ai_walk, 5, NULL,
124 ai_walk, 5, NULL,
125 ai_walk, 5, NULL,
126 ai_walk, 5, NULL,
127 ai_walk, 5, NULL,
128 ai_walk, 5, NULL,
129 ai_walk, 5, NULL,
130 ai_walk, 5, NULL,
131 ai_walk, 5, NULL,
132 ai_walk, 5, NULL,
133 ai_walk, 5, NULL,
134 ai_walk, 5, NULL,
135 ai_walk, 5, NULL,
136 ai_walk, 5, NULL,
137 ai_walk, 5, NULL,
138 ai_walk, 5, NULL,
139 ai_walk, 5, NULL,
140 ai_walk, 5, NULL,
141 ai_walk, 5, NULL,
142 ai_walk, 5, NULL,
143 ai_walk, 5, NULL,
144 ai_walk, 5, NULL,
145 ai_walk, 5, NULL,
146 ai_walk, 5, NULL,
147 ai_walk, 5, NULL,
148 ai_walk, 5, NULL,
149 ai_walk, 5, NULL,
150 ai_walk, 5, NULL,
151 ai_walk, 5, NULL,
152 ai_walk, 5, NULL,
153 ai_walk, 5, NULL,
154 ai_walk, 5, NULL,
155 ai_walk, 5, NULL,
156 ai_walk, 5, NULL,
157 ai_walk, 5, NULL,
158 ai_walk, 5, NULL,
159 ai_walk, 5, NULL,
160 ai_walk, 5, NULL,
161 ai_walk, 5, NULL,
162 ai_walk, 5, NULL,
163 ai_walk, 5, NULL,
164 ai_walk, 5, NULL,
165 ai_walk, 5, NULL
166 };
167 mmove_t flyer_move_walk = {FRAME_stand01, FRAME_stand45, flyer_frames_walk, NULL};
168
169 mframe_t flyer_frames_run [] =
170 {
171 ai_run, 10, NULL,
172 ai_run, 10, NULL,
173 ai_run, 10, NULL,
174 ai_run, 10, NULL,
175 ai_run, 10, NULL,
176 ai_run, 10, NULL,
177 ai_run, 10, NULL,
178 ai_run, 10, NULL,
179 ai_run, 10, NULL,
180 ai_run, 10, NULL,
181 ai_run, 10, NULL,
182 ai_run, 10, NULL,
183 ai_run, 10, NULL,
184 ai_run, 10, NULL,
185 ai_run, 10, NULL,
186 ai_run, 10, NULL,
187 ai_run, 10, NULL,
188 ai_run, 10, NULL,
189 ai_run, 10, NULL,
190 ai_run, 10, NULL,
191 ai_run, 10, NULL,
192 ai_run, 10, NULL,
193 ai_run, 10, NULL,
194 ai_run, 10, NULL,
195 ai_run, 10, NULL,
196 ai_run, 10, NULL,
197 ai_run, 10, NULL,
198 ai_run, 10, NULL,
199 ai_run, 10, NULL,
200 ai_run, 10, NULL,
201 ai_run, 10, NULL,
202 ai_run, 10, NULL,
203 ai_run, 10, NULL,
204 ai_run, 10, NULL,
205 ai_run, 10, NULL,
206 ai_run, 10, NULL,
207 ai_run, 10, NULL,
208 ai_run, 10, NULL,
209 ai_run, 10, NULL,
210 ai_run, 10, NULL,
211 ai_run, 10, NULL,
212 ai_run, 10, NULL,
213 ai_run, 10, NULL,
214 ai_run, 10, NULL,
215 ai_run, 10, NULL
216 };
217 mmove_t flyer_move_run = {FRAME_stand01, FRAME_stand45, flyer_frames_run, NULL};
218
flyer_run(edict_t * self)219 void flyer_run (edict_t *self)
220 {
221 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
222 self->monsterinfo.currentmove = &flyer_move_stand;
223 else
224 self->monsterinfo.currentmove = &flyer_move_run;
225 }
226
flyer_walk(edict_t * self)227 void flyer_walk (edict_t *self)
228 {
229 self->monsterinfo.currentmove = &flyer_move_walk;
230 }
231
flyer_stand(edict_t * self)232 void flyer_stand (edict_t *self)
233 {
234 self->monsterinfo.currentmove = &flyer_move_stand;
235 }
236
237 mframe_t flyer_frames_start [] =
238 {
239 ai_move, 0, NULL,
240 ai_move, 0, NULL,
241 ai_move, 0, NULL,
242 ai_move, 0, NULL,
243 ai_move, 0, NULL,
244 ai_move, 0, flyer_nextmove
245 };
246 mmove_t flyer_move_start = {FRAME_start01, FRAME_start06, flyer_frames_start, NULL};
247
248 mframe_t flyer_frames_stop [] =
249 {
250 ai_move, 0, NULL,
251 ai_move, 0, NULL,
252 ai_move, 0, NULL,
253 ai_move, 0, NULL,
254 ai_move, 0, NULL,
255 ai_move, 0, NULL,
256 ai_move, 0, flyer_nextmove
257 };
258 mmove_t flyer_move_stop = {FRAME_stop01, FRAME_stop07, flyer_frames_stop, NULL};
259
flyer_stop(edict_t * self)260 void flyer_stop (edict_t *self)
261 {
262 self->monsterinfo.currentmove = &flyer_move_stop;
263 }
264
flyer_start(edict_t * self)265 void flyer_start (edict_t *self)
266 {
267 self->monsterinfo.currentmove = &flyer_move_start;
268 }
269
270
271 mframe_t flyer_frames_rollright [] =
272 {
273 ai_move, 0, NULL,
274 ai_move, 0, NULL,
275 ai_move, 0, NULL,
276 ai_move, 0, NULL,
277 ai_move, 0, NULL,
278 ai_move, 0, NULL,
279 ai_move, 0, NULL,
280 ai_move, 0, NULL,
281 ai_move, 0, NULL
282 };
283 mmove_t flyer_move_rollright = {FRAME_rollr01, FRAME_rollr09, flyer_frames_rollright, NULL};
284
285 mframe_t flyer_frames_rollleft [] =
286 {
287 ai_move, 0, NULL,
288 ai_move, 0, NULL,
289 ai_move, 0, NULL,
290 ai_move, 0, NULL,
291 ai_move, 0, NULL,
292 ai_move, 0, NULL,
293 ai_move, 0, NULL,
294 ai_move, 0, NULL,
295 ai_move, 0, NULL
296 };
297 mmove_t flyer_move_rollleft = {FRAME_rollf01, FRAME_rollf09, flyer_frames_rollleft, NULL};
298
299 mframe_t flyer_frames_pain3 [] =
300 {
301 ai_move, 0, NULL,
302 ai_move, 0, NULL,
303 ai_move, 0, NULL,
304 ai_move, 0, NULL
305 };
306 mmove_t flyer_move_pain3 = {FRAME_pain301, FRAME_pain304, flyer_frames_pain3, flyer_run};
307
308 mframe_t flyer_frames_pain2 [] =
309 {
310 ai_move, 0, NULL,
311 ai_move, 0, NULL,
312 ai_move, 0, NULL,
313 ai_move, 0, NULL
314 };
315 mmove_t flyer_move_pain2 = {FRAME_pain201, FRAME_pain204, flyer_frames_pain2, flyer_run};
316
317 mframe_t flyer_frames_pain1 [] =
318 {
319 ai_move, 0, NULL,
320 ai_move, 0, NULL,
321 ai_move, 0, NULL,
322 ai_move, 0, NULL,
323 ai_move, 0, NULL,
324 ai_move, 0, NULL,
325 ai_move, 0, NULL,
326 ai_move, 0, NULL,
327 ai_move, 0, NULL
328 };
329 mmove_t flyer_move_pain1 = {FRAME_pain101, FRAME_pain109, flyer_frames_pain1, flyer_run};
330
331 mframe_t flyer_frames_defense [] =
332 {
333 ai_move, 0, NULL,
334 ai_move, 0, NULL,
335 ai_move, 0, NULL, // Hold this frame
336 ai_move, 0, NULL,
337 ai_move, 0, NULL,
338 ai_move, 0, NULL
339 };
340 mmove_t flyer_move_defense = {FRAME_defens01, FRAME_defens06, flyer_frames_defense, NULL};
341
342 mframe_t flyer_frames_bankright [] =
343 {
344 ai_move, 0, NULL,
345 ai_move, 0, NULL,
346 ai_move, 0, NULL,
347 ai_move, 0, NULL,
348 ai_move, 0, NULL,
349 ai_move, 0, NULL,
350 ai_move, 0, NULL
351 };
352 mmove_t flyer_move_bankright = {FRAME_bankr01, FRAME_bankr07, flyer_frames_bankright, NULL};
353
354 mframe_t flyer_frames_bankleft [] =
355 {
356 ai_move, 0, NULL,
357 ai_move, 0, NULL,
358 ai_move, 0, NULL,
359 ai_move, 0, NULL,
360 ai_move, 0, NULL,
361 ai_move, 0, NULL,
362 ai_move, 0, NULL
363 };
364 mmove_t flyer_move_bankleft = {FRAME_bankl01, FRAME_bankl07, flyer_frames_bankleft, NULL};
365
366
flyer_fire(edict_t * self,int flash_number)367 void flyer_fire (edict_t *self, int flash_number)
368 {
369 vec3_t start;
370 vec3_t forward, right;
371 vec3_t end;
372 vec3_t dir;
373 int effect;
374
375 if ((self->s.frame == FRAME_attak204) || (self->s.frame == FRAME_attak207) || (self->s.frame == FRAME_attak210))
376 effect = EF_HYPERBLASTER;
377 else
378 effect = 0;
379 AngleVectors (self->s.angles, forward, right, NULL);
380 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
381
382 VectorCopy (self->enemy->s.origin, end);
383 end[2] += self->enemy->viewheight;
384 VectorSubtract (end, start, dir);
385
386 monster_fire_blaster (self, start, dir, 1, 1000, flash_number, effect);
387 }
388
flyer_fireleft(edict_t * self)389 void flyer_fireleft (edict_t *self)
390 {
391 flyer_fire (self, MZ2_FLYER_BLASTER_1);
392 }
393
flyer_fireright(edict_t * self)394 void flyer_fireright (edict_t *self)
395 {
396 flyer_fire (self, MZ2_FLYER_BLASTER_2);
397 }
398
399
400 mframe_t flyer_frames_attack2 [] =
401 {
402 ai_charge, 0, NULL,
403 ai_charge, 0, NULL,
404 ai_charge, 0, NULL,
405 ai_charge, -10, flyer_fireleft, // left gun
406 ai_charge, -10, flyer_fireright, // right gun
407 ai_charge, -10, flyer_fireleft, // left gun
408 ai_charge, -10, flyer_fireright, // right gun
409 ai_charge, -10, flyer_fireleft, // left gun
410 ai_charge, -10, flyer_fireright, // right gun
411 ai_charge, -10, flyer_fireleft, // left gun
412 ai_charge, -10, flyer_fireright, // right gun
413 ai_charge, 0, NULL,
414 ai_charge, 0, NULL,
415 ai_charge, 0, NULL,
416 ai_charge, 0, NULL,
417 ai_charge, 0, NULL,
418 ai_charge, 0, NULL
419 };
420 mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames_attack2, flyer_run};
421
422
flyer_slash_left(edict_t * self)423 void flyer_slash_left (edict_t *self)
424 {
425 vec3_t aim;
426
427 VectorSet (aim, MELEE_DISTANCE, self->mins[0], 0);
428 fire_hit (self, aim, 5, 0);
429 gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
430 }
431
flyer_slash_right(edict_t * self)432 void flyer_slash_right (edict_t *self)
433 {
434 vec3_t aim;
435
436 VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 0);
437 fire_hit (self, aim, 5, 0);
438 gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
439 }
440
441 mframe_t flyer_frames_start_melee [] =
442 {
443 ai_charge, 0, flyer_pop_blades,
444 ai_charge, 0, NULL,
445 ai_charge, 0, NULL,
446 ai_charge, 0, NULL,
447 ai_charge, 0, NULL,
448 ai_charge, 0, NULL
449 };
450 mmove_t flyer_move_start_melee = {FRAME_attak101, FRAME_attak106, flyer_frames_start_melee, flyer_loop_melee};
451
452 mframe_t flyer_frames_end_melee [] =
453 {
454 ai_charge, 0, NULL,
455 ai_charge, 0, NULL,
456 ai_charge, 0, NULL
457 };
458 mmove_t flyer_move_end_melee = {FRAME_attak119, FRAME_attak121, flyer_frames_end_melee, flyer_run};
459
460
461 mframe_t flyer_frames_loop_melee [] =
462 {
463 ai_charge, 0, NULL, // Loop Start
464 ai_charge, 0, NULL,
465 ai_charge, 0, flyer_slash_left, // Left Wing Strike
466 ai_charge, 0, NULL,
467 ai_charge, 0, NULL,
468 ai_charge, 0, NULL,
469 ai_charge, 0, NULL,
470 ai_charge, 0, flyer_slash_right, // Right Wing Strike
471 ai_charge, 0, NULL,
472 ai_charge, 0, NULL,
473 ai_charge, 0, NULL,
474 ai_charge, 0, NULL // Loop Ends
475
476 };
477 mmove_t flyer_move_loop_melee = {FRAME_attak107, FRAME_attak118, flyer_frames_loop_melee, flyer_check_melee};
478
flyer_loop_melee(edict_t * self)479 void flyer_loop_melee (edict_t *self)
480 {
481 /* if (random() <= 0.5)
482 self->monsterinfo.currentmove = &flyer_move_attack1;
483 else */
484 self->monsterinfo.currentmove = &flyer_move_loop_melee;
485 }
486
487
488
flyer_attack(edict_t * self)489 void flyer_attack (edict_t *self)
490 {
491 /* if (random() <= 0.5)
492 self->monsterinfo.currentmove = &flyer_move_attack1;
493 else */
494 self->monsterinfo.currentmove = &flyer_move_attack2;
495 }
496
flyer_setstart(edict_t * self)497 void flyer_setstart (edict_t *self)
498 {
499 nextmove = ACTION_run;
500 self->monsterinfo.currentmove = &flyer_move_start;
501 }
502
flyer_nextmove(edict_t * self)503 void flyer_nextmove (edict_t *self)
504 {
505 if (nextmove == ACTION_attack1)
506 self->monsterinfo.currentmove = &flyer_move_start_melee;
507 else if (nextmove == ACTION_attack2)
508 self->monsterinfo.currentmove = &flyer_move_attack2;
509 else if (nextmove == ACTION_run)
510 self->monsterinfo.currentmove = &flyer_move_run;
511 }
512
flyer_melee(edict_t * self)513 void flyer_melee (edict_t *self)
514 {
515 // flyer.nextmove = ACTION_attack1;
516 // self->monsterinfo.currentmove = &flyer_move_stop;
517 self->monsterinfo.currentmove = &flyer_move_start_melee;
518 }
519
flyer_check_melee(edict_t * self)520 void flyer_check_melee(edict_t *self)
521 {
522 if (range (self, self->enemy) == RANGE_MELEE)
523 if (random() <= 0.8)
524 self->monsterinfo.currentmove = &flyer_move_loop_melee;
525 else
526 self->monsterinfo.currentmove = &flyer_move_end_melee;
527 else
528 self->monsterinfo.currentmove = &flyer_move_end_melee;
529 }
530
flyer_pain(edict_t * self,edict_t * other,float kick,int damage)531 void flyer_pain (edict_t *self, edict_t *other, float kick, int damage)
532 {
533 int n;
534
535 if (self->health < (self->max_health / 2))
536 self->s.skinnum = 1;
537
538 if (level.time < self->pain_debounce_time)
539 return;
540
541 self->pain_debounce_time = level.time + 3;
542 if (skill->value == 3)
543 return; // no pain anims in nightmare
544
545 n = rand() % 3;
546 if (n == 0)
547 {
548 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
549 self->monsterinfo.currentmove = &flyer_move_pain1;
550 }
551 else if (n == 1)
552 {
553 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
554 self->monsterinfo.currentmove = &flyer_move_pain2;
555 }
556 else
557 {
558 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
559 self->monsterinfo.currentmove = &flyer_move_pain3;
560 }
561 }
562
563
flyer_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)564 void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
565 {
566 gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
567 BecomeExplosion1(self);
568 }
569
570
571 /*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
572 */
SP_monster_flyer(edict_t * self)573 void SP_monster_flyer (edict_t *self)
574 {
575 if (deathmatch->value)
576 {
577 G_FreeEdict (self);
578 return;
579 }
580
581 // fix a map bug in jail5.bsp
582 if (!Q_stricmp(level.mapname, "jail5") && (self->s.origin[2] == -104))
583 {
584 self->targetname = self->target;
585 self->target = NULL;
586 }
587
588 sound_sight = gi.soundindex ("flyer/flysght1.wav");
589 sound_idle = gi.soundindex ("flyer/flysrch1.wav");
590 sound_pain1 = gi.soundindex ("flyer/flypain1.wav");
591 sound_pain2 = gi.soundindex ("flyer/flypain2.wav");
592 sound_slash = gi.soundindex ("flyer/flyatck2.wav");
593 sound_sproing = gi.soundindex ("flyer/flyatck1.wav");
594 sound_die = gi.soundindex ("flyer/flydeth1.wav");
595
596 gi.soundindex ("flyer/flyatck3.wav");
597
598 self->s.modelindex = gi.modelindex ("models/monsters/flyer/tris.md2");
599 VectorSet (self->mins, -16, -16, -24);
600 VectorSet (self->maxs, 16, 16, 32);
601 self->movetype = MOVETYPE_STEP;
602 self->solid = SOLID_BBOX;
603
604 self->s.sound = gi.soundindex ("flyer/flyidle1.wav");
605
606 self->health = 50;
607 self->mass = 50;
608
609 self->pain = flyer_pain;
610 self->die = flyer_die;
611
612 self->monsterinfo.stand = flyer_stand;
613 self->monsterinfo.walk = flyer_walk;
614 self->monsterinfo.run = flyer_run;
615 self->monsterinfo.attack = flyer_attack;
616 self->monsterinfo.melee = flyer_melee;
617 self->monsterinfo.sight = flyer_sight;
618 self->monsterinfo.idle = flyer_idle;
619
620 gi.linkentity (self);
621
622 self->monsterinfo.currentmove = &flyer_move_stand;
623 self->monsterinfo.scale = MODEL_SCALE;
624
625 flymonster_start (self);
626 }
627