1 /** @file p_inter.c
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2005-2013 Daniel Swanson <danij@dengine.net>
5  * @authors Copyright © 1999 Activision
6  *
7  * @par License
8  * GPL: http://www.gnu.org/licenses/gpl.html
9  *
10  * <small>This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version. This program is distributed in the hope that it
14  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details. You should have received a copy of the GNU
17  * General Public License along with this program; if not, write to the Free
18  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA</small>
20  */
21 
22 #include <string.h>
23 #include <math.h>
24 
25 #include "jhexen.h"
26 #include "p_inter.h"
27 
28 #include "d_netsv.h"
29 #include "g_common.h"
30 #include "hu_inventory.h"
31 #include "mobj.h"
32 #include "p_inventory.h"
33 #include "p_map.h"
34 #include "p_user.h"
35 #include "player.h"
36 
37 #define BONUSADD                (6)
38 
39 typedef enum {
40     IT_NONE = -1,
41     IT_HEALTH_VIAL,
42     IT_ARMOR_MESH,
43     IT_ARMOR_SHIELD,
44     IT_ARMOR_HELMET,
45     IT_ARMOR_AMULET,
46     IT_KEY_STEEL,
47     IT_KEY_CAVE,
48     IT_KEY_AXE,
49     IT_KEY_FIRE,
50     IT_KEY_EMERALD,
51     IT_KEY_DUNGEON,
52     IT_KEY_SILVER,
53     IT_KEY_RUSTED,
54     IT_KEY_HORN,
55     IT_KEY_SWAMP,
56     IT_KEY_CASTLE,
57     IT_ITEM_QUARTZFLASK,
58     IT_ITEM_WINGS,
59     IT_ITEM_DEFENDER,
60     IT_ITEM_SERVANT,
61     IT_ITEM_PORKALATOR,
62     IT_ITEM_MYSTICURN,
63     IT_ITEM_AMBITINCANT,
64     IT_ITEM_TORCH,
65     IT_ITEM_CHAOSDEVICE,
66     IT_ITEM_BANISHDEVICE,
67     IT_ITEM_FLETCHETTE,
68     IT_ITEM_BOOTSOFSPEED,
69     IT_ITEM_KRATEROFMIGHT,
70     IT_ITEM_BRACERS,
71     IT_ITEM_REPULSION,
72     IT_PUZZLE_SKULL,
73     IT_PUZZLE_BIGGEM,
74     IT_PUZZLE_REDGEM,
75     IT_PUZZLE_GREENGEM1,
76     IT_PUZZLE_GREENGEM2,
77     IT_PUZZLE_BLUEGEM1,
78     IT_PUZZLE_BLUEGEM2,
79     IT_PUZZLE_BOOK1,
80     IT_PUZZLE_BOOK2,
81     IT_PUZZLE_SKULL2,
82     IT_PUZZLE_FWEAPON,
83     IT_PUZZLE_CWEAPON,
84     IT_PUZZLE_MWEAPON,
85     IT_PUZZLE_GEAR1,
86     IT_PUZZLE_GEAR2,
87     IT_PUZZLE_GEAR3,
88     IT_PUZZLE_GEAR4,
89     IT_MANA_BLUE,
90     IT_MANA_GREEN,
91     IT_MANA_COMBINED,
92     IT_WEAPON_FROSTSHARDS,
93     IT_WEAPON_ARCOFDEATH,
94     IT_WEAPON_AXE,
95     IT_WEAPON_HAMMER,
96     IT_WEAPON_SERPENTSTAFF,
97     IT_WEAPON_FIRESTORM,
98     IT_WEAPON_QUIETUS1,
99     IT_WEAPON_QUIETUS2,
100     IT_WEAPON_QUIETUS3,
101     IT_WEAPON_WRAITHVERGE1,
102     IT_WEAPON_WRAITHVERGE2,
103     IT_WEAPON_WRAITHVERGE3,
104     IT_WEAPON_BLOODSCOURGE1,
105     IT_WEAPON_BLOODSCOURGE2,
106     IT_WEAPON_BLOODSCOURGE3
107 } itemtype_t;
108 
109 // Item Info Flags:
110 #define IIF_LEAVE_COOP          0x1 // Leave for others in Cooperative games.
111 #define IIF_LEAVE_DEATHMATCH    0x2 // Leave for others in Deathmatch games.
112 
113 typedef struct iteminfo_s {
114     itemtype_t          type;
115     short               flags; // IIF_* flags.
116     dd_bool            (*giveFunc) (player_t*);
117     textenum_t          pickupMsg;
118     sfxenum_t           pickupSound;
119 } iteminfo_t;
120 
121 static void setDormantItem(mobj_t* mo);
122 
123 static dd_bool pickupHealthVial(player_t* plr);
124 static dd_bool pickupMesh(player_t* plr);
125 static dd_bool pickupShield(player_t* plr);
126 static dd_bool pickupHelmet(player_t* plr);
127 static dd_bool pickupAmulet(player_t* plr);
128 static dd_bool pickupSteelKey(player_t* plr);
129 static dd_bool pickupCaveKey(player_t* plr);
130 static dd_bool pickupAxeKey(player_t* plr);
131 static dd_bool pickupFireKey(player_t* plr);
132 static dd_bool pickupEmeraldKey(player_t* plr);
133 static dd_bool pickupDungeonKey(player_t* plr);
134 static dd_bool pickupSilverKey(player_t* plr);
135 static dd_bool pickupRustedKey(player_t* plr);
136 static dd_bool pickupHornKey(player_t* plr);
137 static dd_bool pickupSwampKey(player_t* plr);
138 static dd_bool pickupCastleKey(player_t* plr);
139 static dd_bool pickupQuartzFlask(player_t* plr);
140 static dd_bool pickupWings(player_t* plr);
141 static dd_bool pickupDefender(player_t* plr);
142 static dd_bool pickupServant(player_t* plr);
143 static dd_bool pickupPorkalator(player_t* plr);
144 static dd_bool pickupMysticUrn(player_t* plr);
145 static dd_bool pickupAmbitIncant(player_t* plr);
146 static dd_bool pickupTorch(player_t* plr);
147 static dd_bool pickupChaosDevice(player_t* plr);
148 static dd_bool pickupBanishDevice(player_t* plr);
149 static dd_bool pickupFletchette(player_t* plr);
150 static dd_bool pickupBootsOfSpeed(player_t* plr);
151 static dd_bool pickupKraterOfMight(player_t* plr);
152 static dd_bool pickupBracers(player_t* plr);
153 static dd_bool pickupRepulsion(player_t* plr);
154 static dd_bool pickupSkull(player_t* plr);
155 static dd_bool pickupBigGem(player_t* plr);
156 static dd_bool pickupRedGem(player_t* plr);
157 static dd_bool pickupGreenGem1(player_t* plr);
158 static dd_bool pickupGreenGem2(player_t* plr);
159 static dd_bool pickupBlueGem1(player_t* plr);
160 static dd_bool pickupBlueGem2(player_t* plr);
161 static dd_bool pickupBook1(player_t* plr);
162 static dd_bool pickupBook2(player_t* plr);
163 static dd_bool pickupSkull2(player_t* plr);
164 static dd_bool pickupFWeapon(player_t* plr);
165 static dd_bool pickupCWeapon(player_t* plr);
166 static dd_bool pickupMWeapon(player_t* plr);
167 static dd_bool pickupGear1(player_t* plr);
168 static dd_bool pickupGear2(player_t* plr);
169 static dd_bool pickupGear3(player_t* plr);
170 static dd_bool pickupGear4(player_t* plr);
171 static dd_bool pickupBlueMana(player_t* plr);
172 static dd_bool pickupGreenMana(player_t* plr);
173 static dd_bool pickupCombinedMana(player_t* plr);
174 static dd_bool pickupFrostShards(player_t* plr);
175 static dd_bool pickupArcOfDeath(player_t* plr);
176 static dd_bool pickupAxe(player_t* plr);
177 static dd_bool pickupHammer(player_t* plr);
178 static dd_bool pickupSerpentStaff(player_t* plr);
179 static dd_bool pickupFireStorm(player_t* plr);
180 static dd_bool pickupQuietus1(player_t* plr);
181 static dd_bool pickupQuietus2(player_t* plr);
182 static dd_bool pickupQuietus3(player_t* plr);
183 static dd_bool pickupWraithVerge1(player_t* plr);
184 static dd_bool pickupWraithVerge2(player_t* plr);
185 static dd_bool pickupWraithVerge3(player_t* plr);
186 static dd_bool pickupBloodScourge1(player_t* plr);
187 static dd_bool pickupBloodScourge2(player_t* plr);
188 static dd_bool pickupBloodScourge3(player_t* plr);
189 
190 int TextKeyMessages[] = {
191     TXT_TXT_KEY_STEEL,
192     TXT_TXT_KEY_CAVE,
193     TXT_TXT_KEY_AXE,
194     TXT_TXT_KEY_FIRE,
195     TXT_TXT_KEY_EMERALD,
196     TXT_TXT_KEY_DUNGEON,
197     TXT_TXT_KEY_SILVER,
198     TXT_TXT_KEY_RUSTED,
199     TXT_TXT_KEY_HORN,
200     TXT_TXT_KEY_SWAMP,
201     TXT_TXT_KEY_CASTLE
202 };
203 
204 // Index using itemtype_t - 1;
205 static const iteminfo_t items[] = {
206     { IT_HEALTH_VIAL, 0, pickupHealthVial, TXT_TXT_ITEMHEALTH, SFX_PICKUP_PUZZ },
207     { IT_ARMOR_MESH, 0, pickupMesh, TXT_TXT_ARMOR1, SFX_PICKUP_PUZZ },
208     { IT_ARMOR_SHIELD, 0, pickupShield, TXT_TXT_ARMOR2, SFX_PICKUP_PUZZ },
209     { IT_ARMOR_HELMET, 0, pickupHelmet, TXT_TXT_ARMOR3, SFX_PICKUP_PUZZ },
210     { IT_ARMOR_AMULET, 0, pickupAmulet, TXT_TXT_ARMOR4, SFX_PICKUP_PUZZ },
211     { IT_KEY_STEEL, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupSteelKey, TXT_TXT_KEY_STEEL, SFX_PICKUP_KEY },
212     { IT_KEY_CAVE, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupCaveKey, TXT_TXT_KEY_CAVE, SFX_PICKUP_KEY },
213     { IT_KEY_AXE, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupAxeKey, TXT_TXT_KEY_AXE, SFX_PICKUP_KEY },
214     { IT_KEY_FIRE, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupFireKey, TXT_TXT_KEY_FIRE, SFX_PICKUP_KEY },
215     { IT_KEY_EMERALD, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupEmeraldKey, TXT_TXT_KEY_EMERALD, SFX_PICKUP_KEY },
216     { IT_KEY_DUNGEON, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupDungeonKey, TXT_TXT_KEY_DUNGEON, SFX_PICKUP_KEY },
217     { IT_KEY_SILVER, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupSilverKey, TXT_TXT_KEY_SILVER, SFX_PICKUP_KEY },
218     { IT_KEY_RUSTED, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupRustedKey, TXT_TXT_KEY_RUSTED, SFX_PICKUP_KEY },
219     { IT_KEY_HORN, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupHornKey, TXT_TXT_KEY_HORN, SFX_PICKUP_KEY },
220     { IT_KEY_SWAMP, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupSwampKey, TXT_TXT_KEY_SWAMP, SFX_PICKUP_KEY },
221     { IT_KEY_CASTLE, IIF_LEAVE_COOP | IIF_LEAVE_DEATHMATCH, pickupCastleKey, TXT_TXT_KEY_CASTLE, SFX_PICKUP_KEY },
222     { IT_ITEM_QUARTZFLASK, 0, pickupQuartzFlask, TXT_TXT_INV_HEALTH, SFX_PICKUP_ITEM },
223     { IT_ITEM_WINGS, 0, pickupWings, TXT_TXT_INV_FLY, SFX_PICKUP_ITEM },
224     { IT_ITEM_DEFENDER, 0, pickupDefender, TXT_TXT_INV_INVULNERABILITY, SFX_PICKUP_ITEM },
225     { IT_ITEM_SERVANT, 0, pickupServant, TXT_TXT_INV_SUMMON, SFX_PICKUP_ITEM },
226     { IT_ITEM_PORKALATOR, 0, pickupPorkalator, TXT_TXT_INV_EGG, SFX_PICKUP_ITEM },
227     { IT_ITEM_MYSTICURN, 0, pickupMysticUrn, TXT_TXT_INV_SUPERHEALTH, SFX_PICKUP_ITEM },
228     { IT_ITEM_AMBITINCANT, 0, pickupAmbitIncant, TXT_TXT_INV_HEALINGRADIUS, SFX_PICKUP_ITEM },
229     { IT_ITEM_TORCH, 0, pickupTorch, TXT_TXT_INV_TORCH, SFX_PICKUP_ITEM },
230     { IT_ITEM_CHAOSDEVICE, 0, pickupChaosDevice, TXT_TXT_INV_TELEPORT, SFX_PICKUP_ITEM },
231     { IT_ITEM_BANISHDEVICE, 0, pickupBanishDevice, TXT_TXT_INV_TELEPORTOTHER, SFX_PICKUP_ITEM },
232     { IT_ITEM_FLETCHETTE, 0, pickupFletchette, TXT_TXT_INV_POISONBAG, SFX_PICKUP_ITEM },
233     { IT_ITEM_BOOTSOFSPEED, 0, pickupBootsOfSpeed, TXT_TXT_INV_SPEED, SFX_PICKUP_ITEM },
234     { IT_ITEM_KRATEROFMIGHT, 0, pickupKraterOfMight, TXT_TXT_INV_BOOSTMANA, SFX_PICKUP_ITEM },
235     { IT_ITEM_BRACERS, 0, pickupBracers, TXT_TXT_INV_BOOSTARMOR, SFX_PICKUP_ITEM },
236     { IT_ITEM_REPULSION, 0, pickupRepulsion, TXT_TXT_INV_BLASTRADIUS, SFX_PICKUP_ITEM },
237     { IT_PUZZLE_SKULL, IIF_LEAVE_COOP, pickupSkull, TXT_TXT_INV_PUZZSKULL, SFX_PICKUP_PUZZ },
238     { IT_PUZZLE_BIGGEM, IIF_LEAVE_COOP, pickupBigGem, TXT_TXT_INV_PUZZGEMBIG, SFX_PICKUP_PUZZ },
239     { IT_PUZZLE_REDGEM, IIF_LEAVE_COOP, pickupRedGem, TXT_TXT_INV_PUZZGEMRED, SFX_PICKUP_PUZZ },
240     { IT_PUZZLE_GREENGEM1, IIF_LEAVE_COOP, pickupGreenGem1, TXT_TXT_INV_PUZZGEMGREEN1, SFX_PICKUP_PUZZ },
241     { IT_PUZZLE_GREENGEM2, IIF_LEAVE_COOP, pickupGreenGem2, TXT_TXT_INV_PUZZGEMGREEN2, SFX_PICKUP_PUZZ },
242     { IT_PUZZLE_BLUEGEM1, IIF_LEAVE_COOP, pickupBlueGem1, TXT_TXT_INV_PUZZGEMBLUE1, SFX_PICKUP_PUZZ },
243     { IT_PUZZLE_BLUEGEM2, IIF_LEAVE_COOP, pickupBlueGem2, TXT_TXT_INV_PUZZGEMBLUE2, SFX_PICKUP_PUZZ },
244     { IT_PUZZLE_BOOK1, IIF_LEAVE_COOP, pickupBook1, TXT_TXT_INV_PUZZBOOK1, SFX_PICKUP_PUZZ },
245     { IT_PUZZLE_BOOK2, IIF_LEAVE_COOP, pickupBook2, TXT_TXT_INV_PUZZBOOK2, SFX_PICKUP_PUZZ },
246     { IT_PUZZLE_SKULL2, IIF_LEAVE_COOP, pickupSkull2, TXT_TXT_INV_PUZZSKULL2, SFX_PICKUP_PUZZ },
247     { IT_PUZZLE_FWEAPON, IIF_LEAVE_COOP, pickupFWeapon, TXT_TXT_INV_PUZZFWEAPON, SFX_PICKUP_PUZZ },
248     { IT_PUZZLE_CWEAPON, IIF_LEAVE_COOP, pickupCWeapon, TXT_TXT_INV_PUZZCWEAPON, SFX_PICKUP_PUZZ },
249     { IT_PUZZLE_MWEAPON, IIF_LEAVE_COOP, pickupMWeapon, TXT_TXT_INV_PUZZMWEAPON, SFX_PICKUP_PUZZ },
250     { IT_PUZZLE_GEAR1, IIF_LEAVE_COOP, pickupGear1, TXT_TXT_INV_PUZZGEAR1, SFX_PICKUP_PUZZ },
251     { IT_PUZZLE_GEAR2, IIF_LEAVE_COOP, pickupGear2, TXT_TXT_INV_PUZZGEAR2, SFX_PICKUP_PUZZ },
252     { IT_PUZZLE_GEAR3, IIF_LEAVE_COOP, pickupGear3, TXT_TXT_INV_PUZZGEAR3, SFX_PICKUP_PUZZ },
253     { IT_PUZZLE_GEAR4, IIF_LEAVE_COOP, pickupGear4, TXT_TXT_INV_PUZZGEAR4, SFX_PICKUP_PUZZ },
254     { IT_MANA_BLUE, 0, pickupBlueMana, TXT_TXT_MANA_1, SFX_PICKUP_PUZZ },
255     { IT_MANA_GREEN, 0, pickupGreenMana, TXT_TXT_MANA_2, SFX_PICKUP_PUZZ },
256     { IT_MANA_COMBINED, 0, pickupCombinedMana, TXT_TXT_MANA_BOTH, SFX_PICKUP_PUZZ },
257     { IT_WEAPON_FROSTSHARDS, IIF_LEAVE_COOP, pickupFrostShards, TXT_TXT_WEAPON_M2, SFX_PICKUP_WEAPON },
258     { IT_WEAPON_ARCOFDEATH, IIF_LEAVE_COOP, pickupArcOfDeath, TXT_TXT_WEAPON_M3, SFX_PICKUP_WEAPON },
259     { IT_WEAPON_AXE, IIF_LEAVE_COOP, pickupAxe, TXT_TXT_WEAPON_F2, SFX_PICKUP_WEAPON },
260     { IT_WEAPON_HAMMER, IIF_LEAVE_COOP, pickupHammer, TXT_TXT_WEAPON_F3, SFX_PICKUP_WEAPON },
261     { IT_WEAPON_SERPENTSTAFF, IIF_LEAVE_COOP, pickupSerpentStaff, TXT_TXT_WEAPON_C2, SFX_PICKUP_WEAPON },
262     { IT_WEAPON_FIRESTORM, IIF_LEAVE_COOP, pickupFireStorm, TXT_TXT_WEAPON_C3, SFX_PICKUP_WEAPON },
263     { IT_WEAPON_QUIETUS1, IIF_LEAVE_COOP, pickupQuietus1, TXT_TXT_QUIETUS_PIECE, SFX_PICKUP_WEAPON },
264     { IT_WEAPON_QUIETUS2, IIF_LEAVE_COOP, pickupQuietus2, TXT_TXT_QUIETUS_PIECE, SFX_PICKUP_WEAPON },
265     { IT_WEAPON_QUIETUS3, IIF_LEAVE_COOP, pickupQuietus3, TXT_TXT_QUIETUS_PIECE, SFX_PICKUP_WEAPON },
266     { IT_WEAPON_WRAITHVERGE1, IIF_LEAVE_COOP, pickupWraithVerge1, TXT_TXT_WRAITHVERGE_PIECE, SFX_PICKUP_WEAPON },
267     { IT_WEAPON_WRAITHVERGE2, IIF_LEAVE_COOP, pickupWraithVerge2, TXT_TXT_WRAITHVERGE_PIECE, SFX_PICKUP_WEAPON },
268     { IT_WEAPON_WRAITHVERGE3, IIF_LEAVE_COOP, pickupWraithVerge3, TXT_TXT_WRAITHVERGE_PIECE, SFX_PICKUP_WEAPON },
269     { IT_WEAPON_BLOODSCOURGE1, IIF_LEAVE_COOP, pickupBloodScourge1, TXT_TXT_BLOODSCOURGE_PIECE, SFX_PICKUP_WEAPON },
270     { IT_WEAPON_BLOODSCOURGE2, IIF_LEAVE_COOP, pickupBloodScourge2, TXT_TXT_BLOODSCOURGE_PIECE, SFX_PICKUP_WEAPON },
271     { IT_WEAPON_BLOODSCOURGE3, IIF_LEAVE_COOP, pickupBloodScourge3, TXT_TXT_BLOODSCOURGE_PIECE, SFX_PICKUP_WEAPON }
272 };
273 
P_HideSpecialThing(mobj_t * thing)274 void P_HideSpecialThing(mobj_t *thing)
275 {
276     thing->flags &= ~MF_SPECIAL;
277     thing->flags2 |= MF2_DONTDRAW;
278     P_MobjChangeState(thing, S_HIDESPECIAL1);
279 }
280 
giveOneAmmo(player_t * plr,ammotype_t ammoType,int numRounds)281 static dd_bool giveOneAmmo(player_t *plr, ammotype_t ammoType, int numRounds)
282 {
283     int oldAmmo;
284 
285     DENG_ASSERT(plr != 0);
286     DENG_ASSERT(ammoType >= AT_FIRST && ammoType < NUM_AMMO_TYPES);
287 
288     // Giving the special 'unlimited ammo' type always succeeds.
289     if(ammoType == AT_NOAMMO)
290         return true;
291 
292     // Already fully stocked?
293     if(plr->ammo[ammoType].owned >= MAX_MANA)
294         return false;
295 
296     oldAmmo = plr->ammo[ammoType].owned;
297 
298     if(numRounds == 0)
299     {
300         return false;
301     }
302     else if(numRounds < 0)
303     {
304         // Fully replenish.
305         numRounds = MAX_MANA;
306     }
307 
308     // Give extra rounds at easy/nightmare skill levels.
309     if(gfw_Rule(skill) == SM_BABY ||
310        gfw_Rule(skill) == SM_NIGHTMARE)
311     {
312         numRounds += numRounds / 2;
313     }
314 
315     // Given the new ammo the player may want to change weapon automatically.
316     P_MaybeChangeWeapon(plr, WT_NOCHANGE, ammoType, false);
317 
318     // Restock the player.
319     plr->ammo[ammoType].owned = MIN_OF(MAX_MANA,
320                                        plr->ammo[ammoType].owned + numRounds);
321     plr->update |= PSF_AMMO;
322 
323     /// @todo fixme: This shouldn't be actioned from here.
324     if(plr->class_ == PCLASS_FIGHTER && plr->readyWeapon == WT_SECOND &&
325        ammoType == AT_BLUEMANA && oldAmmo <= 0)
326     {
327         P_SetPsprite(plr, ps_weapon, S_FAXEREADY_G);
328     }
329 
330     // Maybe unhide the HUD?
331     ST_HUDUnHide(plr - players, HUE_ON_PICKUP_AMMO);
332 
333     return true;
334 }
335 
P_GiveAmmo(player_t * plr,ammotype_t ammoType,int numRounds)336 dd_bool P_GiveAmmo(player_t *plr, ammotype_t ammoType, int numRounds)
337 {
338     int gaveAmmos = 0;
339 
340     if(ammoType == NUM_AMMO_TYPES)
341     {
342         // Give all ammos.
343         int i = 0;
344         for(i = 0; i < NUM_AMMO_TYPES; ++i)
345         {
346             gaveAmmos  |= (int)giveOneAmmo(plr, (ammotype_t) i, numRounds) << i;
347         }
348     }
349     else
350     {
351         // Give a single ammo.
352         gaveAmmos  |= (int)giveOneAmmo(plr, ammoType, numRounds) << (int)ammoType;
353     }
354 
355     return gaveAmmos  != 0;
356 }
357 
giveOneWeapon(player_t * plr,weapontype_t weaponType,playerclass_t matchClass)358 static dd_bool giveOneWeapon(player_t *plr, weapontype_t weaponType,
359                              playerclass_t matchClass)
360 {
361     ammotype_t ammoType = (weaponType == WT_SECOND)? AT_BLUEMANA : AT_GREENMANA;
362     dd_bool gaveWeapon = false, gaveAmmo = false;
363 
364     DENG_ASSERT(plr != 0);
365     DENG_ASSERT(weaponType >= WT_FIRST && weaponType < NUM_WEAPON_TYPES);
366 
367     if(plr->class_ != matchClass)
368     {
369         return P_GiveAmmo(plr, ammoType, 25);
370     }
371 
372     // Always attempt to give mana unless this a cooperative game and the
373     // player already has this weapon piece.
374     if(!(IS_NETGAME && !gfw_Rule(deathmatch) && plr->weapons[weaponType].owned))
375     {
376         if(P_GiveAmmo(plr, ammoType, 25))
377         {
378             gaveAmmo = true;
379         }
380     }
381 
382     if(!plr->weapons[weaponType].owned)
383     {
384         gaveWeapon = true;
385 
386         plr->weapons[weaponType].owned = true;
387         plr->update |= PSF_OWNED_WEAPONS;
388 
389         // Given the new weapon the player may want to change automatically.
390         P_MaybeChangeWeapon(plr, weaponType, AT_NOAMMO, false /*don't force*/);
391 
392         // Maybe unhide the HUD?
393         ST_HUDUnHide(plr - players, HUE_ON_PICKUP_WEAPON);
394     }
395 
396     return (gaveWeapon || gaveAmmo);
397 }
398 
P_GiveWeapon2(player_t * plr,weapontype_t weaponType,playerclass_t matchClass)399 dd_bool P_GiveWeapon2(player_t *plr, weapontype_t weaponType, playerclass_t matchClass)
400 {
401     int gaveWeapons = 0;
402 
403     if(weaponType == NUM_WEAPON_TYPES)
404     {
405         // Give all weapons.
406         int i = 0;
407         for(; i < NUM_WEAPON_TYPES; ++i)
408         {
409             gaveWeapons |= (int)giveOneWeapon(plr, (weapontype_t) i, matchClass) << i;
410         }
411     }
412     else
413     {
414         // Give a single weapon.
415         gaveWeapons |= (int)giveOneWeapon(plr, weaponType, matchClass) << (int)weaponType;
416     }
417 
418     // Leave placed weapons forever on net games.
419     if(IS_NETGAME && !gfw_Rule(deathmatch))
420         return false;
421 
422     return gaveWeapons != 0;
423 }
424 
P_GiveWeapon(player_t * plr,weapontype_t weaponType)425 dd_bool P_GiveWeapon(player_t *plr, weapontype_t weaponType)
426 {
427     DENG_ASSERT(plr != 0);
428     return P_GiveWeapon2(plr, weaponType, plr->class_);
429 }
430 
P_GiveWeaponPiece2(player_t * plr,int piece,playerclass_t matchClass)431 dd_bool P_GiveWeaponPiece2(player_t *plr, int piece, playerclass_t matchClass)
432 {
433     dd_bool gaveAmmo = false;
434 
435     // Give all pieces?
436     if(piece < 0 || piece >= WEAPON_FOURTH_PIECE_COUNT)
437     {
438         int gavePieces = 0;
439         int i = 0;
440         for(; i < WEAPON_FOURTH_PIECE_COUNT; ++i)
441         {
442             gavePieces |= (int)P_GiveWeaponPiece2(plr, i, matchClass);
443         }
444         return gavePieces != 0;
445     }
446 
447     if(plr->class_ != matchClass)
448     {
449         // Can't pick up wrong-class weapons in coop netplay.
450         if(IS_NETGAME && !gfw_Rule(deathmatch))
451             return false;
452 
453         return P_GiveAmmo(plr, AT_BLUEMANA, 20) | P_GiveAmmo(plr, AT_GREENMANA, 20);
454     }
455 
456     // Always attempt to give mana unless this a cooperative game and the
457     // player already has this weapon piece.
458     if(!((plr->pieces & (1 << piece)) && IS_NETGAME && !gfw_Rule(deathmatch)))
459     {
460         gaveAmmo = P_GiveAmmo(plr, AT_BLUEMANA, 20) | P_GiveAmmo(plr, AT_GREENMANA, 20);
461     }
462 
463     if(plr->pieces & (1 << piece))
464     {
465         // Already has the piece.
466         if(IS_NETGAME && !gfw_Rule(deathmatch)) // Cooperative net-game.
467             return false;
468 
469         // Deathmatch or single player.
470 
471         if(!gaveAmmo) // Didn't need the ammo so don't pick it up.
472             return false;
473     }
474 
475     // Give the specified weapon piece.
476     plr->pieces |= (1 << piece);
477 
478     // In a cooperative net-game, give the "lesser" pieces also.
479     if(IS_NETGAME && !gfw_Rule(deathmatch))
480     {
481         for(int i = 0; i < piece; ++i)
482         {
483             plr->pieces |= (1 << i);
484         }
485     }
486 
487     // Can we now assemble the fourth-weapon?
488     if(plr->pieces == WEAPON_FOURTH_COMPLETE)
489     {
490         // Bestow the fourth-weapon.
491         /// @todo Should use @ref P_GiveWeapon() here.
492         plr->weapons[WT_FOURTH].owned = true;
493         plr->pendingWeapon = WT_FOURTH;
494         plr->update       |= PSF_WEAPONS | PSF_OWNED_WEAPONS;
495 
496         // Should we change weapon automatically?
497         P_MaybeChangeWeapon(plr, WT_FOURTH, AT_NOAMMO, false);
498     }
499 
500     // Maybe unhide the HUD?
501     ST_HUDUnHide(plr - players, HUE_ON_PICKUP_WEAPON);
502 
503     return true;
504 }
505 
P_GiveWeaponPiece(player_t * plr,int pieceValue)506 dd_bool P_GiveWeaponPiece(player_t *plr, int pieceValue)
507 {
508     DENG_ASSERT(plr != 0);
509     return P_GiveWeaponPiece2(plr, pieceValue, plr->class_);
510 }
511 
maxPlayerHealth(dd_bool morphed)512 static int maxPlayerHealth(dd_bool morphed)
513 {
514     return morphed? MAXMORPHHEALTH : maxHealth;
515 }
516 
P_GiveHealth(player_t * player,int amount)517 dd_bool P_GiveHealth(player_t *player, int amount)
518 {
519     int healthLimit = maxPlayerHealth(player->morphTics != 0);
520 
521     // Already at capacity?
522     if(player->health >= healthLimit)
523         return false;
524 
525     if(amount < 0)
526     {
527         // Fully replenish.
528         amount = healthLimit;
529     }
530 
531     player->health =
532         player->plr->mo->health = MIN_OF(player->health + amount, healthLimit);
533     player->update |= PSF_HEALTH;
534 
535     // Maybe unhide the HUD?
536     ST_HUDUnHide(player - players, HUE_ON_PICKUP_HEALTH);
537 
538     return true;
539 }
540 
giveOneArmor(player_t * plr,armortype_t armorType)541 static dd_bool giveOneArmor(player_t *plr, armortype_t armorType)
542 {
543     int points;
544 
545     DENG_ASSERT(plr != 0);
546     DENG_ASSERT(armorType >= ARMOR_FIRST && armorType < NUMARMOR);
547 
548     points = PCLASS_INFO(plr->class_)->armorIncrement[armorType];
549     if(plr->armorPoints[armorType] >= points)
550         return false;
551 
552     P_PlayerGiveArmorBonus(plr, armorType, points - plr->armorPoints[armorType]);
553 
554     // Maybe unhide the HUD?
555     ST_HUDUnHide(plr - players, HUE_ON_PICKUP_ARMOR);
556 
557     return true;
558 }
559 
P_GiveArmor(player_t * plr,armortype_t armorType)560 dd_bool P_GiveArmor(player_t *plr, armortype_t armorType)
561 {
562     int gaveArmors = 0;
563 
564     if(armorType == NUMARMOR)
565     {
566         // Give all armors.
567         int i = 0;
568         for(i = 0; i < NUMARMOR; ++i)
569         {
570             gaveArmors |= (int)giveOneArmor(plr, (armortype_t) i) << i;
571         }
572     }
573     else
574     {
575         // Give a single armor.
576         gaveArmors |= (int)giveOneArmor(plr, armorType) << (int)armorType;
577     }
578 
579     return gaveArmors != 0;
580 }
581 
P_GiveArmorAlt(player_t * plr,armortype_t armorType,int amount)582 dd_bool P_GiveArmorAlt(player_t *plr, armortype_t armorType, int amount)
583 {
584     int hits, totalArmor;
585 
586     hits = amount * 5 * FRACUNIT;
587     totalArmor =
588         plr->armorPoints[ARMOR_ARMOR] +
589         plr->armorPoints[ARMOR_SHIELD] +
590         plr->armorPoints[ARMOR_HELMET] +
591         plr->armorPoints[ARMOR_AMULET] +
592         PCLASS_INFO(plr->class_)->autoArmorSave;
593 
594     if(totalArmor >= PCLASS_INFO(plr->class_)->maxArmor * 5 * FRACUNIT)
595     {
596         return false;
597     }
598 
599     plr->armorPoints[armorType] += hits;
600     plr->update |= PSF_ARMOR;
601 
602     // Maybe unhide the HUD?
603     ST_HUDUnHide(plr - players, HUE_ON_PICKUP_ARMOR);
604 
605     return true;
606 }
607 
giveOneKey(player_t * plr,keytype_t keyType)608 static dd_bool giveOneKey(player_t *plr, keytype_t keyType)
609 {
610     DENG_ASSERT(plr != 0);
611     DENG_ASSERT(keyType >= KT_FIRST && keyType < NUM_KEY_TYPES);
612 
613     // Already owned?
614     if(plr->keys & (1 << keyType)) return false;
615 
616     plr->keys |= 1 << keyType;
617     plr->bonusCount += BONUSADD;
618     plr->update |= PSF_KEYS;
619 
620     // Maybe unhide the HUD?
621     ST_HUDUnHide(plr - players, HUE_ON_PICKUP_KEY);
622 
623     return true;
624 }
625 
P_GiveKey(player_t * plr,keytype_t keyType)626 dd_bool P_GiveKey(player_t *plr, keytype_t keyType)
627 {
628     int gaveKeys = 0;
629 
630     if(keyType == NUM_KEY_TYPES)
631     {
632         // Give all keys.
633         int i = 0;
634         for(i = 0; i < NUM_KEY_TYPES; ++i)
635         {
636             gaveKeys |= (int)giveOneKey(plr, (keytype_t) i) << i;
637         }
638     }
639     else
640     {
641         // Give a single key.
642         gaveKeys |= (int)giveOneKey(plr, keyType) << (int)keyType;
643     }
644 
645     return gaveKeys != 0;
646 }
647 
P_GivePower(player_t * plr,powertype_t power)648 dd_bool P_GivePower(player_t *plr, powertype_t power)
649 {
650     dd_bool retval = false;
651 
652     plr->update |= PSF_POWERS;
653 
654     switch(power)
655     {
656     case PT_INVULNERABILITY:
657         if(!(plr->powers[power] > BLINKTHRESHOLD))
658         {
659             plr->powers[power] = INVULNTICS;
660             plr->plr->mo->flags2 |= MF2_INVULNERABLE;
661             if(plr->class_ == PCLASS_MAGE)
662             {
663                 plr->plr->mo->flags2 |= MF2_REFLECTIVE;
664             }
665             retval = true;
666         }
667         break;
668 
669     case PT_FLIGHT:
670         if(!(plr->powers[power] > BLINKTHRESHOLD))
671         {
672             plr->powers[power] = FLIGHTTICS;
673             plr->plr->mo->flags2 |= MF2_FLY;
674             plr->plr->mo->flags |= MF_NOGRAVITY;
675             if(plr->plr->mo->origin[VZ] <= plr->plr->mo->floorZ)
676             {
677                 plr->flyHeight = 10; // Thrust the plr in the air a bit.
678                 plr->plr->flags |= DDPF_FIXMOM;
679             }
680             retval = true;
681         }
682         break;
683 
684     case PT_INFRARED:
685         if(!(plr->powers[power] > BLINKTHRESHOLD))
686         {
687             plr->powers[power] = INFRATICS;
688             retval = true;
689         }
690         break;
691 
692     case PT_SPEED:
693         if(!(plr->powers[power] > BLINKTHRESHOLD))
694         {
695             plr->powers[power] = SPEEDTICS;
696             retval = true;
697         }
698         break;
699 
700     case PT_MINOTAUR:
701         // Doesn't matter if already have power, renew ticker.
702         plr->powers[power] = MAULATORTICS;
703         retval = true;
704         break;
705 
706     default:
707         if(!(plr->powers[power]))
708         {
709             plr->powers[power] = 1;
710             retval = true;
711         }
712         break;
713     }
714 
715     if(retval)
716     {
717         // Maybe unhide the HUD?
718         ST_HUDUnHide(plr - players, HUE_ON_PICKUP_POWER);
719     }
720 
721     return retval;
722 }
723 
P_GiveItem(player_t * plr,inventoryitemtype_t item)724 dd_bool P_GiveItem(player_t *plr, inventoryitemtype_t item)
725 {
726     if(plr)
727         return P_InventoryGive(plr - players, item, false);
728 
729     return false;
730 }
731 
732 /**
733  * Removes the MF_SPECIAL flag and initiates the item pickup animation.
734  */
setDormantItem(mobj_t * mo)735 static void setDormantItem(mobj_t *mo)
736 {
737     mo->flags &= ~MF_SPECIAL;
738     if(gfw_Rule(deathmatch) && !(mo->flags2 & MF2_DROPPED))
739     {
740         if(mo->type == MT_ARTIINVULNERABILITY)
741         {
742             P_MobjChangeState(mo, S_DORMANTARTI3_1);
743         }
744         else if(mo->type == MT_SUMMONMAULATOR || mo->type == MT_ARTIFLY)
745         {
746             P_MobjChangeState(mo, S_DORMANTARTI2_1);
747         }
748         else
749         {
750             P_MobjChangeState(mo, S_DORMANTARTI1_1);
751         }
752     }
753     else
754     {   // Don't respawn.
755         P_MobjChangeState(mo, S_DEADARTI1);
756     }
757 }
758 
A_RestoreArtifact(mobj_t * mo)759 void C_DECL A_RestoreArtifact(mobj_t* mo)
760 {
761     mo->flags |= MF_SPECIAL;
762     P_MobjChangeState(mo, P_GetState(mo->type, SN_SPAWN));
763     S_StartSound(SFX_RESPAWN, mo);
764 }
765 
766 /**
767  * Make a special thing visible again.
768  */
A_RestoreSpecialThing1(mobj_t * thing)769 void C_DECL A_RestoreSpecialThing1(mobj_t* thing)
770 {
771     thing->flags2 &= ~MF2_DONTDRAW;
772     S_StartSound(SFX_RESPAWN, thing);
773 }
774 
A_RestoreSpecialThing2(mobj_t * thing)775 void C_DECL A_RestoreSpecialThing2(mobj_t* thing)
776 {
777     thing->flags |= MF_SPECIAL;
778     P_MobjChangeState(thing, P_GetState(thing->type, SN_SPAWN));
779 }
780 
getItemTypeBySprite(spritetype_e sprite)781 static itemtype_t getItemTypeBySprite(spritetype_e sprite)
782 {
783     static const struct item_s {
784         itemtype_t      type;
785         spritetype_e    sprite;
786     } items[] = {
787         { IT_HEALTH_VIAL, SPR_PTN1 },
788         { IT_ARMOR_MESH, SPR_ARM1 },
789         { IT_ARMOR_SHIELD, SPR_ARM2 },
790         { IT_ARMOR_HELMET, SPR_ARM3 },
791         { IT_ARMOR_AMULET, SPR_ARM4 },
792         { IT_KEY_STEEL, SPR_KEY1 },
793         { IT_KEY_CAVE, SPR_KEY2 },
794         { IT_KEY_AXE, SPR_KEY3 },
795         { IT_KEY_FIRE, SPR_KEY4 },
796         { IT_KEY_EMERALD, SPR_KEY5 },
797         { IT_KEY_DUNGEON, SPR_KEY6 },
798         { IT_KEY_SILVER, SPR_KEY7 },
799         { IT_KEY_RUSTED, SPR_KEY8 },
800         { IT_KEY_HORN, SPR_KEY9 },
801         { IT_KEY_SWAMP, SPR_KEYA },
802         { IT_KEY_CASTLE, SPR_KEYB },
803         { IT_ITEM_QUARTZFLASK, SPR_PTN2 },
804         { IT_ITEM_WINGS, SPR_SOAR },
805         { IT_ITEM_DEFENDER, SPR_INVU },
806         { IT_ITEM_SERVANT, SPR_SUMN },
807         { IT_ITEM_PORKALATOR, SPR_PORK },
808         { IT_ITEM_MYSTICURN, SPR_SPHL },
809         { IT_ITEM_AMBITINCANT, SPR_HRAD },
810         { IT_ITEM_TORCH, SPR_TRCH },
811         { IT_ITEM_CHAOSDEVICE, SPR_ATLP },
812         { IT_ITEM_BANISHDEVICE, SPR_TELO },
813         { IT_ITEM_FLETCHETTE, SPR_PSBG },
814         { IT_ITEM_BOOTSOFSPEED, SPR_SPED },
815         { IT_ITEM_KRATEROFMIGHT, SPR_BMAN },
816         { IT_ITEM_BRACERS, SPR_BRAC },
817         { IT_ITEM_REPULSION, SPR_BLST },
818         { IT_PUZZLE_SKULL, SPR_ASKU },
819         { IT_PUZZLE_BIGGEM, SPR_ABGM },
820         { IT_PUZZLE_REDGEM, SPR_AGMR },
821         { IT_PUZZLE_GREENGEM1, SPR_AGMG },
822         { IT_PUZZLE_GREENGEM2, SPR_AGG2 },
823         { IT_PUZZLE_BLUEGEM1, SPR_AGMB },
824         { IT_PUZZLE_BLUEGEM2, SPR_AGB2 },
825         { IT_PUZZLE_BOOK1, SPR_ABK1 },
826         { IT_PUZZLE_BOOK2, SPR_ABK2 },
827         { IT_PUZZLE_SKULL2, SPR_ASK2 },
828         { IT_PUZZLE_FWEAPON, SPR_AFWP },
829         { IT_PUZZLE_CWEAPON, SPR_ACWP },
830         { IT_PUZZLE_MWEAPON, SPR_AMWP },
831         { IT_PUZZLE_GEAR1, SPR_AGER },
832         { IT_PUZZLE_GEAR2, SPR_AGR2 },
833         { IT_PUZZLE_GEAR3, SPR_AGR3 },
834         { IT_PUZZLE_GEAR4, SPR_AGR4 },
835         { IT_MANA_BLUE, SPR_MAN1 },
836         { IT_MANA_GREEN, SPR_MAN2 },
837         { IT_MANA_COMBINED, SPR_MAN3 },
838         { IT_WEAPON_FROSTSHARDS, SPR_WMCS },
839         { IT_WEAPON_ARCOFDEATH, SPR_WMLG },
840         { IT_WEAPON_AXE, SPR_WFAX },
841         { IT_WEAPON_HAMMER, SPR_WFHM },
842         { IT_WEAPON_SERPENTSTAFF, SPR_WCSS },
843         { IT_WEAPON_FIRESTORM, SPR_WCFM },
844         { IT_WEAPON_QUIETUS1, SPR_WFR1 },
845         { IT_WEAPON_QUIETUS2, SPR_WFR2 },
846         { IT_WEAPON_QUIETUS3, SPR_WFR3 },
847         { IT_WEAPON_WRAITHVERGE1, SPR_WCH1 },
848         { IT_WEAPON_WRAITHVERGE2, SPR_WCH2 },
849         { IT_WEAPON_WRAITHVERGE3, SPR_WCH3 },
850         { IT_WEAPON_BLOODSCOURGE1, SPR_WMS1 },
851         { IT_WEAPON_BLOODSCOURGE2, SPR_WMS2 },
852         { IT_WEAPON_BLOODSCOURGE3, SPR_WMS3 },
853         { IT_NONE, 0 }
854     };
855     uint                i;
856 
857     for(i = 0; items[i].type != IT_NONE; ++i)
858         if(items[i].sprite == sprite)
859             return items[i].type;
860 
861     return IT_NONE;
862 }
863 
pickupHealthVial(player_t * plr)864 static dd_bool pickupHealthVial(player_t *plr)
865 {
866     return P_GiveHealth(plr, 10);
867 }
868 
pickupMesh(player_t * plr)869 static dd_bool pickupMesh(player_t *plr)
870 {
871     return P_GiveArmor(plr, ARMOR_ARMOR);
872 }
873 
pickupShield(player_t * plr)874 static dd_bool pickupShield(player_t *plr)
875 {
876     return P_GiveArmor(plr, ARMOR_SHIELD);
877 }
878 
pickupHelmet(player_t * plr)879 static dd_bool pickupHelmet(player_t *plr)
880 {
881     return P_GiveArmor(plr, ARMOR_HELMET);
882 }
883 
pickupAmulet(player_t * plr)884 static dd_bool pickupAmulet(player_t *plr)
885 {
886     return P_GiveArmor(plr, ARMOR_AMULET);
887 }
888 
pickupSteelKey(player_t * plr)889 static dd_bool pickupSteelKey(player_t *plr)
890 {
891     return P_GiveKey(plr, KT_KEY1);
892 }
893 
pickupCaveKey(player_t * plr)894 static dd_bool pickupCaveKey(player_t *plr)
895 {
896     return P_GiveKey(plr, KT_KEY2);
897 }
898 
pickupAxeKey(player_t * plr)899 static dd_bool pickupAxeKey(player_t *plr)
900 {
901     return P_GiveKey(plr, KT_KEY3);
902 }
903 
pickupFireKey(player_t * plr)904 static dd_bool pickupFireKey(player_t *plr)
905 {
906     return P_GiveKey(plr, KT_KEY4);
907 }
908 
pickupEmeraldKey(player_t * plr)909 static dd_bool pickupEmeraldKey(player_t *plr)
910 {
911     return P_GiveKey(plr, KT_KEY5);
912 }
913 
pickupDungeonKey(player_t * plr)914 static dd_bool pickupDungeonKey(player_t *plr)
915 {
916     return P_GiveKey(plr, KT_KEY6);
917 }
918 
pickupSilverKey(player_t * plr)919 static dd_bool pickupSilverKey(player_t *plr)
920 {
921     return P_GiveKey(plr, KT_KEY7);
922 }
923 
pickupRustedKey(player_t * plr)924 static dd_bool pickupRustedKey(player_t *plr)
925 {
926     return P_GiveKey(plr, KT_KEY8);
927 }
928 
pickupHornKey(player_t * plr)929 static dd_bool pickupHornKey(player_t *plr)
930 {
931     return P_GiveKey(plr, KT_KEY9);
932 }
933 
pickupSwampKey(player_t * plr)934 static dd_bool pickupSwampKey(player_t *plr)
935 {
936     return P_GiveKey(plr, KT_KEYA);
937 }
938 
pickupCastleKey(player_t * plr)939 static dd_bool pickupCastleKey(player_t *plr)
940 {
941     return P_GiveKey(plr, KT_KEYB);
942 }
943 
pickupQuartzFlask(player_t * plr)944 static dd_bool pickupQuartzFlask(player_t *plr)
945 {
946     return P_GiveItem(plr, IIT_HEALTH);
947 }
948 
pickupWings(player_t * plr)949 static dd_bool pickupWings(player_t *plr)
950 {
951     return P_GiveItem(plr, IIT_FLY);
952 }
953 
pickupDefender(player_t * plr)954 static dd_bool pickupDefender(player_t *plr)
955 {
956     return P_GiveItem(plr, IIT_INVULNERABILITY);
957 }
958 
pickupServant(player_t * plr)959 static dd_bool pickupServant(player_t *plr)
960 {
961     return P_GiveItem(plr, IIT_SUMMON);
962 }
963 
pickupPorkalator(player_t * plr)964 static dd_bool pickupPorkalator(player_t *plr)
965 {
966     return P_GiveItem(plr, IIT_EGG);
967 }
968 
pickupMysticUrn(player_t * plr)969 static dd_bool pickupMysticUrn(player_t *plr)
970 {
971     return P_GiveItem(plr, IIT_SUPERHEALTH);
972 }
973 
pickupAmbitIncant(player_t * plr)974 static dd_bool pickupAmbitIncant(player_t *plr)
975 {
976     return P_GiveItem(plr, IIT_HEALINGRADIUS);
977 }
978 
pickupTorch(player_t * plr)979 static dd_bool pickupTorch(player_t *plr)
980 {
981     return P_GiveItem(plr, IIT_TORCH);
982 }
983 
pickupChaosDevice(player_t * plr)984 static dd_bool pickupChaosDevice(player_t *plr)
985 {
986     return P_GiveItem(plr, IIT_TELEPORT);
987 }
988 
pickupBanishDevice(player_t * plr)989 static dd_bool pickupBanishDevice(player_t *plr)
990 {
991     return P_GiveItem(plr, IIT_TELEPORTOTHER);
992 }
993 
pickupFletchette(player_t * plr)994 static dd_bool pickupFletchette(player_t *plr)
995 {
996     return P_GiveItem(plr, IIT_POISONBAG);
997 }
998 
pickupBootsOfSpeed(player_t * plr)999 static dd_bool pickupBootsOfSpeed(player_t *plr)
1000 {
1001     return P_GiveItem(plr, IIT_SPEED);
1002 }
1003 
pickupKraterOfMight(player_t * plr)1004 static dd_bool pickupKraterOfMight(player_t *plr)
1005 {
1006     return P_GiveItem(plr, IIT_BOOSTMANA);
1007 }
1008 
pickupBracers(player_t * plr)1009 static dd_bool pickupBracers(player_t *plr)
1010 {
1011     return P_GiveItem(plr, IIT_BOOSTARMOR);
1012 }
1013 
pickupRepulsion(player_t * plr)1014 static dd_bool pickupRepulsion(player_t *plr)
1015 {
1016     return P_GiveItem(plr, IIT_BLASTRADIUS);
1017 }
1018 
pickupSkull(player_t * plr)1019 static dd_bool pickupSkull(player_t *plr)
1020 {
1021     return P_GiveItem(plr, IIT_PUZZSKULL);
1022 }
1023 
pickupBigGem(player_t * plr)1024 static dd_bool pickupBigGem(player_t *plr)
1025 {
1026     return P_GiveItem(plr, IIT_PUZZGEMBIG);
1027 }
1028 
pickupRedGem(player_t * plr)1029 static dd_bool pickupRedGem(player_t *plr)
1030 {
1031     return P_GiveItem(plr, IIT_PUZZGEMRED);
1032 }
1033 
pickupGreenGem1(player_t * plr)1034 static dd_bool pickupGreenGem1(player_t *plr)
1035 {
1036     return P_GiveItem(plr, IIT_PUZZGEMGREEN1);
1037 }
1038 
pickupGreenGem2(player_t * plr)1039 static dd_bool pickupGreenGem2(player_t *plr)
1040 {
1041     return P_GiveItem(plr, IIT_PUZZGEMGREEN2);
1042 }
1043 
pickupBlueGem1(player_t * plr)1044 static dd_bool pickupBlueGem1(player_t *plr)
1045 {
1046     return P_GiveItem(plr, IIT_PUZZGEMBLUE1);
1047 }
1048 
pickupBlueGem2(player_t * plr)1049 static dd_bool pickupBlueGem2(player_t *plr)
1050 {
1051     return P_GiveItem(plr, IIT_PUZZGEMBLUE2);
1052 }
1053 
pickupBook1(player_t * plr)1054 static dd_bool pickupBook1(player_t *plr)
1055 {
1056     return P_GiveItem(plr, IIT_PUZZBOOK1);
1057 }
1058 
pickupBook2(player_t * plr)1059 static dd_bool pickupBook2(player_t *plr)
1060 {
1061     return P_GiveItem(plr, IIT_PUZZBOOK2);
1062 }
1063 
pickupSkull2(player_t * plr)1064 static dd_bool pickupSkull2(player_t *plr)
1065 {
1066     return P_GiveItem(plr, IIT_PUZZSKULL2);
1067 }
1068 
pickupFWeapon(player_t * plr)1069 static dd_bool pickupFWeapon(player_t *plr)
1070 {
1071     return P_GiveItem(plr, IIT_PUZZFWEAPON);
1072 }
1073 
pickupCWeapon(player_t * plr)1074 static dd_bool pickupCWeapon(player_t *plr)
1075 {
1076     return P_GiveItem(plr, IIT_PUZZCWEAPON);
1077 }
1078 
pickupMWeapon(player_t * plr)1079 static dd_bool pickupMWeapon(player_t *plr)
1080 {
1081     return P_GiveItem(plr, IIT_PUZZMWEAPON);
1082 }
1083 
pickupGear1(player_t * plr)1084 static dd_bool pickupGear1(player_t *plr)
1085 {
1086     return P_GiveItem(plr, IIT_PUZZGEAR1);
1087 }
1088 
pickupGear2(player_t * plr)1089 static dd_bool pickupGear2(player_t *plr)
1090 {
1091     return P_GiveItem(plr, IIT_PUZZGEAR2);
1092 }
1093 
pickupGear3(player_t * plr)1094 static dd_bool pickupGear3(player_t *plr)
1095 {
1096     return P_GiveItem(plr, IIT_PUZZGEAR3);
1097 }
1098 
pickupGear4(player_t * plr)1099 static dd_bool pickupGear4(player_t *plr)
1100 {
1101     return P_GiveItem(plr, IIT_PUZZGEAR4);
1102 }
1103 
pickupBlueMana(player_t * plr)1104 static dd_bool pickupBlueMana(player_t *plr)
1105 {
1106     return P_GiveAmmo(plr, AT_BLUEMANA, 15);
1107 }
1108 
pickupGreenMana(player_t * plr)1109 static dd_bool pickupGreenMana(player_t *plr)
1110 {
1111     return P_GiveAmmo(plr, AT_GREENMANA, 15);
1112 }
1113 
pickupCombinedMana(player_t * plr)1114 static dd_bool pickupCombinedMana(player_t *plr)
1115 {
1116     if(!P_GiveAmmo(plr, AT_BLUEMANA, 20))
1117     {
1118         if(!P_GiveAmmo(plr, AT_GREENMANA, 20))
1119             return false;
1120     }
1121     else
1122     {
1123         P_GiveAmmo(plr, AT_GREENMANA, 20);
1124     }
1125 
1126     return true;
1127 }
1128 
pickupWeapon(player_t * plr,weapontype_t weaponType,playerclass_t matchClass)1129 static dd_bool pickupWeapon(player_t *plr, weapontype_t weaponType,
1130                             playerclass_t matchClass)
1131 {
1132     DENG_ASSERT(plr != 0);
1133     DENG_ASSERT(weaponType >= WT_FIRST && weaponType < NUM_WEAPON_TYPES);
1134 
1135     // Depending on the game rules the player should ignore the weapon.
1136     if(plr->class_ != matchClass)
1137     {
1138         // Leave placed weapons forever on net games.
1139         if(IS_NETGAME && !gfw_Rule(deathmatch))
1140             return false;
1141     }
1142 
1143     // Attempt the pickup.
1144     return P_GiveWeapon2(plr, weaponType, matchClass);
1145 }
1146 
pickupFrostShards(player_t * plr)1147 static dd_bool pickupFrostShards(player_t *plr)
1148 {
1149     return pickupWeapon(plr, WT_SECOND, PCLASS_MAGE);
1150 }
1151 
pickupArcOfDeath(player_t * plr)1152 static dd_bool pickupArcOfDeath(player_t *plr)
1153 {
1154     return pickupWeapon(plr, WT_THIRD, PCLASS_MAGE);
1155 }
1156 
pickupAxe(player_t * plr)1157 static dd_bool pickupAxe(player_t *plr)
1158 {
1159     return pickupWeapon(plr, WT_SECOND, PCLASS_FIGHTER);
1160 }
1161 
pickupHammer(player_t * plr)1162 static dd_bool pickupHammer(player_t *plr)
1163 {
1164     return pickupWeapon(plr, WT_THIRD, PCLASS_FIGHTER);
1165 }
1166 
pickupSerpentStaff(player_t * plr)1167 static dd_bool pickupSerpentStaff(player_t *plr)
1168 {
1169     return pickupWeapon(plr, WT_SECOND, PCLASS_CLERIC);
1170 }
1171 
pickupFireStorm(player_t * plr)1172 static dd_bool pickupFireStorm(player_t *plr)
1173 {
1174     return pickupWeapon(plr, WT_THIRD, PCLASS_CLERIC);
1175 }
1176 
pickupQuietus1(player_t * plr)1177 static dd_bool pickupQuietus1(player_t *plr)
1178 {
1179     return P_GiveWeaponPiece2(plr, 0, PCLASS_FIGHTER);
1180 }
1181 
pickupQuietus2(player_t * plr)1182 static dd_bool pickupQuietus2(player_t *plr)
1183 {
1184     return P_GiveWeaponPiece2(plr, 1, PCLASS_FIGHTER);
1185 }
1186 
pickupQuietus3(player_t * plr)1187 static dd_bool pickupQuietus3(player_t *plr)
1188 {
1189     return P_GiveWeaponPiece2(plr, 2, PCLASS_FIGHTER);
1190 }
1191 
pickupWraithVerge1(player_t * plr)1192 static dd_bool pickupWraithVerge1(player_t *plr)
1193 {
1194     return P_GiveWeaponPiece2(plr, 0, PCLASS_CLERIC);
1195 }
1196 
pickupWraithVerge2(player_t * plr)1197 static dd_bool pickupWraithVerge2(player_t *plr)
1198 {
1199     return P_GiveWeaponPiece2(plr, 1, PCLASS_CLERIC);
1200 }
1201 
pickupWraithVerge3(player_t * plr)1202 static dd_bool pickupWraithVerge3(player_t *plr)
1203 {
1204     return P_GiveWeaponPiece2(plr, 2, PCLASS_CLERIC);
1205 }
1206 
pickupBloodScourge1(player_t * plr)1207 static dd_bool pickupBloodScourge1(player_t *plr)
1208 {
1209     return P_GiveWeaponPiece2(plr, 0, PCLASS_MAGE);
1210 }
1211 
pickupBloodScourge2(player_t * plr)1212 static dd_bool pickupBloodScourge2(player_t *plr)
1213 {
1214     return P_GiveWeaponPiece2(plr, 1, PCLASS_MAGE);
1215 }
1216 
pickupBloodScourge3(player_t * plr)1217 static dd_bool pickupBloodScourge3(player_t *plr)
1218 {
1219     return P_GiveWeaponPiece2(plr, 2, PCLASS_MAGE);
1220 }
1221 
giveItem(player_t * plr,itemtype_t item)1222 static dd_bool giveItem(player_t *plr, itemtype_t item)
1223 {
1224     iteminfo_t const *info = &items[item];
1225     int oldPieces = plr->pieces;
1226 
1227     if(!plr)
1228         return false;
1229 
1230     // Attempt to pickup the item.
1231     if(!info->giveFunc(plr))
1232         return false; // Did not make use of it.
1233 
1234     switch(item)
1235     {
1236     case IT_WEAPON_QUIETUS1:
1237     case IT_WEAPON_QUIETUS2:
1238     case IT_WEAPON_QUIETUS3:
1239     case IT_WEAPON_WRAITHVERGE1:
1240     case IT_WEAPON_WRAITHVERGE2:
1241     case IT_WEAPON_WRAITHVERGE3:
1242     case IT_WEAPON_BLOODSCOURGE1:
1243     case IT_WEAPON_BLOODSCOURGE2:
1244     case IT_WEAPON_BLOODSCOURGE3:
1245         if(plr->pieces != oldPieces &&
1246            plr->pieces == WEAPON_FOURTH_COMPLETE)
1247         {
1248             int msg;
1249 
1250             switch(item)
1251             {
1252             default:
1253                 Con_Error("Internal Error: Item type %i not handled in giveItem.", (int) item);
1254                 break; // Unreachable.
1255 
1256             case IT_WEAPON_QUIETUS1:
1257             case IT_WEAPON_QUIETUS2:
1258             case IT_WEAPON_QUIETUS3:
1259                 msg = TXT_TXT_WEAPON_F4;
1260                 break;
1261 
1262             case IT_WEAPON_WRAITHVERGE1:
1263             case IT_WEAPON_WRAITHVERGE2:
1264             case IT_WEAPON_WRAITHVERGE3:
1265                 msg = TXT_TXT_WEAPON_C4;
1266                 break;
1267 
1268             case IT_WEAPON_BLOODSCOURGE1:
1269             case IT_WEAPON_BLOODSCOURGE2:
1270             case IT_WEAPON_BLOODSCOURGE3:
1271                 msg = TXT_TXT_WEAPON_M4;
1272                 break;
1273             }
1274 
1275             P_SetMessage(plr, GET_TXT(msg));
1276             // Play the build-sound full volume for all players.
1277             S_StartSound(SFX_WEAPON_BUILD, NULL);
1278             break;
1279         }
1280         // Fall-through:
1281 
1282     default:
1283         S_StartSound(info->pickupSound, plr->plr->mo);
1284         P_SetMessage(plr, GET_TXT(info->pickupMsg));
1285         break;
1286     }
1287 
1288     return true;
1289 }
1290 
P_TouchSpecialMobj(mobj_t * special,mobj_t * toucher)1291 void P_TouchSpecialMobj(mobj_t* special, mobj_t* toucher)
1292 {
1293     player_t *player;
1294     coord_t delta;
1295     itemtype_t item;
1296     dd_bool wasUsed = false, removeItem = false;
1297 
1298     if(IS_CLIENT) return;
1299 
1300     delta = special->origin[VZ] - toucher->origin[VZ];
1301     if(delta > toucher->height || delta < -32)
1302     {
1303         // Out of reach.
1304         return;
1305     }
1306 
1307     // Dead thing touching (can happen with a sliding player corpse).
1308     if(toucher->health <= 0) return;
1309 
1310     player = toucher->player;
1311 
1312     // Identify by sprite.
1313     if((item = getItemTypeBySprite(special->sprite)) != IT_NONE)
1314     {
1315         iteminfo_t const *info = &items[item];
1316 
1317         if((wasUsed = giveItem(player, item)))
1318         {
1319             // Should we leave this item for others?
1320             if(!((info->flags & IIF_LEAVE_COOP) && IS_NETGAME && !gfw_Rule(deathmatch)) &&
1321                !((info->flags & IIF_LEAVE_DEATHMATCH) && IS_NETGAME && gfw_Rule(deathmatch)))
1322                 removeItem = true;
1323         }
1324     }
1325     else
1326     {
1327         App_Log(DE2_MAP_WARNING, "P_TouchSpecialMobj: Unknown gettable thing %i.",
1328                 (int) special->type);
1329     }
1330 
1331     if(wasUsed && special->special)
1332     {
1333         P_ExecuteLineSpecial(special->special, special->args, NULL, 0,
1334                              toucher);
1335         special->special = 0;
1336     }
1337 
1338     if(removeItem)
1339     {
1340         player->bonusCount += BONUSADD;
1341 
1342         /**
1343          * Taken items are handled differently depending upon the type of
1344          * item: inventory, puzzle or other.
1345          */
1346         switch(item)
1347         {
1348         // Inventory:
1349         case IT_ITEM_QUARTZFLASK:
1350         case IT_ITEM_WINGS:
1351         case IT_ITEM_DEFENDER:
1352         case IT_ITEM_SERVANT:
1353         case IT_ITEM_PORKALATOR:
1354         case IT_ITEM_MYSTICURN:
1355         case IT_ITEM_AMBITINCANT:
1356         case IT_ITEM_TORCH:
1357         case IT_ITEM_CHAOSDEVICE:
1358         case IT_ITEM_BANISHDEVICE:
1359         case IT_ITEM_FLETCHETTE:
1360         case IT_ITEM_BOOTSOFSPEED:
1361         case IT_ITEM_KRATEROFMIGHT:
1362         case IT_ITEM_BRACERS:
1363         case IT_ITEM_REPULSION:
1364             setDormantItem(special);
1365             break;
1366 
1367         // Puzzle items:
1368         case IT_PUZZLE_SKULL:
1369         case IT_PUZZLE_BIGGEM:
1370         case IT_PUZZLE_REDGEM:
1371         case IT_PUZZLE_GREENGEM1:
1372         case IT_PUZZLE_GREENGEM2:
1373         case IT_PUZZLE_BLUEGEM1:
1374         case IT_PUZZLE_BLUEGEM2:
1375         case IT_PUZZLE_BOOK1:
1376         case IT_PUZZLE_BOOK2:
1377         case IT_PUZZLE_SKULL2:
1378         case IT_PUZZLE_FWEAPON:
1379         case IT_PUZZLE_CWEAPON:
1380         case IT_PUZZLE_MWEAPON:
1381         case IT_PUZZLE_GEAR1:
1382         case IT_PUZZLE_GEAR2:
1383         case IT_PUZZLE_GEAR3:
1384         case IT_PUZZLE_GEAR4:
1385             P_MobjRemove(special, false);
1386             break;
1387 
1388         default:
1389             if(gfw_Rule(deathmatch) && !(special->flags2 & MF2_DROPPED))
1390                 P_HideSpecialThing(special);
1391             else
1392                 P_MobjRemove(special, false);
1393             break;
1394         }
1395     }
1396 }
1397 
1398 typedef struct {
1399     player_t* master;
1400     mobj_t* foundMobj;
1401 } findactiveminotaurparams_t;
1402 
findActiveMinotaur(thinker_t * th,void * context)1403 static int findActiveMinotaur(thinker_t* th, void* context)
1404 {
1405     findactiveminotaurparams_t* params =
1406         (findactiveminotaurparams_t*) context;
1407     mobj_t* mo = (mobj_t*) th;
1408 
1409     if(mo->type != MT_MINOTAUR)
1410         return false; // Continue iteration.
1411     if(mo->health <= 0)
1412         return false; // Continue iteration.
1413     if(!(mo->flags & MF_COUNTKILL)) // For morphed minotaurs.
1414         return false; // Continue iteration.
1415     if(mo->flags & MF_CORPSE)
1416         return false; // Continue iteration.
1417 
1418     if(mapTime - mo->argsUInt >= MAULATORTICS)
1419         return false; // Continue iteration.
1420 
1421     if(mo->tracer->player == params->master)
1422     {   // Found it!
1423         params->foundMobj = mo;
1424         return true; // Stop iteration.
1425     }
1426 
1427     return false; // Continue iteration.
1428 }
1429 
ActiveMinotaur(player_t * master)1430 mobj_t* ActiveMinotaur(player_t* master)
1431 {
1432     findactiveminotaurparams_t params;
1433 
1434     params.master = master;
1435     params.foundMobj = NULL;
1436 
1437     if(Thinker_Iterate(P_MobjThinker, findActiveMinotaur, &params))
1438         return params.foundMobj;
1439 
1440     return NULL;
1441 }
1442 
P_KillMobj(mobj_t * source,mobj_t * target)1443 void P_KillMobj(mobj_t *source, mobj_t *target)
1444 {
1445     statenum_t state;
1446 
1447     // Nothing to kill?
1448     if(!target) return;
1449 
1450     target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY);
1451     target->flags |= MF_CORPSE | MF_DROPOFF;
1452     target->flags2 &= ~MF2_PASSMOBJ;
1453     target->height /= 2 * 2;
1454 
1455     if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && target->special)
1456     {
1457         // Initiate monster death actions.
1458         if(target->type == MT_SORCBOSS)
1459         {
1460             P_StartACScript(target->special, NULL, target, NULL, 0);
1461         }
1462         else
1463         {
1464             P_ExecuteLineSpecial(target->special, target->args, NULL, 0, target);
1465         }
1466     }
1467 
1468     Mobj_RunScriptOnDeath(target, source);
1469 
1470     if(source && source->player)
1471     {
1472         // Check for frag changes.
1473         if(target->player && gfw_Rule(deathmatch))
1474         {
1475             if(target == source)
1476             {
1477                 // Self-frag.
1478                 target->player->frags[target->player - players]--;
1479                 NetSv_FragsForAll(target->player);
1480             }
1481             else
1482             {
1483                 source->player->frags[target->player - players]++;
1484                 NetSv_FragsForAll(source->player);
1485             }
1486         }
1487     }
1488 
1489     if(target->player)
1490     {
1491         // Player death.
1492         if(!source)
1493         {
1494             // Self-frag
1495             target->player->frags[target->player - players]--;
1496             NetSv_FragsForAll(target->player);
1497         }
1498 
1499         target->flags &= ~MF_SOLID;
1500         target->flags2 &= ~MF2_FLY;
1501         target->player->powers[PT_FLIGHT] = 0;
1502         target->player->playerState = PST_DEAD;
1503         target->player->rebornWait = PLAYER_REBORN_TICS;
1504         target->player->update |= PSF_STATE | PSF_POWERS;
1505 
1506         // Let the engine know about this, too. The DEAD flag will be
1507         // cleared when the player is reborn.
1508         target->player->plr->flags |= DDPF_DEAD;
1509         P_DropWeapon(target->player);
1510         if(target->flags2 & MF2_FIREDAMAGE)
1511         {
1512             // Player flame death.
1513             /// @todo Should be pulled from the player class definition.
1514             switch(target->player->class_)
1515             {
1516             case PCLASS_FIGHTER:
1517                 S_StartSound(SFX_PLAYER_FIGHTER_BURN_DEATH, target);
1518                 P_MobjChangeState(target, S_PLAY_F_FDTH1);
1519                 return;
1520 
1521             case PCLASS_CLERIC:
1522                 S_StartSound(SFX_PLAYER_CLERIC_BURN_DEATH, target);
1523                 P_MobjChangeState(target, S_PLAY_C_FDTH1);
1524                 return;
1525 
1526             case PCLASS_MAGE:
1527                 S_StartSound(SFX_PLAYER_MAGE_BURN_DEATH, target);
1528                 P_MobjChangeState(target, S_PLAY_M_FDTH1);
1529                 return;
1530 
1531             default:
1532                 break;
1533             }
1534         }
1535 
1536         if(target->flags2 & MF2_ICEDAMAGE)
1537         {
1538             // Player ice death.
1539             target->flags &= ~MF_TRANSLATION; // no translation
1540             target->flags |= MF_ICECORPSE;
1541             /// @todo Should be pulled from the player class definition.
1542             switch(target->player->class_)
1543             {
1544             case PCLASS_FIGHTER:
1545                 P_MobjChangeState(target, S_FPLAY_ICE);
1546                 return;
1547 
1548             case PCLASS_CLERIC:
1549                 P_MobjChangeState(target, S_CPLAY_ICE);
1550                 return;
1551 
1552             case PCLASS_MAGE:
1553                 P_MobjChangeState(target, S_MPLAY_ICE);
1554                 return;
1555 
1556             case PCLASS_PIG:
1557                 P_MobjChangeState(target, S_PIG_ICE);
1558                 return;
1559 
1560             default:
1561                 break;
1562             }
1563         }
1564 
1565         // Don't die with the automap open.
1566         ST_CloseAll(target->player - players, false);
1567     }
1568     else
1569     {   // Target is some monster or an object.
1570 
1571         /**
1572          * mobj death, record as player's kill in netgame + coop could not
1573          * find MF_ targets->flags that indicated *only* enemies (not trees,
1574          * pots, etc), so built a list.
1575          *
1576          * @todo This should be a Thing definition flag.
1577          */
1578         if(IS_NETGAME && !gfw_Rule(deathmatch) && source && source->player &&
1579            source->player->plr && (target->type == MT_CENTAUR ||
1580                                    target->type == MT_CENTAURLEADER ||
1581                                    target->type == MT_DEMON ||
1582                                    target->type == MT_DEMON2 ||
1583                                    target->type == MT_ETTIN ||
1584                                    target->type == MT_PIG ||
1585                                    target->type == MT_FIREDEMON ||
1586                                    target->type == MT_SERPENT ||
1587                                    target->type == MT_SERPENTLEADER ||
1588                                    target->type == MT_WRAITH ||
1589                                    target->type == MT_WRAITHB ||
1590                                    target->type == MT_BISHOP ||
1591                                    target->type == MT_ICEGUY ||
1592                                    target->type == MT_FIGHTER_BOSS ||
1593                                    target->type == MT_CLERIC_BOSS ||
1594                                    target->type == MT_MAGE_BOSS ||
1595                                    target->type == MT_MINOTAUR))
1596         {
1597             source->player->frags[0]++;
1598         }
1599     }
1600 
1601     if(target->flags2 & MF2_FIREDAMAGE)
1602     {
1603         if(target->type == MT_FIGHTER_BOSS || target->type == MT_CLERIC_BOSS ||
1604            target->type == MT_MAGE_BOSS)
1605         {
1606             switch(target->type)
1607             {
1608             case MT_FIGHTER_BOSS:
1609                 S_StartSound(SFX_PLAYER_FIGHTER_BURN_DEATH, target);
1610                 P_MobjChangeState(target, S_PLAY_F_FDTH1);
1611                 return;
1612 
1613             case MT_CLERIC_BOSS:
1614                 S_StartSound(SFX_PLAYER_CLERIC_BURN_DEATH, target);
1615                 P_MobjChangeState(target, S_PLAY_C_FDTH1);
1616                 return;
1617 
1618             case MT_MAGE_BOSS:
1619                 S_StartSound(SFX_PLAYER_MAGE_BURN_DEATH, target);
1620                 P_MobjChangeState(target, S_PLAY_M_FDTH1);
1621                 return;
1622 
1623             default:
1624                 break;
1625             }
1626         }
1627         else if(target->type == MT_TREEDESTRUCTIBLE)
1628         {
1629             P_MobjChangeState(target, S_ZTREEDES_X1);
1630             target->height = 24;
1631             S_StartSound(SFX_TREE_EXPLODE, target);
1632             return;
1633         }
1634     }
1635 
1636     if(target->flags2 & MF2_ICEDAMAGE)
1637     {
1638         target->flags |= MF_ICECORPSE;
1639         switch(target->type)
1640         {
1641         case MT_BISHOP:
1642             P_MobjChangeState(target, S_BISHOP_ICE);
1643             return;
1644 
1645         case MT_CENTAUR:
1646         case MT_CENTAURLEADER:
1647             P_MobjChangeState(target, S_CENTAUR_ICE);
1648             return;
1649 
1650         case MT_DEMON:
1651         case MT_DEMON2:
1652             P_MobjChangeState(target, S_DEMON_ICE);
1653             return;
1654 
1655         case MT_SERPENT:
1656         case MT_SERPENTLEADER:
1657             P_MobjChangeState(target, S_SERPENT_ICE);
1658             return;
1659 
1660         case MT_WRAITH:
1661         case MT_WRAITHB:
1662             P_MobjChangeState(target, S_WRAITH_ICE);
1663             return;
1664 
1665         case MT_ETTIN:
1666             P_MobjChangeState(target, S_ETTIN_ICE1);
1667             return;
1668 
1669         case MT_FIREDEMON:
1670             P_MobjChangeState(target, S_FIRED_ICE1);
1671             return;
1672 
1673         case MT_FIGHTER_BOSS:
1674             P_MobjChangeState(target, S_FIGHTER_ICE);
1675             return;
1676 
1677         case MT_CLERIC_BOSS:
1678             P_MobjChangeState(target, S_CLERIC_ICE);
1679             return;
1680 
1681         case MT_MAGE_BOSS:
1682             P_MobjChangeState(target, S_MAGE_ICE);
1683             return;
1684 
1685         case MT_PIG:
1686             P_MobjChangeState(target, S_PIG_ICE);
1687             return;
1688 
1689         default:
1690             target->flags &= ~MF_ICECORPSE;
1691             break;
1692         }
1693     }
1694 
1695     if(target->type == MT_MINOTAUR)
1696     {
1697         mobj_t *master = target->tracer;
1698         if(master && master->health > 0)
1699         {
1700             if(!ActiveMinotaur(master->player))
1701             {
1702                 master->player->powers[PT_MINOTAUR] = 0;
1703             }
1704         }
1705     }
1706     else if(target->type == MT_TREEDESTRUCTIBLE)
1707     {
1708         target->height = 24;
1709     }
1710 
1711     if((state = P_GetState(target->type, SN_XDEATH)) != S_NULL &&
1712        target->health < -(target->info->spawnHealth / 2))
1713     {
1714         // Extreme death.
1715         P_MobjChangeState(target, state);
1716     }
1717     else
1718     {
1719         // Normal death.
1720         if((state = P_GetState(target->type, SN_XDEATH)) != S_NULL &&
1721            target->type == MT_FIREDEMON &&
1722            target->origin[VZ] <= target->floorZ + 2)
1723         {
1724             // This is to fix the imps' staying in fall state.
1725             P_MobjChangeState(target, state);
1726         }
1727         else
1728         {
1729             P_MobjChangeState(target, P_GetState(target->type, SN_DEATH));
1730         }
1731     }
1732 
1733     target->tics -= P_Random() & 3;
1734 }
1735 
1736 /**
1737  * @return              @c true, if the player gets turned into a pig.
1738  */
P_MorphPlayer(player_t * player)1739 dd_bool P_MorphPlayer(player_t* player)
1740 {
1741     mobj_t* pmo, *fog, *beastMo;
1742     coord_t pos[3];
1743     angle_t angle;
1744     int oldFlags2;
1745 
1746     if(player->powers[PT_INVULNERABILITY])
1747         return false; // Immune when invulnerable.
1748 
1749     if(player->morphTics)
1750         return false; // Player is already morphed.
1751 
1752     pmo = player->plr->mo;
1753 
1754     pos[VX] = pmo->origin[VX];
1755     pos[VY] = pmo->origin[VY];
1756     pos[VZ] = pmo->origin[VZ];
1757     angle = pmo->angle;
1758     oldFlags2 = pmo->flags2;
1759 
1760     if(!(beastMo = P_SpawnMobj(MT_PIGPLAYER, pos, angle, 0)))
1761         return false;
1762 
1763     P_MobjChangeState(pmo, S_FREETARGMOBJ);
1764 
1765     if((fog = P_SpawnMobjXYZ(MT_TFOG, pos[VX], pos[VY],
1766                             pos[VZ] + TELEFOGHEIGHT, angle + ANG180, 0)))
1767         S_StartSound(SFX_TELEPORT, fog);
1768 
1769     beastMo->special1 = player->readyWeapon;
1770     beastMo->player = player;
1771     beastMo->dPlayer = player->plr;
1772 
1773     player->health = beastMo->health = MAXMORPHHEALTH;
1774     player->plr->mo = beastMo;
1775     memset(&player->armorPoints[0], 0, NUMARMOR * sizeof(int));
1776     player->class_ = PCLASS_PIG;
1777 
1778     if(oldFlags2 & MF2_FLY)
1779         beastMo->flags2 |= MF2_FLY;
1780 
1781     player->morphTics = MORPHTICS;
1782     player->update |= PSF_MORPH_TIME | PSF_HEALTH;
1783     player->plr->flags |= DDPF_FIXORIGIN | DDPF_FIXMOM;
1784     P_ActivateMorphWeapon(player);
1785     return true;
1786 }
1787 
P_MorphMonster(mobj_t * actor)1788 dd_bool P_MorphMonster(mobj_t *actor)
1789 {
1790     mobj_t *   master, *monster, *fog;
1791     mobjtype_t moType;
1792     coord_t    pos[3];
1793     mobj_t     oldMonster;
1794     angle_t    oldAngle;
1795 
1796     if (actor->player) return (false);
1797     if (!(actor->flags & MF_COUNTKILL)) return false;
1798     if (actor->flags2 & MF2_BOSS) return false;
1799 
1800     // Originally hardcoded to specific mobj types.
1801     if (actor->flags3 & MF3_NOMORPH) return false;
1802 
1803     moType = actor->type;
1804 
1805     /// @todo Do this properly!
1806     oldMonster = *actor;
1807 
1808     pos[VX]  = actor->origin[VX];
1809     pos[VY]  = actor->origin[VY];
1810     pos[VZ]  = actor->origin[VZ];
1811     oldAngle = actor->angle;
1812 
1813     if (!(monster = P_SpawnMobj(MT_PIG, pos, oldMonster.angle, 0))) return false;
1814 
1815     P_MobjRemoveFromTIDList(actor);
1816     P_MobjChangeState(actor, S_FREETARGMOBJ);
1817 
1818     if ((fog = P_SpawnMobjXYZ(
1819              MT_TFOG, pos[VX], pos[VY], pos[VZ] + TELEFOGHEIGHT, oldAngle + ANG180, 0)))
1820         S_StartSound(SFX_TELEPORT, fog);
1821 
1822     monster->special2 = moType;
1823     monster->special1 = MORPHTICS + P_Random();
1824     monster->flags |= (oldMonster.flags & MF_SHADOW);
1825     monster->target  = oldMonster.target;
1826     monster->tid     = oldMonster.tid;
1827     monster->special = oldMonster.special;
1828     P_MobjInsertIntoTIDList(monster, oldMonster.tid);
1829     memcpy(monster->args, oldMonster.args, 5);
1830 
1831     // Check for turning off minotaur power for active icon.
1832     if (moType == MT_MINOTAUR)
1833     {
1834         master = oldMonster.tracer;
1835         if (master && master->health > 0)
1836         {
1837             if (!ActiveMinotaur(master->player))
1838             {
1839                 master->player->powers[PT_MINOTAUR] = 0;
1840             }
1841         }
1842     }
1843 
1844     return true;
1845 }
1846 
P_AutoUseHealth(player_t * player,int saveHealth)1847 void P_AutoUseHealth(player_t* player, int saveHealth)
1848 {
1849     uint i, count;
1850     int plrnum = player - players;
1851     int normalCount = P_InventoryCount(plrnum, IIT_HEALTH);
1852     int superCount = P_InventoryCount(plrnum, IIT_SUPERHEALTH);
1853 
1854     if(!player->plr->mo) return;
1855 
1856     /// @todo Do this in the inventory code?
1857     if(gfw_Rule(skill) == SM_BABY && normalCount * 25 >= saveHealth)
1858     {
1859         // Use quartz flasks.
1860         count = (saveHealth + 24) / 25;
1861         for(i = 0; i < count; ++i)
1862         {
1863             player->health += 25;
1864             P_InventoryTake(plrnum, IIT_HEALTH, false);
1865         }
1866     }
1867     else if(superCount * 100 >= saveHealth)
1868     {
1869         // Use mystic urns.
1870         count = (saveHealth + 99) / 100;
1871         for(i = 0; i < count; ++i)
1872         {
1873             player->health += 100;
1874             P_InventoryTake(plrnum, IIT_SUPERHEALTH, false);
1875         }
1876     }
1877     else if(gfw_Rule(skill) == SM_BABY &&
1878             superCount * 100 + normalCount * 25 >= saveHealth)
1879     {
1880         // Use mystic urns and quartz flasks.
1881         count = (saveHealth + 24) / 25;
1882         saveHealth -= count * 25;
1883         for(i = 0; i < count; ++i)
1884         {
1885             player->health += 25;
1886             P_InventoryTake(plrnum, IIT_HEALTH, false);
1887         }
1888 
1889         count = (saveHealth + 99) / 100;
1890         for(i = 0; i < count; ++i)
1891         {
1892             player->health += 100;
1893             P_InventoryTake(plrnum, IIT_SUPERHEALTH, false);
1894         }
1895     }
1896 
1897     player->plr->mo->health = player->health;
1898 }
1899 
1900 /**
1901  * Sets up all data concerning poisoning.
1902  */
P_PoisonPlayer(player_t * player,mobj_t * poisoner,int poison)1903 void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison)
1904 {
1905     if((P_GetPlayerCheats(player) & CF_GODMODE) ||
1906        player->powers[PT_INVULNERABILITY])
1907         return;
1908 
1909     player->poisonCount += poison;
1910     player->poisoner = poisoner;
1911 
1912     if(player->poisonCount > 100)
1913         player->poisonCount = 100;
1914 }
1915 
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damageP,dd_bool stomping)1916 int P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source,
1917                  int damageP, dd_bool stomping)
1918 {
1919     return P_DamageMobj2(target, inflictor, source, damageP, stomping, false);
1920 }
1921 
1922 /**
1923  * Damages both enemies and players
1924  * @note 'source' and 'inflictor' are the same for melee attacks.
1925  * 'source' can be NULL for slime, barrel explosions and other environmental
1926  * stuff.
1927  *
1928  * @param inflictor         Is the mobj that caused the damage, creature or
1929  *                          missile, can be @c NULL (slime, etc).
1930  * @param source            Is the mobj to target after taking damage
1931  *                          creature or @c NULL.
1932  */
P_DamageMobj2(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damageP,dd_bool stomping,dd_bool skipNetworkCheck)1933 int P_DamageMobj2(mobj_t *target, mobj_t *inflictor, mobj_t *source, int damageP,
1934     dd_bool stomping, dd_bool skipNetworkCheck)
1935 {
1936     uint an;
1937     angle_t angle;
1938     int i, /*temp,*/ originalHealth;
1939     coord_t thrust;
1940     float saved, savedPercent;
1941     player_t *player;
1942     mobj_t *master;
1943     int damage;
1944 
1945     if(!target) return 0; // Wha?
1946 
1947     originalHealth = target->health;
1948 
1949     // The actual damage (== damageP * netMobDamageModifier for any
1950     // non-player mobj).
1951     damage = damageP;
1952 
1953     if(!skipNetworkCheck)
1954     {
1955         if(IS_NETGAME && !stomping && D_NetDamageMobj(target, inflictor, source, damage))
1956         {   // We're done here.
1957             return 0;
1958         }
1959         // Clients can't harm anybody.
1960         if(IS_CLIENT)
1961             return 0;
1962     }
1963 
1964     if(!(target->flags & MF_SHOOTABLE))
1965         return 0; // Shouldn't happen.
1966 
1967     if(target->health <= 0)
1968     {
1969         if(!(inflictor && (inflictor->flags2 & MF2_ICEDAMAGE)) &&
1970            (target->flags & MF_ICECORPSE))
1971         {   // Frozen.
1972             target->tics = 1;
1973             target->mom[MX] = target->mom[MY] = 0;
1974         }
1975 
1976         return 0;
1977     }
1978 
1979     if((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
1980     {   // mobj is invulnerable.
1981         if(target->player)
1982             return 0; // for player, no exceptions.
1983 
1984         if(!inflictor)
1985             return 0;
1986 
1987         switch(inflictor->type)
1988         {
1989         // These inflictors aren't foiled by invulnerability.
1990         case MT_HOLY_FX:
1991         case MT_POISONCLOUD:
1992         case MT_FIREBOMB:
1993             break;
1994 
1995         default:
1996             return 0;
1997         }
1998     }
1999 
2000     if(target->player) // Player specific.
2001     {
2002         if(damage < 1000 &&
2003            ((P_GetPlayerCheats(target->player) & CF_GODMODE) ||
2004             target->player->powers[PT_INVULNERABILITY]))
2005         {
2006             return 0;
2007         }
2008 
2009         // Check if player-player damage is disabled.
2010         if(source && source->player && source->player != target->player)
2011         {
2012 #if 0
2013             // Co-op damage disabled?
2014             if(IS_NETGAME && !deathmatch && cfg.noCoopDamage)
2015                 return 0;
2016 
2017             // Same color, no damage?
2018             if(cfg.noTeamDamage &&
2019                cfg.playerColor[target->player - players] ==
2020                cfg.playerColor[source->player - players])
2021                 return 0;
2022 #endif
2023         }
2024     }
2025 
2026     if(target->flags & MF_SKULLFLY)
2027     {
2028         target->mom[MX] = target->mom[MY] = target->mom[MZ] = 0;
2029     }
2030 
2031     if(target->flags2 & MF2_DORMANT)
2032         return 0; // Invulnerable, and won't wake up.
2033 
2034     player = target->player;
2035     if(player && gfw_Rule(skill) == SM_BABY)
2036         damage /= 2; // Take half damage in trainer mode.
2037 
2038     // Use the cvar damage multiplier netMobDamageModifier only if the
2039     // inflictor is not a player.
2040     if(inflictor && !inflictor->player &&
2041        (!source || (source && !source->player)))
2042     {
2043         // damage = (int) ((float) damage * netMobDamageModifier);
2044         if(IS_NETGAME)
2045             damage *= cfg.common.netMobDamageModifier;
2046     }
2047 
2048     // Special damage types.
2049     if(inflictor)
2050     {
2051         switch(inflictor->type)
2052         {
2053         case MT_EGGFX:
2054             if(player)
2055             {
2056                 P_MorphPlayer(player);
2057             }
2058             else
2059             {
2060                 P_MorphMonster(target);
2061             }
2062             return 0; // Does no actual "damage" but health IS modified.
2063 
2064         case MT_TELOTHER_FX1:
2065         case MT_TELOTHER_FX2:
2066         case MT_TELOTHER_FX3:
2067         case MT_TELOTHER_FX4:
2068         case MT_TELOTHER_FX5:
2069             if((target->flags & MF_COUNTKILL) && (target->type != MT_SERPENT)
2070                && (target->type != MT_SERPENTLEADER) &&
2071                (!(target->flags2 & MF2_BOSS)))
2072             {
2073                 if(target->player)
2074                 {
2075                     if(gfw_Rule(deathmatch))
2076                         P_TeleportToDeathmatchStarts(target);
2077                     else
2078                         P_TeleportToPlayerStarts(target);
2079                 }
2080                 else
2081                 {
2082                     // If death action, run it upon teleport.
2083                     if(target->flags & MF_COUNTKILL && target->special)
2084                     {
2085                         P_MobjRemoveFromTIDList(target);
2086                         P_ExecuteLineSpecial(target->special, target->args, NULL, 0,
2087                                              target);
2088                         target->special = 0;
2089                     }
2090 
2091                     // Send all monsters to deathmatch spots.
2092                     P_TeleportToDeathmatchStarts(target);
2093                 }
2094             }
2095             return 0;
2096 
2097         case MT_MINOTAUR:
2098             if(inflictor->flags & MF_SKULLFLY)
2099             {
2100                 // Slam only when in charge mode.
2101                 uint an;
2102                 int damageDone;
2103                 angle_t angle;
2104                 coord_t thrust;
2105 
2106                 angle = M_PointToAngle2(inflictor->origin, target->origin);
2107 
2108                 an = angle >> ANGLETOFINESHIFT;
2109                 thrust = 16 + FIX2FLT(P_Random() << 10);
2110                 target->mom[MX] += thrust * FIX2FLT(finecosine[an]);
2111                 target->mom[MY] += thrust * FIX2FLT(finesine[an]);
2112                 damageDone = P_DamageMobj(target, NULL, inflictor, HITDICE(4), false);
2113                 if(target->player)
2114                 {
2115                     target->reactionTime = 14 + (P_Random() & 7);
2116                 }
2117 
2118                 inflictor->args[0] = 0; // Stop charging.
2119                 return damageDone;
2120             }
2121             break;
2122 
2123         case MT_BISH_FX:
2124             // Bishops are just too nasty.
2125             damage /= 2;
2126             break;
2127 
2128         case MT_SHARDFX1:
2129             switch(inflictor->special2)
2130             {
2131             case 3:
2132                 damage *= 8;
2133                 break;
2134 
2135             case 2:
2136                 damage *= 4;
2137                 break;
2138 
2139             case 1:
2140                 damage *= 2;
2141                 break;
2142 
2143             default:
2144                 break;
2145             }
2146             break;
2147 
2148         case MT_CSTAFF_MISSILE:
2149             // Cleric Serpent Staff does poison damage.
2150             if(target->player)
2151             {
2152                 P_PoisonPlayer(target->player, source, 20);
2153                 damage /= 2;
2154             }
2155             break;
2156 
2157         case MT_ICEGUY_FX2:
2158             damage /= 2;
2159             break;
2160 
2161         case MT_POISONDART:
2162             if(target->player)
2163             {
2164                 P_PoisonPlayer(target->player, source, 20);
2165                 damage /= 2;
2166             }
2167             break;
2168 
2169         case MT_POISONCLOUD:
2170             if(target->player)
2171             {
2172                 int damageDone = 0;
2173                 if(target->player->poisonCount < 4)
2174                 {
2175                     damageDone = P_PoisonDamage(target->player, source, 15 + (P_Random() & 15), false);  // Don't play painsound
2176                     P_PoisonPlayer(target->player, source, 50);
2177                     S_StartSound(SFX_PLAYER_POISONCOUGH, target);
2178                 }
2179                 return damageDone;
2180             }
2181             else if(!(target->flags & MF_COUNTKILL))
2182             {
2183                 // Only damage monsters/players with the poison cloud.
2184                 return 0;
2185             }
2186             break;
2187 
2188         case MT_FSWORD_MISSILE:
2189             if(target->player)
2190             {
2191                 damage -= damage / 4;
2192             }
2193             break;
2194 
2195         default:
2196             break;
2197         }
2198     }
2199 
2200     // Some close combat weapons should not inflict thrust and push the
2201     // victim out of reach, thus kick away unless using a melee weapon.
2202     if(inflictor && (!source || !source->player) &&
2203        !(inflictor->flags2 & MF2_NODMGTHRUST))
2204     {
2205         angle = M_PointToAngle2(inflictor->origin, target->origin);
2206 
2207         if (target->info->mass)
2208         {
2209             thrust = FIX2FLT(damage * (FRACUNIT>>3) * 100 / target->info->mass);
2210         }
2211         else
2212         {
2213             thrust = 0;
2214         }
2215 
2216         // Make fall forwards sometimes.
2217         if((damage < 40) && (damage > target->health) &&
2218            (target->origin[VZ] - inflictor->origin[VZ] > 64) && (P_Random() & 1))
2219         {
2220             angle += ANG180;
2221             thrust *= 4;
2222         }
2223 
2224         an = angle >>ANGLETOFINESHIFT;
2225         target->mom[MX] += thrust * FIX2FLT(finecosine[an]);
2226         target->mom[MY] += thrust * FIX2FLT(finesine[an]);
2227         NetSv_PlayerMobjImpulse(target, thrust * FIX2FLT(finecosine[an]), thrust * FIX2FLT(finesine[an]), 0);
2228     }
2229 
2230     // Player specific.
2231     if(player)
2232     {
2233         target->player->update |= PSF_HEALTH;
2234 
2235         /*if(damage < 1000 &&
2236            ((P_GetPlayerCheats(target->player) & CF_GODMODE) ||
2237             target->player->powers[PT_INVULNERABILITY]))
2238         {
2239             return 0;
2240         }*/
2241 
2242         savedPercent = FIX2FLT(
2243             PCLASS_INFO(player->class_)->autoArmorSave + player->armorPoints[ARMOR_ARMOR] +
2244             player->armorPoints[ARMOR_SHIELD] +
2245             player->armorPoints[ARMOR_HELMET] +
2246             player->armorPoints[ARMOR_AMULET]);
2247         if(savedPercent)
2248         {   // Armor absorbed some damage.
2249             if(savedPercent > 100)
2250             {
2251                 savedPercent = 100;
2252             }
2253 
2254             for(i = 0; i < NUMARMOR; ++i)
2255             {
2256                 if(player->armorPoints[i])
2257                 {
2258                     player->armorPoints[i] -=
2259                         FLT2FIX(((float) damage * FIX2FLT(PCLASS_INFO(player->class_)->armorIncrement[i])) /
2260                                  300);
2261 
2262                     if(player->armorPoints[i] < 2 * FRACUNIT)
2263                     {
2264                         player->armorPoints[i] = 0;
2265                     }
2266                 }
2267             }
2268             saved = ((float) damage * savedPercent) / 100;
2269 
2270             if(saved > savedPercent * 2)
2271                 saved = savedPercent * 2;
2272 
2273             damage -= (int) saved;
2274         }
2275 
2276         if(damage >= player->health &&
2277            ((gfw_Rule(skill) == SM_BABY) || gfw_Rule(deathmatch)) &&
2278            !player->morphTics)
2279         {
2280             // Try to use some inventory health.
2281             P_AutoUseHealth(player, damage - player->health + 1);
2282         }
2283 
2284         player->health -= damage;
2285 
2286         if(player->health < 0)
2287             player->health = 0;
2288 
2289         player->attacker = source;
2290         player->damageCount += damage; // Add damage after armor / invuln.
2291 
2292         if(player->damageCount > 100)
2293             player->damageCount = 100; // Teleport stomp does 10k points...
2294 
2295         // temp = (damage < 100 ? damage : 100); Unused?
2296 
2297         // Maybe unhide the HUD?
2298         ST_HUDUnHide(player - players, HUE_ON_DAMAGE);
2299 
2300         R_UpdateViewFilter(player - players);
2301     }
2302 
2303     Mobj_InflictDamage(target, inflictor, damage);
2304 
2305     if(target->health > 0)
2306     {   // Still alive, phew!
2307         if((P_Random() < target->info->painChance) &&
2308            !(target->flags & MF_SKULLFLY))
2309         {
2310             if(inflictor &&
2311                (inflictor->type >= MT_LIGHTNING_FLOOR &&
2312                 inflictor->type <= MT_LIGHTNING_ZAP))
2313             {
2314                 if(P_Random() < 96)
2315                 {
2316                     statenum_t          state;
2317 
2318                     target->flags |= MF_JUSTHIT; // fight back!
2319 
2320                     if((state = P_GetState(target->type, SN_PAIN)) != S_NULL)
2321                         P_MobjChangeState(target, state);
2322                 }
2323                 else
2324                 {   // "electrocute" the target.
2325     //// @todo make fullbright for this frame -->
2326                     //target->frame |= FF_FULLBRIGHT;
2327     // <-- fixme
2328                     if((target->flags & MF_COUNTKILL) && P_Random() < 128 &&
2329                        !S_IsPlaying(SFX_PUPPYBEAT, target))
2330                     {
2331                         if((target->type == MT_CENTAUR) ||
2332                            (target->type == MT_CENTAURLEADER) ||
2333                            (target->type == MT_ETTIN))
2334                         {
2335                             S_StartSound(SFX_PUPPYBEAT, target);
2336                         }
2337                     }
2338                 }
2339             }
2340             else
2341             {
2342                 statenum_t state;
2343 
2344                 target->flags |= MF_JUSTHIT; // fight back!
2345 
2346                 if((state = P_GetState(target->type, SN_PAIN)) != S_NULL)
2347                     P_MobjChangeState(target, state);
2348 
2349                 if(inflictor && inflictor->type == MT_POISONCLOUD)
2350                 {
2351                     if(target->flags & MF_COUNTKILL && P_Random() < 128 &&
2352                        !S_IsPlaying(SFX_PUPPYBEAT, target))
2353                     {
2354                         if((target->type == MT_CENTAUR) ||
2355                            (target->type == MT_CENTAURLEADER) ||
2356                            (target->type == MT_ETTIN))
2357                         {
2358                             S_StartSound(SFX_PUPPYBEAT, target);
2359                         }
2360                     }
2361                 }
2362             }
2363         }
2364 
2365         target->reactionTime = 0; // We're awake now...
2366 
2367         if(!target->threshold && source && !(source->flags3 & MF3_NOINFIGHT) &&
2368            !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
2369         {
2370             // Target is not intent on another, so make it chase source.
2371             if(!((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER) ||
2372                  (target->type == MT_CENTAURLEADER && source->type == MT_CENTAUR)))
2373             {
2374                 statenum_t          state;
2375 
2376                 target->target = source;
2377                 target->threshold = BASETHRESHOLD;
2378 
2379                 if((state = P_GetState(target->type, SN_SEE)) != S_NULL &&
2380                    target->state == &STATES[P_GetState(target->type, SN_SPAWN)])
2381                 {
2382                     P_MobjChangeState(target, state);
2383                 }
2384             }
2385         }
2386     }
2387     else
2388     {   // Death.
2389         if(inflictor)
2390         {   // Check for special fire damage or ice damage deaths.
2391             if(inflictor->flags2 & MF2_FIREDAMAGE)
2392             {
2393                 if(player && !player->morphTics)
2394                 {   // Check for flame death.
2395                     if(target->health > -50 && damage > 25)
2396                     {
2397                         target->flags2 |= MF2_FIREDAMAGE;
2398                     }
2399                 }
2400                 else
2401                 {
2402                     target->flags2 |= MF2_FIREDAMAGE;
2403                 }
2404             }
2405             else if(inflictor->flags2 & MF2_ICEDAMAGE)
2406             {
2407                 target->flags2 |= MF2_ICEDAMAGE;
2408             }
2409         }
2410 
2411         if(source && (source->type == MT_MINOTAUR))
2412         {
2413             // Minotaur's kills go to his master.
2414             master = source->tracer;
2415 
2416             // Make sure still alive and not a pointer to fighter head.
2417             if(master && master->player && (master->player->plr->mo == master))
2418             {
2419                 source = master;
2420             }
2421         }
2422 
2423         if(source && (source->player) &&
2424            (source->player->readyWeapon == WT_FOURTH))
2425         {
2426             // Always extreme death from fourth weapon.
2427             target->health = -5000;
2428         }
2429 
2430         P_KillMobj(source, target);
2431     }
2432 
2433     return originalHealth - target->health;
2434 }
2435 
P_FallingDamage(player_t * player)2436 int P_FallingDamage(player_t* player)
2437 {
2438     int damage;
2439     coord_t mom, dist;
2440 
2441     mom = fabs(player->plr->mo->mom[MZ]);
2442     dist = mom * (16.0f / 23);
2443 
2444     if(mom >= 63)
2445     {   // Automatic death.
2446         return P_DamageMobj(player->plr->mo, NULL, NULL, 10000, false);
2447     }
2448 
2449     damage = ((dist * dist) / 10) - 24;
2450     if(player->plr->mo->mom[MZ] > -39 && damage > player->plr->mo->health &&
2451        player->plr->mo->health != 1)
2452     {   // No-death threshold.
2453         damage = player->plr->mo->health - 1;
2454     }
2455 
2456     S_StartSound(SFX_PLAYER_LAND, player->plr->mo);
2457 
2458     return P_DamageMobj(player->plr->mo, NULL, NULL, damage, false);
2459 }
2460 
P_PoisonDamage(player_t * player,mobj_t * source,int damage,dd_bool playPainSound)2461 int P_PoisonDamage(player_t *player, mobj_t *source, int damage, dd_bool playPainSound)
2462 {
2463     int originalHealth;
2464     mobj_t *target, *inflictor;
2465 
2466     target = player->plr->mo;
2467     originalHealth = target->health;
2468     inflictor = source;
2469 
2470     if(target->health <= 0)
2471         return 0; // Already dead.
2472 
2473     if((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
2474         return 0; // mobj is invulnerable.
2475 
2476     if(gfw_Rule(skill) == SM_BABY)
2477     {
2478         // Take half damage in trainer mode
2479         damage /= 2;
2480     }
2481 
2482     if(damage < 1000 &&
2483        ((P_GetPlayerCheats(player) & CF_GODMODE) || player->powers[PT_INVULNERABILITY]))
2484     {
2485         return 0;
2486     }
2487 
2488     if(damage >= player->health &&
2489        (gfw_Rule(skill) == SM_BABY || gfw_Rule(deathmatch)) &&
2490        !player->morphTics)
2491     {
2492         // Try to use some inventory health.
2493         P_AutoUseHealth(player, damage - player->health + 1);
2494     }
2495 
2496     // Maybe unhide the HUD?
2497     ST_HUDUnHide(player - players, HUE_ON_DAMAGE);
2498 
2499     player->health -= damage;
2500     if(player->health < 0)
2501     {
2502         player->health = 0;
2503     }
2504     player->attacker = source;
2505 
2506     // Do the damage.
2507     target->health -= damage;
2508     if(target->health > 0)
2509     {   // Still alive, phew!
2510         if(!(mapTime & 63) && playPainSound)
2511         {
2512             statenum_t          state;
2513 
2514             if((state = P_GetState(target->type, SN_PAIN)) != S_NULL)
2515                 P_MobjChangeState(target, state);
2516         }
2517     }
2518     else
2519     {   // Death
2520         target->special1 = damage;
2521         if(player && inflictor && !player->morphTics)
2522         {   // Check for flame death.
2523             if((inflictor->flags2 & MF2_FIREDAMAGE) &&
2524                (target->health > -50) && (damage > 25))
2525             {
2526                 target->flags2 |= MF2_FIREDAMAGE;
2527             }
2528 
2529             if(inflictor->flags2 & MF2_ICEDAMAGE)
2530             {
2531                 target->flags2 |= MF2_ICEDAMAGE;
2532             }
2533         }
2534 
2535         P_KillMobj(source, target);
2536     }
2537 
2538     return originalHealth - target->health;
2539 }
2540