p_inter.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. // Handling interactions (i.e., collisions).
  21. //
  22. //-----------------------------------------------------------------------------
  23. static const char
  24. rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
  25. // Data.
  26. #include "doomdef.h"
  27. #include "dstrings.h"
  28. #include "sounds.h"
  29. #include "doomstat.h"
  30. #include "m_random.h"
  31. #include "i_system.h"
  32. #include "am_map.h"
  33. #include "p_local.h"
  34. #include "s_sound.h"
  35. #ifdef __GNUG__
  36. #pragma implementation "p_inter.h"
  37. #endif
  38. #include "p_inter.h"
  39. #define BONUSADD 6
  40. // a weapon is found with two clip loads,
  41. // a big item has five clip loads
  42. int maxammo[NUMAMMO] = {200, 50, 300, 50};
  43. int clipammo[NUMAMMO] = {10, 4, 20, 1};
  44. //
  45. // GET STUFF
  46. //
  47. //
  48. // P_GiveAmmo
  49. // Num is the number of clip loads,
  50. // not the individual count (0= 1/2 clip).
  51. // Returns false if the ammo can't be picked up at all
  52. //
  53. boolean
  54. P_GiveAmmo
  55. ( player_t* player,
  56. ammotype_t ammo,
  57. int num )
  58. {
  59. int oldammo;
  60. if (ammo == am_noammo)
  61. return false;
  62. if (ammo < 0 || ammo > NUMAMMO)
  63. I_Error ("P_GiveAmmo: bad type %i", ammo);
  64. if ( player->ammo[ammo] == player->maxammo[ammo] )
  65. return false;
  66. if (num)
  67. num *= clipammo[ammo];
  68. else
  69. num = clipammo[ammo]/2;
  70. if (gameskill == sk_baby
  71. || gameskill == sk_nightmare)
  72. {
  73. // give double ammo in trainer mode,
  74. // you'll need in nightmare
  75. num <<= 1;
  76. }
  77. oldammo = player->ammo[ammo];
  78. player->ammo[ammo] += num;
  79. if (player->ammo[ammo] > player->maxammo[ammo])
  80. player->ammo[ammo] = player->maxammo[ammo];
  81. // If non zero ammo,
  82. // don't change up weapons,
  83. // player was lower on purpose.
  84. if (oldammo)
  85. return true;
  86. // We were down to zero,
  87. // so select a new weapon.
  88. // Preferences are not user selectable.
  89. switch (ammo)
  90. {
  91. case am_clip:
  92. if (player->readyweapon == wp_fist)
  93. {
  94. if (player->weaponowned[wp_chaingun])
  95. player->pendingweapon = wp_chaingun;
  96. else
  97. player->pendingweapon = wp_pistol;
  98. }
  99. break;
  100. case am_shell:
  101. if (player->readyweapon == wp_fist
  102. || player->readyweapon == wp_pistol)
  103. {
  104. if (player->weaponowned[wp_shotgun])
  105. player->pendingweapon = wp_shotgun;
  106. }
  107. break;
  108. case am_cell:
  109. if (player->readyweapon == wp_fist
  110. || player->readyweapon == wp_pistol)
  111. {
  112. if (player->weaponowned[wp_plasma])
  113. player->pendingweapon = wp_plasma;
  114. }
  115. break;
  116. case am_misl:
  117. if (player->readyweapon == wp_fist)
  118. {
  119. if (player->weaponowned[wp_missile])
  120. player->pendingweapon = wp_missile;
  121. }
  122. default:
  123. break;
  124. }
  125. return true;
  126. }
  127. //
  128. // P_GiveWeapon
  129. // The weapon name may have a MF_DROPPED flag ored in.
  130. //
  131. boolean
  132. P_GiveWeapon
  133. ( player_t* player,
  134. weapontype_t weapon,
  135. boolean dropped )
  136. {
  137. boolean gaveammo;
  138. boolean gaveweapon;
  139. if (netgame
  140. && (deathmatch!=2)
  141. && !dropped )
  142. {
  143. // leave placed weapons forever on net games
  144. if (player->weaponowned[weapon])
  145. return false;
  146. player->bonuscount += BONUSADD;
  147. player->weaponowned[weapon] = true;
  148. if (deathmatch)
  149. P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
  150. else
  151. P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  152. player->pendingweapon = weapon;
  153. if (player == &players[consoleplayer])
  154. S_StartSound (NULL, sfx_wpnup);
  155. return false;
  156. }
  157. if (weaponinfo[weapon].ammo != am_noammo)
  158. {
  159. // give one clip with a dropped weapon,
  160. // two clips with a found weapon
  161. if (dropped)
  162. gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
  163. else
  164. gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  165. }
  166. else
  167. gaveammo = false;
  168. if (player->weaponowned[weapon])
  169. gaveweapon = false;
  170. else
  171. {
  172. gaveweapon = true;
  173. player->weaponowned[weapon] = true;
  174. player->pendingweapon = weapon;
  175. }
  176. return (gaveweapon || gaveammo);
  177. }
  178. //
  179. // P_GiveBody
  180. // Returns false if the body isn't needed at all
  181. //
  182. boolean
  183. P_GiveBody
  184. ( player_t* player,
  185. int num )
  186. {
  187. if (player->health >= MAXHEALTH)
  188. return false;
  189. player->health += num;
  190. if (player->health > MAXHEALTH)
  191. player->health = MAXHEALTH;
  192. player->mo->health = player->health;
  193. return true;
  194. }
  195. //
  196. // P_GiveArmor
  197. // Returns false if the armor is worse
  198. // than the current armor.
  199. //
  200. boolean
  201. P_GiveArmor
  202. ( player_t* player,
  203. int armortype )
  204. {
  205. int hits;
  206. hits = armortype*100;
  207. if (player->armorpoints >= hits)
  208. return false; // don't pick up
  209. player->armortype = armortype;
  210. player->armorpoints = hits;
  211. return true;
  212. }
  213. //
  214. // P_GiveCard
  215. //
  216. void
  217. P_GiveCard
  218. ( player_t* player,
  219. card_t card )
  220. {
  221. if (player->cards[card])
  222. return;
  223. player->bonuscount = BONUSADD;
  224. player->cards[card] = 1;
  225. }
  226. //
  227. // P_GivePower
  228. //
  229. boolean
  230. P_GivePower
  231. ( player_t* player,
  232. int /*powertype_t*/ power )
  233. {
  234. if (power == pw_invulnerability)
  235. {
  236. player->powers[power] = INVULNTICS;
  237. return true;
  238. }
  239. if (power == pw_invisibility)
  240. {
  241. player->powers[power] = INVISTICS;
  242. player->mo->flags |= MF_SHADOW;
  243. return true;
  244. }
  245. if (power == pw_infrared)
  246. {
  247. player->powers[power] = INFRATICS;
  248. return true;
  249. }
  250. if (power == pw_ironfeet)
  251. {
  252. player->powers[power] = IRONTICS;
  253. return true;
  254. }
  255. if (power == pw_strength)
  256. {
  257. P_GiveBody (player, 100);
  258. player->powers[power] = 1;
  259. return true;
  260. }
  261. if (player->powers[power])
  262. return false; // already got it
  263. player->powers[power] = 1;
  264. return true;
  265. }
  266. //
  267. // P_TouchSpecialThing
  268. //
  269. void
  270. P_TouchSpecialThing
  271. ( mobj_t* special,
  272. mobj_t* toucher )
  273. {
  274. player_t* player;
  275. int i;
  276. fixed_t delta;
  277. int sound;
  278. delta = special->z - toucher->z;
  279. if (delta > toucher->height
  280. || delta < -8*FRACUNIT)
  281. {
  282. // out of reach
  283. return;
  284. }
  285. sound = sfx_itemup;
  286. player = toucher->player;
  287. // Dead thing touching.
  288. // Can happen with a sliding player corpse.
  289. if (toucher->health <= 0)
  290. return;
  291. // Identify by sprite.
  292. switch (special->sprite)
  293. {
  294. // armor
  295. case SPR_ARM1:
  296. if (!P_GiveArmor (player, 1))
  297. return;
  298. player->message = GOTARMOR;
  299. break;
  300. case SPR_ARM2:
  301. if (!P_GiveArmor (player, 2))
  302. return;
  303. player->message = GOTMEGA;
  304. break;
  305. // bonus items
  306. case SPR_BON1:
  307. player->health++; // can go over 100%
  308. if (player->health > 200)
  309. player->health = 200;
  310. player->mo->health = player->health;
  311. player->message = GOTHTHBONUS;
  312. break;
  313. case SPR_BON2:
  314. player->armorpoints++; // can go over 100%
  315. if (player->armorpoints > 200)
  316. player->armorpoints = 200;
  317. if (!player->armortype)
  318. player->armortype = 1;
  319. player->message = GOTARMBONUS;
  320. break;
  321. case SPR_SOUL:
  322. player->health += 100;
  323. if (player->health > 200)
  324. player->health = 200;
  325. player->mo->health = player->health;
  326. player->message = GOTSUPER;
  327. sound = sfx_getpow;
  328. break;
  329. case SPR_MEGA:
  330. if (gamemode != commercial)
  331. return;
  332. player->health = 200;
  333. player->mo->health = player->health;
  334. P_GiveArmor (player,2);
  335. player->message = GOTMSPHERE;
  336. sound = sfx_getpow;
  337. break;
  338. // cards
  339. // leave cards for everyone
  340. case SPR_BKEY:
  341. if (!player->cards[it_bluecard])
  342. player->message = GOTBLUECARD;
  343. P_GiveCard (player, it_bluecard);
  344. if (!netgame)
  345. break;
  346. return;
  347. case SPR_YKEY:
  348. if (!player->cards[it_yellowcard])
  349. player->message = GOTYELWCARD;
  350. P_GiveCard (player, it_yellowcard);
  351. if (!netgame)
  352. break;
  353. return;
  354. case SPR_RKEY:
  355. if (!player->cards[it_redcard])
  356. player->message = GOTREDCARD;
  357. P_GiveCard (player, it_redcard);
  358. if (!netgame)
  359. break;
  360. return;
  361. case SPR_BSKU:
  362. if (!player->cards[it_blueskull])
  363. player->message = GOTBLUESKUL;
  364. P_GiveCard (player, it_blueskull);
  365. if (!netgame)
  366. break;
  367. return;
  368. case SPR_YSKU:
  369. if (!player->cards[it_yellowskull])
  370. player->message = GOTYELWSKUL;
  371. P_GiveCard (player, it_yellowskull);
  372. if (!netgame)
  373. break;
  374. return;
  375. case SPR_RSKU:
  376. if (!player->cards[it_redskull])
  377. player->message = GOTREDSKULL;
  378. P_GiveCard (player, it_redskull);
  379. if (!netgame)
  380. break;
  381. return;
  382. // medikits, heals
  383. case SPR_STIM:
  384. if (!P_GiveBody (player, 10))
  385. return;
  386. player->message = GOTSTIM;
  387. break;
  388. case SPR_MEDI:
  389. if (!P_GiveBody (player, 25))
  390. return;
  391. if (player->health < 25)
  392. player->message = GOTMEDINEED;
  393. else
  394. player->message = GOTMEDIKIT;
  395. break;
  396. // power ups
  397. case SPR_PINV:
  398. if (!P_GivePower (player, pw_invulnerability))
  399. return;
  400. player->message = GOTINVUL;
  401. sound = sfx_getpow;
  402. break;
  403. case SPR_PSTR:
  404. if (!P_GivePower (player, pw_strength))
  405. return;
  406. player->message = GOTBERSERK;
  407. if (player->readyweapon != wp_fist)
  408. player->pendingweapon = wp_fist;
  409. sound = sfx_getpow;
  410. break;
  411. case SPR_PINS:
  412. if (!P_GivePower (player, pw_invisibility))
  413. return;
  414. player->message = GOTINVIS;
  415. sound = sfx_getpow;
  416. break;
  417. case SPR_SUIT:
  418. if (!P_GivePower (player, pw_ironfeet))
  419. return;
  420. player->message = GOTSUIT;
  421. sound = sfx_getpow;
  422. break;
  423. case SPR_PMAP:
  424. if (!P_GivePower (player, pw_allmap))
  425. return;
  426. player->message = GOTMAP;
  427. sound = sfx_getpow;
  428. break;
  429. case SPR_PVIS:
  430. if (!P_GivePower (player, pw_infrared))
  431. return;
  432. player->message = GOTVISOR;
  433. sound = sfx_getpow;
  434. break;
  435. // ammo
  436. case SPR_CLIP:
  437. if (special->flags & MF_DROPPED)
  438. {
  439. if (!P_GiveAmmo (player,am_clip,0))
  440. return;
  441. }
  442. else
  443. {
  444. if (!P_GiveAmmo (player,am_clip,1))
  445. return;
  446. }
  447. player->message = GOTCLIP;
  448. break;
  449. case SPR_AMMO:
  450. if (!P_GiveAmmo (player, am_clip,5))
  451. return;
  452. player->message = GOTCLIPBOX;
  453. break;
  454. case SPR_ROCK:
  455. if (!P_GiveAmmo (player, am_misl,1))
  456. return;
  457. player->message = GOTROCKET;
  458. break;
  459. case SPR_BROK:
  460. if (!P_GiveAmmo (player, am_misl,5))
  461. return;
  462. player->message = GOTROCKBOX;
  463. break;
  464. case SPR_CELL:
  465. if (!P_GiveAmmo (player, am_cell,1))
  466. return;
  467. player->message = GOTCELL;
  468. break;
  469. case SPR_CELP:
  470. if (!P_GiveAmmo (player, am_cell,5))
  471. return;
  472. player->message = GOTCELLBOX;
  473. break;
  474. case SPR_SHEL:
  475. if (!P_GiveAmmo (player, am_shell,1))
  476. return;
  477. player->message = GOTSHELLS;
  478. break;
  479. case SPR_SBOX:
  480. if (!P_GiveAmmo (player, am_shell,5))
  481. return;
  482. player->message = GOTSHELLBOX;
  483. break;
  484. case SPR_BPAK:
  485. if (!player->backpack)
  486. {
  487. for (i=0 ; i<NUMAMMO ; i++)
  488. player->maxammo[i] *= 2;
  489. player->backpack = true;
  490. }
  491. for (i=0 ; i<NUMAMMO ; i++)
  492. P_GiveAmmo (player, i, 1);
  493. player->message = GOTBACKPACK;
  494. break;
  495. // weapons
  496. case SPR_BFUG:
  497. if (!P_GiveWeapon (player, wp_bfg, false) )
  498. return;
  499. player->message = GOTBFG9000;
  500. sound = sfx_wpnup;
  501. break;
  502. case SPR_MGUN:
  503. if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
  504. return;
  505. player->message = GOTCHAINGUN;
  506. sound = sfx_wpnup;
  507. break;
  508. case SPR_CSAW:
  509. if (!P_GiveWeapon (player, wp_chainsaw, false) )
  510. return;
  511. player->message = GOTCHAINSAW;
  512. sound = sfx_wpnup;
  513. break;
  514. case SPR_LAUN:
  515. if (!P_GiveWeapon (player, wp_missile, false) )
  516. return;
  517. player->message = GOTLAUNCHER;
  518. sound = sfx_wpnup;
  519. break;
  520. case SPR_PLAS:
  521. if (!P_GiveWeapon (player, wp_plasma, false) )
  522. return;
  523. player->message = GOTPLASMA;
  524. sound = sfx_wpnup;
  525. break;
  526. case SPR_SHOT:
  527. if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
  528. return;
  529. player->message = GOTSHOTGUN;
  530. sound = sfx_wpnup;
  531. break;
  532. case SPR_SGN2:
  533. if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
  534. return;
  535. player->message = GOTSHOTGUN2;
  536. sound = sfx_wpnup;
  537. break;
  538. default:
  539. I_Error ("P_SpecialThing: Unknown gettable thing");
  540. }
  541. if (special->flags & MF_COUNTITEM)
  542. player->itemcount++;
  543. P_RemoveMobj (special);
  544. player->bonuscount += BONUSADD;
  545. if (player == &players[consoleplayer])
  546. S_StartSound (NULL, sound);
  547. }
  548. //
  549. // KillMobj
  550. //
  551. void
  552. P_KillMobj
  553. ( mobj_t* source,
  554. mobj_t* target )
  555. {
  556. mobjtype_t item;
  557. mobj_t* mo;
  558. target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
  559. if (target->type != MT_SKULL)
  560. target->flags &= ~MF_NOGRAVITY;
  561. target->flags |= MF_CORPSE|MF_DROPOFF;
  562. target->height >>= 2;
  563. if (source && source->player)
  564. {
  565. // count for intermission
  566. if (target->flags & MF_COUNTKILL)
  567. source->player->killcount++;
  568. if (target->player)
  569. source->player->frags[target->player-players]++;
  570. }
  571. else if (!netgame && (target->flags & MF_COUNTKILL) )
  572. {
  573. // count all monster deaths,
  574. // even those caused by other monsters
  575. players[0].killcount++;
  576. }
  577. if (target->player)
  578. {
  579. // count environment kills against you
  580. if (!source)
  581. target->player->frags[target->player-players]++;
  582. target->flags &= ~MF_SOLID;
  583. target->player->playerstate = PST_DEAD;
  584. P_DropWeapon (target->player);
  585. if (target->player == &players[consoleplayer]
  586. && automapactive)
  587. {
  588. // don't die in auto map,
  589. // switch view prior to dying
  590. AM_Stop ();
  591. }
  592. }
  593. if (target->health < -target->info->spawnhealth
  594. && target->info->xdeathstate)
  595. {
  596. P_SetMobjState (target, target->info->xdeathstate);
  597. }
  598. else
  599. P_SetMobjState (target, target->info->deathstate);
  600. target->tics -= P_Random()&3;
  601. if (target->tics < 1)
  602. target->tics = 1;
  603. // I_StartSound (&actor->r, actor->info->deathsound);
  604. // Drop stuff.
  605. // This determines the kind of object spawned
  606. // during the death frame of a thing.
  607. switch (target->type)
  608. {
  609. case MT_WOLFSS:
  610. case MT_POSSESSED:
  611. item = MT_CLIP;
  612. break;
  613. case MT_SHOTGUY:
  614. item = MT_SHOTGUN;
  615. break;
  616. case MT_CHAINGUY:
  617. item = MT_CHAINGUN;
  618. break;
  619. default:
  620. return;
  621. }
  622. mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
  623. mo->flags |= MF_DROPPED; // special versions of items
  624. }
  625. //
  626. // P_DamageMobj
  627. // Damages both enemies and players
  628. // "inflictor" is the thing that caused the damage
  629. // creature or missile, can be NULL (slime, etc)
  630. // "source" is the thing to target after taking damage
  631. // creature or NULL
  632. // Source and inflictor are the same for melee attacks.
  633. // Source can be NULL for slime, barrel explosions
  634. // and other environmental stuff.
  635. //
  636. void
  637. P_DamageMobj
  638. ( mobj_t* target,
  639. mobj_t* inflictor,
  640. mobj_t* source,
  641. int damage )
  642. {
  643. unsigned ang;
  644. int saved;
  645. player_t* player;
  646. fixed_t thrust;
  647. int temp;
  648. if ( !(target->flags & MF_SHOOTABLE) )
  649. return; // shouldn't happen...
  650. if (target->health <= 0)
  651. return;
  652. if ( target->flags & MF_SKULLFLY )
  653. {
  654. target->momx = target->momy = target->momz = 0;
  655. }
  656. player = target->player;
  657. if (player && gameskill == sk_baby)
  658. damage >>= 1; // take half damage in trainer mode
  659. // Some close combat weapons should not
  660. // inflict thrust and push the victim out of reach,
  661. // thus kick away unless using the chainsaw.
  662. if (inflictor
  663. && !(target->flags & MF_NOCLIP)
  664. && (!source
  665. || !source->player
  666. || source->player->readyweapon != wp_chainsaw))
  667. {
  668. ang = R_PointToAngle2 ( inflictor->x,
  669. inflictor->y,
  670. target->x,
  671. target->y);
  672. thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
  673. // make fall forwards sometimes
  674. if ( damage < 40
  675. && damage > target->health
  676. && target->z - inflictor->z > 64*FRACUNIT
  677. && (P_Random ()&1) )
  678. {
  679. ang += ANG180;
  680. thrust *= 4;
  681. }
  682. ang >>= ANGLETOFINESHIFT;
  683. target->momx += FixedMul (thrust, finecosine[ang]);
  684. target->momy += FixedMul (thrust, finesine[ang]);
  685. }
  686. // player specific
  687. if (player)
  688. {
  689. // end of game hell hack
  690. if (target->subsector->sector->special == 11
  691. && damage >= target->health)
  692. {
  693. damage = target->health - 1;
  694. }
  695. // Below certain threshold,
  696. // ignore damage in GOD mode, or with INVUL power.
  697. if ( damage < 1000
  698. && ( (player->cheats&CF_GODMODE)
  699. || player->powers[pw_invulnerability] ) )
  700. {
  701. return;
  702. }
  703. if (player->armortype)
  704. {
  705. if (player->armortype == 1)
  706. saved = damage/3;
  707. else
  708. saved = damage/2;
  709. if (player->armorpoints <= saved)
  710. {
  711. // armor is used up
  712. saved = player->armorpoints;
  713. player->armortype = 0;
  714. }
  715. player->armorpoints -= saved;
  716. damage -= saved;
  717. }
  718. player->health -= damage; // mirror mobj health here for Dave
  719. if (player->health < 0)
  720. player->health = 0;
  721. player->attacker = source;
  722. player->damagecount += damage; // add damage after armor / invuln
  723. if (player->damagecount > 100)
  724. player->damagecount = 100; // teleport stomp does 10k points...
  725. temp = damage < 100 ? damage : 100;
  726. if (player == &players[consoleplayer])
  727. I_Tactile (40,10,40+temp*2);
  728. }
  729. // do the damage
  730. target->health -= damage;
  731. if (target->health <= 0)
  732. {
  733. P_KillMobj (source, target);
  734. return;
  735. }
  736. if ( (P_Random () < target->info->painchance)
  737. && !(target->flags&MF_SKULLFLY) )
  738. {
  739. target->flags |= MF_JUSTHIT; // fight back!
  740. P_SetMobjState (target, target->info->painstate);
  741. }
  742. target->reactiontime = 0; // we're awake now...
  743. if ( (!target->threshold || target->type == MT_VILE)
  744. && source && source != target
  745. && source->type != MT_VILE)
  746. {
  747. // if not intent on another player,
  748. // chase after this one
  749. target->target = source;
  750. target->threshold = BASETHRESHOLD;
  751. if (target->state == &states[target->info->spawnstate]
  752. && target->info->seestate != S_NULL)
  753. P_SetMobjState (target, target->info->seestate);
  754. }
  755. }