[docs] Replace cyrillic 'с' with latin 'c' in register names
[kolibrios.git] / contrib / other / sdldoom-1.10 / p_pspr.c
blob2ac53b88a1baa443255f2e46d1ff761d5363ca9f
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.
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.
17 // $Log:$
19 // DESCRIPTION:
20 // Weapon sprite animation, weapon objects.
21 // Action functions for weapons.
23 //-----------------------------------------------------------------------------
25 static const char
26 rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
28 #include "doomdef.h"
29 #include "d_event.h"
32 #include "m_random.h"
33 #include "p_local.h"
34 #include "s_sound.h"
36 // State.
37 #include "doomstat.h"
39 // Data.
40 #include "sounds.h"
42 #include "p_pspr.h"
44 #define LOWERSPEED FRACUNIT*6
45 #define RAISESPEED FRACUNIT*6
47 #define WEAPONBOTTOM 128*FRACUNIT
48 #define WEAPONTOP 32*FRACUNIT
51 // plasma cells for a bfg attack
52 #define BFGCELLS 40
56 // P_SetPsprite
58 void
59 P_SetPsprite
60 ( player_t* player,
61 int position,
62 statenum_t stnum )
64 pspdef_t* psp;
65 state_t* state;
67 psp = &player->psprites[position];
71 if (!stnum)
73 // object removed itself
74 psp->state = NULL;
75 break;
78 state = &states[stnum];
79 psp->state = state;
80 psp->tics = state->tics; // could be 0
82 if (state->misc1)
84 // coordinate set
85 psp->sx = state->misc1 << FRACBITS;
86 psp->sy = state->misc2 << FRACBITS;
89 // Call action routine.
90 // Modified handling.
91 if (state->action.acp2)
93 state->action.acp2(player, psp);
94 if (!psp->state)
95 break;
98 stnum = psp->state->nextstate;
100 } while (!psp->tics);
101 // an initial state of 0 could cycle through
107 // P_CalcSwing
109 fixed_t swingx;
110 fixed_t swingy;
112 void P_CalcSwing (player_t* player)
114 fixed_t swing;
115 int angle;
117 // OPTIMIZE: tablify this.
118 // A LUT would allow for different modes,
119 // and add flexibility.
121 swing = player->bob;
123 angle = (FINEANGLES/70*leveltime)&FINEMASK;
124 swingx = FixedMul ( swing, finesine[angle]);
126 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
127 swingy = -FixedMul ( swingx, finesine[angle]);
133 // P_BringUpWeapon
134 // Starts bringing the pending weapon up
135 // from the bottom of the screen.
136 // Uses player
138 void P_BringUpWeapon (player_t* player)
140 statenum_t newstate;
142 if (player->pendingweapon == wp_nochange)
143 player->pendingweapon = player->readyweapon;
145 if (player->pendingweapon == wp_chainsaw)
146 S_StartSound (player->mo, sfx_sawup);
148 newstate = weaponinfo[player->pendingweapon].upstate;
150 player->pendingweapon = wp_nochange;
151 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
153 P_SetPsprite (player, ps_weapon, newstate);
157 // P_CheckAmmo
158 // Returns true if there is enough ammo to shoot.
159 // If not, selects the next weapon to use.
161 boolean P_CheckAmmo (player_t* player)
163 ammotype_t ammo;
164 int count;
166 ammo = weaponinfo[player->readyweapon].ammo;
168 // Minimal amount for one shot varies.
169 if (player->readyweapon == wp_bfg)
170 count = BFGCELLS;
171 else if (player->readyweapon == wp_supershotgun)
172 count = 2; // Double barrel.
173 else
174 count = 1; // Regular.
176 // Some do not need ammunition anyway.
177 // Return if current ammunition sufficient.
178 if (ammo == am_noammo || player->ammo[ammo] >= count)
179 return true;
181 // Out of ammo, pick a weapon to change to.
182 // Preferences are set here.
185 if (player->weaponowned[wp_plasma]
186 && player->ammo[am_cell]
187 && (gamemode != shareware) )
189 player->pendingweapon = wp_plasma;
191 else if (player->weaponowned[wp_supershotgun]
192 && player->ammo[am_shell]>2
193 && (gamemode == commercial) )
195 player->pendingweapon = wp_supershotgun;
197 else if (player->weaponowned[wp_chaingun]
198 && player->ammo[am_clip])
200 player->pendingweapon = wp_chaingun;
202 else if (player->weaponowned[wp_shotgun]
203 && player->ammo[am_shell])
205 player->pendingweapon = wp_shotgun;
207 else if (player->ammo[am_clip])
209 player->pendingweapon = wp_pistol;
211 else if (player->weaponowned[wp_chainsaw])
213 player->pendingweapon = wp_chainsaw;
215 else if (player->weaponowned[wp_missile]
216 && player->ammo[am_misl])
218 player->pendingweapon = wp_missile;
220 else if (player->weaponowned[wp_bfg]
221 && player->ammo[am_cell]>40
222 && (gamemode != shareware) )
224 player->pendingweapon = wp_bfg;
226 else
228 // If everything fails.
229 player->pendingweapon = wp_fist;
232 } while (player->pendingweapon == wp_nochange);
234 // Now set appropriate weapon overlay.
235 P_SetPsprite (player,
236 ps_weapon,
237 weaponinfo[player->readyweapon].downstate);
239 return false;
244 // P_FireWeapon.
246 void P_FireWeapon (player_t* player)
248 statenum_t newstate;
250 if (!P_CheckAmmo (player))
251 return;
253 P_SetMobjState (player->mo, S_PLAY_ATK1);
254 newstate = weaponinfo[player->readyweapon].atkstate;
255 P_SetPsprite (player, ps_weapon, newstate);
256 P_NoiseAlert (player->mo, player->mo);
262 // P_DropWeapon
263 // Player died, so put the weapon away.
265 void P_DropWeapon (player_t* player)
267 P_SetPsprite (player,
268 ps_weapon,
269 weaponinfo[player->readyweapon].downstate);
275 // A_WeaponReady
276 // The player can fire the weapon
277 // or change to another weapon at this time.
278 // Follows after getting weapon up,
279 // or after previous attack/fire sequence.
281 void
282 A_WeaponReady
283 ( player_t* player,
284 pspdef_t* psp )
286 statenum_t newstate;
287 int angle;
289 // get out of attack state
290 if (player->mo->state == &states[S_PLAY_ATK1]
291 || player->mo->state == &states[S_PLAY_ATK2] )
293 P_SetMobjState (player->mo, S_PLAY);
296 if (player->readyweapon == wp_chainsaw
297 && psp->state == &states[S_SAW])
299 S_StartSound (player->mo, sfx_sawidl);
302 // check for change
303 // if player is dead, put the weapon away
304 if (player->pendingweapon != wp_nochange || !player->health)
306 // change weapon
307 // (pending weapon should allready be validated)
308 newstate = weaponinfo[player->readyweapon].downstate;
309 P_SetPsprite (player, ps_weapon, newstate);
310 return;
313 // check for fire
314 // the missile launcher and bfg do not auto fire
315 if (player->cmd.buttons & BT_ATTACK)
317 if ( !player->attackdown
318 || (player->readyweapon != wp_missile
319 && player->readyweapon != wp_bfg) )
321 player->attackdown = true;
322 P_FireWeapon (player);
323 return;
326 else
327 player->attackdown = false;
329 // bob the weapon based on movement speed
330 angle = (128*leveltime)&FINEMASK;
331 psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]);
332 angle &= FINEANGLES/2-1;
333 psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]);
339 // A_ReFire
340 // The player can re-fire the weapon
341 // without lowering it entirely.
343 void A_ReFire
344 ( player_t* player,
345 pspdef_t* psp )
348 // check for fire
349 // (if a weaponchange is pending, let it go through instead)
350 if ( (player->cmd.buttons & BT_ATTACK)
351 && player->pendingweapon == wp_nochange
352 && player->health)
354 player->refire++;
355 P_FireWeapon (player);
357 else
359 player->refire = 0;
360 P_CheckAmmo (player);
365 void
366 A_CheckReload
367 ( player_t* player,
368 pspdef_t* psp )
370 P_CheckAmmo (player);
371 #if 0
372 if (player->ammo[am_shell]<2)
373 P_SetPsprite (player, ps_weapon, S_DSNR1);
374 #endif
380 // A_Lower
381 // Lowers current weapon,
382 // and changes weapon at bottom.
384 void
385 A_Lower
386 ( player_t* player,
387 pspdef_t* psp )
389 psp->sy += LOWERSPEED;
391 // Is already down.
392 if (psp->sy < WEAPONBOTTOM )
393 return;
395 // Player is dead.
396 if (player->playerstate == PST_DEAD)
398 psp->sy = WEAPONBOTTOM;
400 // don't bring weapon back up
401 return;
404 // The old weapon has been lowered off the screen,
405 // so change the weapon and start raising it
406 if (!player->health)
408 // Player is dead, so keep the weapon off screen.
409 P_SetPsprite (player, ps_weapon, S_NULL);
410 return;
413 player->readyweapon = player->pendingweapon;
415 P_BringUpWeapon (player);
420 // A_Raise
422 void
423 A_Raise
424 ( player_t* player,
425 pspdef_t* psp )
427 statenum_t newstate;
429 psp->sy -= RAISESPEED;
431 if (psp->sy > WEAPONTOP )
432 return;
434 psp->sy = WEAPONTOP;
436 // The weapon has been raised all the way,
437 // so change to the ready state.
438 newstate = weaponinfo[player->readyweapon].readystate;
440 P_SetPsprite (player, ps_weapon, newstate);
446 // A_GunFlash
448 void
449 A_GunFlash
450 ( player_t* player,
451 pspdef_t* psp )
453 P_SetMobjState (player->mo, S_PLAY_ATK2);
454 P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
460 // WEAPON ATTACKS
465 // A_Punch
467 void
468 A_Punch
469 ( player_t* player,
470 pspdef_t* psp )
472 angle_t angle;
473 int damage;
474 int slope;
476 damage = (P_Random ()%10+1)<<1;
478 if (player->powers[pw_strength])
479 damage *= 10;
481 angle = player->mo->angle;
482 angle += (P_Random()-P_Random())<<18;
483 slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
484 P_LineAttack (player->mo, angle, MELEERANGE, slope, damage);
486 // turn to face target
487 if (linetarget)
489 S_StartSound (player->mo, sfx_punch);
490 player->mo->angle = R_PointToAngle2 (player->mo->x,
491 player->mo->y,
492 linetarget->x,
493 linetarget->y);
499 // A_Saw
501 void
502 A_Saw
503 ( player_t* player,
504 pspdef_t* psp )
506 angle_t angle;
507 int damage;
508 int slope;
510 damage = 2*(P_Random ()%10+1);
511 angle = player->mo->angle;
512 angle += (P_Random()-P_Random())<<18;
514 // use meleerange + 1 se the puff doesn't skip the flash
515 slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1);
516 P_LineAttack (player->mo, angle, MELEERANGE+1, slope, damage);
518 if (!linetarget)
520 S_StartSound (player->mo, sfx_sawful);
521 return;
523 S_StartSound (player->mo, sfx_sawhit);
525 // turn to face target
526 angle = R_PointToAngle2 (player->mo->x, player->mo->y,
527 linetarget->x, linetarget->y);
528 if (angle - player->mo->angle > ANG180)
530 if (angle - player->mo->angle < -ANG90/20)
531 player->mo->angle = angle + ANG90/21;
532 else
533 player->mo->angle -= ANG90/20;
535 else
537 if (angle - player->mo->angle > ANG90/20)
538 player->mo->angle = angle - ANG90/21;
539 else
540 player->mo->angle += ANG90/20;
542 player->mo->flags |= MF_JUSTATTACKED;
548 // A_FireMissile
550 void
551 A_FireMissile
552 ( player_t* player,
553 pspdef_t* psp )
555 player->ammo[weaponinfo[player->readyweapon].ammo]--;
556 P_SpawnPlayerMissile (player->mo, MT_ROCKET);
561 // A_FireBFG
563 void
564 A_FireBFG
565 ( player_t* player,
566 pspdef_t* psp )
568 player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
569 P_SpawnPlayerMissile (player->mo, MT_BFG);
575 // A_FirePlasma
577 void
578 A_FirePlasma
579 ( player_t* player,
580 pspdef_t* psp )
582 player->ammo[weaponinfo[player->readyweapon].ammo]--;
584 P_SetPsprite (player,
585 ps_flash,
586 weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) );
588 P_SpawnPlayerMissile (player->mo, MT_PLASMA);
594 // P_BulletSlope
595 // Sets a slope so a near miss is at aproximately
596 // the height of the intended target
598 fixed_t bulletslope;
601 void P_BulletSlope (mobj_t* mo)
603 angle_t an;
605 // see which target is to be aimed at
606 an = mo->angle;
607 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
609 if (!linetarget)
611 an += 1<<26;
612 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
613 if (!linetarget)
615 an -= 2<<26;
616 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
623 // P_GunShot
625 void
626 P_GunShot
627 ( mobj_t* mo,
628 boolean accurate )
630 angle_t angle;
631 int damage;
633 damage = 5*(P_Random ()%3+1);
634 angle = mo->angle;
636 if (!accurate)
637 angle += (P_Random()-P_Random())<<18;
639 P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
644 // A_FirePistol
646 void
647 A_FirePistol
648 ( player_t* player,
649 pspdef_t* psp )
651 S_StartSound (player->mo, sfx_pistol);
653 P_SetMobjState (player->mo, S_PLAY_ATK2);
654 player->ammo[weaponinfo[player->readyweapon].ammo]--;
656 P_SetPsprite (player,
657 ps_flash,
658 weaponinfo[player->readyweapon].flashstate);
660 P_BulletSlope (player->mo);
661 P_GunShot (player->mo, !player->refire);
666 // A_FireShotgun
668 void
669 A_FireShotgun
670 ( player_t* player,
671 pspdef_t* psp )
673 int i;
675 S_StartSound (player->mo, sfx_shotgn);
676 P_SetMobjState (player->mo, S_PLAY_ATK2);
678 player->ammo[weaponinfo[player->readyweapon].ammo]--;
680 P_SetPsprite (player,
681 ps_flash,
682 weaponinfo[player->readyweapon].flashstate);
684 P_BulletSlope (player->mo);
686 for (i=0 ; i<7 ; i++)
687 P_GunShot (player->mo, false);
693 // A_FireShotgun2
695 void
696 A_FireShotgun2
697 ( player_t* player,
698 pspdef_t* psp )
700 int i;
701 angle_t angle;
702 int damage;
705 S_StartSound (player->mo, sfx_dshtgn);
706 P_SetMobjState (player->mo, S_PLAY_ATK2);
708 player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
710 P_SetPsprite (player,
711 ps_flash,
712 weaponinfo[player->readyweapon].flashstate);
714 P_BulletSlope (player->mo);
716 for (i=0 ; i<20 ; i++)
718 damage = 5*(P_Random ()%3+1);
719 angle = player->mo->angle;
720 angle += (P_Random()-P_Random())<<19;
721 P_LineAttack (player->mo,
722 angle,
723 MISSILERANGE,
724 bulletslope + ((P_Random()-P_Random())<<5), damage);
730 // A_FireCGun
732 void
733 A_FireCGun
734 ( player_t* player,
735 pspdef_t* psp )
737 S_StartSound (player->mo, sfx_pistol);
739 if (!player->ammo[weaponinfo[player->readyweapon].ammo])
740 return;
742 P_SetMobjState (player->mo, S_PLAY_ATK2);
743 player->ammo[weaponinfo[player->readyweapon].ammo]--;
745 P_SetPsprite (player,
746 ps_flash,
747 weaponinfo[player->readyweapon].flashstate
748 + psp->state
749 - &states[S_CHAIN1] );
751 P_BulletSlope (player->mo);
753 P_GunShot (player->mo, !player->refire);
759 // ?
761 void A_Light0 (player_t *player, pspdef_t *psp)
763 player->extralight = 0;
766 void A_Light1 (player_t *player, pspdef_t *psp)
768 player->extralight = 1;
771 void A_Light2 (player_t *player, pspdef_t *psp)
773 player->extralight = 2;
778 // A_BFGSpray
779 // Spawn a BFG explosion on every monster in view
781 void A_BFGSpray (mobj_t* mo)
783 int i;
784 int j;
785 int damage;
786 angle_t an;
788 // offset angles from its attack angle
789 for (i=0 ; i<40 ; i++)
791 an = mo->angle - ANG90/2 + ANG90/40*i;
793 // mo->target is the originator (player)
794 // of the missile
795 P_AimLineAttack (mo->target, an, 16*64*FRACUNIT);
797 if (!linetarget)
798 continue;
800 P_SpawnMobj (linetarget->x,
801 linetarget->y,
802 linetarget->z + (linetarget->height>>2),
803 MT_EXTRABFG);
805 damage = 0;
806 for (j=0;j<15;j++)
807 damage += (P_Random()&7) + 1;
809 P_DamageMobj (linetarget, mo->target,mo->target, damage);
815 // A_BFGsound
817 void
818 A_BFGsound
819 ( player_t* player,
820 pspdef_t* psp )
822 S_StartSound (player->mo, sfx_bfg);
828 // P_SetupPsprites
829 // Called at start of level for each player.
831 void P_SetupPsprites (player_t* player)
833 int i;
835 // remove all psprites
836 for (i=0 ; i<NUMPSPRITES ; i++)
837 player->psprites[i].state = NULL;
839 // spawn the gun
840 player->pendingweapon = player->readyweapon;
841 P_BringUpWeapon (player);
848 // P_MovePsprites
849 // Called every tic by player thinking routine.
851 void P_MovePsprites (player_t* player)
853 int i;
854 pspdef_t* psp;
855 state_t* state;
857 psp = &player->psprites[0];
858 for (i=0 ; i<NUMPSPRITES ; i++, psp++)
860 // a null state means not active
861 if ( (state = psp->state) )
863 // drop tic count and possibly change state
865 // a -1 tic count never changes
866 if (psp->tics != -1)
868 psp->tics--;
869 if (!psp->tics)
870 P_SetPsprite (player, i, psp->state->nextstate);
875 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
876 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;