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 parasite
24
25 ==============================================================================
26 */
27
28 #include "g_local.h"
29 #include "m_parasite.h"
30
31
32 static int sound_pain1;
33 static int sound_pain2;
34 static int sound_die;
35 static int sound_launch;
36 static int sound_impact;
37 static int sound_suck;
38 static int sound_reelin;
39 static int sound_sight;
40 static int sound_tap;
41 static int sound_scratch;
42 static int sound_search;
43
44
45 void parasite_stand (edict_t *self);
46 void parasite_start_run (edict_t *self);
47 void parasite_run (edict_t *self);
48 void parasite_walk (edict_t *self);
49 void parasite_start_walk (edict_t *self);
50 void parasite_end_fidget (edict_t *self);
51 void parasite_do_fidget (edict_t *self);
52 void parasite_refidget (edict_t *self);
53
54
parasite_launch(edict_t * self)55 void parasite_launch (edict_t *self)
56 {
57 gi.sound (self, CHAN_WEAPON, sound_launch, 1, ATTN_NORM, 0);
58 }
59
parasite_reel_in(edict_t * self)60 void parasite_reel_in (edict_t *self)
61 {
62 gi.sound (self, CHAN_WEAPON, sound_reelin, 1, ATTN_NORM, 0);
63 }
64
parasite_sight(edict_t * self,edict_t * other)65 void parasite_sight (edict_t *self, edict_t *other)
66 {
67 gi.sound (self, CHAN_WEAPON, sound_sight, 1, ATTN_NORM, 0);
68 }
69
parasite_tap(edict_t * self)70 void parasite_tap (edict_t *self)
71 {
72 gi.sound (self, CHAN_WEAPON, sound_tap, 1, ATTN_IDLE, 0);
73 }
74
parasite_scratch(edict_t * self)75 void parasite_scratch (edict_t *self)
76 {
77 gi.sound (self, CHAN_WEAPON, sound_scratch, 1, ATTN_IDLE, 0);
78 }
79
parasite_search(edict_t * self)80 void parasite_search (edict_t *self)
81 {
82 gi.sound (self, CHAN_WEAPON, sound_search, 1, ATTN_IDLE, 0);
83 }
84
85
86 mframe_t parasite_frames_start_fidget [] =
87 {
88 {ai_stand, 0, NULL},
89 {ai_stand, 0, NULL},
90 {ai_stand, 0, NULL},
91 {ai_stand, 0, NULL}
92 };
93 mmove_t parasite_move_start_fidget = {FRAME_stand18, FRAME_stand21, parasite_frames_start_fidget, parasite_do_fidget};
94
95 mframe_t parasite_frames_fidget [] =
96 {
97 {ai_stand, 0, parasite_scratch},
98 {ai_stand, 0, NULL},
99 {ai_stand, 0, NULL},
100 {ai_stand, 0, parasite_scratch},
101 {ai_stand, 0, NULL},
102 {ai_stand, 0, NULL}
103 };
104 mmove_t parasite_move_fidget = {FRAME_stand22, FRAME_stand27, parasite_frames_fidget, parasite_refidget};
105
106 mframe_t parasite_frames_end_fidget [] =
107 {
108 {ai_stand, 0, parasite_scratch},
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 {ai_stand, 0, NULL}
116 };
117 mmove_t parasite_move_end_fidget = {FRAME_stand28, FRAME_stand35, parasite_frames_end_fidget, parasite_stand};
118
parasite_end_fidget(edict_t * self)119 void parasite_end_fidget (edict_t *self)
120 {
121 self->monsterinfo.currentmove = ¶site_move_end_fidget;
122 }
123
parasite_do_fidget(edict_t * self)124 void parasite_do_fidget (edict_t *self)
125 {
126 self->monsterinfo.currentmove = ¶site_move_fidget;
127 }
128
parasite_refidget(edict_t * self)129 void parasite_refidget (edict_t *self)
130 {
131 if (random() <= 0.8)
132 self->monsterinfo.currentmove = ¶site_move_fidget;
133 else
134 self->monsterinfo.currentmove = ¶site_move_end_fidget;
135 }
136
parasite_idle(edict_t * self)137 void parasite_idle (edict_t *self)
138 {
139 self->monsterinfo.currentmove = ¶site_move_start_fidget;
140 }
141
142
143 mframe_t parasite_frames_stand [] =
144 {
145 {ai_stand, 0, NULL},
146 {ai_stand, 0, NULL},
147 {ai_stand, 0, parasite_tap},
148 {ai_stand, 0, NULL},
149 {ai_stand, 0, parasite_tap},
150 {ai_stand, 0, NULL},
151 {ai_stand, 0, NULL},
152 {ai_stand, 0, NULL},
153 {ai_stand, 0, parasite_tap},
154 {ai_stand, 0, NULL},
155 {ai_stand, 0, parasite_tap},
156 {ai_stand, 0, NULL},
157 {ai_stand, 0, NULL},
158 {ai_stand, 0, NULL},
159 {ai_stand, 0, parasite_tap},
160 {ai_stand, 0, NULL},
161 {ai_stand, 0, parasite_tap}
162 };
163 mmove_t parasite_move_stand = {FRAME_stand01, FRAME_stand17, parasite_frames_stand, parasite_stand};
164
parasite_stand(edict_t * self)165 void parasite_stand (edict_t *self)
166 {
167 self->monsterinfo.currentmove = ¶site_move_stand;
168 }
169
170
171 mframe_t parasite_frames_run [] =
172 {
173 {ai_run, 30, NULL},
174 {ai_run, 30, NULL},
175 {ai_run, 22, NULL},
176 {ai_run, 19, NULL},
177 {ai_run, 24, NULL},
178 {ai_run, 28, NULL},
179 {ai_run, 25, NULL}
180 };
181 mmove_t parasite_move_run = {FRAME_run03, FRAME_run09, parasite_frames_run, NULL};
182
183 mframe_t parasite_frames_start_run [] =
184 {
185 {ai_run, 0, NULL},
186 {ai_run, 30, NULL},
187 };
188 mmove_t parasite_move_start_run = {FRAME_run01, FRAME_run02, parasite_frames_start_run, parasite_run};
189
190 mframe_t parasite_frames_stop_run [] =
191 {
192 {ai_run, 20, NULL},
193 {ai_run, 20, NULL},
194 {ai_run, 12, NULL},
195 {ai_run, 10, NULL},
196 {ai_run, 0, NULL},
197 {ai_run, 0, NULL}
198 };
199 mmove_t parasite_move_stop_run = {FRAME_run10, FRAME_run15, parasite_frames_stop_run, NULL};
200
parasite_start_run(edict_t * self)201 void parasite_start_run (edict_t *self)
202 {
203 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
204 self->monsterinfo.currentmove = ¶site_move_stand;
205 else
206 self->monsterinfo.currentmove = ¶site_move_start_run;
207 }
208
parasite_run(edict_t * self)209 void parasite_run (edict_t *self)
210 {
211 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
212 self->monsterinfo.currentmove = ¶site_move_stand;
213 else
214 self->monsterinfo.currentmove = ¶site_move_run;
215 }
216
217
218 mframe_t parasite_frames_walk [] =
219 {
220 {ai_walk, 30, NULL},
221 {ai_walk, 30, NULL},
222 {ai_walk, 22, NULL},
223 {ai_walk, 19, NULL},
224 {ai_walk, 24, NULL},
225 {ai_walk, 28, NULL},
226 {ai_walk, 25, NULL}
227 };
228 mmove_t parasite_move_walk = {FRAME_run03, FRAME_run09, parasite_frames_walk, parasite_walk};
229
230 mframe_t parasite_frames_start_walk [] =
231 {
232 {ai_walk, 0, NULL},
233 {ai_walk, 30, parasite_walk}
234 };
235 mmove_t parasite_move_start_walk = {FRAME_run01, FRAME_run02, parasite_frames_start_walk, NULL};
236
237 mframe_t parasite_frames_stop_walk [] =
238 {
239 {ai_walk, 20, NULL},
240 {ai_walk, 20, NULL},
241 {ai_walk, 12, NULL},
242 {ai_walk, 10, NULL},
243 {ai_walk, 0, NULL},
244 {ai_walk, 0, NULL}
245 };
246 mmove_t parasite_move_stop_walk = {FRAME_run10, FRAME_run15, parasite_frames_stop_walk, NULL};
247
parasite_start_walk(edict_t * self)248 void parasite_start_walk (edict_t *self)
249 {
250 self->monsterinfo.currentmove = ¶site_move_start_walk;
251 }
252
parasite_walk(edict_t * self)253 void parasite_walk (edict_t *self)
254 {
255 self->monsterinfo.currentmove = ¶site_move_walk;
256 }
257
258
259 mframe_t parasite_frames_pain1 [] =
260 {
261 {ai_move, 0, NULL},
262 {ai_move, 0, NULL},
263 {ai_move, 0, NULL},
264 {ai_move, 0, NULL},
265 {ai_move, 0, NULL},
266 {ai_move, 0, NULL},
267 {ai_move, 6, NULL},
268 {ai_move, 16, NULL},
269 {ai_move, -6, NULL},
270 {ai_move, -7, NULL},
271 {ai_move, 0, NULL}
272 };
273 mmove_t parasite_move_pain1 = {FRAME_pain101, FRAME_pain111, parasite_frames_pain1, parasite_start_run};
274
parasite_pain(edict_t * self,edict_t * other,float kick,int damage)275 void parasite_pain (edict_t *self, edict_t *other, float kick, int damage)
276 {
277 if (self->health < (self->max_health / 2))
278 self->s.skinnum = 1;
279
280 if (level.time < self->pain_debounce_time)
281 return;
282
283 self->pain_debounce_time = level.time + 3;
284
285 if (skill->value == 3)
286 return; // no pain anims in nightmare
287
288 if (random() < 0.5)
289 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
290 else
291 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
292
293 self->monsterinfo.currentmove = ¶site_move_pain1;
294 }
295
296
parasite_drain_attack_ok(vec3_t start,vec3_t end)297 static qboolean parasite_drain_attack_ok (vec3_t start, vec3_t end)
298 {
299 vec3_t dir, angles;
300
301 // check for max distance
302 VectorSubtract (start, end, dir);
303 if (VectorLength(dir) > 256)
304 return false;
305
306 // check for min/max pitch
307 vectoangles (dir, angles);
308 if (angles[0] < -180)
309 angles[0] += 360;
310 if (fabs(angles[0]) > 30)
311 return false;
312
313 return true;
314 }
315
parasite_drain_attack(edict_t * self)316 void parasite_drain_attack (edict_t *self)
317 {
318 vec3_t offset, start, f, r, end, dir;
319 trace_t tr;
320 int damage;
321
322 AngleVectors (self->s.angles, f, r, NULL);
323 VectorSet (offset, 24, 0, 6);
324 G_ProjectSource (self->s.origin, offset, f, r, start);
325
326 VectorCopy (self->enemy->s.origin, end);
327 if (!parasite_drain_attack_ok(start, end))
328 {
329 end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8;
330 if (!parasite_drain_attack_ok(start, end))
331 {
332 end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8;
333 if (!parasite_drain_attack_ok(start, end))
334 return;
335 }
336 }
337 VectorCopy (self->enemy->s.origin, end);
338
339 tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
340 if (tr.ent != self->enemy)
341 return;
342
343 if (self->s.frame == FRAME_drain03)
344 {
345 damage = 5;
346 gi.sound (self->enemy, CHAN_AUTO, sound_impact, 1, ATTN_NORM, 0);
347 }
348 else
349 {
350 if (self->s.frame == FRAME_drain04)
351 gi.sound (self, CHAN_WEAPON, sound_suck, 1, ATTN_NORM, 0);
352 damage = 2;
353 }
354
355 gi.WriteByte (svc_temp_entity);
356 gi.WriteByte (TE_PARASITE_ATTACK);
357 gi.WriteShort (self - g_edicts);
358 gi.WritePosition (start);
359 gi.WritePosition (end);
360 gi.multicast (self->s.origin, MULTICAST_PVS);
361
362 VectorSubtract (start, end, dir);
363 T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN);
364 }
365
366 mframe_t parasite_frames_drain [] =
367 {
368 {ai_charge, 0, parasite_launch},
369 {ai_charge, 0, NULL},
370 {ai_charge, 15, parasite_drain_attack}, // Target hits
371 {ai_charge, 0, parasite_drain_attack}, // drain
372 {ai_charge, 0, parasite_drain_attack}, // drain
373 {ai_charge, 0, parasite_drain_attack}, // drain
374 {ai_charge, 0, parasite_drain_attack}, // drain
375 {ai_charge, -2, parasite_drain_attack}, // drain
376 {ai_charge, -2, parasite_drain_attack}, // drain
377 {ai_charge, -3, parasite_drain_attack}, // drain
378 {ai_charge, -2, parasite_drain_attack}, // drain
379 {ai_charge, 0, parasite_drain_attack}, // drain
380 {ai_charge, -1, parasite_drain_attack}, // drain
381 {ai_charge, 0, parasite_reel_in}, // let go
382 {ai_charge, -2, NULL},
383 {ai_charge, -2, NULL},
384 {ai_charge, -3, NULL},
385 {ai_charge, 0, NULL}
386 };
387 mmove_t parasite_move_drain = {FRAME_drain01, FRAME_drain18, parasite_frames_drain, parasite_start_run};
388
389
390 mframe_t parasite_frames_break [] =
391 {
392 {ai_charge, 0, NULL},
393 {ai_charge, -3, NULL},
394 {ai_charge, 1, NULL},
395 {ai_charge, 2, NULL},
396 {ai_charge, -3, NULL},
397 {ai_charge, 1, NULL},
398 {ai_charge, 1, NULL},
399 {ai_charge, 3, NULL},
400 {ai_charge, 0, NULL},
401 {ai_charge, -18, NULL},
402 {ai_charge, 3, NULL},
403 {ai_charge, 9, NULL},
404 {ai_charge, 6, NULL},
405 {ai_charge, 0, NULL},
406 {ai_charge, -18, NULL},
407 {ai_charge, 0, NULL},
408 {ai_charge, 8, NULL},
409 {ai_charge, 9, NULL},
410 {ai_charge, 0, NULL},
411 {ai_charge, -18, NULL},
412 {ai_charge, 0, NULL},
413 {ai_charge, 0, NULL}, // airborne
414 {ai_charge, 0, NULL}, // airborne
415 {ai_charge, 0, NULL}, // slides
416 {ai_charge, 0, NULL}, // slides
417 {ai_charge, 0, NULL}, // slides
418 {ai_charge, 0, NULL}, // slides
419 {ai_charge, 4, NULL},
420 {ai_charge, 11, NULL},
421 {ai_charge, -2, NULL},
422 {ai_charge, -5, NULL},
423 {ai_charge, 1, NULL}
424 };
425 mmove_t parasite_move_break = {FRAME_break01, FRAME_break32, parasite_frames_break, parasite_start_run};
426
427 /*
428 ===
429 Break Stuff Ends
430 ===
431 */
432
parasite_attack(edict_t * self)433 void parasite_attack (edict_t *self)
434 {
435 // if (random() <= 0.2)
436 // self->monsterinfo.currentmove = ¶site_move_break;
437 // else
438 self->monsterinfo.currentmove = ¶site_move_drain;
439 }
440
441
442
443 /*
444 ===
445 Death Stuff Starts
446 ===
447 */
448
parasite_dead(edict_t * self)449 void parasite_dead (edict_t *self)
450 {
451 VectorSet (self->mins, -16, -16, -24);
452 VectorSet (self->maxs, 16, 16, -8);
453 self->movetype = MOVETYPE_TOSS;
454 self->svflags |= SVF_DEADMONSTER;
455 self->nextthink = 0;
456 gi.linkentity (self);
457 }
458
459 mframe_t parasite_frames_death [] =
460 {
461 {ai_move, 0, NULL},
462 {ai_move, 0, NULL},
463 {ai_move, 0, NULL},
464 {ai_move, 0, NULL},
465 {ai_move, 0, NULL},
466 {ai_move, 0, NULL},
467 {ai_move, 0, NULL}
468 };
469 mmove_t parasite_move_death = {FRAME_death101, FRAME_death107, parasite_frames_death, parasite_dead};
470
parasite_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)471 void parasite_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
472 {
473 int n;
474
475 // check for gib
476 if (self->health <= self->gib_health)
477 {
478 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
479 for (n= 0; n < 2; n++)
480 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
481 for (n= 0; n < 4; n++)
482 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
483 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
484 self->deadflag = DEAD_DEAD;
485 return;
486 }
487
488 if (self->deadflag == DEAD_DEAD)
489 return;
490
491 // regular death
492 gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
493 self->deadflag = DEAD_DEAD;
494 self->takedamage = DAMAGE_YES;
495 self->monsterinfo.currentmove = ¶site_move_death;
496 }
497
498 /*
499 ===
500 End Death Stuff
501 ===
502 */
503
504 /*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
505 */
SP_monster_parasite(edict_t * self)506 void SP_monster_parasite (edict_t *self)
507 {
508 if (deathmatch->value)
509 {
510 G_FreeEdict (self);
511 return;
512 }
513
514 sound_pain1 = gi.soundindex ("parasite/parpain1.wav");
515 sound_pain2 = gi.soundindex ("parasite/parpain2.wav");
516 sound_die = gi.soundindex ("parasite/pardeth1.wav");
517 sound_launch = gi.soundindex("parasite/paratck1.wav");
518 sound_impact = gi.soundindex("parasite/paratck2.wav");
519 sound_suck = gi.soundindex("parasite/paratck3.wav");
520 sound_reelin = gi.soundindex("parasite/paratck4.wav");
521 sound_sight = gi.soundindex("parasite/parsght1.wav");
522 sound_tap = gi.soundindex("parasite/paridle1.wav");
523 sound_scratch = gi.soundindex("parasite/paridle2.wav");
524 sound_search = gi.soundindex("parasite/parsrch1.wav");
525
526 self->s.modelindex = gi.modelindex ("models/monsters/parasite/tris.md2");
527 VectorSet (self->mins, -16, -16, -24);
528 VectorSet (self->maxs, 16, 16, 24);
529 self->movetype = MOVETYPE_STEP;
530 self->solid = SOLID_BBOX;
531
532 self->health = 175;
533 self->gib_health = -50;
534 self->mass = 250;
535
536 self->pain = parasite_pain;
537 self->die = parasite_die;
538
539 self->monsterinfo.stand = parasite_stand;
540 self->monsterinfo.walk = parasite_start_walk;
541 self->monsterinfo.run = parasite_start_run;
542 self->monsterinfo.attack = parasite_attack;
543 self->monsterinfo.sight = parasite_sight;
544 self->monsterinfo.idle = parasite_idle;
545
546 gi.linkentity (self);
547
548 self->monsterinfo.currentmove = ¶site_move_stand;
549 self->monsterinfo.scale = MODEL_SCALE;
550
551 walkmonster_start (self);
552 }
553