osezer patch 001
[theoddone33/hhexen.git] / base / p_pspr.c
1
2 //**************************************************************************
3 //**
4 //** p_pspr.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #include "h2def.h"
16 #include "p_local.h"
17 #include "soundst.h"
18
19 // MACROS ------------------------------------------------------------------
20
21 #define LOWERSPEED FRACUNIT*6
22 #define RAISESPEED FRACUNIT*6
23 #define WEAPONBOTTOM 128*FRACUNIT
24 #define WEAPONTOP 32*FRACUNIT
25
26 // TYPES -------------------------------------------------------------------
27
28 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
29
30 extern void P_ExplodeMissile(mobj_t *mo);
31 extern void A_UnHideThing(mobj_t *actor);
32
33 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
34
35 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
36
37 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
38
39 extern fixed_t FloatBobOffsets[64];
40
41 // PUBLIC DATA DEFINITIONS -------------------------------------------------
42
43 fixed_t bulletslope;
44
45 weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] =
46 {
47         { // First Weapons
48                 { // Fighter First Weapon - Punch
49                         MANA_NONE,                      // mana
50                         S_PUNCHUP,                      // upstate
51                         S_PUNCHDOWN,            // downstate
52                         S_PUNCHREADY,           // readystate
53                         S_PUNCHATK1_1,          // atkstate
54                         S_PUNCHATK1_1,          // holdatkstate
55                         S_NULL                          // flashstate
56                 },
57                 { // Cleric First Weapon - Mace
58                         MANA_NONE,                      // mana
59                         S_CMACEUP,                      // upstate
60                         S_CMACEDOWN,            // downstate
61                         S_CMACEREADY,           // readystate
62                         S_CMACEATK_1,           // atkstate
63                         S_CMACEATK_1,           // holdatkstate
64                         S_NULL                          // flashstate
65                 },
66                 { // Mage First Weapon - Wand
67                         MANA_NONE,
68                         S_MWANDUP,
69                         S_MWANDDOWN,
70                         S_MWANDREADY,
71                         S_MWANDATK_1,
72                         S_MWANDATK_1,
73                         S_NULL
74                 },
75 #ifdef ASSASSIN
76                 { // Assassin - Katar
77                         MANA_NONE,
78                         S_KATARUP,
79                         S_KATARDOWN,
80                         S_KATARREADY,
81                         S_KATARATK1_1,
82                         S_KATARATK1_1,
83                         S_NULL
84                 },
85 #endif
86                 { // Pig - Snout
87                         MANA_NONE,                      // mana
88                         S_SNOUTUP,                      // upstate
89                         S_SNOUTDOWN,            // downstate
90                         S_SNOUTREADY,           // readystate
91                         S_SNOUTATK1,            // atkstate
92                         S_SNOUTATK1,            // holdatkstate
93                         S_NULL                          // flashstate
94                 }
95         },
96         { // Second Weapons
97                 { // Fighter - Axe
98                         MANA_NONE,                      // mana
99                         S_FAXEUP,                       // upstate
100                         S_FAXEDOWN,                     // downstate
101                         S_FAXEREADY,            // readystate
102                         S_FAXEATK_1,            // atkstate
103                         S_FAXEATK_1,            // holdatkstate
104                         S_NULL                          // flashstate
105                 },
106                 { // Cleric - Serpent Staff
107                         MANA_1,                 // mana
108                         S_CSTAFFUP,             // upstate
109                         S_CSTAFFDOWN,   // downstate
110                         S_CSTAFFREADY,  // readystate
111                         S_CSTAFFATK_1,  // atkstate
112                         S_CSTAFFATK_1,  // holdatkstate
113                         S_NULL                  // flashstate
114                 },
115                 { // Mage - Cone of shards
116                         MANA_1,                 // mana
117                         S_CONEUP,               // upstate
118                         S_CONEDOWN,             // downstate
119                         S_CONEREADY,    // readystate
120                         S_CONEATK1_1,   // atkstate
121                         S_CONEATK1_3,   // holdatkstate
122                         S_NULL                  // flashstate
123                 },
124 #ifdef ASSASSIN
125                 { // Assassin - Hand Crossbow
126                         MANA_1,
127                         S_ACROSSUP,
128                         S_ACROSSDOWN,
129                         S_ACROSSREADY,
130                         S_ACROSSATK_1,
131                         S_ACROSSATK_3,
132                         S_NULL
133                 },
134 #endif
135                 { // Pig - Snout
136                         MANA_NONE,                      // mana
137                         S_SNOUTUP,                      // upstate
138                         S_SNOUTDOWN,            // downstate
139                         S_SNOUTREADY,           // readystate
140                         S_SNOUTATK1,            // atkstate
141                         S_SNOUTATK1,            // holdatkstate
142                         S_NULL                          // flashstate
143                 }
144         },
145         { // Third Weapons
146                 { // Fighter - Hammer
147                         MANA_NONE,                      // mana
148                         S_FHAMMERUP,            // upstate
149                         S_FHAMMERDOWN,          // downstate
150                         S_FHAMMERREADY,         // readystate
151                         S_FHAMMERATK_1,         // atkstate
152                         S_FHAMMERATK_1,         // holdatkstate
153                         S_NULL                          // flashstate
154                 },
155                 { // Cleric - Flame Strike
156                         MANA_2,                         // mana
157                         S_CFLAMEUP,                     // upstate
158                         S_CFLAMEDOWN,           // downstate
159                         S_CFLAMEREADY1,         // readystate
160                         S_CFLAMEATK_1,          // atkstate
161                         S_CFLAMEATK_1,          // holdatkstate
162                         S_NULL                          // flashstate
163                 },
164                 { // Mage - Lightning
165                         MANA_2,         // mana
166                         S_MLIGHTNINGUP,         // upstate
167                         S_MLIGHTNINGDOWN,       // downstate
168                         S_MLIGHTNINGREADY,      // readystate
169                         S_MLIGHTNINGATK_1,      // atkstate
170                         S_MLIGHTNINGATK_1,      // holdatkstate
171                         S_NULL                          // flashstate
172                 },
173 #ifdef ASSASSIN
174                 { // Assassin - Grenades
175                         MANA_2,
176                         S_AGRENUP,
177                         S_AGRENDOWN,
178                         S_AGRENREADY,
179                         S_AGRENATK_1,
180                         S_AGRENATK_1,
181                         S_NULL
182                 },
183 #endif
184                 { // Pig - Snout
185                         MANA_NONE,                      // mana
186                         S_SNOUTUP,                      // upstate
187                         S_SNOUTDOWN,            // downstate
188                         S_SNOUTREADY,           // readystate
189                         S_SNOUTATK1,            // atkstate
190                         S_SNOUTATK1,            // holdatkstate
191                         S_NULL                          // flashstate
192                 }
193         },
194         { // Fourth Weapons
195                 { // Fighter - Rune Sword
196                         MANA_BOTH,                      // mana
197                         S_FSWORDUP,                     // upstate
198                         S_FSWORDDOWN,           // downstate
199                         S_FSWORDREADY,          // readystate
200                         S_FSWORDATK_1,          // atkstate
201                         S_FSWORDATK_1,          // holdatkstate
202                         S_NULL                          // flashstate
203                 },
204                 { // Cleric - Holy Symbol
205                         MANA_BOTH,                      // mana
206                         S_CHOLYUP,              // upstate
207                         S_CHOLYDOWN,            // downstate
208                         S_CHOLYREADY,           // readystate
209                         S_CHOLYATK_1,           // atkstate
210                         S_CHOLYATK_1,           // holdatkstate
211                         S_NULL                          // flashstate
212                 },
213                 { // Mage - Staff
214                         MANA_BOTH,              // mana
215                         S_MSTAFFUP,             // upstate
216                         S_MSTAFFDOWN,           // downstate
217                         S_MSTAFFREADY,          // readystate
218                         S_MSTAFFATK_1,  // atkstate
219                         S_MSTAFFATK_1,  // holdatkstate
220                         S_NULL                          // flashstate
221                 },
222 #ifdef ASSASSIN
223                 { // Assassin - Staff of Set
224                         MANA_BOTH,
225                         S_ASTAFFUP,
226                         S_ASTAFFDOWN,
227                         S_ASTAFFREADY,
228                         S_ASTAFFATK_1,
229                         S_ASTAFFATK_1,
230                         S_NULL
231                 },
232 #endif
233                 { // Pig - Snout
234                         MANA_NONE,                      // mana
235                         S_SNOUTUP,                      // upstate
236                         S_SNOUTDOWN,            // downstate
237                         S_SNOUTREADY,           // readystate
238                         S_SNOUTATK1,            // atkstate
239                         S_SNOUTATK1,            // holdatkstate
240                         S_NULL                          // flashstate
241                 }
242         }
243 };
244
245 // PRIVATE DATA DEFINITIONS ------------------------------------------------
246
247 static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] = 
248 {
249         { 0, 2, 3, 14 },
250         { 0, 1, 4, 18 },
251         { 0, 3, 5, 15 },
252 #ifdef ASSASSIN
253         { 0, 3, 3, 1 },         // True to Hexen II
254 #endif
255         { 0, 0, 0, 0 }
256 };
257
258 // CODE --------------------------------------------------------------------
259
260 //---------------------------------------------------------------------------
261 //
262 // PROC P_SetPsprite
263 //
264 //---------------------------------------------------------------------------
265
266 void P_SetPsprite(player_t *player, int position, statenum_t stnum)
267 {
268         pspdef_t *psp;
269         state_t *state;
270
271         psp = &player->psprites[position];
272         do
273         {
274                 if(!stnum)
275                 { // Object removed itself.
276                         psp->state = NULL;
277                         break;
278                 }
279                 state = &states[stnum];
280                 psp->state = state;
281                 psp->tics = state->tics; // could be 0
282                 if(state->misc1)
283                 { // Set coordinates.
284                         psp->sx = state->misc1<<FRACBITS;
285                 }
286                 if(state->misc2)
287                 {
288                         psp->sy = state->misc2<<FRACBITS;
289                 }
290                 if(state->action)
291                 { // Call action routine.
292                         state->action(player, psp);
293                         if(!psp->state)
294                         {
295                                 break;
296                         }
297                 }
298                 stnum = psp->state->nextstate;
299         } while(!psp->tics); // An initial state of 0 could cycle through.
300 }
301
302 //---------------------------------------------------------------------------
303 //
304 // PROC P_SetPspriteNF
305 //
306 // Identical to P_SetPsprite, without calling the action function
307 //---------------------------------------------------------------------------
308
309 void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
310 {
311         pspdef_t *psp;
312         state_t *state;
313
314         psp = &player->psprites[position];
315         do
316         {
317                 if(!stnum)
318                 { // Object removed itself.
319                         psp->state = NULL;
320                         break;
321                 }
322                 state = &states[stnum];
323                 psp->state = state;
324                 psp->tics = state->tics; // could be 0
325                 if(state->misc1)
326                 { // Set coordinates.
327                         psp->sx = state->misc1<<FRACBITS;
328                 }
329                 if(state->misc2)
330                 {
331                         psp->sy = state->misc2<<FRACBITS;
332                 }
333                 stnum = psp->state->nextstate;
334         } while(!psp->tics); // An initial state of 0 could cycle through.
335 }
336
337 /*
338 =================
339 =
340 = P_CalcSwing
341 =
342 =================
343 */
344
345 /*
346 fixed_t swingx, swingy;
347 void P_CalcSwing (player_t *player)
348 {
349         fixed_t swing;
350         int             angle;
351
352 // OPTIMIZE: tablify this
353
354         swing = player->bob;
355
356         angle = (FINEANGLES/70*leveltime)&FINEMASK;
357         swingx = FixedMul ( swing, finesine[angle]);
358
359         angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
360         swingy = -FixedMul ( swingx, finesine[angle]);
361 }
362 */
363
364 //---------------------------------------------------------------------------
365 //
366 // PROC P_ActivateMorphWeapon
367 //
368 //---------------------------------------------------------------------------
369
370 void P_ActivateMorphWeapon(player_t *player)
371 {
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);
376 }
377
378
379 //---------------------------------------------------------------------------
380 //
381 // PROC P_PostMorphWeapon
382 //
383 //---------------------------------------------------------------------------
384
385 void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
386 {
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);
391 }
392
393 //---------------------------------------------------------------------------
394 //
395 // PROC P_BringUpWeapon
396 //
397 // Starts bringing the pending weapon up from the bottom of the screen.
398 //
399 //---------------------------------------------------------------------------
400
401 void P_BringUpWeapon(player_t *player)
402 {
403         statenum_t new;
404
405         if(player->pendingweapon == WP_NOCHANGE)
406         {
407                 player->pendingweapon = player->readyweapon;
408         }
409         if(player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
410         && player->mana[MANA_1])
411         {
412                 new = S_FAXEUP_G;
413         }
414         else
415         {
416                 new = WeaponInfo[player->pendingweapon][player->class].upstate;
417         }
418         player->pendingweapon = WP_NOCHANGE;
419         player->psprites[ps_weapon].sy = WEAPONBOTTOM;
420         P_SetPsprite(player, ps_weapon, new);
421 }
422
423 //---------------------------------------------------------------------------
424 //
425 // FUNC P_CheckMana
426 //
427 // Returns true if there is enough mana to shoot.  If not, selects the
428 // next weapon to use.
429 //
430 //---------------------------------------------------------------------------
431
432 boolean P_CheckMana(player_t *player)
433 {
434         manatype_t mana;
435         int count;
436
437         mana = WeaponInfo[player->readyweapon][player->class].mana;
438         count = WeaponManaUse[player->class][player->readyweapon];
439         if(mana == MANA_BOTH)
440         {
441                 if(player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
442                 {
443                         return true;
444                 }
445         }
446         else if(mana == MANA_NONE || player->mana[mana] >= count)
447         {
448                 return(true);
449         }
450         // out of mana, pick a weapon to change to
451         do
452         {
453                 if(player->weaponowned[WP_THIRD]
454                         && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD])
455                 {
456                         player->pendingweapon = WP_THIRD;
457                 }
458                 else if(player->weaponowned[WP_SECOND]
459                         && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_SECOND])
460                 {
461                         player->pendingweapon = WP_SECOND;
462                 }
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])
466                 {
467                         player->pendingweapon = WP_FOURTH;
468                 }
469                 else
470                 {
471                         player->pendingweapon = WP_FIRST;
472                 }
473         } while(player->pendingweapon == WP_NOCHANGE);
474         P_SetPsprite(player, ps_weapon,
475                 WeaponInfo[player->readyweapon][player->class].downstate);
476         return(false);
477 }
478
479 //---------------------------------------------------------------------------
480 //
481 // PROC P_FireWeapon
482 //
483 //---------------------------------------------------------------------------
484
485 void P_FireWeapon(player_t *player)
486 {
487         statenum_t attackState;
488
489         if(!P_CheckMana(player))
490         {
491                 return;
492         }
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)
496         { // Glowing axe
497                 attackState = S_FAXEATK_G1;
498         }
499         else
500         {
501                 attackState = player->refire ? 
502                         WeaponInfo[player->readyweapon][player->class].holdatkstate
503                         : WeaponInfo[player->readyweapon][player->class].atkstate;
504         }
505         P_SetPsprite(player, ps_weapon, attackState);
506         P_NoiseAlert(player->mo, player->mo);
507 }
508
509 //---------------------------------------------------------------------------
510 //
511 // PROC P_DropWeapon
512 //
513 // The player died, so put the weapon away.
514 //
515 //---------------------------------------------------------------------------
516
517 void P_DropWeapon(player_t *player)
518 {
519         P_SetPsprite(player, ps_weapon,
520                 WeaponInfo[player->readyweapon][player->class].downstate);
521 }
522
523 //---------------------------------------------------------------------------
524 //
525 // PROC A_WeaponReady
526 //
527 // The player can fire the weapon or change to another weapon at this time.
528 //
529 //---------------------------------------------------------------------------
530
531 void A_WeaponReady(player_t *player, pspdef_t *psp)
532 {
533         int angle;
534
535         // Change player from attack state
536         if(player->mo->state >= &states[PStateAttack[player->class]]
537                 && player->mo->state <= &states[PStateAttackEnd[player->class]])
538         {
539                 P_SetMobjState(player->mo, PStateNormal[player->class]);
540         }
541         // Put the weapon away if the player has a pending weapon or has
542         // died.
543         if(player->pendingweapon != WP_NOCHANGE || !player->health)
544         {
545                 P_SetPsprite(player, ps_weapon,
546                         WeaponInfo[player->readyweapon][player->class].downstate);
547                 return;
548         }
549
550         // Check for fire. 
551         if(player->cmd.buttons&BT_ATTACK)
552         {
553                 player->attackdown = true;
554                 P_FireWeapon(player);
555                 return;
556         }
557         else
558         {
559                 player->attackdown = false;
560         }
561
562         if(!player->morphTics)
563         {
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]);
569         }
570 }
571
572 //---------------------------------------------------------------------------
573 //
574 // PROC A_ReFire
575 //
576 // The player can re fire the weapon without lowering it entirely.
577 //
578 //---------------------------------------------------------------------------
579
580 void A_ReFire(player_t *player, pspdef_t *psp)
581 {
582         if((player->cmd.buttons&BT_ATTACK)
583                 && player->pendingweapon == WP_NOCHANGE && player->health)
584         {
585                 player->refire++;
586                 P_FireWeapon(player);
587         }
588         else
589         {
590                 player->refire = 0;
591                 P_CheckMana(player);
592         }
593 }
594
595 //---------------------------------------------------------------------------
596 //
597 // PROC A_Lower
598 //
599 //---------------------------------------------------------------------------
600
601 void A_Lower(player_t *player, pspdef_t *psp)
602 {
603         if(player->morphTics)
604         {
605                 psp->sy = WEAPONBOTTOM;
606         }
607         else
608         {
609                 psp->sy += LOWERSPEED;
610         }
611         if(psp->sy < WEAPONBOTTOM)
612         { // Not lowered all the way yet
613                 return;
614         }
615         if(player->playerstate == PST_DEAD)
616         { // Player is dead, so don't bring up a pending weapon
617                 psp->sy = WEAPONBOTTOM;
618                 return;
619         }
620         if(!player->health)
621         { // Player is dead, so keep the weapon off screen
622                 P_SetPsprite(player,  ps_weapon, S_NULL);
623                 return;
624         }
625         player->readyweapon = player->pendingweapon;
626         P_BringUpWeapon(player);
627 }
628
629 //---------------------------------------------------------------------------
630 //
631 // PROC A_Raise
632 //
633 //---------------------------------------------------------------------------
634
635 void A_Raise(player_t *player, pspdef_t *psp)
636 {
637         psp->sy -= RAISESPEED;
638         if(psp->sy > WEAPONTOP)
639         { // Not raised all the way yet
640                 return;
641         }
642         psp->sy = WEAPONTOP;
643         if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
644         && player->mana[MANA_1])
645         {
646                 P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
647         }
648         else
649         {       
650                 P_SetPsprite(player, ps_weapon,
651                         WeaponInfo[player->readyweapon][player->class].readystate);
652         }
653 }
654
655 /*
656 ===============
657 =
658 = P_BulletSlope
659 =
660 = Sets a slope so a near miss is at aproximately the height of the
661 = intended target
662 =
663 ===============
664 */
665
666 /*
667 void P_BulletSlope (mobj_t *mo)
668 {
669         angle_t         an;
670
671 //
672 // see which target is to be aimed at
673 //
674         an = mo->angle;
675         bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
676         if (!linetarget)
677         {
678                 an += 1<<26;
679                 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
680                 if (!linetarget)
681                 {
682                         an -= 2<<26;
683                         bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
684                 }
685                 if (!linetarget)
686                 {
687                         an += 1<<26;
688                         bulletslope = (mo->player->lookdir<<FRACBITS)/173;
689                 }
690         }
691 }
692 */
693
694 //****************************************************************************
695 //
696 // WEAPON ATTACKS
697 //
698 //****************************************************************************
699
700 //============================================================================
701 //
702 //      AdjustPlayerAngle
703 //
704 //============================================================================
705
706 #define MAX_ANGLE_ADJUST (5*ANGLE_1)
707
708 void AdjustPlayerAngle(mobj_t *pmo)
709 {
710         angle_t angle;
711         int difference;
712
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)
716         {
717                 pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
718         }
719         else
720         {
721                 pmo->angle = angle;
722         }
723 }
724
725 //============================================================================
726 //
727 // A_SnoutAttack
728 //
729 //============================================================================
730
731 void A_SnoutAttack(player_t *player, pspdef_t *psp)
732 {
733         angle_t angle;
734         int damage;
735         int slope;
736
737         damage = 3+(P_Random()&3);
738         angle = player->mo->angle;
739         slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
740         PuffType = MT_SNOUTPUFF;
741         PuffSpawned = NULL;
742         P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
743         S_StartSound(player->mo, SFX_PIG_ACTIVE1+(P_Random()&1));
744         if(linetarget)
745         {
746                 AdjustPlayerAngle(player->mo);
747 //              player->mo->angle = R_PointToAngle2(player->mo->x,
748 //                      player->mo->y, linetarget->x, linetarget->y);
749                 if(PuffSpawned)
750                 { // Bit something
751                         S_StartSound(player->mo, SFX_PIG_ATTACK);
752                 }
753         }
754 }
755
756 //============================================================================
757 //
758 // A_FHammerAttack
759 //
760 //============================================================================
761
762 #define HAMMER_RANGE    (MELEERANGE+MELEERANGE/2)
763
764 void A_FHammerAttack(player_t *player, pspdef_t *psp)
765 {
766         angle_t angle;
767         mobj_t *pmo=player->mo;
768         int damage;
769         fixed_t power;
770         int slope;
771         int i;
772
773         damage = 60+(P_Random()&63);
774         power = 10*FRACUNIT;
775         PuffType = MT_HAMMERPUFF;
776         for(i = 0; i < 16; i++)
777         {
778                 angle = pmo->angle+i*(ANG45/32);
779                 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
780                 if(linetarget)
781                 {
782                         P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
783                         AdjustPlayerAngle(pmo);
784                         if (linetarget->flags&MF_COUNTKILL || linetarget->player)
785                         {
786                                 P_ThrustMobj(linetarget, angle, power);
787                         }
788                         pmo->special1 = false; // Don't throw a hammer
789                         goto hammerdone;
790                 }
791                 angle = pmo->angle-i*(ANG45/32);
792                 slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
793                 if(linetarget)
794                 {
795                         P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
796                         AdjustPlayerAngle(pmo);
797                         if (linetarget->flags&MF_COUNTKILL || linetarget->player)
798                         {
799                                 P_ThrustMobj(linetarget, angle, power);
800                         }
801                         pmo->special1 = false; // Don't throw a hammer
802                         goto hammerdone;
803                 }
804         }
805         // didn't find any targets in meleerange, so set to throw out a hammer
806         PuffSpawned = NULL;
807         angle = pmo->angle;
808         slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
809         P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
810         if(PuffSpawned)
811         {
812                 pmo->special1 = false;
813         }
814         else
815         {
816                 pmo->special1 = true;
817         }
818 hammerdone:
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;
823         }
824         return;         
825 }
826
827 //============================================================================
828 //
829 // A_FHammerThrow
830 //
831 //============================================================================
832
833 void A_FHammerThrow(player_t *player, pspdef_t *psp)
834 {
835         mobj_t *mo;
836
837         if(!player->mo->special1)
838         {
839                 return;
840         }
841         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
842         mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE); 
843         if(mo)
844         {
845                 mo->special1 = 0;
846         }       
847 }
848
849 //============================================================================
850 //
851 // A_FSwordAttack
852 //
853 //============================================================================
854
855 void A_FSwordAttack(player_t *player, pspdef_t *psp)
856 {
857         mobj_t *pmo;
858
859         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
860         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
861         pmo = player->mo;
862         P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-10*FRACUNIT, MT_FSWORD_MISSILE, 
863                 pmo->angle+ANG45/4);
864         P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-5*FRACUNIT, MT_FSWORD_MISSILE, 
865                 pmo->angle+ANG45/8);
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, 
868                 pmo->angle-ANG45/8);
869         P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+10*FRACUNIT, MT_FSWORD_MISSILE, 
870                 pmo->angle-ANG45/4);
871         S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
872 }
873
874 //============================================================================
875 //
876 // A_FSwordAttack2
877 //
878 //============================================================================
879
880 void A_FSwordAttack2(mobj_t *actor)
881 {
882         angle_t angle = actor->angle;
883
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);
890 }
891
892 //============================================================================
893 //
894 // A_FSwordFlames
895 //
896 //============================================================================
897
898 void A_FSwordFlames(mobj_t *actor)
899 {
900         int i;
901
902         for(i = 1+(P_Random()&3); i; i--)
903         {
904                 P_SpawnMobj(actor->x+((P_Random()-128)<<12), actor->y
905                         +((P_Random()-128)<<12), actor->z+((P_Random()-128)<<11),
906                         MT_FSWORD_FLAME);
907         }
908 }
909
910 //============================================================================
911 //
912 // A_MWandAttack
913 //
914 //============================================================================
915
916 void A_MWandAttack(player_t *player, pspdef_t *psp)
917 {
918         mobj_t *mo;
919
920         mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
921         if(mo)
922         {
923                 mo->thinker.function = P_BlasterMobjThinker;
924         }
925         S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
926 }
927
928 // ===== Mage Lightning Weapon =====
929
930 //============================================================================
931 //
932 // A_LightningReady
933 //
934 //============================================================================
935
936 void A_LightningReady(player_t *player, pspdef_t *psp)
937 {
938         A_WeaponReady(player, psp);
939         if(P_Random() < 160)
940         {
941                 S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
942         }
943 }
944
945 //============================================================================
946 //
947 // A_LightningClip
948 //
949 //============================================================================
950
951 #define ZAGSPEED        FRACUNIT
952
953 void A_LightningClip(mobj_t *actor)
954 {
955         mobj_t *cMo;
956         mobj_t *target = NULL;  /* jim added initialiser */
957         int zigZag;
958
959         if(actor->type == MT_LIGHTNING_FLOOR)
960         {
961                 actor->z = actor->floorz;
962                 target = (mobj_t *)((mobj_t *)actor->special2)->special1;
963         }
964         else if(actor->type == MT_LIGHTNING_CEILING)
965         {
966                 actor->z = actor->ceilingz-actor->height;
967                 target = (mobj_t *)actor->special1;
968         }
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;
972                 zigZag = P_Random();
973                 if((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
974                 {
975                         P_ThrustMobj(actor, actor->angle+ANG90, ZAGSPEED);
976                         if(cMo)
977                         {
978                                 P_ThrustMobj(cMo, actor->angle+ANG90, ZAGSPEED);
979                         }
980                         actor->special1++;
981                 }
982                 else
983                 {
984                         P_ThrustMobj(actor, actor->angle-ANG90, ZAGSPEED);
985                         if(cMo)
986                         {
987                                 P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
988                         }
989                         actor->special1--;
990                 }
991         }
992         if(target)
993         {
994                 if(target->health <= 0)
995                 {
996                         P_ExplodeMissile(actor);
997                 }
998                 else
999                 {
1000                         actor->angle = R_PointToAngle2(actor->x, actor->y, target->x,
1001                                 target->y);
1002                         actor->momx = 0;
1003                         actor->momy = 0;
1004                         P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
1005                 }
1006         }
1007 }
1008
1009 //============================================================================
1010 //
1011 // A_LightningZap
1012 //
1013 //============================================================================
1014
1015 void A_LightningZap(mobj_t *actor)
1016 {
1017         mobj_t *mo;
1018         fixed_t deltaZ;
1019
1020         A_LightningClip(actor);
1021
1022         actor->health -= 8;
1023         if(actor->health <= 0)
1024         {
1025                 P_SetMobjState(actor, actor->info->deathstate);
1026                 return;
1027         }
1028         if(actor->type == MT_LIGHTNING_FLOOR)
1029         {
1030                 deltaZ = 10*FRACUNIT;
1031         }
1032         else
1033         {
1034                 deltaZ = -10*FRACUNIT;
1035         }
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);
1039         if(mo)
1040         {
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)
1046                 {
1047                         mo->momz = 20*FRACUNIT;
1048                 }
1049                 else 
1050                 {
1051                         mo->momz = -20*FRACUNIT;
1052                 }
1053         }
1054 /*
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);
1058         if(mo)
1059         {
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)
1065                 {
1066                         mo->momz = 16*FRACUNIT;
1067                 }
1068                 else 
1069                 {
1070                         mo->momz = -16*FRACUNIT;
1071                 }
1072         }
1073 */
1074         if(actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
1075         {
1076                 S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
1077         }
1078 }
1079
1080 //============================================================================
1081 //
1082 // A_MLightningAttack2
1083 //
1084 //============================================================================
1085
1086 void A_MLightningAttack2(mobj_t *actor)
1087 {
1088         mobj_t *fmo, *cmo;
1089
1090         fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
1091         cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
1092         if(fmo)
1093         {
1094                 fmo->special1 = 0;
1095                 fmo->special2 = (int)cmo;
1096                 A_LightningZap(fmo);    
1097         }
1098         if(cmo)
1099         {
1100                 cmo->special1 = 0;      // mobj that it will track
1101                 cmo->special2 = (int)fmo;
1102                 A_LightningZap(cmo);    
1103         }
1104         S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
1105 }
1106
1107 //============================================================================
1108 //
1109 // A_MLightningAttack
1110 //
1111 //============================================================================
1112
1113 void A_MLightningAttack(player_t *player, pspdef_t *psp)
1114 {
1115         A_MLightningAttack2(player->mo);
1116         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1117 }
1118
1119 //============================================================================
1120 //
1121 // A_ZapMimic
1122 //
1123 //============================================================================
1124
1125 void A_ZapMimic(mobj_t *actor)
1126 {
1127         mobj_t *mo;
1128
1129         mo = (mobj_t *)actor->special2;
1130         if(mo)
1131         {
1132                 if(mo->state >= &states[mo->info->deathstate]
1133                         || mo->state == &states[S_FREETARGMOBJ])
1134                 {
1135                         P_ExplodeMissile(actor);
1136                 }
1137                 else
1138                 {
1139                         actor->momx = mo->momx;
1140                         actor->momy = mo->momy;
1141                 }
1142         }
1143 }
1144
1145 //============================================================================
1146 //
1147 // A_LastZap
1148 //
1149 //============================================================================
1150
1151 void A_LastZap(mobj_t *actor)
1152 {
1153         mobj_t *mo;
1154
1155         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
1156         if(mo)
1157         {
1158                 P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
1159                 mo->momz = 40*FRACUNIT;
1160         }
1161 }
1162
1163 //============================================================================
1164 //
1165 // A_LightningRemove
1166 //
1167 //============================================================================
1168
1169 void A_LightningRemove(mobj_t *actor)
1170 {
1171         mobj_t *mo;
1172
1173         mo = (mobj_t *)actor->special2;
1174         if(mo)
1175         {
1176                 mo->special2 = 0;
1177                 P_ExplodeMissile(mo);
1178         }
1179 }
1180
1181
1182 //============================================================================
1183 //
1184 // MStaffSpawn
1185 //
1186 //============================================================================
1187 void MStaffSpawn(mobj_t *pmo, angle_t angle)
1188 {
1189         mobj_t *mo;
1190
1191         mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
1192         if (mo)
1193         {
1194                 mo->target = pmo;
1195                 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1196         }
1197 }
1198
1199 //============================================================================
1200 //
1201 // A_MStaffAttack
1202 //
1203 //============================================================================
1204
1205 void A_MStaffAttack(player_t *player, pspdef_t *psp)
1206 {
1207         angle_t angle;
1208         mobj_t *pmo;
1209
1210         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1211         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1212         pmo = player->mo;
1213         angle = pmo->angle;
1214         
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])
1220         {
1221                 player->damagecount = 0;
1222                 player->bonuscount = 0;
1223                 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1224                         PU_CACHE)+STARTSCOURGEPAL*768);
1225         }
1226 }
1227
1228 //============================================================================
1229 //
1230 // A_MStaffPalette
1231 //
1232 //============================================================================
1233
1234 void A_MStaffPalette(player_t *player, pspdef_t *psp)
1235 {
1236         int pal;
1237
1238         if(player == &players[consoleplayer])
1239         {
1240                 pal = STARTSCOURGEPAL+psp->state-(&states[S_MSTAFFATK_2]);
1241                 if(pal == STARTSCOURGEPAL+3)
1242                 { // reset back to original playpal
1243                         pal = 0;
1244                 }
1245                 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1246                         PU_CACHE)+pal*768);
1247         }
1248 }
1249
1250 //============================================================================
1251 //
1252 // A_MStaffWeave
1253 //
1254 //============================================================================
1255
1256 void A_MStaffWeave(mobj_t *actor)
1257 {
1258         fixed_t newX, newY;
1259         int weaveXY, weaveZ;
1260         int angle;
1261
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)
1279         {
1280                 actor->z = actor->floorz+FRACUNIT;
1281         }
1282         actor->special2 = weaveZ+(weaveXY<<16);
1283 }
1284
1285
1286 //============================================================================
1287 //
1288 // A_MStaffTrack
1289 //
1290 //============================================================================
1291
1292 void A_MStaffTrack(mobj_t *actor)
1293 {
1294         if ((actor->special1 == 0) && (P_Random()<50))
1295         {
1296                 actor->special1 = (int)P_RoughMonsterSearch(actor, 10);
1297         }
1298         P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
1299 }
1300
1301
1302 //============================================================================
1303 //
1304 // MStaffSpawn2 - for use by mage class boss
1305 //
1306 //============================================================================
1307
1308 void MStaffSpawn2(mobj_t *actor, angle_t angle)
1309 {
1310         mobj_t *mo;
1311
1312         mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
1313         if (mo)
1314         {
1315                 mo->target = actor;
1316                 mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
1317         }
1318 }
1319
1320 //============================================================================
1321 //
1322 // A_MStaffAttack2 - for use by mage class boss
1323 //
1324 //============================================================================
1325
1326 void A_MStaffAttack2(mobj_t *actor)
1327 {
1328         angle_t angle;
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);
1334 }
1335
1336 //============================================================================
1337 //
1338 // A_FPunchAttack
1339 //
1340 //============================================================================
1341
1342 void A_FPunchAttack(player_t *player, pspdef_t *psp)
1343 {
1344         angle_t angle;
1345         int damage;
1346         int slope;
1347         mobj_t *pmo = player->mo;
1348         fixed_t power;
1349         int i;
1350
1351         damage = 40+(P_Random()&15);
1352         power = 2*FRACUNIT;
1353         PuffType = MT_PUNCHPUFF;
1354         for(i = 0; i < 16; i++)
1355         {
1356                 angle = pmo->angle+i*(ANG45/16);
1357                 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1358                 if(linetarget)
1359                 {
1360                         player->mo->special1++;
1361                         if(pmo->special1 == 3)
1362                         {
1363                                 damage <<= 1;
1364                                 power = 6*FRACUNIT;
1365                                 PuffType = MT_HAMMERPUFF;
1366                         }
1367                         P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1368                         if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1369                         {
1370                                 P_ThrustMobj(linetarget, angle, power);
1371                         }
1372                         AdjustPlayerAngle(pmo);
1373                         goto punchdone;
1374                 }
1375                 angle = pmo->angle-i*(ANG45/16);
1376                 slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
1377                 if(linetarget)
1378                 {
1379                         pmo->special1++;
1380                         if(pmo->special1 == 3)
1381                         {
1382                                 damage <<= 1;
1383                                 power = 6*FRACUNIT;
1384                                 PuffType = MT_HAMMERPUFF;
1385                         }
1386                         P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
1387                         if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1388                         {
1389                                 P_ThrustMobj(linetarget, angle, power);
1390                         }
1391                         AdjustPlayerAngle(pmo);
1392                         goto punchdone;
1393                 }
1394         }
1395         // didn't find any creatures, so try to strike any walls
1396         pmo->special1 = 0;
1397
1398         angle = pmo->angle;
1399         slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1400         P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1401
1402 punchdone:
1403         if(pmo->special1 == 3)
1404         {
1405                 pmo->special1 = 0;
1406                 P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
1407                 S_StartSound(pmo, SFX_FIGHTER_GRUNT);
1408         }
1409         return;         
1410 }
1411
1412 //============================================================================
1413 //
1414 // A_FAxeAttack
1415 //
1416 //============================================================================
1417
1418 #define AXERANGE        2.25*MELEERANGE
1419
1420 void A_FAxeAttack(player_t *player, pspdef_t *psp)
1421 {
1422         angle_t angle;
1423         mobj_t *pmo=player->mo;
1424         fixed_t power;
1425         int damage;
1426         int slope;
1427         int i;
1428         int useMana;
1429
1430         damage = 40+(P_Random()&15)+(P_Random()&7);
1431         power = 0;
1432         if(player->mana[MANA_1] > 0)
1433         {
1434                 damage <<= 1;
1435                 power = 6*FRACUNIT;
1436                 PuffType = MT_AXEPUFF_GLOW;
1437                 useMana = 1;
1438         }
1439         else
1440         {
1441                 PuffType = MT_AXEPUFF;
1442                 useMana = 0;
1443         }
1444         for(i = 0; i < 16; i++)
1445         {
1446                 angle = pmo->angle+i*(ANG45/16);
1447                 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1448                 if(linetarget)
1449                 {
1450                         P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1451                         if (linetarget->flags&MF_COUNTKILL || linetarget->player)
1452                         {
1453                                 P_ThrustMobj(linetarget, angle, power);
1454                         }
1455                         AdjustPlayerAngle(pmo);
1456                         useMana++; 
1457                         goto axedone;
1458                 }
1459                 angle = pmo->angle-i*(ANG45/16);
1460                 slope = P_AimLineAttack(pmo, angle, AXERANGE);
1461                 if(linetarget)
1462                 {
1463                         P_LineAttack(pmo, angle, AXERANGE, slope, damage);
1464                         if (linetarget->flags&MF_COUNTKILL)
1465                         {
1466                                 P_ThrustMobj(linetarget, angle, power);
1467                         }
1468                         AdjustPlayerAngle(pmo);
1469                         useMana++; 
1470                         goto axedone;
1471                 }
1472         }
1473         // didn't find any creatures, so try to strike any walls
1474         pmo->special1 = 0;
1475
1476         angle = pmo->angle;
1477         slope = P_AimLineAttack(pmo, angle, MELEERANGE);
1478         P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
1479
1480 axedone:
1481         if(useMana == 2)
1482         {
1483                 player->mana[MANA_1] -= 
1484                         WeaponManaUse[player->class][player->readyweapon];
1485                 if(player->mana[MANA_1] <= 0)
1486                 {
1487                         P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
1488                 }
1489         }
1490         return;         
1491 }
1492
1493 //===========================================================================
1494 //
1495 // A_CMaceAttack
1496 //
1497 //===========================================================================
1498
1499 void A_CMaceAttack(player_t *player, pspdef_t *psp)
1500 {
1501         angle_t angle;
1502         int damage;
1503         int slope;
1504         int i;
1505
1506         damage = 25+(P_Random()&15);
1507         PuffType = MT_HAMMERPUFF;
1508         for(i = 0; i < 16; i++)
1509         {
1510                 angle = player->mo->angle+i*(ANG45/16);
1511                 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1512                 if(linetarget)
1513                 {
1514                         P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, 
1515                                 damage);
1516                         AdjustPlayerAngle(player->mo);
1517 //                      player->mo->angle = R_PointToAngle2(player->mo->x,
1518 //                              player->mo->y, linetarget->x, linetarget->y);
1519                         goto macedone;
1520                 }
1521                 angle = player->mo->angle-i*(ANG45/16);
1522                 slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
1523                 if(linetarget)
1524                 {
1525                         P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, 
1526                                 damage);
1527                         AdjustPlayerAngle(player->mo);
1528 //                      player->mo->angle = R_PointToAngle2(player->mo->x,
1529 //                              player->mo->y, linetarget->x, linetarget->y);
1530                         goto macedone;
1531                 }
1532         }
1533         // didn't find any creatures, so try to strike any walls
1534         player->mo->special1 = 0;
1535
1536         angle = player->mo->angle;
1537         slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
1538         P_LineAttack(player->mo, angle, MELEERANGE, slope, 
1539                 damage);
1540 macedone:
1541         return;         
1542 }
1543
1544 //============================================================================
1545 //
1546 // A_CStaffCheck
1547 //
1548 //============================================================================
1549
1550 void A_CStaffCheck(player_t *player, pspdef_t *psp)
1551 {
1552         mobj_t *pmo;
1553         int damage;
1554         int newLife;
1555         angle_t angle;
1556         int slope;
1557         int i;
1558
1559         pmo = player->mo;
1560         damage = 20+(P_Random()&15);
1561         PuffType = MT_CSTAFFPUFF;
1562         for(i = 0; i < 3; i++)
1563         {
1564                 angle = pmo->angle+i*(ANG45/16);
1565                 slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
1566                 if(linetarget)
1567                 {
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))))
1573                         {
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);
1578                         }
1579                         player->mana[MANA_1] -= 
1580                                 WeaponManaUse[player->class][player->readyweapon];
1581                         break;
1582                 }
1583                 angle = pmo->angle-i*(ANG45/16);
1584                 slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
1585                 if(linetarget)
1586                 {
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)
1591                         {
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);
1596                         }
1597                         player->mana[MANA_1] -= 
1598                                 WeaponManaUse[player->class][player->readyweapon];
1599                         break;
1600                 }
1601         }
1602 }
1603
1604 //============================================================================
1605 //
1606 // A_CStaffAttack
1607 //
1608 //============================================================================
1609
1610 void A_CStaffAttack(player_t *player, pspdef_t *psp)
1611 {
1612         mobj_t *mo;
1613         mobj_t *pmo;
1614
1615         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
1616         pmo = player->mo;
1617         mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle-(ANG45/15));
1618         if(mo)
1619         {
1620                 mo->special2 = 32;
1621         }
1622         mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle+(ANG45/15));
1623         if(mo)
1624         {
1625                 mo->special2 = 0;
1626         }
1627         S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
1628 }
1629
1630 //============================================================================
1631 //
1632 // A_CStaffMissileSlither
1633 //
1634 //============================================================================
1635
1636 void A_CStaffMissileSlither(mobj_t *actor)
1637 {
1638         fixed_t newX, newY;
1639         int weaveXY;
1640         int angle;
1641
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;      
1655 }
1656
1657 //============================================================================
1658 //
1659 // A_CStaffInitBlink
1660 //
1661 //============================================================================
1662
1663 void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
1664 {
1665         player->mo->special1 = (P_Random()>>1)+20;
1666 }
1667
1668 //============================================================================
1669 //
1670 // A_CStaffCheckBlink
1671 //
1672 //============================================================================
1673
1674 void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
1675 {
1676         if(!--player->mo->special1)
1677         {
1678                 P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
1679                 player->mo->special1 = (P_Random()+50)>>2;
1680         }
1681 }
1682
1683 //============================================================================
1684 //
1685 // A_CFlameAttack
1686 //
1687 //============================================================================
1688
1689 #define FLAMESPEED      (0.45*FRACUNIT)
1690 #define CFLAMERANGE     (12*64*FRACUNIT)
1691
1692 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1693 {
1694         mobj_t *mo;
1695
1696         mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
1697         if(mo)
1698         {
1699                 mo->thinker.function = P_BlasterMobjThinker;
1700                 mo->special1 = 2;
1701         }
1702
1703         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1704         S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1705 }
1706
1707 //============================================================================
1708 //
1709 // A_CFlamePuff
1710 //
1711 //============================================================================
1712
1713 void A_CFlamePuff(mobj_t *actor)
1714 {
1715         A_UnHideThing(actor);
1716         actor->momx = 0;
1717         actor->momy = 0;
1718         actor->momz = 0;
1719         S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
1720 }
1721
1722 //============================================================================
1723 //
1724 // A_CFlameMissile
1725 //
1726 //============================================================================
1727
1728 void A_CFlameMissile(mobj_t *actor)
1729 {
1730         int i;
1731         int an, an90;
1732         fixed_t dist;
1733         mobj_t *mo;
1734         
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++)
1741                 {
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);
1747                         if(mo)
1748                         {
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;
1754                         }
1755                         mo = P_SpawnMobj(BlockingMobj->x-FixedMul(dist, finecosine[an]),
1756                                 BlockingMobj->y-FixedMul(dist, finesine[an]), 
1757                                 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
1758                         if(mo)
1759                         {
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;
1765                         }
1766                 }
1767                 P_SetMobjState(actor, S_FLAMEPUFF2_1);
1768         }
1769 }
1770
1771 /*
1772 void A_CFlameAttack(player_t *player, pspdef_t *psp)
1773 {
1774         mobj_t *pmo;
1775         angle_t angle;
1776         int damage;
1777         int i;
1778         int an, an90;
1779         fixed_t dist;
1780         mobj_t *mo;
1781
1782         pmo = player->mo;
1783         P_BulletSlope(pmo);
1784         damage = 25+HITDICE(3);
1785         angle = pmo->angle;
1786         if(player->refire)
1787         {
1788                 angle += (P_Random()-P_Random())<<17;
1789         }
1790         P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
1791         if(!linetarget)
1792         {
1793                 angle += ANGLE_1*2;
1794                 P_AimLineAttack(pmo, angle, CFLAMERANGE);
1795                 if(!linetarget)
1796                 {
1797                         angle -= ANGLE_1*4;
1798                         P_AimLineAttack(pmo, angle, CFLAMERANGE);
1799                         if(!linetarget)
1800                         {
1801                                 angle += ANGLE_1*2;
1802                         }
1803                 }               
1804         }
1805         if(linetarget)
1806         {
1807                 PuffType = MT_FLAMEPUFF2;
1808         }
1809         else
1810         {
1811                 PuffType = MT_FLAMEPUFF;
1812         }
1813         P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
1814         if(linetarget)
1815         { // Hit something, so spawn the flame circle around the thing
1816                 dist = linetarget->radius+18*FRACUNIT;
1817                 for(i = 0; i < 4; i++)
1818                 {
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);
1824                         if(mo)
1825                         {
1826                                 mo->angle = an<<ANGLETOFINESHIFT;
1827                                 mo->target = pmo;
1828                                 mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
1829                                 mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
1830                                 mo->tics -= P_Random()&3;
1831                         }
1832                         mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]),
1833                                 linetarget->y-FixedMul(dist, finesine[an]), 
1834                                 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
1835                         if(mo)
1836                         {
1837                                 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
1838                                 mo->target = pmo;
1839                                 mo->momx = mo->special1 = FixedMul(-FLAMESPEED, 
1840                                         finecosine[an]);
1841                                 mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
1842                                 mo->tics -= P_Random()&3;
1843                         }
1844                 }
1845         }
1846 // Create a line of flames from the player to the flame puff
1847         CFlameCreateFlames(player->mo);
1848
1849         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
1850         S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
1851 }
1852 */
1853
1854 //============================================================================
1855 //
1856 // A_CFlameRotate
1857 //
1858 //============================================================================
1859
1860 #define FLAMEROTSPEED   2*FRACUNIT
1861
1862 void A_CFlameRotate(mobj_t *actor)
1863 {
1864         int an;
1865
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;
1870 }
1871
1872
1873 //============================================================================
1874 //
1875 // A_CHolyAttack3
1876 //
1877 //      Spawns the spirits
1878 //============================================================================
1879
1880 void A_CHolyAttack3(mobj_t *actor)
1881 {
1882         P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
1883         S_StartSound(actor, SFX_CHOLY_FIRE);
1884 }
1885
1886
1887 //============================================================================
1888 //
1889 // A_CHolyAttack2 
1890 //
1891 //      Spawns the spirits
1892 //============================================================================
1893
1894 void A_CHolyAttack2(mobj_t *actor)
1895 {
1896         int j;
1897         int i;
1898         mobj_t *mo;
1899         mobj_t *tail, *next;
1900
1901         for(j = 0; j < 4; j++)
1902         {
1903                 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
1904                 if(!mo)
1905                 {
1906                         continue;
1907                 }
1908                 switch(j)
1909                 { // float bob index
1910                         case 0:
1911                                 mo->special2 = P_Random()&7; // upper-left
1912                                 break;
1913                         case 1:
1914                                 mo->special2 = 32+(P_Random()&7); // upper-right
1915                                 break;
1916                         case 2:
1917                                 mo->special2 = (32+(P_Random()&7))<<16; // lower-left
1918                                 break;
1919                         case 3:
1920                                 mo->special2 = ((32+(P_Random()&7))<<16)+32+(P_Random()&7);
1921                                 break;
1922                 }
1923                 mo->z = actor->z;
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
1929                 if(deathmatch)
1930                 { // Ghosts last slightly less longer in DeathMatch
1931                         mo->health = 85;
1932                 }
1933                 if(linetarget)
1934                 {
1935                         mo->special1 = (int)linetarget;
1936                         mo->flags |= MF_NOCLIP|MF_SKULLFLY;
1937                         mo->flags &= ~MF_MISSILE;
1938                 }
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++)
1942                 {
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;
1946                         tail = next;
1947                 }
1948                 tail->special1 = 0; // last tail bit
1949         }
1950 }
1951
1952 //============================================================================
1953 //
1954 // A_CHolyAttack
1955 //
1956 //============================================================================
1957
1958 void A_CHolyAttack(player_t *player, pspdef_t *psp)
1959 {
1960         mobj_t *mo;
1961
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])
1966         {
1967                 player->damagecount = 0;
1968                 player->bonuscount = 0;
1969                 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1970                         PU_CACHE)+STARTHOLYPAL*768);
1971         }
1972         S_StartSound(player->mo, SFX_CHOLY_FIRE);
1973 }
1974
1975 //============================================================================
1976 //
1977 // A_CHolyPalette
1978 //
1979 //============================================================================
1980
1981 void A_CHolyPalette(player_t *player, pspdef_t *psp)
1982 {
1983         int pal;
1984
1985         if(player == &players[consoleplayer])
1986         {
1987                 pal = STARTHOLYPAL+psp->state-(&states[S_CHOLYATK_6]);
1988                 if(pal == STARTHOLYPAL+3)
1989                 { // reset back to original playpal
1990                         pal = 0;
1991                 }
1992                 I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
1993                         PU_CACHE)+pal*768);
1994         }
1995 }
1996
1997 //============================================================================
1998 //
1999 // CHolyFindTarget
2000 //
2001 //============================================================================
2002
2003 static void CHolyFindTarget(mobj_t *actor)
2004 {
2005   /* jim changed to avoid single = in if() */
2006 /*      mobj_t *target; */
2007
2008 /*      if(target = P_RoughMonsterSearch(actor, 6)) */
2009
2010         mobj_t *target = P_RoughMonsterSearch (actor, 6);
2011
2012         if(target != NULL)
2013         {
2014                 actor->special1 = (int)target;
2015                 actor->flags |= MF_NOCLIP|MF_SKULLFLY;
2016                 actor->flags &= ~MF_MISSILE;
2017         }
2018 }
2019
2020 //============================================================================
2021 //
2022 // CHolySeekerMissile
2023 //
2024 //       Similar to P_SeekerMissile, but seeks to a random Z on the target
2025 //============================================================================
2026
2027 static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
2028 {
2029         int dir;
2030         int dist;
2031         angle_t delta;
2032         angle_t angle;
2033         mobj_t *target;
2034         fixed_t newZ;
2035         fixed_t deltaZ;
2036
2037         target = (mobj_t *)actor->special1;
2038         if(target == NULL)
2039         {
2040                 return;
2041         }
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);
2049                 return;
2050         }
2051         dir = P_FaceMobj(actor, target, &delta);
2052         if(delta > thresh)
2053         {
2054                 delta >>= 1;
2055                 if(delta > turnMax)
2056                 {
2057                         delta = turnMax;
2058                 }
2059         }
2060         if(dir)
2061         { // Turn clockwise
2062                 actor->angle += delta;
2063         }
2064         else
2065         { // Turn counter clockwise
2066                 actor->angle -= delta;
2067         }
2068         angle = actor->angle>>ANGLETOFINESHIFT;
2069         actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
2070         actor->momy = FixedMul(actor->info->speed, finesine[angle]);
2071         if(!(leveltime&15) 
2072                 || actor->z > target->z+(target->height)
2073                 || actor->z+actor->height < target->z)
2074         {
2075                 newZ = target->z+((P_Random()*target->height)>>8);
2076                 deltaZ = newZ-actor->z;
2077                 if(abs(deltaZ) > 15*FRACUNIT)
2078                 {
2079                         if(deltaZ > 0)
2080                         {
2081                                 deltaZ = 15*FRACUNIT;
2082                         }
2083                         else
2084                         {
2085                                 deltaZ = -15*FRACUNIT;
2086                         }
2087                 }
2088                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
2089                 dist = dist/actor->info->speed;
2090                 if(dist < 1)
2091                 {
2092                         dist = 1;
2093                 }
2094                 actor->momz = deltaZ/dist;
2095         }
2096         return;
2097 }
2098
2099 //============================================================================
2100 //
2101 // A_CHolyWeave
2102 //
2103 //============================================================================
2104
2105 static void CHolyWeave(mobj_t *actor)
2106 {
2107         fixed_t newX, newY;
2108         int weaveXY, weaveZ;
2109         int angle;
2110
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);
2128 }
2129
2130 //============================================================================
2131 //
2132 // A_CHolySeek
2133 //
2134 //============================================================================
2135
2136 void A_CHolySeek(mobj_t *actor)
2137 {
2138         actor->health--;
2139         if(actor->health <= 0)
2140         {
2141                 actor->momx >>= 2;
2142                 actor->momy >>= 2;
2143                 actor->momz = 0;
2144                 P_SetMobjState(actor, actor->info->deathstate);
2145                 actor->tics -= P_Random()&3;
2146                 return;
2147         }
2148         if(actor->special1)
2149         {
2150                 CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
2151                         actor->args[0]*ANGLE_1*2);
2152                 if(!((leveltime+7)&15))
2153                 {
2154                         actor->args[0] = 5+(P_Random()/20);
2155                 }
2156         }
2157         CHolyWeave(actor);
2158 }
2159
2160 //============================================================================
2161 //
2162 // CHolyTailFollow
2163 //
2164 //============================================================================
2165
2166 static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
2167 {
2168         mobj_t *child;
2169         int an;
2170         fixed_t oldDistance, newDistance;
2171
2172         child = (mobj_t *)actor->special1;
2173         if(child)
2174         {
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])))
2180                 {
2181                         newDistance = P_AproxDistance(child->x-actor->x, 
2182                                 child->y-actor->y)-FRACUNIT;
2183                         if(oldDistance < FRACUNIT)
2184                         {
2185                                 if(child->z < actor->z)
2186                                 {
2187                                         child->z = actor->z-dist;
2188                                 }
2189                                 else
2190                                 {
2191                                         child->z = actor->z+dist;
2192                                 }
2193                         }
2194                         else
2195                         {
2196                                 child->z = actor->z+FixedMul(FixedDiv(newDistance, 
2197                                         oldDistance), child->z-actor->z);
2198                         }
2199                 }
2200                 CHolyTailFollow(child, dist-FRACUNIT);
2201         }
2202 }
2203
2204 //============================================================================
2205 //
2206 // CHolyTailRemove
2207 //
2208 //============================================================================
2209
2210 static void CHolyTailRemove(mobj_t *actor)
2211 {
2212         mobj_t *child;
2213
2214         child = (mobj_t *)actor->special1;
2215         if(child)
2216         {
2217                 CHolyTailRemove(child);
2218         }
2219         P_RemoveMobj(actor);
2220 }
2221
2222 //============================================================================
2223 //
2224 // A_CHolyTail
2225 //
2226 //============================================================================
2227
2228 void A_CHolyTail(mobj_t *actor)
2229 {
2230         mobj_t *parent;
2231
2232         parent = (mobj_t *)actor->special2;
2233
2234         if(parent)
2235         {
2236                 if(parent->state >= &states[parent->info->deathstate])
2237                 { // Ghost removed, so remove all tail parts
2238                         CHolyTailRemove(actor);
2239                         return;
2240                 }
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])))
2245                 {
2246                         actor->z = parent->z-5*FRACUNIT;
2247                 }
2248                 CHolyTailFollow(actor, 10*FRACUNIT);
2249         }
2250 }
2251 //============================================================================
2252 //
2253 // A_CHolyCheckScream
2254 //
2255 //============================================================================
2256
2257 void A_CHolyCheckScream(mobj_t *actor)
2258 {
2259         A_CHolySeek(actor);
2260         if(P_Random() < 20)
2261         {
2262                 S_StartSound(actor, SFX_SPIRIT_ACTIVE);
2263         }
2264         if(!actor->special1)
2265         {
2266                 CHolyFindTarget(actor);
2267         }
2268 }
2269
2270 //============================================================================
2271 //
2272 // A_CHolySpawnPuff
2273 //
2274 //============================================================================
2275
2276 void A_CHolySpawnPuff(mobj_t *actor)
2277 {
2278         P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
2279 }
2280
2281 //----------------------------------------------------------------------------
2282 //
2283 // PROC A_FireConePL1
2284 //
2285 //----------------------------------------------------------------------------
2286
2287 #define SHARDSPAWN_LEFT         1
2288 #define SHARDSPAWN_RIGHT        2
2289 #define SHARDSPAWN_UP           4
2290 #define SHARDSPAWN_DOWN         8
2291
2292 void A_FireConePL1(player_t *player, pspdef_t *psp)
2293 {
2294         angle_t angle;
2295         int damage;
2296         int slope;
2297         int i;
2298         mobj_t *pmo,*mo;
2299         int conedone=false;
2300
2301         pmo = player->mo;
2302         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2303         S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
2304
2305         damage = 90+(P_Random()&15);
2306         for(i = 0; i < 16; i++)
2307         {
2308                 angle = pmo->angle+i*(ANG45/16);
2309                 slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2310                 if(linetarget)
2311                 {
2312                         pmo->flags2 |= MF2_ICEDAMAGE;
2313                         P_DamageMobj(linetarget, pmo, pmo, damage);
2314                         pmo->flags2 &= ~MF2_ICEDAMAGE;
2315                         conedone = true;
2316                         break;
2317                 }
2318         }
2319
2320         // didn't find any creatures, so fire projectiles
2321         if (!conedone)
2322         {
2323                 mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
2324                 if (mo)
2325                 {
2326                         mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
2327                                 |SHARDSPAWN_RIGHT;
2328                         mo->special2 = 3; // Set sperm count (levels of reproductivity)
2329                         mo->target = pmo;
2330                         mo->args[0] = 3;                // Mark Initial shard as super damage
2331                 }
2332         }
2333 }
2334
2335 void A_ShedShard(mobj_t *actor)
2336 {
2337         mobj_t *mo;
2338         int spawndir = actor->special1;
2339         int spermcount = actor->special2;
2340
2341         if (spermcount <= 0) return;                            // No sperm left
2342         actor->special2 = 0;
2343         spermcount--;
2344
2345         // every so many calls, spawn a new missile in it's set directions
2346         if (spawndir & SHARDSPAWN_LEFT)
2347         {
2348                 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle+(ANG45/9),
2349                                                                                          0, (20+2*spermcount)<<FRACBITS);
2350                 if (mo)
2351                 {
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;
2357                 }
2358         }
2359         if (spawndir & SHARDSPAWN_RIGHT)
2360         {
2361                 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle-(ANG45/9),
2362                                                                                          0, (20+2*spermcount)<<FRACBITS);
2363                 if (mo)
2364                 {
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;
2370                 }
2371         }
2372         if (spawndir & SHARDSPAWN_UP)
2373         {
2374                 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 
2375                                                                                          0, (15+2*spermcount)<<FRACBITS);
2376                 if (mo)
2377                 {
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;
2382                         else
2383                                 mo->special1 = SHARDSPAWN_UP;
2384                         mo->special2 = spermcount;
2385                         mo->target = actor->target;
2386                         mo->args[0] = (spermcount==3)?2:0;
2387                 }
2388         }
2389         if (spawndir & SHARDSPAWN_DOWN)
2390         {
2391                 mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 
2392                                                                                          0, (15+2*spermcount)<<FRACBITS);
2393                 if (mo)
2394                 {
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;
2399                         else
2400                                 mo->special1 = SHARDSPAWN_DOWN;
2401                         mo->special2 = spermcount;
2402                         mo->target = actor->target;
2403                         mo->args[0] = (spermcount==3)?2:0;
2404                 }
2405         }
2406 }
2407
2408 //----------------------------------------------------------------------------
2409 //
2410 // PROC A_HideInCeiling
2411 //
2412 //----------------------------------------------------------------------------
2413
2414 /*
2415 void A_HideInCeiling(mobj_t *actor)
2416 {
2417         actor->z = actor->ceilingz+4*FRACUNIT;
2418 }
2419 */
2420
2421 //----------------------------------------------------------------------------
2422 //
2423 // PROC A_FloatPuff
2424 //
2425 //----------------------------------------------------------------------------
2426
2427 /*
2428 void A_FloatPuff(mobj_t *puff)
2429 {
2430         puff->momz += 1.8*FRACUNIT;
2431 }
2432 */
2433
2434 void A_Light0(player_t *player, pspdef_t *psp)
2435 {
2436         player->extralight = 0;
2437 }
2438
2439 /*
2440 void A_Light1(player_t *player, pspdef_t *psp)
2441 {
2442         player->extralight = 1;
2443 }
2444 */
2445
2446 /*
2447 void A_Light2(player_t *player, pspdef_t *psp)
2448 {
2449         player->extralight = 2;
2450 }
2451 */
2452
2453 //------------------------------------------------------------------------
2454 //
2455 // PROC P_SetupPsprites
2456 //
2457 // Called at start of level for each player
2458 //
2459 //------------------------------------------------------------------------
2460
2461 void P_SetupPsprites(player_t *player)
2462 {
2463         int i;
2464
2465         // Remove all psprites
2466         for(i = 0; i < NUMPSPRITES; i++)
2467         {
2468                 player->psprites[i].state = NULL;
2469         }
2470         // Spawn the ready weapon
2471         player->pendingweapon = player->readyweapon;
2472         P_BringUpWeapon(player);
2473 }
2474
2475 //------------------------------------------------------------------------
2476 //
2477 // PROC P_MovePsprites
2478 //
2479 // Called every tic by player thinking routine
2480 //
2481 //------------------------------------------------------------------------
2482
2483 void P_MovePsprites(player_t *player)
2484 {
2485         int i;
2486         pspdef_t *psp;
2487         state_t *state;
2488
2489         psp = &player->psprites[0];
2490         for(i = 0; i < NUMPSPRITES; i++, psp++)
2491         {
2492                 if((state = psp->state) != 0) // a null state means not active
2493                 {
2494                         // drop tic count and possibly change state
2495                         if(psp->tics != -1)     // a -1 tic count never changes
2496                         {
2497                                 psp->tics--;
2498                                 if(!psp->tics)
2499                                 {
2500                                         P_SetPsprite(player, i, psp->state->nextstate);
2501                                 }
2502                         }
2503                 }
2504         }
2505         player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
2506         player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
2507 }
2508
2509 //============================================================================
2510 //
2511 // A_AKnifeAttack
2512 //
2513 // Jim Cameron did most of this one
2514 //============================================================================
2515 #ifdef ASSASSIN
2516 void A_AKnifeAttack(player_t *player, pspdef_t *psp)
2517 {
2518  angle_t angle;
2519  int damage;
2520  int slope;
2521  mobj_t *pmo = player->mo;
2522  fixed_t power;
2523  int i;
2524
2525  boolean oof = false;
2526
2527  /*
2528  * jim - the Katar should be a bit feebler
2529  */
2530  damage = 20+(P_Random()&15);
2531  power = 2*FRACUNIT;
2532  PuffType = MT_PUNCHPUFF;
2533
2534          for(i = 0; i < 16; i++)
2535  {
2536          angle = pmo->angle+i*(ANG45/16);
2537          slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2538          if(linetarget)
2539          {
2540                  player->mo->special1++;
2541                  /*
2542                  * jim - this is the Mighty Blow for the fighter and is
2543                  *  not useful here
2544                  */
2545 #if 0
2546                  if(pmo->special1 == 3)
2547                  {
2548                          damage <<= 1;
2549                          power = 6*FRACUNIT;
2550                          PuffType = MT_HAMMERPUFF;
2551                  }
2552 #endif
2553                  /*
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-)
2560                  */
2561                  if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2562                  {
2563                   if ((angle - linetarget->angle < ANG45) ||
2564                        (linetarget->angle - angle < ANG45))
2565                   {
2566                    damage *= 15;
2567                    power = 6 * FRACUNIT;
2568                    PuffType = MT_HAMMERPUFF;
2569                    oof = true;
2570                   }
2571                  }
2572                  P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2573                  if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2574                  {
2575                          P_ThrustMobj(linetarget, angle, power);
2576                  }
2577                  AdjustPlayerAngle(pmo);
2578                  goto knifedone;
2579          }
2580
2581          angle = pmo->angle-i*(ANG45/16);
2582          slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
2583          if(linetarget)
2584          {
2585                  player->mo->special1++;
2586                  /*
2587                  * jim - this is the Mighty Blow for the fighter and is
2588                  *  not useful here
2589                  */
2590 #if 0
2591                  if(pmo->special1 == 3)
2592                  {
2593                          damage <<= 1;
2594                          power = 6*FRACUNIT;
2595                          PuffType = MT_HAMMERPUFF;
2596                  }
2597 #endif
2598                  /*
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-)
2605                  */
2606                  if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2607                  {
2608                   if ((angle - linetarget->angle < ANG45) ||
2609                        (linetarget->angle - angle < ANG45))
2610                   {
2611                    damage *= 15;
2612                    power = 6 * FRACUNIT;
2613                    PuffType = MT_HAMMERPUFF;
2614                    oof = true;
2615                   }
2616                  }
2617
2618                  P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
2619                  if (linetarget->flags&MF_COUNTKILL || linetarget->player)
2620                  {
2621                          P_ThrustMobj(linetarget, angle, power);
2622                  }
2623                  AdjustPlayerAngle(pmo);
2624                  goto knifedone;
2625          }
2626  }
2627  /* didn't find any creatures, so try to strike any walls*/
2628  pmo->special1 = 0;
2629
2630  angle = pmo->angle;
2631  slope = P_AimLineAttack(pmo, angle, MELEERANGE);
2632  P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
2633
2634 knifedone:
2635  if (oof)
2636  {
2637          pmo->special1 = 0;
2638          P_SetPsprite(player, ps_weapon, S_KATARATK2_1);
2639          /*
2640          * jim - come on, she's a girl!
2641          */
2642          S_StartSound(pmo, SFX_PLAYER_MAGE_GRUNT);
2643  }
2644  return;                 
2645 }
2646
2647 void A_ACrossAttack(player_t *player, pspdef_t *psp)
2648 {
2649         mobj_t *mo;
2650         mobj_t *pmo = player->mo;
2651
2652         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2653 //      pmo = player->mo;
2654 //      P_SpawnPlayerMissile(pmo, MT_CSTAFF_MISSILE);
2655
2656         /*
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.
2661         */
2662         mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle);
2663         if(mo)
2664         {
2665 /*             mo->special2 = 16; */
2666          mo->thinker.function = P_BlasterMobjThinker;
2667         }
2668         mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle-(ANG45/10));
2669         if(mo)
2670         {
2671 /*             mo->special2 = 32; */
2672          mo->thinker.function = P_BlasterMobjThinker;
2673         }
2674         mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle+(ANG45/10));
2675         if(mo)
2676         {
2677 /*             mo->special2 = 0; */
2678          mo->thinker.function = P_BlasterMobjThinker;
2679         }
2680         S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
2681 }
2682
2683
2684 void A_AGrenAttack(player_t *player, pspdef_t *psp)
2685 {
2686         mobj_t *mo;
2687
2688         mo = P_SpawnMobj(player->mo->x, player->mo->y, 
2689                         player->mo->z-player->mo->floorclip+35*FRACUNIT,
2690                         MT_THROWINGBOMB);
2691                 if(mo)
2692                 {
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);                                                                                        
2702                 }
2703 }
2704
2705 void A_AStaffAttack(player_t *player, pspdef_t *psp)
2706 {
2707         angle_t angle;
2708         mobj_t *pmo;
2709
2710
2711         player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
2712         player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
2713
2714         pmo = player->mo;
2715         angle = pmo->angle;
2716
2717 }
2718 #endif  /* ASSASSIN */
2719