1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 
18 #include "h2def.h"
19 #include "m_misc.h"
20 #include "m_random.h"
21 #include "i_system.h"
22 #include "p_local.h"
23 #include "s_sound.h"
24 
25 #define BONUSADD 6
26 
27 int ArmorIncrement[NUMCLASSES][NUMARMOR] = {
28     {25 * FRACUNIT, 20 * FRACUNIT, 15 * FRACUNIT, 5 * FRACUNIT},
29     {10 * FRACUNIT, 25 * FRACUNIT, 5 * FRACUNIT, 20 * FRACUNIT},
30     {5 * FRACUNIT, 15 * FRACUNIT, 10 * FRACUNIT, 25 * FRACUNIT},
31     {0, 0, 0, 0}
32 };
33 
34 int AutoArmorSave[NUMCLASSES] =
35     { 15 * FRACUNIT, 10 * FRACUNIT, 5 * FRACUNIT, 0 };
36 
37 char *TextKeyMessages[] = {
38     TXT_KEY_STEEL,
39     TXT_KEY_CAVE,
40     TXT_KEY_AXE,
41     TXT_KEY_FIRE,
42     TXT_KEY_EMERALD,
43     TXT_KEY_DUNGEON,
44     TXT_KEY_SILVER,
45     TXT_KEY_RUSTED,
46     TXT_KEY_HORN,
47     TXT_KEY_SWAMP,
48     TXT_KEY_CASTLE
49 };
50 
51 static void SetDormantArtifact(mobj_t * arti);
52 static void TryPickupArtifact(player_t * player, artitype_t artifactType,
53                               mobj_t * artifact);
54 static void TryPickupWeapon(player_t * player, pclass_t weaponClass,
55                             weapontype_t weaponType, mobj_t * weapon,
56                             char *message);
57 static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass,
58                                  int pieceValue, mobj_t * pieceMobj);
59 
60 //--------------------------------------------------------------------------
61 //
62 // PROC P_SetMessage
63 //
64 //--------------------------------------------------------------------------
65 
P_SetMessage(player_t * player,char * message,boolean ultmsg)66 void P_SetMessage(player_t * player, char *message, boolean ultmsg)
67 {
68     if ((player->ultimateMessage || !messageson) && !ultmsg)
69     {
70         return;
71     }
72 
73     M_StringCopy(player->message, message, sizeof(player->message));
74 //    strupr(player->message);
75     player->messageTics = MESSAGETICS;
76     player->yellowMessage = false;
77     if (ultmsg)
78     {
79         player->ultimateMessage = true;
80     }
81     if (player == &players[consoleplayer])
82     {
83         BorderTopRefresh = true;
84     }
85 }
86 
87 //==========================================================================
88 //
89 // P_SetYellowMessage
90 //
91 //==========================================================================
92 
P_SetYellowMessage(player_t * player,char * message,boolean ultmsg)93 void P_SetYellowMessage(player_t * player, char *message, boolean ultmsg)
94 {
95     if ((player->ultimateMessage || !messageson) && !ultmsg)
96     {
97         return;
98     }
99     M_StringCopy(player->message, message, sizeof(player->message));
100     player->messageTics = 5 * MESSAGETICS;      // Bold messages last longer
101     player->yellowMessage = true;
102     if (ultmsg)
103     {
104         player->ultimateMessage = true;
105     }
106     if (player == &players[consoleplayer])
107     {
108         BorderTopRefresh = true;
109     }
110 }
111 
112 //==========================================================================
113 //
114 // P_ClearMessage
115 //
116 //==========================================================================
117 
P_ClearMessage(player_t * player)118 void P_ClearMessage(player_t * player)
119 {
120     player->messageTics = 0;
121     if (player == &players[consoleplayer])
122     {
123         BorderTopRefresh = true;
124     }
125 }
126 
127 //----------------------------------------------------------------------------
128 //
129 // PROC P_HideSpecialThing
130 //
131 //----------------------------------------------------------------------------
132 
P_HideSpecialThing(mobj_t * thing)133 void P_HideSpecialThing(mobj_t * thing)
134 {
135     thing->flags &= ~MF_SPECIAL;
136     thing->flags2 |= MF2_DONTDRAW;
137     P_SetMobjState(thing, S_HIDESPECIAL1);
138 }
139 
140 //--------------------------------------------------------------------------
141 //
142 // FUNC P_GiveMana
143 //
144 // Returns true if the player accepted the mana, false if it was
145 // refused (player has MAX_MANA).
146 //
147 //--------------------------------------------------------------------------
148 
P_GiveMana(player_t * player,manatype_t mana,int count)149 boolean P_GiveMana(player_t * player, manatype_t mana, int count)
150 {
151     int prevMana;
152     //weapontype_t changeWeapon;
153 
154     if (mana == MANA_NONE || mana == MANA_BOTH)
155     {
156         return (false);
157     }
158     if ((unsigned int) mana > NUMMANA)
159     {
160         I_Error("P_GiveMana: bad type %i", mana);
161     }
162     if (player->mana[mana] == MAX_MANA)
163     {
164         return (false);
165     }
166     if (gameskill == sk_baby || gameskill == sk_nightmare)
167     {                           // extra mana in baby mode and nightmare mode
168         count += count >> 1;
169     }
170     prevMana = player->mana[mana];
171 
172     player->mana[mana] += count;
173     if (player->mana[mana] > MAX_MANA)
174     {
175         player->mana[mana] = MAX_MANA;
176     }
177     if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
178         && mana == MANA_1 && prevMana <= 0)
179     {
180         P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
181     }
182     return (true);
183 }
184 
185 //==========================================================================
186 //
187 // TryPickupWeapon
188 //
189 //==========================================================================
190 
TryPickupWeapon(player_t * player,pclass_t weaponClass,weapontype_t weaponType,mobj_t * weapon,char * message)191 static void TryPickupWeapon(player_t * player, pclass_t weaponClass,
192                             weapontype_t weaponType, mobj_t * weapon,
193                             char *message)
194 {
195     boolean remove;
196     boolean gaveMana;
197     boolean gaveWeapon;
198 
199     remove = true;
200     if (player->class != weaponClass)
201     {                           // Wrong class, but try to pick up for mana
202         if (netgame && !deathmatch)
203         {                       // Can't pick up weapons for other classes in coop netplay
204             return;
205         }
206         if (weaponType == WP_SECOND)
207         {
208             if (!P_GiveMana(player, MANA_1, 25))
209             {
210                 return;
211             }
212         }
213         else
214         {
215             if (!P_GiveMana(player, MANA_2, 25))
216             {
217                 return;
218             }
219         }
220     }
221     else if (netgame && !deathmatch)
222     {                           // Cooperative net-game
223         if (player->weaponowned[weaponType])
224         {
225             return;
226         }
227         player->weaponowned[weaponType] = true;
228         if (weaponType == WP_SECOND)
229         {
230             P_GiveMana(player, MANA_1, 25);
231         }
232         else
233         {
234             P_GiveMana(player, MANA_2, 25);
235         }
236         player->pendingweapon = weaponType;
237         remove = false;
238     }
239     else
240     {                           // Deathmatch or single player game
241         if (weaponType == WP_SECOND)
242         {
243             gaveMana = P_GiveMana(player, MANA_1, 25);
244         }
245         else
246         {
247             gaveMana = P_GiveMana(player, MANA_2, 25);
248         }
249         if (player->weaponowned[weaponType])
250         {
251             gaveWeapon = false;
252         }
253         else
254         {
255             gaveWeapon = true;
256             player->weaponowned[weaponType] = true;
257             if (weaponType > player->readyweapon)
258             {                   // Only switch to more powerful weapons
259                 player->pendingweapon = weaponType;
260             }
261         }
262         if (!(gaveWeapon || gaveMana))
263         {                       // Player didn't need the weapon or any mana
264             return;
265         }
266     }
267 
268     P_SetMessage(player, message, false);
269     if (weapon->special)
270     {
271         P_ExecuteLineSpecial(weapon->special, weapon->args,
272                              NULL, 0, player->mo);
273         weapon->special = 0;
274     }
275 
276     if (remove)
277     {
278         if (deathmatch && !(weapon->flags2 & MF2_DROPPED))
279         {
280             P_HideSpecialThing(weapon);
281         }
282         else
283         {
284             P_RemoveMobj(weapon);
285         }
286     }
287 
288     player->bonuscount += BONUSADD;
289     if (player == &players[consoleplayer])
290     {
291         S_StartSound(NULL, SFX_PICKUP_WEAPON);
292         SB_PaletteFlash(false);
293     }
294 }
295 
296 //--------------------------------------------------------------------------
297 //
298 // FUNC P_GiveWeapon
299 //
300 // Returns true if the weapon or its mana was accepted.
301 //
302 //--------------------------------------------------------------------------
303 
304 /*
305 boolean P_GiveWeapon(player_t *player, pclass_t class, weapontype_t weapon)
306 {
307 	boolean gaveMana;
308 	boolean gaveWeapon;
309 
310 	if(player->class != class)
311 	{ // player cannot use this weapon, take it anyway, and get mana
312 		if(netgame && !deathmatch)
313 		{ // Can't pick up weapons for other classes in coop netplay
314 			return false;
315 		}
316 		if(weapon == WP_SECOND)
317 		{
318 			return P_GiveMana(player, MANA_1, 25);
319 		}
320 		else
321 		{
322 			return P_GiveMana(player, MANA_2, 25);
323 		}
324 	}
325 	if(netgame && !deathmatch)
326 	{ // Cooperative net-game
327 		if(player->weaponowned[weapon])
328 		{
329 			return(false);
330 		}
331 		player->bonuscount += BONUSADD;
332 		player->weaponowned[weapon] = true;
333 		if(weapon == WP_SECOND)
334 		{
335 			P_GiveMana(player, MANA_1, 25);
336 		}
337 		else
338 		{
339 			P_GiveMana(player, MANA_2, 25);
340 		}
341 		player->pendingweapon = weapon;
342 		if(player == &players[consoleplayer])
343 		{
344 			S_StartSound(NULL, SFX_PICKUP_WEAPON);
345 		}
346 		return(false);
347 	}
348 	if(weapon == WP_SECOND)
349 	{
350 		gaveMana = P_GiveMana(player, MANA_1, 25);
351 	}
352 	else
353 	{
354 		gaveMana = P_GiveMana(player, MANA_2, 25);
355 	}
356 	if(player->weaponowned[weapon])
357 	{
358 		gaveWeapon = false;
359 	}
360 	else
361 	{
362 		gaveWeapon = true;
363 		player->weaponowned[weapon] = true;
364 		if(weapon > player->readyweapon)
365 		{ // Only switch to more powerful weapons
366 			player->pendingweapon = weapon;
367 		}
368 	}
369 	return(gaveWeapon || gaveMana);
370 }
371 */
372 
373 //===========================================================================
374 //
375 // P_GiveWeaponPiece
376 //
377 //===========================================================================
378 
379 /*
380 boolean P_GiveWeaponPiece(player_t *player, pclass_t class, int piece)
381 {
382 	P_GiveMana(player, MANA_1, 20);
383 	P_GiveMana(player, MANA_2, 20);
384 	if(player->class != class)
385 	{
386 		return true;
387 	}
388 	else if(player->pieces&piece)
389 	{ // player already has that weapon piece
390 		return true;
391 	}
392 	player->pieces |= piece;
393 	if(player->pieces == 7)
394 	{ // player has built the fourth weapon!
395 		P_GiveWeapon(player, class, WP_FOURTH);
396 		S_StartSound(player->mo, SFX_WEAPON_BUILD);
397 	}
398 	return true;
399 }
400 */
401 
402 //==========================================================================
403 //
404 // TryPickupWeaponPiece
405 //
406 //==========================================================================
407 
TryPickupWeaponPiece(player_t * player,pclass_t matchClass,int pieceValue,mobj_t * pieceMobj)408 static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass,
409                                  int pieceValue, mobj_t * pieceMobj)
410 {
411     boolean remove;
412     boolean checkAssembled;
413     boolean gaveWeapon;
414     int gaveMana;
415     static char *fourthWeaponText[] = {
416         TXT_WEAPON_F4,
417         TXT_WEAPON_C4,
418         TXT_WEAPON_M4
419     };
420     static char *weaponPieceText[] = {
421         TXT_QUIETUS_PIECE,
422         TXT_WRAITHVERGE_PIECE,
423         TXT_BLOODSCOURGE_PIECE
424     };
425     static int pieceValueTrans[] = {
426         0,                      // 0: never
427         WPIECE1 | WPIECE2 | WPIECE3,    // WPIECE1 (1)
428         WPIECE2 | WPIECE3,      // WPIECE2 (2)
429         0,                      // 3: never
430         WPIECE3                 // WPIECE3 (4)
431     };
432 
433     remove = true;
434     checkAssembled = true;
435     gaveWeapon = false;
436     if (player->class != matchClass)
437     {                           // Wrong class, but try to pick up for mana
438         if (netgame && !deathmatch)
439         {                       // Can't pick up wrong-class weapons in coop netplay
440             return;
441         }
442         checkAssembled = false;
443         gaveMana = P_GiveMana(player, MANA_1, 20) +
444             P_GiveMana(player, MANA_2, 20);
445         if (!gaveMana)
446         {                       // Didn't need the mana, so don't pick it up
447             return;
448         }
449     }
450     else if (netgame && !deathmatch)
451     {                           // Cooperative net-game
452         if (player->pieces & pieceValue)
453         {                       // Already has the piece
454             return;
455         }
456         pieceValue = pieceValueTrans[pieceValue];
457         P_GiveMana(player, MANA_1, 20);
458         P_GiveMana(player, MANA_2, 20);
459         remove = false;
460     }
461     else
462     {                           // Deathmatch or single player game
463         gaveMana = P_GiveMana(player, MANA_1, 20) +
464             P_GiveMana(player, MANA_2, 20);
465         if (player->pieces & pieceValue)
466         {                       // Already has the piece, check if mana needed
467             if (!gaveMana)
468             {                   // Didn't need the mana, so don't pick it up
469                 return;
470             }
471             checkAssembled = false;
472         }
473     }
474 
475     // Pick up the weapon piece
476     if (pieceMobj->special)
477     {
478         P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args,
479                              NULL, 0, player->mo);
480         pieceMobj->special = 0;
481     }
482     if (remove)
483     {
484         if (deathmatch && !(pieceMobj->flags2 & MF2_DROPPED))
485         {
486             P_HideSpecialThing(pieceMobj);
487         }
488         else
489         {
490             P_RemoveMobj(pieceMobj);
491         }
492     }
493     player->bonuscount += BONUSADD;
494     if (player == &players[consoleplayer])
495     {
496         SB_PaletteFlash(false);
497     }
498 
499     // Check if fourth weapon assembled
500     if (checkAssembled)
501     {
502         player->pieces |= pieceValue;
503         if (player->pieces == (WPIECE1 | WPIECE2 | WPIECE3))
504         {
505             gaveWeapon = true;
506             player->weaponowned[WP_FOURTH] = true;
507             player->pendingweapon = WP_FOURTH;
508         }
509     }
510 
511     if (gaveWeapon)
512     {
513         P_SetMessage(player, fourthWeaponText[matchClass], false);
514         // Play the build-sound full volume for all players
515         S_StartSound(NULL, SFX_WEAPON_BUILD);
516     }
517     else
518     {
519         P_SetMessage(player, weaponPieceText[matchClass], false);
520         if (player == &players[consoleplayer])
521         {
522             S_StartSound(NULL, SFX_PICKUP_WEAPON);
523         }
524     }
525 }
526 
527 //---------------------------------------------------------------------------
528 //
529 // FUNC P_GiveBody
530 //
531 // Returns false if the body isn't needed at all.
532 //
533 //---------------------------------------------------------------------------
534 
P_GiveBody(player_t * player,int num)535 boolean P_GiveBody(player_t * player, int num)
536 {
537     int max;
538 
539     max = MAXHEALTH;
540     if (player->morphTics)
541     {
542         max = MAXMORPHHEALTH;
543     }
544     if (player->health >= max)
545     {
546         return (false);
547     }
548     player->health += num;
549     if (player->health > max)
550     {
551         player->health = max;
552     }
553     player->mo->health = player->health;
554     return (true);
555 }
556 
557 //---------------------------------------------------------------------------
558 //
559 // FUNC P_GiveArmor
560 //
561 // Returns false if the armor is worse than the current armor.
562 //
563 //---------------------------------------------------------------------------
564 
P_GiveArmor(player_t * player,armortype_t armortype,int amount)565 boolean P_GiveArmor(player_t * player, armortype_t armortype, int amount)
566 {
567     int hits;
568     int totalArmor;
569 
570     extern int ArmorMax[NUMCLASSES];
571 
572     if (amount == -1)
573     {
574         hits = ArmorIncrement[player->class][armortype];
575         if (player->armorpoints[armortype] >= hits)
576         {
577             return false;
578         }
579         else
580         {
581             player->armorpoints[armortype] = hits;
582         }
583     }
584     else
585     {
586         hits = amount * 5 * FRACUNIT;
587         totalArmor = player->armorpoints[ARMOR_ARMOR]
588             + player->armorpoints[ARMOR_SHIELD]
589             + player->armorpoints[ARMOR_HELMET]
590             + player->armorpoints[ARMOR_AMULET]
591             + AutoArmorSave[player->class];
592         if (totalArmor < ArmorMax[player->class] * 5 * FRACUNIT)
593         {
594             player->armorpoints[armortype] += hits;
595         }
596         else
597         {
598             return false;
599         }
600     }
601     return true;
602 }
603 
604 //---------------------------------------------------------------------------
605 //
606 // PROC P_GiveKey
607 //
608 //---------------------------------------------------------------------------
609 
P_GiveKey(player_t * player,keytype_t key)610 int P_GiveKey(player_t * player, keytype_t key)
611 {
612     if (player->keys & (1 << key))
613     {
614         return false;
615     }
616     player->bonuscount += BONUSADD;
617     player->keys |= 1 << key;
618     return true;
619 }
620 
621 //---------------------------------------------------------------------------
622 //
623 // FUNC P_GivePower
624 //
625 // Returns true if power accepted.
626 //
627 //---------------------------------------------------------------------------
628 
P_GivePower(player_t * player,powertype_t power)629 boolean P_GivePower(player_t * player, powertype_t power)
630 {
631     if (power == pw_invulnerability)
632     {
633         if (player->powers[power] > BLINKTHRESHOLD)
634         {                       // Already have it
635             return (false);
636         }
637         player->powers[power] = INVULNTICS;
638         player->mo->flags2 |= MF2_INVULNERABLE;
639         if (player->class == PCLASS_MAGE)
640         {
641             player->mo->flags2 |= MF2_REFLECTIVE;
642         }
643         return (true);
644     }
645     if (power == pw_flight)
646     {
647         if (player->powers[power] > BLINKTHRESHOLD)
648         {                       // Already have it
649             return (false);
650         }
651         player->powers[power] = FLIGHTTICS;
652         player->mo->flags2 |= MF2_FLY;
653         player->mo->flags |= MF_NOGRAVITY;
654         if (player->mo->z <= player->mo->floorz)
655         {
656             player->flyheight = 10;     // thrust the player in the air a bit
657         }
658         return (true);
659     }
660     if (power == pw_infrared)
661     {
662         if (player->powers[power] > BLINKTHRESHOLD)
663         {                       // Already have it
664             return (false);
665         }
666         player->powers[power] = INFRATICS;
667         return (true);
668     }
669     if (power == pw_speed)
670     {
671         if (player->powers[power] > BLINKTHRESHOLD)
672         {                       // Already have it
673             return (false);
674         }
675         player->powers[power] = SPEEDTICS;
676         return (true);
677     }
678     if (power == pw_minotaur)
679     {
680         // Doesn't matter if already have power, renew ticker
681         player->powers[power] = MAULATORTICS;
682         return (true);
683     }
684 /*
685 	if(power == pw_ironfeet)
686 	{
687 		player->powers[power] = IRONTICS;
688 		return(true);
689 	}
690 	if(power == pw_strength)
691 	{
692 		P_GiveBody(player, 100);
693 		player->powers[power] = 1;
694 		return(true);
695 	}
696 */
697     if (player->powers[power])
698     {
699         return (false);         // already got it
700     }
701     player->powers[power] = 1;
702     return (true);
703 }
704 
705 //==========================================================================
706 //
707 // TryPickupArtifact
708 //
709 //==========================================================================
710 
TryPickupArtifact(player_t * player,artitype_t artifactType,mobj_t * artifact)711 static void TryPickupArtifact(player_t * player, artitype_t artifactType,
712                               mobj_t * artifact)
713 {
714     static char *artifactMessages[NUMARTIFACTS] = {
715         NULL,
716         TXT_ARTIINVULNERABILITY,
717         TXT_ARTIHEALTH,
718         TXT_ARTISUPERHEALTH,
719         TXT_ARTIHEALINGRADIUS,
720         TXT_ARTISUMMON,
721         TXT_ARTITORCH,
722         TXT_ARTIEGG,
723         TXT_ARTIFLY,
724         TXT_ARTIBLASTRADIUS,
725         TXT_ARTIPOISONBAG,
726         TXT_ARTITELEPORTOTHER,
727         TXT_ARTISPEED,
728         TXT_ARTIBOOSTMANA,
729         TXT_ARTIBOOSTARMOR,
730         TXT_ARTITELEPORT,
731         TXT_ARTIPUZZSKULL,
732         TXT_ARTIPUZZGEMBIG,
733         TXT_ARTIPUZZGEMRED,
734         TXT_ARTIPUZZGEMGREEN1,
735         TXT_ARTIPUZZGEMGREEN2,
736         TXT_ARTIPUZZGEMBLUE1,
737         TXT_ARTIPUZZGEMBLUE2,
738         TXT_ARTIPUZZBOOK1,
739         TXT_ARTIPUZZBOOK2,
740         TXT_ARTIPUZZSKULL2,
741         TXT_ARTIPUZZFWEAPON,
742         TXT_ARTIPUZZCWEAPON,
743         TXT_ARTIPUZZMWEAPON,
744         TXT_ARTIPUZZGEAR,       // All gear pickups use the same text
745         TXT_ARTIPUZZGEAR,
746         TXT_ARTIPUZZGEAR,
747         TXT_ARTIPUZZGEAR
748     };
749 
750     if (gamemode == shareware)
751     {
752         artifactMessages[arti_blastradius] = TXT_ARTITELEPORT;
753         artifactMessages[arti_teleport] = TXT_ARTIBLASTRADIUS;
754     }
755 
756     if (P_GiveArtifact(player, artifactType, artifact))
757     {
758         if (artifact->special)
759         {
760             P_ExecuteLineSpecial(artifact->special, artifact->args,
761                                  NULL, 0, NULL);
762             artifact->special = 0;
763         }
764         player->bonuscount += BONUSADD;
765         if (artifactType < arti_firstpuzzitem)
766         {
767             SetDormantArtifact(artifact);
768             S_StartSound(artifact, SFX_PICKUP_ARTIFACT);
769             P_SetMessage(player, artifactMessages[artifactType], false);
770         }
771         else
772         {                       // Puzzle item
773             S_StartSound(NULL, SFX_PICKUP_ITEM);
774             P_SetMessage(player, artifactMessages[artifactType], true);
775             if (!netgame || deathmatch)
776             {                   // Remove puzzle items if not cooperative netplay
777                 P_RemoveMobj(artifact);
778             }
779         }
780     }
781 }
782 
783 //---------------------------------------------------------------------------
784 //
785 // FUNC P_GiveArtifact
786 //
787 // Returns true if artifact accepted.
788 //
789 //---------------------------------------------------------------------------
790 
P_GiveArtifact(player_t * player,artitype_t arti,mobj_t * mo)791 boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo)
792 {
793     int i;
794     int j;
795     boolean slidePointer;
796 
797     slidePointer = false;
798     i = 0;
799     while (player->inventory[i].type != arti && i < player->inventorySlotNum)
800     {
801         i++;
802     }
803     if (i == player->inventorySlotNum)
804     {
805         if (arti < arti_firstpuzzitem)
806         {
807             i = 0;
808             while (player->inventory[i].type < arti_firstpuzzitem
809                    && i < player->inventorySlotNum)
810             {
811                 i++;
812             }
813             if (i != player->inventorySlotNum)
814             {
815                 for (j = player->inventorySlotNum; j > i; j--)
816                 {
817                     player->inventory[j].count =
818                         player->inventory[j - 1].count;
819                     player->inventory[j].type = player->inventory[j - 1].type;
820                     slidePointer = true;
821                 }
822             }
823         }
824         player->inventory[i].count = 1;
825         player->inventory[i].type = arti;
826         player->inventorySlotNum++;
827     }
828     else
829     {
830         if (arti >= arti_firstpuzzitem && netgame && !deathmatch)
831         {                       // Can't carry more than 1 puzzle item in coop netplay
832             return false;
833         }
834         if (player->inventory[i].count >= 25)
835         {                       // Player already has 25 of this item
836             return false;
837         }
838         player->inventory[i].count++;
839     }
840     if (!player->artifactCount)
841     {
842         player->readyArtifact = arti;
843     }
844     else if (player == &players[consoleplayer] && slidePointer
845              && i <= inv_ptr)
846     {
847         inv_ptr++;
848         curpos++;
849         if (curpos > 6)
850         {
851             curpos = 6;
852         }
853     }
854     player->artifactCount++;
855     return (true);
856 }
857 
858 //==========================================================================
859 //
860 // SetDormantArtifact
861 //
862 // Removes the MF_SPECIAL flag and initiates the artifact pickup
863 // animation.
864 //
865 //==========================================================================
866 
SetDormantArtifact(mobj_t * arti)867 static void SetDormantArtifact(mobj_t * arti)
868 {
869     arti->flags &= ~MF_SPECIAL;
870     if (deathmatch && !(arti->flags2 & MF2_DROPPED))
871     {
872         if (arti->type == MT_ARTIINVULNERABILITY)
873         {
874             P_SetMobjState(arti, S_DORMANTARTI3_1);
875         }
876         else if (arti->type == MT_SUMMONMAULATOR || arti->type == MT_ARTIFLY)
877         {
878             P_SetMobjState(arti, S_DORMANTARTI2_1);
879         }
880         else
881         {
882             P_SetMobjState(arti, S_DORMANTARTI1_1);
883         }
884     }
885     else
886     {                           // Don't respawn
887         P_SetMobjState(arti, S_DEADARTI1);
888     }
889 }
890 
891 //---------------------------------------------------------------------------
892 //
893 // PROC A_RestoreArtifact
894 //
895 //---------------------------------------------------------------------------
896 
A_RestoreArtifact(mobj_t * arti)897 void A_RestoreArtifact(mobj_t * arti)
898 {
899     arti->flags |= MF_SPECIAL;
900     P_SetMobjState(arti, arti->info->spawnstate);
901     S_StartSound(arti, SFX_RESPAWN);
902 }
903 
904 //---------------------------------------------------------------------------
905 //
906 // PROC A_RestoreSpecialThing1
907 //
908 // Make a special thing visible again.
909 //
910 //---------------------------------------------------------------------------
911 
A_RestoreSpecialThing1(mobj_t * thing)912 void A_RestoreSpecialThing1(mobj_t * thing)
913 {
914     thing->flags2 &= ~MF2_DONTDRAW;
915     S_StartSound(thing, SFX_RESPAWN);
916 }
917 
918 //---------------------------------------------------------------------------
919 //
920 // PROC A_RestoreSpecialThing2
921 //
922 //---------------------------------------------------------------------------
923 
A_RestoreSpecialThing2(mobj_t * thing)924 void A_RestoreSpecialThing2(mobj_t * thing)
925 {
926     thing->flags |= MF_SPECIAL;
927     P_SetMobjState(thing, thing->info->spawnstate);
928 }
929 
930 //---------------------------------------------------------------------------
931 //
932 // PROC P_TouchSpecialThing
933 //
934 //---------------------------------------------------------------------------
935 
P_TouchSpecialThing(mobj_t * special,mobj_t * toucher)936 void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
937 {
938     player_t *player;
939     fixed_t delta;
940     int sound;
941     boolean respawn;
942 
943     delta = special->z - toucher->z;
944     if (delta > toucher->height || delta < -32 * FRACUNIT)
945     {                           // Out of reach
946         return;
947     }
948     if (toucher->health <= 0)
949     {                           // Toucher is dead
950         return;
951     }
952     sound = SFX_PICKUP_ITEM;
953     player = toucher->player;
954     respawn = true;
955     switch (special->sprite)
956     {
957             // Items
958         case SPR_PTN1:         // Item_HealingPotion
959             if (!P_GiveBody(player, 10))
960             {
961                 return;
962             }
963             P_SetMessage(player, TXT_ITEMHEALTH, false);
964             break;
965         case SPR_ARM1:
966             if (!P_GiveArmor(player, ARMOR_ARMOR, -1))
967             {
968                 return;
969             }
970             P_SetMessage(player, TXT_ARMOR1, false);
971             break;
972         case SPR_ARM2:
973             if (!P_GiveArmor(player, ARMOR_SHIELD, -1))
974             {
975                 return;
976             }
977             P_SetMessage(player, TXT_ARMOR2, false);
978             break;
979         case SPR_ARM3:
980             if (!P_GiveArmor(player, ARMOR_HELMET, -1))
981             {
982                 return;
983             }
984             P_SetMessage(player, TXT_ARMOR3, false);
985             break;
986         case SPR_ARM4:
987             if (!P_GiveArmor(player, ARMOR_AMULET, -1))
988             {
989                 return;
990             }
991             P_SetMessage(player, TXT_ARMOR4, false);
992             break;
993 
994             // Keys
995         case SPR_KEY1:
996         case SPR_KEY2:
997         case SPR_KEY3:
998         case SPR_KEY4:
999         case SPR_KEY5:
1000         case SPR_KEY6:
1001         case SPR_KEY7:
1002         case SPR_KEY8:
1003         case SPR_KEY9:
1004         case SPR_KEYA:
1005         case SPR_KEYB:
1006             if (!P_GiveKey(player, special->sprite - SPR_KEY1))
1007             {
1008                 return;
1009             }
1010             P_SetMessage(player, TextKeyMessages[special->sprite - SPR_KEY1],
1011                          true);
1012             sound = SFX_PICKUP_KEY;
1013 
1014             // Check and process the special now in case the key doesn't
1015             // get removed for coop netplay
1016             if (special->special)
1017             {
1018                 P_ExecuteLineSpecial(special->special, special->args,
1019                                      NULL, 0, toucher);
1020                 special->special = 0;
1021             }
1022 
1023             if (!netgame)
1024             {                   // Only remove keys in single player game
1025                 break;
1026             }
1027             player->bonuscount += BONUSADD;
1028             if (player == &players[consoleplayer])
1029             {
1030                 S_StartSound(NULL, sound);
1031                 SB_PaletteFlash(false);
1032             }
1033             return;
1034 
1035             // Artifacts
1036         case SPR_PTN2:
1037             TryPickupArtifact(player, arti_health, special);
1038             return;
1039         case SPR_SOAR:
1040             TryPickupArtifact(player, arti_fly, special);
1041             return;
1042         case SPR_INVU:
1043             TryPickupArtifact(player, arti_invulnerability, special);
1044             return;
1045         case SPR_SUMN:
1046             TryPickupArtifact(player, arti_summon, special);
1047             return;
1048         case SPR_PORK:
1049             TryPickupArtifact(player, arti_egg, special);
1050             return;
1051         case SPR_SPHL:
1052             TryPickupArtifact(player, arti_superhealth, special);
1053             return;
1054         case SPR_HRAD:
1055             TryPickupArtifact(player, arti_healingradius, special);
1056             return;
1057         case SPR_TRCH:
1058             TryPickupArtifact(player, arti_torch, special);
1059             return;
1060         case SPR_ATLP:
1061             TryPickupArtifact(player, arti_teleport, special);
1062             return;
1063         case SPR_TELO:
1064             TryPickupArtifact(player, arti_teleportother, special);
1065             return;
1066         case SPR_PSBG:
1067             TryPickupArtifact(player, arti_poisonbag, special);
1068             return;
1069         case SPR_SPED:
1070             TryPickupArtifact(player, arti_speed, special);
1071             return;
1072         case SPR_BMAN:
1073             TryPickupArtifact(player, arti_boostmana, special);
1074             return;
1075         case SPR_BRAC:
1076             TryPickupArtifact(player, arti_boostarmor, special);
1077             return;
1078         case SPR_BLST:
1079             TryPickupArtifact(player, arti_blastradius, special);
1080             return;
1081 
1082             // Puzzle artifacts
1083         case SPR_ASKU:
1084             TryPickupArtifact(player, arti_puzzskull, special);
1085             return;
1086         case SPR_ABGM:
1087             TryPickupArtifact(player, arti_puzzgembig, special);
1088             return;
1089         case SPR_AGMR:
1090             TryPickupArtifact(player, arti_puzzgemred, special);
1091             return;
1092         case SPR_AGMG:
1093             TryPickupArtifact(player, arti_puzzgemgreen1, special);
1094             return;
1095         case SPR_AGG2:
1096             TryPickupArtifact(player, arti_puzzgemgreen2, special);
1097             return;
1098         case SPR_AGMB:
1099             TryPickupArtifact(player, arti_puzzgemblue1, special);
1100             return;
1101         case SPR_AGB2:
1102             TryPickupArtifact(player, arti_puzzgemblue2, special);
1103             return;
1104         case SPR_ABK1:
1105             TryPickupArtifact(player, arti_puzzbook1, special);
1106             return;
1107         case SPR_ABK2:
1108             TryPickupArtifact(player, arti_puzzbook2, special);
1109             return;
1110         case SPR_ASK2:
1111             TryPickupArtifact(player, arti_puzzskull2, special);
1112             return;
1113         case SPR_AFWP:
1114             TryPickupArtifact(player, arti_puzzfweapon, special);
1115             return;
1116         case SPR_ACWP:
1117             TryPickupArtifact(player, arti_puzzcweapon, special);
1118             return;
1119         case SPR_AMWP:
1120             TryPickupArtifact(player, arti_puzzmweapon, special);
1121             return;
1122         case SPR_AGER:
1123             TryPickupArtifact(player, arti_puzzgear1, special);
1124             return;
1125         case SPR_AGR2:
1126             TryPickupArtifact(player, arti_puzzgear2, special);
1127             return;
1128         case SPR_AGR3:
1129             TryPickupArtifact(player, arti_puzzgear3, special);
1130             return;
1131         case SPR_AGR4:
1132             TryPickupArtifact(player, arti_puzzgear4, special);
1133             return;
1134 
1135             // Mana
1136         case SPR_MAN1:
1137             if (!P_GiveMana(player, MANA_1, 15))
1138             {
1139                 return;
1140             }
1141             P_SetMessage(player, TXT_MANA_1, false);
1142             break;
1143         case SPR_MAN2:
1144             if (!P_GiveMana(player, MANA_2, 15))
1145             {
1146                 return;
1147             }
1148             P_SetMessage(player, TXT_MANA_2, false);
1149             break;
1150         case SPR_MAN3:         // Double Mana Dodecahedron
1151             if (!P_GiveMana(player, MANA_1, 20))
1152             {
1153                 if (!P_GiveMana(player, MANA_2, 20))
1154                 {
1155                     return;
1156                 }
1157             }
1158             else
1159             {
1160                 P_GiveMana(player, MANA_2, 20);
1161             }
1162             P_SetMessage(player, TXT_MANA_BOTH, false);
1163             break;
1164 
1165             // 2nd and 3rd Mage Weapons
1166         case SPR_WMCS:         // Frost Shards
1167             TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND,
1168                             special, TXT_WEAPON_M2);
1169             return;
1170         case SPR_WMLG:         // Arc of Death
1171             TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD,
1172                             special, TXT_WEAPON_M3);
1173             return;
1174 
1175             // 2nd and 3rd Fighter Weapons
1176         case SPR_WFAX:         // Timon's Axe
1177             TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND,
1178                             special, TXT_WEAPON_F2);
1179             return;
1180         case SPR_WFHM:         // Hammer of Retribution
1181             TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD,
1182                             special, TXT_WEAPON_F3);
1183             return;
1184 
1185             // 2nd and 3rd Cleric Weapons
1186         case SPR_WCSS:         // Serpent Staff
1187             TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND,
1188                             special, TXT_WEAPON_C2);
1189             return;
1190         case SPR_WCFM:         // Firestorm
1191             TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD,
1192                             special, TXT_WEAPON_C3);
1193             return;
1194 
1195             // Fourth Weapon Pieces
1196         case SPR_WFR1:
1197             TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1, special);
1198             return;
1199         case SPR_WFR2:
1200             TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2, special);
1201             return;
1202         case SPR_WFR3:
1203             TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3, special);
1204             return;
1205         case SPR_WCH1:
1206             TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1, special);
1207             return;
1208         case SPR_WCH2:
1209             TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2, special);
1210             return;
1211         case SPR_WCH3:
1212             TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3, special);
1213             return;
1214         case SPR_WMS1:
1215             TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1, special);
1216             return;
1217         case SPR_WMS2:
1218             TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2, special);
1219             return;
1220         case SPR_WMS3:
1221             TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3, special);
1222             return;
1223 
1224         default:
1225             I_Error("P_SpecialThing: Unknown gettable thing");
1226     }
1227     if (special->special)
1228     {
1229         P_ExecuteLineSpecial(special->special, special->args, NULL,
1230                              0, toucher);
1231         special->special = 0;
1232     }
1233     if (deathmatch && respawn && !(special->flags2 & MF2_DROPPED))
1234     {
1235         P_HideSpecialThing(special);
1236     }
1237     else
1238     {
1239         P_RemoveMobj(special);
1240     }
1241     player->bonuscount += BONUSADD;
1242     if (player == &players[consoleplayer])
1243     {
1244         S_StartSound(NULL, sound);
1245         SB_PaletteFlash(false);
1246     }
1247 }
1248 
1249 // Search thinker list for minotaur
ActiveMinotaur(player_t * master)1250 mobj_t *ActiveMinotaur(player_t * master)
1251 {
1252     mobj_t *mo;
1253     player_t *plr;
1254     thinker_t *think;
1255     unsigned int *starttime;
1256 
1257     for (think = thinkercap.next; think != &thinkercap; think = think->next)
1258     {
1259         if (think->function != P_MobjThinker)
1260             continue;
1261         mo = (mobj_t *) think;
1262         if (mo->type != MT_MINOTAUR)
1263             continue;
1264         if (mo->health <= 0)
1265             continue;
1266         if (!(mo->flags & MF_COUNTKILL))
1267             continue;           // for morphed minotaurs
1268         if (mo->flags & MF_CORPSE)
1269             continue;
1270         starttime = (unsigned int *) mo->args;
1271         if ((leveltime - *starttime) >= MAULATORTICS)
1272             continue;
1273         plr = mo->special1.m->player;
1274         if (plr == master)
1275             return (mo);
1276     }
1277     return (NULL);
1278 }
1279 
1280 
1281 //---------------------------------------------------------------------------
1282 //
1283 // PROC P_KillMobj
1284 //
1285 //---------------------------------------------------------------------------
1286 
P_KillMobj(mobj_t * source,mobj_t * target)1287 void P_KillMobj(mobj_t * source, mobj_t * target)
1288 {
1289     byte dummyArgs[3] = {0, 0, 0};
1290     mobj_t *master;
1291 
1292     target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY);
1293     target->flags |= MF_CORPSE | MF_DROPOFF;
1294     target->flags2 &= ~MF2_PASSMOBJ;
1295     target->height >>= 2;
1296     if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL)
1297         && target->special)
1298     {                           // Initiate monster death actions
1299         if (target->type == MT_SORCBOSS)
1300         {
1301             P_StartACS(target->special, 0, dummyArgs, target, NULL, 0);
1302         }
1303         else
1304         {
1305             P_ExecuteLineSpecial(target->special, target->args,
1306                                  NULL, 0, target);
1307         }
1308     }
1309     if (source && source->player)
1310     {                           // Check for frag changes
1311         if (target->player)
1312         {
1313             if (target == source)
1314             {                   // Self-frag
1315                 target->player->frags[target->player - players]--;
1316                 if (cmdfrag && netgame
1317                     && source->player == &players[consoleplayer])
1318                 {               // Send out a frag count packet
1319                     NET_SendFrags(source->player);
1320                 }
1321             }
1322             else
1323             {
1324                 source->player->frags[target->player - players]++;
1325                 if (cmdfrag && netgame
1326                     && source->player == &players[consoleplayer])
1327                 {               // Send out a frag count packet
1328                     NET_SendFrags(source->player);
1329                 }
1330             }
1331         }
1332     }
1333     if (target->player)
1334     {                           // Player death
1335         if (!source)
1336         {                       // Self-frag
1337             target->player->frags[target->player - players]--;
1338             if (cmdfrag && netgame
1339                 && target->player == &players[consoleplayer])
1340             {                   // Send out a frag count packet
1341                 NET_SendFrags(target->player);
1342             }
1343         }
1344         target->flags &= ~MF_SOLID;
1345         target->flags2 &= ~MF2_FLY;
1346         target->player->powers[pw_flight] = 0;
1347         target->player->playerstate = PST_DEAD;
1348         P_DropWeapon(target->player);
1349         if (target->flags2 & MF2_FIREDAMAGE)
1350         {                       // Player flame death
1351             switch (target->player->class)
1352             {
1353                 case PCLASS_FIGHTER:
1354                     S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
1355                     P_SetMobjState(target, S_PLAY_F_FDTH1);
1356                     return;
1357                 case PCLASS_CLERIC:
1358                     S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
1359                     P_SetMobjState(target, S_PLAY_C_FDTH1);
1360                     return;
1361                 case PCLASS_MAGE:
1362                     S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
1363                     P_SetMobjState(target, S_PLAY_M_FDTH1);
1364                     return;
1365                 default:
1366                     break;
1367             }
1368         }
1369         if (target->flags2 & MF2_ICEDAMAGE)
1370         {                       // Player ice death
1371             target->flags &= ~(7 << MF_TRANSSHIFT);     //no translation
1372             target->flags |= MF_ICECORPSE;
1373             switch (target->player->class)
1374             {
1375                 case PCLASS_FIGHTER:
1376                     P_SetMobjState(target, S_FPLAY_ICE);
1377                     return;
1378                 case PCLASS_CLERIC:
1379                     P_SetMobjState(target, S_CPLAY_ICE);
1380                     return;
1381                 case PCLASS_MAGE:
1382                     P_SetMobjState(target, S_MPLAY_ICE);
1383                     return;
1384                 case PCLASS_PIG:
1385                     P_SetMobjState(target, S_PIG_ICE);
1386                     return;
1387                 default:
1388                     break;
1389             }
1390         }
1391     }
1392     if (target->flags2 & MF2_FIREDAMAGE)
1393     {
1394         if (target->type == MT_FIGHTER_BOSS
1395             || target->type == MT_CLERIC_BOSS || target->type == MT_MAGE_BOSS)
1396         {
1397             switch (target->type)
1398             {
1399                 case MT_FIGHTER_BOSS:
1400                     S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
1401                     P_SetMobjState(target, S_PLAY_F_FDTH1);
1402                     return;
1403                 case MT_CLERIC_BOSS:
1404                     S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
1405                     P_SetMobjState(target, S_PLAY_C_FDTH1);
1406                     return;
1407                 case MT_MAGE_BOSS:
1408                     S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
1409                     P_SetMobjState(target, S_PLAY_M_FDTH1);
1410                     return;
1411                 default:
1412                     break;
1413             }
1414         }
1415         else if (target->type == MT_TREEDESTRUCTIBLE)
1416         {
1417             P_SetMobjState(target, S_ZTREEDES_X1);
1418             target->height = 24 * FRACUNIT;
1419             S_StartSound(target, SFX_TREE_EXPLODE);
1420             return;
1421         }
1422     }
1423     if (target->flags2 & MF2_ICEDAMAGE)
1424     {
1425         target->flags |= MF_ICECORPSE;
1426         switch (target->type)
1427         {
1428             case MT_BISHOP:
1429                 P_SetMobjState(target, S_BISHOP_ICE);
1430                 return;
1431             case MT_CENTAUR:
1432             case MT_CENTAURLEADER:
1433                 P_SetMobjState(target, S_CENTAUR_ICE);
1434                 return;
1435             case MT_DEMON:
1436             case MT_DEMON2:
1437                 P_SetMobjState(target, S_DEMON_ICE);
1438                 return;
1439             case MT_SERPENT:
1440             case MT_SERPENTLEADER:
1441                 P_SetMobjState(target, S_SERPENT_ICE);
1442                 return;
1443             case MT_WRAITH:
1444             case MT_WRAITHB:
1445                 P_SetMobjState(target, S_WRAITH_ICE);
1446                 return;
1447             case MT_ETTIN:
1448                 P_SetMobjState(target, S_ETTIN_ICE1);
1449                 return;
1450             case MT_FIREDEMON:
1451                 P_SetMobjState(target, S_FIRED_ICE1);
1452                 return;
1453             case MT_FIGHTER_BOSS:
1454                 P_SetMobjState(target, S_FIGHTER_ICE);
1455                 return;
1456             case MT_CLERIC_BOSS:
1457                 P_SetMobjState(target, S_CLERIC_ICE);
1458                 return;
1459             case MT_MAGE_BOSS:
1460                 P_SetMobjState(target, S_MAGE_ICE);
1461                 return;
1462             case MT_PIG:
1463                 P_SetMobjState(target, S_PIG_ICE);
1464                 return;
1465             default:
1466                 target->flags &= ~MF_ICECORPSE;
1467                 break;
1468         }
1469     }
1470 
1471     if (target->type == MT_MINOTAUR)
1472     {
1473         master = target->special1.m;
1474         if (master->health > 0)
1475         {
1476             if (!ActiveMinotaur(master->player))
1477             {
1478                 master->player->powers[pw_minotaur] = 0;
1479             }
1480         }
1481     }
1482     else if (target->type == MT_TREEDESTRUCTIBLE)
1483     {
1484         target->height = 24 * FRACUNIT;
1485     }
1486     if (target->health < -(target->info->spawnhealth >> 1)
1487         && target->info->xdeathstate)
1488     {                           // Extreme death
1489         P_SetMobjState(target, target->info->xdeathstate);
1490     }
1491     else
1492     {                           // Normal death
1493         if ((target->type == MT_FIREDEMON) &&
1494             (target->z <= target->floorz + 2 * FRACUNIT) &&
1495             (target->info->xdeathstate))
1496         {
1497             // This is to fix the imps' staying in fall state
1498             P_SetMobjState(target, target->info->xdeathstate);
1499         }
1500         else
1501         {
1502             P_SetMobjState(target, target->info->deathstate);
1503         }
1504     }
1505     target->tics -= P_Random() & 3;
1506 //      I_StartSound(&actor->r, actor->info->deathsound);
1507 }
1508 
1509 //---------------------------------------------------------------------------
1510 //
1511 // FUNC P_MinotaurSlam
1512 //
1513 //---------------------------------------------------------------------------
1514 
P_MinotaurSlam(mobj_t * source,mobj_t * target)1515 void P_MinotaurSlam(mobj_t * source, mobj_t * target)
1516 {
1517     angle_t angle;
1518     fixed_t thrust;
1519 
1520     angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
1521     angle >>= ANGLETOFINESHIFT;
1522     thrust = 16 * FRACUNIT + (P_Random() << 10);
1523     target->momx += FixedMul(thrust, finecosine[angle]);
1524     target->momy += FixedMul(thrust, finesine[angle]);
1525     P_DamageMobj(target, NULL, source, HITDICE(4));
1526     if (target->player)
1527     {
1528         target->reactiontime = 14 + (P_Random() & 7);
1529     }
1530     source->args[0] = 0;        // Stop charging
1531 }
1532 
1533 
1534 //---------------------------------------------------------------------------
1535 //
1536 // FUNC P_MorphPlayer
1537 //
1538 // Returns true if the player gets turned into a pig
1539 //
1540 //---------------------------------------------------------------------------
1541 
P_MorphPlayer(player_t * player)1542 boolean P_MorphPlayer(player_t * player)
1543 {
1544     mobj_t *pmo;
1545     mobj_t *fog;
1546     mobj_t *beastMo;
1547     fixed_t x;
1548     fixed_t y;
1549     fixed_t z;
1550     angle_t angle;
1551     int oldFlags2;
1552 
1553     if (player->powers[pw_invulnerability])
1554     {                           // Immune when invulnerable
1555         return (false);
1556     }
1557     if (player->morphTics)
1558     {                           // Player is already a beast
1559         return false;
1560     }
1561     pmo = player->mo;
1562     x = pmo->x;
1563     y = pmo->y;
1564     z = pmo->z;
1565     angle = pmo->angle;
1566     oldFlags2 = pmo->flags2;
1567     P_SetMobjState(pmo, S_FREETARGMOBJ);
1568     fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
1569     S_StartSound(fog, SFX_TELEPORT);
1570     beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER);
1571     beastMo->special1.i = player->readyweapon;
1572     beastMo->angle = angle;
1573     beastMo->player = player;
1574     player->health = beastMo->health = MAXMORPHHEALTH;
1575     player->mo = beastMo;
1576     memset(&player->armorpoints[0], 0, NUMARMOR * sizeof(int));
1577     player->class = PCLASS_PIG;
1578     if (oldFlags2 & MF2_FLY)
1579     {
1580         beastMo->flags2 |= MF2_FLY;
1581     }
1582     player->morphTics = MORPHTICS;
1583     P_ActivateMorphWeapon(player);
1584     return (true);
1585 }
1586 
1587 //---------------------------------------------------------------------------
1588 //
1589 // FUNC P_MorphMonster
1590 //
1591 //---------------------------------------------------------------------------
1592 
P_MorphMonster(mobj_t * actor)1593 boolean P_MorphMonster(mobj_t * actor)
1594 {
1595     mobj_t *master, *monster, *fog;
1596     mobjtype_t moType;
1597     fixed_t x;
1598     fixed_t y;
1599     fixed_t z;
1600     mobj_t oldMonster;
1601 
1602     if (actor->player)
1603         return (false);
1604     if (!(actor->flags & MF_COUNTKILL))
1605         return false;
1606     if (actor->flags2 & MF2_BOSS)
1607         return false;
1608     moType = actor->type;
1609     switch (moType)
1610     {
1611         case MT_PIG:
1612             return (false);
1613         case MT_FIGHTER_BOSS:
1614         case MT_CLERIC_BOSS:
1615         case MT_MAGE_BOSS:
1616             return (false);
1617         default:
1618             break;
1619     }
1620 
1621     oldMonster = *actor;
1622     x = oldMonster.x;
1623     y = oldMonster.y;
1624     z = oldMonster.z;
1625     P_RemoveMobjFromTIDList(actor);
1626     P_SetMobjState(actor, S_FREETARGMOBJ);
1627     fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
1628     S_StartSound(fog, SFX_TELEPORT);
1629     monster = P_SpawnMobj(x, y, z, MT_PIG);
1630     monster->special2.i = moType;
1631     monster->special1.i = MORPHTICS + P_Random();
1632     monster->flags |= (oldMonster.flags & MF_SHADOW);
1633     monster->target = oldMonster.target;
1634     monster->angle = oldMonster.angle;
1635     monster->tid = oldMonster.tid;
1636     monster->special = oldMonster.special;
1637     P_InsertMobjIntoTIDList(monster, oldMonster.tid);
1638     memcpy(monster->args, oldMonster.args, 5);
1639 
1640     // check for turning off minotaur power for active icon
1641     if (moType == MT_MINOTAUR)
1642     {
1643         master = oldMonster.special1.m;
1644         if (master->health > 0)
1645         {
1646             if (!ActiveMinotaur(master->player))
1647             {
1648                 master->player->powers[pw_minotaur] = 0;
1649             }
1650         }
1651     }
1652     return (true);
1653 }
1654 
1655 //---------------------------------------------------------------------------
1656 //
1657 // PROC P_AutoUseHealth
1658 //
1659 //---------------------------------------------------------------------------
1660 
P_AutoUseHealth(player_t * player,int saveHealth)1661 void P_AutoUseHealth(player_t * player, int saveHealth)
1662 {
1663     int i;
1664     int count;
1665     int normalCount;
1666     int normalSlot = 0;
1667     int superCount;
1668     int superSlot = 0;
1669 
1670     normalCount = superCount = 0;
1671     for (i = 0; i < player->inventorySlotNum; i++)
1672     {
1673         if (player->inventory[i].type == arti_health)
1674         {
1675             normalSlot = i;
1676             normalCount = player->inventory[i].count;
1677         }
1678         else if (player->inventory[i].type == arti_superhealth)
1679         {
1680             superSlot = i;
1681             superCount = player->inventory[i].count;
1682         }
1683     }
1684     if ((gameskill == sk_baby) && (normalCount * 25 >= saveHealth))
1685     {                           // Use quartz flasks
1686         count = (saveHealth + 24) / 25;
1687         for (i = 0; i < count; i++)
1688         {
1689             player->health += 25;
1690             P_PlayerRemoveArtifact(player, normalSlot);
1691         }
1692     }
1693     else if (superCount * 100 >= saveHealth)
1694     {                           // Use mystic urns
1695         count = (saveHealth + 99) / 100;
1696         for (i = 0; i < count; i++)
1697         {
1698             player->health += 100;
1699             P_PlayerRemoveArtifact(player, superSlot);
1700         }
1701     }
1702     else if ((gameskill == sk_baby)
1703              && (superCount * 100 + normalCount * 25 >= saveHealth))
1704     {                           // Use mystic urns and quartz flasks
1705         count = (saveHealth + 24) / 25;
1706         saveHealth -= count * 25;
1707         for (i = 0; i < count; i++)
1708         {
1709             player->health += 25;
1710             P_PlayerRemoveArtifact(player, normalSlot);
1711         }
1712         count = (saveHealth + 99) / 100;
1713         for (i = 0; i < count; i++)
1714         {
1715             player->health += 100;
1716             P_PlayerRemoveArtifact(player, normalSlot);
1717         }
1718     }
1719     player->mo->health = player->health;
1720 }
1721 
1722 /*
1723 =================
1724 =
1725 = P_DamageMobj
1726 =
1727 = Damages both enemies and players
1728 = inflictor is the thing that caused the damage
1729 = 		creature or missile, can be NULL (slime, etc)
1730 = source is the thing to target after taking damage
1731 =		creature or NULL
1732 = Source and inflictor are the same for melee attacks
1733 = source can be null for barrel explosions and other environmental stuff
1734 ==================
1735 */
1736 
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damage)1737 void P_DamageMobj
1738     (mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage)
1739 {
1740     unsigned ang;
1741     int saved;
1742     fixed_t savedPercent;
1743     player_t *player;
1744     mobj_t *master;
1745     fixed_t thrust;
1746     int temp;
1747     int i;
1748 
1749     if (!(target->flags & MF_SHOOTABLE))
1750     {
1751         // Shouldn't happen
1752         return;
1753     }
1754     if (target->health <= 0)
1755     {
1756         if (inflictor && inflictor->flags2 & MF2_ICEDAMAGE)
1757         {
1758             return;
1759         }
1760         else if (target->flags & MF_ICECORPSE)  // frozen
1761         {
1762             target->tics = 1;
1763             target->momx = target->momy = 0;
1764         }
1765         return;
1766     }
1767     if ((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
1768     {                           // mobj is invulnerable
1769         if (target->player)
1770             return;             // for player, no exceptions
1771         if (inflictor)
1772         {
1773             switch (inflictor->type)
1774             {
1775                     // These inflictors aren't foiled by invulnerability
1776                 case MT_HOLY_FX:
1777                 case MT_POISONCLOUD:
1778                 case MT_FIREBOMB:
1779                     break;
1780                 default:
1781                     return;
1782             }
1783         }
1784         else
1785         {
1786             return;
1787         }
1788     }
1789     if (target->player)
1790     {
1791         if (damage < 1000 && ((target->player->cheats & CF_GODMODE)
1792                               || target->player->powers[pw_invulnerability]))
1793         {
1794             return;
1795         }
1796     }
1797     if (target->flags & MF_SKULLFLY)
1798     {
1799         target->momx = target->momy = target->momz = 0;
1800     }
1801     if (target->flags2 & MF2_DORMANT)
1802     {
1803         // Invulnerable, and won't wake up
1804         return;
1805     }
1806     player = target->player;
1807     if (player && gameskill == sk_baby)
1808     {
1809         // Take half damage in trainer mode
1810         damage >>= 1;
1811     }
1812     // Special damage types
1813     if (inflictor)
1814     {
1815         switch (inflictor->type)
1816         {
1817             case MT_EGGFX:
1818                 if (player)
1819                 {
1820                     P_MorphPlayer(player);
1821                 }
1822                 else
1823                 {
1824                     P_MorphMonster(target);
1825                 }
1826                 return;         // Always return
1827             case MT_TELOTHER_FX1:
1828             case MT_TELOTHER_FX2:
1829             case MT_TELOTHER_FX3:
1830             case MT_TELOTHER_FX4:
1831             case MT_TELOTHER_FX5:
1832                 if ((target->flags & MF_COUNTKILL) &&
1833                     (target->type != MT_SERPENT) &&
1834                     (target->type != MT_SERPENTLEADER) &&
1835                     (!(target->flags2 & MF2_BOSS)))
1836                 {
1837                     P_TeleportOther(target);
1838                 }
1839                 return;
1840             case MT_MINOTAUR:
1841                 if (inflictor->flags & MF_SKULLFLY)
1842                 {               // Slam only when in charge mode
1843                     P_MinotaurSlam(inflictor, target);
1844                     return;
1845                 }
1846                 break;
1847             case MT_BISH_FX:
1848                 // Bishops are just too nasty
1849                 damage >>= 1;
1850                 break;
1851             case MT_SHARDFX1:
1852                 switch (inflictor->special2.i)
1853                 {
1854                     case 3:
1855                         damage <<= 3;
1856                         break;
1857                     case 2:
1858                         damage <<= 2;
1859                         break;
1860                     case 1:
1861                         damage <<= 1;
1862                         break;
1863                     default:
1864                         break;
1865                 }
1866                 break;
1867             case MT_CSTAFF_MISSILE:
1868                 // Cleric Serpent Staff does poison damage
1869                 if (target->player)
1870                 {
1871                     P_PoisonPlayer(target->player, source, 20);
1872                     damage >>= 1;
1873                 }
1874                 break;
1875             case MT_ICEGUY_FX2:
1876                 damage >>= 1;
1877                 break;
1878             case MT_POISONDART:
1879                 if (target->player)
1880                 {
1881                     P_PoisonPlayer(target->player, source, 20);
1882                     damage >>= 1;
1883                 }
1884                 break;
1885             case MT_POISONCLOUD:
1886                 if (target->player)
1887                 {
1888                     if (target->player->poisoncount < 4)
1889                     {
1890                         P_PoisonDamage(target->player, source, 15 + (P_Random() & 15), false);  // Don't play painsound
1891                         P_PoisonPlayer(target->player, source, 50);
1892                         S_StartSound(target, SFX_PLAYER_POISONCOUGH);
1893                     }
1894                     return;
1895                 }
1896                 else if (!(target->flags & MF_COUNTKILL))
1897                 {               // only damage monsters/players with the poison cloud
1898                     return;
1899                 }
1900                 break;
1901             case MT_FSWORD_MISSILE:
1902                 if (target->player)
1903                 {
1904                     damage -= damage >> 2;
1905                 }
1906                 break;
1907             default:
1908                 break;
1909         }
1910     }
1911     // Push the target unless source is using the gauntlets
1912     if (inflictor && (!source || !source->player)
1913         && !(inflictor->flags2 & MF2_NODMGTHRUST))
1914     {
1915         ang = R_PointToAngle2(inflictor->x, inflictor->y,
1916                               target->x, target->y);
1917         //thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
1918         thrust = damage * (FRACUNIT >> 3) * 150 / target->info->mass;
1919         // make fall forwards sometimes
1920         if ((damage < 40) && (damage > target->health)
1921             && (target->z - inflictor->z > 64 * FRACUNIT) && (P_Random() & 1))
1922         {
1923             ang += ANG180;
1924             thrust *= 4;
1925         }
1926         ang >>= ANGLETOFINESHIFT;
1927         target->momx += FixedMul(thrust, finecosine[ang]);
1928         target->momy += FixedMul(thrust, finesine[ang]);
1929     }
1930 
1931     //
1932     // player specific
1933     //
1934     if (player)
1935     {
1936         savedPercent = AutoArmorSave[player->class]
1937             + player->armorpoints[ARMOR_ARMOR] +
1938             player->armorpoints[ARMOR_SHIELD] +
1939             player->armorpoints[ARMOR_HELMET] +
1940             player->armorpoints[ARMOR_AMULET];
1941         if (savedPercent)
1942         {                       // armor absorbed some damage
1943             if (savedPercent > 100 * FRACUNIT)
1944             {
1945                 savedPercent = 100 * FRACUNIT;
1946             }
1947             for (i = 0; i < NUMARMOR; i++)
1948             {
1949                 if (player->armorpoints[i])
1950                 {
1951                     player->armorpoints[i] -=
1952                         FixedDiv(FixedMul(damage << FRACBITS,
1953                                           ArmorIncrement[player->class][i]),
1954                                  300 * FRACUNIT);
1955                     if (player->armorpoints[i] < 2 * FRACUNIT)
1956                     {
1957                         player->armorpoints[i] = 0;
1958                     }
1959                 }
1960             }
1961             saved = FixedDiv(FixedMul(damage << FRACBITS, savedPercent),
1962                              100 * FRACUNIT);
1963             if (saved > savedPercent * 2)
1964             {
1965                 saved = savedPercent * 2;
1966             }
1967             damage -= saved >> FRACBITS;
1968         }
1969         if (damage >= player->health
1970             && ((gameskill == sk_baby) || deathmatch) && !player->morphTics)
1971         {                       // Try to use some inventory health
1972             P_AutoUseHealth(player, damage - player->health + 1);
1973         }
1974         player->health -= damage;       // mirror mobj health here for Dave
1975         if (player->health < 0)
1976         {
1977             player->health = 0;
1978         }
1979         player->attacker = source;
1980         player->damagecount += damage;  // add damage after armor / invuln
1981         if (player->damagecount > 100)
1982         {
1983             player->damagecount = 100;  // teleport stomp does 10k points...
1984         }
1985         temp = damage < 100 ? damage : 100;
1986         if (player == &players[consoleplayer])
1987         {
1988             I_Tactile(40, 10, 40 + temp * 2);
1989             SB_PaletteFlash(false);
1990         }
1991     }
1992 
1993     //
1994     // do the damage
1995     //
1996     target->health -= damage;
1997     if (target->health <= 0)
1998     {                           // Death
1999         if (inflictor)
2000         {                       // check for special fire damage or ice damage deaths
2001             if (inflictor->flags2 & MF2_FIREDAMAGE)
2002             {
2003                 if (player && !player->morphTics)
2004                 {               // Check for flame death
2005                     if (target->health > -50 && damage > 25)
2006                     {
2007                         target->flags2 |= MF2_FIREDAMAGE;
2008                     }
2009                 }
2010                 else
2011                 {
2012                     target->flags2 |= MF2_FIREDAMAGE;
2013                 }
2014             }
2015             else if (inflictor->flags2 & MF2_ICEDAMAGE)
2016             {
2017                 target->flags2 |= MF2_ICEDAMAGE;
2018             }
2019         }
2020         if (source && (source->type == MT_MINOTAUR))
2021         {                       // Minotaur's kills go to his master
2022             master = source->special1.m;
2023             // Make sure still alive and not a pointer to fighter head
2024             if (master->player && (master->player->mo == master))
2025             {
2026                 source = master;
2027             }
2028         }
2029         if (source && (source->player) &&
2030             (source->player->readyweapon == WP_FOURTH))
2031         {
2032             // Always extreme death from fourth weapon
2033             target->health = -5000;
2034         }
2035         P_KillMobj(source, target);
2036         return;
2037     }
2038     if ((P_Random() < target->info->painchance)
2039         && !(target->flags & MF_SKULLFLY))
2040     {
2041         if (inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR
2042                           && inflictor->type <= MT_LIGHTNING_ZAP))
2043         {
2044             if (P_Random() < 96)
2045             {
2046                 target->flags |= MF_JUSTHIT;    // fight back!
2047                 P_SetMobjState(target, target->info->painstate);
2048             }
2049             else
2050             {                   // "electrocute" the target
2051                 target->frame |= FF_FULLBRIGHT;
2052                 if (target->flags & MF_COUNTKILL && P_Random() < 128
2053                     && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
2054                 {
2055                     if ((target->type == MT_CENTAUR) ||
2056                         (target->type == MT_CENTAURLEADER) ||
2057                         (target->type == MT_ETTIN))
2058                     {
2059                         S_StartSound(target, SFX_PUPPYBEAT);
2060                     }
2061                 }
2062             }
2063         }
2064         else
2065         {
2066             target->flags |= MF_JUSTHIT;        // fight back!
2067             P_SetMobjState(target, target->info->painstate);
2068             if (inflictor && inflictor->type == MT_POISONCLOUD)
2069             {
2070                 if (target->flags & MF_COUNTKILL && P_Random() < 128
2071                     && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
2072                 {
2073                     if ((target->type == MT_CENTAUR) ||
2074                         (target->type == MT_CENTAURLEADER) ||
2075                         (target->type == MT_ETTIN))
2076                     {
2077                         S_StartSound(target, SFX_PUPPYBEAT);
2078                     }
2079                 }
2080             }
2081         }
2082     }
2083     target->reactiontime = 0;   // we're awake now...
2084     if (!target->threshold && source && !(source->flags2 & MF2_BOSS)
2085         && !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
2086     {
2087         // Target actor is not intent on another actor,
2088         // so make him chase after source
2089         if ((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER)
2090             || (target->type == MT_CENTAURLEADER
2091                 && source->type == MT_CENTAUR))
2092         {
2093             return;
2094         }
2095         target->target = source;
2096         target->threshold = BASETHRESHOLD;
2097         if (target->state == &states[target->info->spawnstate]
2098             && target->info->seestate != S_NULL)
2099         {
2100             P_SetMobjState(target, target->info->seestate);
2101         }
2102     }
2103 }
2104 
2105 //==========================================================================
2106 //
2107 // P_FallingDamage
2108 //
2109 //==========================================================================
2110 
P_FallingDamage(player_t * player)2111 void P_FallingDamage(player_t * player)
2112 {
2113     int damage;
2114     int mom;
2115     int dist;
2116 
2117     mom = abs(player->mo->momz);
2118     dist = FixedMul(mom, 16 * FRACUNIT / 23);
2119 
2120     if (mom >= 63 * FRACUNIT)
2121     {                           // automatic death
2122         P_DamageMobj(player->mo, NULL, NULL, 10000);
2123         return;
2124     }
2125     damage = ((FixedMul(dist, dist) / 10) >> FRACBITS) - 24;
2126     if (player->mo->momz > -39 * FRACUNIT && damage > player->mo->health
2127         && player->mo->health != 1)
2128     {                           // No-death threshold
2129         damage = player->mo->health - 1;
2130     }
2131     S_StartSound(player->mo, SFX_PLAYER_LAND);
2132     P_DamageMobj(player->mo, NULL, NULL, damage);
2133 }
2134 
2135 //==========================================================================
2136 //
2137 // P_PoisonPlayer - Sets up all data concerning poisoning
2138 //
2139 //==========================================================================
2140 
P_PoisonPlayer(player_t * player,mobj_t * poisoner,int poison)2141 void P_PoisonPlayer(player_t * player, mobj_t * poisoner, int poison)
2142 {
2143     if ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability])
2144     {
2145         return;
2146     }
2147     player->poisoncount += poison;
2148     player->poisoner = poisoner;
2149     if (player->poisoncount > 100)
2150     {
2151         player->poisoncount = 100;
2152     }
2153 }
2154 
2155 //==========================================================================
2156 //
2157 // P_PoisonDamage - Similar to P_DamageMobj
2158 //
2159 //==========================================================================
2160 
P_PoisonDamage(player_t * player,mobj_t * source,int damage,boolean playPainSound)2161 void P_PoisonDamage(player_t * player, mobj_t * source, int damage,
2162                     boolean playPainSound)
2163 {
2164     mobj_t *target;
2165     mobj_t *inflictor;
2166 
2167     target = player->mo;
2168     inflictor = source;
2169     if (target->health <= 0)
2170     {
2171         return;
2172     }
2173     if (target->flags2 & MF2_INVULNERABLE && damage < 10000)
2174     {                           // mobj is invulnerable
2175         return;
2176     }
2177     if (player && gameskill == sk_baby)
2178     {
2179         // Take half damage in trainer mode
2180         damage >>= 1;
2181     }
2182     if (damage < 1000 && ((player->cheats & CF_GODMODE)
2183                           || player->powers[pw_invulnerability]))
2184     {
2185         return;
2186     }
2187     if (damage >= player->health
2188         && ((gameskill == sk_baby) || deathmatch) && !player->morphTics)
2189     {                           // Try to use some inventory health
2190         P_AutoUseHealth(player, damage - player->health + 1);
2191     }
2192     player->health -= damage;   // mirror mobj health here for Dave
2193     if (player->health < 0)
2194     {
2195         player->health = 0;
2196     }
2197     player->attacker = source;
2198 
2199     //
2200     // do the damage
2201     //
2202     target->health -= damage;
2203     if (target->health <= 0)
2204     {                           // Death
2205         target->special1.i = damage;
2206         if (player && inflictor && !player->morphTics)
2207         {                       // Check for flame death
2208             if ((inflictor->flags2 & MF2_FIREDAMAGE)
2209                 && (target->health > -50) && (damage > 25))
2210             {
2211                 target->flags2 |= MF2_FIREDAMAGE;
2212             }
2213             if (inflictor->flags2 & MF2_ICEDAMAGE)
2214             {
2215                 target->flags2 |= MF2_ICEDAMAGE;
2216             }
2217         }
2218         P_KillMobj(source, target);
2219         return;
2220     }
2221     if (!(leveltime & 63) && playPainSound)
2222     {
2223         P_SetMobjState(target, target->info->painstate);
2224     }
2225 /*
2226 	if((P_Random() < target->info->painchance)
2227 		&& !(target->flags&MF_SKULLFLY))
2228 	{
2229 		target->flags |= MF_JUSTHIT; // fight back!
2230 		P_SetMobjState(target, target->info->painstate);
2231 	}
2232 */
2233 }
2234