Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
298 | serge | 1 | // Emacs style mode select -*- C++ -*- |
2 | //----------------------------------------------------------------------------- |
||
3 | // |
||
4 | // $Id:$ |
||
5 | // |
||
6 | // Copyright (C) 1993-1996 by id Software, Inc. |
||
7 | // |
||
8 | // This source is available for distribution and/or modification |
||
9 | // only under the terms of the DOOM Source Code License as |
||
10 | // published by id Software. All rights reserved. |
||
11 | // |
||
12 | // The source is distributed in the hope that it will be useful, |
||
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
||
15 | // for more details. |
||
16 | // |
||
17 | // $Log:$ |
||
18 | // |
||
19 | // DESCRIPTION: |
||
20 | // Handling interactions (i.e., collisions). |
||
21 | // |
||
22 | //----------------------------------------------------------------------------- |
||
23 | |||
24 | |||
25 | static const char |
||
26 | rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $"; |
||
27 | |||
28 | |||
29 | // Data. |
||
30 | #include "doomdef.h" |
||
31 | #include "dstrings.h" |
||
32 | #include "sounds.h" |
||
33 | |||
34 | #include "doomstat.h" |
||
35 | |||
36 | #include "m_random.h" |
||
37 | #include "i_system.h" |
||
38 | |||
39 | #include "am_map.h" |
||
40 | |||
41 | #include "p_local.h" |
||
42 | |||
43 | #include "s_sound.h" |
||
44 | |||
45 | #ifdef __GNUG__ |
||
46 | #pragma implementation "p_inter.h" |
||
47 | #endif |
||
48 | #include "p_inter.h" |
||
49 | |||
50 | |||
51 | #define BONUSADD 6 |
||
52 | |||
53 | |||
54 | |||
55 | |||
56 | // a weapon is found with two clip loads, |
||
57 | // a big item has five clip loads |
||
58 | int maxammo[NUMAMMO] = {200, 50, 300, 50}; |
||
59 | int clipammo[NUMAMMO] = {10, 4, 20, 1}; |
||
60 | |||
61 | |||
62 | // |
||
63 | // GET STUFF |
||
64 | // |
||
65 | |||
66 | // |
||
67 | // P_GiveAmmo |
||
68 | // Num is the number of clip loads, |
||
69 | // not the individual count (0= 1/2 clip). |
||
70 | // Returns false if the ammo can't be picked up at all |
||
71 | // |
||
72 | |||
73 | boolean |
||
74 | P_GiveAmmo |
||
75 | ( player_t* player, |
||
76 | ammotype_t ammo, |
||
77 | int num ) |
||
78 | { |
||
79 | int oldammo; |
||
80 | |||
81 | if (ammo == am_noammo) |
||
82 | return false; |
||
83 | |||
84 | if (ammo < 0 || ammo > NUMAMMO) |
||
85 | I_Error ("P_GiveAmmo: bad type %i", ammo); |
||
86 | |||
87 | if ( player->ammo[ammo] == player->maxammo[ammo] ) |
||
88 | return false; |
||
89 | |||
90 | if (num) |
||
91 | num *= clipammo[ammo]; |
||
92 | else |
||
93 | num = clipammo[ammo]/2; |
||
94 | |||
95 | if (gameskill == sk_baby |
||
96 | || gameskill == sk_nightmare) |
||
97 | { |
||
98 | // give double ammo in trainer mode, |
||
99 | // you'll need in nightmare |
||
100 | num <<= 1; |
||
101 | } |
||
102 | |||
103 | |||
104 | oldammo = player->ammo[ammo]; |
||
105 | player->ammo[ammo] += num; |
||
106 | |||
107 | if (player->ammo[ammo] > player->maxammo[ammo]) |
||
108 | player->ammo[ammo] = player->maxammo[ammo]; |
||
109 | |||
110 | // If non zero ammo, |
||
111 | // don't change up weapons, |
||
112 | // player was lower on purpose. |
||
113 | if (oldammo) |
||
114 | return true; |
||
115 | |||
116 | // We were down to zero, |
||
117 | // so select a new weapon. |
||
118 | // Preferences are not user selectable. |
||
119 | switch (ammo) |
||
120 | { |
||
121 | case am_clip: |
||
122 | if (player->readyweapon == wp_fist) |
||
123 | { |
||
124 | if (player->weaponowned[wp_chaingun]) |
||
125 | player->pendingweapon = wp_chaingun; |
||
126 | else |
||
127 | player->pendingweapon = wp_pistol; |
||
128 | } |
||
129 | break; |
||
130 | |||
131 | case am_shell: |
||
132 | if (player->readyweapon == wp_fist |
||
133 | || player->readyweapon == wp_pistol) |
||
134 | { |
||
135 | if (player->weaponowned[wp_shotgun]) |
||
136 | player->pendingweapon = wp_shotgun; |
||
137 | } |
||
138 | break; |
||
139 | |||
140 | case am_cell: |
||
141 | if (player->readyweapon == wp_fist |
||
142 | || player->readyweapon == wp_pistol) |
||
143 | { |
||
144 | if (player->weaponowned[wp_plasma]) |
||
145 | player->pendingweapon = wp_plasma; |
||
146 | } |
||
147 | break; |
||
148 | |||
149 | case am_misl: |
||
150 | if (player->readyweapon == wp_fist) |
||
151 | { |
||
152 | if (player->weaponowned[wp_missile]) |
||
153 | player->pendingweapon = wp_missile; |
||
154 | } |
||
155 | default: |
||
156 | break; |
||
157 | } |
||
158 | |||
159 | return true; |
||
160 | } |
||
161 | |||
162 | |||
163 | // |
||
164 | // P_GiveWeapon |
||
165 | // The weapon name may have a MF_DROPPED flag ored in. |
||
166 | // |
||
167 | boolean |
||
168 | P_GiveWeapon |
||
169 | ( player_t* player, |
||
170 | weapontype_t weapon, |
||
171 | boolean dropped ) |
||
172 | { |
||
173 | boolean gaveammo; |
||
174 | boolean gaveweapon; |
||
175 | |||
176 | if (netgame |
||
177 | && (deathmatch!=2) |
||
178 | && !dropped ) |
||
179 | { |
||
180 | // leave placed weapons forever on net games |
||
181 | if (player->weaponowned[weapon]) |
||
182 | return false; |
||
183 | |||
184 | player->bonuscount += BONUSADD; |
||
185 | player->weaponowned[weapon] = true; |
||
186 | |||
187 | if (deathmatch) |
||
188 | P_GiveAmmo (player, weaponinfo[weapon].ammo, 5); |
||
189 | else |
||
190 | P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); |
||
191 | player->pendingweapon = weapon; |
||
192 | |||
193 | if (player == &players[consoleplayer]) |
||
194 | S_StartSound (NULL, sfx_wpnup); |
||
195 | return false; |
||
196 | } |
||
197 | |||
198 | if (weaponinfo[weapon].ammo != am_noammo) |
||
199 | { |
||
200 | // give one clip with a dropped weapon, |
||
201 | // two clips with a found weapon |
||
202 | if (dropped) |
||
203 | gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); |
||
204 | else |
||
205 | gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); |
||
206 | } |
||
207 | else |
||
208 | gaveammo = false; |
||
209 | |||
210 | if (player->weaponowned[weapon]) |
||
211 | gaveweapon = false; |
||
212 | else |
||
213 | { |
||
214 | gaveweapon = true; |
||
215 | player->weaponowned[weapon] = true; |
||
216 | player->pendingweapon = weapon; |
||
217 | } |
||
218 | |||
219 | return (gaveweapon || gaveammo); |
||
220 | } |
||
221 | |||
222 | |||
223 | |||
224 | // |
||
225 | // P_GiveBody |
||
226 | // Returns false if the body isn't needed at all |
||
227 | // |
||
228 | boolean |
||
229 | P_GiveBody |
||
230 | ( player_t* player, |
||
231 | int num ) |
||
232 | { |
||
233 | if (player->health >= MAXHEALTH) |
||
234 | return false; |
||
235 | |||
236 | player->health += num; |
||
237 | if (player->health > MAXHEALTH) |
||
238 | player->health = MAXHEALTH; |
||
239 | player->mo->health = player->health; |
||
240 | |||
241 | return true; |
||
242 | } |
||
243 | |||
244 | |||
245 | |||
246 | // |
||
247 | // P_GiveArmor |
||
248 | // Returns false if the armor is worse |
||
249 | // than the current armor. |
||
250 | // |
||
251 | boolean |
||
252 | P_GiveArmor |
||
253 | ( player_t* player, |
||
254 | int armortype ) |
||
255 | { |
||
256 | int hits; |
||
257 | |||
258 | hits = armortype*100; |
||
259 | if (player->armorpoints >= hits) |
||
260 | return false; // don't pick up |
||
261 | |||
262 | player->armortype = armortype; |
||
263 | player->armorpoints = hits; |
||
264 | |||
265 | return true; |
||
266 | } |
||
267 | |||
268 | |||
269 | |||
270 | // |
||
271 | // P_GiveCard |
||
272 | // |
||
273 | void |
||
274 | P_GiveCard |
||
275 | ( player_t* player, |
||
276 | card_t card ) |
||
277 | { |
||
278 | if (player->cards[card]) |
||
279 | return; |
||
280 | |||
281 | player->bonuscount = BONUSADD; |
||
282 | player->cards[card] = 1; |
||
283 | } |
||
284 | |||
285 | |||
286 | // |
||
287 | // P_GivePower |
||
288 | // |
||
289 | boolean |
||
290 | P_GivePower |
||
291 | ( player_t* player, |
||
292 | int /*powertype_t*/ power ) |
||
293 | { |
||
294 | if (power == pw_invulnerability) |
||
295 | { |
||
296 | player->powers[power] = INVULNTICS; |
||
297 | return true; |
||
298 | } |
||
299 | |||
300 | if (power == pw_invisibility) |
||
301 | { |
||
302 | player->powers[power] = INVISTICS; |
||
303 | player->mo->flags |= MF_SHADOW; |
||
304 | return true; |
||
305 | } |
||
306 | |||
307 | if (power == pw_infrared) |
||
308 | { |
||
309 | player->powers[power] = INFRATICS; |
||
310 | return true; |
||
311 | } |
||
312 | |||
313 | if (power == pw_ironfeet) |
||
314 | { |
||
315 | player->powers[power] = IRONTICS; |
||
316 | return true; |
||
317 | } |
||
318 | |||
319 | if (power == pw_strength) |
||
320 | { |
||
321 | P_GiveBody (player, 100); |
||
322 | player->powers[power] = 1; |
||
323 | return true; |
||
324 | } |
||
325 | |||
326 | if (player->powers[power]) |
||
327 | return false; // already got it |
||
328 | |||
329 | player->powers[power] = 1; |
||
330 | return true; |
||
331 | } |
||
332 | |||
333 | |||
334 | |||
335 | // |
||
336 | // P_TouchSpecialThing |
||
337 | // |
||
338 | void |
||
339 | P_TouchSpecialThing |
||
340 | ( mobj_t* special, |
||
341 | mobj_t* toucher ) |
||
342 | { |
||
343 | player_t* player; |
||
344 | int i; |
||
345 | fixed_t delta; |
||
346 | int sound; |
||
347 | |||
348 | delta = special->z - toucher->z; |
||
349 | |||
350 | if (delta > toucher->height |
||
351 | || delta < -8*FRACUNIT) |
||
352 | { |
||
353 | // out of reach |
||
354 | return; |
||
355 | } |
||
356 | |||
357 | |||
358 | sound = sfx_itemup; |
||
359 | player = toucher->player; |
||
360 | |||
361 | // Dead thing touching. |
||
362 | // Can happen with a sliding player corpse. |
||
363 | if (toucher->health <= 0) |
||
364 | return; |
||
365 | |||
366 | // Identify by sprite. |
||
367 | switch (special->sprite) |
||
368 | { |
||
369 | // armor |
||
370 | case SPR_ARM1: |
||
371 | if (!P_GiveArmor (player, 1)) |
||
372 | return; |
||
373 | player->message = GOTARMOR; |
||
374 | break; |
||
375 | |||
376 | case SPR_ARM2: |
||
377 | if (!P_GiveArmor (player, 2)) |
||
378 | return; |
||
379 | player->message = GOTMEGA; |
||
380 | break; |
||
381 | |||
382 | // bonus items |
||
383 | case SPR_BON1: |
||
384 | player->health++; // can go over 100% |
||
385 | if (player->health > 200) |
||
386 | player->health = 200; |
||
387 | player->mo->health = player->health; |
||
388 | player->message = GOTHTHBONUS; |
||
389 | break; |
||
390 | |||
391 | case SPR_BON2: |
||
392 | player->armorpoints++; // can go over 100% |
||
393 | if (player->armorpoints > 200) |
||
394 | player->armorpoints = 200; |
||
395 | if (!player->armortype) |
||
396 | player->armortype = 1; |
||
397 | player->message = GOTARMBONUS; |
||
398 | break; |
||
399 | |||
400 | case SPR_SOUL: |
||
401 | player->health += 100; |
||
402 | if (player->health > 200) |
||
403 | player->health = 200; |
||
404 | player->mo->health = player->health; |
||
405 | player->message = GOTSUPER; |
||
406 | sound = sfx_getpow; |
||
407 | break; |
||
408 | |||
409 | case SPR_MEGA: |
||
410 | if (gamemode != commercial) |
||
411 | return; |
||
412 | player->health = 200; |
||
413 | player->mo->health = player->health; |
||
414 | P_GiveArmor (player,2); |
||
415 | player->message = GOTMSPHERE; |
||
416 | sound = sfx_getpow; |
||
417 | break; |
||
418 | |||
419 | // cards |
||
420 | // leave cards for everyone |
||
421 | case SPR_BKEY: |
||
422 | if (!player->cards[it_bluecard]) |
||
423 | player->message = GOTBLUECARD; |
||
424 | P_GiveCard (player, it_bluecard); |
||
425 | if (!netgame) |
||
426 | break; |
||
427 | return; |
||
428 | |||
429 | case SPR_YKEY: |
||
430 | if (!player->cards[it_yellowcard]) |
||
431 | player->message = GOTYELWCARD; |
||
432 | P_GiveCard (player, it_yellowcard); |
||
433 | if (!netgame) |
||
434 | break; |
||
435 | return; |
||
436 | |||
437 | case SPR_RKEY: |
||
438 | if (!player->cards[it_redcard]) |
||
439 | player->message = GOTREDCARD; |
||
440 | P_GiveCard (player, it_redcard); |
||
441 | if (!netgame) |
||
442 | break; |
||
443 | return; |
||
444 | |||
445 | case SPR_BSKU: |
||
446 | if (!player->cards[it_blueskull]) |
||
447 | player->message = GOTBLUESKUL; |
||
448 | P_GiveCard (player, it_blueskull); |
||
449 | if (!netgame) |
||
450 | break; |
||
451 | return; |
||
452 | |||
453 | case SPR_YSKU: |
||
454 | if (!player->cards[it_yellowskull]) |
||
455 | player->message = GOTYELWSKUL; |
||
456 | P_GiveCard (player, it_yellowskull); |
||
457 | if (!netgame) |
||
458 | break; |
||
459 | return; |
||
460 | |||
461 | case SPR_RSKU: |
||
462 | if (!player->cards[it_redskull]) |
||
463 | player->message = GOTREDSKULL; |
||
464 | P_GiveCard (player, it_redskull); |
||
465 | if (!netgame) |
||
466 | break; |
||
467 | return; |
||
468 | |||
469 | // medikits, heals |
||
470 | case SPR_STIM: |
||
471 | if (!P_GiveBody (player, 10)) |
||
472 | return; |
||
473 | player->message = GOTSTIM; |
||
474 | break; |
||
475 | |||
476 | case SPR_MEDI: |
||
477 | if (!P_GiveBody (player, 25)) |
||
478 | return; |
||
479 | |||
480 | if (player->health < 25) |
||
481 | player->message = GOTMEDINEED; |
||
482 | else |
||
483 | player->message = GOTMEDIKIT; |
||
484 | break; |
||
485 | |||
486 | |||
487 | // power ups |
||
488 | case SPR_PINV: |
||
489 | if (!P_GivePower (player, pw_invulnerability)) |
||
490 | return; |
||
491 | player->message = GOTINVUL; |
||
492 | sound = sfx_getpow; |
||
493 | break; |
||
494 | |||
495 | case SPR_PSTR: |
||
496 | if (!P_GivePower (player, pw_strength)) |
||
497 | return; |
||
498 | player->message = GOTBERSERK; |
||
499 | if (player->readyweapon != wp_fist) |
||
500 | player->pendingweapon = wp_fist; |
||
501 | sound = sfx_getpow; |
||
502 | break; |
||
503 | |||
504 | case SPR_PINS: |
||
505 | if (!P_GivePower (player, pw_invisibility)) |
||
506 | return; |
||
507 | player->message = GOTINVIS; |
||
508 | sound = sfx_getpow; |
||
509 | break; |
||
510 | |||
511 | case SPR_SUIT: |
||
512 | if (!P_GivePower (player, pw_ironfeet)) |
||
513 | return; |
||
514 | player->message = GOTSUIT; |
||
515 | sound = sfx_getpow; |
||
516 | break; |
||
517 | |||
518 | case SPR_PMAP: |
||
519 | if (!P_GivePower (player, pw_allmap)) |
||
520 | return; |
||
521 | player->message = GOTMAP; |
||
522 | sound = sfx_getpow; |
||
523 | break; |
||
524 | |||
525 | case SPR_PVIS: |
||
526 | if (!P_GivePower (player, pw_infrared)) |
||
527 | return; |
||
528 | player->message = GOTVISOR; |
||
529 | sound = sfx_getpow; |
||
530 | break; |
||
531 | |||
532 | // ammo |
||
533 | case SPR_CLIP: |
||
534 | if (special->flags & MF_DROPPED) |
||
535 | { |
||
536 | if (!P_GiveAmmo (player,am_clip,0)) |
||
537 | return; |
||
538 | } |
||
539 | else |
||
540 | { |
||
541 | if (!P_GiveAmmo (player,am_clip,1)) |
||
542 | return; |
||
543 | } |
||
544 | player->message = GOTCLIP; |
||
545 | break; |
||
546 | |||
547 | case SPR_AMMO: |
||
548 | if (!P_GiveAmmo (player, am_clip,5)) |
||
549 | return; |
||
550 | player->message = GOTCLIPBOX; |
||
551 | break; |
||
552 | |||
553 | case SPR_ROCK: |
||
554 | if (!P_GiveAmmo (player, am_misl,1)) |
||
555 | return; |
||
556 | player->message = GOTROCKET; |
||
557 | break; |
||
558 | |||
559 | case SPR_BROK: |
||
560 | if (!P_GiveAmmo (player, am_misl,5)) |
||
561 | return; |
||
562 | player->message = GOTROCKBOX; |
||
563 | break; |
||
564 | |||
565 | case SPR_CELL: |
||
566 | if (!P_GiveAmmo (player, am_cell,1)) |
||
567 | return; |
||
568 | player->message = GOTCELL; |
||
569 | break; |
||
570 | |||
571 | case SPR_CELP: |
||
572 | if (!P_GiveAmmo (player, am_cell,5)) |
||
573 | return; |
||
574 | player->message = GOTCELLBOX; |
||
575 | break; |
||
576 | |||
577 | case SPR_SHEL: |
||
578 | if (!P_GiveAmmo (player, am_shell,1)) |
||
579 | return; |
||
580 | player->message = GOTSHELLS; |
||
581 | break; |
||
582 | |||
583 | case SPR_SBOX: |
||
584 | if (!P_GiveAmmo (player, am_shell,5)) |
||
585 | return; |
||
586 | player->message = GOTSHELLBOX; |
||
587 | break; |
||
588 | |||
589 | case SPR_BPAK: |
||
590 | if (!player->backpack) |
||
591 | { |
||
592 | for (i=0 ; i |
||
593 | player->maxammo[i] *= 2; |
||
594 | player->backpack = true; |
||
595 | } |
||
596 | for (i=0 ; i |
||
597 | P_GiveAmmo (player, i, 1); |
||
598 | player->message = GOTBACKPACK; |
||
599 | break; |
||
600 | |||
601 | // weapons |
||
602 | case SPR_BFUG: |
||
603 | if (!P_GiveWeapon (player, wp_bfg, false) ) |
||
604 | return; |
||
605 | player->message = GOTBFG9000; |
||
606 | sound = sfx_wpnup; |
||
607 | break; |
||
608 | |||
609 | case SPR_MGUN: |
||
610 | if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) ) |
||
611 | return; |
||
612 | player->message = GOTCHAINGUN; |
||
613 | sound = sfx_wpnup; |
||
614 | break; |
||
615 | |||
616 | case SPR_CSAW: |
||
617 | if (!P_GiveWeapon (player, wp_chainsaw, false) ) |
||
618 | return; |
||
619 | player->message = GOTCHAINSAW; |
||
620 | sound = sfx_wpnup; |
||
621 | break; |
||
622 | |||
623 | case SPR_LAUN: |
||
624 | if (!P_GiveWeapon (player, wp_missile, false) ) |
||
625 | return; |
||
626 | player->message = GOTLAUNCHER; |
||
627 | sound = sfx_wpnup; |
||
628 | break; |
||
629 | |||
630 | case SPR_PLAS: |
||
631 | if (!P_GiveWeapon (player, wp_plasma, false) ) |
||
632 | return; |
||
633 | player->message = GOTPLASMA; |
||
634 | sound = sfx_wpnup; |
||
635 | break; |
||
636 | |||
637 | case SPR_SHOT: |
||
638 | if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) ) |
||
639 | return; |
||
640 | player->message = GOTSHOTGUN; |
||
641 | sound = sfx_wpnup; |
||
642 | break; |
||
643 | |||
644 | case SPR_SGN2: |
||
645 | if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) ) |
||
646 | return; |
||
647 | player->message = GOTSHOTGUN2; |
||
648 | sound = sfx_wpnup; |
||
649 | break; |
||
650 | |||
651 | default: |
||
652 | I_Error ("P_SpecialThing: Unknown gettable thing"); |
||
653 | } |
||
654 | |||
655 | if (special->flags & MF_COUNTITEM) |
||
656 | player->itemcount++; |
||
657 | P_RemoveMobj (special); |
||
658 | player->bonuscount += BONUSADD; |
||
659 | if (player == &players[consoleplayer]) |
||
660 | S_StartSound (NULL, sound); |
||
661 | } |
||
662 | |||
663 | |||
664 | // |
||
665 | // KillMobj |
||
666 | // |
||
667 | void |
||
668 | P_KillMobj |
||
669 | ( mobj_t* source, |
||
670 | mobj_t* target ) |
||
671 | { |
||
672 | mobjtype_t item; |
||
673 | mobj_t* mo; |
||
674 | |||
675 | target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); |
||
676 | |||
677 | if (target->type != MT_SKULL) |
||
678 | target->flags &= ~MF_NOGRAVITY; |
||
679 | |||
680 | target->flags |= MF_CORPSE|MF_DROPOFF; |
||
681 | target->height >>= 2; |
||
682 | |||
683 | if (source && source->player) |
||
684 | { |
||
685 | // count for intermission |
||
686 | if (target->flags & MF_COUNTKILL) |
||
687 | source->player->killcount++; |
||
688 | |||
689 | if (target->player) |
||
690 | source->player->frags[target->player-players]++; |
||
691 | } |
||
692 | else if (!netgame && (target->flags & MF_COUNTKILL) ) |
||
693 | { |
||
694 | // count all monster deaths, |
||
695 | // even those caused by other monsters |
||
696 | players[0].killcount++; |
||
697 | } |
||
698 | |||
699 | if (target->player) |
||
700 | { |
||
701 | // count environment kills against you |
||
702 | if (!source) |
||
703 | target->player->frags[target->player-players]++; |
||
704 | |||
705 | target->flags &= ~MF_SOLID; |
||
706 | target->player->playerstate = PST_DEAD; |
||
707 | P_DropWeapon (target->player); |
||
708 | |||
709 | if (target->player == &players[consoleplayer] |
||
710 | && automapactive) |
||
711 | { |
||
712 | // don't die in auto map, |
||
713 | // switch view prior to dying |
||
714 | AM_Stop (); |
||
715 | } |
||
716 | |||
717 | } |
||
718 | |||
719 | if (target->health < -target->info->spawnhealth |
||
720 | && target->info->xdeathstate) |
||
721 | { |
||
722 | P_SetMobjState (target, target->info->xdeathstate); |
||
723 | } |
||
724 | else |
||
725 | P_SetMobjState (target, target->info->deathstate); |
||
726 | target->tics -= P_Random()&3; |
||
727 | |||
728 | if (target->tics < 1) |
||
729 | target->tics = 1; |
||
730 | |||
731 | // I_StartSound (&actor->r, actor->info->deathsound); |
||
732 | |||
733 | |||
734 | // Drop stuff. |
||
735 | // This determines the kind of object spawned |
||
736 | // during the death frame of a thing. |
||
737 | switch (target->type) |
||
738 | { |
||
739 | case MT_WOLFSS: |
||
740 | case MT_POSSESSED: |
||
741 | item = MT_CLIP; |
||
742 | break; |
||
743 | |||
744 | case MT_SHOTGUY: |
||
745 | item = MT_SHOTGUN; |
||
746 | break; |
||
747 | |||
748 | case MT_CHAINGUY: |
||
749 | item = MT_CHAINGUN; |
||
750 | break; |
||
751 | |||
752 | default: |
||
753 | return; |
||
754 | } |
||
755 | |||
756 | mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); |
||
757 | mo->flags |= MF_DROPPED; // special versions of items |
||
758 | } |
||
759 | |||
760 | |||
761 | |||
762 | |||
763 | // |
||
764 | // P_DamageMobj |
||
765 | // Damages both enemies and players |
||
766 | // "inflictor" is the thing that caused the damage |
||
767 | // creature or missile, can be NULL (slime, etc) |
||
768 | // "source" is the thing to target after taking damage |
||
769 | // creature or NULL |
||
770 | // Source and inflictor are the same for melee attacks. |
||
771 | // Source can be NULL for slime, barrel explosions |
||
772 | // and other environmental stuff. |
||
773 | // |
||
774 | void |
||
775 | P_DamageMobj |
||
776 | ( mobj_t* target, |
||
777 | mobj_t* inflictor, |
||
778 | mobj_t* source, |
||
779 | int damage ) |
||
780 | { |
||
781 | unsigned ang; |
||
782 | int saved; |
||
783 | player_t* player; |
||
784 | fixed_t thrust; |
||
785 | int temp; |
||
786 | |||
787 | if ( !(target->flags & MF_SHOOTABLE) ) |
||
788 | return; // shouldn't happen... |
||
789 | |||
790 | if (target->health <= 0) |
||
791 | return; |
||
792 | |||
793 | if ( target->flags & MF_SKULLFLY ) |
||
794 | { |
||
795 | target->momx = target->momy = target->momz = 0; |
||
796 | } |
||
797 | |||
798 | player = target->player; |
||
799 | if (player && gameskill == sk_baby) |
||
800 | damage >>= 1; // take half damage in trainer mode |
||
801 | |||
802 | |||
803 | // Some close combat weapons should not |
||
804 | // inflict thrust and push the victim out of reach, |
||
805 | // thus kick away unless using the chainsaw. |
||
806 | if (inflictor |
||
807 | && !(target->flags & MF_NOCLIP) |
||
808 | && (!source |
||
809 | || !source->player |
||
810 | || source->player->readyweapon != wp_chainsaw)) |
||
811 | { |
||
812 | ang = R_PointToAngle2 ( inflictor->x, |
||
813 | inflictor->y, |
||
814 | target->x, |
||
815 | target->y); |
||
816 | |||
817 | thrust = damage*(FRACUNIT>>3)*100/target->info->mass; |
||
818 | |||
819 | // make fall forwards sometimes |
||
820 | if ( damage < 40 |
||
821 | && damage > target->health |
||
822 | && target->z - inflictor->z > 64*FRACUNIT |
||
823 | && (P_Random ()&1) ) |
||
824 | { |
||
825 | ang += ANG180; |
||
826 | thrust *= 4; |
||
827 | } |
||
828 | |||
829 | ang >>= ANGLETOFINESHIFT; |
||
830 | target->momx += FixedMul (thrust, finecosine[ang]); |
||
831 | target->momy += FixedMul (thrust, finesine[ang]); |
||
832 | } |
||
833 | |||
834 | // player specific |
||
835 | if (player) |
||
836 | { |
||
837 | // end of game hell hack |
||
838 | if (target->subsector->sector->special == 11 |
||
839 | && damage >= target->health) |
||
840 | { |
||
841 | damage = target->health - 1; |
||
842 | } |
||
843 | |||
844 | |||
845 | // Below certain threshold, |
||
846 | // ignore damage in GOD mode, or with INVUL power. |
||
847 | if ( damage < 1000 |
||
848 | && ( (player->cheats&CF_GODMODE) |
||
849 | || player->powers[pw_invulnerability] ) ) |
||
850 | { |
||
851 | return; |
||
852 | } |
||
853 | |||
854 | if (player->armortype) |
||
855 | { |
||
856 | if (player->armortype == 1) |
||
857 | saved = damage/3; |
||
858 | else |
||
859 | saved = damage/2; |
||
860 | |||
861 | if (player->armorpoints <= saved) |
||
862 | { |
||
863 | // armor is used up |
||
864 | saved = player->armorpoints; |
||
865 | player->armortype = 0; |
||
866 | } |
||
867 | player->armorpoints -= saved; |
||
868 | damage -= saved; |
||
869 | } |
||
870 | player->health -= damage; // mirror mobj health here for Dave |
||
871 | if (player->health < 0) |
||
872 | player->health = 0; |
||
873 | |||
874 | player->attacker = source; |
||
875 | player->damagecount += damage; // add damage after armor / invuln |
||
876 | |||
877 | if (player->damagecount > 100) |
||
878 | player->damagecount = 100; // teleport stomp does 10k points... |
||
879 | |||
880 | temp = damage < 100 ? damage : 100; |
||
881 | |||
882 | if (player == &players[consoleplayer]) |
||
883 | I_Tactile (40,10,40+temp*2); |
||
884 | } |
||
885 | |||
886 | // do the damage |
||
887 | target->health -= damage; |
||
888 | if (target->health <= 0) |
||
889 | { |
||
890 | P_KillMobj (source, target); |
||
891 | return; |
||
892 | } |
||
893 | |||
894 | if ( (P_Random () < target->info->painchance) |
||
895 | && !(target->flags&MF_SKULLFLY) ) |
||
896 | { |
||
897 | target->flags |= MF_JUSTHIT; // fight back! |
||
898 | |||
899 | P_SetMobjState (target, target->info->painstate); |
||
900 | } |
||
901 | |||
902 | target->reactiontime = 0; // we're awake now... |
||
903 | |||
904 | if ( (!target->threshold || target->type == MT_VILE) |
||
905 | && source && source != target |
||
906 | && source->type != MT_VILE) |
||
907 | { |
||
908 | // if not intent on another player, |
||
909 | // chase after this one |
||
910 | target->target = source; |
||
911 | target->threshold = BASETHRESHOLD; |
||
912 | if (target->state == &states[target->info->spawnstate] |
||
913 | && target->info->seestate != S_NULL) |
||
914 | P_SetMobjState (target, target->info->seestate); |
||
915 | } |
||
916 | |||
917 | }>=>>>=>>>=>>>>=>>=><=>> |
||
918 |