1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_inter.c 1537 2020-06-16 05:30:37Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: p_inter.c,v $
21 // Revision 1.30 2004/09/12 19:40:07 darkwolf95
22 // additional chex quest 1 support
23 //
24 // Revision 1.29 2002/11/30 18:39:58 judgecutor
25 // * Fix CR+LF problem
26 // * Fix FFW bug (player spawining istead of weapon)
27 //
28 // Revision 1.28 2002/09/27 16:40:09 tonyd
29 // First commit of acbot
30 //
31 // Revision 1.27 2002/08/24 22:42:03 hurdler
32 // Apply Robert Hogberg patches
33 //
34 // Revision 1.26 2002/07/26 15:21:36 hurdler
35 //
36 // Revision 1.25 2002/07/23 15:07:11 mysterial
37 // Messages to second player appear on his half of the screen
38 //
39 // Revision 1.24 2002/01/21 23:14:28 judgecutor
40 // Frag's Weapon Falling fixes
41 //
42 // Revision 1.23 2001/12/26 22:46:01 hurdler
43 // Revision 1.22 2001/12/26 22:42:52 hurdler
44 // Revision 1.18 2001/06/10 21:16:01 bpereira
45 // Revision 1.17 2001/05/27 13:42:47 bpereira
46 // Revision 1.16 2001/05/16 21:21:14 bpereira
47 //
48 // Revision 1.15 2001/05/14 19:02:58 metzgermeister
49 // * Fixed floor not moving up with player on E3M1
50 // * Fixed crash due to oversized string in screen message ... bad bug!
51 // * Corrected some typos
52 // * fixed sound bug in SDL
53 //
54 // Revision 1.14 2001/04/19 05:51:47 metzgermeister
55 // fixed 10 shells instead of 4 - bug
56 //
57 // Revision 1.13 2001/03/30 17:12:50 bpereira
58 // Revision 1.12 2001/02/24 13:35:20 bpereira
59 //
60 // Revision 1.11 2001/01/25 22:15:43 bpereira
61 // added heretic support
62 //
63 // Revision 1.10 2000/11/02 17:50:07 stroggonmeth
64 // Big 3Dfloors & FraggleScript commit!!
65 //
66 // Revision 1.9 2000/10/02 18:25:45 bpereira
67 // Revision 1.8 2000/10/01 10:18:17 bpereira
68 // Revision 1.7 2000/09/28 20:57:16 bpereira
69 // Revision 1.6 2000/08/31 14:30:55 bpereira
70 // Revision 1.5 2000/04/16 18:38:07 bpereira
71 //
72 // Revision 1.4 2000/04/04 00:32:46 stroggonmeth
73 // Initial Boom compatability plus few misc changes all around.
74 //
75 // Revision 1.3 2000/02/27 00:42:10 hurdler
76 // Revision 1.2 2000/02/26 00:28:42 hurdler
77 // Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)
78 //
79 //
80 // DESCRIPTION:
81 // Handling interactions (i.e., collisions).
82 //
83 //-----------------------------------------------------------------------------
84
85 #include "doomincl.h"
86 #include "p_local.h"
87 #include "p_tick.h"
88 // class-list
89 #include "p_inter.h"
90 #include "g_game.h"
91 #include "g_input.h"
92 // cv_allowrocketjump
93 #include "i_system.h"
94 //I_Tactile currently has no effect
95 #include "am_map.h"
96 #include "dstrings.h"
97 #include "m_random.h"
98 #include "s_sound.h"
99 #include "r_main.h"
100 #include "st_stuff.h"
101
102 #define BONUSADD 6
103 #define PICKUP_FLASH_TICS 10
104
105
106 // a weapon is found with two clip loads,
107 // a big item has five clip loads
108 int maxammo[NUMAMMO] = {200, 50, 300, 50};
109 int clipammo[NUMAMMO] = {10, 4, 20, 1};
110
111 consvar_t cv_fragsweaponfalling
112 = {"fragsweaponfalling" ,"0", CV_NETVAR, CV_YesNo};
113
114 // added 4-2-98 (Boris) for dehacked patch
115 // (i don't like that but do you see another solution ?)
116 int MAXHEALTH= 100;
117
118 //--------------------------------------------------------------------------
119 //
120 // PROC P_SetMessage
121 //
122 //--------------------------------------------------------------------------
123
124 // [WDJ] Replaces the Heretic ultimatemsg flag for IDKFA and IDDQD.
125 // That made the IDKFA and IDDQD message block most other messages,
126 // until the next player tic.
127 // But Legacy message timing is different and separate.
128 // A user control limits the messages seen based on the message level,
129 // (Off, minimal, normal, verbose, debug).
130 // This also uses the new message level as priority for competing messages
131 // that are issued in the same tic.
132
133 // Player Message for cheats and object interactions.
134 // Subject to message level control.
135 // This does not attempt to duplicate Heretic message blocking identically,
136 // as it has finer control.
137 // msglevel:
138 // 0..9 debug
139 // 10..19 verbose
140 // 20..29 normal play
141 // 30..39 minimal msg play
142 // 40..49 major
143 // 50..59 god mode messages
144 // 60..64 mandatory (even when messages are off)
P_SetMessage(player_t * player,char * message,byte msglevel)145 void P_SetMessage(player_t *player, char *message, byte msglevel)
146 {
147 // This actually optimizes cheaper than a table.
148 switch( cv_showmessages.EV )
149 {
150 case 5: // dev level
151 case 4: // debug level
152 break;
153 case 3: // verbose level
154 if( msglevel < 10 ) return;
155 break;
156 case 2: // play level
157 if( msglevel < 20 ) return;
158 break;
159 case 1: // minimal msg play level
160 if( msglevel < 30 ) return;
161 break;
162 default: // off
163 // Does not block mandatory messages.
164 if( msglevel < 60 ) return;
165 break;
166 }
167
168 // Check competing messages in same tic.
169 // Per player, to support splitplayer.
170 if( player->msglevel > msglevel )
171 return;
172
173 player->msglevel = msglevel;
174 player->message = message;
175 //player->messageTics = MESSAGETICS;
176 //BorderTopRefresh = true;
177 }
178
179 //
180 // GET STUFF
181 //
182
183 // added by Boris : preferred weapons order
VerifFavoritWeapon(player_t * player)184 void VerifFavoritWeapon (player_t *player)
185 {
186 int newweapon;
187
188 if (player->pendingweapon != wp_nochange)
189 return;
190
191 newweapon = FindBestWeapon(player);
192
193 if (newweapon != player->readyweapon)
194 player->pendingweapon = newweapon;
195 }
196
FindBestWeapon(player_t * player)197 int FindBestWeapon(player_t *player)
198 {
199 int actualprior, actualweapon = 0, i;
200
201 actualprior = -1;
202
203 for (i = 0; i < NUMWEAPONS; i++)
204 {
205 // skip super shotgun for non-Doom2
206 if (gamemode!=doom2_commercial && i==wp_supershotgun)
207 continue;
208 // skip plasma-bfg in shareware
209 if (gamemode==doom_shareware && (i==wp_plasma || i==wp_bfg))
210 continue;
211
212 if (player->weaponowned[i] &&
213 actualprior < player->favoritweapon[i] &&
214 player->ammo[player->weaponinfo[i].ammo] >= player->weaponinfo[i].ammopershoot)
215 {
216 actualweapon = i;
217 actualprior = player->favoritweapon[i];
218 }
219 }
220
221 return actualweapon;
222 }
223
224 static const weapontype_t GetAmmoChange[] =
225 {
226 wp_goldwand,
227 wp_crossbow,
228 wp_blaster,
229 wp_skullrod,
230 wp_phoenixrod,
231 wp_mace
232 };
233
234 //
235 // P_GiveAmmo
236 // Num is the number of clip loads,
237 // not the individual count (0= 1/2 clip).
238 // Returns false if the ammo can't be picked up at all
239 //
240
241 static
P_GiveAmmo(player_t * player,ammotype_t ammo,int count)242 boolean P_GiveAmmo ( player_t* player,
243 ammotype_t ammo,
244 int count )
245 {
246 unsigned int oldammo, newammo;
247
248 if (ammo == am_noammo)
249 return false;
250
251 if (ammo < 0 || ammo > NUMAMMO)
252 {
253 GenPrintf(EMSG_warn, "\2P_GiveAmmo: bad type %i", ammo);
254 return false;
255 }
256
257 oldammo = player->ammo[ammo];
258 if ( oldammo == player->maxammo[ammo] )
259 return false;
260 /*
261 if (num)
262 num *= clipammo[ammo];
263 else
264 num = clipammo[ammo]/2;
265 */
266 if (gameskill == sk_baby
267 || gameskill == sk_nightmare)
268 {
269 if( EN_heretic )
270 count += count>>1; // add 50% more
271 else
272 {
273 // give double ammo in trainer mode,
274 // you'll need in nightmare
275 count <<= 1; // add 100% more
276 }
277 }
278
279
280 newammo = oldammo + count;
281
282 if (newammo > player->maxammo[ammo])
283 newammo = player->maxammo[ammo];
284
285 player->ammo[ammo] = newammo;
286
287 if( newammo > oldammo )
288 {
289 // ammo pickup screen indication
290 if(ammo == player->weaponinfo[player->readyweapon].ammo)
291 {
292 player->ammo_pickup = PICKUP_FLASH_TICS; // ammo for current weapon
293 }
294 else
295 {
296 player->ammo_pickup += PICKUP_FLASH_TICS/2; // some other ammo
297 if( player->ammo_pickup > 35 )
298 player->ammo_pickup = 35;
299 }
300 }
301
302 // If non zero ammo,
303 // don't change up weapons,
304 // player was lower on purpose.
305 if (oldammo)
306 return true;
307
308 // We were down to zero,
309 // so select a new weapon.
310 // Preferences are not user selectable.
311
312 // Boris hack for preferred weapons order...
313 if(!player->originalweaponswitch)
314 {
315 if(player->ammo[player->weaponinfo[player->readyweapon].ammo]
316 < player->weaponinfo[player->readyweapon].ammopershoot)
317 VerifFavoritWeapon(player);
318 return true;
319 }
320 else //eof Boris
321 if( EN_heretic )
322 {
323 if( ( player->readyweapon == wp_staff
324 || player->readyweapon == wp_gauntlets)
325 && player->weaponowned[GetAmmoChange[ammo]])
326 player->pendingweapon = GetAmmoChange[ammo];
327 }
328 else
329 switch (ammo)
330 {
331 case am_clip:
332 if (player->readyweapon == wp_fist)
333 {
334 if (player->weaponowned[wp_chaingun])
335 player->pendingweapon = wp_chaingun;
336 else
337 player->pendingweapon = wp_pistol;
338 }
339 break;
340
341 case am_shell:
342 if (player->readyweapon == wp_fist
343 || player->readyweapon == wp_pistol)
344 {
345 if (player->weaponowned[wp_shotgun])
346 player->pendingweapon = wp_shotgun;
347 }
348 break;
349
350 case am_cell:
351 if (player->readyweapon == wp_fist
352 || player->readyweapon == wp_pistol)
353 {
354 if (player->weaponowned[wp_plasma])
355 player->pendingweapon = wp_plasma;
356 }
357 break;
358
359 case am_misl:
360 if (player->readyweapon == wp_fist)
361 {
362 if (player->weaponowned[wp_missile])
363 player->pendingweapon = wp_missile;
364 }
365 default:
366 break;
367 }
368
369 return true;
370 }
371
372 // ammo get with the weapon
373 int GetWeaponAmmo[NUMWEAPONS] =
374 {
375 0, // staff fist
376 20, // gold wand pistol
377 8, // crossbow shotgun
378 20, // blaster chaingun
379 2, // skull rod missile
380 40, // phoenix rod plasma
381 40, // mace bfg
382 0, // gauntlets chainsaw
383 8, // beak supershotgun
384 };
385
386 static int has_ammo_dropped = 0;
387 //
388 // P_GiveWeapon
389 // The weapon name may have a MF_DROPPED flag ored in.
390 //
391 static
P_GiveWeapon(player_t * player,weapontype_t weapon,boolean dropped)392 boolean P_GiveWeapon ( player_t* player,
393 weapontype_t weapon,
394 boolean dropped )
395 {
396 boolean gaveammo;
397 boolean gaveweapon;
398 int ammo_count;
399
400 // [WDJ] Orig: (cv_deathmatch != 2)
401 if( multiplayer && weapon_persist && !dropped )
402 {
403 // Deathmatch 1 and 3, map placed weapons persist.
404 // Each player can pick up each weapon type only once.
405
406 // leave placed weapons forever on net games
407 if (player->weaponowned[weapon])
408 return false;
409
410 player->bonuscount += BONUSADD;
411 player->weapon_pickup = PICKUP_FLASH_TICS;
412 player->weaponowned[weapon] = true;
413
414 if( deathmatch )
415 P_GiveAmmo (player, player->weaponinfo[weapon].ammo, 5*clipammo[player->weaponinfo[weapon].ammo]);
416 else // coop
417 P_GiveAmmo (player, player->weaponinfo[weapon].ammo, GetWeaponAmmo[weapon]);
418
419 // Boris hack preferred weapons order...
420 if(player->originalweaponswitch
421 || player->favoritweapon[weapon] > player->favoritweapon[player->readyweapon])
422 player->pendingweapon = weapon; // do like Doom2 original
423
424 //added:16-01-98:changed consoleplayer to displayplayer
425 // (hear the sounds from the viewpoint)
426 if (player == displayplayer_ptr
427 || (cv_splitscreen.EV && player == displayplayer2_ptr)) // NULL when unused
428 S_StartSound(sfx_wpnup);
429 return false;
430 }
431
432 if (player->weaponinfo[weapon].ammo != am_noammo)
433 {
434 // give one clip with a dropped weapon,
435 // two clips with a found weapon
436 if (dropped)
437 {
438 ammo_count = has_ammo_dropped ?
439 (has_ammo_dropped < 0 ? 0 : has_ammo_dropped) : clipammo[player->weaponinfo[weapon].ammo];
440 //gaveammo = P_GiveAmmo (player, player->weaponinfo[weapon].ammo, clipammo[player->weaponinfo[weapon].ammo]);
441 }
442 else
443 {
444 //gaveammo = P_GiveAmmo (player, player->weaponinfo[weapon].ammo, GetWeaponAmmo[weapon]);
445 ammo_count = GetWeaponAmmo[weapon];
446 }
447 gaveammo = P_GiveAmmo (player, player->weaponinfo[weapon].ammo, ammo_count);
448 }
449 else
450 gaveammo = false;
451
452 if (player->weaponowned[weapon])
453 gaveweapon = false;
454 else
455 {
456 gaveweapon = true;
457 player->weaponowned[weapon] = true;
458 player->weapon_pickup = PICKUP_FLASH_TICS;
459 if (player->originalweaponswitch
460 || player->favoritweapon[weapon] > player->favoritweapon[player->readyweapon])
461 player->pendingweapon = weapon; // Doom2 original stuff
462 }
463
464 return (gaveweapon || gaveammo);
465 }
466
467
468
469 //
470 // P_GiveHealth (P_GiveBody)
471 // Returns false if the health isn't needed at all
472 //
P_GiveHealth(player_t * player,int num)473 boolean P_GiveHealth ( player_t* player,
474 int num )
475 {
476 int max;
477
478 max = MAXHEALTH;
479 if(player->chickenTics)
480 max = MAXCHICKENHEALTH;
481
482 if (player->health >= max)
483 return false;
484
485 player->health += num;
486 if (player->health > max)
487 player->health = max;
488 player->mo->health = player->health;
489
490 player->health_pickup = PICKUP_FLASH_TICS;
491 return true;
492 }
493
494
495
496 //
497 // P_GiveArmor
498 // Returns false if the armor is worse
499 // than the current armor.
500 //
501 static
P_GiveArmor(player_t * player,int armortype)502 boolean P_GiveArmor ( player_t* player,
503 int armortype )
504 {
505 int hits;
506
507 hits = armortype*100;
508 if (player->armorpoints >= hits)
509 return false; // don't pick up
510
511 player->armortype = armortype;
512 player->armorpoints = hits;
513
514 player->armor_pickup = PICKUP_FLASH_TICS;
515 return true;
516 }
517
518
519
520 //
521 // P_GiveCard
522 //
523 static
P_GiveCard(player_t * player,card_t card)524 boolean P_GiveCard ( player_t* player,
525 card_t card )
526 {
527 if (player->cards & card )
528 return false;
529
530 player->cards |= card;
531 player->bonuscount = BONUSADD;
532 player->key_pickup = PICKUP_FLASH_TICS;
533 return true;
534 }
535
536
537 //
538 // P_GivePower
539 //
540 // power : powertype index
P_GivePower(player_t * player,int power)541 boolean P_GivePower ( player_t* player, int power )
542 {
543 // Was using inventory to detect heretic and hexen rules,
544 // but these rules have nothing to do with inventory.
545 if (power == pw_invulnerability)
546 {
547 // Already have it
548 if( EN_heretic_hexen && (player->powers[power] > BLINKTHRESHOLD ) )
549 return false;
550
551 player->powers[power] = INVULNTICS;
552 return true;
553 }
554 if(power == pw_weaponlevel2)
555 {
556 // Already have it
557 if( EN_heretic_hexen && (player->powers[power] > BLINKTHRESHOLD) )
558 return false;
559
560 player->powers[power] = WPNLEV2TICS;
561 player->weaponinfo = wpnlev2info;
562 return true;
563 }
564 if (power == pw_invisibility)
565 {
566 // Already have it
567 if( EN_heretic_hexen && (player->powers[power] > BLINKTHRESHOLD) )
568 return false;
569
570 player->powers[power] = INVISTICS;
571 player->mo->flags |= MF_SHADOW;
572 return true;
573 }
574 if(power == pw_flight)
575 {
576 // Already have it
577 if(player->powers[power] > BLINKTHRESHOLD)
578 return(false);
579
580 player->powers[power] = FLIGHTTICS;
581 player->mo->flags2 |= MF2_FLY;
582 player->mo->flags |= MF_NOGRAVITY;
583 if(player->mo->z <= player->mo->floorz)
584 {
585 player->flyheight = 10; // thrust the player in the air a bit
586 }
587 return(true);
588 }
589 if (power == pw_infrared)
590 {
591 // Already have it
592 if(player->powers[power] > BLINKTHRESHOLD)
593 return(false);
594
595 player->powers[power] = INFRATICS;
596 return true;
597 }
598
599 if (power == pw_ironfeet)
600 {
601 player->powers[power] = IRONTICS;
602 return true;
603 }
604
605 if (power == pw_strength)
606 {
607 P_GiveHealth (player, 100);
608 player->powers[power] = 1;
609 return true;
610 }
611
612 if (player->powers[power])
613 return false; // already got it
614
615 player->powers[power] = 1;
616 return true;
617 }
618
619 // Boris stuff : dehacked patches hack
620 int max_armor=200;
621 int green_armor_class=1;
622 int blue_armor_class=2;
623 int maxsoul=200;
624 int soul_health=100;
625 int mega_health=200;
626 // eof Boris
627
628 //---------------------------------------------------------------------------
629 //
630 // FUNC P_GiveArtifact
631 //
632 // Returns true if artifact accepted.
633 //
634 //---------------------------------------------------------------------------
635
P_GiveArtifact(player_t * player,artitype_t arti,mobj_t * mo)636 boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
637 {
638 int i;
639
640 i = 0;
641 while(player->inventory[i].type != arti && i < player->inventorySlotNum)
642 {
643 i++;
644 }
645 if(i == player->inventorySlotNum)
646 {
647 player->inventory[i].count = 1;
648 player->inventory[i].type = arti;
649 player->inventorySlotNum++;
650 }
651 else
652 {
653 if(player->inventory[i].count >= MAXARTECONT)
654 { // Player already has 16 of this item
655 return(false);
656 }
657 player->inventory[i].count++;
658 }
659 if( player->inventory[player->inv_ptr].count == 0 )
660 player->inv_ptr = i;
661
662 if(mo && (mo->flags&MF_COUNTITEM))
663 {
664 player->itemcount++;
665 }
666 return(true);
667 }
668
669
670 //---------------------------------------------------------------------------
671 //
672 // PROC P_SetDormantArtifact
673 //
674 // Removes the MF_SPECIAL flag, and initiates the artifact pickup
675 // animation.
676 //
677 //---------------------------------------------------------------------------
678
679 static
P_SetDormantArtifact(mobj_t * arti)680 void P_SetDormantArtifact(mobj_t *arti)
681 {
682 arti->flags &= ~MF_SPECIAL;
683 if( deathmatch
684 && (arti->type != MT_ARTIINVULNERABILITY )
685 && (arti->type != MT_ARTIINVISIBILITY) )
686 {
687 P_SetMobjState(arti, S_DORMANTARTI1);
688 }
689 else
690 { // Don't respawn
691 P_SetMobjState(arti, S_DEADARTI1);
692 }
693 S_StartObjSound(arti, sfx_artiup);
694 }
695
696 //---------------------------------------------------------------------------
697 //
698 // PROC A_RestoreArtifact
699 //
700 //---------------------------------------------------------------------------
701
A_RestoreArtifact(mobj_t * arti)702 void A_RestoreArtifact(mobj_t *arti)
703 {
704 arti->flags |= MF_SPECIAL;
705 P_SetMobjState(arti, arti->info->spawnstate);
706 S_StartObjSound(arti, sfx_itmbk);
707 }
708
709 //----------------------------------------------------------------------------
710 //
711 // PROC P_HideSpecialThing
712 //
713 //----------------------------------------------------------------------------
714
P_HideSpecialThing(mobj_t * thing)715 void P_HideSpecialThing(mobj_t *thing)
716 {
717 thing->flags &= ~MF_SPECIAL;
718 thing->flags2 |= MF2_DONTDRAW;
719 P_SetMobjState(thing, S_HIDESPECIAL1);
720 }
721
722 //---------------------------------------------------------------------------
723 //
724 // PROC A_RestoreSpecialThing1
725 //
726 // Make a special thing visible again.
727 //
728 //---------------------------------------------------------------------------
729
A_RestoreSpecialThing1(mobj_t * thing)730 void A_RestoreSpecialThing1(mobj_t *thing)
731 {
732 if(thing->type == MT_WMACE)
733 { // Do random mace placement
734 P_RepositionMace(thing);
735 }
736 thing->flags2 &= ~MF2_DONTDRAW;
737 S_StartObjSound(thing, sfx_itmbk);
738 }
739
740 //---------------------------------------------------------------------------
741 //
742 // PROC A_RestoreSpecialThing2
743 //
744 //---------------------------------------------------------------------------
745
A_RestoreSpecialThing2(mobj_t * thing)746 void A_RestoreSpecialThing2(mobj_t *thing)
747 {
748 thing->flags |= MF_SPECIAL;
749 P_SetMobjState(thing, thing->info->spawnstate);
750 }
751
752
753 //----------------------------------------------------------------------------
754 //
755 // PROC A_HideThing
756 //
757 //----------------------------------------------------------------------------
758
A_HideThing(mobj_t * actor)759 void A_HideThing(mobj_t *actor)
760 {
761 //P_UnsetThingPosition(actor);
762 actor->flags2 |= MF2_DONTDRAW;
763 }
764
765 //----------------------------------------------------------------------------
766 //
767 // PROC A_UnHideThing
768 //
769 //----------------------------------------------------------------------------
770
A_UnHideThing(mobj_t * actor)771 void A_UnHideThing(mobj_t *actor)
772 {
773 //P_SetThingPosition(actor);
774 actor->flags2 &= ~MF2_DONTDRAW;
775 }
776
777
778 //
779 // P_TouchSpecialThing
780 //
P_TouchSpecialThing(mobj_t * special,mobj_t * toucher)781 void P_TouchSpecialThing ( mobj_t* special,
782 mobj_t* toucher )
783 {
784 player_t* player;
785 char * msg = NULL;
786 byte msglevel = 20; // normal play for common ammo
787 spritenum_t group = 0xFFFF; // combined handling by spritenum
788 boolean special_dropped; // special item was dropped
789 int val, i;
790 fixed_t delta;
791 int sound;
792
793 delta = special->z - toucher->z;
794
795 //SoM: 3/27/2000: For some reason, the old code allowed the player to
796 //grab items that were out of reach...
797 if (delta > toucher->height
798 || delta < -special->height)
799 {
800 // out of reach
801 return;
802 }
803
804 // Dead thing touching.
805 // Can happen with a sliding player corpse.
806 if (toucher->health <= 0 || toucher->flags&MF_CORPSE)
807 return;
808
809 sound = sfx_itemup;
810 player = toucher->player;
811
812 if( player &&
813 toucher != player->mo ) // voodoo doll toucher
814 {
815 if( voodoo_mode >= VM_target )
816 {
817 // Target last player to trigger a switch or linedef.
818 if( spechit_player && spechit_player->mo )
819 {
820 player = spechit_player;
821 toucher = player->mo;
822 }
823 }
824 if( !player || !player->mo )
825 return; // player left or voodoo multiplayer spawn
826 }
827
828 #ifdef PARANOIA
829 if( !player )
830 I_Error("P_TouchSpecialThing: without player\n");
831 #endif
832
833
834 // FWF support
835 has_ammo_dropped = special->dropped_ammo_count;
836
837 // Avoid muiltiple conversions to boolean.
838 special_dropped = (boolean)(special->flags & MF_DROPPED);
839
840 // Identify by sprite.
841 switch (special->sprite)
842 {
843 case SPR_SHLD: // Item_Shield1
844 // armor
845 case SPR_ARM1: // common armor
846 if (!P_GiveArmor (player, green_armor_class))
847 return;
848 msg = GOTARMOR;
849 msglevel = 28;
850 break;
851
852 case SPR_SHD2: // Item_Shield2
853 case SPR_ARM2:
854 if (!P_GiveArmor (player, blue_armor_class))
855 return;
856 msg = GOTMEGA;
857 msglevel = 37;
858 break;
859
860 // bonus items
861 case SPR_BON1: // common health inc
862 val = player->health + 1; // can go over 100%
863 if (val > 2*MAXHEALTH)
864 val = 2*MAXHEALTH;
865 if((val > player->health) && (player->health_pickup < 35))
866 player->health_pickup += PICKUP_FLASH_TICS/2;
867 player->mo->health = player->health = val;
868 msg = GOTHTHBONUS;
869 msglevel = 22;
870 break;
871
872 case SPR_BON2: // common armor inc
873 val = player->armorpoints + 1; // can go over 100%
874 if (val > max_armor)
875 val = max_armor;
876 if((val > player->armorpoints) && (player->armor_pickup < 35))
877 player->armor_pickup += PICKUP_FLASH_TICS/2;
878 player->armorpoints = val;
879 if (!player->armortype)
880 player->armortype = 1;
881 msg = GOTARMBONUS;
882 msglevel = 22;
883 break;
884
885 case SPR_SOUL:
886 val = player->health + soul_health;
887 if (val > maxsoul)
888 val = maxsoul;
889 if((val > player->health) && (player->health_pickup < 35))
890 player->health_pickup += PICKUP_FLASH_TICS;
891 player->mo->health = player->health = val;
892 msg = GOTSUPER;
893 msglevel = 38;
894 sound = sfx_getpow;
895 break;
896
897 case SPR_MEGA:
898 if (gamemode != doom2_commercial)
899 return;
900 player->health = mega_health;
901 player->mo->health = player->health;
902 if(player->health_pickup < 35)
903 player->health_pickup += PICKUP_FLASH_TICS;
904 P_GiveArmor (player,2);
905 msg = GOTMSPHERE;
906 msglevel = 38;
907 sound = sfx_getpow;
908 break;
909
910 // cards
911 // leave cards for everyone
912 case SPR_BKYY: // Key_Blue
913 case SPR_BKEY:
914 group = SPR_BKEY;
915 if( P_GiveCard (player, it_bluecard) )
916 {
917 msg = GOTBLUECARD;
918 msglevel = 45;
919 }
920 break;
921
922 case SPR_CKYY: // Key_Yellow
923 case SPR_YKEY:
924 group = SPR_BKEY;
925 if( P_GiveCard (player, it_yellowcard) )
926 {
927 msg = GOTYELWCARD;
928 msglevel = 45;
929 }
930 break;
931
932 case SPR_AKYY: // Key_Green
933 case SPR_RKEY:
934 group = SPR_BKEY;
935 if (P_GiveCard (player, it_redcard))
936 {
937 msg = GOTREDCARD;
938 msglevel = 45;
939 }
940 break;
941
942 case SPR_BSKU:
943 group = SPR_BKEY;
944 if (P_GiveCard (player, it_blueskull))
945 {
946 msg = GOTBLUESKUL;
947 msglevel = 45;
948 }
949 break;
950
951 case SPR_YSKU:
952 group = SPR_BKEY;
953 if (P_GiveCard (player, it_yellowskull))
954 {
955 msg = GOTYELWSKUL;
956 msglevel = 45;
957 }
958 break;
959
960 case SPR_RSKU:
961 group = SPR_BKEY;
962 if (P_GiveCard (player, it_redskull))
963 {
964 msg = GOTREDSKULL;
965 msglevel = 45;
966 }
967 break;
968
969 // medikits, heals
970 case SPR_PTN1: // Item_HealingPotion
971 case SPR_STIM:
972 if (!P_GiveHealth (player, 10))
973 return;
974 msg = GOTSTIM;
975 break;
976
977 case SPR_MEDI:
978 // [WDJ] fix medkit message
979 // DoomWiki fix would put messages first, but that would give
980 // message even when not using the medkit
981 if (!P_GiveHealth (player, 25)) // add 25 to health
982 return;
983 // if health was used, then give message
984 // use fix from prboom, thanks to Quasar
985 if (player->health < 50) // old health was < 25, before adding 25
986 {
987 msg = GOTMEDINEED;
988 msglevel = 31;
989 }
990 else
991 {
992 msg = GOTMEDIKIT;
993 msglevel = 23;
994 }
995 break;
996
997 // heretic Artifacts :
998 case SPR_PTN2: // Arti_HealingPotion
999 if(P_GiveArtifact(player, arti_health, special))
1000 {
1001 P_SetMessage(player, TXT_ARTIHEALTH, 28);
1002 P_SetDormantArtifact(special);
1003 }
1004 return;
1005 case SPR_SOAR: // Arti_Fly
1006 if(P_GiveArtifact(player, arti_fly, special))
1007 {
1008 P_SetMessage(player, TXT_ARTIFLY, 31);
1009 P_SetDormantArtifact(special);
1010 }
1011 return;
1012 case SPR_INVU: // Arti_Invulnerability
1013 if(P_GiveArtifact(player, arti_invulnerability, special))
1014 {
1015 P_SetMessage(player, TXT_ARTIINVULNERABILITY, 31);
1016 P_SetDormantArtifact(special);
1017 }
1018 return;
1019 case SPR_PWBK: // Arti_TomeOfPower
1020 if(P_GiveArtifact(player, arti_tomeofpower, special))
1021 {
1022 P_SetMessage(player, TXT_ARTITOMEOFPOWER, 31);
1023 P_SetDormantArtifact(special);
1024 }
1025 return;
1026 case SPR_INVS: // Arti_Invisibility
1027 if(P_GiveArtifact(player, arti_invisibility, special))
1028 {
1029 P_SetMessage(player, TXT_ARTIINVISIBILITY, 31);
1030 P_SetDormantArtifact(special);
1031 }
1032 return;
1033 case SPR_EGGC: // Arti_Egg
1034 if(P_GiveArtifact(player, arti_egg, special))
1035 {
1036 P_SetMessage(player, TXT_ARTIEGG, 31);
1037 P_SetDormantArtifact(special);
1038 }
1039 return;
1040 case SPR_SPHL: // Arti_SuperHealth
1041 if(P_GiveArtifact(player, arti_superhealth, special))
1042 {
1043 P_SetMessage(player, TXT_ARTISUPERHEALTH, 31);
1044 P_SetDormantArtifact(special);
1045 }
1046 return;
1047 case SPR_TRCH: // Arti_Torch
1048 if(P_GiveArtifact(player, arti_torch, special))
1049 {
1050 P_SetMessage(player, TXT_ARTITORCH, 31);
1051 P_SetDormantArtifact(special);
1052 }
1053 return;
1054 case SPR_FBMB: // Arti_FireBomb
1055 if(P_GiveArtifact(player, arti_firebomb, special))
1056 {
1057 P_SetMessage(player, TXT_ARTIFIREBOMB, 31);
1058 P_SetDormantArtifact(special);
1059 }
1060 return;
1061 case SPR_ATLP: // Arti_Teleport
1062 if(P_GiveArtifact(player, arti_teleport, special))
1063 {
1064 P_SetMessage(player, TXT_ARTITELEPORT, 31);
1065 P_SetDormantArtifact(special);
1066 }
1067 return;
1068
1069 // power ups
1070 case SPR_PINV:
1071 if (!P_GivePower (player, pw_invulnerability))
1072 return;
1073 msg = GOTINVUL;
1074 msglevel = 34;
1075 sound = sfx_getpow;
1076 break;
1077
1078 case SPR_PSTR:
1079 if (!P_GivePower (player, pw_strength))
1080 return;
1081 msg = GOTBERSERK;
1082 msglevel = 34;
1083 if (player->readyweapon != wp_fist)
1084 player->pendingweapon = wp_fist;
1085 sound = sfx_getpow;
1086 break;
1087
1088 case SPR_PINS:
1089 if (!P_GivePower (player, pw_invisibility))
1090 return;
1091 msg = GOTINVIS;
1092 msglevel = 34;
1093 sound = sfx_getpow;
1094 break;
1095
1096 case SPR_SUIT:
1097 if (!P_GivePower (player, pw_ironfeet))
1098 return;
1099 msg = GOTSUIT;
1100 msglevel = 32;
1101 sound = sfx_getpow;
1102 break;
1103
1104 case SPR_SPMP: // Item_SuperMap
1105 case SPR_PMAP:
1106 if (!P_GivePower (player, pw_allmap))
1107 return;
1108 msg = GOTMAP;
1109 msglevel = 31;
1110 if( EN_doom_etc )
1111 sound = sfx_getpow;
1112 break;
1113
1114 case SPR_PVIS:
1115 if (!P_GivePower (player, pw_infrared))
1116 return;
1117 msg = GOTVISOR;
1118 msglevel = 32;
1119 sound = sfx_getpow;
1120 break;
1121
1122 // heretic Ammo
1123 case SPR_AMG1: // Ammo_GoldWandWimpy
1124 if(!P_GiveAmmo(player, am_goldwand, special->health))
1125 return;
1126 msg = TXT_AMMOGOLDWAND1;
1127 break;
1128 case SPR_AMG2: // Ammo_GoldWandHefty
1129 if(!P_GiveAmmo(player, am_goldwand, special->health))
1130 return;
1131 msg = TXT_AMMOGOLDWAND2;
1132 break;
1133 case SPR_AMM1: // Ammo_MaceWimpy
1134 if(!P_GiveAmmo(player, am_mace, special->health))
1135 return;
1136 msg = TXT_AMMOMACE1;
1137 break;
1138 case SPR_AMM2: // Ammo_MaceHefty
1139 if(!P_GiveAmmo(player, am_mace, special->health))
1140 return;
1141 msg = TXT_AMMOMACE2;
1142 break;
1143 case SPR_AMC1: // Ammo_CrossbowWimpy
1144 if(!P_GiveAmmo(player, am_crossbow, special->health))
1145 return;
1146 msg = TXT_AMMOCROSSBOW1;
1147 break;
1148 case SPR_AMC2: // Ammo_CrossbowHefty
1149 if(!P_GiveAmmo(player, am_crossbow, special->health))
1150 return;
1151 msg = TXT_AMMOCROSSBOW2;
1152 break;
1153 case SPR_AMB1: // Ammo_BlasterWimpy
1154 if(!P_GiveAmmo(player, am_blaster, special->health))
1155 return;
1156 msg = TXT_AMMOBLASTER1;
1157 break;
1158 case SPR_AMB2: // Ammo_BlasterHefty
1159 if(!P_GiveAmmo(player, am_blaster, special->health))
1160 return;
1161 msg = TXT_AMMOBLASTER2;
1162 break;
1163 case SPR_AMS1: // Ammo_SkullRodWimpy
1164 if(!P_GiveAmmo(player, am_skullrod, special->health))
1165 return;
1166 msg = TXT_AMMOSKULLROD1;
1167 break;
1168 case SPR_AMS2: // Ammo_SkullRodHefty
1169 if(!P_GiveAmmo(player, am_skullrod, special->health))
1170 return;
1171 msg = TXT_AMMOSKULLROD2;
1172 break;
1173 case SPR_AMP1: // Ammo_PhoenixRodWimpy
1174 if(!P_GiveAmmo(player, am_phoenixrod, special->health))
1175 return;
1176 msg = TXT_AMMOPHOENIXROD1;
1177 break;
1178 case SPR_AMP2: // Ammo_PhoenixRodHefty
1179 if(!P_GiveAmmo(player, am_phoenixrod, special->health))
1180 return;
1181 msg = TXT_AMMOPHOENIXROD2;
1182 break;
1183
1184 // ammo
1185 case SPR_CLIP:
1186 if (!P_GiveAmmo (player, am_clip,
1187 ((special_dropped)? clipammo[am_clip]/2 : clipammo[am_clip]) ))
1188 msg = GOTCLIP;
1189 break;
1190
1191 case SPR_AMMO:
1192 if (!P_GiveAmmo (player, am_clip,5*clipammo[am_clip]))
1193 return;
1194 msg = GOTCLIPBOX;
1195 break;
1196
1197 case SPR_ROCK:
1198 if (!P_GiveAmmo (player, am_misl,clipammo[am_misl]))
1199 return;
1200 msg = GOTROCKET;
1201 break;
1202
1203 case SPR_BROK:
1204 if (!P_GiveAmmo (player, am_misl,5*clipammo[am_misl]))
1205 return;
1206 msg = GOTROCKBOX;
1207 break;
1208
1209 case SPR_CELL:
1210 if (!P_GiveAmmo (player, am_cell,clipammo[am_cell]))
1211 return;
1212 msg = GOTCELL;
1213 break;
1214
1215 case SPR_CELP:
1216 if (!P_GiveAmmo (player, am_cell,5*clipammo[am_cell]))
1217 return;
1218 msg = GOTCELLBOX;
1219 break;
1220
1221 case SPR_SHEL:
1222 if (!P_GiveAmmo (player, am_shell,clipammo[am_shell]))
1223 return;
1224 msg = GOTSHELLS;
1225 break;
1226
1227 case SPR_SBOX:
1228 if (!P_GiveAmmo (player, am_shell,5*clipammo[am_shell]))
1229 return;
1230 msg = GOTSHELLBOX;
1231 break;
1232
1233 case SPR_BPAK:
1234 if (!player->backpack)
1235 {
1236 for (i=0 ; i<NUMAMMO ; i++)
1237 player->maxammo[i] *= 2;
1238 player->backpack = true;
1239 }
1240 for (i=0 ; i<NUMAMMO ; i++)
1241 P_GiveAmmo (player, i, clipammo[i]);
1242 msg = GOTBACKPACK;
1243 msglevel = 27;
1244 break;
1245
1246 case SPR_BAGH: // Item_BagOfHolding
1247 if(!player->backpack)
1248 {
1249 for(i = 0; i < NUMAMMO; i++)
1250 player->maxammo[i] *= 2;
1251 player->backpack = true;
1252 }
1253 P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY);
1254 P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY);
1255 P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
1256 P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
1257 P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
1258 msg = TXT_ITEMBAGOFHOLDING;
1259 msglevel = 27;
1260 break;
1261
1262 // weapons
1263 case SPR_BFUG:
1264 if (!P_GiveWeapon (player, wp_bfg, special_dropped) )
1265 return;
1266 msg = GOTBFG9000;
1267 msglevel = 38;
1268 sound = sfx_wpnup;
1269 break;
1270
1271 case SPR_MGUN:
1272 if (!P_GiveWeapon (player, wp_chaingun, special_dropped) )
1273 return;
1274 msg = GOTCHAINGUN;
1275 msglevel = 29;
1276 sound = sfx_wpnup;
1277 break;
1278
1279 case SPR_CSAW:
1280 if (!P_GiveWeapon (player, wp_chainsaw, false) )
1281 return;
1282 msg = GOTCHAINSAW;
1283 msglevel = 21;
1284 sound = sfx_wpnup;
1285 break;
1286
1287 case SPR_LAUN:
1288 if (!P_GiveWeapon (player, wp_missile, special_dropped) )
1289 return;
1290 msg = GOTLAUNCHER;
1291 msglevel = 32;
1292 sound = sfx_wpnup;
1293 break;
1294
1295 case SPR_PLAS:
1296 if (!P_GiveWeapon (player, wp_plasma, special_dropped) )
1297 return;
1298 msg = GOTPLASMA;
1299 msglevel = 32;
1300 sound = sfx_wpnup;
1301 break;
1302
1303 case SPR_SHOT:
1304 if (!P_GiveWeapon (player, wp_shotgun, special_dropped) )
1305 return;
1306 msg = GOTSHOTGUN;
1307 msglevel = 24;
1308 sound = sfx_wpnup;
1309 break;
1310
1311 case SPR_SGN2:
1312 if (!P_GiveWeapon (player, wp_supershotgun, special_dropped) )
1313 return;
1314 msg = GOTSHOTGUN2;
1315 msglevel = 32;
1316 sound = sfx_wpnup;
1317 break;
1318
1319 // heretic weapons
1320 case SPR_WMCE: // Weapon_Mace
1321 if(!P_GiveWeapon(player, wp_mace, special_dropped))
1322 return;
1323 msg = TXT_WPNMACE;
1324 msglevel = 32;
1325 sound = sfx_wpnup;
1326 break;
1327 case SPR_WBOW: // Weapon_Crossbow
1328 if(!P_GiveWeapon(player, wp_crossbow, special_dropped))
1329 return;
1330 msg = TXT_WPNCROSSBOW;
1331 msglevel = 24;
1332 sound = sfx_wpnup;
1333 break;
1334 case SPR_WBLS: // Weapon_Blaster
1335 if(!P_GiveWeapon(player, wp_blaster, special_dropped))
1336 return;
1337 msg = TXT_WPNBLASTER;
1338 msglevel = 32;
1339 sound = sfx_wpnup;
1340 break;
1341 case SPR_WSKL: // Weapon_SkullRod
1342 if(!P_GiveWeapon(player, wp_skullrod, special_dropped))
1343 return;
1344 msg = TXT_WPNSKULLROD;
1345 msglevel = 36;
1346 sound = sfx_wpnup;
1347 break;
1348 case SPR_WPHX: // Weapon_PhoenixRod
1349 if(!P_GiveWeapon(player, wp_phoenixrod, special_dropped))
1350 return;
1351 msg = TXT_WPNPHOENIXROD;
1352 msglevel = 38;
1353 sound = sfx_wpnup;
1354 break;
1355 case SPR_WGNT: // Weapon_Gauntlets
1356 if(!P_GiveWeapon(player, wp_gauntlets, false))
1357 return;
1358 msg = TXT_WPNGAUNTLETS;
1359 msglevel = 21;
1360 sound = sfx_wpnup;
1361 break;
1362
1363 default:
1364 // SoM: New gettable things with FraggleScript!
1365 //debug_Printf ("\2P_TouchSpecialThing: Unknown gettable thing\n");
1366 return;
1367 }
1368
1369 if( msg )
1370 {
1371 P_SetMessage( player, msg, msglevel );
1372 }
1373 if( group == SPR_BKEY ) // all keys
1374 {
1375 // keycard
1376 if( EN_heretic )
1377 sound = sfx_keyup;
1378 if (multiplayer) return; // leave keys in multiplayer
1379 }
1380
1381 if (special->flags & MF_COUNTITEM)
1382 player->itemcount++;
1383 P_RemoveMobj ( special );
1384 player->bonuscount += BONUSADD;
1385
1386 //added:16-01-98:consoleplayer -> displayplayer (hear sounds from viewpoint)
1387 if (player == displayplayer_ptr
1388 || (cv_splitscreen.EV && player == displayplayer2_ptr)) // NULL when unused
1389 S_StartSound(sound);
1390 }
1391
1392
1393
1394 #ifdef thatsbuggycode
1395 //
1396 // Tell each supported thing to check again its position,
1397 // because the 'base' thing has vanished or diminished,
1398 // the supported things might fall.
1399 //
1400 //added:28-02-98:
P_CheckSupportThings(mobj_t * mobj)1401 void P_CheckSupportThings (mobj_t* mobj)
1402 {
1403 fixed_t supportz = mobj->z + mobj->height;
1404
1405 while ((mobj = mobj->supportthings))
1406 {
1407 // only for things above support thing
1408 if (mobj->z > supportz)
1409 mobj->eflags |= MF_CHECKPOS;
1410 }
1411 }
1412
1413
1414 //
1415 // If a thing moves and supportthings,
1416 // move the supported things along.
1417 //
1418 //added:28-02-98:
P_MoveSupportThings(mobj_t * mobj,fixed_t xmove,fixed_t ymove,fixed_t zmove)1419 void P_MoveSupportThings (mobj_t* mobj, fixed_t xmove, fixed_t ymove, fixed_t zmove)
1420 {
1421 fixed_t supportz = mobj->z + mobj->height;
1422 mobj_t *mo = mobj->supportthings;
1423
1424 while (mo)
1425 {
1426 //added:28-02-98:debug
1427 if (mo==mobj)
1428 {
1429 mobj->supportthings = NULL;
1430 break;
1431 }
1432
1433 // only for things above support thing
1434 if (mobj->z > supportz)
1435 {
1436 mobj->eflags |= MF_CHECKPOS;
1437 mobj->momx += xmove;
1438 mobj->momy += ymove;
1439 mobj->momz += zmove;
1440 }
1441
1442 mo = mo->supportthings;
1443 }
1444 }
1445
1446
1447 //
1448 // Link a thing to it's 'base' (supporting) thing.
1449 // When the supporting thing will move or change size,
1450 // the supported will then be aware.
1451 //
1452 //added:28-02-98:
P_LinkFloorThing(mobj_t * mobj)1453 void P_LinkFloorThing(mobj_t* mobj)
1454 {
1455 mobj_t* mo;
1456 mobj_t* nmo;
1457
1458 // no supporting thing
1459 if (!(mo = mobj->floorthing))
1460 return;
1461
1462 // link mobj 'above' the lower mobjs, so that lower supporting
1463 // mobjs act upon this mobj
1464 while ( (nmo = mo->supportthings) &&
1465 (nmo->z<=mobj->z) )
1466 {
1467 // dont link multiple times
1468 if (nmo==mobj)
1469 return;
1470
1471 mo = nmo;
1472 }
1473 mo->supportthings = mobj;
1474 mobj->supportthings = nmo;
1475 }
1476
1477
1478 //
1479 // Unlink a thing from it's support,
1480 // when it's 'floorthing' has changed,
1481 // before linking with the new 'floorthing'.
1482 //
1483 //added:28-02-98:
P_UnlinkFloorThing(mobj_t * mobj)1484 void P_UnlinkFloorThing(mobj_t* mobj)
1485 {
1486 mobj_t* mo;
1487
1488 if (!(mo = mobj->floorthing)) // just to be sure (may happen)
1489 return;
1490
1491 while (mo->supportthings)
1492 {
1493 if (mo->supportthings == mobj)
1494 {
1495 mo->supportthings = NULL;
1496 break;
1497 }
1498 mo = mo->supportthings;
1499 }
1500 }
1501 #endif
1502
1503
1504 #define BUFFSIZE 512
1505 // Death messages relating to the target (dying) player
1506 //
1507 static
P_DeathMessages(mobj_t * target,mobj_t * inflictor,mobj_t * source)1508 void P_DeathMessages ( mobj_t* target,
1509 mobj_t* inflictor,
1510 mobj_t* source )
1511 {
1512 char txt[BUFFSIZE+1];
1513 int w;
1514 char *str;
1515
1516 if (!target || !target->player)
1517 return;
1518
1519 if (target->player->mo != target ) // voodoo doll died
1520 return;
1521
1522 if (source && source->player)
1523 {
1524 if (source->player==target->player)
1525 {
1526 str = text[DEATHMSG_SUICIDE];
1527 snprintf(txt, BUFFSIZE, str, player_names[target->player - players]);
1528 txt[BUFFSIZE-1] = 0;
1529 GenPrintf(EMSG_playmsg, txt);
1530 if( cv_splitscreen.EV )
1531 GenPrintf(EMSG_playmsg2, txt);
1532 }
1533 else
1534 {
1535 if (target->health < -9000) // telefrag !
1536 str = text[DEATHMSG_TELEFRAG];
1537 else
1538 {
1539 w = source->player->readyweapon;
1540 if( inflictor )
1541 {
1542 switch(inflictor->type) {
1543 case MT_ROCKET : w = wp_missile; break;
1544 case MT_PLASMA : w = wp_plasma; break;
1545 case MT_EXTRABFG :
1546 case MT_BFG : w = wp_bfg; break;
1547 default : break;
1548 }
1549 }
1550
1551 switch(w)
1552 {
1553 case wp_fist:
1554 str = text[DEATHMSG_FIST];
1555 break;
1556 case wp_pistol:
1557 str = text[DEATHMSG_GUN];
1558 break;
1559 case wp_shotgun:
1560 str = text[DEATHMSG_SHOTGUN];
1561 break;
1562 case wp_chaingun:
1563 str = text[DEATHMSG_MACHGUN];
1564 break;
1565 case wp_missile:
1566 str = text[DEATHMSG_ROCKET];
1567 if (target->health < -target->info->spawnhealth &&
1568 target->info->xdeathstate)
1569 str = text[DEATHMSG_GIBROCKET];
1570 break;
1571 case wp_plasma:
1572 str = text[DEATHMSG_PLASMA];
1573 break;
1574 case wp_bfg:
1575 str = text[DEATHMSG_BFGBALL];
1576 break;
1577 case wp_chainsaw:
1578 str = text[DEATHMSG_CHAINSAW];
1579 break;
1580 case wp_supershotgun:
1581 str = text[DEATHMSG_SUPSHOTGUN];
1582 break;
1583 default:
1584 str = text[DEATHMSG_PLAYUNKNOW];
1585 break;
1586 }
1587 }
1588
1589 snprintf(txt, BUFFSIZE, str,
1590 player_names[target->player - players],
1591 player_names[source->player - players]);
1592 txt[BUFFSIZE-1] = 0;
1593 GenPrintf(EMSG_playmsg, txt);
1594 if( cv_splitscreen.EV )
1595 GenPrintf(EMSG_playmsg2, txt);
1596 }
1597 }
1598 else
1599 {
1600 if (!source)
1601 {
1602 // environment kills
1603 w = target->player->specialsector; //see p_spec.c
1604
1605 if (w==5)
1606 str = text[DEATHMSG_HELLSLIME];
1607 else if (w==7)
1608 str = text[DEATHMSG_NUKE];
1609 else if (w==16 || w==4)
1610 str = text[DEATHMSG_SUPHELLSLIME];
1611 else
1612 str = text[DEATHMSG_SPECUNKNOW];
1613 }
1614 else
1615 {
1616 // check for lava,slime,water,crush,fall,monsters..
1617 if (source->type == MT_BARREL)
1618 {
1619 if (source->target->player)
1620 {
1621 GenPrintf(EMSG_playmsg, text[DEATHMSG_BARRELFRAG],
1622 player_names[target->player - players],
1623 player_names[source->target->player - players]);
1624 return;
1625 }
1626 else
1627 str = text[DEATHMSG_BARREL];
1628 }
1629 else
1630 switch (source->type)
1631 {
1632 case MT_POSSESSED: str = text[DEATHMSG_POSSESSED]; break;
1633 case MT_SHOTGUY: str = text[DEATHMSG_SHOTGUY]; break;
1634 case MT_VILE: str = text[DEATHMSG_VILE]; break;
1635 case MT_FATSO: str = text[DEATHMSG_FATSO]; break;
1636 case MT_CHAINGUY: str = text[DEATHMSG_CHAINGUY]; break;
1637 case MT_TROOP: str = text[DEATHMSG_TROOP]; break;
1638 case MT_SERGEANT: str = text[DEATHMSG_SERGEANT]; break;
1639 case MT_SHADOWS: str = text[DEATHMSG_SHADOWS]; break;
1640 case MT_HEAD: str = text[DEATHMSG_HEAD]; break;
1641 case MT_BRUISER: str = text[DEATHMSG_BRUISER]; break;
1642 case MT_UNDEAD: str = text[DEATHMSG_UNDEAD]; break;
1643 case MT_KNIGHT: str = text[DEATHMSG_KNIGHT]; break;
1644 case MT_SKULL: str = text[DEATHMSG_SKULL]; break;
1645 case MT_SPIDER: str = text[DEATHMSG_SPIDER]; break;
1646 case MT_BABY: str = text[DEATHMSG_BABY]; break;
1647 case MT_CYBORG: str = text[DEATHMSG_CYBORG]; break;
1648 case MT_PAIN: str = text[DEATHMSG_PAIN]; break;
1649 case MT_WOLFSS: str = text[DEATHMSG_WOLFSS]; break;
1650 default: str = text[DEATHMSG_DEAD]; break;
1651 }
1652 }
1653 GenPrintf(EMSG_playmsg, str, player_names[target->player - players]);
1654 }
1655 }
1656
1657 // WARNING : check cv_fraglimit>0 before call this function !
P_CheckFragLimit(player_t * p)1658 void P_CheckFragLimit(player_t *p)
1659 {
1660 int fragteam = 0;
1661 if( cv_teamplay.EV )
1662 {
1663 int i;
1664 for(i=0;i<MAXPLAYERS;i++)
1665 {
1666 if(ST_SameTeam(p,&players[i]))
1667 fragteam += ST_PlayerFrags(i);
1668 }
1669 }
1670 else
1671 {
1672 fragteam = ST_PlayerFrags(p - players);
1673 }
1674 // CV_VALUE, may be too large for EV
1675 if( fragteam >= cv_fraglimit.value )
1676 G_ExitLevel();
1677 }
1678
1679
1680 /************************************************************
1681 *
1682 * Returns ammo count in current weapon
1683 *
1684 ************************************************************
1685 */
1686 static
P_AmmoInWeapon(player_t * player)1687 int P_AmmoInWeapon(player_t *player)
1688 {
1689 ammotype_t ammo = player->weaponinfo[player->readyweapon].ammo;
1690 int ammo_count = player->ammo[ammo];
1691
1692 return ammo == am_noammo ? 0
1693 : ammo_count ? ammo_count : -1;
1694 }
1695
1696
1697 // P_KillMobj
1698 //
1699 // source is the attacker, (for revenge, frags)
1700 // target is the 'target' of the attack, target dies...
1701 // inflictor is the weapon, missile, creature melee, or NULL, (for messages)
1702 // 113
P_KillMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source)1703 void P_KillMobj ( mobj_t* target,
1704 mobj_t* inflictor,
1705 mobj_t* source )
1706 {
1707 mobjtype_t item = 0;
1708 mobj_t* mo;
1709 int drop_ammo_count = 0;
1710
1711 // dead target is no more shootable
1712 if( ! cv_solidcorpse.EV )
1713 target->flags &= ~MF_SHOOTABLE;
1714
1715 target->flags &= ~(MF_FLOAT|MF_SKULLFLY);
1716
1717 if (target->type != MT_SKULL)
1718 target->flags &= ~MF_NOGRAVITY;
1719
1720 #ifdef DOGS
1721 // [WDJ] MBF dogs, extension for DoomLegacy.
1722 if( (target->type == MT_DOG) || (target->type == helper_MT) )
1723 G_KillDog( target );
1724 #endif
1725
1726 // scream a corpse :)
1727 if( target->flags & MF_CORPSE )
1728 {
1729 // Turn it to gibs.
1730 P_SetMobjState (target, S_GIBS);
1731
1732 target->flags &= ~MF_SOLID;
1733 target->height = 0;
1734 target->radius<<= 1;
1735 target->skin = 0;
1736
1737 //added:22-02-98: lets have a neat 'crunch' sound!
1738 S_StartObjSound(target, sfx_slop);
1739 return;
1740 }
1741
1742 //added:22-02-98: remember who exploded the barrel, so that the guy who
1743 // shot the barrel which killed another guy, gets the frag!
1744 // (source is passed from barrel to barrel also!)
1745 // (only for multiplayer fun, does not remember monsters)
1746 if ((target->type == MT_BARREL || target->type == MT_POD)
1747 && source && source->player)
1748 {
1749 P_SetReference(target->target, source);
1750 target->target = source;
1751 }
1752
1753 if( EV_legacy < 131 ) // old Legacy, Boom, MBF
1754 {
1755 // Version 131 and after this is done later in A_Fall.
1756 // (this fix the stepping monster)
1757 target->flags |= MF_CORPSE|MF_DROPOFF;
1758 target->height >>= 2;
1759 if( EV_legacy >= 112 )
1760 target->radius -= (target->radius>>4); //for solid corpses
1761 }
1762 // show death messages, only if it concern the console player
1763 // (be it an attacker or a target)
1764 if (target->player && (target->player == consoleplayer_ptr) )
1765 P_DeathMessages (target, inflictor, source);
1766 else
1767 if (source && source->player && (source->player == consoleplayer_ptr) )
1768 P_DeathMessages (target, inflictor, source);
1769 else
1770 if (target->player && target->player->bot) //added by AC for acbot
1771 P_DeathMessages (target, inflictor, source);
1772
1773
1774
1775 // if killed by a player
1776 if (source && source->player)
1777 {
1778 // count for intermission
1779 if (target->flags & MF_COUNTKILL)
1780 source->player->killcount++;
1781
1782 // count frags if player killed player
1783 if (target->player)
1784 {
1785 source->player->frags[target->player-players]++;
1786 if( EN_heretic )
1787 {
1788 if(source->player == displayplayer_ptr
1789 || source->player == displayplayer2_ptr )
1790 S_StartSound(sfx_gfrag);
1791
1792 // Make a super chicken
1793 if(source->player->chickenTics)
1794 P_GivePower(source->player, pw_weaponlevel2);
1795 }
1796 // check fraglimit cvar
1797 if (cv_fraglimit.value)
1798 P_CheckFragLimit(source->player);
1799 }
1800 }
1801 else if (!multiplayer && (target->flags & MF_COUNTKILL))
1802 {
1803 // count all monster deaths,
1804 // even those caused by other monsters
1805 players[0].killcount++;
1806 }
1807
1808 // if a player avatar dies...
1809 if (target->player)
1810 {
1811 // count environment kills against you (you fragged yourself!)
1812 if (!source)
1813 target->player->frags[target->player-players]++;
1814
1815 if( ! cv_solidcorpse.EV )
1816 target->flags &= ~MF_SOLID; // does not block
1817 target->flags2 &= ~MF2_FLY;
1818 target->player->powers[pw_flight] = 0;
1819 target->player->powers[pw_weaponlevel2] = 0;
1820 target->player->playerstate = PST_DEAD;
1821 P_DropWeapon (target->player); // put weapon away
1822 if (target->player == consoleplayer_ptr )
1823 {
1824 // don't die in auto map,
1825 // switch view prior to dying
1826 if (automapactive)
1827 AM_Stop ();
1828
1829 //added:22-02-98: recenter view for next live...
1830 localaiming[0] = 0;
1831 }
1832 if (target->player == displayplayer2_ptr) // NULL when unused
1833 {
1834 // player 2
1835 //added:22-02-98: recenter view for next live...
1836 localaiming[1] = 0;
1837 }
1838 /* HERETODO
1839 if(target->flags2&MF2_FIREDAMAGE)
1840 { // Player flame death
1841 P_SetMobjState(target, S_PLAY_FDTH1);
1842 //S_StartObjSound(target, sfx_hedat1); // Burn sound
1843 goto done;
1844 }
1845 */
1846 }
1847
1848 if ( target->info->xdeathstate
1849 && ( target->health < -(
1850 (EN_heretic)? (target->info->spawnhealth>>1) // heretic
1851 : target->info->spawnhealth // doom
1852 ) )
1853 )
1854 {
1855 P_SetMobjState (target, target->info->xdeathstate);
1856 }
1857 else
1858 P_SetMobjState (target, target->info->deathstate);
1859
1860 target->tics -= PP_Random(pr_killtics)&3;
1861
1862 if (target->tics < 1)
1863 target->tics = 1;
1864
1865 // Drop stuff.
1866 // This determines the kind of object spawned
1867 // during the death frame of a thing.
1868
1869 // Frags Weapon Falling support
1870 if( target->player && cv_fragsweaponfalling.EV )
1871 {
1872 drop_ammo_count = P_AmmoInWeapon(target->player);
1873 //if (!drop_ammo_count)
1874 // goto done;
1875
1876 if (EN_heretic)
1877 {
1878 switch (target->player->readyweapon)
1879 {
1880 case wp_crossbow:
1881 item = MT_HMISC15;
1882 break;
1883
1884 case wp_blaster:
1885 item = MT_RIPPER;
1886 break;
1887
1888 case wp_skullrod:
1889 item = MT_WSKULLROD;
1890 break;
1891
1892 case wp_phoenixrod:
1893 item = MT_WPHOENIXROD;
1894 break;
1895
1896 case wp_mace:
1897 item = MT_WMACE;
1898 break;
1899
1900 default:
1901 //debug_Printf("Unknown weapon %d\n", target->player->readyweapon);
1902 goto done;
1903 }
1904 }
1905 else
1906 {
1907 switch (target->player->readyweapon)
1908 {
1909 case wp_shotgun:
1910 item = MT_SHOTGUN;
1911 break;
1912
1913 case wp_supershotgun:
1914 item = MT_SUPERSHOTGUN;
1915 break;
1916
1917 case wp_chaingun:
1918 item = MT_CHAINGUN;
1919 break;
1920
1921 case wp_missile:
1922 item = MT_ROCKETLAUNCH;
1923 break;
1924
1925 case wp_plasma:
1926 item = MT_PLASMAGUN;
1927 break;
1928
1929 case wp_bfg:
1930 item = MT_BFG9000;
1931 break;
1932
1933 default:
1934 //debug_Printf("Unknown weapon %d\n", target->player->readyweapon);
1935 goto done;
1936 }
1937 }
1938 }
1939 else
1940 {
1941 //DarkWolf95: Support for Chex Quest
1942 if(gamemode == chexquest1) //don't drop monster ammo in chex quest
1943 goto done;
1944
1945 switch (target->type)
1946 {
1947 case MT_WOLFSS:
1948 case MT_POSSESSED:
1949 item = MT_CLIP;
1950 break;
1951
1952 case MT_SHOTGUY:
1953 item = MT_SHOTGUN;
1954 break;
1955
1956 case MT_CHAINGUY:
1957 item = MT_CHAINGUN;
1958 break;
1959
1960 default:
1961 goto done;
1962 }
1963 }
1964
1965 // SoM: Damnit! Why not use the target's floorz?
1966 // Doom, Boom, MBF use ONFLOORZ.
1967 mo = P_SpawnMobj (target->x, target->y,
1968 ((EV_legacy < 132) ? ONFLOORZ : target->floorz), item);
1969 mo->flags |= MF_DROPPED; // special versions of items
1970
1971 if( !cv_fragsweaponfalling.EV )
1972 drop_ammo_count = 0; // Doom default ammo count
1973
1974 mo->dropped_ammo_count = drop_ammo_count;
1975
1976 done:
1977 return;
1978 }
1979
1980
1981 //---------------------------------------------------------------------------
1982 //
1983 // FUNC P_MinotaurSlam
1984 //
1985 //---------------------------------------------------------------------------
1986
1987 static
P_MinotaurSlam(mobj_t * source,mobj_t * target)1988 void P_MinotaurSlam(mobj_t *source, mobj_t *target)
1989 {
1990 angle_t angle;
1991 fixed_t thrust;
1992
1993 angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
1994 thrust = 16*FRACUNIT + (PP_Random(ph_minoslam)<<10);
1995 target->momx += FixedMul(thrust, cosine_ANG(angle));
1996 target->momy += FixedMul(thrust, sine_ANG(angle));
1997 P_DamageMobj(target, NULL, NULL, HITDICE(6));
1998 if(target->player)
1999 {
2000 target->reactiontime = 14 + (PP_Random(ph_minoslam)&7);
2001 }
2002 }
2003
2004 //---------------------------------------------------------------------------
2005 //
2006 // FUNC P_TouchWhirlwind
2007 //
2008 //---------------------------------------------------------------------------
2009
2010 static
P_TouchWhirlwind(mobj_t * target)2011 boolean P_TouchWhirlwind(mobj_t *target)
2012 {
2013 int randVal;
2014
2015 target->angle += PP_SignedRandom(ph_whirlwind)<<20;
2016 target->momx += PP_SignedRandom(ph_whirlwind)<<10;
2017 target->momy += PP_SignedRandom(ph_whirlwind)<<10;
2018 if(leveltime&16 && !(target->flags2&MF2_BOSS))
2019 {
2020 randVal = PP_Random(ph_whirlwind);
2021 if(randVal > 160)
2022 {
2023 randVal = 160;
2024 }
2025 target->momz += randVal<<10;
2026 if(target->momz > 12*FRACUNIT)
2027 {
2028 target->momz = 12*FRACUNIT;
2029 }
2030 }
2031 if(!(leveltime&7))
2032 {
2033 return P_DamageMobj(target, NULL, NULL, 3);
2034 }
2035 return false;
2036 }
2037
2038
2039 //---------------------------------------------------------------------------
2040 //
2041 // FUNC P_ChickenMorphPlayer
2042 //
2043 // Returns true if the player gets turned into a chicken.
2044 //
2045 //---------------------------------------------------------------------------
2046
2047 // [WDJ] Fixed to keep the same player mobj.
2048 // Used to change the player mobj, and hide the prev as a corpse above
2049 // the ceiling using S_FREETARGMOBJ. This could happen in Line attack or Damage.
P_ChickenMorphPlayer(player_t * player)2050 boolean P_ChickenMorphPlayer(player_t *player)
2051 {
2052 mobj_t *pmo;
2053 int oldflags2;
2054
2055 if(player->chickenTics)
2056 {
2057 if((player->chickenTics < CHICKENTICS-TICRATE)
2058 && !player->powers[pw_weaponlevel2])
2059 { // Make a super chicken
2060 P_GivePower(player, pw_weaponlevel2);
2061 }
2062 return false;
2063 }
2064 if(player->powers[pw_invulnerability])
2065 { // Immune when invulnerable
2066 return false;
2067 }
2068 pmo = player->mo;
2069 oldflags2 = pmo->flags2;
2070 P_MorphMobj(pmo, MT_CHICPLAYER, MM_telefog,
2071 #ifdef PLAYER_CHICKEN_KEEPS_SHADOW
2072 MF_SHADOW
2073 #else
2074 0
2075 #endif
2076 );
2077 pmo->special1 = player->readyweapon; // save for later restore
2078 pmo->flags2 |= oldflags2&MF2_FLY; // preserve fly
2079 // Clear skin so it does not override chicken.
2080 pmo->skin = NULL; // Chickens all look alike.
2081 pmo->tflags &= ~MFT_TRANSLATION6; // no color translation for chicken
2082 // spawnhealth for chicken is 100, this is 30
2083 player->health = pmo->health = MAXCHICKENHEALTH;
2084 player->armorpoints = player->armortype = 0;
2085 #ifndef PLAYER_CHICKEN_KEEPS_SHADOW
2086 // If keep MF_SHADOW and cancel invisibility, then MF_SHADOW is permananet.
2087 player->powers[pw_invisibility] = 0;
2088 #endif
2089 player->powers[pw_weaponlevel2] = 0;
2090 player->weaponinfo = wpnlev1info;
2091 player->chickenTics = CHICKENTICS; // start chicken timer
2092 P_ActivateBeak(player);
2093 return true;
2094 }
2095
2096 //---------------------------------------------------------------------------
2097 //
2098 // FUNC P_ChickenMorph
2099 //
2100 //---------------------------------------------------------------------------
2101
2102 // Other actors, not players.
P_ChickenMorph(mobj_t * actor)2103 boolean P_ChickenMorph(mobj_t *actor)
2104 {
2105 mobjtype_t moType;
2106
2107 if(actor->player)
2108 {
2109 return false;
2110 }
2111 moType = actor->type;
2112 switch(moType)
2113 {
2114 case MT_POD:
2115 case MT_CHICKEN:
2116 case MT_HHEAD:
2117 case MT_MINOTAUR:
2118 case MT_SORCERER1:
2119 case MT_SORCERER2:
2120 return false;
2121 default:
2122 break;
2123 }
2124
2125 // preserve position, angle, target, invisible
2126 P_MorphMobj(actor, MT_CHICKEN, MM_telefog, MF_SHADOW);
2127 actor->special1 = CHICKENTICS+PP_Random(ph_chickenmorph); // monster chickentics
2128 actor->special2 = moType; // save type for restore
2129 return true;
2130 }
2131
2132 //---------------------------------------------------------------------------
2133 //
2134 // FUNC P_AutoUseChaosDevice
2135 //
2136 //---------------------------------------------------------------------------
2137
P_AutoUseChaosDevice(player_t * player)2138 boolean P_AutoUseChaosDevice(player_t *player)
2139 {
2140 int i;
2141
2142 for(i = 0; i < player->inventorySlotNum; i++)
2143 {
2144 if(player->inventory[i].type == arti_teleport)
2145 {
2146 P_PlayerUseArtifact(player, arti_teleport);
2147 player->health = player->mo->health = (player->health+1)/2;
2148 return(true);
2149 }
2150 }
2151 return(false);
2152 }
2153
2154 //---------------------------------------------------------------------------
2155 //
2156 // PROC P_AutoUseHealth
2157 //
2158 //---------------------------------------------------------------------------
2159
2160 // From Heretic
P_AutoUseHealth(player_t * player,int saveHealth)2161 void P_AutoUseHealth(player_t *player, int saveHealth)
2162 {
2163 int i;
2164 int count;
2165 int normalCount;
2166 int superCount;
2167
2168 // Uses P_PlayerUseArtifact, so do not need to know inventory slot.
2169 normalCount = superCount = 0;
2170 for(i = 0; i < player->inventorySlotNum; i++)
2171 {
2172 if(player->inventory[i].type == arti_health)
2173 {
2174 normalCount = player->inventory[i].count;
2175 }
2176 else if(player->inventory[i].type == arti_superhealth)
2177 {
2178 superCount = player->inventory[i].count;
2179 }
2180 }
2181 if((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
2182 { // Use quartz flasks
2183 count = (saveHealth+24)/25;
2184 for(i = 0; i < count; i++)
2185 P_PlayerUseArtifact( player, arti_health);
2186 }
2187 else if(superCount*100 >= saveHealth)
2188 { // Use mystic urns
2189 count = (saveHealth+99)/100;
2190 for(i = 0; i < count; i++)
2191 P_PlayerUseArtifact( player, arti_superhealth);
2192 }
2193 else if((gameskill == sk_baby)
2194 && (superCount*100+normalCount*25 >= saveHealth))
2195 { // Use mystic urns and quartz flasks
2196 count = (saveHealth+24)/25;
2197 for(i = 0; i < count; i++)
2198 P_PlayerUseArtifact( player, arti_health);
2199
2200 saveHealth -= count*25;
2201 count = (saveHealth+99)/100;
2202 for(i = 0; i < count; i++)
2203 P_PlayerUseArtifact( player, arti_superhealth);
2204 }
2205 player->mo->health = player->health;
2206 }
2207
2208
2209 //
2210 // P_DamageMobj
2211 // Damages both enemies and players
2212 // "inflictor" is the thing that caused the damage
2213 // creature or missile, can be NULL (slime, etc)
2214 // "source" is the thing to target after taking damage
2215 // creature or NULL
2216 // Source and inflictor are the same for melee attacks.
2217 // Source can be NULL for slime, barrel explosions
2218 // and other environmental stuff.
2219 //
2220 // Return true when damaged, for blood splats and other effects.
2221 // Fixed to not change the player mobj.
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damage)2222 boolean P_DamageMobj ( mobj_t* target,
2223 mobj_t* inflictor,
2224 mobj_t* source,
2225 int damage )
2226 {
2227 angle_t ang;
2228 int angf;
2229 int saved;
2230 player_t* player; // always target->player
2231 fixed_t thrust;
2232 boolean voodoo_target = false;
2233 boolean mbf_justhit = false; // MBF, delayed MF_JUSTHIT
2234 boolean takedamage = true; // block damage between members of same team
2235
2236 player = target->player;
2237
2238 // [WDJ] 7/2017 Moved the voodoo intercept of damage to be tested earlier
2239 // because of the weapons and armor specific player checks that
2240 // can get applied to the wrong player otherwise.
2241 // This code can change the target of the damage.
2242 // If we ever implement the player as a monster, this code needs to be first.
2243 if( player )
2244 {
2245 // [WDJ] 2/7/2011 Intercept voodoo damage
2246 voodoo_target = (player->mo != target);
2247 if( voodoo_target )
2248 {
2249 mobj_t * voodoo_thing = target;
2250 if(voodoo_mode >= VM_target)
2251 {
2252 // Multiplayer and single player:
2253 // try to find someone appropriate, instead of spawn point player.
2254 // Target source player causing damage
2255 if( source && source->player
2256 && (source->player->mo == source) )
2257 {
2258 // Shooting any voodoo doll, select shooting player
2259 player = source->player;
2260 }
2261 // Target last player to trigger a switch or linedef.
2262 else if( spechit_player && spechit_player->mo )
2263 {
2264 player = spechit_player;
2265 }
2266 }
2267
2268 if(! player->mo ) // this player is not present
2269 {
2270 if( voodoo_mode < VM_target )
2271 {
2272 // remove this voodoo doll to avoid segfaults
2273 P_RemoveMobj( voodoo_thing );
2274 }
2275 goto ret_false;
2276 }
2277
2278 if( voodoo_mode == VM_vanilla )
2279 {
2280 target->health -= damage; // damage the voodoo too
2281 }
2282 else
2283 {
2284 if( multiplayer && (damage > player->health))
2285 {
2286 // Kill the voodoo, so it cannot kill after respawn.
2287 // Voodoo doll in crusher is game fatal otherwise.
2288 voodoo_thing->health = 0;
2289 voodoo_thing->player = NULL;
2290 P_KillMobj ( voodoo_thing, inflictor, source );
2291 spechit_player = NULL; // cancel voodoo damage
2292 }
2293 // let player mobj get the damage, no Zombies
2294 target = player->mo;
2295 }
2296 }
2297
2298 if( gameskill == sk_baby )
2299 damage >>= 1; // take half damage in trainer mode
2300 }
2301
2302
2303 // killough 8/31/98: allow bouncers to take damage
2304 if ( !(target->flags & (MF_SHOOTABLE | MF_BOUNCES)) )
2305 goto ret_false; // shouldn't happen...
2306
2307 // [WDJ] Solid Corpse health < 0.
2308 if( (target->health <= 0) && !(target->flags & MF_CORPSE) )
2309 goto ret_false;
2310
2311 if ( target->flags & MF_SKULLFLY )
2312 {
2313 // Minotaur is invulnerable during charge attack
2314 if(target->type == MT_MINOTAUR)
2315 goto ret_false;
2316
2317 target->momx = target->momy = target->momz = 0;
2318 }
2319
2320 // Special damage types
2321 if(inflictor)
2322 {
2323 switch(inflictor->type)
2324 {
2325 case MT_EGGFX:
2326 if(player)
2327 {
2328 // Fixed to not change the player mobj.
2329 P_ChickenMorphPlayer(player);
2330 }
2331 else
2332 {
2333 P_ChickenMorph(target);
2334 }
2335 goto ret_false; // Always return
2336 case MT_WHIRLWIND:
2337 takedamage = P_TouchWhirlwind(target);
2338 goto ret_damage;
2339 case MT_MINOTAUR:
2340 if(inflictor->flags&MF_SKULLFLY)
2341 { // Slam only when in charge mode
2342 P_MinotaurSlam(inflictor, target);
2343 goto ret_true;
2344 }
2345 break;
2346 case MT_MACEFX4: // Death ball
2347 if((target->flags2&MF2_BOSS) || target->type == MT_HHEAD)
2348 { // Don't allow cheap boss kills
2349 break;
2350 }
2351 else if(player)
2352 { // Player specific checks
2353 if(player->powers[pw_invulnerability])
2354 { // Can't hurt invulnerable players
2355 break;
2356 }
2357 if(P_AutoUseChaosDevice(player))
2358 { // Player was saved using chaos device
2359 goto ret_false;
2360 }
2361 }
2362 damage = 10000; // Something's gonna die
2363 break;
2364 case MT_PHOENIXFX2: // Flame thrower
2365 if(player && PP_Random(ph_phoenixdam2) < 128)
2366 { // Freeze player for a bit
2367 target->reactiontime += 4;
2368 }
2369 break;
2370 case MT_RAINPLR1: // Rain missiles
2371 case MT_RAINPLR2:
2372 case MT_RAINPLR3:
2373 case MT_RAINPLR4:
2374 if(target->flags2&MF2_BOSS)
2375 { // Decrease damage for bosses
2376 damage = (PP_Random(ph_raindam)&7)+1;
2377 }
2378 break;
2379 case MT_HORNRODFX2:
2380 case MT_PHOENIXFX1:
2381 if(target->type == MT_SORCERER2 && PP_Random(ph_sordam) < 96)
2382 { // D'Sparil teleports away
2383 P_DSparilTeleport(target);
2384 goto ret_false;
2385 }
2386 break;
2387 case MT_BLASTERFX1:
2388 case MT_RIPPER:
2389 if(target->type == MT_HHEAD)
2390 { // Less damage to Ironlich bosses
2391 damage = PP_Random(ph_headdam)&1;
2392 if(!damage)
2393 goto ret_false;
2394 }
2395 break;
2396 default:
2397 break;
2398 }
2399 }
2400
2401 // Some close combat weapons should not
2402 // inflict thrust and push the victim out of reach,
2403 // thus kick away unless using the chainsaw.
2404 if (inflictor
2405 && !(target->flags & MF_NOCLIP) // unless target is NOCLIP
2406 && !(inflictor->flags2&MF2_NODMGTHRUST) // unless inflictor cannot thrust
2407 && (!source // not chainsaw
2408 || !source->player
2409 || source->player->readyweapon != wp_chainsaw))
2410 {
2411 // Impose thrust upon the target from the weapon
2412 fixed_t amomx, amomy, amomz=0;//SoM: 3/28/2000
2413
2414 ang = R_PointToAngle2 ( inflictor->x, inflictor->y,
2415 target->x, target->y);
2416
2417 if (EN_heretic )
2418 thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
2419 else
2420 thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
2421
2422 // sometimes a target shot down might fall off a ledge forwards
2423 if ( damage < 40
2424 && damage > target->health
2425 && target->z - inflictor->z > 64*FRACUNIT
2426 && (PP_Random(pr_damagemobj) & 0x01)
2427 )
2428 {
2429 ang += ANG180;
2430 thrust *= 4;
2431 }
2432
2433 angf = ANGLE_TO_FINE(ang);
2434
2435 if( EN_heretic
2436 && source && (source == inflictor)
2437 && source->player
2438 && source->player->powers[pw_weaponlevel2]
2439 && source->player->readyweapon == wp_staff)
2440 {
2441 // Staff power level 2
2442 target->momx += FixedMul(10*FRACUNIT, finecosine[angf]);
2443 target->momy += FixedMul(10*FRACUNIT, finesine[angf]);
2444 if(!(target->flags&MF_NOGRAVITY))
2445 {
2446 target->momz += 5*FRACUNIT;
2447 }
2448 }
2449 else
2450 {
2451 // all other thrusting weapons
2452 amomx = FixedMul (thrust, finecosine[angf]);
2453 amomy = FixedMul (thrust, finesine[angf]);
2454 target->momx += amomx;
2455 target->momy += amomy;
2456
2457 // added momz (do it better for missiles explosion)
2458 if ( source
2459 && (EV_legacy >= 124)
2460 && ((EV_legacy < 129) || !cv_allowrocketjump.EV))
2461 {
2462 // Legacy
2463 int dist,z;
2464
2465 if(source==target) // rocket in yourself (suicide)
2466 {
2467 viewx=inflictor->x;
2468 viewy=inflictor->y;
2469 z=inflictor->z;
2470 }
2471 else
2472 {
2473 viewx=source->x;
2474 viewy=source->y;
2475 z=source->z;
2476 }
2477 dist=R_PointToDist(target->x,target->y);
2478
2479 viewx=0;
2480 viewy=z;
2481 ang = R_PointToAngle(dist,target->z);
2482 amomz = FixedMul (thrust, sine_ANG(ang));
2483 }
2484 else //SoM: 2/28/2000: Added new function.
2485 if( (EV_legacy >= 129) && cv_allowrocketjump.EV )
2486 {
2487 // Legacy rocket jump.
2488 fixed_t delta1 = abs(inflictor->z - target->z);
2489 fixed_t delta2 = abs(inflictor->z - (target->z + target->height));
2490 amomz = (abs(amomx) + abs(amomy))>>1;
2491
2492 if(delta1 >= delta2 && inflictor->momz < 0)
2493 amomz = -amomz;
2494 }
2495
2496 target->momz += amomz;
2497 #ifdef CLIENTPREDICTION2
2498 if( player && player->spirit )
2499 {
2500 player->spirit->momx += amomx;
2501 player->spirit->momy += amomy;
2502 player->spirit->momz += amomz;
2503 }
2504 #endif
2505 // [WDJ] MBF
2506 // killough 11/98: thrust objects hanging off ledges
2507 if( target->eflags & MF_FALLING && (target->tipcount >= MAXTIPCOUNT) )
2508 target->tipcount = 0;
2509 }
2510 }
2511
2512 // Solid Corpse specific
2513 if( target->flags & MF_CORPSE )
2514 {
2515 target->health -= damage;
2516 // [WDJ] Corpse health < 0, so solid corpse test is < 0.
2517 if( target->health < -target->info->spawnhealth )
2518 P_KillMobj ( target, inflictor, source ); // to gibs
2519 // Keep corpse from ticking the P_Random in the pain test.
2520 goto ret_true;
2521 }
2522
2523 // target player specific
2524 if (player)
2525 {
2526 // end of game hell hack
2527 if (target->subsector->sector->special == 11
2528 && damage >= target->health)
2529 {
2530 damage = target->health - 1;
2531 }
2532
2533 // Below certain threshold,
2534 // ignore damage in GOD mode, or with INVUL power.
2535 if( (player->cheats&CF_GODMODE) || player->powers[pw_invulnerability] )
2536 {
2537 // Boom, MBF: killough 3/26/98: make god mode 100%
2538 // !comp[comp_god]
2539 if( (player->cheats&CF_GODMODE) && EN_invul_god )
2540 goto ret_false;
2541
2542 if( damage < 1000 )
2543 goto ret_false;
2544 }
2545
2546 if (player->armortype)
2547 {
2548 if (player->armortype == 1)
2549 saved = (EN_heretic)? damage>>1 : damage/3;
2550 else
2551 saved = (EN_heretic)? (damage>>1)+(damage>>2) : damage/2;
2552
2553 if (player->armorpoints <= saved)
2554 {
2555 // armor is used up
2556 saved = player->armorpoints;
2557 player->armortype = 0;
2558 }
2559 player->armorpoints -= saved;
2560 damage -= saved;
2561 }
2562
2563 // added team play and teamdamage (view logboris at 13-8-98 to understand)
2564 // [WDJ] 2/7/2011 Allow damage to player when:
2565 // olddemo (version < 125) // because they did not have these restrictions
2566 // OR telefrag // not subject to friendly fire tests
2567 // OR no source // no source interaction, sector damage etc.
2568 // OR NOT sourceplayer // monster attack
2569 // OR (source==target) // self inflicted damage (missile launcher)
2570 // OR voodoo_target // voodoo damage allowed by previous tests
2571 // OR NOT multiplayer // single player
2572 // OR ( coop // all on same team
2573 // AND cv_teamdamage // team members can hurt each other
2574 // )
2575 // OR ( deathmatch // teams or individual, not coop
2576 // AND ( NOT teamplay
2577 // // otherwise teamplay
2578 // OR cv_teamdamage // team members can hurt each other
2579 // OR (target.team != source.team)
2580 // )
2581 // )
2582 // [WDJ] For readability and understanding, please do not try to reduce
2583 // these equations, they are not executed very often, and the
2584 // compiler will reduce them during optimization anyway.
2585 if( (! source) // no source interaction, sector damage etc.
2586 || (! source->player) // monster attack
2587 || voodoo_target // allowed voodoo damage
2588 || (damage>1000) // telefrag and death-ball
2589 || (EV_legacy < 125) // old demoversion bypasses restrictions
2590 || (source==target) // self-inflicted
2591 || (! multiplayer) // single player
2592 || ( (!deathmatch) && cv_teamdamage.EV ) // coop
2593 || ( deathmatch // deathmatch 1,2,3
2594 && ( (!cv_teamplay.EV) // no teams
2595 || cv_teamdamage.EV // can damage within team
2596 || ! ST_SameTeam(source->player,player) // diff team
2597 )
2598 )
2599 )
2600 {
2601 if(damage >= player->health
2602 && ((gameskill == sk_baby) || deathmatch)
2603 && !player->chickenTics)
2604 { // Try to use some inventory health
2605 P_AutoUseHealth(player, damage - player->health + 1);
2606 }
2607
2608 // Update player health here, because they may die before
2609 // reaching the later player update.
2610 player->health -= damage; // mirror mobj health here for Dave
2611 if (player->health < 0)
2612 player->health = 0;
2613 // [WDJ] If player->mo is updated here, it prevents player gibs.
2614 // target = player->mo, as set in voodoo logic.
2615
2616 player->damagecount += damage; // add damage after armor / invuln
2617
2618 if (player->damagecount > 100)
2619 player->damagecount = 100; // teleport stomp does 10k points...
2620
2621 //added:22-02-98: force feedback ??? electro-shock???
2622 if (player == consoleplayer_ptr )
2623 I_Tactile (40,10,40+min(damage, 100)*2);
2624 }
2625 else
2626 {
2627 takedamage = false; // block damage
2628 }
2629 player->attacker = source;
2630 }
2631
2632 if( takedamage )
2633 {
2634 target->health -= damage;
2635
2636 // check for kill
2637 if (target->health <= 0)
2638 {
2639 target->special1 = damage;
2640 if(player && inflictor && !player->chickenTics)
2641 { // Check for flame death
2642 if((inflictor->flags2&MF2_FIREDAMAGE)
2643 || ((inflictor->type == MT_PHOENIXFX1)
2644 && (target->health > -50) && (damage > 25)))
2645 {
2646 target->flags2 |= MF2_FIREDAMAGE;
2647 }
2648 }
2649
2650 P_KillMobj ( target, inflictor, source );
2651 goto ret_true;
2652 }
2653
2654 // This must be after KillMobj, so target damage can be negative.
2655 if( player )
2656 {
2657 if( player->mo )
2658 player->mo->health = player->health; // keep mobj and player health same
2659 }
2660
2661 // [WDJ] MBF, From MBF, PrBoom, EternityEngine.
2662 // killough 9/7/98: keep track of targets so that friends can help friends
2663 if( EN_mbf )
2664 {
2665 // If target is a player, set player's target to source,
2666 // so that a friend can tell who is hurting a player
2667 if(player)
2668 {
2669 P_SetReference(target->target, source);
2670 target->target = source;
2671 }
2672
2673 // killough 9/8/98:
2674 // If target's health is less than 50%, move it to the front of its list.
2675 // This will slightly increase the chances that enemies will choose to
2676 // "finish it off", but its main purpose is to alert friends of danger.
2677 if( target->health*2 < target->info->spawnhealth )
2678 {
2679 P_MoveClassThink( &target->thinker, 1 ); // move first
2680 }
2681 }
2682
2683 if( (PP_Random(pr_painchance) < target->info->painchance)
2684 && !(target->flags&(MF_SKULLFLY|MF_CORPSE)) )
2685 {
2686 if( EN_mbf )
2687 mbf_justhit = true; // defer setting MF_JUSTHIT to below
2688 else
2689 target->flags |= MF_JUSTHIT; // fight back!
2690
2691 P_SetMobjState (target, target->info->painstate);
2692 }
2693
2694 target->reactiontime = 0; // we're awake now...
2695 }
2696
2697 if ( source && source != target // fixes bug where monster attacks self
2698 && source->type != MT_VILE
2699 && (!target->threshold || target->type == MT_VILE)
2700 && !(source->flags2 & MF2_BOSS)
2701 && !(source->type == MT_WIZARD && target->type == MT_SORCERER2)
2702 && ( MONSTER_INFIGHTING
2703 || ! (EN_mbf && SAME_FRIEND(source, target))
2704 )
2705 )
2706 {
2707 // killough 2/15/98: remember last enemy, to prevent sleeping early
2708 // 2/21/98: Place priority on players
2709 // killough 9/9/98: cleaned up, made more consistent:
2710 if( !target->lastenemy
2711 || target->lastenemy->health <= 0
2712 ||( EN_mbf ?
2713 ( target->target != source
2714 && SAME_FRIEND(target, target->lastenemy) ) // MBF
2715 : ! target->lastenemy->player // Vanilla
2716 )
2717 )
2718 {
2719 // remember last enemy - killough
2720 P_SetReference(target->lastenemy, target->target);
2721 target->lastenemy = target->target;
2722 }
2723
2724 // if not intent on another player,
2725 // chase after this one
2726 P_SetReference(target->target, source); // killough 11/98
2727 target->target = source;
2728
2729 target->threshold = BASETHRESHOLD;
2730 if( target->state == &states[target->info->spawnstate]
2731 && target->info->seestate != S_NULL)
2732 P_SetMobjState (target, target->info->seestate);
2733 }
2734
2735 // killough 11/98: Don't attack a friend, unless hit by that friend.
2736 // cph 2006/04/01 - implicitly this is only if mbf_features
2737 if( mbf_justhit // set by MBF to defer MF_JUSTHIT to here
2738 && ( !target->target
2739 || target->target == source
2740 || !BOTH_FRIEND(target, target->target) )
2741 )
2742 target->flags |= MF_JUSTHIT; // fight back!
2743
2744 ret_damage:
2745 return takedamage;
2746
2747 ret_false:
2748 return false;
2749
2750 ret_true:
2751 return true; // damaged
2752 }
2753