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