# Correct the needed linklibs in curl-config also.
[AROS-Contrib.git] / Games / Doom / p_pspr.c
blobe8fcb3135608841714f6e2cb802fe7113c1ce7ac
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$
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
22 // DESCRIPTION:
23 // Weapon sprite animation, weapon objects.
24 // Action functions for weapons.
26 //-----------------------------------------------------------------------------
28 static const char
29 rcsid[] = "$Id$";
31 #include "doomdef.h"
32 #include "d_event.h"
35 #include "m_random.h"
36 #include "p_local.h"
37 #include "s_sound.h"
39 // State.
40 #include "doomstat.h"
42 // Data.
43 #include "sounds.h"
45 #include "p_pspr.h"
47 #define LOWERSPEED FRACUNIT*6
48 #define RAISESPEED FRACUNIT*6
50 #define WEAPONBOTTOM 128*FRACUNIT
51 #define WEAPONTOP 32*FRACUNIT
54 // plasma cells for a bfg attack
55 int BFGCELLS=40; // Dehacked
59 // P_SetPsprite
61 void
62 P_SetPsprite
63 ( player_t* player,
64 int position,
65 statenum_t stnum )
67 pspdef_t* psp;
68 state_t* state;
70 psp = &player->psprites[position];
74 if (!stnum)
76 // object removed itself
77 psp->state = NULL;
78 break;
81 state = &states[stnum];
82 psp->state = state;
83 psp->tics = state->tics; // could be 0
85 if (state->misc1)
87 // coordinate set
88 psp->sx = state->misc1 << FRACBITS;
89 psp->sy = state->misc2 << FRACBITS;
92 // Call action routine.
93 // Modified handling.
94 if (state->action.acp2)
96 state->action.acp2(player, psp);
97 if (!psp->state)
98 break;
101 stnum = psp->state->nextstate;
103 } while (!psp->tics);
104 // an initial state of 0 could cycle through
110 // P_CalcSwing
112 fixed_t swingx;
113 fixed_t swingy;
115 void P_CalcSwing (player_t* player)
117 fixed_t swing;
118 int angle;
120 // OPTIMIZE: tablify this.
121 // A LUT would allow for different modes,
122 // and add flexibility.
124 swing = player->bob;
126 angle = (FINEANGLES/70*leveltime)&FINEMASK;
127 swingx = FixedMul ( swing, finesine[angle]);
129 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
130 swingy = -FixedMul ( swingx, finesine[angle]);
136 // P_BringUpWeapon
137 // Starts bringing the pending weapon up
138 // from the bottom of the screen.
139 // Uses player
141 void P_BringUpWeapon (player_t* player)
143 statenum_t newstate;
145 if (player->pendingweapon == wp_nochange)
146 player->pendingweapon = player->readyweapon;
148 if (player->pendingweapon == wp_chainsaw)
149 S_StartSound (player->mo, sfx_sawup);
151 newstate = weaponinfo[player->pendingweapon].upstate;
153 player->pendingweapon = wp_nochange;
154 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
156 P_SetPsprite (player, ps_weapon, newstate);
160 // P_CheckAmmo
161 // Returns true if there is enough ammo to shoot.
162 // If not, selects the next weapon to use.
164 boolean P_CheckAmmo (player_t* player)
166 ammotype_t ammo;
167 int count;
169 ammo = weaponinfo[player->readyweapon].ammo;
171 // Minimal amount for one shot varies.
172 if (player->readyweapon == wp_bfg)
173 count = BFGCELLS;
174 else if (player->readyweapon == wp_supershotgun)
175 count = 2; // Double barrel.
176 else
177 count = 1; // Regular.
179 // Some do not need ammunition anyway.
180 // Return if current ammunition sufficient.
181 if (ammo == am_noammo || player->ammo[ammo] >= count)
182 return true;
184 // Out of ammo, pick a weapon to change to.
185 // Preferences are set here.
188 if (player->weaponowned[wp_plasma]
189 && player->ammo[am_cell]
190 && (gamemode != shareware) )
192 player->pendingweapon = wp_plasma;
194 else if (player->weaponowned[wp_supershotgun]
195 && player->ammo[am_shell]>2
196 && (gamemode == commercial) )
198 player->pendingweapon = wp_supershotgun;
200 else if (player->weaponowned[wp_chaingun]
201 && player->ammo[am_clip])
203 player->pendingweapon = wp_chaingun;
205 else if (player->weaponowned[wp_shotgun]
206 && player->ammo[am_shell])
208 player->pendingweapon = wp_shotgun;
210 else if (player->ammo[am_clip])
212 player->pendingweapon = wp_pistol;
214 else if (player->weaponowned[wp_chainsaw])
216 player->pendingweapon = wp_chainsaw;
218 else if (player->weaponowned[wp_missile]
219 && player->ammo[am_misl])
221 player->pendingweapon = wp_missile;
223 else if (player->weaponowned[wp_bfg]
224 && player->ammo[am_cell]>40
225 && (gamemode != shareware) )
227 player->pendingweapon = wp_bfg;
229 else
231 // If everything fails.
232 player->pendingweapon = wp_fist;
235 } while (player->pendingweapon == wp_nochange);
237 // Now set appropriate weapon overlay.
238 P_SetPsprite (player,
239 ps_weapon,
240 weaponinfo[player->readyweapon].downstate);
242 return false;
247 // P_FireWeapon.
249 void P_FireWeapon (player_t* player)
251 statenum_t newstate;
253 if (!P_CheckAmmo (player))
254 return;
256 P_SetMobjState (player->mo, S_PLAY_ATK1);
257 newstate = weaponinfo[player->readyweapon].atkstate;
258 P_SetPsprite (player, ps_weapon, newstate);
259 P_NoiseAlert (player->mo, player->mo);
265 // P_DropWeapon
266 // Player died, so put the weapon away.
268 void P_DropWeapon (player_t* player)
270 P_SetPsprite (player,
271 ps_weapon,
272 weaponinfo[player->readyweapon].downstate);
278 // A_WeaponReady
279 // The player can fire the weapon
280 // or change to another weapon at this time.
281 // Follows after getting weapon up,
282 // or after previous attack/fire sequence.
284 void
285 A_WeaponReady
286 ( player_t* player,
287 pspdef_t* psp )
289 statenum_t newstate;
290 int angle;
292 // get out of attack state
293 if (player->mo->state == &states[S_PLAY_ATK1]
294 || player->mo->state == &states[S_PLAY_ATK2] )
296 P_SetMobjState (player->mo, S_PLAY);
299 if (player->readyweapon == wp_chainsaw
300 && psp->state == &states[S_SAW])
302 S_StartSound (player->mo, sfx_sawidl);
305 // check for change
306 // if player is dead, put the weapon away
307 if (player->pendingweapon != wp_nochange || !player->health)
309 // change weapon
310 // (pending weapon should allready be validated)
311 newstate = weaponinfo[player->readyweapon].downstate;
312 P_SetPsprite (player, ps_weapon, newstate);
313 return;
316 // check for fire
317 // the missile launcher and bfg do not auto fire
318 if (player->cmd.buttons & BT_ATTACK)
320 if ( !player->attackdown
321 || (player->readyweapon != wp_missile
322 && player->readyweapon != wp_bfg) )
324 player->attackdown = true;
325 P_FireWeapon (player);
326 return;
329 else
330 player->attackdown = false;
332 // bob the weapon based on movement speed
333 angle = (128*leveltime)&FINEMASK;
334 psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]);
335 angle &= FINEANGLES/2-1;
336 psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]);
342 // A_ReFire
343 // The player can re-fire the weapon
344 // without lowering it entirely.
346 void A_ReFire
347 ( player_t* player,
348 pspdef_t* psp )
351 // check for fire
352 // (if a weaponchange is pending, let it go through instead)
353 if ( (player->cmd.buttons & BT_ATTACK)
354 && player->pendingweapon == wp_nochange
355 && player->health)
357 player->refire++;
358 P_FireWeapon (player);
360 else
362 player->refire = 0;
363 P_CheckAmmo (player);
368 void
369 A_CheckReload
370 ( player_t* player,
371 pspdef_t* psp )
373 P_CheckAmmo (player);
374 #if 0
375 if (player->ammo[am_shell]<2)
376 P_SetPsprite (player, ps_weapon, S_DSNR1);
377 #endif
383 // A_Lower
384 // Lowers current weapon,
385 // and changes weapon at bottom.
387 void
388 A_Lower
389 ( player_t* player,
390 pspdef_t* psp )
392 psp->sy += LOWERSPEED;
394 // Is already down.
395 if (psp->sy < WEAPONBOTTOM )
396 return;
398 // Player is dead.
399 if (player->playerstate == PST_DEAD)
401 psp->sy = WEAPONBOTTOM;
403 // don't bring weapon back up
404 return;
407 // The old weapon has been lowered off the screen,
408 // so change the weapon and start raising it
409 if (!player->health)
411 // Player is dead, so keep the weapon off screen.
412 P_SetPsprite (player, ps_weapon, S_NULL);
413 return;
416 player->readyweapon = player->pendingweapon;
418 P_BringUpWeapon (player);
423 // A_Raise
425 void
426 A_Raise
427 ( player_t* player,
428 pspdef_t* psp )
430 statenum_t newstate;
432 psp->sy -= RAISESPEED;
434 if (psp->sy > WEAPONTOP )
435 return;
437 psp->sy = WEAPONTOP;
439 // The weapon has been raised all the way,
440 // so change to the ready state.
441 newstate = weaponinfo[player->readyweapon].readystate;
443 P_SetPsprite (player, ps_weapon, newstate);
449 // A_GunFlash
451 void
452 A_GunFlash
453 ( player_t* player,
454 pspdef_t* psp )
456 P_SetMobjState (player->mo, S_PLAY_ATK2);
457 P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
463 // WEAPON ATTACKS
468 // A_Punch
470 void
471 A_Punch
472 ( player_t* player,
473 pspdef_t* psp )
475 angle_t angle;
476 int damage;
477 int slope;
479 damage = (P_Random ()%10+1)<<1;
481 if (player->powers[pw_strength])
482 damage *= 10;
484 angle = player->mo->angle;
485 angle += (P_Random()-P_Random())<<18;
486 slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
487 P_LineAttack (player->mo, angle, MELEERANGE, slope, damage);
489 // turn to face target
490 if (linetarget)
492 S_StartSound (player->mo, sfx_punch);
493 player->mo->angle = R_PointToAngle2 (player->mo->x,
494 player->mo->y,
495 linetarget->x,
496 linetarget->y);
502 // A_Saw
504 void
505 A_Saw
506 ( player_t* player,
507 pspdef_t* psp )
509 angle_t angle;
510 int damage;
511 int slope;
513 damage = 2*(P_Random ()%10+1);
514 angle = player->mo->angle;
515 angle += (P_Random()-P_Random())<<18;
517 // use meleerange + 1 se the puff doesn't skip the flash
518 slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1);
519 P_LineAttack (player->mo, angle, MELEERANGE+1, slope, damage);
521 if (!linetarget)
523 S_StartSound (player->mo, sfx_sawful);
524 return;
526 S_StartSound (player->mo, sfx_sawhit);
528 // turn to face target
529 angle = R_PointToAngle2 (player->mo->x, player->mo->y,
530 linetarget->x, linetarget->y);
531 if (angle - player->mo->angle > ANG180)
533 if (angle - player->mo->angle < -ANG90/20)
534 player->mo->angle = angle + ANG90/21;
535 else
536 player->mo->angle -= ANG90/20;
538 else
540 if (angle - player->mo->angle > ANG90/20)
541 player->mo->angle = angle - ANG90/21;
542 else
543 player->mo->angle += ANG90/20;
545 player->mo->flags |= MF_JUSTATTACKED;
551 // A_FireMissile
553 void
554 A_FireMissile
555 ( player_t* player,
556 pspdef_t* psp )
558 player->ammo[weaponinfo[player->readyweapon].ammo]--;
559 P_SpawnPlayerMissile (player->mo, MT_ROCKET);
564 // A_FireBFG
566 void
567 A_FireBFG
568 ( player_t* player,
569 pspdef_t* psp )
571 player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
572 P_SpawnPlayerMissile (player->mo, MT_BFG);
578 // A_FirePlasma
580 void
581 A_FirePlasma
582 ( player_t* player,
583 pspdef_t* psp )
585 player->ammo[weaponinfo[player->readyweapon].ammo]--;
587 P_SetPsprite (player,
588 ps_flash,
589 weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) );
591 P_SpawnPlayerMissile (player->mo, MT_PLASMA);
597 // P_BulletSlope
598 // Sets a slope so a near miss is at aproximately
599 // the height of the intended target
601 fixed_t bulletslope;
604 void P_BulletSlope (mobj_t* mo)
606 angle_t an;
608 // see which target is to be aimed at
609 an = mo->angle;
610 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
612 if (!linetarget)
614 an += 1<<26;
615 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
616 if (!linetarget)
618 an -= 2<<26;
619 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
626 // P_GunShot
628 void
629 P_GunShot
630 ( mobj_t* mo,
631 boolean accurate )
633 angle_t angle;
634 int damage;
636 damage = 5*(P_Random ()%3+1);
637 angle = mo->angle;
639 if (!accurate)
640 angle += (P_Random()-P_Random())<<18;
642 P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
647 // A_FirePistol
649 void
650 A_FirePistol
651 ( player_t* player,
652 pspdef_t* psp )
654 S_StartSound (player->mo, sfx_pistol);
656 P_SetMobjState (player->mo, S_PLAY_ATK2);
657 player->ammo[weaponinfo[player->readyweapon].ammo]--;
659 P_SetPsprite (player,
660 ps_flash,
661 weaponinfo[player->readyweapon].flashstate);
663 P_BulletSlope (player->mo);
664 P_GunShot (player->mo, !player->refire);
669 // A_FireShotgun
671 void
672 A_FireShotgun
673 ( player_t* player,
674 pspdef_t* psp )
676 int i;
678 S_StartSound (player->mo, sfx_shotgn);
679 P_SetMobjState (player->mo, S_PLAY_ATK2);
681 player->ammo[weaponinfo[player->readyweapon].ammo]--;
683 P_SetPsprite (player,
684 ps_flash,
685 weaponinfo[player->readyweapon].flashstate);
687 P_BulletSlope (player->mo);
689 for (i=0 ; i<7 ; i++)
690 P_GunShot (player->mo, false);
696 // A_FireShotgun2
698 void
699 A_FireShotgun2
700 ( player_t* player,
701 pspdef_t* psp )
703 int i;
704 angle_t angle;
705 int damage;
708 S_StartSound (player->mo, sfx_dshtgn);
709 P_SetMobjState (player->mo, S_PLAY_ATK2);
711 player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
713 P_SetPsprite (player,
714 ps_flash,
715 weaponinfo[player->readyweapon].flashstate);
717 P_BulletSlope (player->mo);
719 for (i=0 ; i<20 ; i++)
721 damage = 5*(P_Random ()%3+1);
722 angle = player->mo->angle;
723 angle += (P_Random()-P_Random())<<19;
724 P_LineAttack (player->mo,
725 angle,
726 MISSILERANGE,
727 bulletslope + ((P_Random()-P_Random())<<5), damage);
733 // A_FireCGun
735 void
736 A_FireCGun
737 ( player_t* player,
738 pspdef_t* psp )
740 S_StartSound (player->mo, sfx_pistol);
742 if (!player->ammo[weaponinfo[player->readyweapon].ammo])
743 return;
745 P_SetMobjState (player->mo, S_PLAY_ATK2);
746 player->ammo[weaponinfo[player->readyweapon].ammo]--;
748 P_SetPsprite (player,
749 ps_flash,
750 weaponinfo[player->readyweapon].flashstate
751 + psp->state
752 - &states[S_CHAIN1] );
754 P_BulletSlope (player->mo);
756 P_GunShot (player->mo, !player->refire);
762 // ?
764 void A_Light0 (player_t *player, pspdef_t *psp)
766 player->extralight = 0;
769 void A_Light1 (player_t *player, pspdef_t *psp)
771 player->extralight = 1;
774 void A_Light2 (player_t *player, pspdef_t *psp)
776 player->extralight = 2;
781 // A_BFGSpray
782 // Spawn a BFG explosion on every monster in view
784 void A_BFGSpray (mobj_t* mo)
786 int i;
787 int j;
788 int damage;
789 angle_t an;
791 // offset angles from its attack angle
792 for (i=0 ; i<40 ; i++)
794 an = mo->angle - ANG90/2 + ANG90/40*i;
796 // mo->target is the originator (player)
797 // of the missile
798 P_AimLineAttack (mo->target, an, 16*64*FRACUNIT);
800 if (!linetarget)
801 continue;
803 P_SpawnMobj (linetarget->x,
804 linetarget->y,
805 linetarget->z + (linetarget->height>>2),
806 MT_EXTRABFG);
808 damage = 0;
809 for (j=0;j<15;j++)
810 damage += (P_Random()&7) + 1;
812 P_DamageMobj (linetarget, mo->target,mo->target, damage);
818 // A_BFGsound
820 void
821 A_BFGsound
822 ( player_t* player,
823 pspdef_t* psp )
825 S_StartSound (player->mo, sfx_bfg);
831 // P_SetupPsprites
832 // Called at start of level for each player.
834 void P_SetupPsprites (player_t* player)
836 int i;
838 // remove all psprites
839 for (i=0 ; i<NUMPSPRITES ; i++)
840 player->psprites[i].state = NULL;
842 // spawn the gun
843 player->pendingweapon = player->readyweapon;
844 P_BringUpWeapon (player);
851 // P_MovePsprites
852 // Called every tic by player thinking routine.
854 void P_MovePsprites (player_t* player)
856 int i;
857 pspdef_t* psp;
858 state_t* state;
860 psp = &player->psprites[0];
861 for (i=0 ; i<NUMPSPRITES ; i++, psp++)
863 // a null state means not active
864 if ( (state = psp->state) )
866 // drop tic count and possibly change state
868 // a -1 tic count never changes
869 if (psp->tics != -1)
871 psp->tics--;
872 if (!psp->tics)
873 P_SetPsprite (player, i, psp->state->nextstate);
878 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
879 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;