1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16
17 // P_pspr.c
18
19 #include "doomdef.h"
20 #include "i_system.h"
21 #include "m_random.h"
22 #include "p_local.h"
23 #include "s_sound.h"
24
25 // Macros
26
27 #define LOWERSPEED FRACUNIT*6
28 #define RAISESPEED FRACUNIT*6
29 #define WEAPONBOTTOM 128*FRACUNIT
30 #define WEAPONTOP 32*FRACUNIT
31 #define FLAME_THROWER_TICS 10*35
32 #define MAGIC_JUNK 1234
33 #define MAX_MACE_SPOTS 8
34
35 static int MaceSpotCount;
36 static struct
37 {
38 fixed_t x;
39 fixed_t y;
40 } MaceSpots[MAX_MACE_SPOTS];
41
42 fixed_t bulletslope;
43
44 static int WeaponAmmoUsePL1[NUMWEAPONS] = {
45 0, // staff
46 USE_GWND_AMMO_1, // gold wand
47 USE_CBOW_AMMO_1, // crossbow
48 USE_BLSR_AMMO_1, // blaster
49 USE_SKRD_AMMO_1, // skull rod
50 USE_PHRD_AMMO_1, // phoenix rod
51 USE_MACE_AMMO_1, // mace
52 0, // gauntlets
53 0 // beak
54 };
55
56 static int WeaponAmmoUsePL2[NUMWEAPONS] = {
57 0, // staff
58 USE_GWND_AMMO_2, // gold wand
59 USE_CBOW_AMMO_2, // crossbow
60 USE_BLSR_AMMO_2, // blaster
61 USE_SKRD_AMMO_2, // skull rod
62 USE_PHRD_AMMO_2, // phoenix rod
63 USE_MACE_AMMO_2, // mace
64 0, // gauntlets
65 0 // beak
66 };
67
68 weaponinfo_t wpnlev1info[NUMWEAPONS] = {
69 { // Staff
70 am_noammo, // ammo
71 S_STAFFUP, // upstate
72 S_STAFFDOWN, // downstate
73 S_STAFFREADY, // readystate
74 S_STAFFATK1_1, // atkstate
75 S_STAFFATK1_1, // holdatkstate
76 S_NULL // flashstate
77 },
78 { // Gold wand
79 am_goldwand, // ammo
80 S_GOLDWANDUP, // upstate
81 S_GOLDWANDDOWN, // downstate
82 S_GOLDWANDREADY, // readystate
83 S_GOLDWANDATK1_1, // atkstate
84 S_GOLDWANDATK1_1, // holdatkstate
85 S_NULL // flashstate
86 },
87 { // Crossbow
88 am_crossbow, // ammo
89 S_CRBOWUP, // upstate
90 S_CRBOWDOWN, // downstate
91 S_CRBOW1, // readystate
92 S_CRBOWATK1_1, // atkstate
93 S_CRBOWATK1_1, // holdatkstate
94 S_NULL // flashstate
95 },
96 { // Blaster
97 am_blaster, // ammo
98 S_BLASTERUP, // upstate
99 S_BLASTERDOWN, // downstate
100 S_BLASTERREADY, // readystate
101 S_BLASTERATK1_1, // atkstate
102 S_BLASTERATK1_3, // holdatkstate
103 S_NULL // flashstate
104 },
105 { // Skull rod
106 am_skullrod, // ammo
107 S_HORNRODUP, // upstate
108 S_HORNRODDOWN, // downstate
109 S_HORNRODREADY, // readystae
110 S_HORNRODATK1_1, // atkstate
111 S_HORNRODATK1_1, // holdatkstate
112 S_NULL // flashstate
113 },
114 { // Phoenix rod
115 am_phoenixrod, // ammo
116 S_PHOENIXUP, // upstate
117 S_PHOENIXDOWN, // downstate
118 S_PHOENIXREADY, // readystate
119 S_PHOENIXATK1_1, // atkstate
120 S_PHOENIXATK1_1, // holdatkstate
121 S_NULL // flashstate
122 },
123 { // Mace
124 am_mace, // ammo
125 S_MACEUP, // upstate
126 S_MACEDOWN, // downstate
127 S_MACEREADY, // readystate
128 S_MACEATK1_1, // atkstate
129 S_MACEATK1_2, // holdatkstate
130 S_NULL // flashstate
131 },
132 { // Gauntlets
133 am_noammo, // ammo
134 S_GAUNTLETUP, // upstate
135 S_GAUNTLETDOWN, // downstate
136 S_GAUNTLETREADY, // readystate
137 S_GAUNTLETATK1_1, // atkstate
138 S_GAUNTLETATK1_3, // holdatkstate
139 S_NULL // flashstate
140 },
141 { // Beak
142 am_noammo, // ammo
143 S_BEAKUP, // upstate
144 S_BEAKDOWN, // downstate
145 S_BEAKREADY, // readystate
146 S_BEAKATK1_1, // atkstate
147 S_BEAKATK1_1, // holdatkstate
148 S_NULL // flashstate
149 }
150 };
151
152 weaponinfo_t wpnlev2info[NUMWEAPONS] = {
153 { // Staff
154 am_noammo, // ammo
155 S_STAFFUP2, // upstate
156 S_STAFFDOWN2, // downstate
157 S_STAFFREADY2_1, // readystate
158 S_STAFFATK2_1, // atkstate
159 S_STAFFATK2_1, // holdatkstate
160 S_NULL // flashstate
161 },
162 { // Gold wand
163 am_goldwand, // ammo
164 S_GOLDWANDUP, // upstate
165 S_GOLDWANDDOWN, // downstate
166 S_GOLDWANDREADY, // readystate
167 S_GOLDWANDATK2_1, // atkstate
168 S_GOLDWANDATK2_1, // holdatkstate
169 S_NULL // flashstate
170 },
171 { // Crossbow
172 am_crossbow, // ammo
173 S_CRBOWUP, // upstate
174 S_CRBOWDOWN, // downstate
175 S_CRBOW1, // readystate
176 S_CRBOWATK2_1, // atkstate
177 S_CRBOWATK2_1, // holdatkstate
178 S_NULL // flashstate
179 },
180 { // Blaster
181 am_blaster, // ammo
182 S_BLASTERUP, // upstate
183 S_BLASTERDOWN, // downstate
184 S_BLASTERREADY, // readystate
185 S_BLASTERATK2_1, // atkstate
186 S_BLASTERATK2_3, // holdatkstate
187 S_NULL // flashstate
188 },
189 { // Skull rod
190 am_skullrod, // ammo
191 S_HORNRODUP, // upstate
192 S_HORNRODDOWN, // downstate
193 S_HORNRODREADY, // readystae
194 S_HORNRODATK2_1, // atkstate
195 S_HORNRODATK2_1, // holdatkstate
196 S_NULL // flashstate
197 },
198 { // Phoenix rod
199 am_phoenixrod, // ammo
200 S_PHOENIXUP, // upstate
201 S_PHOENIXDOWN, // downstate
202 S_PHOENIXREADY, // readystate
203 S_PHOENIXATK2_1, // atkstate
204 S_PHOENIXATK2_2, // holdatkstate
205 S_NULL // flashstate
206 },
207 { // Mace
208 am_mace, // ammo
209 S_MACEUP, // upstate
210 S_MACEDOWN, // downstate
211 S_MACEREADY, // readystate
212 S_MACEATK2_1, // atkstate
213 S_MACEATK2_1, // holdatkstate
214 S_NULL // flashstate
215 },
216 { // Gauntlets
217 am_noammo, // ammo
218 S_GAUNTLETUP2, // upstate
219 S_GAUNTLETDOWN2, // downstate
220 S_GAUNTLETREADY2_1, // readystate
221 S_GAUNTLETATK2_1, // atkstate
222 S_GAUNTLETATK2_3, // holdatkstate
223 S_NULL // flashstate
224 },
225 { // Beak
226 am_noammo, // ammo
227 S_BEAKUP, // upstate
228 S_BEAKDOWN, // downstate
229 S_BEAKREADY, // readystate
230 S_BEAKATK2_1, // atkstate
231 S_BEAKATK2_1, // holdatkstate
232 S_NULL // flashstate
233 }
234 };
235
236 //---------------------------------------------------------------------------
237 //
238 // PROC P_OpenWeapons
239 //
240 // Called at level load before things are loaded.
241 //
242 //---------------------------------------------------------------------------
243
P_OpenWeapons(void)244 void P_OpenWeapons(void)
245 {
246 MaceSpotCount = 0;
247 }
248
249 //---------------------------------------------------------------------------
250 //
251 // PROC P_AddMaceSpot
252 //
253 //---------------------------------------------------------------------------
254
P_AddMaceSpot(mapthing_t * mthing)255 void P_AddMaceSpot(mapthing_t * mthing)
256 {
257 if (MaceSpotCount == MAX_MACE_SPOTS)
258 {
259 I_Error("Too many mace spots.");
260 }
261 MaceSpots[MaceSpotCount].x = mthing->x << FRACBITS;
262 MaceSpots[MaceSpotCount].y = mthing->y << FRACBITS;
263 MaceSpotCount++;
264 }
265
266 //---------------------------------------------------------------------------
267 //
268 // PROC P_RepositionMace
269 //
270 // Chooses the next spot to place the mace.
271 //
272 //---------------------------------------------------------------------------
273
P_RepositionMace(mobj_t * mo)274 void P_RepositionMace(mobj_t * mo)
275 {
276 int spot;
277 subsector_t *ss;
278
279 P_UnsetThingPosition(mo);
280 spot = P_Random() % MaceSpotCount;
281 mo->x = MaceSpots[spot].x;
282 mo->y = MaceSpots[spot].y;
283 ss = R_PointInSubsector(mo->x, mo->y);
284 mo->z = mo->floorz = ss->sector->floorheight;
285 mo->ceilingz = ss->sector->ceilingheight;
286 P_SetThingPosition(mo);
287 }
288
289 //---------------------------------------------------------------------------
290 //
291 // PROC P_CloseWeapons
292 //
293 // Called at level load after things are loaded.
294 //
295 //---------------------------------------------------------------------------
296
P_CloseWeapons(void)297 void P_CloseWeapons(void)
298 {
299 int spot;
300
301 if (!MaceSpotCount)
302 { // No maces placed
303 return;
304 }
305 if (!deathmatch && P_Random() < 64)
306 { // Sometimes doesn't show up if not in deathmatch
307 return;
308 }
309 spot = P_Random() % MaceSpotCount;
310 P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE);
311 }
312
313 //---------------------------------------------------------------------------
314 //
315 // PROC P_SetPsprite
316 //
317 //---------------------------------------------------------------------------
318
P_SetPsprite(player_t * player,int position,statenum_t stnum)319 void P_SetPsprite(player_t * player, int position, statenum_t stnum)
320 {
321 pspdef_t *psp;
322 state_t *state;
323
324 psp = &player->psprites[position];
325 do
326 {
327 if (!stnum)
328 { // Object removed itself.
329 psp->state = NULL;
330 break;
331 }
332 state = &states[stnum];
333 psp->state = state;
334 psp->tics = state->tics; // could be 0
335 if (state->misc1)
336 { // Set coordinates.
337 psp->sx = state->misc1 << FRACBITS;
338 psp->sy = state->misc2 << FRACBITS;
339 }
340 if (state->action)
341 { // Call action routine.
342 state->action(player, psp);
343 if (!psp->state)
344 {
345 break;
346 }
347 }
348 stnum = psp->state->nextstate;
349 }
350 while (!psp->tics); // An initial state of 0 could cycle through.
351 }
352
353 /*
354 =================
355 =
356 = P_CalcSwing
357 =
358 =================
359 */
360
361 /*
362 fixed_t swingx, swingy;
363 void P_CalcSwing (player_t *player)
364 {
365 fixed_t swing;
366 int angle;
367
368 // OPTIMIZE: tablify this
369
370 swing = player->bob;
371
372 angle = (FINEANGLES/70*leveltime)&FINEMASK;
373 swingx = FixedMul ( swing, finesine[angle]);
374
375 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
376 swingy = -FixedMul ( swingx, finesine[angle]);
377 }
378 */
379
380 //---------------------------------------------------------------------------
381 //
382 // PROC P_ActivateBeak
383 //
384 //---------------------------------------------------------------------------
385
P_ActivateBeak(player_t * player)386 void P_ActivateBeak(player_t * player)
387 {
388 player->pendingweapon = wp_nochange;
389 player->readyweapon = wp_beak;
390 player->psprites[ps_weapon].sy = WEAPONTOP;
391 P_SetPsprite(player, ps_weapon, S_BEAKREADY);
392 }
393
394 //---------------------------------------------------------------------------
395 //
396 // PROC P_PostChickenWeapon
397 //
398 //---------------------------------------------------------------------------
399
P_PostChickenWeapon(player_t * player,weapontype_t weapon)400 void P_PostChickenWeapon(player_t * player, weapontype_t weapon)
401 {
402 if (weapon == wp_beak)
403 { // Should never happen
404 weapon = wp_staff;
405 }
406 player->pendingweapon = wp_nochange;
407 player->readyweapon = weapon;
408 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
409 P_SetPsprite(player, ps_weapon, wpnlev1info[weapon].upstate);
410 }
411
412 //---------------------------------------------------------------------------
413 //
414 // PROC P_BringUpWeapon
415 //
416 // Starts bringing the pending weapon up from the bottom of the screen.
417 //
418 //---------------------------------------------------------------------------
419
P_BringUpWeapon(player_t * player)420 void P_BringUpWeapon(player_t * player)
421 {
422 statenum_t new;
423
424 if (player->pendingweapon == wp_nochange)
425 {
426 player->pendingweapon = player->readyweapon;
427 }
428 if (player->pendingweapon == wp_gauntlets)
429 {
430 S_StartSound(player->mo, sfx_gntact);
431 }
432 if (player->powers[pw_weaponlevel2])
433 {
434 new = wpnlev2info[player->pendingweapon].upstate;
435 }
436 else
437 {
438 new = wpnlev1info[player->pendingweapon].upstate;
439 }
440 player->pendingweapon = wp_nochange;
441 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
442 P_SetPsprite(player, ps_weapon, new);
443 }
444
445 //---------------------------------------------------------------------------
446 //
447 // FUNC P_CheckAmmo
448 //
449 // Returns true if there is enough ammo to shoot. If not, selects the
450 // next weapon to use.
451 //
452 //---------------------------------------------------------------------------
453
P_CheckAmmo(player_t * player)454 boolean P_CheckAmmo(player_t * player)
455 {
456 ammotype_t ammo;
457 int *ammoUse;
458 int count;
459
460 ammo = wpnlev1info[player->readyweapon].ammo;
461 if (player->powers[pw_weaponlevel2] && !deathmatch)
462 {
463 ammoUse = WeaponAmmoUsePL2;
464 }
465 else
466 {
467 ammoUse = WeaponAmmoUsePL1;
468 }
469 count = ammoUse[player->readyweapon];
470 if (ammo == am_noammo || player->ammo[ammo] >= count)
471 {
472 return (true);
473 }
474 // out of ammo, pick a weapon to change to
475 do
476 {
477 if (player->weaponowned[wp_skullrod]
478 && player->ammo[am_skullrod] > ammoUse[wp_skullrod])
479 {
480 player->pendingweapon = wp_skullrod;
481 }
482 else if (player->weaponowned[wp_blaster]
483 && player->ammo[am_blaster] > ammoUse[wp_blaster])
484 {
485 player->pendingweapon = wp_blaster;
486 }
487 else if (player->weaponowned[wp_crossbow]
488 && player->ammo[am_crossbow] > ammoUse[wp_crossbow])
489 {
490 player->pendingweapon = wp_crossbow;
491 }
492 else if (player->weaponowned[wp_mace]
493 && player->ammo[am_mace] > ammoUse[wp_mace])
494 {
495 player->pendingweapon = wp_mace;
496 }
497 else if (player->ammo[am_goldwand] > ammoUse[wp_goldwand])
498 {
499 player->pendingweapon = wp_goldwand;
500 }
501 else if (player->weaponowned[wp_gauntlets])
502 {
503 player->pendingweapon = wp_gauntlets;
504 }
505 else if (player->weaponowned[wp_phoenixrod]
506 && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod])
507 {
508 player->pendingweapon = wp_phoenixrod;
509 }
510 else
511 {
512 player->pendingweapon = wp_staff;
513 }
514 }
515 while (player->pendingweapon == wp_nochange);
516 if (player->powers[pw_weaponlevel2])
517 {
518 P_SetPsprite(player, ps_weapon,
519 wpnlev2info[player->readyweapon].downstate);
520 }
521 else
522 {
523 P_SetPsprite(player, ps_weapon,
524 wpnlev1info[player->readyweapon].downstate);
525 }
526 return (false);
527 }
528
529 //---------------------------------------------------------------------------
530 //
531 // PROC P_FireWeapon
532 //
533 //---------------------------------------------------------------------------
534
P_FireWeapon(player_t * player)535 void P_FireWeapon(player_t * player)
536 {
537 weaponinfo_t *wpinfo;
538 statenum_t attackState;
539
540 if (!P_CheckAmmo(player))
541 {
542 return;
543 }
544 P_SetMobjState(player->mo, S_PLAY_ATK2);
545 wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[0]
546 : &wpnlev1info[0];
547 attackState = player->refire ? wpinfo[player->readyweapon].holdatkstate
548 : wpinfo[player->readyweapon].atkstate;
549 P_SetPsprite(player, ps_weapon, attackState);
550 P_NoiseAlert(player->mo, player->mo);
551 if (player->readyweapon == wp_gauntlets && !player->refire)
552 { // Play the sound for the initial gauntlet attack
553 S_StartSound(player->mo, sfx_gntuse);
554 }
555 }
556
557 //---------------------------------------------------------------------------
558 //
559 // PROC P_DropWeapon
560 //
561 // The player died, so put the weapon away.
562 //
563 //---------------------------------------------------------------------------
564
P_DropWeapon(player_t * player)565 void P_DropWeapon(player_t * player)
566 {
567 if (player->powers[pw_weaponlevel2])
568 {
569 P_SetPsprite(player, ps_weapon,
570 wpnlev2info[player->readyweapon].downstate);
571 }
572 else
573 {
574 P_SetPsprite(player, ps_weapon,
575 wpnlev1info[player->readyweapon].downstate);
576 }
577 }
578
579 //---------------------------------------------------------------------------
580 //
581 // PROC A_WeaponReady
582 //
583 // The player can fire the weapon or change to another weapon at this time.
584 //
585 //---------------------------------------------------------------------------
586
A_WeaponReady(player_t * player,pspdef_t * psp)587 void A_WeaponReady(player_t * player, pspdef_t * psp)
588 {
589 int angle;
590
591 if (player->chickenTics)
592 { // Change to the chicken beak
593 P_ActivateBeak(player);
594 return;
595 }
596 // Change player from attack state
597 if (player->mo->state == &states[S_PLAY_ATK1]
598 || player->mo->state == &states[S_PLAY_ATK2])
599 {
600 P_SetMobjState(player->mo, S_PLAY);
601 }
602 // Check for staff PL2 active sound
603 if ((player->readyweapon == wp_staff)
604 && (psp->state == &states[S_STAFFREADY2_1]) && P_Random() < 128)
605 {
606 S_StartSound(player->mo, sfx_stfcrk);
607 }
608 // Put the weapon away if the player has a pending weapon or has
609 // died.
610 if (player->pendingweapon != wp_nochange || !player->health)
611 {
612 if (player->powers[pw_weaponlevel2])
613 {
614 P_SetPsprite(player, ps_weapon,
615 wpnlev2info[player->readyweapon].downstate);
616 }
617 else
618 {
619 P_SetPsprite(player, ps_weapon,
620 wpnlev1info[player->readyweapon].downstate);
621 }
622 return;
623 }
624
625 // Check for fire. The phoenix rod does not auto fire.
626 if (player->cmd.buttons & BT_ATTACK)
627 {
628 if (!player->attackdown || (player->readyweapon != wp_phoenixrod))
629 {
630 player->attackdown = true;
631 P_FireWeapon(player);
632 return;
633 }
634 }
635 else
636 {
637 player->attackdown = false;
638 }
639
640 // Bob the weapon based on movement speed.
641 angle = (128 * leveltime) & FINEMASK;
642 psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
643 angle &= FINEANGLES / 2 - 1;
644 psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
645 }
646
647 //---------------------------------------------------------------------------
648 //
649 // PROC P_UpdateBeak
650 //
651 //---------------------------------------------------------------------------
652
P_UpdateBeak(player_t * player,pspdef_t * psp)653 void P_UpdateBeak(player_t * player, pspdef_t * psp)
654 {
655 psp->sy = WEAPONTOP + (player->chickenPeck << (FRACBITS - 1));
656 }
657
658 //---------------------------------------------------------------------------
659 //
660 // PROC A_BeakReady
661 //
662 //---------------------------------------------------------------------------
663
A_BeakReady(player_t * player,pspdef_t * psp)664 void A_BeakReady(player_t * player, pspdef_t * psp)
665 {
666 if (player->cmd.buttons & BT_ATTACK)
667 { // Chicken beak attack
668 player->attackdown = true;
669 P_SetMobjState(player->mo, S_CHICPLAY_ATK1);
670 if (player->powers[pw_weaponlevel2])
671 {
672 P_SetPsprite(player, ps_weapon, S_BEAKATK2_1);
673 }
674 else
675 {
676 P_SetPsprite(player, ps_weapon, S_BEAKATK1_1);
677 }
678 P_NoiseAlert(player->mo, player->mo);
679 }
680 else
681 {
682 if (player->mo->state == &states[S_CHICPLAY_ATK1])
683 { // Take out of attack state
684 P_SetMobjState(player->mo, S_CHICPLAY);
685 }
686 player->attackdown = false;
687 }
688 }
689
690 //---------------------------------------------------------------------------
691 //
692 // PROC A_ReFire
693 //
694 // The player can re fire the weapon without lowering it entirely.
695 //
696 //---------------------------------------------------------------------------
697
A_ReFire(player_t * player,pspdef_t * psp)698 void A_ReFire(player_t * player, pspdef_t * psp)
699 {
700 if ((player->cmd.buttons & BT_ATTACK)
701 && player->pendingweapon == wp_nochange && player->health)
702 {
703 player->refire++;
704 P_FireWeapon(player);
705 }
706 else
707 {
708 player->refire = 0;
709 P_CheckAmmo(player);
710 }
711 }
712
713 //---------------------------------------------------------------------------
714 //
715 // PROC A_Lower
716 //
717 //---------------------------------------------------------------------------
718
A_Lower(player_t * player,pspdef_t * psp)719 void A_Lower(player_t * player, pspdef_t * psp)
720 {
721 if (player->chickenTics)
722 {
723 psp->sy = WEAPONBOTTOM;
724 }
725 else
726 {
727 psp->sy += LOWERSPEED;
728 }
729 if (psp->sy < WEAPONBOTTOM)
730 { // Not lowered all the way yet
731 return;
732 }
733 if (player->playerstate == PST_DEAD)
734 { // Player is dead, so don't bring up a pending weapon
735 psp->sy = WEAPONBOTTOM;
736 return;
737 }
738 if (!player->health)
739 { // Player is dead, so keep the weapon off screen
740 P_SetPsprite(player, ps_weapon, S_NULL);
741 return;
742 }
743 player->readyweapon = player->pendingweapon;
744 P_BringUpWeapon(player);
745 }
746
747 //---------------------------------------------------------------------------
748 //
749 // PROC A_BeakRaise
750 //
751 //---------------------------------------------------------------------------
752
A_BeakRaise(player_t * player,pspdef_t * psp)753 void A_BeakRaise(player_t * player, pspdef_t * psp)
754 {
755 psp->sy = WEAPONTOP;
756 P_SetPsprite(player, ps_weapon,
757 wpnlev1info[player->readyweapon].readystate);
758 }
759
760 //---------------------------------------------------------------------------
761 //
762 // PROC A_Raise
763 //
764 //---------------------------------------------------------------------------
765
A_Raise(player_t * player,pspdef_t * psp)766 void A_Raise(player_t * player, pspdef_t * psp)
767 {
768 psp->sy -= RAISESPEED;
769 if (psp->sy > WEAPONTOP)
770 { // Not raised all the way yet
771 return;
772 }
773 psp->sy = WEAPONTOP;
774 if (player->powers[pw_weaponlevel2])
775 {
776 P_SetPsprite(player, ps_weapon,
777 wpnlev2info[player->readyweapon].readystate);
778 }
779 else
780 {
781 P_SetPsprite(player, ps_weapon,
782 wpnlev1info[player->readyweapon].readystate);
783 }
784 }
785
786 /*
787 ===============
788 =
789 = P_BulletSlope
790 =
791 = Sets a slope so a near miss is at aproximately the height of the
792 = intended target
793 =
794 ===============
795 */
796
P_BulletSlope(mobj_t * mo)797 void P_BulletSlope(mobj_t * mo)
798 {
799 angle_t an;
800
801 //
802 // see which target is to be aimed at
803 //
804 an = mo->angle;
805 bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
806 if (!linetarget)
807 {
808 an += 1 << 26;
809 bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
810 if (!linetarget)
811 {
812 an -= 2 << 26;
813 bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
814 }
815 if (!linetarget)
816 {
817 an += 2 << 26;
818 bulletslope = (mo->player->lookdir << FRACBITS) / 173;
819 }
820 }
821 }
822
823 //****************************************************************************
824 //
825 // WEAPON ATTACKS
826 //
827 //****************************************************************************
828
829 //----------------------------------------------------------------------------
830 //
831 // PROC A_BeakAttackPL1
832 //
833 //----------------------------------------------------------------------------
834
A_BeakAttackPL1(player_t * player,pspdef_t * psp)835 void A_BeakAttackPL1(player_t * player, pspdef_t * psp)
836 {
837 angle_t angle;
838 int damage;
839 int slope;
840
841 damage = 1 + (P_Random() & 3);
842 angle = player->mo->angle;
843 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
844 PuffType = MT_BEAKPUFF;
845 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
846 if (linetarget)
847 {
848 player->mo->angle = R_PointToAngle2(player->mo->x,
849 player->mo->y, linetarget->x,
850 linetarget->y);
851 }
852 S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
853 player->chickenPeck = 12;
854 psp->tics -= P_Random() & 7;
855 }
856
857 //----------------------------------------------------------------------------
858 //
859 // PROC A_BeakAttackPL2
860 //
861 //----------------------------------------------------------------------------
862
A_BeakAttackPL2(player_t * player,pspdef_t * psp)863 void A_BeakAttackPL2(player_t * player, pspdef_t * psp)
864 {
865 angle_t angle;
866 int damage;
867 int slope;
868
869 damage = HITDICE(4);
870 angle = player->mo->angle;
871 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
872 PuffType = MT_BEAKPUFF;
873 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
874 if (linetarget)
875 {
876 player->mo->angle = R_PointToAngle2(player->mo->x,
877 player->mo->y, linetarget->x,
878 linetarget->y);
879 }
880 S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
881 player->chickenPeck = 12;
882 psp->tics -= P_Random() & 3;
883 }
884
885 //----------------------------------------------------------------------------
886 //
887 // PROC A_StaffAttackPL1
888 //
889 //----------------------------------------------------------------------------
890
A_StaffAttackPL1(player_t * player,pspdef_t * psp)891 void A_StaffAttackPL1(player_t * player, pspdef_t * psp)
892 {
893 angle_t angle;
894 int damage;
895 int slope;
896
897 damage = 5 + (P_Random() & 15);
898 angle = player->mo->angle;
899 angle += P_SubRandom() << 18;
900 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
901 PuffType = MT_STAFFPUFF;
902 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
903 if (linetarget)
904 {
905 //S_StartSound(player->mo, sfx_stfhit);
906 // turn to face target
907 player->mo->angle = R_PointToAngle2(player->mo->x,
908 player->mo->y, linetarget->x,
909 linetarget->y);
910 }
911 }
912
913 //----------------------------------------------------------------------------
914 //
915 // PROC A_StaffAttackPL2
916 //
917 //----------------------------------------------------------------------------
918
A_StaffAttackPL2(player_t * player,pspdef_t * psp)919 void A_StaffAttackPL2(player_t * player, pspdef_t * psp)
920 {
921 angle_t angle;
922 int damage;
923 int slope;
924
925 // P_inter.c:P_DamageMobj() handles target momentums
926 damage = 18 + (P_Random() & 63);
927 angle = player->mo->angle;
928 angle += P_SubRandom() << 18;
929 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
930 PuffType = MT_STAFFPUFF2;
931 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
932 if (linetarget)
933 {
934 //S_StartSound(player->mo, sfx_stfpow);
935 // turn to face target
936 player->mo->angle = R_PointToAngle2(player->mo->x,
937 player->mo->y, linetarget->x,
938 linetarget->y);
939 }
940 }
941
942 //----------------------------------------------------------------------------
943 //
944 // PROC A_FireBlasterPL1
945 //
946 //----------------------------------------------------------------------------
947
A_FireBlasterPL1(player_t * player,pspdef_t * psp)948 void A_FireBlasterPL1(player_t * player, pspdef_t * psp)
949 {
950 mobj_t *mo;
951 angle_t angle;
952 int damage;
953
954 mo = player->mo;
955 S_StartSound(mo, sfx_gldhit);
956 player->ammo[am_blaster] -= USE_BLSR_AMMO_1;
957 P_BulletSlope(mo);
958 damage = HITDICE(4);
959 angle = mo->angle;
960 if (player->refire)
961 {
962 angle += P_SubRandom() << 18;
963 }
964 PuffType = MT_BLASTERPUFF1;
965 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
966 S_StartSound(player->mo, sfx_blssht);
967 }
968
969 //----------------------------------------------------------------------------
970 //
971 // PROC A_FireBlasterPL2
972 //
973 //----------------------------------------------------------------------------
974
A_FireBlasterPL2(player_t * player,pspdef_t * psp)975 void A_FireBlasterPL2(player_t * player, pspdef_t * psp)
976 {
977 mobj_t *mo;
978
979 player->ammo[am_blaster] -=
980 deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2;
981 mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1);
982 if (mo)
983 {
984 mo->thinker.function = P_BlasterMobjThinker;
985 }
986 S_StartSound(player->mo, sfx_blssht);
987 }
988
989 //----------------------------------------------------------------------------
990 //
991 // PROC A_FireGoldWandPL1
992 //
993 //----------------------------------------------------------------------------
994
A_FireGoldWandPL1(player_t * player,pspdef_t * psp)995 void A_FireGoldWandPL1(player_t * player, pspdef_t * psp)
996 {
997 mobj_t *mo;
998 angle_t angle;
999 int damage;
1000
1001 mo = player->mo;
1002 player->ammo[am_goldwand] -= USE_GWND_AMMO_1;
1003 P_BulletSlope(mo);
1004 damage = 7 + (P_Random() & 7);
1005 angle = mo->angle;
1006 if (player->refire)
1007 {
1008 angle += P_SubRandom() << 18;
1009 }
1010 PuffType = MT_GOLDWANDPUFF1;
1011 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
1012 S_StartSound(player->mo, sfx_gldhit);
1013 }
1014
1015 //----------------------------------------------------------------------------
1016 //
1017 // PROC A_FireGoldWandPL2
1018 //
1019 //----------------------------------------------------------------------------
1020
A_FireGoldWandPL2(player_t * player,pspdef_t * psp)1021 void A_FireGoldWandPL2(player_t * player, pspdef_t * psp)
1022 {
1023 int i;
1024 mobj_t *mo;
1025 angle_t angle;
1026 int damage;
1027 fixed_t momz;
1028
1029 mo = player->mo;
1030 player->ammo[am_goldwand] -=
1031 deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2;
1032 PuffType = MT_GOLDWANDPUFF2;
1033 P_BulletSlope(mo);
1034 momz = FixedMul(mobjinfo[MT_GOLDWANDFX2].speed, bulletslope);
1035 P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle - (ANG45 / 8), momz);
1036 P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle + (ANG45 / 8), momz);
1037 angle = mo->angle - (ANG45 / 8);
1038 for (i = 0; i < 5; i++)
1039 {
1040 damage = 1 + (P_Random() & 7);
1041 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
1042 angle += ((ANG45 / 8) * 2) / 4;
1043 }
1044 S_StartSound(player->mo, sfx_gldhit);
1045 }
1046
1047 //----------------------------------------------------------------------------
1048 //
1049 // PROC A_FireMacePL1B
1050 //
1051 //----------------------------------------------------------------------------
1052
A_FireMacePL1B(player_t * player,pspdef_t * psp)1053 void A_FireMacePL1B(player_t * player, pspdef_t * psp)
1054 {
1055 mobj_t *pmo;
1056 mobj_t *ball;
1057 angle_t angle;
1058
1059 if (player->ammo[am_mace] < USE_MACE_AMMO_1)
1060 {
1061 return;
1062 }
1063 player->ammo[am_mace] -= USE_MACE_AMMO_1;
1064 pmo = player->mo;
1065
1066 // Vanilla bug here:
1067 // Original code here looks like:
1068 // (pmo->flags2 & MF2_FEETARECLIPPED != 0)
1069 // C's operator precedence interprets this as:
1070 // (pmo->flags2 & (MF2_FEETARECLIPPED != 0))
1071 // Which simplifies to:
1072 // (pmo->flags2 & 1)
1073 ball = P_SpawnMobj(pmo->x, pmo->y, pmo->z + 28 * FRACUNIT
1074 - FOOTCLIPSIZE * (pmo->flags2 & 1), MT_MACEFX2);
1075
1076 ball->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
1077 angle = pmo->angle;
1078 ball->target = pmo;
1079 ball->angle = angle;
1080 ball->z += (player->lookdir) << (FRACBITS - 4);
1081 angle >>= ANGLETOFINESHIFT;
1082 ball->momx = (pmo->momx >> 1)
1083 + FixedMul(ball->info->speed, finecosine[angle]);
1084 ball->momy = (pmo->momy >> 1)
1085 + FixedMul(ball->info->speed, finesine[angle]);
1086 S_StartSound(ball, sfx_lobsht);
1087 P_CheckMissileSpawn(ball);
1088 }
1089
1090 //----------------------------------------------------------------------------
1091 //
1092 // PROC A_FireMacePL1
1093 //
1094 //----------------------------------------------------------------------------
1095
A_FireMacePL1(player_t * player,pspdef_t * psp)1096 void A_FireMacePL1(player_t * player, pspdef_t * psp)
1097 {
1098 mobj_t *ball;
1099
1100 if (P_Random() < 28)
1101 {
1102 A_FireMacePL1B(player, psp);
1103 return;
1104 }
1105 if (player->ammo[am_mace] < USE_MACE_AMMO_1)
1106 {
1107 return;
1108 }
1109 player->ammo[am_mace] -= USE_MACE_AMMO_1;
1110 psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
1111 psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
1112 ball = P_SPMAngle(player->mo, MT_MACEFX1, player->mo->angle
1113 + (((P_Random() & 7) - 4) << 24));
1114 if (ball)
1115 {
1116 ball->special1.i = 16; // tics till dropoff
1117 }
1118 }
1119
1120 //----------------------------------------------------------------------------
1121 //
1122 // PROC A_MacePL1Check
1123 //
1124 //----------------------------------------------------------------------------
1125
A_MacePL1Check(mobj_t * ball)1126 void A_MacePL1Check(mobj_t * ball)
1127 {
1128 angle_t angle;
1129
1130 if (ball->special1.i == 0)
1131 {
1132 return;
1133 }
1134 ball->special1.i -= 4;
1135 if (ball->special1.i > 0)
1136 {
1137 return;
1138 }
1139 ball->special1.i = 0;
1140 ball->flags2 |= MF2_LOGRAV;
1141 angle = ball->angle >> ANGLETOFINESHIFT;
1142 ball->momx = FixedMul(7 * FRACUNIT, finecosine[angle]);
1143 ball->momy = FixedMul(7 * FRACUNIT, finesine[angle]);
1144 ball->momz -= ball->momz >> 1;
1145 }
1146
1147 //----------------------------------------------------------------------------
1148 //
1149 // PROC A_MaceBallImpact
1150 //
1151 //----------------------------------------------------------------------------
1152
A_MaceBallImpact(mobj_t * ball)1153 void A_MaceBallImpact(mobj_t * ball)
1154 {
1155 if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1156 { // Landed in some sort of liquid
1157 P_RemoveMobj(ball);
1158 return;
1159 }
1160 if ((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz)
1161 && ball->momz)
1162 { // Bounce
1163 ball->health = MAGIC_JUNK;
1164 ball->momz = (ball->momz * 192) >> 8;
1165 ball->flags2 &= ~MF2_FLOORBOUNCE;
1166 P_SetMobjState(ball, ball->info->spawnstate);
1167 S_StartSound(ball, sfx_bounce);
1168 }
1169 else
1170 { // Explode
1171 ball->flags |= MF_NOGRAVITY;
1172 ball->flags2 &= ~MF2_LOGRAV;
1173 S_StartSound(ball, sfx_lobhit);
1174 }
1175 }
1176
1177 //----------------------------------------------------------------------------
1178 //
1179 // PROC A_MaceBallImpact2
1180 //
1181 //----------------------------------------------------------------------------
1182
A_MaceBallImpact2(mobj_t * ball)1183 void A_MaceBallImpact2(mobj_t * ball)
1184 {
1185 mobj_t *tiny;
1186 angle_t angle;
1187
1188 if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1189 { // Landed in some sort of liquid
1190 P_RemoveMobj(ball);
1191 return;
1192 }
1193 if ((ball->z != ball->floorz) || (ball->momz < 2 * FRACUNIT))
1194 { // Explode
1195 ball->momx = ball->momy = ball->momz = 0;
1196 ball->flags |= MF_NOGRAVITY;
1197 ball->flags2 &= ~(MF2_LOGRAV | MF2_FLOORBOUNCE);
1198 }
1199 else
1200 { // Bounce
1201 ball->momz = (ball->momz * 192) >> 8;
1202 P_SetMobjState(ball, ball->info->spawnstate);
1203
1204 tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
1205 angle = ball->angle + ANG90;
1206 tiny->target = ball->target;
1207 tiny->angle = angle;
1208 angle >>= ANGLETOFINESHIFT;
1209 tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
1210 finecosine[angle]);
1211 tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
1212 finesine[angle]);
1213 tiny->momz = ball->momz;
1214 P_CheckMissileSpawn(tiny);
1215
1216 tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
1217 angle = ball->angle - ANG90;
1218 tiny->target = ball->target;
1219 tiny->angle = angle;
1220 angle >>= ANGLETOFINESHIFT;
1221 tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
1222 finecosine[angle]);
1223 tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
1224 finesine[angle]);
1225 tiny->momz = ball->momz;
1226 P_CheckMissileSpawn(tiny);
1227 }
1228 }
1229
1230 //----------------------------------------------------------------------------
1231 //
1232 // PROC A_FireMacePL2
1233 //
1234 //----------------------------------------------------------------------------
1235
A_FireMacePL2(player_t * player,pspdef_t * psp)1236 void A_FireMacePL2(player_t * player, pspdef_t * psp)
1237 {
1238 mobj_t *mo;
1239
1240 player->ammo[am_mace] -= deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2;
1241 mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4);
1242 if (mo)
1243 {
1244 mo->momx += player->mo->momx;
1245 mo->momy += player->mo->momy;
1246 mo->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
1247 if (linetarget)
1248 {
1249 mo->special1.m = linetarget;
1250 }
1251 }
1252 S_StartSound(player->mo, sfx_lobsht);
1253 }
1254
1255 //----------------------------------------------------------------------------
1256 //
1257 // PROC A_DeathBallImpact
1258 //
1259 //----------------------------------------------------------------------------
1260
A_DeathBallImpact(mobj_t * ball)1261 void A_DeathBallImpact(mobj_t * ball)
1262 {
1263 int i;
1264 mobj_t *target;
1265 angle_t angle;
1266 boolean newAngle;
1267
1268 if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1269 { // Landed in some sort of liquid
1270 P_RemoveMobj(ball);
1271 return;
1272 }
1273 if ((ball->z <= ball->floorz) && ball->momz)
1274 { // Bounce
1275 newAngle = false;
1276 target = (mobj_t *) ball->special1.m;
1277 if (target)
1278 {
1279 if (!(target->flags & MF_SHOOTABLE))
1280 { // Target died
1281 ball->special1.m = NULL;
1282 }
1283 else
1284 { // Seek
1285 angle = R_PointToAngle2(ball->x, ball->y,
1286 target->x, target->y);
1287 newAngle = true;
1288 }
1289 }
1290 else
1291 { // Find new target
1292 angle = 0;
1293 for (i = 0; i < 16; i++)
1294 {
1295 P_AimLineAttack(ball, angle, 10 * 64 * FRACUNIT);
1296 if (linetarget && ball->target != linetarget)
1297 {
1298 ball->special1.m = linetarget;
1299 angle = R_PointToAngle2(ball->x, ball->y,
1300 linetarget->x, linetarget->y);
1301 newAngle = true;
1302 break;
1303 }
1304 angle += ANG45 / 2;
1305 }
1306 }
1307 if (newAngle)
1308 {
1309 ball->angle = angle;
1310 angle >>= ANGLETOFINESHIFT;
1311 ball->momx = FixedMul(ball->info->speed, finecosine[angle]);
1312 ball->momy = FixedMul(ball->info->speed, finesine[angle]);
1313 }
1314 P_SetMobjState(ball, ball->info->spawnstate);
1315 S_StartSound(ball, sfx_pstop);
1316 }
1317 else
1318 { // Explode
1319 ball->flags |= MF_NOGRAVITY;
1320 ball->flags2 &= ~MF2_LOGRAV;
1321 S_StartSound(ball, sfx_phohit);
1322 }
1323 }
1324
1325 //----------------------------------------------------------------------------
1326 //
1327 // PROC A_SpawnRippers
1328 //
1329 //----------------------------------------------------------------------------
1330
A_SpawnRippers(mobj_t * actor)1331 void A_SpawnRippers(mobj_t * actor)
1332 {
1333 unsigned int i;
1334 angle_t angle;
1335 mobj_t *ripper;
1336
1337 for (i = 0; i < 8; i++)
1338 {
1339 ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER);
1340 angle = i * ANG45;
1341 ripper->target = actor->target;
1342 ripper->angle = angle;
1343 angle >>= ANGLETOFINESHIFT;
1344 ripper->momx = FixedMul(ripper->info->speed, finecosine[angle]);
1345 ripper->momy = FixedMul(ripper->info->speed, finesine[angle]);
1346 P_CheckMissileSpawn(ripper);
1347 }
1348 }
1349
1350 //----------------------------------------------------------------------------
1351 //
1352 // PROC A_FireCrossbowPL1
1353 //
1354 //----------------------------------------------------------------------------
1355
A_FireCrossbowPL1(player_t * player,pspdef_t * psp)1356 void A_FireCrossbowPL1(player_t * player, pspdef_t * psp)
1357 {
1358 mobj_t *pmo;
1359
1360 pmo = player->mo;
1361 player->ammo[am_crossbow] -= USE_CBOW_AMMO_1;
1362 P_SpawnPlayerMissile(pmo, MT_CRBOWFX1);
1363 P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 10));
1364 P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 10));
1365 }
1366
1367 //----------------------------------------------------------------------------
1368 //
1369 // PROC A_FireCrossbowPL2
1370 //
1371 //----------------------------------------------------------------------------
1372
A_FireCrossbowPL2(player_t * player,pspdef_t * psp)1373 void A_FireCrossbowPL2(player_t * player, pspdef_t * psp)
1374 {
1375 mobj_t *pmo;
1376
1377 pmo = player->mo;
1378 player->ammo[am_crossbow] -=
1379 deathmatch ? USE_CBOW_AMMO_1 : USE_CBOW_AMMO_2;
1380 P_SpawnPlayerMissile(pmo, MT_CRBOWFX2);
1381 P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle - (ANG45 / 10));
1382 P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle + (ANG45 / 10));
1383 P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 5));
1384 P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 5));
1385 }
1386
1387 //----------------------------------------------------------------------------
1388 //
1389 // PROC A_BoltSpark
1390 //
1391 //----------------------------------------------------------------------------
1392
A_BoltSpark(mobj_t * bolt)1393 void A_BoltSpark(mobj_t * bolt)
1394 {
1395 mobj_t *spark;
1396
1397 if (P_Random() > 50)
1398 {
1399 spark = P_SpawnMobj(bolt->x, bolt->y, bolt->z, MT_CRBOWFX4);
1400 spark->x += P_SubRandom() << 10;
1401 spark->y += P_SubRandom() << 10;
1402 }
1403 }
1404
1405 //----------------------------------------------------------------------------
1406 //
1407 // PROC A_FireSkullRodPL1
1408 //
1409 //----------------------------------------------------------------------------
1410
A_FireSkullRodPL1(player_t * player,pspdef_t * psp)1411 void A_FireSkullRodPL1(player_t * player, pspdef_t * psp)
1412 {
1413 mobj_t *mo;
1414
1415 if (player->ammo[am_skullrod] < USE_SKRD_AMMO_1)
1416 {
1417 return;
1418 }
1419 player->ammo[am_skullrod] -= USE_SKRD_AMMO_1;
1420 mo = P_SpawnPlayerMissile(player->mo, MT_HORNRODFX1);
1421 // Randomize the first frame
1422 if (mo && P_Random() > 128)
1423 {
1424 P_SetMobjState(mo, S_HRODFX1_2);
1425 }
1426 }
1427
1428 //----------------------------------------------------------------------------
1429 //
1430 // PROC A_FireSkullRodPL2
1431 //
1432 // The special2 field holds the player number that shot the rain missile.
1433 // The special1 field is used for the seeking routines, then as a counter
1434 // for the sound looping.
1435 //
1436 //----------------------------------------------------------------------------
1437
A_FireSkullRodPL2(player_t * player,pspdef_t * psp)1438 void A_FireSkullRodPL2(player_t * player, pspdef_t * psp)
1439 {
1440 player->ammo[am_skullrod] -=
1441 deathmatch ? USE_SKRD_AMMO_1 : USE_SKRD_AMMO_2;
1442 P_SpawnPlayerMissile(player->mo, MT_HORNRODFX2);
1443 // Use MissileMobj instead of the return value from
1444 // P_SpawnPlayerMissile because we need to give info to the mobj
1445 // even if it exploded immediately.
1446 if (netgame)
1447 { // Multi-player game
1448 MissileMobj->special2.i = P_GetPlayerNum(player);
1449 }
1450 else
1451 { // Always use red missiles in single player games
1452 MissileMobj->special2.i = 2;
1453 }
1454 if (linetarget)
1455 {
1456 MissileMobj->special1.m = linetarget;
1457 }
1458 S_StartSound(MissileMobj, sfx_hrnpow);
1459 }
1460
1461 //----------------------------------------------------------------------------
1462 //
1463 // PROC A_SkullRodPL2Seek
1464 //
1465 //----------------------------------------------------------------------------
1466
A_SkullRodPL2Seek(mobj_t * actor)1467 void A_SkullRodPL2Seek(mobj_t * actor)
1468 {
1469 P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30);
1470 }
1471
1472 //----------------------------------------------------------------------------
1473 //
1474 // PROC A_AddPlayerRain
1475 //
1476 //----------------------------------------------------------------------------
1477
A_AddPlayerRain(mobj_t * actor)1478 void A_AddPlayerRain(mobj_t * actor)
1479 {
1480 int playerNum;
1481 player_t *player;
1482
1483 playerNum = netgame ? actor->special2.i : 0;
1484 if (!playeringame[playerNum])
1485 { // Player left the game
1486 return;
1487 }
1488 player = &players[playerNum];
1489 if (player->health <= 0)
1490 { // Player is dead
1491 return;
1492 }
1493 if (player->rain1 && player->rain2)
1494 { // Terminate an active rain
1495 if (player->rain1->health < player->rain2->health)
1496 {
1497 if (player->rain1->health > 16)
1498 {
1499 player->rain1->health = 16;
1500 }
1501 player->rain1 = NULL;
1502 }
1503 else
1504 {
1505 if (player->rain2->health > 16)
1506 {
1507 player->rain2->health = 16;
1508 }
1509 player->rain2 = NULL;
1510 }
1511 }
1512 // Add rain mobj to list
1513 if (player->rain1)
1514 {
1515 player->rain2 = actor;
1516 }
1517 else
1518 {
1519 player->rain1 = actor;
1520 }
1521 }
1522
1523 //----------------------------------------------------------------------------
1524 //
1525 // PROC A_SkullRodStorm
1526 //
1527 //----------------------------------------------------------------------------
1528
A_SkullRodStorm(mobj_t * actor)1529 void A_SkullRodStorm(mobj_t * actor)
1530 {
1531 fixed_t x;
1532 fixed_t y;
1533 mobj_t *mo;
1534 int playerNum;
1535 player_t *player;
1536
1537 if (actor->health-- == 0)
1538 {
1539 P_SetMobjState(actor, S_NULL);
1540 playerNum = netgame ? actor->special2.i : 0;
1541 if (!playeringame[playerNum])
1542 { // Player left the game
1543 return;
1544 }
1545 player = &players[playerNum];
1546 if (player->health <= 0)
1547 { // Player is dead
1548 return;
1549 }
1550 if (player->rain1 == actor)
1551 {
1552 player->rain1 = NULL;
1553 }
1554 else if (player->rain2 == actor)
1555 {
1556 player->rain2 = NULL;
1557 }
1558 return;
1559 }
1560 if (P_Random() < 25)
1561 { // Fudge rain frequency
1562 return;
1563 }
1564 x = actor->x + ((P_Random() & 127) - 64) * FRACUNIT;
1565 y = actor->y + ((P_Random() & 127) - 64) * FRACUNIT;
1566 mo = P_SpawnMobj(x, y, ONCEILINGZ, MT_RAINPLR1 + actor->special2.i);
1567 mo->target = actor->target;
1568 mo->momx = 1; // Force collision detection
1569 mo->momz = -mo->info->speed;
1570 mo->special2.i = actor->special2.i; // Transfer player number
1571 P_CheckMissileSpawn(mo);
1572 if (!(actor->special1.i & 31))
1573 {
1574 S_StartSound(actor, sfx_ramrain);
1575 }
1576 actor->special1.i++;
1577 }
1578
1579 //----------------------------------------------------------------------------
1580 //
1581 // PROC A_RainImpact
1582 //
1583 //----------------------------------------------------------------------------
1584
A_RainImpact(mobj_t * actor)1585 void A_RainImpact(mobj_t * actor)
1586 {
1587 if (actor->z > actor->floorz)
1588 {
1589 P_SetMobjState(actor, S_RAINAIRXPLR1_1 + actor->special2.i);
1590 }
1591 else if (P_Random() < 40)
1592 {
1593 P_HitFloor(actor);
1594 }
1595 }
1596
1597 //----------------------------------------------------------------------------
1598 //
1599 // PROC A_HideInCeiling
1600 //
1601 //----------------------------------------------------------------------------
1602
A_HideInCeiling(mobj_t * actor)1603 void A_HideInCeiling(mobj_t * actor)
1604 {
1605 actor->z = actor->ceilingz + 4 * FRACUNIT;
1606 }
1607
1608 //----------------------------------------------------------------------------
1609 //
1610 // PROC A_FirePhoenixPL1
1611 //
1612 //----------------------------------------------------------------------------
1613
A_FirePhoenixPL1(player_t * player,pspdef_t * psp)1614 void A_FirePhoenixPL1(player_t * player, pspdef_t * psp)
1615 {
1616 angle_t angle;
1617
1618 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_1;
1619 P_SpawnPlayerMissile(player->mo, MT_PHOENIXFX1);
1620 //P_SpawnPlayerMissile(player->mo, MT_MNTRFX2);
1621 angle = player->mo->angle + ANG180;
1622 angle >>= ANGLETOFINESHIFT;
1623 player->mo->momx += FixedMul(4 * FRACUNIT, finecosine[angle]);
1624 player->mo->momy += FixedMul(4 * FRACUNIT, finesine[angle]);
1625 }
1626
1627 //----------------------------------------------------------------------------
1628 //
1629 // PROC A_PhoenixPuff
1630 //
1631 //----------------------------------------------------------------------------
1632
A_PhoenixPuff(mobj_t * actor)1633 void A_PhoenixPuff(mobj_t * actor)
1634 {
1635 mobj_t *puff;
1636 angle_t angle;
1637
1638 P_SeekerMissile(actor, ANG1_X * 5, ANG1_X * 10);
1639 puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1640 angle = actor->angle + ANG90;
1641 angle >>= ANGLETOFINESHIFT;
1642 puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
1643 puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
1644 puff->momz = 0;
1645 puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1646 angle = actor->angle - ANG90;
1647 angle >>= ANGLETOFINESHIFT;
1648 puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
1649 puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
1650 puff->momz = 0;
1651 }
1652
1653 //
1654 // This function was present in the Heretic 1.0 executable for the
1655 // removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED).
1656 // The purpose of this object is unknown, as is this function.
1657 //
1658
A_RemovedPhoenixFunc(mobj_t * actor)1659 void A_RemovedPhoenixFunc(mobj_t *actor)
1660 {
1661 I_Error("Action function invoked for removed Phoenix action!");
1662 }
1663
1664 //----------------------------------------------------------------------------
1665 //
1666 // PROC A_InitPhoenixPL2
1667 //
1668 //----------------------------------------------------------------------------
1669
A_InitPhoenixPL2(player_t * player,pspdef_t * psp)1670 void A_InitPhoenixPL2(player_t * player, pspdef_t * psp)
1671 {
1672 player->flamecount = FLAME_THROWER_TICS;
1673 }
1674
1675 //----------------------------------------------------------------------------
1676 //
1677 // PROC A_FirePhoenixPL2
1678 //
1679 // Flame thrower effect.
1680 //
1681 //----------------------------------------------------------------------------
1682
A_FirePhoenixPL2(player_t * player,pspdef_t * psp)1683 void A_FirePhoenixPL2(player_t * player, pspdef_t * psp)
1684 {
1685 mobj_t *mo;
1686 mobj_t *pmo;
1687 angle_t angle;
1688 fixed_t x, y, z;
1689 fixed_t slope;
1690
1691 if (--player->flamecount == 0)
1692 { // Out of flame
1693 P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4);
1694 player->refire = 0;
1695 return;
1696 }
1697 pmo = player->mo;
1698 angle = pmo->angle;
1699 x = pmo->x + (P_SubRandom() << 9);
1700 y = pmo->y + (P_SubRandom() << 9);
1701 z = pmo->z + 26 * FRACUNIT + ((player->lookdir) << FRACBITS) / 173;
1702 if (pmo->flags2 & MF2_FEETARECLIPPED)
1703 {
1704 z -= FOOTCLIPSIZE;
1705 }
1706 slope = ((player->lookdir) << FRACBITS) / 173 + (FRACUNIT / 10);
1707 mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2);
1708 mo->target = pmo;
1709 mo->angle = angle;
1710 mo->momx = pmo->momx + FixedMul(mo->info->speed,
1711 finecosine[angle >> ANGLETOFINESHIFT]);
1712 mo->momy = pmo->momy + FixedMul(mo->info->speed,
1713 finesine[angle >> ANGLETOFINESHIFT]);
1714 mo->momz = FixedMul(mo->info->speed, slope);
1715 if (!player->refire || !(leveltime % 38))
1716 {
1717 S_StartSound(player->mo, sfx_phopow);
1718 }
1719 P_CheckMissileSpawn(mo);
1720 }
1721
1722 //----------------------------------------------------------------------------
1723 //
1724 // PROC A_ShutdownPhoenixPL2
1725 //
1726 //----------------------------------------------------------------------------
1727
A_ShutdownPhoenixPL2(player_t * player,pspdef_t * psp)1728 void A_ShutdownPhoenixPL2(player_t * player, pspdef_t * psp)
1729 {
1730 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
1731 }
1732
1733 //----------------------------------------------------------------------------
1734 //
1735 // PROC A_FlameEnd
1736 //
1737 //----------------------------------------------------------------------------
1738
A_FlameEnd(mobj_t * actor)1739 void A_FlameEnd(mobj_t * actor)
1740 {
1741 actor->momz += (fixed_t)(1.5 * FRACUNIT);
1742 }
1743
1744 //----------------------------------------------------------------------------
1745 //
1746 // PROC A_FloatPuff
1747 //
1748 //----------------------------------------------------------------------------
1749
A_FloatPuff(mobj_t * puff)1750 void A_FloatPuff(mobj_t * puff)
1751 {
1752 puff->momz += (fixed_t)(1.8 * FRACUNIT);
1753 }
1754
1755 //---------------------------------------------------------------------------
1756 //
1757 // PROC A_GauntletAttack
1758 //
1759 //---------------------------------------------------------------------------
1760
A_GauntletAttack(player_t * player,pspdef_t * psp)1761 void A_GauntletAttack(player_t * player, pspdef_t * psp)
1762 {
1763 angle_t angle;
1764 int damage;
1765 int slope;
1766 int randVal;
1767 fixed_t dist;
1768
1769 psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
1770 psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
1771 angle = player->mo->angle;
1772 if (player->powers[pw_weaponlevel2])
1773 {
1774 damage = HITDICE(2);
1775 dist = 4 * MELEERANGE;
1776 angle += P_SubRandom() << 17;
1777 PuffType = MT_GAUNTLETPUFF2;
1778 }
1779 else
1780 {
1781 damage = HITDICE(2);
1782 dist = MELEERANGE + 1;
1783 angle += P_SubRandom() << 18;
1784 PuffType = MT_GAUNTLETPUFF1;
1785 }
1786 slope = P_AimLineAttack(player->mo, angle, dist);
1787 P_LineAttack(player->mo, angle, dist, slope, damage);
1788 if (!linetarget)
1789 {
1790 if (P_Random() > 64)
1791 {
1792 player->extralight = !player->extralight;
1793 }
1794 S_StartSound(player->mo, sfx_gntful);
1795 return;
1796 }
1797 randVal = P_Random();
1798 if (randVal < 64)
1799 {
1800 player->extralight = 0;
1801 }
1802 else if (randVal < 160)
1803 {
1804 player->extralight = 1;
1805 }
1806 else
1807 {
1808 player->extralight = 2;
1809 }
1810 if (player->powers[pw_weaponlevel2])
1811 {
1812 P_GiveBody(player, damage >> 1);
1813 S_StartSound(player->mo, sfx_gntpow);
1814 }
1815 else
1816 {
1817 S_StartSound(player->mo, sfx_gnthit);
1818 }
1819 // turn to face target
1820 angle = R_PointToAngle2(player->mo->x, player->mo->y,
1821 linetarget->x, linetarget->y);
1822 if (angle - player->mo->angle > ANG180)
1823 {
1824 if (angle - player->mo->angle < -ANG90 / 20)
1825 player->mo->angle = angle + ANG90 / 21;
1826 else
1827 player->mo->angle -= ANG90 / 20;
1828 }
1829 else
1830 {
1831 if (angle - player->mo->angle > ANG90 / 20)
1832 player->mo->angle = angle - ANG90 / 21;
1833 else
1834 player->mo->angle += ANG90 / 20;
1835 }
1836 player->mo->flags |= MF_JUSTATTACKED;
1837 }
1838
A_Light0(player_t * player,pspdef_t * psp)1839 void A_Light0(player_t * player, pspdef_t * psp)
1840 {
1841 player->extralight = 0;
1842 }
1843
A_Light1(player_t * player,pspdef_t * psp)1844 void A_Light1(player_t * player, pspdef_t * psp)
1845 {
1846 player->extralight = 1;
1847 }
1848
A_Light2(player_t * player,pspdef_t * psp)1849 void A_Light2(player_t * player, pspdef_t * psp)
1850 {
1851 player->extralight = 2;
1852 }
1853
1854 //------------------------------------------------------------------------
1855 //
1856 // PROC P_SetupPsprites
1857 //
1858 // Called at start of level for each player
1859 //
1860 //------------------------------------------------------------------------
1861
P_SetupPsprites(player_t * player)1862 void P_SetupPsprites(player_t * player)
1863 {
1864 int i;
1865
1866 // Remove all psprites
1867 for (i = 0; i < NUMPSPRITES; i++)
1868 {
1869 player->psprites[i].state = NULL;
1870 }
1871 // Spawn the ready weapon
1872 player->pendingweapon = player->readyweapon;
1873 P_BringUpWeapon(player);
1874 }
1875
1876 //------------------------------------------------------------------------
1877 //
1878 // PROC P_MovePsprites
1879 //
1880 // Called every tic by player thinking routine
1881 //
1882 //------------------------------------------------------------------------
1883
P_MovePsprites(player_t * player)1884 void P_MovePsprites(player_t * player)
1885 {
1886 int i;
1887 pspdef_t *psp;
1888
1889 psp = &player->psprites[0];
1890 for (i = 0; i < NUMPSPRITES; i++, psp++)
1891 {
1892 if (psp->state != 0) // a null state means not active
1893 {
1894 // drop tic count and possibly change state
1895 if (psp->tics != -1) // a -1 tic count never changes
1896 {
1897 psp->tics--;
1898 if (!psp->tics)
1899 {
1900 P_SetPsprite(player, i, psp->state->nextstate);
1901 }
1902 }
1903 }
1904 }
1905 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
1906 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
1907 }
1908