p_inter.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:19k
源码类别:

射击游戏

开发平台:

Visual C++

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