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