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->floatVal == 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 qBool parasite_drain_attack_ok (vec3_t start, vec3_t end)
298 {
299 vec3_t dir, angles;
300
301 // check for max distance
302 Vec3Subtract (start, end, dir);
303 if (Vec3Length(dir) > 256)
304 return qFalse;
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 qFalse;
312
313 return qTrue;
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 Angles_Vectors (self->s.angles, f, r, NULL);
323 Vec3Set (offset, 24, 0, 6);
324 G_ProjectSource (self->s.origin, offset, f, r, start);
325
326 Vec3Copy (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 Vec3Copy (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 Vec3Subtract (start, end, dir);
363 T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3Origin, 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 Vec3Set (self->mins, -16, -16, -24);
452 Vec3Set (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->floatVal)
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 Vec3Set (self->mins, -16, -16, -24);
528 Vec3Set (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