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