1
2 /* P_inter.c */
3
4 #include "doomdef.h"
5 #include "p_local.h"
6 #include "soundst.h"
7
8 #define BONUSADD 6
9
10 int WeaponValue[] =
11 {
12 1, /* staff */
13 3, /* goldwand */
14 4, /* crossbow */
15 5, /* blaster */
16 6, /* skullrod */
17 7, /* phoenixrod */
18 8, /* mace */
19 2, /* gauntlets */
20 0 /* beak */
21 };
22
23 int maxammo[NUMAMMO] =
24 {
25 100, /* gold wand */
26 50, /* crossbow */
27 200, /* blaster */
28 200, /* skull rod */
29 20, /* phoenix rod */
30 150 /* mace */
31 };
32
33 static int GetWeaponAmmo[NUMWEAPONS] =
34 {
35 0, /* staff */
36 25, /* gold wand */
37 10, /* crossbow */
38 30, /* blaster */
39 50, /* skull rod */
40 2, /* phoenix rod */
41 50, /* mace */
42 0, /* gauntlets */
43 0 /* beak */
44 };
45
46 static weapontype_t GetAmmoChange[] =
47 {
48 wp_goldwand,
49 wp_crossbow,
50 wp_blaster,
51 wp_skullrod,
52 wp_phoenixrod,
53 wp_mace
54 };
55
56 /*
57 static boolean GetAmmoChangePL1[NUMWEAPONS][NUMAMMO] =
58 {
59 // staff
60 {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
61 // gold wand
62 {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
63 // crossbow
64 {-1, -1, wp_blaster, wp_skullrod, -1, -1},
65 // blaster
66 {-1, -1, -1, -1, -1, -1},
67 // skull rod
68 {-1, -1, -1, -1, -1, -1},
69 // phoenix rod
70 {-1, -1, -1, -1, -1, -1},
71 // mace
72 {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
73 // gauntlets
74 {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}
75 };
76 */
77
78 /*
79 static boolean GetAmmoChangePL2[NUMWEAPONS][NUMAMMO] =
80 {
81 // staff
82 {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod,
83 wp_mace},
84 // gold wand
85 {-1, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace},
86 // crossbow
87 {-1, -1, wp_blaster, wp_skullrod, wp_phoenixrod, -1},
88 // blaster
89 {-1, -1, -1, wp_skullrod, wp_phoenixrod, -1},
90 // skull rod
91 {-1, -1, -1, -1, -1, -1},
92 // phoenix rod
93 {-1, -1, -1, -1, -1, -1},
94 // mace
95 {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
96 // gauntlets
97 {-1, -1, -1, wp_skullrod, wp_phoenixrod, wp_mace}
98 };
99 */
100
101
102 /*
103 //--------------------------------------------------------------------------
104 //
105 // PROC P_SetMessage
106 //
107 //--------------------------------------------------------------------------
108 */
109 boolean ultimatemsg;
110
P_SetMessage(player_t * player,char * message,boolean ultmsg)111 void P_SetMessage(player_t *player, char *message, boolean ultmsg)
112 {
113 extern boolean messageson;
114
115 if((ultimatemsg || !messageson) && !ultmsg)
116 {
117 return;
118 }
119 player->message = message;
120 player->messageTics = MESSAGETICS;
121 BorderTopRefresh = true;
122 if(ultmsg)
123 {
124 ultimatemsg = true;
125 }
126 }
127
128
129 /*
130 //--------------------------------------------------------------------------
131 //
132 // FUNC P_GiveAmmo
133 //
134 // Returns true if the player accepted the ammo, false if it was
135 // refused (player has maxammo[ammo]).
136 //
137 //--------------------------------------------------------------------------
138 */
P_GiveAmmo(player_t * player,ammotype_t ammo,int count)139 boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int count)
140 {
141 int prevAmmo;
142 /* weapontype_t changeWeapon; */
143
144 if(ammo == am_noammo)
145 {
146 return(false);
147 }
148 if(ammo < 0 || ammo > NUMAMMO)
149 {
150 I_Error("P_GiveAmmo: bad type %i", ammo);
151 }
152 if(player->ammo[ammo] == player->maxammo[ammo])
153 {
154 return(false);
155 }
156 if(gameskill == sk_baby || gameskill == sk_nightmare)
157 { /* extra ammo in baby mode and nightmare mode */
158 count += count>>1;
159 }
160 prevAmmo = player->ammo[ammo];
161
162 player->ammo[ammo] += count;
163 if(player->ammo[ammo] > player->maxammo[ammo])
164 {
165 player->ammo[ammo] = player->maxammo[ammo];
166 }
167 if(prevAmmo)
168 {
169 /*
170 * Don't attempt to change weapons if the player already had
171 * ammo of the type just given
172 */
173 return(true);
174 }
175 if(player->readyweapon == wp_staff
176 || player->readyweapon == wp_gauntlets)
177 {
178 if(player->weaponowned[GetAmmoChange[ammo]])
179 {
180 player->pendingweapon = GetAmmoChange[ammo];
181 }
182 }
183 /*
184 if(player->powers[pw_weaponlevel2])
185 {
186 changeWeapon = GetAmmoChangePL2[player->readyweapon][ammo];
187 }
188 else
189 {
190 changeWeapon = GetAmmoChangePL1[player->readyweapon][ammo];
191 }
192 if(changeWeapon != -1)
193 {
194 if(player->weaponowned[changeWeapon])
195 {
196 player->pendingweapon = changeWeapon;
197 }
198 }
199 */
200 return(true);
201 }
202
203
204 /*
205 //--------------------------------------------------------------------------
206 //
207 // FUNC P_GiveWeapon
208 //
209 // Returns true if the weapon or its ammo was accepted.
210 //
211 //--------------------------------------------------------------------------
212 */
P_GiveWeapon(player_t * player,weapontype_t weapon)213 boolean P_GiveWeapon(player_t *player, weapontype_t weapon)
214 {
215 boolean gaveAmmo;
216 boolean gaveWeapon;
217
218 if(netgame && !deathmatch)
219 { /* Cooperative net-game */
220 if(player->weaponowned[weapon])
221 {
222 return(false);
223 }
224 player->bonuscount += BONUSADD;
225 player->weaponowned[weapon] = true;
226 P_GiveAmmo(player, wpnlev1info[weapon].ammo,
227 GetWeaponAmmo[weapon]);
228 player->pendingweapon = weapon;
229 if(player == &players[consoleplayer])
230 {
231 S_StartSound(NULL, sfx_wpnup);
232 }
233 return(false);
234 }
235 gaveAmmo = P_GiveAmmo(player, wpnlev1info[weapon].ammo,
236 GetWeaponAmmo[weapon]);
237 if(player->weaponowned[weapon])
238 {
239 gaveWeapon = false;
240 }
241 else
242 {
243 gaveWeapon = true;
244 player->weaponowned[weapon] = true;
245 if(WeaponValue[weapon] > WeaponValue[player->readyweapon])
246 { /* Only switch to more powerful weapons */
247 player->pendingweapon = weapon;
248 }
249 }
250 return(gaveWeapon || gaveAmmo);
251 }
252
253
254 /*
255 //---------------------------------------------------------------------------
256 //
257 // FUNC P_GiveBody
258 //
259 // Returns false if the body isn't needed at all.
260 //
261 //---------------------------------------------------------------------------
262 */
P_GiveBody(player_t * player,int num)263 boolean P_GiveBody(player_t *player, int num)
264 {
265 int max;
266
267 max = MAXHEALTH;
268 if(player->chickenTics)
269 {
270 max = MAXCHICKENHEALTH;
271 }
272 if(player->health >= max)
273 {
274 return(false);
275 }
276 player->health += num;
277 if(player->health > max)
278 {
279 player->health = max;
280 }
281 player->mo->health = player->health;
282 return(true);
283 }
284
285
286 /*
287 //---------------------------------------------------------------------------
288 //
289 // FUNC P_GiveArmor
290 //
291 // Returns false if the armor is worse than the current armor.
292 //
293 //---------------------------------------------------------------------------
294 */
P_GiveArmor(player_t * player,int armortype)295 boolean P_GiveArmor(player_t *player, int armortype)
296 {
297 int hits;
298
299 hits = armortype*100;
300 if(player->armorpoints >= hits)
301 {
302 return(false);
303 }
304 player->armortype = armortype;
305 player->armorpoints = hits;
306 return(true);
307 }
308
309
310 /*
311 //---------------------------------------------------------------------------
312 //
313 // PROC P_GiveKey
314 //
315 //---------------------------------------------------------------------------
316 */
P_GiveKey(player_t * player,keytype_t key)317 void P_GiveKey(player_t *player, keytype_t key)
318 {
319 extern int playerkeys;
320 extern vertex_t KeyPoints[];
321
322 if(player->keys[key])
323 {
324 return;
325 }
326 if(player == &players[consoleplayer])
327 {
328 playerkeys |= 1<<key;
329 KeyPoints[key].x = 0;
330 KeyPoints[key].y = 0;
331 }
332 player->bonuscount = BONUSADD;
333 player->keys[key] = true;
334 }
335
336
337 /*
338 //---------------------------------------------------------------------------
339 //
340 // FUNC P_GivePower
341 //
342 // Returns true if power accepted.
343 //
344 //---------------------------------------------------------------------------
345 */
P_GivePower(player_t * player,powertype_t power)346 boolean P_GivePower(player_t *player, powertype_t power)
347 {
348 if(power == pw_invulnerability)
349 {
350 if(player->powers[power] > BLINKTHRESHOLD)
351 { /* Already have it */
352 return(false);
353 }
354 player->powers[power] = INVULNTICS;
355 return(true);
356 }
357 if(power == pw_weaponlevel2)
358 {
359 if(player->powers[power] > BLINKTHRESHOLD)
360 { /* Already have it */
361 return(false);
362 }
363 player->powers[power] = WPNLEV2TICS;
364 return(true);
365 }
366 if(power == pw_invisibility)
367 {
368 if(player->powers[power] > BLINKTHRESHOLD)
369 { /* Already have it */
370 return(false);
371 }
372 player->powers[power] = INVISTICS;
373 player->mo->flags |= MF_SHADOW;
374 return(true);
375 }
376 if(power == pw_flight)
377 {
378 if(player->powers[power] > BLINKTHRESHOLD)
379 { /* Already have it */
380 return(false);
381 }
382 player->powers[power] = FLIGHTTICS;
383 player->mo->flags2 |= MF2_FLY;
384 player->mo->flags |= MF_NOGRAVITY;
385 if(player->mo->z <= player->mo->floorz)
386 {
387 player->flyheight = 10; /* thrust the player in the air a bit */
388 }
389 return(true);
390 }
391 if(power == pw_infrared)
392 {
393 if(player->powers[power] > BLINKTHRESHOLD)
394 { /* Already have it */
395 return(false);
396 }
397 player->powers[power] = INFRATICS;
398 return(true);
399 }
400 /*
401 if(power == pw_ironfeet)
402 {
403 player->powers[power] = IRONTICS;
404 return(true);
405 }
406 if(power == pw_strength)
407 {
408 P_GiveBody(player, 100);
409 player->powers[power] = 1;
410 return(true);
411 }
412 */
413 if(player->powers[power])
414 {
415 return(false); /* already got it */
416 }
417 player->powers[power] = 1;
418 return(true);
419 }
420
421
422 /*
423 //---------------------------------------------------------------------------
424 //
425 // FUNC P_GiveArtifact
426 //
427 // Returns true if artifact accepted.
428 //
429 //---------------------------------------------------------------------------
430 */
P_GiveArtifact(player_t * player,artitype_t arti,mobj_t * mo)431 boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
432 {
433 int i;
434
435 i = 0;
436 while(player->inventory[i].type != arti && i < player->inventorySlotNum)
437 {
438 i++;
439 }
440 if(i == player->inventorySlotNum)
441 {
442 player->inventory[i].count = 1;
443 player->inventory[i].type = arti;
444 player->inventorySlotNum++;
445 }
446 else
447 {
448 if(player->inventory[i].count >= 16)
449 { /* Player already has 16 of this item */
450 return(false);
451 }
452 player->inventory[i].count++;
453 }
454 if(player->artifactCount == 0)
455 {
456 player->readyArtifact = arti;
457 }
458 player->artifactCount++;
459 if(mo && (mo->flags&MF_COUNTITEM))
460 {
461 player->itemcount++;
462 }
463 return(true);
464 }
465
466
467 /*
468 //---------------------------------------------------------------------------
469 //
470 // PROC P_SetDormantArtifact
471 //
472 // Removes the MF_SPECIAL flag, and initiates the artifact pickup
473 // animation.
474 //
475 //---------------------------------------------------------------------------
476 */
P_SetDormantArtifact(mobj_t * arti)477 void P_SetDormantArtifact(mobj_t *arti)
478 {
479 arti->flags &= ~MF_SPECIAL;
480 if(
481 (deathmatch && (arti->type != MT_ARTIINVULNERABILITY)
482 && (arti->type != MT_ARTIINVISIBILITY))
483 || (respawnartifacts) )
484 {
485 P_SetMobjState(arti, S_DORMANTARTI1);
486 }
487 else
488 { /* Don't respawn */
489 P_SetMobjState(arti, S_DEADARTI1);
490 }
491 S_StartSound(arti, sfx_artiup);
492 }
493
494
495 /*
496 //---------------------------------------------------------------------------
497 //
498 // PROC A_RestoreArtifact
499 //
500 //---------------------------------------------------------------------------
501 */
A_RestoreArtifact(mobj_t * arti)502 void A_RestoreArtifact(mobj_t *arti)
503 {
504 arti->flags |= MF_SPECIAL;
505 P_SetMobjState(arti, arti->info->spawnstate);
506 S_StartSound(arti, sfx_respawn);
507 }
508
509
510 /*
511 //----------------------------------------------------------------------------
512 //
513 // PROC P_HideSpecialThing
514 //
515 //----------------------------------------------------------------------------
516 */
P_HideSpecialThing(mobj_t * thing)517 void P_HideSpecialThing(mobj_t *thing)
518 {
519 thing->flags &= ~MF_SPECIAL;
520 thing->flags2 |= MF2_DONTDRAW;
521 P_SetMobjState(thing, S_HIDESPECIAL1);
522 }
523
524
525 /*
526 //---------------------------------------------------------------------------
527 //
528 // PROC A_RestoreSpecialThing1
529 //
530 // Make a special thing visible again.
531 //
532 //---------------------------------------------------------------------------
533 */
A_RestoreSpecialThing1(mobj_t * thing)534 void A_RestoreSpecialThing1(mobj_t *thing)
535 {
536 if(thing->type == MT_WMACE)
537 { /* Do random mace placement */
538 P_RepositionMace(thing);
539 }
540 thing->flags2 &= ~MF2_DONTDRAW;
541 S_StartSound(thing, sfx_respawn);
542 }
543
544
545 /*
546 //---------------------------------------------------------------------------
547 //
548 // PROC A_RestoreSpecialThing2
549 //
550 //---------------------------------------------------------------------------
551 */
A_RestoreSpecialThing2(mobj_t * thing)552 void A_RestoreSpecialThing2(mobj_t *thing)
553 {
554 thing->flags |= MF_SPECIAL;
555 P_SetMobjState(thing, thing->info->spawnstate);
556 }
557
558
559 /*
560 //---------------------------------------------------------------------------
561 //
562 // PROC P_TouchSpecialThing
563 //
564 //---------------------------------------------------------------------------
565 */
P_TouchSpecialThing(mobj_t * special,mobj_t * toucher)566 void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
567 {
568 int i;
569 player_t *player;
570 fixed_t delta;
571 int sound;
572 boolean respawn;
573
574 delta = special->z-toucher->z;
575 if(delta > toucher->height || delta < -32*FRACUNIT)
576 { /* Out of reach */
577 return;
578 }
579 if(toucher->health <= 0)
580 { /* Toucher is dead */
581 return;
582 }
583 sound = sfx_itemup;
584 player = toucher->player;
585 respawn = true;
586 switch(special->sprite)
587 {
588 /* Items */
589 case SPR_PTN1: /* Item_HealingPotion */
590 if(!P_GiveBody(player, 10))
591 {
592 return;
593 }
594 P_SetMessage(player, TXT_ITEMHEALTH, false);
595 break;
596 case SPR_SHLD: /* Item_Shield1 */
597 if(!P_GiveArmor(player, 1))
598 {
599 return;
600 }
601 P_SetMessage(player, TXT_ITEMSHIELD1, false);
602 break;
603 case SPR_SHD2: /* Item_Shield2 */
604 if(!P_GiveArmor(player, 2))
605 {
606 return;
607 }
608 P_SetMessage(player, TXT_ITEMSHIELD2, false);
609 break;
610 case SPR_BAGH: /* Item_BagOfHolding */
611 if(!player->backpack)
612 {
613 for(i = 0; i < NUMAMMO; i++)
614 {
615 player->maxammo[i] *= 2;
616 }
617 player->backpack = true;
618 }
619 P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY);
620 P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY);
621 P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
622 P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
623 P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
624 P_SetMessage(player, TXT_ITEMBAGOFHOLDING, false);
625 break;
626 case SPR_SPMP: /* Item_SuperMap */
627 if(!P_GivePower(player, pw_allmap))
628 {
629 return;
630 }
631 P_SetMessage(player, TXT_ITEMSUPERMAP, false);
632 break;
633
634 /* Keys */
635 case SPR_BKYY: /* Key_Blue */
636 if(!player->keys[key_blue])
637 {
638 P_SetMessage(player, TXT_GOTBLUEKEY, false);
639 }
640 P_GiveKey(player, key_blue);
641 sound = sfx_keyup;
642 if(!netgame)
643 {
644 break;
645 }
646 return;
647 case SPR_CKYY: /* Key_Yellow */
648 if(!player->keys[key_yellow])
649 {
650 P_SetMessage(player, TXT_GOTYELLOWKEY, false);
651 }
652 sound = sfx_keyup;
653 P_GiveKey(player, key_yellow);
654 if(!netgame)
655 {
656 break;
657 }
658 return;
659 case SPR_AKYY: /* Key_Green */
660 if(!player->keys[key_green])
661 {
662 P_SetMessage(player, TXT_GOTGREENKEY, false);
663 }
664 sound = sfx_keyup;
665 P_GiveKey(player, key_green);
666 if(!netgame)
667 {
668 break;
669 }
670 return;
671
672 /* Artifacts */
673 case SPR_PTN2: /* Arti_HealingPotion */
674 if(P_GiveArtifact(player, arti_health, special))
675 {
676 P_SetMessage(player, TXT_ARTIHEALTH, false);
677 P_SetDormantArtifact(special);
678 }
679 return;
680 case SPR_SOAR: /* Arti_Fly */
681 if(P_GiveArtifact(player, arti_fly, special))
682 {
683 P_SetMessage(player, TXT_ARTIFLY, false);
684 P_SetDormantArtifact(special);
685 }
686 return;
687 case SPR_INVU: /* Arti_Invulnerability */
688 if(P_GiveArtifact(player, arti_invulnerability, special))
689 {
690 P_SetMessage(player, TXT_ARTIINVULNERABILITY, false);
691 P_SetDormantArtifact(special);
692 }
693 return;
694 case SPR_PWBK: /* Arti_TomeOfPower */
695 if(P_GiveArtifact(player, arti_tomeofpower, special))
696 {
697 P_SetMessage(player, TXT_ARTITOMEOFPOWER, false);
698 P_SetDormantArtifact(special);
699 }
700 return;
701 case SPR_INVS: /* Arti_Invisibility */
702 if(P_GiveArtifact(player, arti_invisibility, special))
703 {
704 P_SetMessage(player, TXT_ARTIINVISIBILITY, false);
705 P_SetDormantArtifact(special);
706 }
707 return;
708 case SPR_EGGC: /* Arti_Egg */
709 if(P_GiveArtifact(player, arti_egg, special))
710 {
711 P_SetMessage(player, TXT_ARTIEGG, false);
712 P_SetDormantArtifact(special);
713 }
714 return;
715 case SPR_SPHL: /* Arti_SuperHealth */
716 if(P_GiveArtifact(player, arti_superhealth, special))
717 {
718 P_SetMessage(player, TXT_ARTISUPERHEALTH, false);
719 P_SetDormantArtifact(special);
720 }
721 return;
722 case SPR_TRCH: /* Arti_Torch */
723 if(P_GiveArtifact(player, arti_torch, special))
724 {
725 P_SetMessage(player, TXT_ARTITORCH, false);
726 P_SetDormantArtifact(special);
727 }
728 return;
729 case SPR_FBMB: /* Arti_FireBomb */
730 if(P_GiveArtifact(player, arti_firebomb, special))
731 {
732 P_SetMessage(player, TXT_ARTIFIREBOMB, false);
733 P_SetDormantArtifact(special);
734 }
735 return;
736 case SPR_ATLP: /* Arti_Teleport */
737 if(P_GiveArtifact(player, arti_teleport, special))
738 {
739 P_SetMessage(player, TXT_ARTITELEPORT, false);
740 P_SetDormantArtifact(special);
741 }
742 return;
743
744 /* Ammo */
745 case SPR_AMG1: /* Ammo_GoldWandWimpy */
746 if(!P_GiveAmmo(player, am_goldwand, special->health))
747 {
748 return;
749 }
750 P_SetMessage(player, TXT_AMMOGOLDWAND1, false);
751 break;
752 case SPR_AMG2: /* Ammo_GoldWandHefty */
753 if(!P_GiveAmmo(player, am_goldwand, special->health))
754 {
755 return;
756 }
757 P_SetMessage(player, TXT_AMMOGOLDWAND2, false);
758 break;
759 case SPR_AMM1: /* Ammo_MaceWimpy */
760 if(!P_GiveAmmo(player, am_mace, special->health))
761 {
762 return;
763 }
764 P_SetMessage(player, TXT_AMMOMACE1, false);
765 break;
766 case SPR_AMM2: /* Ammo_MaceHefty */
767 if(!P_GiveAmmo(player, am_mace, special->health))
768 {
769 return;
770 }
771 P_SetMessage(player, TXT_AMMOMACE2, false);
772 break;
773 case SPR_AMC1: /* Ammo_CrossbowWimpy */
774 if(!P_GiveAmmo(player, am_crossbow, special->health))
775 {
776 return;
777 }
778 P_SetMessage(player, TXT_AMMOCROSSBOW1, false);
779 break;
780 case SPR_AMC2: /* Ammo_CrossbowHefty */
781 if(!P_GiveAmmo(player, am_crossbow, special->health))
782 {
783 return;
784 }
785 P_SetMessage(player, TXT_AMMOCROSSBOW2, false);
786 break;
787 case SPR_AMB1: /* Ammo_BlasterWimpy */
788 if(!P_GiveAmmo(player, am_blaster, special->health))
789 {
790 return;
791 }
792 P_SetMessage(player, TXT_AMMOBLASTER1, false);
793 break;
794 case SPR_AMB2: /* Ammo_BlasterHefty */
795 if(!P_GiveAmmo(player, am_blaster, special->health))
796 {
797 return;
798 }
799 P_SetMessage(player, TXT_AMMOBLASTER2, false);
800 break;
801 case SPR_AMS1: /* Ammo_SkullRodWimpy */
802 if(!P_GiveAmmo(player, am_skullrod, special->health))
803 {
804 return;
805 }
806 P_SetMessage(player, TXT_AMMOSKULLROD1, false);
807 break;
808 case SPR_AMS2: /* Ammo_SkullRodHefty */
809 if(!P_GiveAmmo(player, am_skullrod, special->health))
810 {
811 return;
812 }
813 P_SetMessage(player, TXT_AMMOSKULLROD2, false);
814 break;
815 case SPR_AMP1: /* Ammo_PhoenixRodWimpy */
816 if(!P_GiveAmmo(player, am_phoenixrod, special->health))
817 {
818 return;
819 }
820 P_SetMessage(player, TXT_AMMOPHOENIXROD1, false);
821 break;
822 case SPR_AMP2: /* Ammo_PhoenixRodHefty */
823 if(!P_GiveAmmo(player, am_phoenixrod, special->health))
824 {
825 return;
826 }
827 P_SetMessage(player, TXT_AMMOPHOENIXROD2, false);
828 break;
829
830 /* Weapons */
831 case SPR_WMCE: /* Weapon_Mace */
832 if(!P_GiveWeapon(player, wp_mace))
833 {
834 return;
835 }
836 P_SetMessage(player, TXT_WPNMACE, false);
837 sound = sfx_wpnup;
838 break;
839 case SPR_WBOW: /* Weapon_Crossbow */
840 if(!P_GiveWeapon(player, wp_crossbow))
841 {
842 return;
843 }
844 P_SetMessage(player, TXT_WPNCROSSBOW, false);
845 sound = sfx_wpnup;
846 break;
847 case SPR_WBLS: /* Weapon_Blaster */
848 if(!P_GiveWeapon(player, wp_blaster))
849 {
850 return;
851 }
852 P_SetMessage(player, TXT_WPNBLASTER, false);
853 sound = sfx_wpnup;
854 break;
855 case SPR_WSKL: /* Weapon_SkullRod */
856 if(!P_GiveWeapon(player, wp_skullrod))
857 {
858 return;
859 }
860 P_SetMessage(player, TXT_WPNSKULLROD, false);
861 sound = sfx_wpnup;
862 break;
863 case SPR_WPHX: /* Weapon_PhoenixRod */
864 if(!P_GiveWeapon(player, wp_phoenixrod))
865 {
866 return;
867 }
868 P_SetMessage(player, TXT_WPNPHOENIXROD, false);
869 sound = sfx_wpnup;
870 break;
871 case SPR_WGNT: /* Weapon_Gauntlets */
872 if(!P_GiveWeapon(player, wp_gauntlets))
873 {
874 return;
875 }
876 P_SetMessage(player, TXT_WPNGAUNTLETS, false);
877 sound = sfx_wpnup;
878 break;
879 default:
880 I_Error("P_SpecialThing: Unknown gettable thing");
881 }
882 if(special->flags&MF_COUNTITEM)
883 {
884 player->itemcount++;
885 }
886 if(deathmatch && respawn && !(special->flags&MF_DROPPED))
887 {
888 P_HideSpecialThing(special);
889 }
890 else
891 {
892 P_RemoveMobj(special);
893 }
894 player->bonuscount += BONUSADD;
895 if(player == &players[consoleplayer])
896 {
897 S_StartSound(NULL, sound);
898 SB_PaletteFlash();
899 }
900 }
901
902
903 /*
904 //---------------------------------------------------------------------------
905 //
906 // PROC P_KillMobj
907 //
908 //---------------------------------------------------------------------------
909 */
P_KillMobj(mobj_t * source,mobj_t * target)910 void P_KillMobj(mobj_t *source, mobj_t *target)
911 {
912 target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
913 target->flags |= MF_CORPSE|MF_DROPOFF;
914 target->flags2 &= ~MF2_PASSMOBJ;
915 target->height >>= 2;
916 if(source && source->player)
917 {
918 if(target->flags&MF_COUNTKILL)
919 { /* Count for intermission */
920 source->player->killcount++;
921 }
922 if(target->player)
923 { /* Frag stuff */
924 if(target == source)
925 { /* Self-frag */
926 target->player->frags[target->player-players]--;
927 }
928 else
929 {
930 source->player->frags[target->player-players]++;
931 if(source->player == &players[consoleplayer])
932 {
933 S_StartSound(NULL, sfx_gfrag);
934 }
935 if(source->player->chickenTics)
936 { /* Make a super chicken */
937 P_GivePower(source->player, pw_weaponlevel2);
938 }
939 }
940 }
941 }
942 else if(!netgame && (target->flags&MF_COUNTKILL))
943 { /* Count all monster deaths */
944 players[0].killcount++;
945 }
946 if(target->player)
947 {
948 if(!source)
949 { /* Self-frag */
950 target->player->frags[target->player-players]--;
951 }
952 target->flags &= ~MF_SOLID;
953 target->flags2 &= ~MF2_FLY;
954 target->player->powers[pw_flight] = 0;
955 target->player->powers[pw_weaponlevel2] = 0;
956 target->player->playerstate = PST_DEAD;
957 P_DropWeapon(target->player);
958 if(target->flags2&MF2_FIREDAMAGE)
959 { /* Player flame death */
960 P_SetMobjState(target, S_PLAY_FDTH1);
961 /* S_StartSound(target, sfx_hedat1); // Burn sound */
962 return;
963 }
964 }
965 if(target->health < -(target->info->spawnhealth>>1)
966 && target->info->xdeathstate)
967 { /* Extreme death */
968 P_SetMobjState(target, target->info->xdeathstate);
969 }
970 else
971 { /* Normal death */
972 P_SetMobjState(target, target->info->deathstate);
973 }
974 target->tics -= P_Random()&3;
975 /* I_StartSound(&actor->r, actor->info->deathsound); */
976 }
977
978
979 /*
980 //---------------------------------------------------------------------------
981 //
982 // FUNC P_MinotaurSlam
983 //
984 //---------------------------------------------------------------------------
985 */
P_MinotaurSlam(mobj_t * source,mobj_t * target)986 void P_MinotaurSlam(mobj_t *source, mobj_t *target)
987 {
988 angle_t angle;
989 fixed_t thrust;
990
991 angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
992 angle >>= ANGLETOFINESHIFT;
993 thrust = 16*FRACUNIT+(P_Random()<<10);
994 target->momx += FixedMul(thrust, finecosine[angle]);
995 target->momy += FixedMul(thrust, finesine[angle]);
996 P_DamageMobj(target, NULL, NULL, HITDICE(6));
997 if(target->player)
998 {
999 target->reactiontime = 14+(P_Random()&7);
1000 }
1001 }
1002
1003
1004 /*
1005 //---------------------------------------------------------------------------
1006 //
1007 // FUNC P_TouchWhirlwind
1008 //
1009 //---------------------------------------------------------------------------
1010 */
P_TouchWhirlwind(mobj_t * target)1011 void P_TouchWhirlwind(mobj_t *target)
1012 {
1013 int randVal;
1014
1015 target->angle += (P_Random()-P_Random())<<20;
1016 target->momx += (P_Random()-P_Random())<<10;
1017 target->momy += (P_Random()-P_Random())<<10;
1018 if(leveltime&16 && !(target->flags2&MF2_BOSS))
1019 {
1020 randVal = P_Random();
1021 if(randVal > 160)
1022 {
1023 randVal = 160;
1024 }
1025 target->momz += randVal<<10;
1026 if(target->momz > 12*FRACUNIT)
1027 {
1028 target->momz = 12*FRACUNIT;
1029 }
1030 }
1031 if(!(leveltime&7))
1032 {
1033 P_DamageMobj(target, NULL, NULL, 3);
1034 }
1035 }
1036
1037
1038 /*
1039 //---------------------------------------------------------------------------
1040 //
1041 // FUNC P_ChickenMorphPlayer
1042 //
1043 // Returns true if the player gets turned into a chicken.
1044 //
1045 //---------------------------------------------------------------------------
1046 */
P_ChickenMorphPlayer(player_t * player)1047 boolean P_ChickenMorphPlayer(player_t *player)
1048 {
1049 mobj_t *pmo;
1050 mobj_t *fog;
1051 mobj_t *chicken;
1052 fixed_t x;
1053 fixed_t y;
1054 fixed_t z;
1055 angle_t angle;
1056 int oldFlags2;
1057
1058 if(player->chickenTics)
1059 {
1060 if((player->chickenTics < CHICKENTICS-TICSPERSEC)
1061 && !player->powers[pw_weaponlevel2])
1062 { /* Make a super chicken */
1063 P_GivePower(player, pw_weaponlevel2);
1064 }
1065 return(false);
1066 }
1067 if(player->powers[pw_invulnerability])
1068 { /* Immune when invulnerable */
1069 return(false);
1070 }
1071 pmo = player->mo;
1072 x = pmo->x;
1073 y = pmo->y;
1074 z = pmo->z;
1075 angle = pmo->angle;
1076 oldFlags2 = pmo->flags2;
1077 P_SetMobjState(pmo, S_FREETARGMOBJ);
1078 fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1079 S_StartSound(fog, sfx_telept);
1080 chicken = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
1081 chicken->special1 = player->readyweapon;
1082 chicken->angle = angle;
1083 chicken->player = player;
1084 player->health = chicken->health = MAXCHICKENHEALTH;
1085 player->mo = chicken;
1086 player->armorpoints = player->armortype = 0;
1087 player->powers[pw_invisibility] = 0;
1088 player->powers[pw_weaponlevel2] = 0;
1089 if(oldFlags2&MF2_FLY)
1090 {
1091 chicken->flags2 |= MF2_FLY;
1092 }
1093 player->chickenTics = CHICKENTICS;
1094 P_ActivateBeak(player);
1095 return(true);
1096 }
1097
1098
1099 /*
1100 //---------------------------------------------------------------------------
1101 //
1102 // FUNC P_ChickenMorph
1103 //
1104 //---------------------------------------------------------------------------
1105 */
P_ChickenMorph(mobj_t * actor)1106 boolean P_ChickenMorph(mobj_t *actor)
1107 {
1108 mobj_t *fog;
1109 mobj_t *chicken;
1110 mobj_t *target;
1111 mobjtype_t moType;
1112 fixed_t x;
1113 fixed_t y;
1114 fixed_t z;
1115 angle_t angle;
1116 int ghost;
1117
1118 if(actor->player)
1119 {
1120 return(false);
1121 }
1122 moType = actor->type;
1123 switch(moType)
1124 {
1125 case MT_POD:
1126 case MT_CHICKEN:
1127 case MT_HEAD:
1128 case MT_MINOTAUR:
1129 case MT_SORCERER1:
1130 case MT_SORCERER2:
1131 return(false);
1132 default:
1133 break;
1134 }
1135 x = actor->x;
1136 y = actor->y;
1137 z = actor->z;
1138 angle = actor->angle;
1139 ghost = actor->flags&MF_SHADOW;
1140 target = actor->target;
1141 P_SetMobjState(actor, S_FREETARGMOBJ);
1142 fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1143 S_StartSound(fog, sfx_telept);
1144 chicken = P_SpawnMobj(x, y, z, MT_CHICKEN);
1145 chicken->special2 = moType;
1146 chicken->special1 = CHICKENTICS+P_Random();
1147 chicken->flags |= ghost;
1148 chicken->target = target;
1149 chicken->angle = angle;
1150 return(true);
1151 }
1152
1153
1154 /*
1155 //---------------------------------------------------------------------------
1156 //
1157 // FUNC P_AutoUseChaosDevice
1158 //
1159 //---------------------------------------------------------------------------
1160 */
P_AutoUseChaosDevice(player_t * player)1161 boolean P_AutoUseChaosDevice(player_t *player)
1162 {
1163 int i;
1164
1165 for(i = 0; i < player->inventorySlotNum; i++)
1166 {
1167 if(player->inventory[i].type == arti_teleport)
1168 {
1169 P_PlayerUseArtifact(player, arti_teleport);
1170 player->health = player->mo->health = (player->health+1)/2;
1171 return(true);
1172 }
1173 }
1174 return(false);
1175 }
1176
1177
1178 /*
1179 //---------------------------------------------------------------------------
1180 //
1181 // PROC P_AutoUseHealth
1182 //
1183 //---------------------------------------------------------------------------
1184 */
P_AutoUseHealth(player_t * player,int saveHealth)1185 void P_AutoUseHealth(player_t *player, int saveHealth)
1186 {
1187 int i;
1188 int count;
1189 int normalCount;
1190 /* changed from int normalSlot */
1191 int normalSlot=0;
1192 int superCount;
1193 /* changed from int superSlot */
1194 int superSlot=0;
1195
1196 normalCount = superCount = 0;
1197 for(i = 0; i < player->inventorySlotNum; i++)
1198 {
1199 if(player->inventory[i].type == arti_health)
1200 {
1201 normalSlot = i;
1202 normalCount = player->inventory[i].count;
1203 }
1204 else if(player->inventory[i].type == arti_superhealth)
1205 {
1206 superSlot = i;
1207 superCount = player->inventory[i].count;
1208 }
1209 }
1210 if((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
1211 { /* Use quartz flasks */
1212 count = (saveHealth+24)/25;
1213 for(i = 0; i < count; i++)
1214 {
1215 player->health += 25;
1216 P_PlayerRemoveArtifact(player, normalSlot);
1217 }
1218 }
1219 else if(superCount*100 >= saveHealth)
1220 { /* Use mystic urns */
1221 count = (saveHealth+99)/100;
1222 for(i = 0; i < count; i++)
1223 {
1224 player->health += 100;
1225 P_PlayerRemoveArtifact(player, superSlot);
1226 }
1227 }
1228 else if((gameskill == sk_baby)
1229 && (superCount*100+normalCount*25 >= saveHealth))
1230 { /* Use mystic urns and quartz flasks */
1231 count = (saveHealth+24)/25;
1232 saveHealth -= count*25;
1233 for(i = 0; i < count; i++)
1234 {
1235 player->health += 25;
1236 P_PlayerRemoveArtifact(player, normalSlot);
1237 }
1238 count = (saveHealth+99)/100;
1239 for(i = 0; i < count; i++)
1240 {
1241 player->health += 100;
1242 P_PlayerRemoveArtifact(player, normalSlot);
1243 }
1244 }
1245 player->mo->health = player->health;
1246 }
1247
1248 /*
1249 =================
1250 =
1251 = P_DamageMobj
1252 =
1253 = Damages both enemies and players
1254 = inflictor is the thing that caused the damage
1255 = creature or missile, can be NULL (slime, etc)
1256 = source is the thing to target after taking damage
1257 = creature or NULL
1258 = Source and inflictor are the same for melee attacks
1259 = source can be null for barrel explosions and other environmental stuff
1260 ==================
1261 */
1262
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damage)1263 void P_DamageMobj
1264 (
1265 mobj_t *target,
1266 mobj_t *inflictor,
1267 mobj_t *source,
1268 int damage
1269 )
1270 {
1271 unsigned ang;
1272 int saved;
1273 player_t *player;
1274 fixed_t thrust;
1275 int temp;
1276
1277 if(!(target->flags&MF_SHOOTABLE))
1278 {
1279 /* Shouldn't happen */
1280 return;
1281 }
1282 if(target->health <= 0)
1283 {
1284 return;
1285 }
1286 if(target->flags&MF_SKULLFLY)
1287 {
1288 if(target->type == MT_MINOTAUR)
1289 { /* Minotaur is invulnerable during charge attack */
1290 return;
1291 }
1292 target->momx = target->momy = target->momz = 0;
1293 }
1294 player = target->player;
1295 if(player && gameskill == sk_baby)
1296 {
1297 /* Take half damage in trainer mode */
1298 damage >>= 1;
1299 }
1300 /* Special damage types */
1301 if(inflictor)
1302 {
1303 switch(inflictor->type)
1304 {
1305 case MT_EGGFX:
1306 if(player)
1307 {
1308 P_ChickenMorphPlayer(player);
1309 }
1310 else
1311 {
1312 P_ChickenMorph(target);
1313 }
1314 return; /* Always return */
1315 case MT_WHIRLWIND:
1316 P_TouchWhirlwind(target);
1317 return;
1318 case MT_MINOTAUR:
1319 if(inflictor->flags&MF_SKULLFLY)
1320 { /* Slam only when in charge mode */
1321 P_MinotaurSlam(inflictor, target);
1322 return;
1323 }
1324 break;
1325 case MT_MACEFX4: /* Death ball */
1326 if((target->flags2&MF2_BOSS) || target->type == MT_HEAD)
1327 { /* Don't allow cheap boss kills */
1328 break;
1329 }
1330 else if(target->player)
1331 { /* Player specific checks */
1332 if(target->player->powers[pw_invulnerability])
1333 { /* Can't hurt invulnerable players */
1334 break;
1335 }
1336 if(P_AutoUseChaosDevice(target->player))
1337 { /* Player was saved using chaos device */
1338 return;
1339 }
1340 }
1341 damage = 10000; /* Something's gonna die */
1342 break;
1343 case MT_PHOENIXFX2: /* Flame thrower */
1344 if(target->player && P_Random() < 128)
1345 { /* Freeze player for a bit */
1346 target->reactiontime += 4;
1347 }
1348 break;
1349 case MT_RAINPLR1: /* Rain missiles */
1350 case MT_RAINPLR2:
1351 case MT_RAINPLR3:
1352 case MT_RAINPLR4:
1353 if(target->flags2&MF2_BOSS)
1354 { /* Decrease damage for bosses */
1355 damage = (P_Random()&7)+1;
1356 }
1357 break;
1358 case MT_HORNRODFX2:
1359 case MT_PHOENIXFX1:
1360 if(target->type == MT_SORCERER2 && P_Random() < 96)
1361 { /* D'Sparil teleports away */
1362 P_DSparilTeleport(target);
1363 return;
1364 }
1365 break;
1366 case MT_BLASTERFX1:
1367 case MT_RIPPER:
1368 if(target->type == MT_HEAD)
1369 { /* Less damage to Ironlich bosses */
1370 damage = P_Random()&1;
1371 if(!damage)
1372 {
1373 return;
1374 }
1375 }
1376 break;
1377 default:
1378 break;
1379 }
1380 }
1381 /* Push the target unless source is using the gauntlets */
1382 if(inflictor && (!source || !source->player
1383 || source->player->readyweapon != wp_gauntlets)
1384 && !(inflictor->flags2&MF2_NODMGTHRUST))
1385 {
1386 ang = R_PointToAngle2(inflictor->x, inflictor->y,
1387 target->x, target->y);
1388 /* thrust = damage*(FRACUNIT>>3)*100/target->info->mass; */
1389 thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
1390 /* make fall forwards sometimes */
1391 if((damage < 40) && (damage > target->health)
1392 && (target->z-inflictor->z > 64*FRACUNIT) && (P_Random()&1))
1393 {
1394 ang += ANG180;
1395 thrust *= 4;
1396 }
1397 ang >>= ANGLETOFINESHIFT;
1398 if(source && source->player && (source == inflictor)
1399 && source->player->powers[pw_weaponlevel2]
1400 && source->player->readyweapon == wp_staff)
1401 {
1402 /* Staff power level 2 */
1403 target->momx += FixedMul(10*FRACUNIT, finecosine[ang]);
1404 target->momy += FixedMul(10*FRACUNIT, finesine[ang]);
1405 if(!(target->flags&MF_NOGRAVITY))
1406 {
1407 target->momz += 5*FRACUNIT;
1408 }
1409 }
1410 else
1411 {
1412 target->momx += FixedMul(thrust, finecosine[ang]);
1413 target->momy += FixedMul(thrust, finesine[ang]);
1414 }
1415 }
1416
1417 /*
1418 * player specific
1419 */
1420 if(player)
1421 {
1422 /*
1423 // end of game hell hack
1424 //if(target->subsector->sector->special == 11
1425 // && damage >= target->health)
1426 //{
1427 // damage = target->health - 1;
1428 //}
1429 */
1430
1431 if(damage < 1000 && ((player->cheats&CF_GODMODE)
1432 || player->powers[pw_invulnerability]))
1433 {
1434 return;
1435 }
1436 if(player->armortype)
1437 {
1438 if(player->armortype == 1)
1439 {
1440 saved = damage>>1;
1441 }
1442 else
1443 {
1444 saved = (damage>>1)+(damage>>2);
1445 }
1446 if(player->armorpoints <= saved)
1447 {
1448 /* armor is used up */
1449 saved = player->armorpoints;
1450 player->armortype = 0;
1451 }
1452 player->armorpoints -= saved;
1453 damage -= saved;
1454 }
1455 if(damage >= player->health
1456 && ((gameskill == sk_baby) || deathmatch)
1457 && !player->chickenTics)
1458 { /* Try to use some inventory health */
1459 P_AutoUseHealth(player, damage-player->health+1);
1460 }
1461 player->health -= damage; /* mirror mobj health here for Dave */
1462 if(player->health < 0)
1463 {
1464 player->health = 0;
1465 }
1466 player->attacker = source;
1467 player->damagecount += damage; /* add damage after armor / invuln */
1468 if(player->damagecount > 100)
1469 {
1470 player->damagecount = 100; /* teleport stomp does 10k points... */
1471 }
1472 temp = damage < 100 ? damage : 100;
1473 if(player == &players[consoleplayer])
1474 {
1475 /* MR ! */
1476 /* I_Tactile(40, 10, 40+temp*2); */
1477 SB_PaletteFlash();
1478 }
1479 }
1480
1481 /*
1482 * do the damage
1483 */
1484 target->health -= damage;
1485 if(target->health <= 0)
1486 { /* Death */
1487 target->special1 = damage;
1488 if(target->type == MT_POD && source && source->type != MT_POD)
1489 { /* Make sure players get frags for chain-reaction kills */
1490 target->target = source;
1491 }
1492 if(player && inflictor && !player->chickenTics)
1493 { /* Check for flame death */
1494 if((inflictor->flags2&MF2_FIREDAMAGE)
1495 || ((inflictor->type == MT_PHOENIXFX1)
1496 && (target->health > -50) && (damage > 25)))
1497 {
1498 target->flags2 |= MF2_FIREDAMAGE;
1499 }
1500 }
1501 P_KillMobj(source, target);
1502 return;
1503 }
1504 if((P_Random() < target->info->painchance)
1505 && !(target->flags&MF_SKULLFLY))
1506 {
1507 target->flags |= MF_JUSTHIT; /* fight back! */
1508 P_SetMobjState(target, target->info->painstate);
1509 }
1510 target->reactiontime = 0; /* we're awake now... */
1511 if(!target->threshold && source && !(source->flags2&MF2_BOSS)
1512 && !(target->type == MT_SORCERER2 && source->type == MT_WIZARD))
1513 {
1514 /*
1515 * Target actor is not intent on another actor,
1516 * so make him chase after source
1517 */
1518 target->target = source;
1519 target->threshold = BASETHRESHOLD;
1520 if(target->state == &states[target->info->spawnstate]
1521 && target->info->seestate != S_NULL)
1522 {
1523 P_SetMobjState(target, target->info->seestate);
1524 }
1525 }
1526 }
1527
1528
1529