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

射击游戏

开发平台:

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. // Weapon sprite animation, weapon objects.
  21. // Action functions for weapons.
  22. //
  23. //-----------------------------------------------------------------------------
  24. static const char
  25. rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
  26. #include "doomdef.h"
  27. #include "d_event.h"
  28. #include "m_random.h"
  29. #include "p_local.h"
  30. #include "s_sound.h"
  31. // State.
  32. #include "doomstat.h"
  33. // Data.
  34. #include "sounds.h"
  35. #include "p_pspr.h"
  36. #define LOWERSPEED FRACUNIT*6
  37. #define RAISESPEED FRACUNIT*6
  38. #define WEAPONBOTTOM 128*FRACUNIT
  39. #define WEAPONTOP 32*FRACUNIT
  40. // plasma cells for a bfg attack
  41. #define BFGCELLS 40
  42. //
  43. // P_SetPsprite
  44. //
  45. void
  46. P_SetPsprite
  47. ( player_t* player,
  48.   int position,
  49.   statenum_t stnum ) 
  50. {
  51.     pspdef_t* psp;
  52.     state_t* state;
  53.     psp = &player->psprites[position];
  54.     do
  55.     {
  56. if (!stnum)
  57. {
  58.     // object removed itself
  59.     psp->state = NULL;
  60.     break;
  61. }
  62. state = &states[stnum];
  63. psp->state = state;
  64. psp->tics = state->tics; // could be 0
  65. if (state->misc1)
  66. {
  67.     // coordinate set
  68.     psp->sx = state->misc1 << FRACBITS;
  69.     psp->sy = state->misc2 << FRACBITS;
  70. }
  71. // Call action routine.
  72. // Modified handling.
  73. if (state->action.acp2)
  74. {
  75.     state->action.acp2(player, psp);
  76.     if (!psp->state)
  77. break;
  78. }
  79. stnum = psp->state->nextstate;
  80.     } while (!psp->tics);
  81.     // an initial state of 0 could cycle through
  82. }
  83. //
  84. // P_CalcSwing
  85. //
  86. fixed_t swingx;
  87. fixed_t swingy;
  88. void P_CalcSwing (player_t* player)
  89. {
  90.     fixed_t swing;
  91.     int angle;
  92.     // OPTIMIZE: tablify this.
  93.     // A LUT would allow for different modes,
  94.     //  and add flexibility.
  95.     swing = player->bob;
  96.     angle = (FINEANGLES/70*leveltime)&FINEMASK;
  97.     swingx = FixedMul ( swing, finesine[angle]);
  98.     angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
  99.     swingy = -FixedMul ( swingx, finesine[angle]);
  100. }
  101. //
  102. // P_BringUpWeapon
  103. // Starts bringing the pending weapon up
  104. // from the bottom of the screen.
  105. // Uses player
  106. //
  107. void P_BringUpWeapon (player_t* player)
  108. {
  109.     statenum_t newstate;
  110.     if (player->pendingweapon == wp_nochange)
  111. player->pendingweapon = player->readyweapon;
  112.     if (player->pendingweapon == wp_chainsaw)
  113. S_StartSound (player->mo, sfx_sawup);
  114.     newstate = weaponinfo[player->pendingweapon].upstate;
  115.     player->pendingweapon = wp_nochange;
  116.     player->psprites[ps_weapon].sy = WEAPONBOTTOM; 
  117.     P_SetPsprite (player, ps_weapon, newstate);
  118. }
  119. //
  120. // P_CheckAmmo
  121. // Returns true if there is enough ammo to shoot.
  122. // If not, selects the next weapon to use.
  123. //
  124. boolean P_CheckAmmo (player_t* player)
  125. {
  126.     ammotype_t ammo;
  127.     int count;
  128.     ammo = weaponinfo[player->readyweapon].ammo;
  129.     // Minimal amount for one shot varies.
  130.     if (player->readyweapon == wp_bfg)
  131. count = BFGCELLS;
  132.     else if (player->readyweapon == wp_supershotgun)
  133. count = 2; // Double barrel.
  134.     else
  135. count = 1; // Regular.
  136.     // Some do not need ammunition anyway.
  137.     // Return if current ammunition sufficient.
  138.     if (ammo == am_noammo || player->ammo[ammo] >= count)
  139. return true;
  140.     // Out of ammo, pick a weapon to change to.
  141.     // Preferences are set here.
  142.     do
  143.     {
  144. if (player->weaponowned[wp_plasma]
  145.     && player->ammo[am_cell]
  146.     && (gamemode != shareware) )
  147. {
  148.     player->pendingweapon = wp_plasma;
  149. }
  150. else if (player->weaponowned[wp_supershotgun] 
  151.  && player->ammo[am_shell]>2
  152.  && (gamemode == commercial) )
  153. {
  154.     player->pendingweapon = wp_supershotgun;
  155. }
  156. else if (player->weaponowned[wp_chaingun]
  157.  && player->ammo[am_clip])
  158. {
  159.     player->pendingweapon = wp_chaingun;
  160. }
  161. else if (player->weaponowned[wp_shotgun]
  162.  && player->ammo[am_shell])
  163. {
  164.     player->pendingweapon = wp_shotgun;
  165. }
  166. else if (player->ammo[am_clip])
  167. {
  168.     player->pendingweapon = wp_pistol;
  169. }
  170. else if (player->weaponowned[wp_chainsaw])
  171. {
  172.     player->pendingweapon = wp_chainsaw;
  173. }
  174. else if (player->weaponowned[wp_missile]
  175.  && player->ammo[am_misl])
  176. {
  177.     player->pendingweapon = wp_missile;
  178. }
  179. else if (player->weaponowned[wp_bfg]
  180.  && player->ammo[am_cell]>40
  181.  && (gamemode != shareware) )
  182. {
  183.     player->pendingweapon = wp_bfg;
  184. }
  185. else
  186. {
  187.     // If everything fails.
  188.     player->pendingweapon = wp_fist;
  189. }
  190.     } while (player->pendingweapon == wp_nochange);
  191.     // Now set appropriate weapon overlay.
  192.     P_SetPsprite (player,
  193.   ps_weapon,
  194.   weaponinfo[player->readyweapon].downstate);
  195.     return false;
  196. }
  197. //
  198. // P_FireWeapon.
  199. //
  200. void P_FireWeapon (player_t* player)
  201. {
  202.     statenum_t newstate;
  203.     if (!P_CheckAmmo (player))
  204. return;
  205.     P_SetMobjState (player->mo, S_PLAY_ATK1);
  206.     newstate = weaponinfo[player->readyweapon].atkstate;
  207.     P_SetPsprite (player, ps_weapon, newstate);
  208.     P_NoiseAlert (player->mo, player->mo);
  209. }
  210. //
  211. // P_DropWeapon
  212. // Player died, so put the weapon away.
  213. //
  214. void P_DropWeapon (player_t* player)
  215. {
  216.     P_SetPsprite (player,
  217.   ps_weapon,
  218.   weaponinfo[player->readyweapon].downstate);
  219. }
  220. //
  221. // A_WeaponReady
  222. // The player can fire the weapon
  223. // or change to another weapon at this time.
  224. // Follows after getting weapon up,
  225. // or after previous attack/fire sequence.
  226. //
  227. void
  228. A_WeaponReady
  229. ( player_t* player,
  230.   pspdef_t* psp )
  231. {
  232.     statenum_t newstate;
  233.     int angle;
  234.     
  235.     // get out of attack state
  236.     if (player->mo->state == &states[S_PLAY_ATK1]
  237. || player->mo->state == &states[S_PLAY_ATK2] )
  238.     {
  239. P_SetMobjState (player->mo, S_PLAY);
  240.     }
  241.     
  242.     if (player->readyweapon == wp_chainsaw
  243. && psp->state == &states[S_SAW])
  244.     {
  245. S_StartSound (player->mo, sfx_sawidl);
  246.     }
  247.     
  248.     // check for change
  249.     //  if player is dead, put the weapon away
  250.     if (player->pendingweapon != wp_nochange || !player->health)
  251.     {
  252. // change weapon
  253. //  (pending weapon should allready be validated)
  254. newstate = weaponinfo[player->readyweapon].downstate;
  255. P_SetPsprite (player, ps_weapon, newstate);
  256. return;
  257.     }
  258.     
  259.     // check for fire
  260.     //  the missile launcher and bfg do not auto fire
  261.     if (player->cmd.buttons & BT_ATTACK)
  262.     {
  263. if ( !player->attackdown
  264.      || (player->readyweapon != wp_missile
  265.  && player->readyweapon != wp_bfg) )
  266. {
  267.     player->attackdown = true;
  268.     P_FireWeapon (player);
  269.     return;
  270. }
  271.     }
  272.     else
  273. player->attackdown = false;
  274.     
  275.     // bob the weapon based on movement speed
  276.     angle = (128*leveltime)&FINEMASK;
  277.     psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]);
  278.     angle &= FINEANGLES/2-1;
  279.     psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]);
  280. }
  281. //
  282. // A_ReFire
  283. // The player can re-fire the weapon
  284. // without lowering it entirely.
  285. //
  286. void A_ReFire
  287. ( player_t* player,
  288.   pspdef_t* psp )
  289. {
  290.     
  291.     // check for fire
  292.     //  (if a weaponchange is pending, let it go through instead)
  293.     if ( (player->cmd.buttons & BT_ATTACK) 
  294.  && player->pendingweapon == wp_nochange
  295.  && player->health)
  296.     {
  297. player->refire++;
  298. P_FireWeapon (player);
  299.     }
  300.     else
  301.     {
  302. player->refire = 0;
  303. P_CheckAmmo (player);
  304.     }
  305. }
  306. void
  307. A_CheckReload
  308. ( player_t* player,
  309.   pspdef_t* psp )
  310. {
  311.     P_CheckAmmo (player);
  312. #if 0
  313.     if (player->ammo[am_shell]<2)
  314. P_SetPsprite (player, ps_weapon, S_DSNR1);
  315. #endif
  316. }
  317. //
  318. // A_Lower
  319. // Lowers current weapon,
  320. //  and changes weapon at bottom.
  321. //
  322. void
  323. A_Lower
  324. ( player_t* player,
  325.   pspdef_t* psp )
  326. {
  327.     psp->sy += LOWERSPEED;
  328.     // Is already down.
  329.     if (psp->sy < WEAPONBOTTOM )
  330. return;
  331.     // Player is dead.
  332.     if (player->playerstate == PST_DEAD)
  333.     {
  334. psp->sy = WEAPONBOTTOM;
  335. // don't bring weapon back up
  336. return;
  337.     }
  338.     
  339.     // The old weapon has been lowered off the screen,
  340.     // so change the weapon and start raising it
  341.     if (!player->health)
  342.     {
  343. // Player is dead, so keep the weapon off screen.
  344. P_SetPsprite (player,  ps_weapon, S_NULL);
  345. return;
  346.     }
  347.     player->readyweapon = player->pendingweapon; 
  348.     P_BringUpWeapon (player);
  349. }
  350. //
  351. // A_Raise
  352. //
  353. void
  354. A_Raise
  355. ( player_t* player,
  356.   pspdef_t* psp )
  357. {
  358.     statenum_t newstate;
  359.     psp->sy -= RAISESPEED;
  360.     if (psp->sy > WEAPONTOP )
  361. return;
  362.     
  363.     psp->sy = WEAPONTOP;
  364.     
  365.     // The weapon has been raised all the way,
  366.     //  so change to the ready state.
  367.     newstate = weaponinfo[player->readyweapon].readystate;
  368.     P_SetPsprite (player, ps_weapon, newstate);
  369. }
  370. //
  371. // A_GunFlash
  372. //
  373. void
  374. A_GunFlash
  375. ( player_t* player,
  376.   pspdef_t* psp ) 
  377. {
  378.     P_SetMobjState (player->mo, S_PLAY_ATK2);
  379.     P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
  380. }
  381. //
  382. // WEAPON ATTACKS
  383. //
  384. //
  385. // A_Punch
  386. //
  387. void
  388. A_Punch
  389. ( player_t* player,
  390.   pspdef_t* psp ) 
  391. {
  392.     angle_t angle;
  393.     int damage;
  394.     int slope;
  395.     damage = (P_Random ()%10+1)<<1;
  396.     if (player->powers[pw_strength])
  397. damage *= 10;
  398.     angle = player->mo->angle;
  399.     angle += (P_Random()-P_Random())<<18;
  400.     slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
  401.     P_LineAttack (player->mo, angle, MELEERANGE, slope, damage);
  402.     // turn to face target
  403.     if (linetarget)
  404.     {
  405. S_StartSound (player->mo, sfx_punch);
  406. player->mo->angle = R_PointToAngle2 (player->mo->x,
  407.      player->mo->y,
  408.      linetarget->x,
  409.      linetarget->y);
  410.     }
  411. }
  412. //
  413. // A_Saw
  414. //
  415. void
  416. A_Saw
  417. ( player_t* player,
  418.   pspdef_t* psp ) 
  419. {
  420.     angle_t angle;
  421.     int damage;
  422.     int slope;
  423.     damage = 2*(P_Random ()%10+1);
  424.     angle = player->mo->angle;
  425.     angle += (P_Random()-P_Random())<<18;
  426.     
  427.     // use meleerange + 1 se the puff doesn't skip the flash
  428.     slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1);
  429.     P_LineAttack (player->mo, angle, MELEERANGE+1, slope, damage);
  430.     if (!linetarget)
  431.     {
  432. S_StartSound (player->mo, sfx_sawful);
  433. return;
  434.     }
  435.     S_StartSound (player->mo, sfx_sawhit);
  436.     // turn to face target
  437.     angle = R_PointToAngle2 (player->mo->x, player->mo->y,
  438.      linetarget->x, linetarget->y);
  439.     if (angle - player->mo->angle > ANG180)
  440.     {
  441. if (angle - player->mo->angle < -ANG90/20)
  442.     player->mo->angle = angle + ANG90/21;
  443. else
  444.     player->mo->angle -= ANG90/20;
  445.     }
  446.     else
  447.     {
  448. if (angle - player->mo->angle > ANG90/20)
  449.     player->mo->angle = angle - ANG90/21;
  450. else
  451.     player->mo->angle += ANG90/20;
  452.     }
  453.     player->mo->flags |= MF_JUSTATTACKED;
  454. }
  455. //
  456. // A_FireMissile
  457. //
  458. void
  459. A_FireMissile
  460. ( player_t* player,
  461.   pspdef_t* psp ) 
  462. {
  463.     player->ammo[weaponinfo[player->readyweapon].ammo]--;
  464.     P_SpawnPlayerMissile (player->mo, MT_ROCKET);
  465. }
  466. //
  467. // A_FireBFG
  468. //
  469. void
  470. A_FireBFG
  471. ( player_t* player,
  472.   pspdef_t* psp ) 
  473. {
  474.     player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
  475.     P_SpawnPlayerMissile (player->mo, MT_BFG);
  476. }
  477. //
  478. // A_FirePlasma
  479. //
  480. void
  481. A_FirePlasma
  482. ( player_t* player,
  483.   pspdef_t* psp ) 
  484. {
  485.     player->ammo[weaponinfo[player->readyweapon].ammo]--;
  486.     P_SetPsprite (player,
  487.   ps_flash,
  488.   weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) );
  489.     P_SpawnPlayerMissile (player->mo, MT_PLASMA);
  490. }
  491. //
  492. // P_BulletSlope
  493. // Sets a slope so a near miss is at aproximately
  494. // the height of the intended target
  495. //
  496. fixed_t bulletslope;
  497. void P_BulletSlope (mobj_t* mo)
  498. {
  499.     angle_t an;
  500.     
  501.     // see which target is to be aimed at
  502.     an = mo->angle;
  503.     bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  504.     if (!linetarget)
  505.     {
  506. an += 1<<26;
  507. bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  508. if (!linetarget)
  509. {
  510.     an -= 2<<26;
  511.     bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  512. }
  513.     }
  514. }
  515. //
  516. // P_GunShot
  517. //
  518. void
  519. P_GunShot
  520. ( mobj_t* mo,
  521.   boolean accurate )
  522. {
  523.     angle_t angle;
  524.     int damage;
  525.     damage = 5*(P_Random ()%3+1);
  526.     angle = mo->angle;
  527.     if (!accurate)
  528. angle += (P_Random()-P_Random())<<18;
  529.     P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
  530. }
  531. //
  532. // A_FirePistol
  533. //
  534. void
  535. A_FirePistol
  536. ( player_t* player,
  537.   pspdef_t* psp ) 
  538. {
  539.     S_StartSound (player->mo, sfx_pistol);
  540.     P_SetMobjState (player->mo, S_PLAY_ATK2);
  541.     player->ammo[weaponinfo[player->readyweapon].ammo]--;
  542.     P_SetPsprite (player,
  543.   ps_flash,
  544.   weaponinfo[player->readyweapon].flashstate);
  545.     P_BulletSlope (player->mo);
  546.     P_GunShot (player->mo, !player->refire);
  547. }
  548. //
  549. // A_FireShotgun
  550. //
  551. void
  552. A_FireShotgun
  553. ( player_t* player,
  554.   pspdef_t* psp ) 
  555. {
  556.     int i;
  557.     S_StartSound (player->mo, sfx_shotgn);
  558.     P_SetMobjState (player->mo, S_PLAY_ATK2);
  559.     player->ammo[weaponinfo[player->readyweapon].ammo]--;
  560.     P_SetPsprite (player,
  561.   ps_flash,
  562.   weaponinfo[player->readyweapon].flashstate);
  563.     P_BulletSlope (player->mo);
  564.     for (i=0 ; i<7 ; i++)
  565. P_GunShot (player->mo, false);
  566. }
  567. //
  568. // A_FireShotgun2
  569. //
  570. void
  571. A_FireShotgun2
  572. ( player_t* player,
  573.   pspdef_t* psp ) 
  574. {
  575.     int i;
  576.     angle_t angle;
  577.     int damage;
  578.     S_StartSound (player->mo, sfx_dshtgn);
  579.     P_SetMobjState (player->mo, S_PLAY_ATK2);
  580.     player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
  581.     P_SetPsprite (player,
  582.   ps_flash,
  583.   weaponinfo[player->readyweapon].flashstate);
  584.     P_BulletSlope (player->mo);
  585.     for (i=0 ; i<20 ; i++)
  586.     {
  587. damage = 5*(P_Random ()%3+1);
  588. angle = player->mo->angle;
  589. angle += (P_Random()-P_Random())<<19;
  590. P_LineAttack (player->mo,
  591.       angle,
  592.       MISSILERANGE,
  593.       bulletslope + ((P_Random()-P_Random())<<5), damage);
  594.     }
  595. }
  596. //
  597. // A_FireCGun
  598. //
  599. void
  600. A_FireCGun
  601. ( player_t* player,
  602.   pspdef_t* psp ) 
  603. {
  604.     S_StartSound (player->mo, sfx_pistol);
  605.     if (!player->ammo[weaponinfo[player->readyweapon].ammo])
  606. return;
  607.     P_SetMobjState (player->mo, S_PLAY_ATK2);
  608.     player->ammo[weaponinfo[player->readyweapon].ammo]--;
  609.     P_SetPsprite (player,
  610.   ps_flash,
  611.   weaponinfo[player->readyweapon].flashstate
  612.   + psp->state
  613.   - &states[S_CHAIN1] );
  614.     P_BulletSlope (player->mo);
  615.     P_GunShot (player->mo, !player->refire);
  616. }
  617. //
  618. // ?
  619. //
  620. void A_Light0 (player_t *player, pspdef_t *psp)
  621. {
  622.     player->extralight = 0;
  623. }
  624. void A_Light1 (player_t *player, pspdef_t *psp)
  625. {
  626.     player->extralight = 1;
  627. }
  628. void A_Light2 (player_t *player, pspdef_t *psp)
  629. {
  630.     player->extralight = 2;
  631. }
  632. //
  633. // A_BFGSpray
  634. // Spawn a BFG explosion on every monster in view
  635. //
  636. void A_BFGSpray (mobj_t* mo) 
  637. {
  638.     int i;
  639.     int j;
  640.     int damage;
  641.     angle_t an;
  642.     // offset angles from its attack angle
  643.     for (i=0 ; i<40 ; i++)
  644.     {
  645. an = mo->angle - ANG90/2 + ANG90/40*i;
  646. // mo->target is the originator (player)
  647. //  of the missile
  648. P_AimLineAttack (mo->target, an, 16*64*FRACUNIT);
  649. if (!linetarget)
  650.     continue;
  651. P_SpawnMobj (linetarget->x,
  652.      linetarget->y,
  653.      linetarget->z + (linetarget->height>>2),
  654.      MT_EXTRABFG);
  655. damage = 0;
  656. for (j=0;j<15;j++)
  657.     damage += (P_Random()&7) + 1;
  658. P_DamageMobj (linetarget, mo->target,mo->target, damage);
  659.     }
  660. }
  661. //
  662. // A_BFGsound
  663. //
  664. void
  665. A_BFGsound
  666. ( player_t* player,
  667.   pspdef_t* psp )
  668. {
  669.     S_StartSound (player->mo, sfx_bfg);
  670. }
  671. //
  672. // P_SetupPsprites
  673. // Called at start of level for each player.
  674. //
  675. void P_SetupPsprites (player_t* player) 
  676. {
  677.     int i;
  678.     // remove all psprites
  679.     for (i=0 ; i<NUMPSPRITES ; i++)
  680. player->psprites[i].state = NULL;
  681.     // spawn the gun
  682.     player->pendingweapon = player->readyweapon;
  683.     P_BringUpWeapon (player);
  684. }
  685. //
  686. // P_MovePsprites
  687. // Called every tic by player thinking routine.
  688. //
  689. void P_MovePsprites (player_t* player) 
  690. {
  691.     int i;
  692.     pspdef_t* psp;
  693.     state_t* state;
  694.     psp = &player->psprites[0];
  695.     for (i=0 ; i<NUMPSPRITES ; i++, psp++)
  696.     {
  697. // a null state means not active
  698. if ( (state = psp->state) )
  699. {
  700.     // drop tic count and possibly change state
  701.     // a -1 tic count never changes
  702.     if (psp->tics != -1)
  703.     {
  704. psp->tics--;
  705. if (!psp->tics)
  706.     P_SetPsprite (player, i, psp->state->nextstate);
  707.     }
  708. }
  709.     }
  710.     
  711.     player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
  712.     player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
  713. }