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
89 S_SNOUTDOWN, // downstate
90 S_SNOUTREADY, // readystate
91 S_SNOUTATK1, // atkstate
92 S_SNOUTATK1, // holdatkstate
100 S_FAXEDOWN, // downstate
101 S_FAXEREADY, // readystate
102 S_FAXEATK_1, // atkstate
103 S_FAXEATK_1, // holdatkstate
106 { // Cleric - Serpent Staff
108 S_CSTAFFUP, // upstate
109 S_CSTAFFDOWN, // downstate
110 S_CSTAFFREADY, // readystate
111 S_CSTAFFATK_1, // atkstate
112 S_CSTAFFATK_1, // holdatkstate
115 { // Mage - Cone of shards
118 S_CONEDOWN, // downstate
119 S_CONEREADY, // readystate
120 S_CONEATK1_1, // atkstate
121 S_CONEATK1_3, // holdatkstate
125 { // Assassin - Hand Crossbow
137 S_SNOUTUP, // upstate
138 S_SNOUTDOWN, // downstate
139 S_SNOUTREADY, // readystate
140 S_SNOUTATK1, // atkstate
141 S_SNOUTATK1, // holdatkstate
146 { // Fighter - Hammer
148 S_FHAMMERUP, // upstate
149 S_FHAMMERDOWN, // downstate
150 S_FHAMMERREADY, // readystate
151 S_FHAMMERATK_1, // atkstate
152 S_FHAMMERATK_1, // holdatkstate
155 { // Cleric - Flame Strike
157 S_CFLAMEUP, // upstate
158 S_CFLAMEDOWN, // downstate
159 S_CFLAMEREADY1, // readystate
160 S_CFLAMEATK_1, // atkstate
161 S_CFLAMEATK_1, // holdatkstate
164 { // Mage - Lightning
166 S_MLIGHTNINGUP, // upstate
167 S_MLIGHTNINGDOWN, // downstate
168 S_MLIGHTNINGREADY, // readystate
169 S_MLIGHTNINGATK_1, // atkstate
170 S_MLIGHTNINGATK_1, // holdatkstate
174 { // Assassin - Grenades
186 S_SNOUTUP, // upstate
187 S_SNOUTDOWN, // downstate
188 S_SNOUTREADY, // readystate
189 S_SNOUTATK1, // atkstate
190 S_SNOUTATK1, // holdatkstate
195 { // Fighter - Rune Sword
197 S_FSWORDUP, // upstate
198 S_FSWORDDOWN, // downstate
199 S_FSWORDREADY, // readystate
200 S_FSWORDATK_1, // atkstate
201 S_FSWORDATK_1, // holdatkstate
204 { // Cleric - Holy Symbol
206 S_CHOLYUP, // upstate
207 S_CHOLYDOWN, // downstate
208 S_CHOLYREADY, // readystate
209 S_CHOLYATK_1, // atkstate
210 S_CHOLYATK_1, // holdatkstate
215 S_MSTAFFUP, // upstate
216 S_MSTAFFDOWN, // downstate
217 S_MSTAFFREADY, // readystate
218 S_MSTAFFATK_1, // atkstate
219 S_MSTAFFATK_1, // holdatkstate
223 { // Assassin - Staff of Set
235 S_SNOUTUP, // upstate
236 S_SNOUTDOWN, // downstate
237 S_SNOUTREADY, // readystate
238 S_SNOUTATK1, // atkstate
239 S_SNOUTATK1, // holdatkstate
245 // PRIVATE DATA DEFINITIONS ------------------------------------------------
247 static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] =
253 { 0, 3, 3, 1 }, // True to Hexen II
258 // CODE --------------------------------------------------------------------
260 //---------------------------------------------------------------------------
264 //---------------------------------------------------------------------------
266 void P_SetPsprite(player_t *player, int position, statenum_t stnum)
271 psp = &player->psprites[position];
275 { // Object removed itself.
279 state = &states[stnum];
281 psp->tics = state->tics; // could be 0
283 { // Set coordinates.
284 psp->sx = state->misc1<<FRACBITS;
288 psp->sy = state->misc2<<FRACBITS;
291 { // Call action routine.
292 state->action(player, psp);
298 stnum = psp->state->nextstate;
299 } while(!psp->tics); // An initial state of 0 could cycle through.
302 //---------------------------------------------------------------------------
304 // PROC P_SetPspriteNF
306 // Identical to P_SetPsprite, without calling the action function
307 //---------------------------------------------------------------------------
309 void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
314 psp = &player->psprites[position];
318 { // Object removed itself.
322 state = &states[stnum];
324 psp->tics = state->tics; // could be 0
326 { // Set coordinates.
327 psp->sx = state->misc1<<FRACBITS;
331 psp->sy = state->misc2<<FRACBITS;
333 stnum = psp->state->nextstate;
334 } while(!psp->tics); // An initial state of 0 could cycle through.
346 fixed_t swingx, swingy;
347 void P_CalcSwing (player_t *player)
352 // OPTIMIZE: tablify this
356 angle = (FINEANGLES/70*leveltime)&FINEMASK;
357 swingx = FixedMul ( swing, finesine[angle]);
359 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
360 swingy = -FixedMul ( swingx, finesine[angle]);
364 //---------------------------------------------------------------------------
366 // PROC P_ActivateMorphWeapon
368 //---------------------------------------------------------------------------
370 void P_ActivateMorphWeapon(player_t *player)
372 player->pendingweapon = WP_NOCHANGE;
373 player->psprites[ps_weapon].sy = WEAPONTOP;
374 player->readyweapon = WP_FIRST; // Snout is the first weapon
375 P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
379 //---------------------------------------------------------------------------
381 // PROC P_PostMorphWeapon
383 //---------------------------------------------------------------------------
385 void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
387 player->pendingweapon = WP_NOCHANGE;
388 player->readyweapon = weapon;
389 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
390 P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->class].upstate);
393 //---------------------------------------------------------------------------
395 // PROC P_BringUpWeapon
397 // Starts bringing the pending weapon up from the bottom of the screen.
399 //---------------------------------------------------------------------------
401 void P_BringUpWeapon(player_t *player)
405 if(player->pendingweapon == WP_NOCHANGE)
407 player->pendingweapon = player->readyweapon;
409 if(player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
410 && player->mana[MANA_1])
416 new = WeaponInfo[player->pendingweapon][player->class].upstate;
418 player->pendingweapon = WP_NOCHANGE;
419 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
420 P_SetPsprite(player, ps_weapon, new);
423 //---------------------------------------------------------------------------
427 // Returns true if there is enough mana to shoot. If not, selects the
428 // next weapon to use.
430 //---------------------------------------------------------------------------
432 boolean P_CheckMana(player_t *player)
437 mana = WeaponInfo[player->readyweapon][player->class].mana;
438 count = WeaponManaUse[player->class][player->readyweapon];
439 if(mana == MANA_BOTH)
441 if(player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
446 else if(mana == MANA_NONE || player->mana[mana] >= count)
450 // out of mana, pick a weapon to change to
453 if(player->weaponowned[WP_THIRD]
454 && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD])
456 player->pendingweapon = WP_THIRD;
458 else if(player->weaponowned[WP_SECOND]
459 && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_SECOND])
461 player->pendingweapon = WP_SECOND;
463 else if(player->weaponowned[WP_FOURTH]
464 && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_FOURTH]
465 && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_FOURTH])
467 player->pendingweapon = WP_FOURTH;
471 player->pendingweapon = WP_FIRST;
473 } while(player->pendingweapon == WP_NOCHANGE);
474 P_SetPsprite(player, ps_weapon,
475 WeaponInfo[player->readyweapon][player->class].downstate);
479 //---------------------------------------------------------------------------
483 //---------------------------------------------------------------------------
485 void P_FireWeapon(player_t *player)
487 statenum_t attackState;
489 if(!P_CheckMana(player))
493 P_SetMobjState(player->mo, PStateAttack[player->class]); // S_PLAY_ATK1);
494 if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
495 && player->mana[MANA_1] > 0)
497 attackState = S_FAXEATK_G1;
501 attackState = player->refire ?
502 WeaponInfo[player->readyweapon][player->class].holdatkstate
503 : WeaponInfo[player->readyweapon][player->class].atkstate;
505 P_SetPsprite(player, ps_weapon, attackState);
506 P_NoiseAlert(player->mo, player->mo);
509 //---------------------------------------------------------------------------
513 // The player died, so put the weapon away.
515 //---------------------------------------------------------------------------
517 void P_DropWeapon(player_t *player)
519 P_SetPsprite(player, ps_weapon,
520 WeaponInfo[player->readyweapon][player->class].downstate);
523 //---------------------------------------------------------------------------
525 // PROC A_WeaponReady
527 // The player can fire the weapon or change to another weapon at this time.
529 //---------------------------------------------------------------------------
531 void A_WeaponReady(player_t *player, pspdef_t *psp)
535 // Change player from attack state
536 if(player->mo->state >= &states[PStateAttack[player->class]]
537 && player->mo->state <= &states[PStateAttackEnd[player->class]])
539 P_SetMobjState(player->mo, PStateNormal[player->class]);
541 // Put the weapon away if the player has a pending weapon or has
543 if(player->pendingweapon != WP_NOCHANGE || !player->health)
545 P_SetPsprite(player, ps_weapon,
546 WeaponInfo[player->readyweapon][player->class].downstate);
551 if(player->cmd.buttons&BT_ATTACK)
553 player->attackdown = true;
554 P_FireWeapon(player);
559 player->attackdown = false;
562 if(!player->morphTics)
564 // Bob the weapon based on movement speed.
565 angle = (128*leveltime)&FINEMASK;
566 psp->sx = FRACUNIT+FixedMul(player->bob, finecosine[angle]);
567 angle &= FINEANGLES/2-1;
568 psp->sy = WEAPONTOP+FixedMul(player->bob, finesine[angle]);
572 //---------------------------------------------------------------------------
576 // The player can re fire the weapon without lowering it entirely.
578 //---------------------------------------------------------------------------
580 void A_ReFire(player_t *player, pspdef_t *psp)
582 if((player->cmd.buttons&BT_ATTACK)
583 && player->pendingweapon == WP_NOCHANGE && player->health)
586 P_FireWeapon(player);
595 //---------------------------------------------------------------------------
599 //---------------------------------------------------------------------------
601 void A_Lower(player_t *player, pspdef_t *psp)
603 if(player->morphTics)
605 psp->sy = WEAPONBOTTOM;
609 psp->sy += LOWERSPEED;
611 if(psp->sy < WEAPONBOTTOM)
612 { // Not lowered all the way yet
615 if(player->playerstate == PST_DEAD)
616 { // Player is dead, so don't bring up a pending weapon
617 psp->sy = WEAPONBOTTOM;
621 { // Player is dead, so keep the weapon off screen
622 P_SetPsprite(player, ps_weapon, S_NULL);
625 player->readyweapon = player->pendingweapon;
626 P_BringUpWeapon(player);
629 //---------------------------------------------------------------------------
633 //---------------------------------------------------------------------------
635 void A_Raise(player_t *player, pspdef_t *psp)
637 psp->sy -= RAISESPEED;
638 if(psp->sy > WEAPONTOP)
639 { // Not raised all the way yet
643 if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
644 && player->mana[MANA_1])
646 P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
650 P_SetPsprite(player, ps_weapon,
651 WeaponInfo[player->readyweapon][player->class].readystate);
660 = Sets a slope so a near miss is at aproximately the height of the
667 void P_BulletSlope (mobj_t *mo)
672 // see which target is to be aimed at
675 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
679 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
683 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
688 bulletslope = (mo->player->lookdir<<FRACBITS)/173;
694 //****************************************************************************
698 //****************************************************************************
700 //============================================================================
704 //============================================================================
706 #define MAX_ANGLE_ADJUST (5*ANGLE_1)
708 void AdjustPlayerAngle(mobj_t *pmo)
713 angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
714 difference = (int)angle-(int)pmo->angle;
715 if(abs(difference) > MAX_ANGLE_ADJUST)
717 pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
725 //============================================================================
729 //============================================================================
731 void A_SnoutAttack(player_t *player, pspdef_t *psp)
737 damage = 3+(P_Random()&3);
738 angle = player->mo->angle;
739 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
740 PuffType = MT_SNOUTPUFF;
742 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
743 S_StartSound(player->mo, SFX_PIG_ACTIVE1+(P_Random()&1));
746 AdjustPlayerAngle(player->mo);
747 // player->mo->angle = R_PointToAngle2(player->mo->x,
748 // player->mo->y, linetarget->x, linetarget->y);
751 S_StartSound(player->mo, SFX_PIG_ATTACK);
756 //============================================================================
760 //============================================================================
762 #define HAMMER_RANGE (MELEERANGE+MELEERANGE/2)
764 void A_FHammerAttack(player_t *player, pspdef_t *psp)
767 mobj_t *pmo=player->mo;
773 damage = 60+(P_Random()&63);
775 PuffType = MT_HAMMERPUFF;
776 for(i = 0; i < 16; i++)
778 angle = pmo->angle+i*(ANG45/32);
779 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
782 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
783 AdjustPlayerAngle(pmo);
784 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
786 P_ThrustMobj(linetarget, angle, power);
788 pmo->special1 = false; // Don't throw a hammer
791 angle = pmo->angle-i*(ANG45/32);
792 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
795 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
796 AdjustPlayerAngle(pmo);
797 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
799 P_ThrustMobj(linetarget, angle, power);
801 pmo->special1 = false; // Don't throw a hammer
805 // didn't find any targets in meleerange, so set to throw out a hammer
808 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
809 P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
812 pmo->special1 = false;
816 pmo->special1 = true;
819 if(player->mana[MANA_2] <
820 WeaponManaUse[player->class][player->readyweapon])
821 { // Don't spawn a hammer if the player doesn't have enough mana
822 pmo->special1 = false;
827 //============================================================================
831 //============================================================================
833 void A_FHammerThrow(player_t *player, pspdef_t *psp)
837 if(!player->mo->special1)
841 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
842 mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE);
849 //============================================================================
853 //============================================================================
855 void A_FSwordAttack(player_t *player, pspdef_t *psp)
859 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
860 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
862 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-10*FRACUNIT, MT_FSWORD_MISSILE,
864 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-5*FRACUNIT, MT_FSWORD_MISSILE,
866 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
867 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+5*FRACUNIT, MT_FSWORD_MISSILE,
869 P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+10*FRACUNIT, MT_FSWORD_MISSILE,
871 S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
874 //============================================================================
878 //============================================================================
880 void A_FSwordAttack2(mobj_t *actor)
882 angle_t angle = actor->angle;
884 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/4, 0);
885 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/8, 0);
886 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle, 0);
887 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/8, 0);
888 P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/4, 0);
889 S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
892 //============================================================================
896 //============================================================================
898 void A_FSwordFlames(mobj_t *actor)
902 for(i = 1+(P_Random()&3); i; i--)
904 P_SpawnMobj(actor->x+((P_Random()-128)<<12), actor->y
905 +((P_Random()-128)<<12), actor->z+((P_Random()-128)<<11),
910 //============================================================================
914 //============================================================================
916 void A_MWandAttack(player_t *player, pspdef_t *psp)
920 mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
923 mo->thinker.function = P_BlasterMobjThinker;
925 S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
928 // ===== Mage Lightning Weapon =====
930 //============================================================================
934 //============================================================================
936 void A_LightningReady(player_t *player, pspdef_t *psp)
938 A_WeaponReady(player, psp);
941 S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
945 //============================================================================
949 //============================================================================
951 #define ZAGSPEED FRACUNIT
953 void A_LightningClip(mobj_t *actor)
956 mobj_t *target = NULL; /* jim added initialiser */
959 if(actor->type == MT_LIGHTNING_FLOOR)
961 actor->z = actor->floorz;
962 target = (mobj_t *)((mobj_t *)actor->special2)->special1;
964 else if(actor->type == MT_LIGHTNING_CEILING)
966 actor->z = actor->ceilingz-actor->height;
967 target = (mobj_t *)actor->special1;
969 if(actor->type == MT_LIGHTNING_FLOOR)
970 { // floor lightning zig-zags, and forces the ceiling lightning to mimic
971 cMo = (mobj_t *)actor->special2;
973 if((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
975 P_ThrustMobj(actor, actor->angle+ANG90, ZAGSPEED);
978 P_ThrustMobj(cMo, actor->angle+ANG90, ZAGSPEED);
984 P_ThrustMobj(actor, actor->angle-ANG90, ZAGSPEED);
987 P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
994 if(target->health <= 0)
996 P_ExplodeMissile(actor);
1000 actor->angle = R_PointToAngle2(actor->x, actor->y, target->x,
1004 P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
1009 //============================================================================
1013 //============================================================================
1015 void A_LightningZap(mobj_t *actor)
1020 A_LightningClip(actor);
1023 if(actor->health <= 0)
1025 P_SetMobjState(actor, actor->info->deathstate);
1028 if(actor->type == MT_LIGHTNING_FLOOR)
1030 deltaZ = 10*FRACUNIT;
1034 deltaZ = -10*FRACUNIT;
1036 mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256),
1037 actor->y+((P_Random()-128)*actor->radius/256),
1038 actor->z+deltaZ, MT_LIGHTNING_ZAP);
1041 mo->special2 = (int)actor;
1042 mo->momx = actor->momx;
1043 mo->momy = actor->momy;
1044 mo->target = actor->target;
1045 if(actor->type == MT_LIGHTNING_FLOOR)
1047 mo->momz = 20*FRACUNIT;
1051 mo->momz = -20*FRACUNIT;
1055 mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256),
1056 actor->y+((P_Random()-128)*actor->radius/256),
1057 actor->z+deltaZ, MT_LIGHTNING_ZAP);
1060 mo->special2 = (int)actor;
1061 mo->momx = actor->momx;
1062 mo->momy = actor->momy;
1063 mo->target = actor->target;
1064 if(actor->type == MT_LIGHTNING_FLOOR)
1066 mo->momz = 16*FRACUNIT;
1070 mo->momz = -16*FRACUNIT;
1074 if(actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
1076 S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
1080 //============================================================================
1082 // A_MLightningAttack2
1084 //============================================================================
1086 void A_MLightningAttack2(mobj_t *actor)
1090 fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
1091 cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
1095 fmo->special2 = (int)cmo;
1096 A_LightningZap(fmo);
1100 cmo->special1 = 0; // mobj that it will track
1101 cmo->special2 = (int)fmo;
1102 A_LightningZap(cmo);
1104 S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
1107 //============================================================================
1109 // A_MLightningAttack
1111 //============================================================================
1113 void A_MLightningAttack(player_t *player, pspdef_t *psp)
1115 A_MLightningAttack2(player->mo);
1116 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1119 //============================================================================
1123 //============================================================================
1125 void A_ZapMimic(mobj_t *actor)
1129 mo = (mobj_t *)actor->special2;
1132 if(mo->state >= &states[mo->info->deathstate]
1133 || mo->state == &states[S_FREETARGMOBJ])
1135 P_ExplodeMissile(actor);
1139 actor->momx = mo->momx;
1140 actor->momy = mo->momy;
1145 //============================================================================
1149 //============================================================================
1151 void A_LastZap(mobj_t *actor)
1155 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
1158 P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
1159 mo->momz = 40*FRACUNIT;
1163 //============================================================================
1165 // A_LightningRemove
1167 //============================================================================
1169 void A_LightningRemove(mobj_t *actor)
1173 mo = (mobj_t *)actor->special2;
1177 P_ExplodeMissile(mo);
1182 //============================================================================
1186 //============================================================================
1187 void MStaffSpawn(mobj_t *pmo, angle_t angle)
1191 mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
1195 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1199 //============================================================================
1203 //============================================================================
1205 void A_MStaffAttack(player_t *player, pspdef_t *psp)
1210 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1211 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1215 MStaffSpawn(pmo, angle);
1216 MStaffSpawn(pmo, angle-ANGLE_1*5);
1217 MStaffSpawn(pmo, angle+ANGLE_1*5);
1218 S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
1219 if(player == &players[consoleplayer])
1221 player->damagecount = 0;
1222 player->bonuscount = 0;
1223 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1224 PU_CACHE)+STARTSCOURGEPAL*768);
1228 //============================================================================
1232 //============================================================================
1234 void A_MStaffPalette(player_t *player, pspdef_t *psp)
1238 if(player == &players[consoleplayer])
1240 pal = STARTSCOURGEPAL+psp->state-(&states[S_MSTAFFATK_2]);
1241 if(pal == STARTSCOURGEPAL+3)
1242 { // reset back to original playpal
1245 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1250 //============================================================================
1254 //============================================================================
1256 void A_MStaffWeave(mobj_t *actor)
1259 int weaveXY, weaveZ;
1262 weaveXY = actor->special2>>16;
1263 weaveZ = actor->special2&0xFFFF;
1264 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1265 newX = actor->x-FixedMul(finecosine[angle],
1266 FloatBobOffsets[weaveXY]<<2);
1267 newY = actor->y-FixedMul(finesine[angle],
1268 FloatBobOffsets[weaveXY]<<2);
1269 weaveXY = (weaveXY+6)&63;
1270 newX += FixedMul(finecosine[angle],
1271 FloatBobOffsets[weaveXY]<<2);
1272 newY += FixedMul(finesine[angle],
1273 FloatBobOffsets[weaveXY]<<2);
1274 P_TryMove(actor, newX, newY);
1275 actor->z -= FloatBobOffsets[weaveZ]<<1;
1276 weaveZ = (weaveZ+3)&63;
1277 actor->z += FloatBobOffsets[weaveZ]<<1;
1278 if(actor->z <= actor->floorz)
1280 actor->z = actor->floorz+FRACUNIT;
1282 actor->special2 = weaveZ+(weaveXY<<16);
1286 //============================================================================
1290 //============================================================================
1292 void A_MStaffTrack(mobj_t *actor)
1294 if ((actor->special1 == 0) && (P_Random()<50))
1296 actor->special1 = (int)P_RoughMonsterSearch(actor, 10);
1298 P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
1302 //============================================================================
1304 // MStaffSpawn2 - for use by mage class boss
1306 //============================================================================
1308 void MStaffSpawn2(mobj_t *actor, angle_t angle)
1312 mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
1316 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1320 //============================================================================
1322 // A_MStaffAttack2 - for use by mage class boss
1324 //============================================================================
1326 void A_MStaffAttack2(mobj_t *actor)
1329 angle = actor->angle;
1330 MStaffSpawn2(actor, angle);
1331 MStaffSpawn2(actor, angle-ANGLE_1*5);
1332 MStaffSpawn2(actor, angle+ANGLE_1*5);
1333 S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
1336 //============================================================================
1340 //============================================================================
1342 void A_FPunchAttack(player_t *player, pspdef_t *psp)
1347 mobj_t *pmo = player->mo;
1351 damage = 40+(P_Random()&15);
1353 PuffType = MT_PUNCHPUFF;
1354 for(i = 0; i < 16; i++)
1356 angle = pmo->angle+i*(ANG45/16);
1357 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1360 player->mo->special1++;
1361 if(pmo->special1 == 3)
1365 PuffType = MT_HAMMERPUFF;
1367 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1368 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1370 P_ThrustMobj(linetarget, angle, power);
1372 AdjustPlayerAngle(pmo);
1375 angle = pmo->angle-i*(ANG45/16);
1376 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1380 if(pmo->special1 == 3)
1384 PuffType = MT_HAMMERPUFF;
1386 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1387 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1389 P_ThrustMobj(linetarget, angle, power);
1391 AdjustPlayerAngle(pmo);
1395 // didn't find any creatures, so try to strike any walls
1399 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1400 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1403 if(pmo->special1 == 3)
1406 P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
1407 S_StartSound(pmo, SFX_FIGHTER_GRUNT);
1412 //============================================================================
1416 //============================================================================
1418 #define AXERANGE 2.25*MELEERANGE
1420 void A_FAxeAttack(player_t *player, pspdef_t *psp)
1423 mobj_t *pmo=player->mo;
1430 damage = 40+(P_Random()&15)+(P_Random()&7);
1432 if(player->mana[MANA_1] > 0)
1436 PuffType = MT_AXEPUFF_GLOW;
1441 PuffType = MT_AXEPUFF;
1444 for(i = 0; i < 16; i++)
1446 angle = pmo->angle+i*(ANG45/16);
1447 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1450 P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1451 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1453 P_ThrustMobj(linetarget, angle, power);
1455 AdjustPlayerAngle(pmo);
1459 angle = pmo->angle-i*(ANG45/16);
1460 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1463 P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1464 if (linetarget->flags&MF_COUNTKILL)
1466 P_ThrustMobj(linetarget, angle, power);
1468 AdjustPlayerAngle(pmo);
1473 // didn't find any creatures, so try to strike any walls
1477 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1478 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1483 player->mana[MANA_1] -=
1484 WeaponManaUse[player->class][player->readyweapon];
1485 if(player->mana[MANA_1] <= 0)
1487 P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
1493 //===========================================================================
1497 //===========================================================================
1499 void A_CMaceAttack(player_t *player, pspdef_t *psp)
1506 damage = 25+(P_Random()&15);
1507 PuffType = MT_HAMMERPUFF;
1508 for(i = 0; i < 16; i++)
1510 angle = player->mo->angle+i*(ANG45/16);
1511 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1514 P_LineAttack(player->mo, angle, 2*MELEERANGE, slope,
1516 AdjustPlayerAngle(player->mo);
1517 // player->mo->angle = R_PointToAngle2(player->mo->x,
1518 // player->mo->y, linetarget->x, linetarget->y);
1521 angle = player->mo->angle-i*(ANG45/16);
1522 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1525 P_LineAttack(player->mo, angle, 2*MELEERANGE, slope,
1527 AdjustPlayerAngle(player->mo);
1528 // player->mo->angle = R_PointToAngle2(player->mo->x,
1529 // player->mo->y, linetarget->x, linetarget->y);
1533 // didn't find any creatures, so try to strike any walls
1534 player->mo->special1 = 0;
1536 angle = player->mo->angle;
1537 slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
1538 P_LineAttack(player->mo, angle, MELEERANGE, slope,
1544 //============================================================================
1548 //============================================================================
1550 void A_CStaffCheck(player_t *player, pspdef_t *psp)
1560 damage = 20+(P_Random()&15);
1561 PuffType = MT_CSTAFFPUFF;
1562 for(i = 0; i < 3; i++)
1564 angle = pmo->angle+i*(ANG45/16);
1565 slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
1568 P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
1569 pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
1570 linetarget->x, linetarget->y);
1571 if((linetarget->player || linetarget->flags&MF_COUNTKILL)
1572 && (!(linetarget->flags2&(MF2_DORMANT+MF2_INVULNERABLE))))
1574 newLife = player->health+(damage>>3);
1575 newLife = newLife > 100 ? 100 : newLife;
1576 pmo->health = player->health = newLife;
1577 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
1579 player->mana[MANA_1] -=
1580 WeaponManaUse[player->class][player->readyweapon];
1583 angle = pmo->angle-i*(ANG45/16);
1584 slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
1587 P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
1588 pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
1589 linetarget->x, linetarget->y);
1590 if(linetarget->player || linetarget->flags&MF_COUNTKILL)
1592 newLife = player->health+(damage>>4);
1593 newLife = newLife > 100 ? 100 : newLife;
1594 pmo->health = player->health = newLife;
1595 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
1597 player->mana[MANA_1] -=
1598 WeaponManaUse[player->class][player->readyweapon];
1604 //============================================================================
1608 //============================================================================
1610 void A_CStaffAttack(player_t *player, pspdef_t *psp)
1615 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1617 mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle-(ANG45/15));
1622 mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle+(ANG45/15));
1627 S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
1630 //============================================================================
1632 // A_CStaffMissileSlither
1634 //============================================================================
1636 void A_CStaffMissileSlither(mobj_t *actor)
1642 weaveXY = actor->special2;
1643 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1644 newX = actor->x-FixedMul(finecosine[angle],
1645 FloatBobOffsets[weaveXY]);
1646 newY = actor->y-FixedMul(finesine[angle],
1647 FloatBobOffsets[weaveXY]);
1648 weaveXY = (weaveXY+3)&63;
1649 newX += FixedMul(finecosine[angle],
1650 FloatBobOffsets[weaveXY]);
1651 newY += FixedMul(finesine[angle],
1652 FloatBobOffsets[weaveXY]);
1653 P_TryMove(actor, newX, newY);
1654 actor->special2 = weaveXY;
1657 //============================================================================
1659 // A_CStaffInitBlink
1661 //============================================================================
1663 void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
1665 player->mo->special1 = (P_Random()>>1)+20;
1668 //============================================================================
1670 // A_CStaffCheckBlink
1672 //============================================================================
1674 void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
1676 if(!--player->mo->special1)
1678 P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
1679 player->mo->special1 = (P_Random()+50)>>2;
1683 //============================================================================
1687 //============================================================================
1689 #define FLAMESPEED (0.45*FRACUNIT)
1690 #define CFLAMERANGE (12*64*FRACUNIT)
1692 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1696 mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
1699 mo->thinker.function = P_BlasterMobjThinker;
1703 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1704 S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1707 //============================================================================
1711 //============================================================================
1713 void A_CFlamePuff(mobj_t *actor)
1715 A_UnHideThing(actor);
1719 S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
1722 //============================================================================
1726 //============================================================================
1728 void A_CFlameMissile(mobj_t *actor)
1735 A_UnHideThing(actor);
1736 S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
1737 if(BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE)
1738 { // Hit something, so spawn the flame circle around the thing
1739 dist = BlockingMobj->radius+18*FRACUNIT;
1740 for(i = 0; i < 4; i++)
1742 an = (i*ANG45)>>ANGLETOFINESHIFT;
1743 an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
1744 mo = P_SpawnMobj(BlockingMobj->x+FixedMul(dist, finecosine[an]),
1745 BlockingMobj->y+FixedMul(dist, finesine[an]),
1746 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
1749 mo->angle = an<<ANGLETOFINESHIFT;
1750 mo->target = actor->target;
1751 mo->momx = mo->special1 = FixedMul(finecosine[an], FLAMESPEED);
1752 mo->momy = mo->special2 = FixedMul(finesine[an], FLAMESPEED);
1753 mo->tics -= P_Random()&3;
1755 mo = P_SpawnMobj(BlockingMobj->x-FixedMul(dist, finecosine[an]),
1756 BlockingMobj->y-FixedMul(dist, finesine[an]),
1757 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
1760 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
1761 mo->target = actor->target;
1762 mo->momx = mo->special1 = FixedMul(finecosine[an],-FLAMESPEED);
1763 mo->momy = mo->special2 = FixedMul(finesine[an],-FLAMESPEED);
1764 mo->tics -= P_Random()&3;
1767 P_SetMobjState(actor, S_FLAMEPUFF2_1);
1772 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1784 damage = 25+HITDICE(3);
1788 angle += (P_Random()-P_Random())<<17;
1790 P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
1794 P_AimLineAttack(pmo, angle, CFLAMERANGE);
1798 P_AimLineAttack(pmo, angle, CFLAMERANGE);
1807 PuffType = MT_FLAMEPUFF2;
1811 PuffType = MT_FLAMEPUFF;
1813 P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
1815 { // Hit something, so spawn the flame circle around the thing
1816 dist = linetarget->radius+18*FRACUNIT;
1817 for(i = 0; i < 4; i++)
1819 an = (i*ANG45)>>ANGLETOFINESHIFT;
1820 an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
1821 mo = P_SpawnMobj(linetarget->x+FixedMul(dist, finecosine[an]),
1822 linetarget->y+FixedMul(dist, finesine[an]),
1823 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
1826 mo->angle = an<<ANGLETOFINESHIFT;
1828 mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
1829 mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
1830 mo->tics -= P_Random()&3;
1832 mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]),
1833 linetarget->y-FixedMul(dist, finesine[an]),
1834 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
1837 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
1839 mo->momx = mo->special1 = FixedMul(-FLAMESPEED,
1841 mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
1842 mo->tics -= P_Random()&3;
1846 // Create a line of flames from the player to the flame puff
1847 CFlameCreateFlames(player->mo);
1849 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1850 S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1854 //============================================================================
1858 //============================================================================
1860 #define FLAMEROTSPEED 2*FRACUNIT
1862 void A_CFlameRotate(mobj_t *actor)
1866 an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
1867 actor->momx = actor->special1+FixedMul(FLAMEROTSPEED, finecosine[an]);
1868 actor->momy = actor->special2+FixedMul(FLAMEROTSPEED, finesine[an]);
1869 actor->angle += ANG90/15;
1873 //============================================================================
1877 // Spawns the spirits
1878 //============================================================================
1880 void A_CHolyAttack3(mobj_t *actor)
1882 P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
1883 S_StartSound(actor, SFX_CHOLY_FIRE);
1887 //============================================================================
1891 // Spawns the spirits
1892 //============================================================================
1894 void A_CHolyAttack2(mobj_t *actor)
1899 mobj_t *tail, *next;
1901 for(j = 0; j < 4; j++)
1903 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
1909 { // float bob index
1911 mo->special2 = P_Random()&7; // upper-left
1914 mo->special2 = 32+(P_Random()&7); // upper-right
1917 mo->special2 = (32+(P_Random()&7))<<16; // lower-left
1920 mo->special2 = ((32+(P_Random()&7))<<16)+32+(P_Random()&7);
1924 mo->angle = actor->angle+(ANGLE_45+ANGLE_45/2)-ANGLE_45*j;
1925 P_ThrustMobj(mo, mo->angle, mo->info->speed);
1926 mo->target = actor->target;
1927 mo->args[0] = 10; // initial turn value
1928 mo->args[1] = 0; // initial look angle
1930 { // Ghosts last slightly less longer in DeathMatch
1935 mo->special1 = (int)linetarget;
1936 mo->flags |= MF_NOCLIP|MF_SKULLFLY;
1937 mo->flags &= ~MF_MISSILE;
1939 tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
1940 tail->special2 = (int)mo; // parent
1941 for(i = 1; i < 3; i++)
1943 next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
1944 P_SetMobjState(next, next->info->spawnstate+1);
1945 tail->special1 = (int)next;
1948 tail->special1 = 0; // last tail bit
1952 //============================================================================
1956 //============================================================================
1958 void A_CHolyAttack(player_t *player, pspdef_t *psp)
1962 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1963 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1964 mo = P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
1965 if(player == &players[consoleplayer])
1967 player->damagecount = 0;
1968 player->bonuscount = 0;
1969 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1970 PU_CACHE)+STARTHOLYPAL*768);
1972 S_StartSound(player->mo, SFX_CHOLY_FIRE);
1975 //============================================================================
1979 //============================================================================
1981 void A_CHolyPalette(player_t *player, pspdef_t *psp)
1985 if(player == &players[consoleplayer])
1987 pal = STARTHOLYPAL+psp->state-(&states[S_CHOLYATK_6]);
1988 if(pal == STARTHOLYPAL+3)
1989 { // reset back to original playpal
1992 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1997 //============================================================================
2001 //============================================================================
2003 static void CHolyFindTarget(mobj_t *actor)
2005 /* jim changed to avoid single = in if() */
2006 /* mobj_t *target; */
2008 /* if(target = P_RoughMonsterSearch(actor, 6)) */
2010 mobj_t *target = P_RoughMonsterSearch (actor, 6);
2014 actor->special1 = (int)target;
2015 actor->flags |= MF_NOCLIP|MF_SKULLFLY;
2016 actor->flags &= ~MF_MISSILE;
2020 //============================================================================
2022 // CHolySeekerMissile
2024 // Similar to P_SeekerMissile, but seeks to a random Z on the target
2025 //============================================================================
2027 static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
2037 target = (mobj_t *)actor->special1;
2042 if(!(target->flags&MF_SHOOTABLE)
2043 || (!(target->flags&MF_COUNTKILL) && !target->player))
2044 { // Target died/target isn't a player or creature
2045 actor->special1 = 0;
2046 actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
2047 actor->flags |= MF_MISSILE;
2048 CHolyFindTarget(actor);
2051 dir = P_FaceMobj(actor, target, &delta);
2062 actor->angle += delta;
2065 { // Turn counter clockwise
2066 actor->angle -= delta;
2068 angle = actor->angle>>ANGLETOFINESHIFT;
2069 actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
2070 actor->momy = FixedMul(actor->info->speed, finesine[angle]);
2072 || actor->z > target->z+(target->height)
2073 || actor->z+actor->height < target->z)
2075 newZ = target->z+((P_Random()*target->height)>>8);
2076 deltaZ = newZ-actor->z;
2077 if(abs(deltaZ) > 15*FRACUNIT)
2081 deltaZ = 15*FRACUNIT;
2085 deltaZ = -15*FRACUNIT;
2088 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
2089 dist = dist/actor->info->speed;
2094 actor->momz = deltaZ/dist;
2099 //============================================================================
2103 //============================================================================
2105 static void CHolyWeave(mobj_t *actor)
2108 int weaveXY, weaveZ;
2111 weaveXY = actor->special2>>16;
2112 weaveZ = actor->special2&0xFFFF;
2113 angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
2114 newX = actor->x-FixedMul(finecosine[angle],
2115 FloatBobOffsets[weaveXY]<<2);
2116 newY = actor->y-FixedMul(finesine[angle],
2117 FloatBobOffsets[weaveXY]<<2);
2118 weaveXY = (weaveXY+(P_Random()%5))&63;
2119 newX += FixedMul(finecosine[angle],
2120 FloatBobOffsets[weaveXY]<<2);
2121 newY += FixedMul(finesine[angle],
2122 FloatBobOffsets[weaveXY]<<2);
2123 P_TryMove(actor, newX, newY);
2124 actor->z -= FloatBobOffsets[weaveZ]<<1;
2125 weaveZ = (weaveZ+(P_Random()%5))&63;
2126 actor->z += FloatBobOffsets[weaveZ]<<1;
2127 actor->special2 = weaveZ+(weaveXY<<16);
2130 //============================================================================
2134 //============================================================================
2136 void A_CHolySeek(mobj_t *actor)
2139 if(actor->health <= 0)
2144 P_SetMobjState(actor, actor->info->deathstate);
2145 actor->tics -= P_Random()&3;
2150 CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
2151 actor->args[0]*ANGLE_1*2);
2152 if(!((leveltime+7)&15))
2154 actor->args[0] = 5+(P_Random()/20);
2160 //============================================================================
2164 //============================================================================
2166 static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
2170 fixed_t oldDistance, newDistance;
2172 child = (mobj_t *)actor->special1;
2175 an = R_PointToAngle2(actor->x, actor->y, child->x,
2176 child->y)>>ANGLETOFINESHIFT;
2177 oldDistance = P_AproxDistance(child->x-actor->x, child->y-actor->y);
2178 if(P_TryMove(child, actor->x+FixedMul(dist, finecosine[an]),
2179 actor->y+FixedMul(dist, finesine[an])))
2181 newDistance = P_AproxDistance(child->x-actor->x,
2182 child->y-actor->y)-FRACUNIT;
2183 if(oldDistance < FRACUNIT)
2185 if(child->z < actor->z)
2187 child->z = actor->z-dist;
2191 child->z = actor->z+dist;
2196 child->z = actor->z+FixedMul(FixedDiv(newDistance,
2197 oldDistance), child->z-actor->z);
2200 CHolyTailFollow(child, dist-FRACUNIT);
2204 //============================================================================
2208 //============================================================================
2210 static void CHolyTailRemove(mobj_t *actor)
2214 child = (mobj_t *)actor->special1;
2217 CHolyTailRemove(child);
2219 P_RemoveMobj(actor);
2222 //============================================================================
2226 //============================================================================
2228 void A_CHolyTail(mobj_t *actor)
2232 parent = (mobj_t *)actor->special2;
2236 if(parent->state >= &states[parent->info->deathstate])
2237 { // Ghost removed, so remove all tail parts
2238 CHolyTailRemove(actor);
2241 else if(P_TryMove(actor, parent->x-FixedMul(14*FRACUNIT,
2242 finecosine[parent->angle>>ANGLETOFINESHIFT]),
2243 parent->y-FixedMul(14*FRACUNIT,
2244 finesine[parent->angle>>ANGLETOFINESHIFT])))
2246 actor->z = parent->z-5*FRACUNIT;
2248 CHolyTailFollow(actor, 10*FRACUNIT);
2251 //============================================================================
2253 // A_CHolyCheckScream
2255 //============================================================================
2257 void A_CHolyCheckScream(mobj_t *actor)
2262 S_StartSound(actor, SFX_SPIRIT_ACTIVE);
2264 if(!actor->special1)
2266 CHolyFindTarget(actor);
2270 //============================================================================
2274 //============================================================================
2276 void A_CHolySpawnPuff(mobj_t *actor)
2278 P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
2281 //----------------------------------------------------------------------------
2283 // PROC A_FireConePL1
2285 //----------------------------------------------------------------------------
2287 #define SHARDSPAWN_LEFT 1
2288 #define SHARDSPAWN_RIGHT 2
2289 #define SHARDSPAWN_UP 4
2290 #define SHARDSPAWN_DOWN 8
2292 void A_FireConePL1(player_t *player, pspdef_t *psp)
2302 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2303 S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
2305 damage = 90+(P_Random()&15);
2306 for(i = 0; i < 16; i++)
2308 angle = pmo->angle+i*(ANG45/16);
2309 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2312 pmo->flags2 |= MF2_ICEDAMAGE;
2313 P_DamageMobj(linetarget, pmo, pmo, damage);
2314 pmo->flags2 &= ~MF2_ICEDAMAGE;
2320 // didn't find any creatures, so fire projectiles
2323 mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
2326 mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
2328 mo->special2 = 3; // Set sperm count (levels of reproductivity)
2330 mo->args[0] = 3; // Mark Initial shard as super damage
2335 void A_ShedShard(mobj_t *actor)
2338 int spawndir = actor->special1;
2339 int spermcount = actor->special2;
2341 if (spermcount <= 0) return; // No sperm left
2342 actor->special2 = 0;
2345 // every so many calls, spawn a new missile in it's set directions
2346 if (spawndir & SHARDSPAWN_LEFT)
2348 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle+(ANG45/9),
2349 0, (20+2*spermcount)<<FRACBITS);
2352 mo->special1 = SHARDSPAWN_LEFT;
2353 mo->special2 = spermcount;
2354 mo->momz = actor->momz;
2355 mo->target = actor->target;
2356 mo->args[0] = (spermcount==3)?2:0;
2359 if (spawndir & SHARDSPAWN_RIGHT)
2361 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle-(ANG45/9),
2362 0, (20+2*spermcount)<<FRACBITS);
2365 mo->special1 = SHARDSPAWN_RIGHT;
2366 mo->special2 = spermcount;
2367 mo->momz = actor->momz;
2368 mo->target = actor->target;
2369 mo->args[0] = (spermcount==3)?2:0;
2372 if (spawndir & SHARDSPAWN_UP)
2374 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
2375 0, (15+2*spermcount)<<FRACBITS);
2378 mo->momz = actor->momz;
2379 mo->z += 8*FRACUNIT;
2380 if (spermcount & 1) // Every other reproduction
2381 mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
2383 mo->special1 = SHARDSPAWN_UP;
2384 mo->special2 = spermcount;
2385 mo->target = actor->target;
2386 mo->args[0] = (spermcount==3)?2:0;
2389 if (spawndir & SHARDSPAWN_DOWN)
2391 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
2392 0, (15+2*spermcount)<<FRACBITS);
2395 mo->momz = actor->momz;
2396 mo->z -= 4*FRACUNIT;
2397 if (spermcount & 1) // Every other reproduction
2398 mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
2400 mo->special1 = SHARDSPAWN_DOWN;
2401 mo->special2 = spermcount;
2402 mo->target = actor->target;
2403 mo->args[0] = (spermcount==3)?2:0;
2408 //----------------------------------------------------------------------------
2410 // PROC A_HideInCeiling
2412 //----------------------------------------------------------------------------
2415 void A_HideInCeiling(mobj_t *actor)
2417 actor->z = actor->ceilingz+4*FRACUNIT;
2421 //----------------------------------------------------------------------------
2425 //----------------------------------------------------------------------------
2428 void A_FloatPuff(mobj_t *puff)
2430 puff->momz += 1.8*FRACUNIT;
2434 void A_Light0(player_t *player, pspdef_t *psp)
2436 player->extralight = 0;
2440 void A_Light1(player_t *player, pspdef_t *psp)
2442 player->extralight = 1;
2447 void A_Light2(player_t *player, pspdef_t *psp)
2449 player->extralight = 2;
2453 //------------------------------------------------------------------------
2455 // PROC P_SetupPsprites
2457 // Called at start of level for each player
2459 //------------------------------------------------------------------------
2461 void P_SetupPsprites(player_t *player)
2465 // Remove all psprites
2466 for(i = 0; i < NUMPSPRITES; i++)
2468 player->psprites[i].state = NULL;
2470 // Spawn the ready weapon
2471 player->pendingweapon = player->readyweapon;
2472 P_BringUpWeapon(player);
2475 //------------------------------------------------------------------------
2477 // PROC P_MovePsprites
2479 // Called every tic by player thinking routine
2481 //------------------------------------------------------------------------
2483 void P_MovePsprites(player_t *player)
2489 psp = &player->psprites[0];
2490 for(i = 0; i < NUMPSPRITES; i++, psp++)
2492 if((state = psp->state) != 0) // a null state means not active
2494 // drop tic count and possibly change state
2495 if(psp->tics != -1) // a -1 tic count never changes
2500 P_SetPsprite(player, i, psp->state->nextstate);
2505 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
2506 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
2509 //============================================================================
2513 // Jim Cameron did most of this one
2514 //============================================================================
2516 void A_AKnifeAttack(player_t *player, pspdef_t *psp)
2521 mobj_t *pmo = player->mo;
2525 boolean oof = false;
2528 * jim - the Katar should be a bit feebler
2530 damage = 20+(P_Random()&15);
2532 PuffType = MT_PUNCHPUFF;
2534 for(i = 0; i < 16; i++)
2536 angle = pmo->angle+i*(ANG45/16);
2537 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2540 player->mo->special1++;
2542 * jim - this is the Mighty Blow for the fighter and is
2546 if(pmo->special1 == 3)
2550 PuffType = MT_HAMMERPUFF;
2554 * jim - instead of that we make the Katar deal more
2555 * damage to a monster if struck from behind. Assume
2556 * so if the angle of striking is within 45 degrees
2557 * of the angle the target is facing in
2558 * OOOPS! but only if it IS a monster! Striking trees from
2559 * behind might be amusing but doesn't do much for realism 8-)
2561 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2563 if ((angle - linetarget->angle < ANG45) ||
2564 (linetarget->angle - angle < ANG45))
2567 power = 6 * FRACUNIT;
2568 PuffType = MT_HAMMERPUFF;
2572 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2573 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2575 P_ThrustMobj(linetarget, angle, power);
2577 AdjustPlayerAngle(pmo);
2581 angle = pmo->angle-i*(ANG45/16);
2582 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2585 player->mo->special1++;
2587 * jim - this is the Mighty Blow for the fighter and is
2591 if(pmo->special1 == 3)
2595 PuffType = MT_HAMMERPUFF;
2599 * jim - instead of that we make the Katar deal more
2600 * damage to a monster if struck from behind. Assume
2601 * so if the angle of striking is within 45 degrees
2602 * of the angle the target is facing in
2603 * OOOPS! but only if it IS a monster! Striking trees from
2604 * behind might be amusing but doesn't do much for realism 8-)
2606 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2608 if ((angle - linetarget->angle < ANG45) ||
2609 (linetarget->angle - angle < ANG45))
2612 power = 6 * FRACUNIT;
2613 PuffType = MT_HAMMERPUFF;
2618 P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2619 if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2621 P_ThrustMobj(linetarget, angle, power);
2623 AdjustPlayerAngle(pmo);
2627 /* didn't find any creatures, so try to strike any walls*/
2631 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2632 P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
2638 P_SetPsprite(player, ps_weapon, S_KATARATK2_1);
2640 * jim - come on, she's a girl!
2642 S_StartSound(pmo, SFX_PLAYER_MAGE_GRUNT);
2647 void A_ACrossAttack(player_t *player, pspdef_t *psp)
2650 mobj_t *pmo = player->mo;
2652 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2653 // pmo = player->mo;
2654 // P_SpawnPlayerMissile(pmo, MT_CSTAFF_MISSILE);
2657 * jim - special2 is used to control the serpent staff projectiles'
2658 * `slither' and is not used here
2659 * We do however want to give crossbow missiles BlasterMobjThinker()s
2660 * instead of the ordinary ones because they are FAST.
2662 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle);
2665 /* mo->special2 = 16; */
2666 mo->thinker.function = P_BlasterMobjThinker;
2668 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle-(ANG45/10));
2671 /* mo->special2 = 32; */
2672 mo->thinker.function = P_BlasterMobjThinker;
2674 mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle+(ANG45/10));
2677 /* mo->special2 = 0; */
2678 mo->thinker.function = P_BlasterMobjThinker;
2680 S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
2684 void A_AGrenAttack(player_t *player, pspdef_t *psp)
2688 mo = P_SpawnMobj(player->mo->x, player->mo->y,
2689 player->mo->z-player->mo->floorclip+35*FRACUNIT,
2693 mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
2694 mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
2695 mo->z += player->lookdir<<(FRACBITS-4);
2696 P_ThrustMobj(mo, mo->angle, mo->info->speed);
2697 mo->momx += player->mo->momx>>1;
2698 mo->momy += player->mo->momy>>1;
2699 mo->target = player->mo;
2700 mo->tics -= P_Random()&3;
2701 P_CheckMissileSpawn(mo);
2705 void A_AStaffAttack(player_t *player, pspdef_t *psp)
2711 player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2712 player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
2718 #endif /* ASSASSIN */