p_pspr.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  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. // get out of attack state
  235. if (player->mo->state == &states[S_PLAY_ATK1]
  236. || player->mo->state == &states[S_PLAY_ATK2] )
  237. {
  238. P_SetMobjState (player->mo, S_PLAY);
  239. }
  240. if (player->readyweapon == wp_chainsaw
  241. && psp->state == &states[S_SAW])
  242. {
  243. S_StartSound (player->mo, sfx_sawidl);
  244. }
  245. // check for change
  246. // if player is dead, put the weapon away
  247. if (player->pendingweapon != wp_nochange || !player->health)
  248. {
  249. // change weapon
  250. // (pending weapon should allready be validated)
  251. newstate = weaponinfo[player->readyweapon].downstate;
  252. P_SetPsprite (player, ps_weapon, newstate);
  253. return;
  254. }
  255. // check for fire
  256. // the missile launcher and bfg do not auto fire
  257. if (player->cmd.buttons & BT_ATTACK)
  258. {
  259. if ( !player->attackdown
  260. || (player->readyweapon != wp_missile
  261. && player->readyweapon != wp_bfg) )
  262. {
  263. player->attackdown = true;
  264. P_FireWeapon (player);
  265. return;
  266. }
  267. }
  268. else
  269. player->attackdown = false;
  270. // bob the weapon based on movement speed
  271. angle = (128*leveltime)&FINEMASK;
  272. psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]);
  273. angle &= FINEANGLES/2-1;
  274. psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]);
  275. }
  276. //
  277. // A_ReFire
  278. // The player can re-fire the weapon
  279. // without lowering it entirely.
  280. //
  281. void A_ReFire
  282. ( player_t* player,
  283. pspdef_t* psp )
  284. {
  285. // check for fire
  286. // (if a weaponchange is pending, let it go through instead)
  287. if ( (player->cmd.buttons & BT_ATTACK)
  288. && player->pendingweapon == wp_nochange
  289. && player->health)
  290. {
  291. player->refire++;
  292. P_FireWeapon (player);
  293. }
  294. else
  295. {
  296. player->refire = 0;
  297. P_CheckAmmo (player);
  298. }
  299. }
  300. void
  301. A_CheckReload
  302. ( player_t* player,
  303. pspdef_t* psp )
  304. {
  305. P_CheckAmmo (player);
  306. #if 0
  307. if (player->ammo[am_shell]<2)
  308. P_SetPsprite (player, ps_weapon, S_DSNR1);
  309. #endif
  310. }
  311. //
  312. // A_Lower
  313. // Lowers current weapon,
  314. // and changes weapon at bottom.
  315. //
  316. void
  317. A_Lower
  318. ( player_t* player,
  319. pspdef_t* psp )
  320. {
  321. psp->sy += LOWERSPEED;
  322. // Is already down.
  323. if (psp->sy < WEAPONBOTTOM )
  324. return;
  325. // Player is dead.
  326. if (player->playerstate == PST_DEAD)
  327. {
  328. psp->sy = WEAPONBOTTOM;
  329. // don't bring weapon back up
  330. return;
  331. }
  332. // The old weapon has been lowered off the screen,
  333. // so change the weapon and start raising it
  334. if (!player->health)
  335. {
  336. // Player is dead, so keep the weapon off screen.
  337. P_SetPsprite (player, ps_weapon, S_NULL);
  338. return;
  339. }
  340. player->readyweapon = player->pendingweapon;
  341. P_BringUpWeapon (player);
  342. }
  343. //
  344. // A_Raise
  345. //
  346. void
  347. A_Raise
  348. ( player_t* player,
  349. pspdef_t* psp )
  350. {
  351. statenum_t newstate;
  352. psp->sy -= RAISESPEED;
  353. if (psp->sy > WEAPONTOP )
  354. return;
  355. psp->sy = WEAPONTOP;
  356. // The weapon has been raised all the way,
  357. // so change to the ready state.
  358. newstate = weaponinfo[player->readyweapon].readystate;
  359. P_SetPsprite (player, ps_weapon, newstate);
  360. }
  361. //
  362. // A_GunFlash
  363. //
  364. void
  365. A_GunFlash
  366. ( player_t* player,
  367. pspdef_t* psp )
  368. {
  369. P_SetMobjState (player->mo, S_PLAY_ATK2);
  370. P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
  371. }
  372. //
  373. // WEAPON ATTACKS
  374. //
  375. //
  376. // A_Punch
  377. //
  378. void
  379. A_Punch
  380. ( player_t* player,
  381. pspdef_t* psp )
  382. {
  383. angle_t angle;
  384. int damage;
  385. int slope;
  386. damage = (P_Random ()%10+1)<<1;
  387. if (player->powers[pw_strength])
  388. damage *= 10;
  389. angle = player->mo->angle;
  390. angle += (P_Random()-P_Random())<<18;
  391. slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
  392. P_LineAttack (player->mo, angle, MELEERANGE, slope, damage);
  393. // turn to face target
  394. if (linetarget)
  395. {
  396. S_StartSound (player->mo, sfx_punch);
  397. player->mo->angle = R_PointToAngle2 (player->mo->x,
  398. player->mo->y,
  399. linetarget->x,
  400. linetarget->y);
  401. }
  402. }
  403. //
  404. // A_Saw
  405. //
  406. void
  407. A_Saw
  408. ( player_t* player,
  409. pspdef_t* psp )
  410. {
  411. angle_t angle;
  412. int damage;
  413. int slope;
  414. damage = 2*(P_Random ()%10+1);
  415. angle = player->mo->angle;
  416. angle += (P_Random()-P_Random())<<18;
  417. // use meleerange + 1 se the puff doesn't skip the flash
  418. slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1);
  419. P_LineAttack (player->mo, angle, MELEERANGE+1, slope, damage);
  420. if (!linetarget)
  421. {
  422. S_StartSound (player->mo, sfx_sawful);
  423. return;
  424. }
  425. S_StartSound (player->mo, sfx_sawhit);
  426. // turn to face target
  427. angle = R_PointToAngle2 (player->mo->x, player->mo->y,
  428. linetarget->x, linetarget->y);
  429. if (angle - player->mo->angle > ANG180)
  430. {
  431. if (angle - player->mo->angle < -ANG90/20)
  432. player->mo->angle = angle + ANG90/21;
  433. else
  434. player->mo->angle -= ANG90/20;
  435. }
  436. else
  437. {
  438. if (angle - player->mo->angle > ANG90/20)
  439. player->mo->angle = angle - ANG90/21;
  440. else
  441. player->mo->angle += ANG90/20;
  442. }
  443. player->mo->flags |= MF_JUSTATTACKED;
  444. }
  445. //
  446. // A_FireMissile
  447. //
  448. void
  449. A_FireMissile
  450. ( player_t* player,
  451. pspdef_t* psp )
  452. {
  453. player->ammo[weaponinfo[player->readyweapon].ammo]--;
  454. P_SpawnPlayerMissile (player->mo, MT_ROCKET);
  455. }
  456. //
  457. // A_FireBFG
  458. //
  459. void
  460. A_FireBFG
  461. ( player_t* player,
  462. pspdef_t* psp )
  463. {
  464. player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
  465. P_SpawnPlayerMissile (player->mo, MT_BFG);
  466. }
  467. //
  468. // A_FirePlasma
  469. //
  470. void
  471. A_FirePlasma
  472. ( player_t* player,
  473. pspdef_t* psp )
  474. {
  475. player->ammo[weaponinfo[player->readyweapon].ammo]--;
  476. P_SetPsprite (player,
  477. ps_flash,
  478. weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) );
  479. P_SpawnPlayerMissile (player->mo, MT_PLASMA);
  480. }
  481. //
  482. // P_BulletSlope
  483. // Sets a slope so a near miss is at aproximately
  484. // the height of the intended target
  485. //
  486. fixed_t bulletslope;
  487. void P_BulletSlope (mobj_t* mo)
  488. {
  489. angle_t an;
  490. // see which target is to be aimed at
  491. an = mo->angle;
  492. bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  493. if (!linetarget)
  494. {
  495. an += 1<<26;
  496. bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  497. if (!linetarget)
  498. {
  499. an -= 2<<26;
  500. bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  501. }
  502. }
  503. }
  504. //
  505. // P_GunShot
  506. //
  507. void
  508. P_GunShot
  509. ( mobj_t* mo,
  510. boolean accurate )
  511. {
  512. angle_t angle;
  513. int damage;
  514. damage = 5*(P_Random ()%3+1);
  515. angle = mo->angle;
  516. if (!accurate)
  517. angle += (P_Random()-P_Random())<<18;
  518. P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
  519. }
  520. //
  521. // A_FirePistol
  522. //
  523. void
  524. A_FirePistol
  525. ( player_t* player,
  526. pspdef_t* psp )
  527. {
  528. S_StartSound (player->mo, sfx_pistol);
  529. P_SetMobjState (player->mo, S_PLAY_ATK2);
  530. player->ammo[weaponinfo[player->readyweapon].ammo]--;
  531. P_SetPsprite (player,
  532. ps_flash,
  533. weaponinfo[player->readyweapon].flashstate);
  534. P_BulletSlope (player->mo);
  535. P_GunShot (player->mo, !player->refire);
  536. }
  537. //
  538. // A_FireShotgun
  539. //
  540. void
  541. A_FireShotgun
  542. ( player_t* player,
  543. pspdef_t* psp )
  544. {
  545. int i;
  546. S_StartSound (player->mo, sfx_shotgn);
  547. P_SetMobjState (player->mo, S_PLAY_ATK2);
  548. player->ammo[weaponinfo[player->readyweapon].ammo]--;
  549. P_SetPsprite (player,
  550. ps_flash,
  551. weaponinfo[player->readyweapon].flashstate);
  552. P_BulletSlope (player->mo);
  553. for (i=0 ; i<7 ; i++)
  554. P_GunShot (player->mo, false);
  555. }
  556. //
  557. // A_FireShotgun2
  558. //
  559. void
  560. A_FireShotgun2
  561. ( player_t* player,
  562. pspdef_t* psp )
  563. {
  564. int i;
  565. angle_t angle;
  566. int damage;
  567. S_StartSound (player->mo, sfx_dshtgn);
  568. P_SetMobjState (player->mo, S_PLAY_ATK2);
  569. player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
  570. P_SetPsprite (player,
  571. ps_flash,
  572. weaponinfo[player->readyweapon].flashstate);
  573. P_BulletSlope (player->mo);
  574. for (i=0 ; i<20 ; i++)
  575. {
  576. damage = 5*(P_Random ()%3+1);
  577. angle = player->mo->angle;
  578. angle += (P_Random()-P_Random())<<19;
  579. P_LineAttack (player->mo,
  580. angle,
  581. MISSILERANGE,
  582. bulletslope + ((P_Random()-P_Random())<<5), damage);
  583. }
  584. }
  585. //
  586. // A_FireCGun
  587. //
  588. void
  589. A_FireCGun
  590. ( player_t* player,
  591. pspdef_t* psp )
  592. {
  593. S_StartSound (player->mo, sfx_pistol);
  594. if (!player->ammo[weaponinfo[player->readyweapon].ammo])
  595. return;
  596. P_SetMobjState (player->mo, S_PLAY_ATK2);
  597. player->ammo[weaponinfo[player->readyweapon].ammo]--;
  598. P_SetPsprite (player,
  599. ps_flash,
  600. weaponinfo[player->readyweapon].flashstate
  601. + psp->state
  602. - &states[S_CHAIN1] );
  603. P_BulletSlope (player->mo);
  604. P_GunShot (player->mo, !player->refire);
  605. }
  606. //
  607. // ?
  608. //
  609. void A_Light0 (player_t *player, pspdef_t *psp)
  610. {
  611. player->extralight = 0;
  612. }
  613. void A_Light1 (player_t *player, pspdef_t *psp)
  614. {
  615. player->extralight = 1;
  616. }
  617. void A_Light2 (player_t *player, pspdef_t *psp)
  618. {
  619. player->extralight = 2;
  620. }
  621. //
  622. // A_BFGSpray
  623. // Spawn a BFG explosion on every monster in view
  624. //
  625. void A_BFGSpray (mobj_t* mo)
  626. {
  627. int i;
  628. int j;
  629. int damage;
  630. angle_t an;
  631. // offset angles from its attack angle
  632. for (i=0 ; i<40 ; i++)
  633. {
  634. an = mo->angle - ANG90/2 + ANG90/40*i;
  635. // mo->target is the originator (player)
  636. // of the missile
  637. P_AimLineAttack (mo->target, an, 16*64*FRACUNIT);
  638. if (!linetarget)
  639. continue;
  640. P_SpawnMobj (linetarget->x,
  641. linetarget->y,
  642. linetarget->z + (linetarget->height>>2),
  643. MT_EXTRABFG);
  644. damage = 0;
  645. for (j=0;j<15;j++)
  646. damage += (P_Random()&7) + 1;
  647. P_DamageMobj (linetarget, mo->target,mo->target, damage);
  648. }
  649. }
  650. //
  651. // A_BFGsound
  652. //
  653. void
  654. A_BFGsound
  655. ( player_t* player,
  656. pspdef_t* psp )
  657. {
  658. S_StartSound (player->mo, sfx_bfg);
  659. }
  660. //
  661. // P_SetupPsprites
  662. // Called at start of level for each player.
  663. //
  664. void P_SetupPsprites (player_t* player)
  665. {
  666. int i;
  667. // remove all psprites
  668. for (i=0 ; i<NUMPSPRITES ; i++)
  669. player->psprites[i].state = NULL;
  670. // spawn the gun
  671. player->pendingweapon = player->readyweapon;
  672. P_BringUpWeapon (player);
  673. }
  674. //
  675. // P_MovePsprites
  676. // Called every tic by player thinking routine.
  677. //
  678. void P_MovePsprites (player_t* player)
  679. {
  680. int i;
  681. pspdef_t* psp;
  682. state_t* state;
  683. psp = &player->psprites[0];
  684. for (i=0 ; i<NUMPSPRITES ; i++, psp++)
  685. {
  686. // a null state means not active
  687. if ( (state = psp->state) )
  688. {
  689. // drop tic count and possibly change state
  690. // a -1 tic count never changes
  691. if (psp->tics != -1)
  692. {
  693. psp->tics--;
  694. if (!psp->tics)
  695. P_SetPsprite (player, i, psp->state->nextstate);
  696. }
  697. }
  698. }
  699. player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
  700. player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
  701. }