p_inter.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Handling interactions (i.e., collisions).
  31. *
  32. *-----------------------------------------------------------------------------*/
  33. #include "doomstat.h"
  34. #include "dstrings.h"
  35. #include "m_random.h"
  36. #include "am_map.h"
  37. #include "r_main.h"
  38. #include "s_sound.h"
  39. #include "sounds.h"
  40. #include "d_deh.h" // Ty 03/22/98 - externalized strings
  41. #include "p_tick.h"
  42. #include "lprintf.h"
  43. #include "p_inter.h"
  44. #include "p_enemy.h"
  45. #ifdef __GNUG__
  46. #pragma implementation "p_inter.h"
  47. #endif
  48. #include "p_inter.h"
  49. #include "doomiphone.h"
  50. #define BONUSADD 6
  51. // Ty 03/07/98 - add deh externals
  52. // Maximums and such were hardcoded values. Need to externalize those for
  53. // dehacked support (and future flexibility). Most var names came from the key
  54. // strings used in dehacked.
  55. int initial_health = 100;
  56. int initial_bullets = 50;
  57. int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module
  58. int max_armor = 200;
  59. int green_armor_class = 1; // these are involved with armortype below
  60. int blue_armor_class = 2;
  61. int max_soul = 200;
  62. int soul_health = 100;
  63. int mega_health = 200;
  64. int god_health = 100; // these are used in cheats (see st_stuff.c)
  65. int idfa_armor = 200;
  66. int idfa_armor_class = 2;
  67. // not actually used due to pairing of cheat_k and cheat_fa
  68. int idkfa_armor = 200;
  69. int idkfa_armor_class = 2;
  70. int bfgcells = 40; // used in p_pspr.c
  71. int monsters_infight = 0; // e6y: Dehacked support - monsters infight
  72. // Ty 03/07/98 - end deh externals
  73. // a weapon is found with two clip loads,
  74. // a big item has five clip loads
  75. int maxammo[NUMAMMO] = {200, 50, 300, 50};
  76. int clipammo[NUMAMMO] = { 10, 4, 20, 1};
  77. //
  78. // GET STUFF
  79. //
  80. //
  81. // P_GiveAmmo
  82. // Num is the number of clip loads,
  83. // not the individual count (0= 1/2 clip).
  84. // Returns false if the ammo can't be picked up at all
  85. //
  86. static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num)
  87. {
  88. int oldammo;
  89. if (ammo == am_noammo)
  90. return false;
  91. #ifdef RANGECHECK
  92. if (ammo > NUMAMMO)
  93. I_Error ("P_GiveAmmo: bad type %i", ammo);
  94. #endif
  95. if ( player->ammo[ammo] == player->maxammo[ammo] )
  96. return false;
  97. if (num)
  98. num *= clipammo[ammo];
  99. else
  100. num = clipammo[ammo]/2;
  101. // give double ammo in trainer mode, you'll need in nightmare
  102. if (gameskill == sk_baby || gameskill == sk_nightmare)
  103. num <<= 1;
  104. oldammo = player->ammo[ammo];
  105. player->ammo[ammo] += num;
  106. if (player->ammo[ammo] > player->maxammo[ammo])
  107. player->ammo[ammo] = player->maxammo[ammo];
  108. // If non zero ammo, don't change up weapons, player was lower on purpose.
  109. if (oldammo)
  110. return true;
  111. // We were down to zero, so select a new weapon.
  112. // Preferences are not user selectable.
  113. switch (ammo)
  114. {
  115. case am_clip:
  116. if (player->readyweapon == wp_fist) {
  117. if (player->weaponowned[wp_chaingun])
  118. player->pendingweapon = wp_chaingun;
  119. else
  120. player->pendingweapon = wp_pistol;
  121. }
  122. break;
  123. case am_shell:
  124. if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
  125. if (player->weaponowned[wp_shotgun])
  126. player->pendingweapon = wp_shotgun;
  127. break;
  128. case am_cell:
  129. if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
  130. if (player->weaponowned[wp_plasma])
  131. player->pendingweapon = wp_plasma;
  132. break;
  133. case am_misl:
  134. if (player->readyweapon == wp_fist)
  135. if (player->weaponowned[wp_missile])
  136. player->pendingweapon = wp_missile;
  137. default:
  138. break;
  139. }
  140. return true;
  141. }
  142. //
  143. // P_GiveWeapon
  144. // The weapon name may have a MF_DROPPED flag ored in.
  145. //
  146. static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped)
  147. {
  148. boolean gaveammo;
  149. boolean gaveweapon;
  150. if (netgame && deathmatch!=2 && !dropped)
  151. {
  152. // leave placed weapons forever on net games
  153. if (player->weaponowned[weapon])
  154. return false;
  155. player->bonuscount += BONUSADD;
  156. player->weaponowned[weapon] = true;
  157. P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2);
  158. player->pendingweapon = weapon;
  159. /* cph 20028/10 - for old-school DM addicts, allow old behavior
  160. * where only consoleplayer's pickup sounds are heard */
  161. // displayplayer, not consoleplayer, for viewing multiplayer demos
  162. if (!comp[comp_sound] || player == &players[displayplayer])
  163. S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98
  164. return false;
  165. }
  166. if (weaponinfo[weapon].ammo != am_noammo)
  167. {
  168. // give one clip with a dropped weapon,
  169. // two clips with a found weapon
  170. gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2);
  171. }
  172. else
  173. gaveammo = false;
  174. if (player->weaponowned[weapon])
  175. gaveweapon = false;
  176. else
  177. {
  178. gaveweapon = true;
  179. player->weaponowned[weapon] = true;
  180. player->pendingweapon = weapon;
  181. }
  182. return gaveweapon || gaveammo;
  183. }
  184. //
  185. // P_GiveBody
  186. // Returns false if the body isn't needed at all
  187. //
  188. static boolean P_GiveBody(player_t *player, int num)
  189. {
  190. if (player->health >= maxhealth)
  191. return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth
  192. player->health += num;
  193. if (player->health > maxhealth)
  194. player->health = maxhealth;
  195. player->mo->health = player->health;
  196. return true;
  197. }
  198. //
  199. // P_GiveArmor
  200. // Returns false if the armor is worse
  201. // than the current armor.
  202. //
  203. static boolean P_GiveArmor(player_t *player, int armortype)
  204. {
  205. int hits = armortype*100;
  206. if (player->armorpoints >= hits)
  207. return false; // don't pick up
  208. player->armortype = armortype;
  209. player->armorpoints = hits;
  210. return true;
  211. }
  212. //
  213. // P_GiveCard
  214. //
  215. static void P_GiveCard(player_t *player, card_t card)
  216. {
  217. if (player->cards[card])
  218. return;
  219. player->bonuscount = BONUSADD;
  220. player->cards[card] = 1;
  221. }
  222. //
  223. // P_GivePower
  224. //
  225. // Rewritten by Lee Killough
  226. //
  227. boolean P_GivePower(player_t *player, int power)
  228. {
  229. static const int tics[NUMPOWERS] = {
  230. INVULNTICS, 1 /* strength */, INVISTICS,
  231. IRONTICS, 1 /* allmap */, INFRATICS,
  232. };
  233. switch (power)
  234. {
  235. case pw_invisibility:
  236. player->mo->flags |= MF_SHADOW;
  237. break;
  238. case pw_allmap:
  239. if (player->powers[pw_allmap])
  240. return false;
  241. break;
  242. case pw_strength:
  243. P_GiveBody(player,100);
  244. break;
  245. }
  246. // Unless player has infinite duration cheat, set duration (killough)
  247. if (player->powers[power] >= 0)
  248. player->powers[power] = tics[power];
  249. return true;
  250. }
  251. //
  252. // P_TouchSpecialThing
  253. //
  254. void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
  255. {
  256. player_t *player;
  257. int i;
  258. int sound;
  259. fixed_t delta = special->z - toucher->z;
  260. if (delta > toucher->height || delta < -8*FRACUNIT)
  261. return; // out of reach
  262. sound = sfx_itemup;
  263. player = toucher->player;
  264. // Dead thing touching.
  265. // Can happen with a sliding player corpse.
  266. if (toucher->health <= 0)
  267. return;
  268. // Identify by sprite.
  269. switch (special->sprite)
  270. {
  271. // armor
  272. case SPR_ARM1:
  273. if (!P_GiveArmor (player, green_armor_class))
  274. return;
  275. player->message = s_GOTARMOR; // Ty 03/22/98 - externalized
  276. break;
  277. case SPR_ARM2:
  278. if (!P_GiveArmor (player, blue_armor_class))
  279. return;
  280. player->message = s_GOTMEGA; // Ty 03/22/98 - externalized
  281. break;
  282. // bonus items
  283. case SPR_BON1:
  284. player->health++; // can go over 100%
  285. if (player->health > (maxhealth * 2))
  286. player->health = (maxhealth * 2);
  287. player->mo->health = player->health;
  288. player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized
  289. break;
  290. case SPR_BON2:
  291. player->armorpoints++; // can go over 100%
  292. if (player->armorpoints > max_armor)
  293. player->armorpoints = max_armor;
  294. if (!player->armortype)
  295. player->armortype = green_armor_class;
  296. player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized
  297. break;
  298. case SPR_SOUL:
  299. player->health += soul_health;
  300. if (player->health > max_soul)
  301. player->health = max_soul;
  302. player->mo->health = player->health;
  303. player->message = s_GOTSUPER; // Ty 03/22/98 - externalized
  304. sound = sfx_getpow;
  305. break;
  306. case SPR_MEGA:
  307. if (gamemode != commercial)
  308. return;
  309. player->health = mega_health;
  310. player->mo->health = player->health;
  311. P_GiveArmor (player,blue_armor_class);
  312. player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized
  313. sound = sfx_getpow;
  314. break;
  315. // cards
  316. // leave cards for everyone
  317. case SPR_BKEY:
  318. if (!player->cards[it_bluecard])
  319. player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized
  320. P_GiveCard (player, it_bluecard);
  321. if (!netgame)
  322. break;
  323. return;
  324. case SPR_YKEY:
  325. if (!player->cards[it_yellowcard])
  326. player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized
  327. P_GiveCard (player, it_yellowcard);
  328. if (!netgame)
  329. break;
  330. return;
  331. case SPR_RKEY:
  332. if (!player->cards[it_redcard])
  333. player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized
  334. P_GiveCard (player, it_redcard);
  335. if (!netgame)
  336. break;
  337. return;
  338. case SPR_BSKU:
  339. if (!player->cards[it_blueskull])
  340. player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized
  341. P_GiveCard (player, it_blueskull);
  342. if (!netgame)
  343. break;
  344. return;
  345. case SPR_YSKU:
  346. if (!player->cards[it_yellowskull])
  347. player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized
  348. P_GiveCard (player, it_yellowskull);
  349. if (!netgame)
  350. break;
  351. return;
  352. case SPR_RSKU:
  353. if (!player->cards[it_redskull])
  354. player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized
  355. P_GiveCard (player, it_redskull);
  356. if (!netgame)
  357. break;
  358. return;
  359. // medikits, heals
  360. case SPR_STIM:
  361. if (!P_GiveBody (player, 10))
  362. return;
  363. player->message = s_GOTSTIM; // Ty 03/22/98 - externalized
  364. break;
  365. case SPR_MEDI:
  366. if (!P_GiveBody (player, 25))
  367. return;
  368. if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug
  369. player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized
  370. else
  371. player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized
  372. break;
  373. // power ups
  374. case SPR_PINV:
  375. if (!P_GivePower (player, pw_invulnerability))
  376. return;
  377. player->message = s_GOTINVUL; // Ty 03/22/98 - externalized
  378. sound = sfx_getpow;
  379. break;
  380. case SPR_PSTR:
  381. if (!P_GivePower (player, pw_strength))
  382. return;
  383. player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized
  384. if (player->readyweapon != wp_fist)
  385. player->pendingweapon = wp_fist;
  386. sound = sfx_getpow;
  387. break;
  388. case SPR_PINS:
  389. if (!P_GivePower (player, pw_invisibility))
  390. return;
  391. player->message = s_GOTINVIS; // Ty 03/22/98 - externalized
  392. sound = sfx_getpow;
  393. break;
  394. case SPR_SUIT:
  395. if (!P_GivePower (player, pw_ironfeet))
  396. return;
  397. player->message = s_GOTSUIT; // Ty 03/22/98 - externalized
  398. sound = sfx_getpow;
  399. break;
  400. case SPR_PMAP:
  401. if (!P_GivePower (player, pw_allmap))
  402. return;
  403. player->message = s_GOTMAP; // Ty 03/22/98 - externalized
  404. sound = sfx_getpow;
  405. break;
  406. case SPR_PVIS:
  407. if (!P_GivePower (player, pw_infrared))
  408. return;
  409. player->message = s_GOTVISOR; // Ty 03/22/98 - externalized
  410. sound = sfx_getpow;
  411. break;
  412. // ammo
  413. case SPR_CLIP:
  414. if (special->flags & MF_DROPPED)
  415. {
  416. if (!P_GiveAmmo (player,am_clip,0))
  417. return;
  418. }
  419. else
  420. {
  421. if (!P_GiveAmmo (player,am_clip,1))
  422. return;
  423. }
  424. player->message = s_GOTCLIP; // Ty 03/22/98 - externalized
  425. break;
  426. case SPR_AMMO:
  427. if (!P_GiveAmmo (player, am_clip,5))
  428. return;
  429. player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized
  430. break;
  431. case SPR_ROCK:
  432. if (!P_GiveAmmo (player, am_misl,1))
  433. return;
  434. player->message = s_GOTROCKET; // Ty 03/22/98 - externalized
  435. break;
  436. case SPR_BROK:
  437. if (!P_GiveAmmo (player, am_misl,5))
  438. return;
  439. player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized
  440. break;
  441. case SPR_CELL:
  442. if (!P_GiveAmmo (player, am_cell,1))
  443. return;
  444. player->message = s_GOTCELL; // Ty 03/22/98 - externalized
  445. break;
  446. case SPR_CELP:
  447. if (!P_GiveAmmo (player, am_cell,5))
  448. return;
  449. player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized
  450. break;
  451. case SPR_SHEL:
  452. if (!P_GiveAmmo (player, am_shell,1))
  453. return;
  454. player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized
  455. break;
  456. case SPR_SBOX:
  457. if (!P_GiveAmmo (player, am_shell,5))
  458. return;
  459. player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized
  460. break;
  461. case SPR_BPAK:
  462. if (!player->backpack)
  463. {
  464. for (i=0 ; i<NUMAMMO ; i++)
  465. player->maxammo[i] *= 2;
  466. player->backpack = true;
  467. }
  468. for (i=0 ; i<NUMAMMO ; i++)
  469. P_GiveAmmo (player, i, 1);
  470. player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized
  471. break;
  472. // weapons
  473. case SPR_BFUG:
  474. if (!P_GiveWeapon (player, wp_bfg, false) )
  475. return;
  476. player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized
  477. sound = sfx_wpnup;
  478. break;
  479. case SPR_MGUN:
  480. if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) )
  481. return;
  482. player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized
  483. sound = sfx_wpnup;
  484. break;
  485. case SPR_CSAW:
  486. if (!P_GiveWeapon (player, wp_chainsaw, false) )
  487. return;
  488. player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized
  489. sound = sfx_wpnup;
  490. break;
  491. case SPR_LAUN:
  492. if (!P_GiveWeapon (player, wp_missile, false) )
  493. return;
  494. player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized
  495. sound = sfx_wpnup;
  496. break;
  497. case SPR_PLAS:
  498. if (!P_GiveWeapon (player, wp_plasma, false) )
  499. return;
  500. player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized
  501. sound = sfx_wpnup;
  502. break;
  503. case SPR_SHOT:
  504. if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) )
  505. return;
  506. player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized
  507. sound = sfx_wpnup;
  508. break;
  509. case SPR_SGN2:
  510. if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0))
  511. return;
  512. player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized
  513. sound = sfx_wpnup;
  514. break;
  515. default:
  516. I_Error ("P_SpecialThing: Unknown gettable thing");
  517. }
  518. if (special->flags & MF_COUNTITEM)
  519. player->itemcount++;
  520. P_RemoveMobj (special);
  521. player->bonuscount += BONUSADD;
  522. /* cph 20028/10 - for old-school DM addicts, allow old behavior
  523. * where only consoleplayer's pickup sounds are heard */
  524. // displayplayer, not consoleplayer, for viewing multiplayer demos
  525. if (!comp[comp_sound] || player == &players[displayplayer])
  526. S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98
  527. }
  528. //
  529. // KillMobj
  530. //
  531. // killough 11/98: make static
  532. static void P_KillMobj(mobj_t *source, mobj_t *target)
  533. {
  534. mobjtype_t item;
  535. mobj_t *mo;
  536. target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
  537. if (target->type != MT_SKULL)
  538. target->flags &= ~MF_NOGRAVITY;
  539. target->flags |= MF_CORPSE|MF_DROPOFF;
  540. target->height >>= 2;
  541. if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
  542. totallive--;
  543. if (source && source->player)
  544. {
  545. // count for intermission
  546. if (target->flags & MF_COUNTKILL)
  547. source->player->killcount++;
  548. if (target->player)
  549. source->player->frags[target->player-players]++;
  550. }
  551. else
  552. if (target->flags & MF_COUNTKILL) { /* Add to kills tally */
  553. if ((compatibility_level < lxdoom_1_compatibility) || !netgame) {
  554. if (!netgame)
  555. // count all monster deaths,
  556. // even those caused by other monsters
  557. players[0].killcount++;
  558. } else
  559. if (!deathmatch) {
  560. // try and find a player to give the kill to, otherwise give the
  561. // kill to a random player. this fixes the missing monsters bug
  562. // in coop - rain
  563. // CPhipps - not a bug as such, but certainly an inconsistency.
  564. if (target->lastenemy && target->lastenemy->health > 0
  565. && target->lastenemy->player) // Fighting a player
  566. target->lastenemy->player->killcount++;
  567. else {
  568. // cph - randomely choose a player in the game to be credited
  569. // and do it uniformly between the active players
  570. unsigned int activeplayers = 0, player, i;
  571. for (player = 0; player<MAXPLAYERS; player++)
  572. if (playeringame[player])
  573. activeplayers++;
  574. if (activeplayers) {
  575. player = P_Random(pr_friends) % activeplayers;
  576. for (i=0; i<MAXPLAYERS; i++)
  577. if (playeringame[i])
  578. if (!player--)
  579. players[i].killcount++;
  580. }
  581. }
  582. }
  583. }
  584. if (target->player)
  585. {
  586. // count environment kills against you
  587. if (!source)
  588. target->player->frags[target->player-players]++;
  589. target->flags &= ~MF_SOLID;
  590. target->player->playerstate = PST_DEAD;
  591. P_DropWeapon (target->player);
  592. if (target->player == &players[consoleplayer] && (automapmode & am_active))
  593. AM_Stop(); // don't die in auto map; switch view prior to dying
  594. }
  595. if (target->health < -target->info->spawnhealth && target->info->xdeathstate)
  596. P_SetMobjState (target, target->info->xdeathstate);
  597. else
  598. P_SetMobjState (target, target->info->deathstate);
  599. target->tics -= P_Random(pr_killtics)&3;
  600. if (target->tics < 1)
  601. target->tics = 1;
  602. // Drop stuff.
  603. // This determines the kind of object spawned
  604. // during the death frame of a thing.
  605. switch (target->type)
  606. {
  607. case MT_WOLFSS:
  608. case MT_POSSESSED:
  609. item = MT_CLIP;
  610. break;
  611. case MT_SHOTGUY:
  612. item = MT_SHOTGUN;
  613. break;
  614. case MT_CHAINGUY:
  615. item = MT_CHAINGUN;
  616. break;
  617. default:
  618. return;
  619. }
  620. mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
  621. mo->flags |= MF_DROPPED; // special versions of items
  622. }
  623. //
  624. // P_DamageMobj
  625. // Damages both enemies and players
  626. // "inflictor" is the thing that caused the damage
  627. // creature or missile, can be NULL (slime, etc)
  628. // "source" is the thing to target after taking damage
  629. // creature or NULL
  630. // Source and inflictor are the same for melee attacks.
  631. // Source can be NULL for slime, barrel explosions
  632. // and other environmental stuff.
  633. //
  634. void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage)
  635. {
  636. player_t *player;
  637. boolean justhit = false; /* killough 11/98 */
  638. /* killough 8/31/98: allow bouncers to take damage */
  639. if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES)))
  640. return; // shouldn't happen...
  641. if (target->health <= 0)
  642. return;
  643. if (target->flags & MF_SKULLFLY)
  644. target->momx = target->momy = target->momz = 0;
  645. player = target->player;
  646. if (player && gameskill == sk_baby)
  647. damage >>= 1; // take half damage in trainer mode
  648. // Some close combat weapons should not
  649. // inflict thrust and push the victim out of reach,
  650. // thus kick away unless using the chainsaw.
  651. if (inflictor && !(target->flags & MF_NOCLIP) &&
  652. (!source || !source->player ||
  653. source->player->readyweapon != wp_chainsaw))
  654. {
  655. unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y,
  656. target->x, target->y);
  657. fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
  658. // make fall forwards sometimes
  659. if ( damage < 40 && damage > target->health
  660. && target->z - inflictor->z > 64*FRACUNIT
  661. && P_Random(pr_damagemobj) & 1)
  662. {
  663. ang += ANG180;
  664. thrust *= 4;
  665. }
  666. ang >>= ANGLETOFINESHIFT;
  667. target->momx += FixedMul (thrust, finecosine[ang]);
  668. target->momy += FixedMul (thrust, finesine[ang]);
  669. /* killough 11/98: thrust objects hanging off ledges */
  670. if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR)
  671. target->gear = 0;
  672. }
  673. // player specific
  674. if (player)
  675. {
  676. // end of game hell hack
  677. if (target->subsector->sector->special == 11 && damage >= target->health)
  678. damage = target->health - 1;
  679. // Below certain threshold,
  680. // ignore damage in GOD mode, or with INVUL power.
  681. // killough 3/26/98: make god mode 100% god mode in non-compat mode
  682. if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) &&
  683. (player->cheats&CF_GODMODE || player->powers[pw_invulnerability]))
  684. return;
  685. if (player->armortype)
  686. {
  687. int saved = player->armortype == 1 ? damage/3 : damage/2;
  688. if (player->armorpoints <= saved)
  689. {
  690. // armor is used up
  691. saved = player->armorpoints;
  692. player->armortype = 0;
  693. }
  694. player->armorpoints -= saved;
  695. damage -= saved;
  696. }
  697. player->health -= damage; // mirror mobj health here for Dave
  698. if (player->health < 0)
  699. player->health = 0;
  700. player->attacker = source;
  701. player->damagecount += damage; // add damage after armor / invuln
  702. #ifdef IPHONE
  703. if ( player == &players[consoleplayer] && !demoplayback ) { // vibe during demos is annoying
  704. SysIPhoneVibrate();
  705. }
  706. #endif
  707. if (player->damagecount > 100)
  708. player->damagecount = 100; // teleport stomp does 10k points...
  709. }
  710. // do the damage
  711. target->health -= damage;
  712. if (target->health <= 0)
  713. {
  714. P_KillMobj (source, target);
  715. return;
  716. }
  717. // killough 9/7/98: keep track of targets so that friends can help friends
  718. if (mbf_features)
  719. {
  720. /* If target is a player, set player's target to source,
  721. * so that a friend can tell who's hurting a player
  722. */
  723. if (player)
  724. P_SetTarget(&target->target, source);
  725. /* killough 9/8/98:
  726. * If target's health is less than 50%, move it to the front of its list.
  727. * This will slightly increase the chances that enemies will choose to
  728. * "finish it off", but its main purpose is to alert friends of danger.
  729. */
  730. if (target->health*2 < target->info->spawnhealth)
  731. {
  732. thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ?
  733. th_friends : th_enemies];
  734. (target->thinker.cprev->cnext = target->thinker.cnext)->cprev =
  735. target->thinker.cprev;
  736. (target->thinker.cnext = cap->cnext)->cprev = &target->thinker;
  737. (target->thinker.cprev = cap)->cnext = &target->thinker;
  738. }
  739. }
  740. if (P_Random (pr_painchance) < target->info->painchance &&
  741. !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below
  742. if (mbf_features)
  743. justhit = true;
  744. else
  745. target->flags |= MF_JUSTHIT; // fight back!
  746. P_SetMobjState(target, target->info->painstate);
  747. }
  748. target->reactiontime = 0; // we're awake now...
  749. /* killough 9/9/98: cleaned up, made more consistent: */
  750. if (source && source != target && source->type != MT_VILE &&
  751. (!target->threshold || target->type == MT_VILE) &&
  752. ((source->flags ^ target->flags) & MF_FRIEND ||
  753. monster_infighting ||
  754. !mbf_features))
  755. {
  756. /* if not intent on another player, chase after this one
  757. *
  758. * killough 2/15/98: remember last enemy, to prevent
  759. * sleeping early; 2/21/98: Place priority on players
  760. * killough 9/9/98: cleaned up, made more consistent:
  761. */
  762. if (!target->lastenemy || target->lastenemy->health <= 0 ||
  763. (!mbf_features ?
  764. !target->lastenemy->player :
  765. !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) &&
  766. target->target != source)) // remember last enemy - killough
  767. P_SetTarget(&target->lastenemy, target->target);
  768. P_SetTarget(&target->target, source); // killough 11/98
  769. target->threshold = BASETHRESHOLD;
  770. if (target->state == &states[target->info->spawnstate]
  771. && target->info->seestate != S_NULL)
  772. P_SetMobjState (target, target->info->seestate);
  773. }
  774. /* killough 11/98: Don't attack a friend, unless hit by that friend.
  775. * cph 2006/04/01 - implicitly this is only if mbf_features */
  776. if (justhit && (target->target == source || !target->target ||
  777. !(target->flags & target->target->flags & MF_FRIEND)))
  778. target->flags |= MF_JUSTHIT; // fight back!
  779. }