P_INTER.C 33 KB

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