2 //**************************************************************************
4 //** p_pspr.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
19 // MACROS ------------------------------------------------------------------
21 #define LOWERSPEED FRACUNIT*6
22 #define RAISESPEED FRACUNIT*6
23 #define WEAPONBOTTOM 128*FRACUNIT
24 #define WEAPONTOP 32*FRACUNIT
26 // TYPES -------------------------------------------------------------------
28 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
30 extern void P_ExplodeMissile(mobj_t *mo);
31 extern void A_UnHideThing(mobj_t *actor);
33 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
35 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
37 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
39 extern fixed_t FloatBobOffsets[64];
41 // PUBLIC DATA DEFINITIONS -------------------------------------------------
45 weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] =
48 { // Fighter First Weapon - Punch
51 S_PUNCHDOWN, // downstate
52 S_PUNCHREADY, // readystate
53 S_PUNCHATK1_1, // atkstate
54 S_PUNCHATK1_1, // holdatkstate
57 { // Cleric First Weapon - Mace
60 S_CMACEDOWN, // downstate
61 S_CMACEREADY, // readystate
62 S_CMACEATK_1, // atkstate
63 S_CMACEATK_1, // holdatkstate
66 { // Mage First Weapon - Wand
87 S_SNOUTDOWN, // downstate
88 S_SNOUTREADY, // readystate
89 S_SNOUTATK1, // atkstate
90 S_SNOUTATK1, // holdatkstate
98 S_FAXEDOWN, // downstate
99 S_FAXEREADY, // readystate
100 S_FAXEATK_1, // atkstate
101 S_FAXEATK_1, // holdatkstate
104 { // Cleric - Serpent Staff
106 S_CSTAFFUP, // upstate
107 S_CSTAFFDOWN, // downstate
108 S_CSTAFFREADY, // readystate
109 S_CSTAFFATK_1, // atkstate
110 S_CSTAFFATK_1, // holdatkstate
113 { // Mage - Cone of shards
116 S_CONEDOWN, // downstate
117 S_CONEREADY, // readystate
118 S_CONEATK1_1, // atkstate
119 S_CONEATK1_3, // holdatkstate
122 { // Assassin - Hand Crossbow
133 S_SNOUTUP, // upstate
134 S_SNOUTDOWN, // downstate
135 S_SNOUTREADY, // readystate
136 S_SNOUTATK1, // atkstate
137 S_SNOUTATK1, // holdatkstate
142 { // Fighter - Hammer
144 S_FHAMMERUP, // upstate
145 S_FHAMMERDOWN, // downstate
146 S_FHAMMERREADY, // readystate
147 S_FHAMMERATK_1, // atkstate
148 S_FHAMMERATK_1, // holdatkstate
151 { // Cleric - Flame Strike
153 S_CFLAMEUP, // upstate
154 S_CFLAMEDOWN, // downstate
155 S_CFLAMEREADY1, // readystate
156 S_CFLAMEATK_1, // atkstate
157 S_CFLAMEATK_1, // holdatkstate
160 { // Mage - Lightning
162 S_MLIGHTNINGUP, // upstate
163 S_MLIGHTNINGDOWN, // downstate
164 S_MLIGHTNINGREADY, // readystate
165 S_MLIGHTNINGATK_1, // atkstate
166 S_MLIGHTNINGATK_1, // holdatkstate
169 { // Assassin - Grenades
180 S_SNOUTUP, // upstate
181 S_SNOUTDOWN, // downstate
182 S_SNOUTREADY, // readystate
183 S_SNOUTATK1, // atkstate
184 S_SNOUTATK1, // holdatkstate
189 { // Fighter - Rune Sword
191 S_FSWORDUP, // upstate
192 S_FSWORDDOWN, // downstate
193 S_FSWORDREADY, // readystate
194 S_FSWORDATK_1, // atkstate
195 S_FSWORDATK_1, // holdatkstate
198 { // Cleric - Holy Symbol
200 S_CHOLYUP, // upstate
201 S_CHOLYDOWN, // downstate
202 S_CHOLYREADY, // readystate
203 S_CHOLYATK_1, // atkstate
204 S_CHOLYATK_1, // holdatkstate
209 S_MSTAFFUP, // upstate
210 S_MSTAFFDOWN, // downstate
211 S_MSTAFFREADY, // readystate
212 S_MSTAFFATK_1, // atkstate
213 S_MSTAFFATK_1, // holdatkstate
216 { // Assassin - Staff of Set
227 S_SNOUTUP, // upstate
228 S_SNOUTDOWN, // downstate
229 S_SNOUTREADY, // readystate
230 S_SNOUTATK1, // atkstate
231 S_SNOUTATK1, // holdatkstate
237 // PRIVATE DATA DEFINITIONS ------------------------------------------------
239 static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] =
244 { 0, 3, 3, 1 }, // True to Hexen II
248 // CODE --------------------------------------------------------------------
250 //---------------------------------------------------------------------------
254 //---------------------------------------------------------------------------
256 void P_SetPsprite(player_t *player, int position, statenum_t stnum)
261 psp = &player->psprites[position];
265 { // Object removed itself.
269 state = &states[stnum];
271 psp->tics = state->tics; // could be 0
273 { // Set coordinates.
274 psp->sx = state->misc1<<FRACBITS;
278 psp->sy = state->misc2<<FRACBITS;
281 { // Call action routine.
282 state->action(player, psp);
288 stnum = psp->state->nextstate;
289 } while(!psp->tics); // An initial state of 0 could cycle through.
292 //---------------------------------------------------------------------------
294 // PROC P_SetPspriteNF
296 // Identical to P_SetPsprite, without calling the action function
297 //---------------------------------------------------------------------------
299 void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
304 psp = &player->psprites[position];
308 { // Object removed itself.
312 state = &states[stnum];
314 psp->tics = state->tics; // could be 0
316 { // Set coordinates.
317 psp->sx = state->misc1<<FRACBITS;
321 psp->sy = state->misc2<<FRACBITS;
323 stnum = psp->state->nextstate;
324 } while(!psp->tics); // An initial state of 0 could cycle through.
336 fixed_t swingx, swingy;
337 void P_CalcSwing (player_t *player)
342 // OPTIMIZE: tablify this
346 angle = (FINEANGLES/70*leveltime)&FINEMASK;
347 swingx = FixedMul ( swing, finesine[angle]);
349 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
350 swingy = -FixedMul ( swingx, finesine[angle]);
354 //---------------------------------------------------------------------------
356 // PROC P_ActivateMorphWeapon
358 //---------------------------------------------------------------------------
360 void P_ActivateMorphWeapon(player_t *player)
362 player->pendingweapon = WP_NOCHANGE;
363 player->psprites[ps_weapon].sy = WEAPONTOP;
364 player->readyweapon = WP_FIRST; // Snout is the first weapon
365 P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
369 //---------------------------------------------------------------------------
371 // PROC P_PostMorphWeapon
373 //---------------------------------------------------------------------------
375 void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
377 player->pendingweapon = WP_NOCHANGE;
378 player->readyweapon = weapon;
379 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
380 P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->class].upstate);
383 //---------------------------------------------------------------------------
385 // PROC P_BringUpWeapon
387 // Starts bringing the pending weapon up from the bottom of the screen.
389 //---------------------------------------------------------------------------
391 void P_BringUpWeapon(player_t *player)
395 if(player->pendingweapon == WP_NOCHANGE)
397 player->pendingweapon = player->readyweapon;
399 if(player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
400 && player->mana[MANA_1])
406 new = WeaponInfo[player->pendingweapon][player->class].upstate;
408 player->pendingweapon = WP_NOCHANGE;
409 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
410 P_SetPsprite(player, ps_weapon, new);
413 //---------------------------------------------------------------------------
417 // Returns true if there is enough mana to shoot. If not, selects the
418 // next weapon to use.
420 //---------------------------------------------------------------------------
422 boolean P_CheckMana(player_t *player)
427 mana = WeaponInfo[player->readyweapon][player->class].mana;
428 count = WeaponManaUse[player->class][player->readyweapon];
429 if(mana == MANA_BOTH)
431 if(player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
436 else if(mana == MANA_NONE || player->mana[mana] >= count)
440 // out of mana, pick a weapon to change to
443 if(player->weaponowned[WP_THIRD]
444 && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD])
446 player->pendingweapon = WP_THIRD;
448 else if(player->weaponowned[WP_SECOND]
449 && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_SECOND])
451 player->pendingweapon = WP_SECOND;
453 else if(player->weaponowned[WP_FOURTH]
454 && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_FOURTH]
455 && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_FOURTH])
457 player->pendingweapon = WP_FOURTH;
461 player->pendingweapon = WP_FIRST;
463 } while(player->pendingweapon == WP_NOCHANGE);
464 P_SetPsprite(player, ps_weapon,
465 WeaponInfo[player->readyweapon][player->class].downstate);
469 //---------------------------------------------------------------------------
473 //---------------------------------------------------------------------------
475 void P_FireWeapon(player_t *player)
477 statenum_t attackState;
479 if(!P_CheckMana(player))
483 P_SetMobjState(player->mo, PStateAttack[player->class]); // S_PLAY_ATK1);
484 if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
485 && player->mana[MANA_1] > 0)
487 attackState = S_FAXEATK_G1;
491 attackState = player->refire ?
492 WeaponInfo[player->readyweapon][player->class].holdatkstate
493 : WeaponInfo[player->readyweapon][player->class].atkstate;
495 P_SetPsprite(player, ps_weapon, attackState);
496 P_NoiseAlert(player->mo, player->mo);
499 //---------------------------------------------------------------------------
503 // The player died, so put the weapon away.
505 //---------------------------------------------------------------------------
507 void P_DropWeapon(player_t *player)
509 P_SetPsprite(player, ps_weapon,
510 WeaponInfo[player->readyweapon][player->class].downstate);
513 //---------------------------------------------------------------------------
515 // PROC A_WeaponReady
517 // The player can fire the weapon or change to another weapon at this time.
519 //---------------------------------------------------------------------------
521 void A_WeaponReady(player_t *player, pspdef_t *psp)
525 // Change player from attack state
526 if(player->mo->state >= &states[PStateAttack[player->class]]
527 && player->mo->state <= &states[PStateAttackEnd[player->class]])
529 P_SetMobjState(player->mo, PStateNormal[player->class]);
531 // Put the weapon away if the player has a pending weapon or has
533 if(player->pendingweapon != WP_NOCHANGE || !player->health)
535 P_SetPsprite(player, ps_weapon,
536 WeaponInfo[player->readyweapon][player->class].downstate);
541 if(player->cmd.buttons&BT_ATTACK)
543 player->attackdown = true;
544 P_FireWeapon(player);
549 player->attackdown = false;
552 if(!player->morphTics)
554 // Bob the weapon based on movement speed.
555 angle = (128*leveltime)&FINEMASK;
556 psp->sx = FRACUNIT+FixedMul(player->bob, finecosine[angle]);
557 angle &= FINEANGLES/2-1;
558 psp->sy = WEAPONTOP+FixedMul(player->bob, finesine[angle]);
562 //---------------------------------------------------------------------------
566 // The player can re fire the weapon without lowering it entirely.
568 //---------------------------------------------------------------------------
570 void A_ReFire(player_t *player, pspdef_t *psp)
572 if((player->cmd.buttons&BT_ATTACK)
573 && player->pendingweapon == WP_NOCHANGE && player->health)
576 P_FireWeapon(player);
585 //---------------------------------------------------------------------------
589 //---------------------------------------------------------------------------
591 void A_Lower(player_t *player, pspdef_t *psp)
593 if(player->morphTics)
595 psp->sy = WEAPONBOTTOM;
599 psp->sy += LOWERSPEED;
601 if(psp->sy < WEAPONBOTTOM)
602 { // Not lowered all the way yet
605 if(player->playerstate == PST_DEAD)
606 { // Player is dead, so don't bring up a pending weapon
607 psp->sy = WEAPONBOTTOM;
611 { // Player is dead, so keep the weapon off screen
612 P_SetPsprite(player, ps_weapon, S_NULL);
615 player->readyweapon = player->pendingweapon;
616 P_BringUpWeapon(player);
619 //---------------------------------------------------------------------------
623 //---------------------------------------------------------------------------
625 void A_Raise(player_t *player, pspdef_t *psp)
627 psp->sy -= RAISESPEED;
628 if(psp->sy > WEAPONTOP)
629 { // Not raised all the way yet
633 if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
634 && player->mana[MANA_1])
636 P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
640 P_SetPsprite(player, ps_weapon,
641 WeaponInfo[player->readyweapon][player->class].readystate);
650 = Sets a slope so a near miss is at aproximately the height of the
657 void P_BulletSlope (mobj_t *mo)
662 // see which target is to be aimed at
665 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
669 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
673 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
678 bulletslope = (mo->player->lookdir<<FRACBITS)/173;
684 //****************************************************************************
688 //****************************************************************************
690 //============================================================================
694 //============================================================================
696 #define MAX_ANGLE_ADJUST (5*ANGLE_1)
698 void AdjustPlayerAngle(mobj_t *pmo)
703 angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
704 difference = (int)angle-(int)pmo->angle;
705 if(abs(difference) > MAX_ANGLE_ADJUST)
707 pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
715 //============================================================================
719 //============================================================================
721 void A_SnoutAttack(player_t *player, pspdef_t *psp)
727 damage = 3+(P_Random()&3);
728 angle = player->mo->angle;
729 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
730 PuffType = MT_SNOUTPUFF;
732 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
733 S_StartSound(player->mo, SFX_PIG_ACTIVE1+(P_Random()&1));
736 AdjustPlayerAngle(player->mo);
737 // player->mo->angle = R_PointToAngle2(player->mo->x,
738 // player->mo->y, linetarget->x, linetarget->y);
741 S_StartSound(player->mo, SFX_PIG_ATTACK);
746 //============================================================================
750 //============================================================================
752 #define HAMMER_RANGE (MELEERANGE+MELEERANGE/2)
754 void A_FHammerAttack(player_t *player, pspdef_t *psp)
757 mobj_t *pmo=player->mo;
763 damage = 60+(P_Random()&63);
765 PuffType = MT_HAMMERPUFF;
766 for(i = 0; i < 16; i++)
768 angle = pmo->angle+i*(ANG45/32);
769 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
772 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
773 AdjustPlayerAngle(pmo);
774 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
776 P_ThrustMobj(linetarget, angle, power);
778 pmo->special1 = false; // Don't throw a hammer
781 angle = pmo->angle-i*(ANG45/32);
782 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
785 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
786 AdjustPlayerAngle(pmo);
787 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
789 P_ThrustMobj(linetarget, angle, power);
791 pmo->special1 = false; // Don't throw a hammer
795 // didn't find any targets in meleerange, so set to throw out a hammer
798 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
799 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
802 pmo->special1 = false;
806 pmo->special1 = true;
809 if(player->mana[MANA_2] <
810 WeaponManaUse[player->class][player->readyweapon])
811 { // Don't spawn a hammer if the player doesn't have enough mana
812 pmo->special1 = false;
817 //============================================================================
821 //============================================================================
823 void A_FHammerThrow(player_t *player, pspdef_t *psp)
827 if(!player->mo->special1)
831 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
832 mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE);
839 //============================================================================
843 //============================================================================
845 void A_FSwordAttack(player_t *player, pspdef_t *psp)
849 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
850 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
852 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-10*FRACUNIT, MT_FSWORD_MISSILE,
854 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-5*FRACUNIT, MT_FSWORD_MISSILE,
856 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
857 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+5*FRACUNIT, MT_FSWORD_MISSILE,
859 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+10*FRACUNIT, MT_FSWORD_MISSILE,
861 S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
864 //============================================================================
868 //============================================================================
870 void A_FSwordAttack2(mobj_t *actor)
872 angle_t angle = actor->angle;
874 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/4, 0);
875 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/8, 0);
876 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle, 0);
877 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/8, 0);
878 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/4, 0);
879 S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
882 //============================================================================
886 //============================================================================
888 void A_FSwordFlames(mobj_t *actor)
892 for(i = 1+(P_Random()&3); i; i--)
894 P_SpawnMobj(actor->x+((P_Random()-128)<<12), actor->y
895 +((P_Random()-128)<<12), actor->z+((P_Random()-128)<<11),
900 //============================================================================
904 //============================================================================
906 void A_MWandAttack(player_t *player, pspdef_t *psp)
910 mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
913 mo->thinker.function = P_BlasterMobjThinker;
915 S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
918 // ===== Mage Lightning Weapon =====
920 //============================================================================
924 //============================================================================
926 void A_LightningReady(player_t *player, pspdef_t *psp)
928 A_WeaponReady(player, psp);
931 S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
935 //============================================================================
939 //============================================================================
941 #define ZAGSPEED FRACUNIT
943 void A_LightningClip(mobj_t *actor)
946 mobj_t *target = NULL; /* jim added initialiser */
949 if(actor->type == MT_LIGHTNING_FLOOR)
951 actor->z = actor->floorz;
952 target = (mobj_t *)((mobj_t *)actor->special2)->special1;
954 else if(actor->type == MT_LIGHTNING_CEILING)
956 actor->z = actor->ceilingz-actor->height;
957 target = (mobj_t *)actor->special1;
959 if(actor->type == MT_LIGHTNING_FLOOR)
960 { // floor lightning zig-zags, and forces the ceiling lightning to mimic
961 cMo = (mobj_t *)actor->special2;
963 if((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
965 P_ThrustMobj(actor, actor->angle+ANG90, ZAGSPEED);
968 P_ThrustMobj(cMo, actor->angle+ANG90, ZAGSPEED);
974 P_ThrustMobj(actor, actor->angle-ANG90, ZAGSPEED);
977 P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
984 if(target->health <= 0)
986 P_ExplodeMissile(actor);
990 actor->angle = R_PointToAngle2(actor->x, actor->y, target->x,
994 P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
999 //============================================================================
1003 //============================================================================
1005 void A_LightningZap(mobj_t *actor)
1010 A_LightningClip(actor);
1013 if(actor->health <= 0)
1015 P_SetMobjState(actor, actor->info->deathstate);
1018 if(actor->type == MT_LIGHTNING_FLOOR)
1020 deltaZ = 10*FRACUNIT;
1024 deltaZ = -10*FRACUNIT;
1026 mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256),
1027 actor->y+((P_Random()-128)*actor->radius/256),
1028 actor->z+deltaZ, MT_LIGHTNING_ZAP);
1031 mo->special2 = (int)actor;
1032 mo->momx = actor->momx;
1033 mo->momy = actor->momy;
1034 mo->target = actor->target;
1035 if(actor->type == MT_LIGHTNING_FLOOR)
1037 mo->momz = 20*FRACUNIT;
1041 mo->momz = -20*FRACUNIT;
1045 mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256),
1046 actor->y+((P_Random()-128)*actor->radius/256),
1047 actor->z+deltaZ, MT_LIGHTNING_ZAP);
1050 mo->special2 = (int)actor;
1051 mo->momx = actor->momx;
1052 mo->momy = actor->momy;
1053 mo->target = actor->target;
1054 if(actor->type == MT_LIGHTNING_FLOOR)
1056 mo->momz = 16*FRACUNIT;
1060 mo->momz = -16*FRACUNIT;
1064 if(actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
1066 S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
1070 //============================================================================
1072 // A_MLightningAttack2
1074 //============================================================================
1076 void A_MLightningAttack2(mobj_t *actor)
1080 fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
1081 cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
1085 fmo->special2 = (int)cmo;
1086 A_LightningZap(fmo);
1090 cmo->special1 = 0; // mobj that it will track
1091 cmo->special2 = (int)fmo;
1092 A_LightningZap(cmo);
1094 S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
1097 //============================================================================
1099 // A_MLightningAttack
1101 //============================================================================
1103 void A_MLightningAttack(player_t *player, pspdef_t *psp)
1105 A_MLightningAttack2(player->mo);
1106 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1109 //============================================================================
1113 //============================================================================
1115 void A_ZapMimic(mobj_t *actor)
1119 mo = (mobj_t *)actor->special2;
1122 if(mo->state >= &states[mo->info->deathstate]
1123 || mo->state == &states[S_FREETARGMOBJ])
1125 P_ExplodeMissile(actor);
1129 actor->momx = mo->momx;
1130 actor->momy = mo->momy;
1135 //============================================================================
1139 //============================================================================
1141 void A_LastZap(mobj_t *actor)
1145 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
1148 P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
1149 mo->momz = 40*FRACUNIT;
1153 //============================================================================
1155 // A_LightningRemove
1157 //============================================================================
1159 void A_LightningRemove(mobj_t *actor)
1163 mo = (mobj_t *)actor->special2;
1167 P_ExplodeMissile(mo);
1172 //============================================================================
1176 //============================================================================
1177 void MStaffSpawn(mobj_t *pmo, angle_t angle)
1181 mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
1185 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1189 //============================================================================
1193 //============================================================================
1195 void A_MStaffAttack(player_t *player, pspdef_t *psp)
1200 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1201 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1205 MStaffSpawn(pmo, angle);
1206 MStaffSpawn(pmo, angle-ANGLE_1*5);
1207 MStaffSpawn(pmo, angle+ANGLE_1*5);
1208 S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
1209 if(player == &players[consoleplayer])
1211 player->damagecount = 0;
1212 player->bonuscount = 0;
1213 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1214 PU_CACHE)+STARTSCOURGEPAL*768);
1218 //============================================================================
1222 //============================================================================
1224 void A_MStaffPalette(player_t *player, pspdef_t *psp)
1228 if(player == &players[consoleplayer])
1230 pal = STARTSCOURGEPAL+psp->state-(&states[S_MSTAFFATK_2]);
1231 if(pal == STARTSCOURGEPAL+3)
1232 { // reset back to original playpal
1235 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1240 //============================================================================
1244 //============================================================================
1246 void A_MStaffWeave(mobj_t *actor)
1249 int weaveXY, weaveZ;
1252 weaveXY = actor->special2>>16;
1253 weaveZ = actor->special2&0xFFFF;
1254 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1255 newX = actor->x-FixedMul(finecosine[angle],
1256 FloatBobOffsets[weaveXY]<<2);
1257 newY = actor->y-FixedMul(finesine[angle],
1258 FloatBobOffsets[weaveXY]<<2);
1259 weaveXY = (weaveXY+6)&63;
1260 newX += FixedMul(finecosine[angle],
1261 FloatBobOffsets[weaveXY]<<2);
1262 newY += FixedMul(finesine[angle],
1263 FloatBobOffsets[weaveXY]<<2);
1264 P_TryMove(actor, newX, newY);
1265 actor->z -= FloatBobOffsets[weaveZ]<<1;
1266 weaveZ = (weaveZ+3)&63;
1267 actor->z += FloatBobOffsets[weaveZ]<<1;
1268 if(actor->z <= actor->floorz)
1270 actor->z = actor->floorz+FRACUNIT;
1272 actor->special2 = weaveZ+(weaveXY<<16);
1276 //============================================================================
1280 //============================================================================
1282 void A_MStaffTrack(mobj_t *actor)
1284 if ((actor->special1 == 0) && (P_Random()<50))
1286 actor->special1 = (int)P_RoughMonsterSearch(actor, 10);
1288 P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
1292 //============================================================================
1294 // MStaffSpawn2 - for use by mage class boss
1296 //============================================================================
1298 void MStaffSpawn2(mobj_t *actor, angle_t angle)
1302 mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
1306 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1310 //============================================================================
1312 // A_MStaffAttack2 - for use by mage class boss
1314 //============================================================================
1316 void A_MStaffAttack2(mobj_t *actor)
1319 angle = actor->angle;
1320 MStaffSpawn2(actor, angle);
1321 MStaffSpawn2(actor, angle-ANGLE_1*5);
1322 MStaffSpawn2(actor, angle+ANGLE_1*5);
1323 S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
1326 //============================================================================
1330 //============================================================================
1332 void A_FPunchAttack(player_t *player, pspdef_t *psp)
1337 mobj_t *pmo = player->mo;
1341 damage = 40+(P_Random()&15);
1343 PuffType = MT_PUNCHPUFF;
1344 for(i = 0; i < 16; i++)
1346 angle = pmo->angle+i*(ANG45/16);
1347 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1350 player->mo->special1++;
1351 if(pmo->special1 == 3)
1355 PuffType = MT_HAMMERPUFF;
1357 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1358 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1360 P_ThrustMobj(linetarget, angle, power);
1362 AdjustPlayerAngle(pmo);
1365 angle = pmo->angle-i*(ANG45/16);
1366 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1370 if(pmo->special1 == 3)
1374 PuffType = MT_HAMMERPUFF;
1376 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1377 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1379 P_ThrustMobj(linetarget, angle, power);
1381 AdjustPlayerAngle(pmo);
1385 // didn't find any creatures, so try to strike any walls
1389 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1390 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1393 if(pmo->special1 == 3)
1396 P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
1397 S_StartSound(pmo, SFX_FIGHTER_GRUNT);
1402 //============================================================================
1406 //============================================================================
1408 #define AXERANGE 2.25*MELEERANGE
1410 void A_FAxeAttack(player_t *player, pspdef_t *psp)
1413 mobj_t *pmo=player->mo;
1420 damage = 40+(P_Random()&15)+(P_Random()&7);
1422 if(player->mana[MANA_1] > 0)
1426 PuffType = MT_AXEPUFF_GLOW;
1431 PuffType = MT_AXEPUFF;
1434 for(i = 0; i < 16; i++)
1436 angle = pmo->angle+i*(ANG45/16);
1437 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1440 P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1441 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1443 P_ThrustMobj(linetarget, angle, power);
1445 AdjustPlayerAngle(pmo);
1449 angle = pmo->angle-i*(ANG45/16);
1450 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1453 P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1454 if (linetarget->flags&MF_COUNTKILL)
1456 P_ThrustMobj(linetarget, angle, power);
1458 AdjustPlayerAngle(pmo);
1463 // didn't find any creatures, so try to strike any walls
1467 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1468 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1473 player->mana[MANA_1] -=
1474 WeaponManaUse[player->class][player->readyweapon];
1475 if(player->mana[MANA_1] <= 0)
1477 P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
1483 //===========================================================================
1487 //===========================================================================
1489 void A_CMaceAttack(player_t *player, pspdef_t *psp)
1496 damage = 25+(P_Random()&15);
1497 PuffType = MT_HAMMERPUFF;
1498 for(i = 0; i < 16; i++)
1500 angle = player->mo->angle+i*(ANG45/16);
1501 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1504 P_LineAttack(player->mo, angle, 2*MELEERANGE, slope,
1506 AdjustPlayerAngle(player->mo);
1507 // player->mo->angle = R_PointToAngle2(player->mo->x,
1508 // player->mo->y, linetarget->x, linetarget->y);
1511 angle = player->mo->angle-i*(ANG45/16);
1512 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1515 P_LineAttack(player->mo, angle, 2*MELEERANGE, slope,
1517 AdjustPlayerAngle(player->mo);
1518 // player->mo->angle = R_PointToAngle2(player->mo->x,
1519 // player->mo->y, linetarget->x, linetarget->y);
1523 // didn't find any creatures, so try to strike any walls
1524 player->mo->special1 = 0;
1526 angle = player->mo->angle;
1527 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
1528 P_LineAttack(player->mo, angle, MELEERANGE, slope,
1534 //============================================================================
1538 //============================================================================
1540 void A_CStaffCheck(player_t *player, pspdef_t *psp)
1550 damage = 20+(P_Random()&15);
1551 PuffType = MT_CSTAFFPUFF;
1552 for(i = 0; i < 3; i++)
1554 angle = pmo->angle+i*(ANG45/16);
1555 slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
1558 P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
1559 pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
1560 linetarget->x, linetarget->y);
1561 if((linetarget->player || linetarget->flags&MF_COUNTKILL)
1562 && (!(linetarget->flags2&(MF2_DORMANT+MF2_INVULNERABLE))))
1564 newLife = player->health+(damage>>3);
1565 newLife = newLife > 100 ? 100 : newLife;
1566 pmo->health = player->health = newLife;
1567 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
1569 player->mana[MANA_1] -=
1570 WeaponManaUse[player->class][player->readyweapon];
1573 angle = pmo->angle-i*(ANG45/16);
1574 slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
1577 P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
1578 pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
1579 linetarget->x, linetarget->y);
1580 if(linetarget->player || linetarget->flags&MF_COUNTKILL)
1582 newLife = player->health+(damage>>4);
1583 newLife = newLife > 100 ? 100 : newLife;
1584 pmo->health = player->health = newLife;
1585 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
1587 player->mana[MANA_1] -=
1588 WeaponManaUse[player->class][player->readyweapon];
1594 //============================================================================
1598 //============================================================================
1600 void A_CStaffAttack(player_t *player, pspdef_t *psp)
1605 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1607 mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle-(ANG45/15));
1612 mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle+(ANG45/15));
1617 S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
1620 //============================================================================
1622 // A_CStaffMissileSlither
1624 //============================================================================
1626 void A_CStaffMissileSlither(mobj_t *actor)
1632 weaveXY = actor->special2;
1633 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1634 newX = actor->x-FixedMul(finecosine[angle],
1635 FloatBobOffsets[weaveXY]);
1636 newY = actor->y-FixedMul(finesine[angle],
1637 FloatBobOffsets[weaveXY]);
1638 weaveXY = (weaveXY+3)&63;
1639 newX += FixedMul(finecosine[angle],
1640 FloatBobOffsets[weaveXY]);
1641 newY += FixedMul(finesine[angle],
1642 FloatBobOffsets[weaveXY]);
1643 P_TryMove(actor, newX, newY);
1644 actor->special2 = weaveXY;
1647 //============================================================================
1649 // A_CStaffInitBlink
1651 //============================================================================
1653 void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
1655 player->mo->special1 = (P_Random()>>1)+20;
1658 //============================================================================
1660 // A_CStaffCheckBlink
1662 //============================================================================
1664 void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
1666 if(!--player->mo->special1)
1668 P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
1669 player->mo->special1 = (P_Random()+50)>>2;
1673 //============================================================================
1677 //============================================================================
1679 #define FLAMESPEED (0.45*FRACUNIT)
1680 #define CFLAMERANGE (12*64*FRACUNIT)
1682 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1686 mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
1689 mo->thinker.function = P_BlasterMobjThinker;
1693 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1694 S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1697 //============================================================================
1701 //============================================================================
1703 void A_CFlamePuff(mobj_t *actor)
1705 A_UnHideThing(actor);
1709 S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
1712 //============================================================================
1716 //============================================================================
1718 void A_CFlameMissile(mobj_t *actor)
1725 A_UnHideThing(actor);
1726 S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
1727 if(BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE)
1728 { // Hit something, so spawn the flame circle around the thing
1729 dist = BlockingMobj->radius+18*FRACUNIT;
1730 for(i = 0; i < 4; i++)
1732 an = (i*ANG45)>>ANGLETOFINESHIFT;
1733 an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
1734 mo = P_SpawnMobj(BlockingMobj->x+FixedMul(dist, finecosine[an]),
1735 BlockingMobj->y+FixedMul(dist, finesine[an]),
1736 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
1739 mo->angle = an<<ANGLETOFINESHIFT;
1740 mo->target = actor->target;
1741 mo->momx = mo->special1 = FixedMul(finecosine[an], FLAMESPEED);
1742 mo->momy = mo->special2 = FixedMul(finesine[an], FLAMESPEED);
1743 mo->tics -= P_Random()&3;
1745 mo = P_SpawnMobj(BlockingMobj->x-FixedMul(dist, finecosine[an]),
1746 BlockingMobj->y-FixedMul(dist, finesine[an]),
1747 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
1750 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
1751 mo->target = actor->target;
1752 mo->momx = mo->special1 = FixedMul(finecosine[an],-FLAMESPEED);
1753 mo->momy = mo->special2 = FixedMul(finesine[an],-FLAMESPEED);
1754 mo->tics -= P_Random()&3;
1757 P_SetMobjState(actor, S_FLAMEPUFF2_1);
1762 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1774 damage = 25+HITDICE(3);
1778 angle += (P_Random()-P_Random())<<17;
1780 P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
1784 P_AimLineAttack(pmo, angle, CFLAMERANGE);
1788 P_AimLineAttack(pmo, angle, CFLAMERANGE);
1797 PuffType = MT_FLAMEPUFF2;
1801 PuffType = MT_FLAMEPUFF;
1803 P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
1805 { // Hit something, so spawn the flame circle around the thing
1806 dist = linetarget->radius+18*FRACUNIT;
1807 for(i = 0; i < 4; i++)
1809 an = (i*ANG45)>>ANGLETOFINESHIFT;
1810 an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
1811 mo = P_SpawnMobj(linetarget->x+FixedMul(dist, finecosine[an]),
1812 linetarget->y+FixedMul(dist, finesine[an]),
1813 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
1816 mo->angle = an<<ANGLETOFINESHIFT;
1818 mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
1819 mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
1820 mo->tics -= P_Random()&3;
1822 mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]),
1823 linetarget->y-FixedMul(dist, finesine[an]),
1824 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
1827 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
1829 mo->momx = mo->special1 = FixedMul(-FLAMESPEED,
1831 mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
1832 mo->tics -= P_Random()&3;
1836 // Create a line of flames from the player to the flame puff
1837 CFlameCreateFlames(player->mo);
1839 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1840 S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1844 //============================================================================
1848 //============================================================================
1850 #define FLAMEROTSPEED 2*FRACUNIT
1852 void A_CFlameRotate(mobj_t *actor)
1856 an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1857 actor->momx = actor->special1+FixedMul(FLAMEROTSPEED, finecosine[an]);
1858 actor->momy = actor->special2+FixedMul(FLAMEROTSPEED, finesine[an]);
1859 actor->angle += ANG90/15;
1863 //============================================================================
1867 // Spawns the spirits
1868 //============================================================================
1870 void A_CHolyAttack3(mobj_t *actor)
1872 P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
1873 S_StartSound(actor, SFX_CHOLY_FIRE);
1877 //============================================================================
1881 // Spawns the spirits
1882 //============================================================================
1884 void A_CHolyAttack2(mobj_t *actor)
1889 mobj_t *tail, *next;
1891 for(j = 0; j < 4; j++)
1893 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
1899 { // float bob index
1901 mo->special2 = P_Random()&7; // upper-left
1904 mo->special2 = 32+(P_Random()&7); // upper-right
1907 mo->special2 = (32+(P_Random()&7))<<16; // lower-left
1910 mo->special2 = ((32+(P_Random()&7))<<16)+32+(P_Random()&7);
1914 mo->angle = actor->angle+(ANGLE_45+ANGLE_45/2)-ANGLE_45*j;
1915 P_ThrustMobj(mo, mo->angle, mo->info->speed);
1916 mo->target = actor->target;
1917 mo->args[0] = 10; // initial turn value
1918 mo->args[1] = 0; // initial look angle
1920 { // Ghosts last slightly less longer in DeathMatch
1925 mo->special1 = (int)linetarget;
1926 mo->flags |= MF_NOCLIP|MF_SKULLFLY;
1927 mo->flags &= ~MF_MISSILE;
1929 tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
1930 tail->special2 = (int)mo; // parent
1931 for(i = 1; i < 3; i++)
1933 next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
1934 P_SetMobjState(next, next->info->spawnstate+1);
1935 tail->special1 = (int)next;
1938 tail->special1 = 0; // last tail bit
1942 //============================================================================
1946 //============================================================================
1948 void A_CHolyAttack(player_t *player, pspdef_t *psp)
1952 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1953 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1954 mo = P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
1955 if(player == &players[consoleplayer])
1957 player->damagecount = 0;
1958 player->bonuscount = 0;
1959 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1960 PU_CACHE)+STARTHOLYPAL*768);
1962 S_StartSound(player->mo, SFX_CHOLY_FIRE);
1965 //============================================================================
1969 //============================================================================
1971 void A_CHolyPalette(player_t *player, pspdef_t *psp)
1975 if(player == &players[consoleplayer])
1977 pal = STARTHOLYPAL+psp->state-(&states[S_CHOLYATK_6]);
1978 if(pal == STARTHOLYPAL+3)
1979 { // reset back to original playpal
1982 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1987 //============================================================================
1991 //============================================================================
1993 static void CHolyFindTarget(mobj_t *actor)
1995 /* jim changed to avoid single = in if() */
1996 /* mobj_t *target; */
1998 /* if(target = P_RoughMonsterSearch(actor, 6)) */
2000 mobj_t *target = P_RoughMonsterSearch (actor, 6);
2004 actor->special1 = (int)target;
2005 actor->flags |= MF_NOCLIP|MF_SKULLFLY;
2006 actor->flags &= ~MF_MISSILE;
2010 //============================================================================
2012 // CHolySeekerMissile
2014 // Similar to P_SeekerMissile, but seeks to a random Z on the target
2015 //============================================================================
2017 static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
2027 target = (mobj_t *)actor->special1;
2032 if(!(target->flags&MF_SHOOTABLE)
2033 || (!(target->flags&MF_COUNTKILL) && !target->player))
2034 { // Target died/target isn't a player or creature
2035 actor->special1 = 0;
2036 actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
2037 actor->flags |= MF_MISSILE;
2038 CHolyFindTarget(actor);
2041 dir = P_FaceMobj(actor, target, &delta);
2052 actor->angle += delta;
2055 { // Turn counter clockwise
2056 actor->angle -= delta;
2058 angle = actor->angle>>ANGLETOFINESHIFT;
2059 actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
2060 actor->momy = FixedMul(actor->info->speed, finesine[angle]);
2062 || actor->z > target->z+(target->height)
2063 || actor->z+actor->height < target->z)
2065 newZ = target->z+((P_Random()*target->height)>>8);
2066 deltaZ = newZ-actor->z;
2067 if(abs(deltaZ) > 15*FRACUNIT)
2071 deltaZ = 15*FRACUNIT;
2075 deltaZ = -15*FRACUNIT;
2078 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
2079 dist = dist/actor->info->speed;
2084 actor->momz = deltaZ/dist;
2089 //============================================================================
2093 //============================================================================
2095 static void CHolyWeave(mobj_t *actor)
2098 int weaveXY, weaveZ;
2101 weaveXY = actor->special2>>16;
2102 weaveZ = actor->special2&0xFFFF;
2103 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
2104 newX = actor->x-FixedMul(finecosine[angle],
2105 FloatBobOffsets[weaveXY]<<2);
2106 newY = actor->y-FixedMul(finesine[angle],
2107 FloatBobOffsets[weaveXY]<<2);
2108 weaveXY = (weaveXY+(P_Random()%5))&63;
2109 newX += FixedMul(finecosine[angle],
2110 FloatBobOffsets[weaveXY]<<2);
2111 newY += FixedMul(finesine[angle],
2112 FloatBobOffsets[weaveXY]<<2);
2113 P_TryMove(actor, newX, newY);
2114 actor->z -= FloatBobOffsets[weaveZ]<<1;
2115 weaveZ = (weaveZ+(P_Random()%5))&63;
2116 actor->z += FloatBobOffsets[weaveZ]<<1;
2117 actor->special2 = weaveZ+(weaveXY<<16);
2120 //============================================================================
2124 //============================================================================
2126 void A_CHolySeek(mobj_t *actor)
2129 if(actor->health <= 0)
2134 P_SetMobjState(actor, actor->info->deathstate);
2135 actor->tics -= P_Random()&3;
2140 CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
2141 actor->args[0]*ANGLE_1*2);
2142 if(!((leveltime+7)&15))
2144 actor->args[0] = 5+(P_Random()/20);
2150 //============================================================================
2154 //============================================================================
2156 static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
2160 fixed_t oldDistance, newDistance;
2162 child = (mobj_t *)actor->special1;
2165 an = R_PointToAngle2(actor->x, actor->y, child->x,
2166 child->y)>>ANGLETOFINESHIFT;
2167 oldDistance = P_AproxDistance(child->x-actor->x, child->y-actor->y);
2168 if(P_TryMove(child, actor->x+FixedMul(dist, finecosine[an]),
2169 actor->y+FixedMul(dist, finesine[an])))
2171 newDistance = P_AproxDistance(child->x-actor->x,
2172 child->y-actor->y)-FRACUNIT;
2173 if(oldDistance < FRACUNIT)
2175 if(child->z < actor->z)
2177 child->z = actor->z-dist;
2181 child->z = actor->z+dist;
2186 child->z = actor->z+FixedMul(FixedDiv(newDistance,
2187 oldDistance), child->z-actor->z);
2190 CHolyTailFollow(child, dist-FRACUNIT);
2194 //============================================================================
2198 //============================================================================
2200 static void CHolyTailRemove(mobj_t *actor)
2204 child = (mobj_t *)actor->special1;
2207 CHolyTailRemove(child);
2209 P_RemoveMobj(actor);
2212 //============================================================================
2216 //============================================================================
2218 void A_CHolyTail(mobj_t *actor)
2222 parent = (mobj_t *)actor->special2;
2226 if(parent->state >= &states[parent->info->deathstate])
2227 { // Ghost removed, so remove all tail parts
2228 CHolyTailRemove(actor);
2231 else if(P_TryMove(actor, parent->x-FixedMul(14*FRACUNIT,
2232 finecosine[parent->angle>>ANGLETOFINESHIFT]),
2233 parent->y-FixedMul(14*FRACUNIT,
2234 finesine[parent->angle>>ANGLETOFINESHIFT])))
2236 actor->z = parent->z-5*FRACUNIT;
2238 CHolyTailFollow(actor, 10*FRACUNIT);
2241 //============================================================================
2243 // A_CHolyCheckScream
2245 //============================================================================
2247 void A_CHolyCheckScream(mobj_t *actor)
2252 S_StartSound(actor, SFX_SPIRIT_ACTIVE);
2254 if(!actor->special1)
2256 CHolyFindTarget(actor);
2260 //============================================================================
2264 //============================================================================
2266 void A_CHolySpawnPuff(mobj_t *actor)
2268 P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
2271 //----------------------------------------------------------------------------
2273 // PROC A_FireConePL1
2275 //----------------------------------------------------------------------------
2277 #define SHARDSPAWN_LEFT 1
2278 #define SHARDSPAWN_RIGHT 2
2279 #define SHARDSPAWN_UP 4
2280 #define SHARDSPAWN_DOWN 8
2282 void A_FireConePL1(player_t *player, pspdef_t *psp)
2292 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2293 S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
2295 damage = 90+(P_Random()&15);
2296 for(i = 0; i < 16; i++)
2298 angle = pmo->angle+i*(ANG45/16);
2299 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2302 pmo->flags2 |= MF2_ICEDAMAGE;
2303 P_DamageMobj(linetarget, pmo, pmo, damage);
2304 pmo->flags2 &= ~MF2_ICEDAMAGE;
2310 // didn't find any creatures, so fire projectiles
2313 mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
2316 mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
2318 mo->special2 = 3; // Set sperm count (levels of reproductivity)
2320 mo->args[0] = 3; // Mark Initial shard as super damage
2325 void A_ShedShard(mobj_t *actor)
2328 int spawndir = actor->special1;
2329 int spermcount = actor->special2;
2331 if (spermcount <= 0) return; // No sperm left
2332 actor->special2 = 0;
2335 // every so many calls, spawn a new missile in it's set directions
2336 if (spawndir & SHARDSPAWN_LEFT)
2338 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle+(ANG45/9),
2339 0, (20+2*spermcount)<<FRACBITS);
2342 mo->special1 = SHARDSPAWN_LEFT;
2343 mo->special2 = spermcount;
2344 mo->momz = actor->momz;
2345 mo->target = actor->target;
2346 mo->args[0] = (spermcount==3)?2:0;
2349 if (spawndir & SHARDSPAWN_RIGHT)
2351 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle-(ANG45/9),
2352 0, (20+2*spermcount)<<FRACBITS);
2355 mo->special1 = SHARDSPAWN_RIGHT;
2356 mo->special2 = spermcount;
2357 mo->momz = actor->momz;
2358 mo->target = actor->target;
2359 mo->args[0] = (spermcount==3)?2:0;
2362 if (spawndir & SHARDSPAWN_UP)
2364 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
2365 0, (15+2*spermcount)<<FRACBITS);
2368 mo->momz = actor->momz;
2369 mo->z += 8*FRACUNIT;
2370 if (spermcount & 1) // Every other reproduction
2371 mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
2373 mo->special1 = SHARDSPAWN_UP;
2374 mo->special2 = spermcount;
2375 mo->target = actor->target;
2376 mo->args[0] = (spermcount==3)?2:0;
2379 if (spawndir & SHARDSPAWN_DOWN)
2381 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
2382 0, (15+2*spermcount)<<FRACBITS);
2385 mo->momz = actor->momz;
2386 mo->z -= 4*FRACUNIT;
2387 if (spermcount & 1) // Every other reproduction
2388 mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
2390 mo->special1 = SHARDSPAWN_DOWN;
2391 mo->special2 = spermcount;
2392 mo->target = actor->target;
2393 mo->args[0] = (spermcount==3)?2:0;
2398 //----------------------------------------------------------------------------
2400 // PROC A_HideInCeiling
2402 //----------------------------------------------------------------------------
2405 void A_HideInCeiling(mobj_t *actor)
2407 actor->z = actor->ceilingz+4*FRACUNIT;
2411 //----------------------------------------------------------------------------
2415 //----------------------------------------------------------------------------
2418 void A_FloatPuff(mobj_t *puff)
2420 puff->momz += 1.8*FRACUNIT;
2424 void A_Light0(player_t *player, pspdef_t *psp)
2426 player->extralight = 0;
2430 void A_Light1(player_t *player, pspdef_t *psp)
2432 player->extralight = 1;
2437 void A_Light2(player_t *player, pspdef_t *psp)
2439 player->extralight = 2;
2443 //------------------------------------------------------------------------
2445 // PROC P_SetupPsprites
2447 // Called at start of level for each player
2449 //------------------------------------------------------------------------
2451 void P_SetupPsprites(player_t *player)
2455 // Remove all psprites
2456 for(i = 0; i < NUMPSPRITES; i++)
2458 player->psprites[i].state = NULL;
2460 // Spawn the ready weapon
2461 player->pendingweapon = player->readyweapon;
2462 P_BringUpWeapon(player);
2465 //------------------------------------------------------------------------
2467 // PROC P_MovePsprites
2469 // Called every tic by player thinking routine
2471 //------------------------------------------------------------------------
2473 void P_MovePsprites(player_t *player)
2479 psp = &player->psprites[0];
2480 for(i = 0; i < NUMPSPRITES; i++, psp++)
2482 if((state = psp->state) != 0) // a null state means not active
2484 // drop tic count and possibly change state
2485 if(psp->tics != -1) // a -1 tic count never changes
2490 P_SetPsprite(player, i, psp->state->nextstate);
2495 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
2496 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
2499 //============================================================================
2503 // Jim Cameron did most of this one
2504 //============================================================================
2506 void A_AKnifeAttack(player_t *player, pspdef_t *psp)
2511 mobj_t *pmo = player->mo;
2515 boolean oof = false;
2518 * jim - the Katar should be a bit feebler
2520 damage = 20+(P_Random()&15);
2522 PuffType = MT_PUNCHPUFF;
2524 for(i = 0; i < 16; i++)
2526 angle = pmo->angle+i*(ANG45/16);
2527 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2530 player->mo->special1++;
2532 * jim - this is the Mighty Blow for the fighter and is
2536 if(pmo->special1 == 3)
2540 PuffType = MT_HAMMERPUFF;
2544 * jim - instead of that we make the Katar deal more
2545 * damage to a monster if struck from behind. Assume
2546 * so if the angle of striking is within 45 degrees
2547 * of the angle the target is facing in
2548 * OOOPS! but only if it IS a monster! Striking trees from
2549 * behind might be amusing but doesn't do much for realism 8-)
2551 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2553 if ((angle - linetarget->angle < ANG45) ||
2554 (linetarget->angle - angle < ANG45))
2557 power = 6 * FRACUNIT;
2558 PuffType = MT_HAMMERPUFF;
2562 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2563 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2565 P_ThrustMobj(linetarget, angle, power);
2567 AdjustPlayerAngle(pmo);
2571 angle = pmo->angle-i*(ANG45/16);
2572 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2575 player->mo->special1++;
2577 * jim - this is the Mighty Blow for the fighter and is
2581 if(pmo->special1 == 3)
2585 PuffType = MT_HAMMERPUFF;
2589 * jim - instead of that we make the Katar deal more
2590 * damage to a monster if struck from behind. Assume
2591 * so if the angle of striking is within 45 degrees
2592 * of the angle the target is facing in
2593 * OOOPS! but only if it IS a monster! Striking trees from
2594 * behind might be amusing but doesn't do much for realism 8-)
2596 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2598 if ((angle - linetarget->angle < ANG45) ||
2599 (linetarget->angle - angle < ANG45))
2602 power = 6 * FRACUNIT;
2603 PuffType = MT_HAMMERPUFF;
2608 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2609 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2611 P_ThrustMobj(linetarget, angle, power);
2613 AdjustPlayerAngle(pmo);
2617 /* didn't find any creatures, so try to strike any walls*/
2621 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2622 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
2628 P_SetPsprite(player, ps_weapon, S_KATARATK2_1);
2630 * jim - come on, she's a girl!
2632 S_StartSound(pmo, SFX_PLAYER_MAGE_GRUNT);
2636 void A_ACrossAttack(player_t *player, pspdef_t *psp)
2639 mobj_t *pmo = player->mo;
2641 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2642 // pmo = player->mo;
2643 // P_SpawnPlayerMissile(pmo, MT_CSTAFF_MISSILE);
2646 * jim - special2 is used to control the serpent staff projectiles'
2647 * `slither' and is not used here
2648 * We do however want to give crossbow missiles BlasterMobjThinker()s
2649 * instead of the ordinary ones because they are FAST.
2651 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle);
2654 /* mo->special2 = 16; */
2655 mo->thinker.function = P_BlasterMobjThinker;
2657 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle-(ANG45/10));
2660 /* mo->special2 = 32; */
2661 mo->thinker.function = P_BlasterMobjThinker;
2663 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle+(ANG45/10));
2666 /* mo->special2 = 0; */
2667 mo->thinker.function = P_BlasterMobjThinker;
2669 S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
2673 void A_AGrenAttack(player_t *player, pspdef_t *psp)
2677 mo = P_SpawnMobj(player->mo->x, player->mo->y,
2678 player->mo->z-player->mo->floorclip+35*FRACUNIT,
2682 mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
2683 mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
2684 mo->z += player->lookdir<<(FRACBITS-4);
2685 P_ThrustMobj(mo, mo->angle, mo->info->speed);
2686 mo->momx += player->mo->momx>>1;
2687 mo->momy += player->mo->momy>>1;
2688 mo->target = player->mo;
2689 mo->tics -= P_Random()&3;
2690 P_CheckMissileSpawn(mo);
2694 void A_AStaffAttack(player_t *player, pspdef_t *psp)
2700 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2701 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];