]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_enemy.c
osezer patch 007
[theoddone33/hhexen.git] / base / p_enemy.c
1
2 //**************************************************************************
3 //**
4 //** p_enemy.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 #include "h2def.h"
14 #include "p_local.h"
15 #include "soundst.h"
16
17 // Macros
18 // Types
19 // Private Data
20 // External Data
21 extern fixed_t FloatBobOffsets[64];
22
23
24 //----------------------------------------------------------------------------
25 //
26 // PROC P_RecursiveSound
27 //
28 //----------------------------------------------------------------------------
29
30 mobj_t *soundtarget;
31
32 void P_RecursiveSound(sector_t *sec, int soundblocks)
33 {
34         int i;
35         line_t *check;
36         sector_t *other;
37
38         // Wake up all monsters in this sector
39         if(sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
40         { // Already flooded
41                 return;
42         }
43         sec->validcount = validcount;
44         sec->soundtraversed = soundblocks+1;
45         sec->soundtarget = soundtarget;
46         for(i = 0; i < sec->linecount; i++)
47         {
48                 check = sec->lines[i];
49                 if(!(check->flags&ML_TWOSIDED))
50                 {
51                         continue;
52                 }
53                 P_LineOpening(check);
54                 if(openrange <= 0)
55                 { // Closed door
56                         continue;
57                 }
58                 if(sides[check->sidenum[0]].sector == sec)
59                 {
60                         other = sides[check->sidenum[1]].sector;
61                 }
62                 else
63                 {
64                         other = sides[check->sidenum[0]].sector;
65                 }
66                 if(check->flags&ML_SOUNDBLOCK)
67                 {
68                         if(!soundblocks)
69                         {
70                                 P_RecursiveSound(other, 1);
71                         }
72                 }
73                 else
74                 {
75                         P_RecursiveSound(other, soundblocks);
76                 }
77         }
78 }
79
80 //----------------------------------------------------------------------------
81 //
82 // PROC P_NoiseAlert
83 //
84 // If a monster yells at a player, it will alert other monsters to the
85 // player.
86 //
87 //----------------------------------------------------------------------------
88
89 void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
90 {
91         soundtarget = target;
92         validcount++;
93         P_RecursiveSound(emmiter->subsector->sector, 0);
94 }
95
96 //----------------------------------------------------------------------------
97 //
98 // FUNC P_CheckMeleeRange
99 //
100 //----------------------------------------------------------------------------
101
102 boolean P_CheckMeleeRange(mobj_t *actor)
103 {
104         mobj_t *mo;
105         fixed_t dist;
106
107         if(!actor->target)
108         {
109                 return(false);
110         }
111         mo = actor->target;
112         dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y);
113         if(dist >= MELEERANGE)
114         {
115                 return(false);
116         }
117         if(!P_CheckSight(actor, mo))
118         {
119                 return(false);
120         }
121         if(mo->z > actor->z+actor->height)
122         { // Target is higher than the attacker
123                 return(false);
124         }
125         else if(actor->z > mo->z+mo->height)
126         { // Attacker is higher
127                 return(false);
128         }
129         return(true);
130 }
131
132 //----------------------------------------------------------------------------
133 //
134 // FUNC P_CheckMeleeRange2
135 //
136 //----------------------------------------------------------------------------
137
138 boolean P_CheckMeleeRange2(mobj_t *actor)
139 {
140         mobj_t *mo;
141         fixed_t dist;
142
143         if(!actor->target)
144         {
145                 return(false);
146         }
147         mo = actor->target;
148         dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y);
149         if(dist >= MELEERANGE*2 || dist < MELEERANGE)
150         {
151                 return(false);
152         }
153         if(!P_CheckSight(actor, mo))
154         {
155                 return(false);
156         }
157         if(mo->z > actor->z+actor->height)
158         { // Target is higher than the attacker
159                 return(false);
160         }
161         else if(actor->z > mo->z+mo->height)
162         { // Attacker is higher
163                 return(false);
164         }
165         return(true);
166 }
167
168 //----------------------------------------------------------------------------
169 //
170 // FUNC P_CheckMissileRange
171 //
172 //----------------------------------------------------------------------------
173
174 boolean P_CheckMissileRange(mobj_t *actor)
175 {
176         fixed_t dist;
177
178         if(!P_CheckSight(actor, actor->target))
179         {
180                 return(false);
181         }
182         if(actor->flags&MF_JUSTHIT)
183         { // The target just hit the enemy, so fight back!
184                 actor->flags &= ~MF_JUSTHIT;
185                 return(true);
186         }
187         if(actor->reactiontime)
188         { // Don't attack yet
189                 return(false);
190         }
191         dist = (P_AproxDistance(actor->x-actor->target->x,
192                 actor->y-actor->target->y)>>FRACBITS)-64;
193         if(!actor->info->meleestate)
194         { // No melee attack, so fire more frequently
195                 dist -= 128;
196         }
197         if(dist > 200)
198         {
199                 dist = 200;
200         }
201         if(P_Random() < dist)
202         {
203                 return(false);
204         }
205         return(true);
206 }
207
208 /*
209 ================
210 =
211 = P_Move
212 =
213 = Move in the current direction
214 = returns false if the move is blocked
215 ================
216 */
217
218 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
219 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
220
221 #define MAXSPECIALCROSS         8
222 extern  line_t  *spechit[MAXSPECIALCROSS];
223 extern  int                      numspechit;
224
225 boolean P_Move(mobj_t *actor)
226 {
227         fixed_t tryx, tryy;
228         line_t *ld;
229         boolean good;
230
231         if(actor->flags2&MF2_BLASTED) return(true);
232         if(actor->movedir == DI_NODIR)
233         {
234                 return(false);
235         }
236         tryx = actor->x+actor->info->speed*xspeed[actor->movedir];
237         tryy = actor->y+actor->info->speed*yspeed[actor->movedir];
238         if(!P_TryMove(actor, tryx, tryy))
239         { // open any specials
240                 if(actor->flags&MF_FLOAT && floatok)
241                 { // must adjust height
242                         if(actor->z < tmfloorz)
243                         {
244                                 actor->z += FLOATSPEED;
245                         }
246                         else
247                         {
248                                 actor->z -= FLOATSPEED;
249                         }
250                         actor->flags |= MF_INFLOAT;
251                         return(true);
252                 }
253                 if(!numspechit)
254                 {
255                         return false;
256                 }
257                 actor->movedir = DI_NODIR;
258                 good = false;
259                 while(numspechit--)
260                 {
261                         ld = spechit[numspechit];
262                         // if the special isn't a door that can be opened, return false
263                         if(P_ActivateLine(ld, actor, 0, SPAC_USE))
264                         {
265                                 good = true;
266                         }
267 /* Old version before use/cross/impact specials were combined
268                         if(P_UseSpecialLine(actor, ld))
269                         {
270                                 good = true;
271                         }
272 */
273                 }
274                 return(good);
275         }
276         else
277         {
278                 actor->flags &= ~MF_INFLOAT;
279         }
280         if(!(actor->flags&MF_FLOAT))
281         {
282                 if(actor->z > actor->floorz)
283                 {
284                         P_HitFloor(actor);
285                 }
286                 actor->z = actor->floorz;
287         }
288         return(true);
289 }
290
291 //----------------------------------------------------------------------------
292 //
293 // FUNC P_TryWalk
294 //
295 // Attempts to move actor in its current (ob->moveangle) direction.
296 // If blocked by either a wall or an actor returns FALSE.
297 // If move is either clear of block only by a door, returns TRUE and sets.
298 // If a door is in the way, an OpenDoor call is made to start it opening.
299 //
300 //----------------------------------------------------------------------------
301
302 boolean P_TryWalk(mobj_t *actor)
303 {
304         if(!P_Move(actor))
305         {
306                 return(false);
307         }
308         actor->movecount = P_Random()&15;
309         return(true);
310 }
311
312 /*
313 ================
314 =
315 = P_NewChaseDir
316 =
317 ================
318 */
319
320 dirtype_t opposite[] =
321 {DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
322 DI_NORTH, DI_NORTHWEST, DI_NODIR};
323
324 dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST};
325
326 void P_NewChaseDir (mobj_t *actor)
327 {
328         fixed_t         deltax,deltay;
329         dirtype_t       d[3];
330         dirtype_t       tdir, olddir, turnaround;
331
332         if (!actor->target)
333                 I_Error ("P_NewChaseDir: called with no target");
334
335         olddir = actor->movedir;
336         turnaround=opposite[olddir];
337
338         deltax = actor->target->x - actor->x;
339         deltay = actor->target->y - actor->y;
340         if (deltax>10*FRACUNIT)
341                 d[1]= DI_EAST;
342         else if (deltax<-10*FRACUNIT)
343                 d[1]= DI_WEST;
344         else
345                 d[1]=DI_NODIR;
346         if (deltay<-10*FRACUNIT)
347                 d[2]= DI_SOUTH;
348         else if (deltay>10*FRACUNIT)
349                 d[2]= DI_NORTH;
350         else
351                 d[2]=DI_NODIR;
352
353 // try direct route
354         if (d[1] != DI_NODIR && d[2] != DI_NODIR)
355         {
356                 actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
357                 if (actor->movedir != turnaround && P_TryWalk(actor))
358                         return;
359         }
360
361 // try other directions
362         if (P_Random() > 200 ||  abs(deltay)>abs(deltax))
363         {
364                 tdir=d[1];
365                 d[1]=d[2];
366                 d[2]=tdir;
367         }
368
369         if (d[1]==turnaround)
370                 d[1]=DI_NODIR;
371         if (d[2]==turnaround)
372                 d[2]=DI_NODIR;
373
374         if (d[1]!=DI_NODIR)
375         {
376                 actor->movedir = d[1];
377                 if (P_TryWalk(actor))
378                         return;     /*either moved forward or attacked*/
379         }
380
381         if (d[2]!=DI_NODIR)
382         {
383                 actor->movedir =d[2];
384                 if (P_TryWalk(actor))
385                         return;
386         }
387
388 /* there is no direct path to the player, so pick another direction */
389
390         if (olddir!=DI_NODIR)
391         {
392                 actor->movedir =olddir;
393                 if (P_TryWalk(actor))
394                         return;
395         }
396
397         if (P_Random()&1)       /*randomly determine direction of search*/
398         {
399                 for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++)
400                 {
401                         if (tdir!=turnaround)
402                         {
403                                 actor->movedir =tdir;
404                                 if ( P_TryWalk(actor) )
405                                         return;
406                         }
407                 }
408         }
409         else
410         {
411                 for (tdir=DI_SOUTHEAST ; (int)tdir >= DI_EAST;tdir--)
412                 {
413                         if (tdir!=turnaround)
414                         {
415                                 actor->movedir =tdir;
416                                 if ( P_TryWalk(actor) )
417                                 return;
418                         }
419                 }
420         }
421
422         if (turnaround !=  DI_NODIR)
423         {
424                 actor->movedir =turnaround;
425                 if ( P_TryWalk(actor) )
426                         return;
427         }
428
429         actor->movedir = DI_NODIR;              // can't move
430 }
431
432 //---------------------------------------------------------------------------
433 //
434 // FUNC P_LookForMonsters
435 //
436 //---------------------------------------------------------------------------
437
438 #define MONS_LOOK_RANGE (16*64*FRACUNIT)
439 #define MONS_LOOK_LIMIT 64
440
441 boolean P_LookForMonsters(mobj_t *actor)
442 {
443         int count;
444         mobj_t *mo;
445         thinker_t *think;
446
447         if(!P_CheckSight(players[0].mo, actor))
448         { // Player can't see monster
449                 return(false);
450         }
451         count = 0;
452         for(think = thinkercap.next; think != &thinkercap; think = think->next)
453         {
454                 if(think->function != P_MobjThinker)
455                 { // Not a mobj thinker
456                         continue;
457                 }
458                 mo = (mobj_t *)think;
459                 if(!(mo->flags&MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
460                 { // Not a valid monster
461                         continue;
462                 }
463                 if(P_AproxDistance(actor->x-mo->x, actor->y-mo->y)
464                         > MONS_LOOK_RANGE)
465                 { // Out of range
466                         continue;
467                 }
468                 if(P_Random() < 16)
469                 { // Skip
470                         continue;
471                 }
472                 if(count++ > MONS_LOOK_LIMIT)
473                 { // Stop searching
474                         return(false);
475                 }
476                 if(!P_CheckSight(actor, mo))
477                 { // Out of sight
478                         continue;
479                 }
480                 if (actor->type == MT_MINOTAUR)
481                 {
482                         if ((mo->type == MT_MINOTAUR) && 
483                                  (mo->target != ((player_t *)actor->special1)->mo))
484                         {
485                                 continue;
486                         }
487                 }
488                 // Found a target monster
489                 actor->target = mo;
490                 return(true);
491         }
492         return(false);
493 }
494
495 /*
496 ================
497 =
498 = P_LookForPlayers
499 =
500 = If allaround is false, only look 180 degrees in front
501 = returns true if a player is targeted
502 ================
503 */
504
505 boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
506 {
507         int c;
508         int stop;
509         player_t *player;
510         sector_t *sector;
511         angle_t an;
512         fixed_t dist;
513
514         if(!netgame && players[0].health <= 0)
515         { // Single player game and player is dead, look for monsters
516                 return(P_LookForMonsters(actor));
517         }
518         sector = actor->subsector->sector;
519         c = 0;
520         stop = (actor->lastlook-1)&3;
521         for( ; ; actor->lastlook = (actor->lastlook+1)&3 )
522         {
523                 if (!playeringame[actor->lastlook])
524                         continue;
525
526                 if (c++ == 2 || actor->lastlook == stop)
527                         return false;           // done looking
528
529                 player = &players[actor->lastlook];
530                 if (player->health <= 0)
531                         continue;               // dead
532                 if (!P_CheckSight (actor, player->mo))
533                         continue;               // out of sight
534
535                 if (!allaround)
536                 {
537                         an = R_PointToAngle2 (actor->x, actor->y,
538                         player->mo->x, player->mo->y) - actor->angle;
539                         if (an > ANG90 && an < ANG270)
540                         {
541                                 dist = P_AproxDistance (player->mo->x - actor->x,
542                                         player->mo->y - actor->y);
543                                 // if real close, react anyway
544                                 if (dist > MELEERANGE)
545                                         continue;               // behind back
546                         }
547                 }
548                 if(player->mo->flags&MF_SHADOW)
549                 { // Player is invisible
550                         if((P_AproxDistance(player->mo->x-actor->x,
551                                 player->mo->y-actor->y) > 2*MELEERANGE)
552                                 && P_AproxDistance(player->mo->momx, player->mo->momy)
553                                 < 5*FRACUNIT)
554                         { // Player is sneaking - can't detect
555                                 return(false);
556                         }
557                         if(P_Random() < 225)
558                         { // Player isn't sneaking, but still didn't detect
559                                 return(false);
560                         }
561                 }
562                 if (actor->type == MT_MINOTAUR)
563                 {
564                         if(((player_t *)(actor->special1)) == player)
565                         {
566                                 continue;                       // Don't target master
567                         }
568                 }
569
570                 actor->target = player->mo;
571                 return(true);
572         }
573         return(false);
574 }
575
576 /*
577 ===============================================================================
578
579                                                 ACTION ROUTINES
580
581 ===============================================================================
582 */
583
584 /*
585 ==============
586 =
587 = A_Look
588 =
589 = Stay in state until a player is sighted
590 =
591 ==============
592 */
593
594 void A_Look (mobj_t *actor)
595 {
596         mobj_t          *targ;
597
598         actor->threshold = 0;           // any shot will wake up
599         targ = actor->subsector->sector->soundtarget;
600         if (targ && (targ->flags & MF_SHOOTABLE) )
601         {
602                 actor->target = targ;
603                 if ( actor->flags & MF_AMBUSH )
604                 {
605                         if (P_CheckSight (actor, actor->target))
606                                 goto seeyou;
607                 }
608                 else
609                         goto seeyou;
610         }
611
612
613         if (!P_LookForPlayers (actor, false) )
614                 return;
615
616 // go into chase state
617 seeyou:
618         if (actor->info->seesound)
619         {
620                 int             sound;
621
622                 sound = actor->info->seesound;
623                 if(actor->flags2&MF2_BOSS)
624                 { // Full volume
625                         S_StartSound(NULL, sound);
626                 }
627                 else
628                 {
629                         S_StartSound(actor, sound);
630                 }
631         }
632         P_SetMobjState(actor, actor->info->seestate);
633 }
634
635
636 /*
637 ==============
638 =
639 = A_Chase
640 =
641 = Actor has a melee attack, so it tries to close as fast as possible
642 =
643 ==============
644 */
645
646 void A_Chase(mobj_t *actor)
647 {
648         int delta;
649
650         if(actor->reactiontime)
651         {
652                 actor->reactiontime--;
653         }
654
655         // Modify target threshold
656         if(actor->threshold)
657         {
658                 actor->threshold--;
659         }
660
661         if(gameskill == sk_nightmare)
662         { // Monsters move faster in nightmare mode
663                 actor->tics -= actor->tics/2;
664                 if(actor->tics < 3)
665                 {
666                         actor->tics = 3;
667                 }
668         }
669
670 //
671 // turn towards movement direction if not there yet
672 //
673         if(actor->movedir < 8)
674         {
675                 actor->angle &= (7<<29);
676                 delta = actor->angle-(actor->movedir << 29);
677                 if(delta > 0)
678                 {
679                         actor->angle -= ANG90/2;
680                 }
681                 else if(delta < 0)
682                 {
683                         actor->angle += ANG90/2;
684                 }
685         }
686
687         if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
688         { // look for a new target
689                 if(P_LookForPlayers(actor, true))
690                 { // got a new target
691                         return;
692                 }
693                 P_SetMobjState(actor, actor->info->spawnstate);
694                 return;
695         }
696
697 //
698 // don't attack twice in a row
699 //
700         if(actor->flags & MF_JUSTATTACKED)
701         {
702                 actor->flags &= ~MF_JUSTATTACKED;
703                 if (gameskill != sk_nightmare)
704                         P_NewChaseDir (actor);
705                 return;
706         }
707
708 //
709 // check for melee attack
710 //
711         if (actor->info->meleestate && P_CheckMeleeRange (actor))
712         {
713                 if(actor->info->attacksound)
714                 {
715                         S_StartSound (actor, actor->info->attacksound);
716                 }
717                 P_SetMobjState (actor, actor->info->meleestate);
718                 return;
719         }
720
721 //
722 // check for missile attack
723 //
724         if (actor->info->missilestate)
725         {
726                 if (gameskill < sk_nightmare && actor->movecount)
727                         goto nomissile;
728                 if (!P_CheckMissileRange (actor))
729                         goto nomissile;
730                 P_SetMobjState (actor, actor->info->missilestate);
731                 actor->flags |= MF_JUSTATTACKED;
732                 return;
733         }
734 nomissile:
735
736 //
737 // possibly choose another target
738 //
739         if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
740         {
741                 if (P_LookForPlayers(actor,true))
742                         return;         // got a new target
743         }
744
745 //
746 // chase towards player
747 //
748         if (--actor->movecount<0 || !P_Move (actor))
749         {
750                 P_NewChaseDir (actor);
751         }
752
753 //
754 // make active sound
755 //
756         if(actor->info->activesound && P_Random() < 3)
757         {
758                 if(actor->type == MT_BISHOP && P_Random() < 128)
759                 {
760                         S_StartSound(actor, actor->info->seesound);
761                 }
762                 else if(actor->type == MT_PIG)
763                 {
764                         S_StartSound(actor, SFX_PIG_ACTIVE1+(P_Random()&1));
765                 }
766                 else if(actor->flags2&MF2_BOSS)
767                 {
768                         S_StartSound(NULL, actor->info->activesound);
769                 }
770                 else
771                 {
772                         S_StartSound(actor, actor->info->activesound);
773                 }
774         }
775 }
776
777 //----------------------------------------------------------------------------
778 //
779 // PROC A_FaceTarget
780 //
781 //----------------------------------------------------------------------------
782
783 void A_FaceTarget(mobj_t *actor)
784 {
785         if(!actor->target)
786         {
787                 return;
788         }
789         actor->flags &= ~MF_AMBUSH;
790         actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
791                 actor->target->y);
792         if(actor->target->flags&MF_SHADOW)
793         { // Target is a ghost
794                 actor->angle += (P_Random()-P_Random())<<21;
795         }
796 }
797
798 //----------------------------------------------------------------------------
799 //
800 // PROC A_Pain
801 //
802 //----------------------------------------------------------------------------
803
804 void A_Pain(mobj_t *actor)
805 {
806         if(actor->info->painsound)
807         {
808                 S_StartSound(actor, actor->info->painsound);
809         }
810 }
811
812 //============================================================================
813 //
814 // A_SetInvulnerable
815 //
816 //============================================================================
817
818 void A_SetInvulnerable(mobj_t *actor)
819 {
820         actor->flags2 |= MF2_INVULNERABLE;
821 }
822
823 //============================================================================
824 //
825 // A_UnSetInvulnerable
826 //
827 //============================================================================
828
829 void A_UnSetInvulnerable(mobj_t *actor)
830 {
831         actor->flags2 &= ~MF2_INVULNERABLE;
832 }
833
834 //============================================================================
835 //
836 // A_SetReflective
837 //
838 //============================================================================
839
840 void A_SetReflective(mobj_t *actor)
841 {
842         actor->flags2 |= MF2_REFLECTIVE;
843
844         if ((actor->type == MT_CENTAUR) ||
845                 (actor->type == MT_CENTAURLEADER))
846         {
847                 A_SetInvulnerable(actor);
848         }
849 }
850
851 //============================================================================
852 //
853 // A_UnSetReflective
854 //
855 //============================================================================
856
857 void A_UnSetReflective(mobj_t *actor)
858 {
859         actor->flags2 &= ~MF2_REFLECTIVE;
860
861         if ((actor->type == MT_CENTAUR) ||
862                 (actor->type == MT_CENTAURLEADER))
863         {
864                 A_UnSetInvulnerable(actor);
865         }
866 }
867
868
869 //----------------------------------------------------------------------------
870 //
871 // FUNC P_UpdateMorphedMonster
872 //
873 // Returns true if the pig morphs.
874 //
875 //----------------------------------------------------------------------------
876
877 boolean P_UpdateMorphedMonster(mobj_t *actor, int tics)
878 {
879         mobj_t *fog;
880         fixed_t x;
881         fixed_t y;
882         fixed_t z;
883         mobjtype_t moType;
884         mobj_t *mo;
885         mobj_t oldMonster;
886
887         actor->special1 -= tics;
888         if(actor->special1 > 0)
889         {
890                 return(false);
891         }
892         moType = actor->special2;
893         switch(moType)
894         {
895                 case MT_WRAITHB:                        // These must remain morphed
896                 case MT_SERPENT:
897                 case MT_SERPENTLEADER:
898                 case MT_MINOTAUR:
899                         return(false);
900                 default:
901                         break;
902         }
903         x = actor->x;
904         y = actor->y;
905         z = actor->z;
906         oldMonster = *actor;                    // Save pig vars
907
908         P_RemoveMobjFromTIDList(actor);
909         P_SetMobjState(actor, S_FREETARGMOBJ);
910         mo = P_SpawnMobj(x, y, z, moType);
911
912         if(P_TestMobjLocation(mo) == false)
913         { // Didn't fit
914                 P_RemoveMobj(mo);
915                 mo = P_SpawnMobj(x, y, z, oldMonster.type);
916                 mo->angle = oldMonster.angle;
917                 mo->flags = oldMonster.flags;
918                 mo->health = oldMonster.health;
919                 mo->target = oldMonster.target;
920                 mo->special = oldMonster.special;
921                 mo->special1 = 5*35; // Next try in 5 seconds
922                 mo->special2 = moType;
923                 mo->tid = oldMonster.tid;
924                 memcpy(mo->args, oldMonster.args, 5);
925                 P_InsertMobjIntoTIDList(mo, oldMonster.tid);
926                 return(false);
927         }
928         mo->angle = oldMonster.angle;
929         mo->target = oldMonster.target;
930         mo->tid = oldMonster.tid;
931         mo->special = oldMonster.special;
932         memcpy(mo->args, oldMonster.args, 5);
933         P_InsertMobjIntoTIDList(mo, oldMonster.tid);
934         fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
935         S_StartSound(fog, SFX_TELEPORT);
936         return(true);
937 }
938
939 //----------------------------------------------------------------------------
940 //
941 // PROC A_PigLook
942 //
943 //----------------------------------------------------------------------------
944
945 void A_PigLook(mobj_t *actor)
946 {
947         if(P_UpdateMorphedMonster(actor, 10))
948         {
949                 return;
950         }
951         A_Look(actor);
952 }
953
954 //----------------------------------------------------------------------------
955 //
956 // PROC A_PigChase
957 //
958 //----------------------------------------------------------------------------
959
960 void A_PigChase(mobj_t *actor)
961 {
962         if(P_UpdateMorphedMonster(actor, 3))
963         {
964                 return;
965         }
966         A_Chase(actor);
967 }
968
969 //============================================================================
970 //
971 // A_PigAttack
972 //
973 //============================================================================
974
975 void A_PigAttack(mobj_t *actor)
976 {
977         if(P_UpdateMorphedMonster(actor, 18))
978         {
979                 return;
980         }
981         if(!actor->target)
982         {
983                 return;
984         }
985         if(P_CheckMeleeRange(actor))
986         {
987                 P_DamageMobj(actor->target, actor, actor, 2+(P_Random()&1));
988                 S_StartSound(actor, SFX_PIG_ATTACK);
989         }
990 }
991
992 //============================================================================
993 //
994 // A_PigPain
995 //
996 //============================================================================
997
998 void A_PigPain(mobj_t *actor)
999 {
1000         A_Pain(actor);
1001         if(actor->z <= actor->floorz)
1002         {
1003                 actor->momz = 3.5*FRACUNIT;
1004         }
1005 }
1006
1007
1008
1009 void FaceMovementDirection(mobj_t *actor)
1010 {
1011         switch(actor->movedir)
1012         {
1013                 case DI_EAST:
1014                         actor->angle = 0<<24;
1015                         break;
1016                 case DI_NORTHEAST:
1017                         actor->angle = 32<<24;
1018                         break;
1019                 case DI_NORTH:
1020                         actor->angle = 64<<24;
1021                         break;
1022                 case DI_NORTHWEST:
1023                         actor->angle = 96<<24;
1024                         break;
1025                 case DI_WEST:
1026                         actor->angle = 128<<24;
1027                         break;
1028                 case DI_SOUTHWEST:
1029                         actor->angle = 160<<24;
1030                         break;
1031                 case DI_SOUTH:
1032                         actor->angle = 192<<24;
1033                         break;
1034                 case DI_SOUTHEAST:
1035                         actor->angle = 224<<24;
1036                         break;
1037         }
1038 }
1039
1040
1041 //----------------------------------------------------------------------------
1042 //
1043 // Minotaur variables
1044 //
1045 //      special1                pointer to player that spawned it (mobj_t)
1046 //      special2                internal to minotaur AI
1047 //      args[0]                 args[0]-args[3] together make up minotaur start time
1048 //      args[1]                 |
1049 //      args[2]                 |
1050 //      args[3]                 V
1051 //      args[4]                 charge duration countdown
1052 //----------------------------------------------------------------------------
1053
1054 void A_MinotaurFade0(mobj_t *actor)
1055 {
1056         actor->flags &= ~MF_ALTSHADOW;
1057         actor->flags |= MF_SHADOW;
1058 }
1059
1060 void A_MinotaurFade1(mobj_t *actor)
1061 {
1062         // Second level of transparency
1063         actor->flags &= ~MF_SHADOW;
1064         actor->flags |= MF_ALTSHADOW;
1065 }
1066
1067 void A_MinotaurFade2(mobj_t *actor)
1068 {
1069         // Make fully visible
1070         actor->flags &= ~MF_SHADOW;
1071         actor->flags &= ~MF_ALTSHADOW;
1072 }
1073
1074
1075 //----------------------------------------------------------------------------
1076 //
1077 // A_MinotaurRoam - 
1078 //
1079 // 
1080 //----------------------------------------------------------------------------
1081
1082 void A_MinotaurLook(mobj_t *actor);
1083
1084 void A_MinotaurRoam(mobj_t *actor)
1085 {
1086         unsigned int *starttime = (unsigned int *)actor->args;
1087
1088         actor->flags &= ~MF_SHADOW;                     // In case pain caused him to 
1089         actor->flags &= ~MF_ALTSHADOW;          // skip his fade in.
1090
1091         if ((leveltime - *starttime) >= MAULATORTICS)
1092         {
1093                 P_DamageMobj(actor,NULL,NULL,10000);
1094                 return;
1095         }
1096
1097         if (P_Random()<30)
1098                 A_MinotaurLook(actor);          // adjust to closest target
1099
1100         if (P_Random()<6)
1101         {
1102                 //Choose new direction
1103                 actor->movedir = P_Random() % 8;
1104                 FaceMovementDirection(actor);
1105         }
1106         if (!P_Move(actor))
1107         {
1108                 // Turn
1109                 if (P_Random() & 1)
1110                         actor->movedir = (++actor->movedir)%8;
1111                 else
1112                         actor->movedir = (actor->movedir+7)%8;
1113                 FaceMovementDirection(actor);
1114         }
1115 }
1116
1117
1118 //----------------------------------------------------------------------------
1119 //
1120 //      PROC A_MinotaurLook
1121 //
1122 // Look for enemy of player
1123 //----------------------------------------------------------------------------
1124 #define MINOTAUR_LOOK_DIST              (16*54*FRACUNIT)
1125
1126 void A_MinotaurLook(mobj_t *actor)
1127 {
1128         mobj_t *mo=NULL;
1129         player_t *player;
1130         thinker_t *think;
1131         fixed_t dist;
1132         int i;
1133         mobj_t *master = (mobj_t *)(actor->special1);
1134
1135         actor->target = NULL;
1136         if (deathmatch)                                 // Quick search for players
1137         {
1138         for (i=0; i<MAXPLAYERS; i++)
1139                 {
1140                         if (!playeringame[i]) continue;
1141                         player = &players[i];
1142                         mo = player->mo;
1143                         if (mo == master) continue;
1144                         if (mo->health <= 0) continue;
1145                         dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
1146                         if (dist > MINOTAUR_LOOK_DIST) continue;
1147                         actor->target = mo;
1148                         break;
1149                 }
1150         }
1151
1152         if (!actor->target)                             // Near player monster search
1153         {
1154                 if (master && (master->health>0) && (master->player))
1155                         mo = P_RoughMonsterSearch(master, 20);
1156                 else
1157                         mo = P_RoughMonsterSearch(actor, 20);
1158                 actor->target = mo;
1159         }
1160
1161         if (!actor->target)                             // Normal monster search
1162         {
1163                 for(think = thinkercap.next; think != &thinkercap; think = think->next)
1164                 {
1165                         if(think->function != P_MobjThinker) continue;
1166                         mo = (mobj_t *)think;
1167                         if (!(mo->flags&MF_COUNTKILL)) continue;
1168                         if (mo->health <= 0) continue;
1169                         if (!(mo->flags&MF_SHOOTABLE)) continue;
1170                         dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
1171                         if (dist > MINOTAUR_LOOK_DIST) continue;
1172                         if ((mo == master) || (mo == actor)) continue;
1173                         if ((mo->type == MT_MINOTAUR) &&
1174                                 (mo->special1 == actor->special1)) continue;
1175                         actor->target = mo;
1176                         break;                  // Found mobj to attack
1177                 }
1178         }
1179
1180         if (actor->target)
1181         {
1182                 P_SetMobjStateNF(actor, S_MNTR_WALK1);
1183         }
1184         else
1185         {
1186                 P_SetMobjStateNF(actor, S_MNTR_ROAM1);
1187         }
1188 }
1189
1190
1191
1192
1193 void A_MinotaurChase(mobj_t *actor)
1194 {
1195         unsigned int *starttime = (unsigned int *)actor->args;
1196
1197         actor->flags &= ~MF_SHADOW;                     // In case pain caused him to 
1198         actor->flags &= ~MF_ALTSHADOW;          // skip his fade in.
1199
1200         if ((leveltime - *starttime) >= MAULATORTICS)
1201         {
1202                 P_DamageMobj(actor,NULL,NULL,10000);
1203                 return;
1204         }
1205
1206         if (P_Random()<30)
1207                 A_MinotaurLook(actor);          // adjust to closest target
1208
1209         if (!actor->target || (actor->target->health <= 0) ||
1210                 !(actor->target->flags&MF_SHOOTABLE))
1211         { // look for a new target
1212                 P_SetMobjState(actor, S_MNTR_LOOK1);
1213                 return;
1214         }
1215
1216         FaceMovementDirection(actor);
1217         actor->reactiontime=0;
1218
1219         // Melee attack
1220         if (actor->info->meleestate && P_CheckMeleeRange(actor))
1221         {
1222                 if(actor->info->attacksound)
1223                 {
1224                         S_StartSound (actor, actor->info->attacksound);
1225                 }
1226                 P_SetMobjState (actor, actor->info->meleestate);
1227                 return;
1228         }
1229
1230         // Missile attack
1231         if (actor->info->missilestate && P_CheckMissileRange(actor))
1232         {
1233                 P_SetMobjState (actor, actor->info->missilestate);
1234                 return;
1235         }
1236
1237         // chase towards target
1238         if (!P_Move(actor))
1239         {
1240                 P_NewChaseDir(actor);
1241         }
1242
1243         // Active sound
1244         if(actor->info->activesound && P_Random() < 6)
1245         {
1246                 S_StartSound(actor, actor->info->activesound);
1247         }
1248
1249 }
1250
1251
1252 //----------------------------------------------------------------------------
1253 //
1254 // PROC A_MinotaurAtk1
1255 //
1256 // Melee attack.
1257 //
1258 //----------------------------------------------------------------------------
1259
1260 void A_MinotaurAtk1(mobj_t *actor)
1261 {
1262         if (!actor->target) return;
1263
1264         S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
1265         if(P_CheckMeleeRange(actor))
1266         {
1267                 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
1268         }
1269 }
1270
1271 //----------------------------------------------------------------------------
1272 //
1273 // PROC A_MinotaurDecide
1274 //
1275 // Choose a missile attack.
1276 //
1277 //----------------------------------------------------------------------------
1278
1279 #define MNTR_CHARGE_SPEED (23*FRACUNIT)
1280
1281 void A_MinotaurDecide(mobj_t *actor)
1282 {
1283         angle_t angle;
1284         mobj_t *target = actor->target;
1285         int dist;
1286
1287         if (!target) return;
1288         dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
1289
1290         if(target->z+target->height > actor->z
1291                 && target->z+target->height < actor->z+actor->height
1292                 && dist < 16*64*FRACUNIT
1293                 && dist > 1*64*FRACUNIT
1294                 && P_Random() < 230)
1295         { // Charge attack
1296                 // Don't call the state function right away
1297                 P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
1298                 actor->flags |= MF_SKULLFLY;
1299                 A_FaceTarget(actor);
1300                 angle = actor->angle>>ANGLETOFINESHIFT;
1301                 actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
1302                 actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
1303                 actor->args[4] = 35/2; // Charge duration
1304         }
1305         else if(target->z == target->floorz
1306                 && dist < 9*64*FRACUNIT
1307                 && P_Random() < 100)
1308         { // Floor fire attack
1309                 P_SetMobjState(actor, S_MNTR_ATK3_1);
1310                 actor->special2 = 0;
1311         }
1312         else
1313         { // Swing attack
1314                 A_FaceTarget(actor);
1315                 // Don't need to call P_SetMobjState because the current state
1316                 // falls through to the swing attack
1317         }
1318 }
1319
1320 //----------------------------------------------------------------------------
1321 //
1322 // PROC A_MinotaurCharge
1323 //
1324 //----------------------------------------------------------------------------
1325
1326 void A_MinotaurCharge(mobj_t *actor)
1327 {
1328         mobj_t *puff;
1329
1330         if (!actor->target) return;
1331
1332         if(actor->args[4] > 0)
1333         {
1334                 puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PUNCHPUFF);
1335                 puff->momz = 2*FRACUNIT;
1336                 actor->args[4]--;
1337         }
1338         else
1339         {
1340                 actor->flags &= ~MF_SKULLFLY;
1341                 P_SetMobjState(actor, actor->info->seestate);
1342         }
1343 }
1344
1345 //----------------------------------------------------------------------------
1346 //
1347 // PROC A_MinotaurAtk2
1348 //
1349 // Swing attack.
1350 //
1351 //----------------------------------------------------------------------------
1352
1353 void A_MinotaurAtk2(mobj_t *actor)
1354 {
1355         mobj_t *mo;
1356         angle_t angle;
1357         fixed_t momz;
1358
1359         if(!actor->target) return;
1360
1361         S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
1362         if(P_CheckMeleeRange(actor))
1363         {
1364                 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
1365                 return;
1366         }
1367         mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
1368         if(mo)
1369         {
1370                 //S_StartSound(mo, sfx_minat2);
1371                 momz = mo->momz;
1372                 angle = mo->angle;
1373                 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/8), momz);
1374                 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/8), momz);
1375                 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/16), momz);
1376                 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/16), momz);
1377         }
1378 }
1379
1380 //----------------------------------------------------------------------------
1381 //
1382 // PROC A_MinotaurAtk3
1383 //
1384 // Floor fire attack.
1385 //
1386 //----------------------------------------------------------------------------
1387
1388 void A_MinotaurAtk3(mobj_t *actor)
1389 {
1390         mobj_t *mo;
1391         player_t *player;
1392
1393         if(!actor->target)
1394         {
1395                 return;
1396         }
1397         if(P_CheckMeleeRange(actor))
1398         {
1399                 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
1400                 if((player = actor->target->player) != NULL)
1401                 { // Squish the player
1402                         player->deltaviewheight = -16*FRACUNIT;
1403                 }
1404         }
1405         else
1406         {
1407                 mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
1408                 if(mo != NULL)
1409                 {
1410                         S_StartSound(mo, SFX_MAULATOR_HAMMER_HIT);
1411                 }
1412         }
1413         if(P_Random() < 192 && actor->special2 == 0)
1414         {
1415                 P_SetMobjState(actor, S_MNTR_ATK3_4);
1416                 actor->special2 = 1;
1417         }
1418 }
1419
1420 //----------------------------------------------------------------------------
1421 //
1422 // PROC A_MntrFloorFire
1423 //
1424 //----------------------------------------------------------------------------
1425
1426 void A_MntrFloorFire(mobj_t *actor)
1427 {
1428         mobj_t *mo;
1429
1430         actor->z = actor->floorz;
1431         mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
1432                 actor->y+((P_Random()-P_Random())<<10), ONFLOORZ, MT_MNTRFX3);
1433         mo->target = actor->target;
1434         mo->momx = 1; // Force block checking
1435         P_CheckMissileSpawn(mo);
1436 }
1437
1438
1439 //----------------------------------------------------------------------------
1440 //
1441 // PROC A_Scream
1442 //
1443 //----------------------------------------------------------------------------
1444
1445 void A_Scream(mobj_t *actor)
1446 {
1447         int sound;
1448
1449         S_StopSound(actor);
1450         if(actor->player)
1451         {
1452                 if(actor->player->morphTics)
1453                 {
1454                         S_StartSound(actor, actor->info->deathsound);
1455                 }
1456                 else
1457                 {
1458                         // Handle the different player death screams
1459                         if(actor->momz <= -39*FRACUNIT)
1460                         { // Falling splat
1461                                 sound = SFX_PLAYER_FALLING_SPLAT;
1462                         }
1463                         else if(actor->health > -50)
1464                         { // Normal death sound
1465                                 switch(actor->player->class)
1466                                 {
1467                                         case PCLASS_FIGHTER:
1468                                                 sound = SFX_PLAYER_FIGHTER_NORMAL_DEATH;
1469                                                 break;
1470                                         case PCLASS_CLERIC:
1471                                                 sound = SFX_PLAYER_CLERIC_NORMAL_DEATH;
1472                                                 break;
1473                                         case PCLASS_MAGE:
1474                                                 sound = SFX_PLAYER_MAGE_NORMAL_DEATH;
1475                                                 break;
1476                                         default:
1477                                                 sound = SFX_NONE;
1478                                                 break;
1479                                 }
1480                         }
1481                         else if(actor->health > -100)
1482                         { // Crazy death sound
1483                                 switch(actor->player->class)
1484                                 {
1485                                         case PCLASS_FIGHTER:
1486                                                 sound = SFX_PLAYER_FIGHTER_CRAZY_DEATH;
1487                                                 break;
1488                                         case PCLASS_CLERIC:
1489                                                 sound = SFX_PLAYER_CLERIC_CRAZY_DEATH;
1490                                                 break;
1491                                         case PCLASS_MAGE:
1492                                                 sound = SFX_PLAYER_MAGE_CRAZY_DEATH;
1493                                                 break;
1494                                         default:
1495                                                 sound = SFX_NONE;
1496                                                 break;
1497                                 }
1498                         }
1499                         else
1500                         { // Extreme death sound
1501                                 switch(actor->player->class)
1502                                 {
1503                                         case PCLASS_FIGHTER:
1504                                                 sound = SFX_PLAYER_FIGHTER_EXTREME1_DEATH;
1505                                                 break;
1506                                         case PCLASS_CLERIC:
1507                                                 sound = SFX_PLAYER_CLERIC_EXTREME1_DEATH;
1508                                                 break;
1509                                         case PCLASS_MAGE:
1510                                                 sound = SFX_PLAYER_MAGE_EXTREME1_DEATH;
1511                                                 break;
1512                                         default:
1513                                                 sound = SFX_NONE;
1514                                                 break;
1515                                 }
1516                                 sound += P_Random()%3; // Three different extreme deaths
1517                         }
1518                         S_StartSound(actor, sound);
1519                 }
1520         }
1521         else
1522         {
1523                 S_StartSound(actor, actor->info->deathsound);
1524         }
1525 }
1526
1527 //---------------------------------------------------------------------------
1528 //
1529 // PROC P_DropItem
1530 //
1531 //---------------------------------------------------------------------------
1532
1533 /*
1534 void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
1535 {
1536         mobj_t *mo;
1537
1538         if(P_Random() > chance)
1539         {
1540                 return;
1541         }
1542         mo = P_SpawnMobj(source->x, source->y,
1543                 source->z+(source->height>>1), type);
1544         mo->momx = (P_Random()-P_Random())<<8;
1545         mo->momy = (P_Random()-P_Random())<<8;
1546         mo->momz = FRACUNIT*5+(P_Random()<<10);
1547         mo->flags2 |= MF2_DROPPED;
1548         mo->health = special;
1549 }
1550 */
1551
1552 //----------------------------------------------------------------------------
1553 //
1554 // PROC A_NoBlocking
1555 //
1556 //----------------------------------------------------------------------------
1557
1558 void A_NoBlocking(mobj_t *actor)
1559 {
1560         actor->flags &= ~MF_SOLID;
1561
1562         // Check for monsters dropping things
1563 /*      switch(actor->type)
1564         {
1565                 // Add the monster dropped items here
1566                 case MT_MUMMYLEADERGHOST:
1567                         P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
1568                         break;
1569                 default:
1570                         break;
1571         }
1572 */
1573 }
1574
1575 //----------------------------------------------------------------------------
1576 //
1577 // PROC A_Explode
1578 //
1579 // Handles a bunch of exploding things.
1580 //
1581 //----------------------------------------------------------------------------
1582
1583 void A_Explode(mobj_t *actor)
1584 {
1585         int damage;
1586         int distance;
1587         boolean damageSelf;
1588
1589         damage = 128;
1590         distance = 128;
1591         damageSelf = true;
1592         switch(actor->type)
1593         {
1594                 case MT_FIREBOMB: // Time Bombs
1595                         actor->z += 32*FRACUNIT;
1596                         actor->flags &= ~MF_SHADOW;
1597                         break;
1598                 case MT_MNTRFX2: // Minotaur floor fire
1599                         damage = 24;
1600                         break;
1601                 case MT_BISHOP: // Bishop radius death
1602                         damage = 25+(P_Random()&15);
1603                         break;
1604                 case MT_HAMMER_MISSILE: // Fighter Hammer
1605                         damage = 128;
1606                         damageSelf = false;
1607                         break;
1608                 case MT_FSWORD_MISSILE: // Fighter Runesword
1609                         damage = 64;
1610                         damageSelf = false;
1611                         break;
1612                 case MT_CIRCLEFLAME: // Cleric Flame secondary flames
1613                         damage = 20;
1614                         damageSelf = false;
1615                         break;
1616                 case MT_SORCBALL1:      // Sorcerer balls
1617                 case MT_SORCBALL2:
1618                 case MT_SORCBALL3:
1619                         distance = 255;
1620                         damage = 255;
1621                         actor->args[0] = 1;             // don't play bounce
1622                         break;
1623                 case MT_SORCFX1:        // Sorcerer spell 1
1624                         damage = 30;
1625                         break;
1626                 case MT_SORCFX4:        // Sorcerer spell 4
1627                         damage = 20;
1628                         break;
1629                 case MT_TREEDESTRUCTIBLE:
1630                         damage = 10;
1631                         break;
1632                 case MT_DRAGON_FX2:
1633                         damage = 80;
1634                         damageSelf = false;
1635                         break;
1636                 case MT_MSTAFF_FX:
1637                         damage = 64;
1638                         distance = 192;
1639                         damageSelf = false;
1640                         break;
1641                 case MT_MSTAFF_FX2:
1642                         damage = 80;
1643                         distance = 192;
1644                         damageSelf = false;
1645                         break;
1646                 case MT_POISONCLOUD:
1647                         damage = 4;
1648                         distance = 40;
1649                         break;
1650                 case MT_ZXMAS_TREE:
1651                 case MT_ZSHRUB2:
1652                         damage = 30;
1653                         distance = 64;
1654                         break;
1655                 default:
1656                         break;
1657         }
1658         P_RadiusAttack(actor, actor->target, damage, distance, damageSelf);
1659         if(actor->z <= actor->floorz+(distance<<FRACBITS)
1660                 && actor->type != MT_POISONCLOUD)
1661         {
1662                 P_HitFloor(actor);
1663         }
1664 }
1665
1666 //----------------------------------------------------------------------------
1667 //
1668 // PROC P_Massacre
1669 //
1670 // Kills all monsters.
1671 //
1672 //----------------------------------------------------------------------------
1673
1674 int P_Massacre(void)
1675 {
1676         int count;
1677         mobj_t *mo;
1678         thinker_t *think;
1679
1680         count = 0;
1681         for(think = thinkercap.next; think != &thinkercap;
1682                 think = think->next)
1683         {
1684                 if(think->function != P_MobjThinker)
1685                 { // Not a mobj thinker
1686                         continue;
1687                 }
1688                 mo = (mobj_t *)think;
1689                 if((mo->flags&MF_COUNTKILL) && (mo->health > 0))
1690                 {
1691                         mo->flags2 &= ~(MF2_NONSHOOTABLE+MF2_INVULNERABLE);
1692                         mo->flags |= MF_SHOOTABLE;
1693                         P_DamageMobj(mo, NULL, NULL, 10000);
1694                         count++;
1695                 }
1696         }
1697         return count;
1698 }
1699
1700
1701
1702 //----------------------------------------------------------------------------
1703 //
1704 // PROC A_SkullPop
1705 //
1706 //----------------------------------------------------------------------------
1707
1708 void A_SkullPop(mobj_t *actor)
1709 {
1710         mobj_t *mo;
1711         player_t *player;
1712
1713         if(!actor->player)
1714         {
1715                 return;
1716         }
1717         actor->flags &= ~MF_SOLID;
1718         mo = P_SpawnMobj(actor->x, actor->y, actor->z+48*FRACUNIT,
1719                 MT_BLOODYSKULL);
1720         //mo->target = actor;
1721         mo->momx = (P_Random()-P_Random())<<9;
1722         mo->momy = (P_Random()-P_Random())<<9;
1723         mo->momz = FRACUNIT*2+(P_Random()<<6);
1724         // Attach player mobj to bloody skull
1725         player = actor->player;
1726         actor->player = NULL;
1727         actor->special1 = player->class;
1728         mo->player = player;
1729         mo->health = actor->health;
1730         mo->angle = actor->angle;
1731         player->mo = mo;
1732         player->lookdir = 0;
1733         player->damagecount = 32;
1734 }
1735
1736 //----------------------------------------------------------------------------
1737 //
1738 // PROC A_CheckSkullFloor
1739 //
1740 //----------------------------------------------------------------------------
1741
1742 void A_CheckSkullFloor(mobj_t *actor)
1743 {
1744         if(actor->z <= actor->floorz)
1745         {
1746                 P_SetMobjState(actor, S_BLOODYSKULLX1);
1747                 S_StartSound(actor, SFX_DRIP);
1748         }
1749 }
1750
1751 //----------------------------------------------------------------------------
1752 //
1753 // PROC A_CheckSkullDone
1754 //
1755 //----------------------------------------------------------------------------
1756
1757 void A_CheckSkullDone(mobj_t *actor)
1758 {
1759         if(actor->special2 == 666)
1760         {
1761                 P_SetMobjState(actor, S_BLOODYSKULLX2);
1762         }
1763 }
1764
1765 //----------------------------------------------------------------------------
1766 //
1767 // PROC A_CheckBurnGone
1768 //
1769 //----------------------------------------------------------------------------
1770
1771 void A_CheckBurnGone(mobj_t *actor)
1772 {
1773         if(actor->special2 == 666)
1774         {
1775                 P_SetMobjState(actor, S_PLAY_FDTH20);
1776         }
1777 }
1778
1779 //----------------------------------------------------------------------------
1780 //
1781 // PROC A_FreeTargMobj
1782 //
1783 //----------------------------------------------------------------------------
1784
1785 void A_FreeTargMobj(mobj_t *mo)
1786 {
1787         mo->momx = mo->momy = mo->momz = 0;
1788         mo->z = mo->ceilingz+4*FRACUNIT;
1789         mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID|MF_COUNTKILL);
1790         mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
1791         mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
1792         mo->flags2 |= MF2_DONTDRAW;
1793         mo->player = NULL;
1794         mo->health = -1000;             // Don't resurrect
1795 }
1796
1797
1798 //----------------------------------------------------------------------------
1799 //
1800 // CorpseQueue Routines
1801 //
1802 //----------------------------------------------------------------------------
1803
1804 // Corpse queue for monsters - this should be saved out
1805 #define CORPSEQUEUESIZE 64
1806 mobj_t *corpseQueue[CORPSEQUEUESIZE];
1807 int corpseQueueSlot;
1808
1809 // throw another corpse on the queue
1810 void A_QueueCorpse(mobj_t *actor)
1811 {
1812         mobj_t *corpse;
1813
1814         if(corpseQueueSlot >= CORPSEQUEUESIZE)
1815         { // Too many corpses - remove an old one
1816                 corpse = corpseQueue[corpseQueueSlot%CORPSEQUEUESIZE];
1817                 if (corpse) P_RemoveMobj(corpse);
1818         }
1819         corpseQueue[corpseQueueSlot%CORPSEQUEUESIZE] = actor;
1820         corpseQueueSlot++;
1821 }
1822
1823 // Remove a mobj from the queue (for resurrection)
1824 void A_DeQueueCorpse(mobj_t *actor)
1825 {
1826         int slot;
1827
1828         for (slot=0; slot<CORPSEQUEUESIZE; slot++)
1829         {
1830                 if (corpseQueue[slot] == actor)
1831                 {
1832                         corpseQueue[slot] = NULL;
1833                         break;
1834                 }
1835         }
1836 }
1837
1838 void P_InitCreatureCorpseQueue(boolean corpseScan)
1839 {
1840         thinker_t *think;
1841         mobj_t *mo;
1842
1843         // Initialize queue
1844         corpseQueueSlot=0;
1845         memset(corpseQueue, 0, sizeof(mobj_t *)*CORPSEQUEUESIZE);
1846
1847         if (!corpseScan) return;
1848
1849         // Search mobj list for corpses and place them in this queue
1850         for(think = thinkercap.next; think != &thinkercap; think = think->next)
1851         {
1852                 if(think->function != P_MobjThinker) continue;
1853                 mo = (mobj_t *)think;
1854                 if (!(mo->flags&MF_CORPSE)) continue;   // Must be a corpse
1855                 if (mo->flags&MF_ICECORPSE) continue;   // Not ice corpses
1856                 // Only corpses that call A_QueueCorpse from death routine
1857                 switch(mo->type)
1858                 {
1859                         case MT_CENTAUR:
1860                         case MT_CENTAURLEADER:
1861                         case MT_DEMON:
1862                         case MT_DEMON2:
1863                         case MT_WRAITH:
1864                         case MT_WRAITHB:
1865                         case MT_BISHOP:
1866                         case MT_ETTIN:
1867                         case MT_PIG:
1868                         case MT_CENTAUR_SHIELD:
1869                         case MT_CENTAUR_SWORD:
1870                         case MT_DEMONCHUNK1:
1871                         case MT_DEMONCHUNK2:
1872                         case MT_DEMONCHUNK3:
1873                         case MT_DEMONCHUNK4:
1874                         case MT_DEMONCHUNK5:
1875                         case MT_DEMON2CHUNK1:
1876                         case MT_DEMON2CHUNK2:
1877                         case MT_DEMON2CHUNK3:
1878                         case MT_DEMON2CHUNK4:
1879                         case MT_DEMON2CHUNK5:
1880                         case MT_FIREDEMON_SPLOTCH1:
1881                         case MT_FIREDEMON_SPLOTCH2:
1882                                 A_QueueCorpse(mo);              // Add corpse to queue
1883                                 break;
1884                         default:
1885                                 break;
1886                 }
1887         }
1888 }
1889
1890
1891 //----------------------------------------------------------------------------
1892 //
1893 // PROC A_AddPlayerCorpse
1894 //
1895 //----------------------------------------------------------------------------
1896
1897 #define BODYQUESIZE 32
1898 mobj_t *bodyque[BODYQUESIZE];
1899 int bodyqueslot;
1900
1901 void A_AddPlayerCorpse(mobj_t *actor)
1902 {
1903         if(bodyqueslot >= BODYQUESIZE)
1904         { // Too many player corpses - remove an old one
1905                 P_RemoveMobj(bodyque[bodyqueslot%BODYQUESIZE]);
1906         }
1907         bodyque[bodyqueslot%BODYQUESIZE] = actor;
1908         bodyqueslot++;
1909 }
1910
1911 //============================================================================
1912 //
1913 // A_SerpentUnHide
1914 //
1915 //============================================================================
1916
1917 void A_SerpentUnHide(mobj_t *actor)
1918 {
1919         actor->flags2 &= ~MF2_DONTDRAW;
1920         actor->floorclip = 24*FRACUNIT;
1921 }
1922
1923 //============================================================================
1924 //
1925 // A_SerpentHide
1926 //
1927 //============================================================================
1928
1929 void A_SerpentHide(mobj_t *actor)
1930 {
1931         actor->flags2 |= MF2_DONTDRAW;
1932         actor->floorclip = 0;
1933 }
1934 //============================================================================
1935 //
1936 // A_SerpentChase
1937 //
1938 //============================================================================
1939
1940 void A_SerpentChase(mobj_t *actor)
1941 {
1942         int delta;
1943         int oldX, oldY, oldFloor;
1944
1945         if(actor->reactiontime)
1946         {
1947                 actor->reactiontime--;
1948         }
1949
1950         // Modify target threshold
1951         if(actor->threshold)
1952         {
1953                 actor->threshold--;
1954         }
1955
1956         if(gameskill == sk_nightmare)
1957         { // Monsters move faster in nightmare mode
1958                 actor->tics -= actor->tics/2;
1959                 if(actor->tics < 3)
1960                 {
1961                         actor->tics = 3;
1962                 }
1963         }
1964
1965 //
1966 // turn towards movement direction if not there yet
1967 //
1968         if(actor->movedir < 8)
1969         {
1970                 actor->angle &= (7<<29);
1971                 delta = actor->angle-(actor->movedir << 29);
1972                 if(delta > 0)
1973                 {
1974                         actor->angle -= ANG90/2;
1975                 }
1976                 else if(delta < 0)
1977                 {
1978                         actor->angle += ANG90/2;
1979                 }
1980         }
1981
1982         if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
1983         { // look for a new target
1984                 if(P_LookForPlayers(actor, true))
1985                 { // got a new target
1986                         return;
1987                 }
1988                 P_SetMobjState(actor, actor->info->spawnstate);
1989                 return;
1990         }
1991
1992 //
1993 // don't attack twice in a row
1994 //
1995         if(actor->flags & MF_JUSTATTACKED)
1996         {
1997                 actor->flags &= ~MF_JUSTATTACKED;
1998                 if (gameskill != sk_nightmare)
1999                         P_NewChaseDir (actor);
2000                 return;
2001         }
2002
2003 //
2004 // check for melee attack
2005 //
2006         if (actor->info->meleestate && P_CheckMeleeRange (actor))
2007         {
2008                 if(actor->info->attacksound)
2009                 {
2010                         S_StartSound (actor, actor->info->attacksound);
2011                 }
2012                 P_SetMobjState (actor, actor->info->meleestate);
2013                 return;
2014         }
2015
2016 //
2017 // possibly choose another target
2018 //
2019         if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
2020         {
2021                 if (P_LookForPlayers(actor,true))
2022                         return;         // got a new target
2023         }
2024
2025 //
2026 // chase towards player
2027 //
2028         oldX = actor->x;
2029         oldY = actor->y;
2030         oldFloor = actor->subsector->sector->floorpic;
2031         if (--actor->movecount<0 || !P_Move (actor))
2032         {
2033                 P_NewChaseDir (actor);
2034         }
2035         if(actor->subsector->sector->floorpic != oldFloor)
2036         {
2037                 P_TryMove(actor, oldX, oldY);
2038                 P_NewChaseDir (actor);
2039         }
2040
2041 //
2042 // make active sound
2043 //
2044         if(actor->info->activesound && P_Random() < 3)
2045         {
2046                 S_StartSound(actor, actor->info->activesound);
2047         }
2048 }
2049
2050 //============================================================================
2051 //
2052 // A_SerpentRaiseHump
2053 // 
2054 // Raises the hump above the surface by raising the floorclip level
2055 //============================================================================
2056
2057 void A_SerpentRaiseHump(mobj_t *actor)
2058 {
2059         actor->floorclip -= 4*FRACUNIT;
2060 }
2061
2062 //============================================================================
2063 //
2064 // A_SerpentLowerHump
2065 // 
2066 //============================================================================
2067
2068 void A_SerpentLowerHump(mobj_t *actor)
2069 {
2070         actor->floorclip += 4*FRACUNIT;
2071 }
2072
2073 //============================================================================
2074 //
2075 // A_SerpentHumpDecide
2076 //
2077 //              Decided whether to hump up, or if the mobj is a serpent leader, 
2078 //                      to missile attack
2079 //============================================================================
2080
2081 void A_SerpentHumpDecide(mobj_t *actor)
2082 {
2083         if(actor->type == MT_SERPENTLEADER)
2084         {
2085                 if(P_Random() > 30)
2086                 {
2087                         return;
2088                 }
2089                 else if(P_Random() < 40)
2090                 { // Missile attack
2091                         P_SetMobjState(actor, S_SERPENT_SURFACE1);
2092                         return;
2093                 }
2094         }
2095         else if(P_Random() > 3)
2096         {
2097                 return;
2098         }
2099         if(!P_CheckMeleeRange(actor))
2100         { // The hump shouldn't occur when within melee range
2101                 if(actor->type == MT_SERPENTLEADER && P_Random() < 128)
2102                 {
2103                         P_SetMobjState(actor, S_SERPENT_SURFACE1);
2104                 }
2105                 else
2106                 {       
2107                         P_SetMobjState(actor, S_SERPENT_HUMP1);
2108                         S_StartSound(actor, SFX_SERPENT_ACTIVE);
2109                 }
2110         }
2111 }
2112
2113 //============================================================================
2114 //
2115 // A_SerpentBirthScream
2116 //
2117 //============================================================================
2118
2119 void A_SerpentBirthScream(mobj_t *actor)
2120 {
2121         S_StartSound(actor, SFX_SERPENT_BIRTH);
2122 }
2123
2124 //============================================================================
2125 //
2126 // A_SerpentDiveSound
2127 //
2128 //============================================================================
2129
2130 void A_SerpentDiveSound(mobj_t *actor)
2131 {
2132         S_StartSound(actor, SFX_SERPENT_ACTIVE);
2133 }
2134
2135 //============================================================================
2136 //
2137 // A_SerpentWalk
2138 //
2139 // Similar to A_Chase, only has a hardcoded entering of meleestate
2140 //============================================================================
2141
2142 void A_SerpentWalk(mobj_t *actor)
2143 {
2144         int delta;
2145
2146         if(actor->reactiontime)
2147         {
2148                 actor->reactiontime--;
2149         }
2150
2151         // Modify target threshold
2152         if(actor->threshold)
2153         {
2154                 actor->threshold--;
2155         }
2156
2157         if(gameskill == sk_nightmare)
2158         { // Monsters move faster in nightmare mode
2159                 actor->tics -= actor->tics/2;
2160                 if(actor->tics < 3)
2161                 {
2162                         actor->tics = 3;
2163                 }
2164         }
2165
2166 //
2167 // turn towards movement direction if not there yet
2168 //
2169         if(actor->movedir < 8)
2170         {
2171                 actor->angle &= (7<<29);
2172                 delta = actor->angle-(actor->movedir << 29);
2173                 if(delta > 0)
2174                 {
2175                         actor->angle -= ANG90/2;
2176                 }
2177                 else if(delta < 0)
2178                 {
2179                         actor->angle += ANG90/2;
2180                 }
2181         }
2182
2183         if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
2184         { // look for a new target
2185                 if(P_LookForPlayers(actor, true))
2186                 { // got a new target
2187                         return;
2188                 }
2189                 P_SetMobjState(actor, actor->info->spawnstate);
2190                 return;
2191         }
2192
2193 //
2194 // don't attack twice in a row
2195 //
2196         if(actor->flags & MF_JUSTATTACKED)
2197         {
2198                 actor->flags &= ~MF_JUSTATTACKED;
2199                 if (gameskill != sk_nightmare)
2200                         P_NewChaseDir (actor);
2201                 return;
2202         }
2203
2204 //
2205 // check for melee attack
2206 //
2207         if (actor->info->meleestate && P_CheckMeleeRange (actor))
2208         {
2209                 if (actor->info->attacksound)
2210                 {
2211                         S_StartSound (actor, actor->info->attacksound);
2212                 }
2213                 P_SetMobjState(actor, S_SERPENT_ATK1);
2214                 return;
2215         }
2216 //
2217 // possibly choose another target
2218 //
2219         if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
2220         {
2221                 if (P_LookForPlayers(actor,true))
2222                         return;         // got a new target
2223         }
2224
2225 //
2226 // chase towards player
2227 //
2228         if (--actor->movecount<0 || !P_Move (actor))
2229         {
2230                 P_NewChaseDir (actor);
2231         }
2232 }
2233
2234 //============================================================================
2235 //
2236 // A_SerpentCheckForAttack
2237 //
2238 //============================================================================
2239
2240 void A_SerpentCheckForAttack(mobj_t *actor)
2241 {
2242         if(!actor->target)
2243         {
2244                 return;
2245         }
2246         if(actor->type == MT_SERPENTLEADER)
2247         {
2248                 if(!P_CheckMeleeRange(actor))
2249                 {
2250                         P_SetMobjState(actor, S_SERPENT_ATK1);
2251                         return;
2252                 }
2253         }
2254         if(P_CheckMeleeRange2(actor))
2255         {
2256                 P_SetMobjState(actor, S_SERPENT_WALK1);
2257         }
2258         else if(P_CheckMeleeRange(actor))
2259         {
2260                 if(P_Random() < 32)
2261                 {
2262                         P_SetMobjState(actor, S_SERPENT_WALK1);
2263                 }
2264                 else
2265                 {
2266                         P_SetMobjState(actor, S_SERPENT_ATK1);
2267                 }
2268         }
2269 }
2270
2271 //============================================================================
2272 //
2273 // A_SerpentChooseAttack
2274 //
2275 //============================================================================
2276
2277 void A_SerpentChooseAttack(mobj_t *actor)
2278 {
2279         if(!actor->target || P_CheckMeleeRange(actor))
2280         {
2281                 return;
2282         }
2283         if(actor->type == MT_SERPENTLEADER)
2284         {
2285                 P_SetMobjState(actor, S_SERPENT_MISSILE1);
2286         }
2287 }
2288         
2289 //============================================================================
2290 //
2291 // A_SerpentMeleeAttack
2292 //
2293 //============================================================================
2294
2295 void A_SerpentMeleeAttack(mobj_t *actor)
2296 {
2297         if(!actor->target)
2298         {
2299                 return;
2300         }
2301         if(P_CheckMeleeRange(actor))
2302         {
2303                 P_DamageMobj(actor->target, actor, actor, HITDICE(5));
2304                 S_StartSound(actor, SFX_SERPENT_MELEEHIT);
2305         }
2306         if(P_Random() < 96)
2307         {
2308                 A_SerpentCheckForAttack(actor);
2309         }
2310 }
2311
2312 //============================================================================
2313 //
2314 // A_SerpentMissileAttack
2315 //
2316 //============================================================================
2317         
2318 void A_SerpentMissileAttack(mobj_t *actor)
2319 {
2320         mobj_t *mo;
2321
2322         if(!actor->target)
2323         {
2324                 return;
2325         }
2326         mo = P_SpawnMissile(actor, actor->target, MT_SERPENTFX);
2327 }
2328
2329 //============================================================================
2330 //
2331 // A_SerpentHeadPop
2332 //
2333 //============================================================================
2334
2335 void A_SerpentHeadPop(mobj_t *actor)
2336 {
2337         P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, MT_SERPENT_HEAD);
2338 }
2339
2340 //============================================================================
2341 //
2342 // A_SerpentSpawnGibs
2343 //
2344 //============================================================================
2345
2346 void A_SerpentSpawnGibs(mobj_t *actor)
2347 {
2348         mobj_t *mo;
2349
2350         mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12), 
2351                 actor->y+((P_Random()-128)<<12), actor->floorz+FRACUNIT,
2352                 MT_SERPENT_GIB1);       
2353         if(mo)
2354         {
2355                 mo->momx = (P_Random()-128)<<6;
2356                 mo->momy = (P_Random()-128)<<6;
2357                 mo->floorclip = 6*FRACUNIT;
2358         }
2359         mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12), 
2360                 actor->y+((P_Random()-128)<<12), actor->floorz+FRACUNIT,
2361                 MT_SERPENT_GIB2);       
2362         if(mo)
2363         {
2364                 mo->momx = (P_Random()-128)<<6;
2365                 mo->momy = (P_Random()-128)<<6;
2366                 mo->floorclip = 6*FRACUNIT;
2367         }
2368         mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12), 
2369                 actor->y+((P_Random()-128)<<12), actor->floorz+FRACUNIT,
2370                 MT_SERPENT_GIB3);       
2371         if(mo)
2372         {
2373                 mo->momx = (P_Random()-128)<<6;
2374                 mo->momy = (P_Random()-128)<<6;
2375                 mo->floorclip = 6*FRACUNIT;
2376         }
2377 }
2378
2379 //============================================================================
2380 //
2381 // A_FloatGib
2382 //
2383 //============================================================================
2384
2385 void A_FloatGib(mobj_t *actor)
2386 {
2387         actor->floorclip -= FRACUNIT;
2388 }
2389
2390 //============================================================================
2391 //
2392 // A_SinkGib
2393 //
2394 //============================================================================
2395
2396 void A_SinkGib(mobj_t *actor)
2397 {
2398         actor->floorclip += FRACUNIT;
2399 }
2400
2401 //============================================================================
2402 //
2403 // A_DelayGib
2404 //
2405 //============================================================================
2406
2407 void A_DelayGib(mobj_t *actor)
2408 {
2409         actor->tics -= P_Random()>>2;
2410 }
2411
2412 //============================================================================
2413 //
2414 // A_SerpentHeadCheck
2415 //
2416 //============================================================================
2417
2418 void A_SerpentHeadCheck(mobj_t *actor)
2419 {
2420         if(actor->z <= actor->floorz)
2421         {
2422                 if(P_GetThingFloorType(actor) >= FLOOR_LIQUID)
2423                 {
2424                         P_HitFloor(actor);
2425                         P_SetMobjState(actor, S_NULL);
2426                 }
2427                 else
2428                 {
2429                         P_SetMobjState(actor, S_SERPENT_HEAD_X1);
2430                 }
2431         }
2432 }
2433
2434 //============================================================================
2435 //
2436 // A_CentaurAttack
2437 //
2438 //============================================================================
2439
2440 void A_CentaurAttack(mobj_t *actor)
2441 {
2442         if(!actor->target)
2443         {
2444                 return;
2445         }
2446         if(P_CheckMeleeRange(actor))
2447         {
2448                 P_DamageMobj(actor->target, actor, actor, P_Random()%7+3);
2449         }
2450 }
2451
2452 //============================================================================
2453 //
2454 // A_CentaurAttack2
2455 //
2456 //============================================================================
2457
2458 void A_CentaurAttack2(mobj_t *actor)
2459 {
2460         if(!actor->target)
2461         {
2462                 return;
2463         }
2464         P_SpawnMissile(actor, actor->target, MT_CENTAUR_FX);
2465         S_StartSound(actor, SFX_CENTAURLEADER_ATTACK);
2466 }
2467
2468 //============================================================================
2469 //
2470 // A_CentaurDropStuff
2471 //
2472 //      Spawn shield/sword sprites when the centaur pulps //============================================================================
2473
2474 void A_CentaurDropStuff(mobj_t *actor)
2475 {
2476         mobj_t *mo;
2477         angle_t angle;
2478
2479         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
2480                 MT_CENTAUR_SHIELD);
2481         if(mo)
2482         {
2483                 angle = actor->angle+ANG90;
2484                 mo->momz = FRACUNIT*8+(P_Random()<<10);
2485                 mo->momx = FixedMul(((P_Random()-128)<<11)+FRACUNIT,
2486                         finecosine[angle>>ANGLETOFINESHIFT]);
2487                 mo->momy = FixedMul(((P_Random()-128)<<11)+FRACUNIT, 
2488                         finesine[angle>>ANGLETOFINESHIFT]);
2489                 mo->target = actor;
2490         }
2491         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
2492                 MT_CENTAUR_SWORD);
2493         if(mo)
2494         {
2495                 angle = actor->angle-ANG90;
2496                 mo->momz = FRACUNIT*8+(P_Random()<<10);
2497                 mo->momx = FixedMul(((P_Random()-128)<<11)+FRACUNIT,
2498                         finecosine[angle>>ANGLETOFINESHIFT]);
2499                 mo->momy = FixedMul(((P_Random()-128)<<11)+FRACUNIT, 
2500                         finesine[angle>>ANGLETOFINESHIFT]);
2501                 mo->target = actor;
2502         }
2503 }
2504
2505 //============================================================================
2506 //
2507 // A_CentaurDefend
2508 //
2509 //============================================================================
2510
2511 void A_CentaurDefend(mobj_t *actor)
2512 {
2513         A_FaceTarget(actor);
2514         if(P_CheckMeleeRange(actor) && P_Random() < 32)
2515         {
2516                 A_UnSetInvulnerable(actor);
2517                 P_SetMobjState(actor, actor->info->meleestate);
2518         }
2519 }
2520
2521 //============================================================================
2522 //
2523 // A_BishopAttack
2524 //
2525 //============================================================================
2526
2527 void A_BishopAttack(mobj_t *actor)
2528 {
2529         if(!actor->target)
2530         {
2531                 return;
2532         }
2533         S_StartSound(actor, actor->info->attacksound);
2534         if(P_CheckMeleeRange(actor))
2535         {
2536                 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
2537                 return;
2538         }
2539         actor->special1 = (P_Random()&3)+5;
2540 }
2541
2542 //============================================================================
2543 //
2544 // A_BishopAttack2
2545 //
2546 //              Spawns one of a string of bishop missiles
2547 //============================================================================
2548
2549 void A_BishopAttack2(mobj_t *actor)
2550 {
2551         mobj_t *mo;
2552
2553         if(!actor->target || !actor->special1)
2554         {
2555                 actor->special1 = 0;
2556                 P_SetMobjState(actor, S_BISHOP_WALK1);
2557                 return;
2558         }
2559         mo = P_SpawnMissile(actor, actor->target, MT_BISH_FX);
2560         if(mo)
2561         {
2562                 mo->special1 = (int)actor->target;
2563                 mo->special2 = 16; // High word == x/y, Low word == z
2564         }
2565         actor->special1--;
2566 }
2567
2568 //============================================================================
2569 //
2570 // A_BishopMissileWeave
2571 //
2572 //============================================================================
2573
2574 void A_BishopMissileWeave(mobj_t *actor)
2575 {
2576         fixed_t newX, newY;
2577         int weaveXY, weaveZ;
2578         int angle;
2579
2580         weaveXY = actor->special2>>16;
2581         weaveZ = actor->special2&0xFFFF;
2582         angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
2583         newX = actor->x-FixedMul(finecosine[angle], 
2584                 FloatBobOffsets[weaveXY]<<1);
2585         newY = actor->y-FixedMul(finesine[angle],
2586                 FloatBobOffsets[weaveXY]<<1);
2587         weaveXY = (weaveXY+2)&63;
2588         newX += FixedMul(finecosine[angle], 
2589                 FloatBobOffsets[weaveXY]<<1);
2590         newY += FixedMul(finesine[angle], 
2591                 FloatBobOffsets[weaveXY]<<1);
2592         P_TryMove(actor, newX, newY);
2593         actor->z -= FloatBobOffsets[weaveZ];
2594         weaveZ = (weaveZ+2)&63;
2595         actor->z += FloatBobOffsets[weaveZ];    
2596         actor->special2 = weaveZ+(weaveXY<<16);
2597 }
2598
2599 //============================================================================
2600 //
2601 // A_BishopMissileSeek
2602 //
2603 //============================================================================
2604
2605 void A_BishopMissileSeek(mobj_t *actor)
2606 {
2607         P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*3);
2608 }
2609
2610 //============================================================================
2611 //
2612 // A_BishopDecide
2613 //
2614 //============================================================================
2615
2616 void A_BishopDecide(mobj_t *actor)
2617 {
2618         if(P_Random() < 220)
2619         {
2620                 return;
2621         }
2622         else
2623         {
2624                 P_SetMobjState(actor, S_BISHOP_BLUR1);
2625         }               
2626 }
2627
2628 //============================================================================
2629 //
2630 // A_BishopDoBlur
2631 //
2632 //============================================================================
2633
2634 void A_BishopDoBlur(mobj_t *actor)
2635 {
2636         actor->special1 = (P_Random()&3)+3; // Random number of blurs
2637         if(P_Random() < 120)
2638         {
2639                 P_ThrustMobj(actor, actor->angle+ANG90, 11*FRACUNIT);
2640         }
2641         else if(P_Random() > 125)
2642         {
2643                 P_ThrustMobj(actor, actor->angle-ANG90, 11*FRACUNIT);
2644         }
2645         else
2646         { // Thrust forward
2647                 P_ThrustMobj(actor, actor->angle, 11*FRACUNIT);
2648         }
2649         S_StartSound(actor, SFX_BISHOP_BLUR);
2650 }
2651
2652 //============================================================================
2653 //
2654 // A_BishopSpawnBlur
2655 //
2656 //============================================================================
2657
2658 void A_BishopSpawnBlur(mobj_t *actor)
2659 {
2660         mobj_t *mo;
2661
2662         if(!--actor->special1)
2663         {
2664                 actor->momx = 0;
2665                 actor->momy = 0;
2666                 if(P_Random() > 96)
2667                 {
2668                         P_SetMobjState(actor, S_BISHOP_WALK1);
2669                 }
2670                 else
2671                 {
2672                         P_SetMobjState(actor, S_BISHOP_ATK1);
2673                 }
2674         }
2675         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOPBLUR);
2676         if(mo)
2677         {
2678                 mo->angle = actor->angle;
2679         }
2680 }
2681
2682 //============================================================================
2683 //
2684 // A_BishopChase
2685 //
2686 //============================================================================
2687
2688 void A_BishopChase(mobj_t *actor)
2689 {
2690         actor->z -= FloatBobOffsets[actor->special2]>>1;
2691         actor->special2 = (actor->special2+4)&63;
2692         actor->z += FloatBobOffsets[actor->special2]>>1;
2693 }
2694
2695 //============================================================================
2696 //
2697 // A_BishopPuff
2698 //
2699 //============================================================================
2700
2701 void A_BishopPuff(mobj_t *actor)
2702 {
2703         mobj_t *mo;
2704
2705         mo = P_SpawnMobj(actor->x, actor->y, actor->z+40*FRACUNIT,      
2706                 MT_BISHOP_PUFF);
2707         if(mo)
2708         {
2709                 mo->momz = FRACUNIT/2;
2710         }
2711 }
2712
2713 //============================================================================
2714 //
2715 // A_BishopPainBlur
2716 //
2717 //============================================================================
2718
2719 void A_BishopPainBlur(mobj_t *actor)
2720 {
2721         mobj_t *mo;
2722
2723         if(P_Random() < 64)
2724         {
2725                 P_SetMobjState(actor, S_BISHOP_BLUR1);
2726                 return;
2727         }
2728         mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<12), actor->y
2729                 +((P_Random()-P_Random())<<12), actor->z+((P_Random()-P_Random())<<11),
2730                 MT_BISHOPPAINBLUR);
2731         if(mo)
2732         {
2733                 mo->angle = actor->angle;
2734         }
2735 }
2736
2737 //============================================================================
2738 //
2739 // DragonSeek
2740 //
2741 //============================================================================
2742
2743 static void DragonSeek(mobj_t *actor, angle_t thresh, angle_t turnMax)
2744 {
2745         int dir;
2746         int dist;
2747         angle_t delta;
2748         angle_t angle;
2749         mobj_t *target;
2750         int search;
2751         int i;
2752         int bestArg;
2753         angle_t bestAngle;
2754         angle_t angleToSpot, angleToTarget;
2755         mobj_t *mo;
2756
2757         target = (mobj_t *)actor->special1;
2758         if(target == NULL)
2759         {
2760                 return;
2761         }
2762         dir = P_FaceMobj(actor, target, &delta);
2763         if(delta > thresh)
2764         {
2765                 delta >>= 1;
2766                 if(delta > turnMax)
2767                 {
2768                         delta = turnMax;
2769                 }
2770         }
2771         if(dir)
2772         { // Turn clockwise
2773                 actor->angle += delta;
2774         }
2775         else
2776         { // Turn counter clockwise
2777                 actor->angle -= delta;
2778         }
2779         angle = actor->angle>>ANGLETOFINESHIFT;
2780         actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
2781         actor->momy = FixedMul(actor->info->speed, finesine[angle]);
2782         if(actor->z+actor->height < target->z 
2783                 || target->z+target->height < actor->z)
2784         {
2785                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
2786                 dist = dist/actor->info->speed;
2787                 if(dist < 1)
2788                 {
2789                         dist = 1;
2790                 }
2791                 actor->momz = (target->z-actor->z)/dist;
2792         }
2793         else
2794         {
2795                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
2796                 dist = dist/actor->info->speed;
2797         }
2798         if(target->flags&MF_SHOOTABLE && P_Random() < 64)
2799         { // attack the destination mobj if it's attackable
2800                 mobj_t *oldTarget;
2801         
2802                 if(abs(actor->angle-R_PointToAngle2(actor->x, actor->y, 
2803                         target->x, target->y)) < ANGLE_45/2)
2804                 {
2805                         oldTarget = actor->target;
2806                         actor->target = target;
2807                         if(P_CheckMeleeRange(actor))
2808                         {
2809                                 P_DamageMobj(actor->target, actor, actor, HITDICE(10));
2810                                 S_StartSound(actor, SFX_DRAGON_ATTACK);
2811                         }
2812                         else if(P_Random() < 128 && P_CheckMissileRange(actor))
2813                         {
2814                                 P_SpawnMissile(actor, target, MT_DRAGON_FX);                                            
2815                                 S_StartSound(actor, SFX_DRAGON_ATTACK);
2816                         }
2817                         actor->target = oldTarget;
2818                 }
2819         }
2820         if(dist < 4)
2821         { // Hit the target thing
2822                 if(actor->target && P_Random() < 200)
2823                 {
2824                         bestArg = -1;
2825                         bestAngle = ANGLE_MAX;
2826                         angleToTarget = R_PointToAngle2(actor->x, actor->y,
2827                                 actor->target->x, actor->target->y);
2828                         for(i = 0; i < 5; i++)
2829                         {
2830                                 if(!target->args[i])
2831                                 {
2832                                         continue;
2833                                 }
2834                                 search = -1;
2835                                 mo = P_FindMobjFromTID(target->args[i], &search);
2836                                 angleToSpot = R_PointToAngle2(actor->x, actor->y, 
2837                                         mo->x, mo->y);
2838                                 if(abs(angleToSpot-angleToTarget) < bestAngle)
2839                                 {
2840                                         bestAngle = abs(angleToSpot-angleToTarget);
2841                                         bestArg = i;
2842                                 }
2843                         }
2844                         if(bestArg != -1)
2845                         {
2846                                 search = -1;
2847                                 actor->special1 = (int)P_FindMobjFromTID(target->args[bestArg], 
2848                                         &search);
2849                         }
2850                 }
2851                 else
2852                 {
2853                         do
2854                         {
2855                                 i = (P_Random()>>2)%5;
2856                         } while(!target->args[i]);
2857                         search = -1;
2858                         actor->special1 = (int)P_FindMobjFromTID(target->args[i], &search);
2859                 }
2860         }
2861 }
2862
2863 //============================================================================
2864 //
2865 // A_DragonInitFlight
2866 //
2867 //============================================================================
2868
2869 void A_DragonInitFlight(mobj_t *actor)
2870 {
2871         int search;
2872
2873         search = -1;
2874         do
2875         { // find the first tid identical to the dragon's tid
2876                 actor->special1 = (int)P_FindMobjFromTID(actor->tid, &search);
2877                 if(search == -1)
2878                 {
2879                         P_SetMobjState(actor, actor->info->spawnstate);
2880                         return;
2881                 }
2882         } while(actor->special1 == (int)actor);
2883         P_RemoveMobjFromTIDList(actor);
2884 }
2885
2886 //============================================================================
2887 //
2888 // A_DragonFlight
2889 //
2890 //============================================================================
2891
2892 void A_DragonFlight(mobj_t *actor)
2893 {
2894         angle_t angle;
2895
2896         DragonSeek(actor, 4*ANGLE_1, 8*ANGLE_1);
2897         if(actor->target)
2898         {
2899                 if(!(actor->target->flags&MF_SHOOTABLE))
2900                 { // target died
2901                         actor->target = NULL;
2902                         return;
2903                 }
2904                 angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
2905                         actor->target->y);
2906                 if(abs(actor->angle-angle) < ANGLE_45/2 && P_CheckMeleeRange(actor))
2907                 {
2908                         P_DamageMobj(actor->target, actor, actor, HITDICE(8));
2909                         S_StartSound(actor, SFX_DRAGON_ATTACK);
2910                 }
2911                 else if(abs(actor->angle-angle) <= ANGLE_1*20)
2912                 {
2913                         P_SetMobjState(actor, actor->info->missilestate);
2914                         S_StartSound(actor, SFX_DRAGON_ATTACK);
2915                 }
2916         }
2917         else
2918         {
2919                 P_LookForPlayers(actor, true);
2920         }
2921 }
2922
2923 //============================================================================
2924 //
2925 // A_DragonFlap
2926 //
2927 //============================================================================
2928
2929 void A_DragonFlap(mobj_t *actor)
2930 {
2931         A_DragonFlight(actor);
2932         if(P_Random() < 240)
2933         {
2934                 S_StartSound(actor, SFX_DRAGON_WINGFLAP);
2935         }
2936         else
2937         {
2938                 S_StartSound(actor, actor->info->activesound);
2939         }
2940 }
2941
2942 //============================================================================
2943 //
2944 // A_DragonAttack
2945 //
2946 //============================================================================
2947
2948 void A_DragonAttack(mobj_t *actor)
2949 {
2950         mobj_t *mo;
2951
2952         mo = P_SpawnMissile(actor, actor->target, MT_DRAGON_FX);                                                
2953 }
2954
2955 //============================================================================
2956 //
2957 // A_DragonFX2
2958 //
2959 //============================================================================
2960
2961 void A_DragonFX2(mobj_t *actor)
2962 {
2963         mobj_t *mo;
2964         int i;
2965         int delay;
2966
2967         delay = 16+(P_Random()>>3);
2968         for(i = 1+(P_Random()&3); i; i--)
2969         {
2970                 mo = P_SpawnMobj(actor->x+((P_Random()-128)<<14), 
2971                         actor->y+((P_Random()-128)<<14), actor->z+((P_Random()-128)<<12),
2972                         MT_DRAGON_FX2);
2973                 if(mo)
2974                 {
2975                         mo->tics = delay+(P_Random()&3)*i*2;
2976                         mo->target = actor->target;
2977                 }
2978         } 
2979 }
2980
2981 //============================================================================
2982 //
2983 // A_DragonPain
2984 //
2985 //============================================================================
2986
2987 void A_DragonPain(mobj_t *actor)
2988 {
2989         A_Pain(actor);
2990         if(!actor->special1)
2991         { // no destination spot yet
2992                 P_SetMobjState(actor, S_DRAGON_INIT);
2993         }
2994 }
2995
2996 //============================================================================
2997 //
2998 // A_DragonCheckCrash
2999 //
3000 //============================================================================
3001
3002 void A_DragonCheckCrash(mobj_t *actor)
3003 {
3004         if(actor->z <= actor->floorz)
3005         {
3006                 P_SetMobjState(actor, S_DRAGON_CRASH1);
3007         }
3008 }
3009
3010 //============================================================================
3011 // Demon AI
3012 //============================================================================
3013
3014 //
3015 // A_DemonAttack1 (melee)
3016 //
3017 void A_DemonAttack1(mobj_t *actor)
3018 {
3019         if(P_CheckMeleeRange(actor))
3020         {
3021                 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
3022         }
3023 }
3024
3025
3026 //
3027 // A_DemonAttack2 (missile)
3028 //
3029 void A_DemonAttack2(mobj_t *actor)
3030 {
3031         mobj_t *mo;
3032         int fireBall;
3033
3034         if(actor->type == MT_DEMON)
3035         {
3036                 fireBall = MT_DEMONFX1;
3037         }
3038         else
3039         {
3040                 fireBall = MT_DEMON2FX1;
3041         }
3042         mo = P_SpawnMissile(actor, actor->target, fireBall);
3043         if (mo)
3044         {
3045                 mo->z += 30*FRACUNIT;
3046                 S_StartSound(actor, SFX_DEMON_MISSILE_FIRE);
3047         }
3048 }
3049
3050 //
3051 // A_DemonDeath
3052 //
3053
3054 void A_DemonDeath(mobj_t *actor)
3055 {
3056         mobj_t *mo;
3057         angle_t angle;
3058
3059         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3060                 MT_DEMONCHUNK1);
3061         if(mo)
3062         {
3063                 angle = actor->angle+ANG90;
3064                 mo->momz = 8*FRACUNIT;
3065                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3066                         finecosine[angle>>ANGLETOFINESHIFT]);
3067                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3068                         finesine[angle>>ANGLETOFINESHIFT]);
3069                 mo->target = actor;
3070         }
3071         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3072                 MT_DEMONCHUNK2);
3073         if(mo)
3074         {
3075                 angle = actor->angle-ANG90;
3076                 mo->momz = 8*FRACUNIT;
3077                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3078                         finecosine[angle>>ANGLETOFINESHIFT]);
3079                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3080                         finesine[angle>>ANGLETOFINESHIFT]);
3081                 mo->target = actor;
3082         }
3083         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3084                 MT_DEMONCHUNK3);
3085         if(mo)
3086         {
3087                 angle = actor->angle-ANG90;
3088                 mo->momz = 8*FRACUNIT;
3089                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3090                         finecosine[angle>>ANGLETOFINESHIFT]);
3091                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3092                         finesine[angle>>ANGLETOFINESHIFT]);
3093                 mo->target = actor;
3094         }
3095         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3096                 MT_DEMONCHUNK4);
3097         if(mo)
3098         {
3099                 angle = actor->angle-ANG90;
3100                 mo->momz = 8*FRACUNIT;
3101                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3102                         finecosine[angle>>ANGLETOFINESHIFT]);
3103                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3104                         finesine[angle>>ANGLETOFINESHIFT]);
3105                 mo->target = actor;
3106         }
3107         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3108                 MT_DEMONCHUNK5);
3109         if(mo)
3110         {
3111                 angle = actor->angle-ANG90;
3112                 mo->momz = 8*FRACUNIT;
3113                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3114                         finecosine[angle>>ANGLETOFINESHIFT]);
3115                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3116                         finesine[angle>>ANGLETOFINESHIFT]);
3117                 mo->target = actor;
3118         }
3119 }
3120
3121 //===========================================================================
3122 //
3123 // A_Demon2Death
3124 //
3125 //===========================================================================
3126
3127 void A_Demon2Death(mobj_t *actor)
3128 {
3129         mobj_t *mo;
3130         angle_t angle;
3131
3132         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3133                 MT_DEMON2CHUNK1);
3134         if(mo)
3135         {
3136                 angle = actor->angle+ANG90;
3137                 mo->momz = 8*FRACUNIT;
3138                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3139                         finecosine[angle>>ANGLETOFINESHIFT]);
3140                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3141                         finesine[angle>>ANGLETOFINESHIFT]);
3142                 mo->target = actor;
3143         }
3144         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3145                 MT_DEMON2CHUNK2);
3146         if(mo)
3147         {
3148                 angle = actor->angle-ANG90;
3149                 mo->momz = 8*FRACUNIT;
3150                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3151                         finecosine[angle>>ANGLETOFINESHIFT]);
3152                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3153                         finesine[angle>>ANGLETOFINESHIFT]);
3154                 mo->target = actor;
3155         }
3156         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3157                 MT_DEMON2CHUNK3);
3158         if(mo)
3159         {
3160                 angle = actor->angle-ANG90;
3161                 mo->momz = 8*FRACUNIT;
3162                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3163                         finecosine[angle>>ANGLETOFINESHIFT]);
3164                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3165                         finesine[angle>>ANGLETOFINESHIFT]);
3166                 mo->target = actor;
3167         }
3168         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3169                 MT_DEMON2CHUNK4);
3170         if(mo)
3171         {
3172                 angle = actor->angle-ANG90;
3173                 mo->momz = 8*FRACUNIT;
3174                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3175                         finecosine[angle>>ANGLETOFINESHIFT]);
3176                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3177                         finesine[angle>>ANGLETOFINESHIFT]);
3178                 mo->target = actor;
3179         }
3180         mo = P_SpawnMobj(actor->x, actor->y, actor->z+45*FRACUNIT, 
3181                 MT_DEMON2CHUNK5);
3182         if(mo)
3183         {
3184                 angle = actor->angle-ANG90;
3185                 mo->momz = 8*FRACUNIT;
3186                 mo->momx = FixedMul((P_Random()<<10)+FRACUNIT,
3187                         finecosine[angle>>ANGLETOFINESHIFT]);
3188                 mo->momy = FixedMul((P_Random()<<10)+FRACUNIT, 
3189                         finesine[angle>>ANGLETOFINESHIFT]);
3190                 mo->target = actor;
3191         }
3192 }
3193
3194
3195
3196 //
3197 // A_SinkMobj
3198 // Sink a mobj incrementally into the floor
3199 //
3200
3201 boolean A_SinkMobj(mobj_t *actor)
3202 {
3203         if (actor->floorclip <  actor->info->height)
3204         {
3205                 switch(actor->type)
3206                 {
3207                         case MT_THRUSTFLOOR_DOWN:
3208                         case MT_THRUSTFLOOR_UP:
3209                                 actor->floorclip += 6*FRACUNIT;
3210                                 break;
3211                         default:
3212                                 actor->floorclip += FRACUNIT;
3213                                 break;
3214                 }
3215                 return false;
3216         }
3217         return true;
3218 }
3219
3220 //
3221 // A_RaiseMobj
3222 // Raise a mobj incrementally from the floor to 
3223 // 
3224
3225 boolean A_RaiseMobj(mobj_t *actor)
3226 {
3227         int done = true;
3228
3229         // Raise a mobj from the ground
3230         if (actor->floorclip > 0)
3231         {
3232                 switch(actor->type)
3233                 {
3234                         case MT_WRAITHB:
3235                                 actor->floorclip -= 2*FRACUNIT;
3236                                 break;
3237                         case MT_THRUSTFLOOR_DOWN:
3238                         case MT_THRUSTFLOOR_UP:
3239                                 actor->floorclip -= actor->special2*FRACUNIT;
3240                                 break;
3241                         default:
3242                                 actor->floorclip -= 2*FRACUNIT;
3243                                 break;
3244                 }
3245                 if (actor->floorclip <= 0)
3246                 {
3247                         actor->floorclip = 0;
3248                         done=true;
3249                 }
3250                 else
3251                 {
3252                         done = false;
3253                 }
3254         }
3255         return done;            // Reached target height
3256 }
3257
3258
3259 //============================================================================
3260 // Wraith Variables
3261 //
3262 //      special1                                Internal index into floatbob
3263 //      special2
3264 //============================================================================
3265
3266 //
3267 // A_WraithInit
3268 //
3269
3270 void A_WraithInit(mobj_t *actor)
3271 {
3272         actor->z += 48<<FRACBITS;
3273         actor->special1 = 0;                    // index into floatbob
3274 }
3275
3276 void A_WraithRaiseInit(mobj_t *actor)
3277 {
3278         actor->flags2 &= ~MF2_DONTDRAW;
3279         actor->flags2 &= ~MF2_NONSHOOTABLE;
3280         actor->flags |= MF_SHOOTABLE|MF_SOLID;
3281         actor->floorclip = actor->info->height;
3282 }
3283
3284 void A_WraithRaise(mobj_t *actor)
3285 {
3286         if (A_RaiseMobj(actor))
3287         {
3288                 // Reached it's target height
3289                 P_SetMobjState(actor,S_WRAITH_CHASE1);
3290         }
3291
3292         P_SpawnDirt(actor, actor->radius);
3293 }
3294
3295
3296 void A_WraithMelee(mobj_t *actor)
3297 {
3298         int amount;
3299
3300         // Steal health from target and give to player
3301         if(P_CheckMeleeRange(actor) && (P_Random()<220))
3302         {
3303                 amount = HITDICE(2);
3304                 P_DamageMobj(actor->target, actor, actor, amount);
3305                 actor->health += amount;
3306         }
3307 }
3308
3309 void A_WraithMissile(mobj_t *actor)
3310 {
3311         mobj_t *mo;
3312
3313         mo = P_SpawnMissile(actor, actor->target, MT_WRAITHFX1);
3314         if (mo)
3315         {
3316                 S_StartSound(actor, SFX_WRAITH_MISSILE_FIRE);
3317         }
3318 }
3319
3320
3321 //
3322 // A_WraithFX2 - spawns sparkle tail of missile
3323 //
3324
3325 void A_WraithFX2(mobj_t *actor)
3326 {
3327         mobj_t *mo;
3328         angle_t angle;
3329         int i;
3330
3331         for (i=0; i<2; i++)
3332         {
3333                 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX2);
3334                 if(mo)
3335                 {
3336                         if (P_Random()<128)
3337                         {
3338                                  angle = actor->angle+(P_Random()<<22);
3339                         }
3340                         else
3341                         {
3342                                  angle = actor->angle-(P_Random()<<22);
3343                         }
3344                         mo->momz = 0;
3345                         mo->momx = FixedMul((P_Random()<<7)+FRACUNIT,
3346                                  finecosine[angle>>ANGLETOFINESHIFT]);
3347                         mo->momy = FixedMul((P_Random()<<7)+FRACUNIT, 
3348                                  finesine[angle>>ANGLETOFINESHIFT]);
3349                         mo->target = actor;
3350                         mo->floorclip = 10*FRACUNIT;
3351                 }
3352         }
3353 }
3354
3355
3356 // Spawn an FX3 around the actor during attacks
3357 void A_WraithFX3(mobj_t *actor)
3358 {
3359         mobj_t *mo;
3360         int numdropped=P_Random()%15;
3361         int i;
3362
3363         for (i=0; i<numdropped; i++)
3364         {
3365                   mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX3);
3366                   if(mo)
3367                   {
3368                                 mo->x += (P_Random()-128)<<11;
3369                                 mo->y += (P_Random()-128)<<11;
3370                                 mo->z += (P_Random()<<10);
3371                                 mo->target = actor;
3372                   }
3373         }
3374 }
3375
3376 // Spawn an FX4 during movement
3377 void A_WraithFX4(mobj_t *actor)
3378 {
3379         mobj_t *mo;
3380         int chance = P_Random();
3381         int spawn4,spawn5;
3382
3383         if (chance < 10)
3384         {
3385                 spawn4 = true;
3386                 spawn5 = false;
3387         }
3388         else if (chance < 20)
3389         {
3390                 spawn4 = false;
3391                 spawn5 = true;
3392         }
3393         else if (chance < 25)
3394         {
3395                 spawn4 = true;
3396                 spawn5 = true;
3397         }
3398         else
3399         {
3400                 spawn4 = false;
3401                 spawn5 = false;
3402         }
3403
3404         if (spawn4)
3405         {
3406                   mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX4);
3407                   if(mo)
3408                   {
3409                                 mo->x += (P_Random()-128)<<12;
3410                                 mo->y += (P_Random()-128)<<12;
3411                                 mo->z += (P_Random()<<10);
3412                                 mo->target = actor;
3413                   }
3414         }
3415         if (spawn5)
3416         {
3417                   mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX5);
3418                   if(mo)
3419                   {
3420                                 mo->x += (P_Random()-128)<<11;
3421                                 mo->y += (P_Random()-128)<<11;
3422                                 mo->z += (P_Random()<<10);
3423                                 mo->target = actor;
3424                   }
3425         }
3426 }
3427
3428
3429 void A_WraithLook(mobj_t *actor)
3430 {
3431 //      A_WraithFX4(actor);             // too expensive
3432         A_Look(actor);
3433 }
3434
3435
3436 void A_WraithChase(mobj_t *actor)
3437 {
3438         int weaveindex = actor->special1;
3439         actor->z += FloatBobOffsets[weaveindex];
3440         actor->special1 = (weaveindex+2)&63;
3441 //      if (actor->floorclip > 0)
3442 //      {
3443 //              P_SetMobjState(actor, S_WRAITH_RAISE2);
3444 //              return;
3445 //      }
3446         A_Chase(actor);
3447         A_WraithFX4(actor);
3448 }
3449
3450
3451
3452 //============================================================================
3453 // Ettin AI
3454 //============================================================================
3455
3456 void A_EttinAttack(mobj_t *actor)
3457 {
3458         if(P_CheckMeleeRange(actor))
3459         {
3460                 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
3461         }
3462 }
3463
3464
3465 void A_DropMace(mobj_t *actor)
3466 {
3467         mobj_t *mo;
3468
3469         mo = P_SpawnMobj(actor->x, actor->y,
3470                 actor->z+(actor->height>>1), MT_ETTIN_MACE);
3471         if (mo)
3472         {
3473                 mo->momx = (P_Random()-128)<<11;
3474                 mo->momy = (P_Random()-128)<<11;
3475                 mo->momz = FRACUNIT*10+(P_Random()<<10);
3476                 mo->target = actor;
3477         }
3478 }
3479
3480
3481 //============================================================================
3482 // Fire Demon AI
3483 //
3484 // special1                     index into floatbob
3485 // special2                     whether strafing or not
3486 //============================================================================
3487
3488 void A_FiredSpawnRock(mobj_t *actor)
3489 {
3490         mobj_t *mo;
3491         int x,y,z;
3492         int rtype = 0; /* jim gcc disappointed me here */
3493
3494         switch(P_Random()%5)
3495         {
3496                 case 0:
3497                         rtype = MT_FIREDEMON_FX1;
3498                         break;
3499                 case 1:
3500                         rtype = MT_FIREDEMON_FX2;
3501                         break;
3502                 case 2:
3503                         rtype = MT_FIREDEMON_FX3;
3504                         break;
3505                 case 3:
3506                         rtype = MT_FIREDEMON_FX4;
3507                         break;
3508                 case 4:
3509                         rtype = MT_FIREDEMON_FX5;
3510                         break;
3511         }
3512
3513         x = actor->x + ((P_Random()-128) << 12);
3514         y = actor->y + ((P_Random()-128) << 12);
3515         z = actor->z + ((P_Random()) << 11);
3516         mo = P_SpawnMobj(x,y,z,rtype);
3517         if (mo)
3518         {
3519                 mo->target = actor;
3520                 mo->momx = (P_Random()-128)<<10;
3521                 mo->momy = (P_Random()-128)<<10;
3522                 mo->momz = (P_Random()<<10);
3523                 mo->special1 = 2;               // Number bounces
3524         }
3525
3526         // Initialize fire demon
3527         actor->special2 = 0;
3528         actor->flags &= ~MF_JUSTATTACKED;
3529 }
3530
3531 void A_FiredRocks(mobj_t *actor)
3532 {
3533         A_FiredSpawnRock(actor);
3534         A_FiredSpawnRock(actor);
3535         A_FiredSpawnRock(actor);
3536         A_FiredSpawnRock(actor);
3537         A_FiredSpawnRock(actor);
3538 }
3539
3540 void A_FiredAttack(mobj_t *actor)
3541 {
3542         mobj_t *mo;
3543         mo = P_SpawnMissile(actor, actor->target, MT_FIREDEMON_FX6);
3544         if (mo) S_StartSound(actor, SFX_FIRED_ATTACK);
3545 }
3546
3547 void A_SmBounce(mobj_t *actor)
3548 {
3549         // give some more momentum (x,y,&z)
3550         actor->z = actor->floorz + FRACUNIT;
3551         actor->momz = (2*FRACUNIT) + (P_Random()<<10);
3552         actor->momx = P_Random()%3<<FRACBITS;
3553         actor->momy = P_Random()%3<<FRACBITS;
3554 }
3555
3556
3557 #define FIREDEMON_ATTACK_RANGE  64*8*FRACUNIT
3558
3559 void A_FiredChase(mobj_t *actor)
3560 {
3561         int weaveindex = actor->special1;
3562         mobj_t *target = actor->target;
3563         angle_t ang;
3564         fixed_t dist;
3565
3566         if(actor->reactiontime) actor->reactiontime--;
3567         if(actor->threshold) actor->threshold--;
3568
3569         // Float up and down
3570         actor->z += FloatBobOffsets[weaveindex];
3571         actor->special1 = (weaveindex+2)&63;
3572
3573         // Insure it stays above certain height
3574         if (actor->z < actor->floorz + (64*FRACUNIT))
3575         {
3576                 actor->z += 2*FRACUNIT;
3577         }
3578
3579         if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
3580         {       // Invalid target
3581                 P_LookForPlayers(actor,true);
3582                 return;
3583         }
3584
3585         // Strafe
3586         if (actor->special2 > 0)
3587         {
3588                 actor->special2--;
3589         }
3590         else
3591         {
3592                 actor->special2 = 0;
3593                 actor->momx = actor->momy = 0;
3594                 dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
3595                 if (dist < FIREDEMON_ATTACK_RANGE)
3596                 {
3597                         if (P_Random()<30)
3598                         {
3599                                 ang = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
3600                                 if (P_Random()<128)
3601                                         ang += ANGLE_90;
3602                                 else
3603                                         ang -= ANGLE_90;
3604                                 ang>>=ANGLETOFINESHIFT;
3605                                 actor->momx = FixedMul(8*FRACUNIT, finecosine[ang]);
3606                                 actor->momy = FixedMul(8*FRACUNIT, finesine[ang]);
3607                                 actor->special2 = 3;            // strafe time
3608                         }
3609                 }
3610         }
3611
3612         FaceMovementDirection(actor);
3613
3614         // Normal movement
3615         if (!actor->special2)
3616         {
3617                 if (--actor->movecount<0 || !P_Move (actor))
3618                 {
3619                         P_NewChaseDir (actor);
3620                 }
3621         }
3622
3623         // Do missile attack
3624         if (!(actor->flags&MF_JUSTATTACKED))
3625         {
3626                 if (P_CheckMissileRange(actor) && (P_Random()<20))
3627                 {
3628                         P_SetMobjState (actor, actor->info->missilestate);
3629                         actor->flags |= MF_JUSTATTACKED;
3630                         return;
3631                 }
3632         }
3633         else
3634         {
3635                 actor->flags &= ~MF_JUSTATTACKED;
3636         }
3637
3638         // make active sound
3639         if(actor->info->activesound && P_Random() < 3)
3640         {
3641                 S_StartSound(actor, actor->info->activesound);
3642         }
3643 }
3644
3645 void A_FiredSplotch(mobj_t *actor)
3646 {
3647         mobj_t *mo;
3648
3649         mo = P_SpawnMobj(actor->x,actor->y,actor->z, MT_FIREDEMON_SPLOTCH1);
3650         if (mo)
3651         {
3652                 mo->momx = (P_Random()-128)<<11;
3653                 mo->momy = (P_Random()-128)<<11;
3654                 mo->momz = FRACUNIT*3 + (P_Random()<<10);
3655         }
3656         mo = P_SpawnMobj(actor->x,actor->y,actor->z, MT_FIREDEMON_SPLOTCH2);
3657         if (mo)
3658         {
3659                 mo->momx = (P_Random()-128)<<11;
3660                 mo->momy = (P_Random()-128)<<11;
3661                 mo->momz = FRACUNIT*3 + (P_Random()<<10);
3662         }
3663 }
3664
3665
3666 //============================================================================
3667 //
3668 // A_IceGuyLook
3669 //
3670 //============================================================================
3671
3672 void A_IceGuyLook(mobj_t *actor)
3673 {
3674         fixed_t dist;
3675         fixed_t an;
3676
3677         A_Look(actor);
3678         if(P_Random() < 64)
3679         {
3680                 dist = ((P_Random()-128)*actor->radius)>>7;
3681                 an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
3682
3683                 P_SpawnMobj(actor->x+FixedMul(dist, finecosine[an]),
3684                         actor->y+FixedMul(dist, finesine[an]), actor->z+60*FRACUNIT,
3685                         MT_ICEGUY_WISP1+(P_Random()&1));
3686         }
3687 }
3688
3689 //============================================================================
3690 //
3691 // A_IceGuyChase
3692 //
3693 //============================================================================
3694
3695 void A_IceGuyChase(mobj_t *actor)
3696 {
3697         fixed_t dist;
3698         fixed_t an;
3699         mobj_t *mo;
3700
3701         A_Chase(actor);
3702         if(P_Random() < 128)
3703         {
3704                 dist = ((P_Random()-128)*actor->radius)>>7;
3705                 an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
3706
3707                 mo = P_SpawnMobj(actor->x+FixedMul(dist, finecosine[an]),
3708                         actor->y+FixedMul(dist, finesine[an]), actor->z+60*FRACUNIT,
3709                         MT_ICEGUY_WISP1+(P_Random()&1));
3710                 if(mo)
3711                 {
3712                         mo->momx = actor->momx;
3713                         mo->momy = actor->momy;
3714                         mo->momz = actor->momz;
3715                         mo->target = actor;
3716                 }
3717         }
3718 }
3719
3720 //============================================================================
3721 //
3722 // A_IceGuyAttack
3723 //
3724 //============================================================================
3725
3726 void A_IceGuyAttack(mobj_t *actor)
3727 {
3728         fixed_t an;
3729
3730         if(!actor->target) 
3731         {
3732                 return;
3733         }
3734         an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
3735         P_SpawnMissileXYZ(actor->x+FixedMul(actor->radius>>1,
3736                 finecosine[an]), actor->y+FixedMul(actor->radius>>1,
3737                 finesine[an]), actor->z+40*FRACUNIT, actor, actor->target,
3738                 MT_ICEGUY_FX);
3739         an = (actor->angle-ANG90)>>ANGLETOFINESHIFT;
3740         P_SpawnMissileXYZ(actor->x+FixedMul(actor->radius>>1,
3741                 finecosine[an]), actor->y+FixedMul(actor->radius>>1,
3742                 finesine[an]), actor->z+40*FRACUNIT, actor, actor->target,
3743                 MT_ICEGUY_FX);
3744         S_StartSound(actor, actor->info->attacksound);
3745 }
3746
3747 //============================================================================
3748 //
3749 // A_IceGuyMissilePuff
3750 //
3751 //============================================================================
3752
3753 void A_IceGuyMissilePuff(mobj_t *actor)
3754 {
3755         mobj_t *mo;
3756         mo = P_SpawnMobj(actor->x, actor->y, actor->z+2*FRACUNIT, MT_ICEFX_PUFF);
3757 }
3758
3759 //============================================================================
3760 //
3761 // A_IceGuyDie
3762 //
3763 //============================================================================
3764
3765 void A_IceGuyDie(mobj_t *actor)
3766 {
3767         void A_FreezeDeathChunks(mobj_t *actor);
3768
3769         actor->momx = 0;
3770         actor->momy = 0;
3771         actor->momz = 0;
3772         actor->height <<= 2;
3773         A_FreezeDeathChunks(actor);
3774 }
3775
3776 //============================================================================
3777 //
3778 // A_IceGuyMissileExplode
3779 //
3780 //============================================================================
3781
3782 void A_IceGuyMissileExplode(mobj_t *actor)
3783 {
3784         mobj_t *mo;
3785         int i;
3786
3787         for(i = 0; i < 8; i++)
3788         {
3789                 mo = P_SpawnMissileAngle(actor, MT_ICEGUY_FX2, i*ANG45, -0.3*FRACUNIT);
3790                 if(mo)
3791                 {
3792                         mo->target = actor->target;
3793                 }
3794         }
3795 }
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805 //============================================================================
3806 //
3807 //      Sorcerer stuff
3808 //
3809 // Sorcerer Variables
3810 //              special1                Angle of ball 1 (all others relative to that)
3811 //              special2                which ball to stop at in stop mode (MT_???)
3812 //              args[0]                 Denfense time
3813 //              args[1]                 Number of full rotations since stopping mode
3814 //              args[2]                 Target orbit speed for acceleration/deceleration
3815 //              args[3]                 Movement mode (see SORC_ macros)
3816 //              args[4]                 Current ball orbit speed
3817 //      Sorcerer Ball Variables
3818 //              special1                Previous angle of ball (for woosh)
3819 //              special2                Countdown of rapid fire (FX4)
3820 //              args[0]                 If set, don't play the bounce sound when bouncing
3821 //============================================================================
3822
3823 #define SORCBALL_INITIAL_SPEED          7
3824 #define SORCBALL_TERMINAL_SPEED         25
3825 #define SORCBALL_SPEED_ROTATIONS        5
3826 #define SORC_DEFENSE_TIME                       255
3827 #define SORC_DEFENSE_HEIGHT                     45
3828 #define BOUNCE_TIME_UNIT                        (35/2)
3829 #define SORCFX4_RAPIDFIRE_TIME          (6*3)           // 3 seconds
3830 #define SORCFX4_SPREAD_ANGLE            20
3831
3832 #define SORC_DECELERATE         0
3833 #define SORC_ACCELERATE         1
3834 #define SORC_STOPPING           2
3835 #define SORC_FIRESPELL          3
3836 #define SORC_STOPPED            4
3837 #define SORC_NORMAL                     5
3838 #define SORC_FIRING_SPELL       6
3839
3840 #define BALL1_ANGLEOFFSET       0
3841 #define BALL2_ANGLEOFFSET       (ANGLE_MAX/3)
3842 #define BALL3_ANGLEOFFSET       ((ANGLE_MAX/3)*2)
3843
3844 void A_SorcBallOrbit(mobj_t *actor);
3845 void A_SorcSpinBalls(mobj_t *actor);
3846 void A_SpeedBalls(mobj_t *actor);
3847 void A_SlowBalls(mobj_t *actor);
3848 void A_StopBalls(mobj_t *actor);
3849 void A_AccelBalls(mobj_t *actor);
3850 void A_DecelBalls(mobj_t *actor);
3851 void A_SorcBossAttack(mobj_t *actor);
3852 void A_SpawnFizzle(mobj_t *actor);
3853 void A_CastSorcererSpell(mobj_t *actor);
3854 void A_SorcUpdateBallAngle(mobj_t *actor);
3855 void A_BounceCheck(mobj_t *actor);
3856 void A_SorcFX1Seek(mobj_t *actor);
3857 void A_SorcOffense1(mobj_t *actor);
3858 void A_SorcOffense2(mobj_t *actor);
3859
3860
3861 // Spawn spinning balls above head - actor is sorcerer
3862 void A_SorcSpinBalls(mobj_t *actor)
3863 {
3864         mobj_t *mo;
3865         fixed_t z;
3866
3867         A_SlowBalls(actor);
3868         actor->args[0] = 0;                                                                     // Currently no defense
3869         actor->args[3] = SORC_NORMAL;
3870         actor->args[4] = SORCBALL_INITIAL_SPEED;                // Initial orbit speed
3871         actor->special1 = ANGLE_1;
3872         z = actor->z - actor->floorclip + actor->info->height;
3873         
3874         mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL1);
3875         if (mo)
3876         {
3877                 mo->target = actor;
3878                 mo->special2 = SORCFX4_RAPIDFIRE_TIME;
3879         }
3880         mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL2);
3881         if (mo) mo->target = actor;
3882         mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL3);
3883         if (mo) mo->target = actor;
3884 }
3885
3886
3887 //
3888 // A_SorcBallOrbit() ==========================================
3889 //
3890
3891 void A_SorcBallOrbit(mobj_t *actor)
3892 {
3893         int x,y;
3894         angle_t angle = 0, baseangle; /* jim initialiser added */
3895         int mode = actor->target->args[3];
3896         mobj_t *parent = (mobj_t *)actor->target;
3897         int dist = parent->radius - (actor->radius<<1);
3898         angle_t prevangle = actor->special1;
3899         
3900         if (actor->target->health <= 0)
3901                 P_SetMobjState(actor, actor->info->painstate);
3902
3903         baseangle = (angle_t)parent->special1;
3904         switch(actor->type)
3905         {
3906                 case MT_SORCBALL1:
3907                         angle = baseangle + BALL1_ANGLEOFFSET;
3908                         break;
3909                 case MT_SORCBALL2:
3910                         angle = baseangle + BALL2_ANGLEOFFSET;
3911                         break;
3912                 case MT_SORCBALL3:
3913                         angle = baseangle + BALL3_ANGLEOFFSET;
3914                         break;
3915                 default:
3916                         I_Error("corrupted sorcerer");
3917                         break;
3918         }
3919         actor->angle = angle;
3920         angle >>= ANGLETOFINESHIFT;
3921
3922         switch(mode)
3923         {
3924                 case SORC_NORMAL:                               // Balls rotating normally
3925                         A_SorcUpdateBallAngle(actor);
3926                         break;
3927                 case SORC_DECELERATE:           // Balls decelerating
3928                         A_DecelBalls(actor);
3929                         A_SorcUpdateBallAngle(actor);
3930                         break;
3931                 case SORC_ACCELERATE:           // Balls accelerating
3932                         A_AccelBalls(actor);
3933                         A_SorcUpdateBallAngle(actor);
3934                         break;
3935                 case SORC_STOPPING:                     // Balls stopping
3936                         if ((parent->special2 == actor->type) &&
3937                                  (parent->args[1] > SORCBALL_SPEED_ROTATIONS) &&
3938                                  (abs(angle - (parent->angle>>ANGLETOFINESHIFT)) < (30<<5)))
3939                         {
3940                                 // Can stop now
3941                                 actor->target->args[3] = SORC_FIRESPELL;
3942                                 actor->target->args[4] = 0;
3943                                 // Set angle so ball angle == sorcerer angle
3944                                 switch(actor->type)
3945                                 {
3946                                         case MT_SORCBALL1:
3947                                                 parent->special1 = (int)(parent->angle -
3948                                                                                                                 BALL1_ANGLEOFFSET);
3949                                                 break;
3950                                         case MT_SORCBALL2:
3951                                                 parent->special1 = (int)(parent->angle -
3952                                                                                                                 BALL2_ANGLEOFFSET);
3953                                                 break;
3954                                         case MT_SORCBALL3:
3955                                                 parent->special1 = (int)(parent->angle -
3956                                                                                                                 BALL3_ANGLEOFFSET);
3957                                                 break;
3958                                         default:
3959                                                 break;
3960                                 }
3961                         }
3962                         else
3963                         {
3964                                 A_SorcUpdateBallAngle(actor);
3965                         }
3966                         break;
3967                 case SORC_FIRESPELL:                    // Casting spell
3968                         if (parent->special2 == actor->type)
3969                         {
3970                                 // Put sorcerer into special throw spell anim
3971                                 if (parent->health > 0)
3972                                         P_SetMobjStateNF(parent, S_SORC_ATTACK1);
3973
3974                                 if (actor->type==MT_SORCBALL1 && P_Random()<200)
3975                                 {
3976                                         S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
3977                                         actor->special2 = SORCFX4_RAPIDFIRE_TIME;
3978                                         actor->args[4] = 128;
3979                                         parent->args[3] = SORC_FIRING_SPELL;
3980                                 }
3981                                 else
3982                                 {
3983                                         A_CastSorcererSpell(actor);
3984                                         parent->args[3] = SORC_STOPPED;
3985                                 }
3986                         }
3987                         break;
3988                 case SORC_FIRING_SPELL:
3989                         if (parent->special2 == actor->type)
3990                         {
3991                                 if (actor->special2-- <= 0)
3992                                 {
3993                                         // Done rapid firing 
3994                                         parent->args[3] = SORC_STOPPED;
3995                                         // Back to orbit balls
3996                                         if (parent->health > 0)
3997                                                 P_SetMobjStateNF(parent, S_SORC_ATTACK4);       
3998                                 }
3999                                 else
4000                                 {
4001                                         // Do rapid fire spell
4002                                         A_SorcOffense2(actor);
4003                                 }
4004                         }
4005                         break;
4006                 case SORC_STOPPED:                      // Balls stopped
4007                 default:
4008                         break;
4009         }
4010
4011         if ((angle < prevangle) && (parent->args[4]==SORCBALL_TERMINAL_SPEED))
4012         {
4013                 parent->args[1]++;                      // Bump rotation counter
4014                 // Completed full rotation - make woosh sound
4015                 S_StartSound(actor, SFX_SORCERER_BALLWOOSH);
4016         }
4017         actor->special1 = angle;                // Set previous angle
4018         x = parent->x + FixedMul(dist, finecosine[angle]);
4019         y = parent->y + FixedMul(dist, finesine[angle]);
4020         actor->x = x;
4021         actor->y = y;
4022         actor->z = parent->z - parent->floorclip + parent->info->height;
4023 }
4024
4025
4026 //
4027 // Set balls to speed mode - actor is sorcerer
4028 //
4029 void A_SpeedBalls(mobj_t *actor)
4030 {
4031         actor->args[3] = SORC_ACCELERATE;                               // speed mode
4032         actor->args[2] = SORCBALL_TERMINAL_SPEED;               // target speed
4033 }
4034
4035
4036 //
4037 // Set balls to slow mode - actor is sorcerer
4038 //
4039 void A_SlowBalls(mobj_t *actor)
4040 {
4041         actor->args[3] = SORC_DECELERATE;                               // slow mode
4042         actor->args[2] = SORCBALL_INITIAL_SPEED;                // target speed
4043 }
4044
4045
4046 //
4047 // Instant stop when rotation gets to ball in special2
4048 //              actor is sorcerer
4049 //
4050 void A_StopBalls(mobj_t *actor)
4051 {
4052         int chance = P_Random();
4053         actor->args[3] = SORC_STOPPING;                         // stopping mode
4054         actor->args[1] = 0;                                                     // Reset rotation counter
4055
4056         if ((actor->args[0] <= 0) && (chance < 200))
4057         {
4058                 actor->special2 = MT_SORCBALL2;                 // Blue
4059         }
4060         else if((actor->health < (actor->info->spawnhealth >> 1)) &&
4061                         (chance < 200))
4062         {
4063                 actor->special2 = MT_SORCBALL3;                 // Green
4064         }
4065         else
4066         {
4067                 actor->special2 = MT_SORCBALL1;                 // Yellow
4068         }
4069
4070
4071 }
4072
4073
4074 //
4075 // Increase ball orbit speed - actor is ball
4076 //
4077 void A_AccelBalls(mobj_t *actor)
4078 {
4079         mobj_t *sorc = actor->target;
4080
4081         if (sorc->args[4] < sorc->args[2])
4082         {
4083                 sorc->args[4]++;
4084         }
4085         else
4086         {
4087                 sorc->args[3] = SORC_NORMAL;
4088                 if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED)
4089                 {
4090                         // Reached terminal velocity - stop balls
4091                         A_StopBalls(sorc);
4092                 }
4093         }
4094 }
4095
4096
4097 // Decrease ball orbit speed - actor is ball
4098 void A_DecelBalls(mobj_t *actor)
4099 {
4100         mobj_t *sorc = actor->target;
4101
4102         if (sorc->args[4] > sorc->args[2])
4103         {
4104                 sorc->args[4]--;
4105         }
4106         else
4107         {
4108                 sorc->args[3] = SORC_NORMAL;
4109         }
4110 }
4111
4112
4113 // Update angle if first ball - actor is ball
4114 void A_SorcUpdateBallAngle(mobj_t *actor)
4115 {
4116         if (actor->type == MT_SORCBALL1)
4117         {
4118                 actor->target->special1 += ANGLE_1*actor->target->args[4];
4119         }
4120 }
4121
4122
4123 // actor is ball
4124 void A_CastSorcererSpell(mobj_t *actor)
4125 {
4126         mobj_t *mo;
4127         int spell = actor->type;
4128         angle_t ang1,ang2;
4129         fixed_t z;
4130         mobj_t *parent = actor->target;
4131
4132         S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
4133
4134         // Put sorcerer into throw spell animation
4135         if (parent->health > 0) P_SetMobjStateNF(parent, S_SORC_ATTACK4);
4136
4137         switch(spell)
4138         {
4139                 case MT_SORCBALL1:                              // Offensive
4140                         A_SorcOffense1(actor);
4141                         break;
4142                 case MT_SORCBALL2:                              // Defensive
4143                         z = parent->z - parent->floorclip + 
4144                                 SORC_DEFENSE_HEIGHT*FRACUNIT;
4145                         mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCFX2);
4146                         parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE;
4147                         parent->args[0] = SORC_DEFENSE_TIME;
4148                         if (mo) mo->target = parent;
4149                         break;
4150                 case MT_SORCBALL3:                              // Reinforcements
4151                         ang1 = actor->angle - ANGLE_45;
4152                         ang2 = actor->angle + ANGLE_45;
4153                         if(actor->health < (actor->info->spawnhealth/3))
4154                         {       // Spawn 2 at a time
4155                                 mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
4156                                 if (mo) mo->target = parent;
4157                                 mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang2, 4*FRACUNIT);
4158                                 if (mo) mo->target = parent;
4159                         }                       
4160                         else
4161                         {
4162                                 if (P_Random() < 128)
4163                                         ang1 = ang2;
4164                                 mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
4165                                 if (mo) mo->target = parent;
4166                         }
4167                         break;
4168                 default:
4169                         break;
4170         }
4171 }
4172
4173 /*
4174 void A_SpawnReinforcements(mobj_t *actor)
4175 {
4176         mobj_t *parent = actor->target;
4177         mobj_t *mo;
4178         angle_t ang;
4179
4180         ang = ANGLE_1 * P_Random();
4181         mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5*FRACUNIT);
4182         if (mo) mo->target = parent;
4183 }
4184 */
4185
4186 // actor is ball
4187 void A_SorcOffense1(mobj_t *actor)
4188 {
4189         mobj_t *mo;
4190         angle_t ang1,ang2;
4191         mobj_t *parent=(mobj_t *)actor->target;
4192
4193         ang1 = actor->angle + ANGLE_1*70;
4194         ang2 = actor->angle - ANGLE_1*70;
4195         mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang1, 0);
4196         if (mo)
4197         {
4198                 mo->target = parent;
4199                 mo->special1 = (int)parent->target;
4200                 mo->args[4] = BOUNCE_TIME_UNIT;
4201                 mo->args[3] = 15;                               // Bounce time in seconds
4202         }
4203         mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang2, 0);
4204         if (mo)
4205         {
4206                 mo->target = parent;
4207                 mo->special1 = (int)parent->target;
4208                 mo->args[4] = BOUNCE_TIME_UNIT;
4209                 mo->args[3] = 15;                               // Bounce time in seconds
4210         }
4211 }
4212
4213
4214 // Actor is ball
4215 void A_SorcOffense2(mobj_t *actor)
4216 {
4217         angle_t ang1;
4218         mobj_t *mo;
4219         int delta, index;
4220         mobj_t *parent = actor->target;
4221         mobj_t *dest = parent->target;
4222         int dist;
4223
4224         index = actor->args[4] << 5;
4225         actor->args[4] += 15;
4226         delta = (finesine[index])*SORCFX4_SPREAD_ANGLE;
4227         delta = (delta>>FRACBITS)*ANGLE_1;
4228         ang1 = actor->angle + delta;
4229         mo = P_SpawnMissileAngle(parent, MT_SORCFX4, ang1, 0);
4230         if (mo)
4231         {
4232                 mo->special2 = 35*5/2;          // 5 seconds
4233                 dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y);
4234                 dist = dist/mo->info->speed;
4235                 if(dist < 1) dist = 1;
4236                 mo->momz = (dest->z-mo->z)/dist;
4237         }
4238 }
4239
4240
4241 // Resume ball spinning
4242 void A_SorcBossAttack(mobj_t *actor)
4243 {
4244         actor->args[3] = SORC_ACCELERATE;
4245         actor->args[2] = SORCBALL_INITIAL_SPEED;
4246 }
4247
4248
4249 // spell cast magic fizzle
4250 void A_SpawnFizzle(mobj_t *actor)
4251 {
4252         fixed_t x,y,z;
4253         fixed_t dist = 5*FRACUNIT;
4254         angle_t angle = actor->angle >> ANGLETOFINESHIFT;
4255         fixed_t speed = actor->info->speed;
4256         angle_t rangle;
4257         mobj_t *mo;
4258         int ix;
4259
4260         x = actor->x + FixedMul(dist,finecosine[angle]);
4261         y = actor->y + FixedMul(dist,finesine[angle]);
4262         z = actor->z - actor->floorclip + (actor->height>>1);
4263         for (ix=0; ix<5; ix++)
4264         {
4265                 mo = P_SpawnMobj(x,y,z,MT_SORCSPARK1);
4266                 if (mo)
4267                 {
4268                         rangle = angle + ((P_Random()%5) << 1);
4269                         mo->momx = FixedMul(P_Random()%speed,finecosine[rangle]);
4270                         mo->momy = FixedMul(P_Random()%speed,finesine[rangle]);
4271                         mo->momz = FRACUNIT*2;
4272                 }
4273         }
4274 }
4275
4276
4277 //============================================================================
4278 // Yellow spell - offense
4279 //============================================================================
4280
4281 void A_SorcFX1Seek(mobj_t *actor)
4282 {
4283         A_BounceCheck(actor);
4284         P_SeekerMissile(actor,ANGLE_1*2,ANGLE_1*6);
4285 }
4286
4287
4288 //============================================================================
4289 // Blue spell - defense
4290 //============================================================================
4291 //
4292 // FX2 Variables
4293 //              special1                current angle
4294 //              special2
4295 //              args[0]         0 = CW,  1 = CCW
4296 //              args[1]         
4297 //============================================================================
4298
4299 // Split ball in two
4300 void A_SorcFX2Split(mobj_t *actor)
4301 {
4302         mobj_t *mo;
4303
4304         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
4305         if (mo)
4306         {
4307                 mo->target = actor->target;
4308                 mo->args[0] = 0;                                                                        // CW
4309                 mo->special1 = actor->angle;                                    // Set angle
4310                 P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
4311         }
4312         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
4313         if (mo)
4314         {
4315                 mo->target = actor->target;
4316                 mo->args[0] = 1;                                                                        // CCW
4317                 mo->special1 = actor->angle;                                    // Set angle
4318                 P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
4319         }
4320         P_SetMobjStateNF(actor, S_NULL);
4321 }
4322
4323
4324 // Orbit FX2 about sorcerer
4325 void A_SorcFX2Orbit(mobj_t *actor)
4326 {
4327         angle_t angle;
4328         fixed_t x,y,z;
4329         mobj_t *parent = actor->target;
4330         fixed_t dist = parent->info->radius;
4331
4332         if ((parent->health <= 0) ||            // Sorcerer is dead
4333                 (!parent->args[0]))                             // Time expired
4334         {
4335                 P_SetMobjStateNF(actor, actor->info->deathstate);
4336                 parent->args[0] = 0;
4337                 parent->flags2 &= ~MF2_REFLECTIVE;
4338                 parent->flags2 &= ~MF2_INVULNERABLE;
4339         }
4340
4341         if (actor->args[0] && (parent->args[0]-- <= 0))         // Time expired
4342         {
4343                 P_SetMobjStateNF(actor, actor->info->deathstate);
4344                 parent->args[0] = 0;
4345                 parent->flags2 &= ~MF2_REFLECTIVE;
4346         }
4347
4348         // Move to new position based on angle
4349         if (actor->args[0])             // Counter clock-wise
4350         {
4351                 actor->special1 += ANGLE_1*10;
4352                 angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
4353                 x = parent->x + FixedMul(dist, finecosine[angle]);
4354                 y = parent->y + FixedMul(dist, finesine[angle]);
4355                 z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
4356                 z += FixedMul(15*FRACUNIT,finecosine[angle]);
4357                 // Spawn trailer
4358                 P_SpawnMobj(x,y,z, MT_SORCFX2_T1);
4359         }
4360         else                                                    // Clock wise
4361         {
4362                 actor->special1 -= ANGLE_1*10;
4363                 angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
4364                 x = parent->x + FixedMul(dist, finecosine[angle]);
4365                 y = parent->y + FixedMul(dist, finesine[angle]);
4366                 z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
4367                 z += FixedMul(20*FRACUNIT,finesine[angle]);
4368                 // Spawn trailer
4369                 P_SpawnMobj(x,y,z, MT_SORCFX2_T1);
4370         }
4371
4372         actor->x = x;
4373         actor->y = y;
4374         actor->z = z;
4375 }
4376
4377
4378
4379 //============================================================================
4380 // Green spell - spawn bishops
4381 //============================================================================
4382
4383 void A_SpawnBishop(mobj_t *actor)
4384 {
4385         mobj_t *mo;
4386         mo=P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOP);
4387         if(mo)
4388         {
4389                 if(!P_TestMobjLocation(mo))
4390                 {
4391                         P_SetMobjState(mo, S_NULL);
4392                 }
4393         }
4394         P_SetMobjState(actor, S_NULL);
4395 }
4396
4397 /*
4398 void A_SmokePuffEntry(mobj_t *actor)
4399 {
4400         P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
4401 }
4402 */
4403
4404 void A_SmokePuffExit(mobj_t *actor)
4405 {
4406         P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKEEXIT);
4407 }
4408
4409 void A_SorcererBishopEntry(mobj_t *actor)
4410 {
4411         P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX3_EXPLOSION);
4412         S_StartSound(actor, actor->info->seesound);
4413 }
4414
4415
4416 //============================================================================
4417 // FX4 - rapid fire balls
4418 //============================================================================
4419
4420 void A_SorcFX4Check(mobj_t *actor)
4421 {
4422         if (actor->special2-- <= 0)
4423         {
4424                 P_SetMobjStateNF(actor, actor->info->deathstate);
4425         }
4426 }
4427
4428 //============================================================================
4429 // Ball death - spawn stuff
4430 //============================================================================
4431
4432 void A_SorcBallPop(mobj_t *actor)
4433 {
4434         S_StartSound(NULL, SFX_SORCERER_BALLPOP);
4435         actor->flags &= ~MF_NOGRAVITY;
4436         actor->flags2 |= MF2_LOGRAV;
4437         actor->momx = ((P_Random()%10)-5) << FRACBITS;
4438         actor->momy = ((P_Random()%10)-5) << FRACBITS;
4439         actor->momz = (2+(P_Random()%3)) << FRACBITS;
4440         actor->special2 = 4*FRACUNIT;           // Initial bounce factor
4441         actor->args[4] = BOUNCE_TIME_UNIT;      // Bounce time unit
4442         actor->args[3] = 5;                                     // Bounce time in seconds
4443 }
4444
4445
4446
4447 void A_BounceCheck(mobj_t *actor)
4448 {
4449         if (actor->args[4]-- <= 0)
4450         {
4451                 if (actor->args[3]-- <= 0)
4452                 {
4453                         P_SetMobjState(actor, actor->info->deathstate);
4454                         switch(actor->type)
4455                         {
4456                                 case MT_SORCBALL1:
4457                                 case MT_SORCBALL2:
4458                                 case MT_SORCBALL3:
4459                                         S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
4460                                         break;
4461                                 case MT_SORCFX1:
4462                                         S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
4463                                         break;
4464                                 default:
4465                                         break;
4466                         }
4467                 }
4468                 else
4469                 {
4470                         actor->args[4] = BOUNCE_TIME_UNIT;
4471                 }
4472         }
4473 }
4474
4475
4476
4477
4478 //============================================================================
4479 // Class Bosses
4480 //============================================================================
4481 #define CLASS_BOSS_STRAFE_RANGE 64*10*FRACUNIT
4482
4483 void A_FastChase(mobj_t *actor)
4484 {
4485         int delta;
4486         fixed_t dist;
4487         angle_t ang;
4488         mobj_t *target;
4489
4490         if(actor->reactiontime)
4491         {
4492                 actor->reactiontime--;
4493         }
4494
4495         // Modify target threshold
4496         if(actor->threshold)
4497         {
4498                 actor->threshold--;
4499         }
4500
4501         if(gameskill == sk_nightmare)
4502         { // Monsters move faster in nightmare mode
4503                 actor->tics -= actor->tics/2;
4504                 if(actor->tics < 3)
4505                 {
4506                         actor->tics = 3;
4507                 }
4508         }
4509
4510 //
4511 // turn towards movement direction if not there yet
4512 //
4513         if(actor->movedir < 8)
4514         {
4515                 actor->angle &= (7<<29);
4516                 delta = actor->angle-(actor->movedir << 29);
4517                 if(delta > 0)
4518                 {
4519                         actor->angle -= ANG90/2;
4520                 }
4521                 else if(delta < 0)
4522                 {
4523                         actor->angle += ANG90/2;
4524                 }
4525         }
4526
4527         if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
4528         { // look for a new target
4529                 if(P_LookForPlayers(actor, true))
4530                 { // got a new target
4531                         return;
4532                 }
4533                 P_SetMobjState(actor, actor->info->spawnstate);
4534                 return;
4535         }
4536
4537 //
4538 // don't attack twice in a row
4539 //
4540         if(actor->flags & MF_JUSTATTACKED)
4541         {
4542                 actor->flags &= ~MF_JUSTATTACKED;
4543                 if (gameskill != sk_nightmare)
4544                         P_NewChaseDir (actor);
4545                 return;
4546         }
4547
4548         // Strafe
4549         if (actor->special2 > 0)
4550         {
4551                 actor->special2--;
4552         }
4553         else
4554         {
4555                 target = actor->target;
4556                 actor->special2 = 0;
4557                 actor->momx = actor->momy = 0;
4558                 dist=P_AproxDistance(actor->x - target->x,
4559                                                                 actor->y - target->y);
4560                 if (dist < CLASS_BOSS_STRAFE_RANGE)
4561                 {
4562                         if (P_Random()<100)
4563                         {
4564                                 ang = R_PointToAngle2(actor->x, actor->y,
4565                                                                         target->x, target->y);
4566                                 if (P_Random()<128)
4567                                         ang += ANGLE_90;
4568                                 else
4569                                         ang -= ANGLE_90;
4570                                 ang>>=ANGLETOFINESHIFT;
4571                                 actor->momx = FixedMul(13*FRACUNIT, finecosine[ang]);
4572                                 actor->momy = FixedMul(13*FRACUNIT, finesine[ang]);
4573                                 actor->special2 = 3;            // strafe time
4574                         }
4575                 }
4576         }
4577
4578 //
4579 // check for missile attack
4580 //
4581         if (actor->info->missilestate)
4582         {
4583                 if (gameskill < sk_nightmare && actor->movecount)
4584                         goto nomissile;
4585                 if (!P_CheckMissileRange (actor))
4586                         goto nomissile;
4587                 P_SetMobjState (actor, actor->info->missilestate);
4588                 actor->flags |= MF_JUSTATTACKED;
4589                 return;
4590         }
4591 nomissile:
4592
4593 //
4594 // possibly choose another target
4595 //
4596         if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
4597         {
4598                 if (P_LookForPlayers(actor,true))
4599                         return;         // got a new target
4600         }
4601
4602 //
4603 // chase towards player
4604 //
4605         if (!actor->special2)
4606         {
4607                 if (--actor->movecount<0 || !P_Move (actor))
4608                 {
4609                         P_NewChaseDir (actor);
4610                 }
4611         }
4612 }
4613
4614
4615 void A_FighterAttack(mobj_t *actor)
4616 {
4617         extern void A_FSwordAttack2(mobj_t *actor);
4618
4619         if(!actor->target) return;
4620         A_FSwordAttack2(actor);
4621 }
4622
4623
4624 void A_ClericAttack(mobj_t *actor)
4625 {
4626         extern void A_CHolyAttack3(mobj_t *actor);
4627
4628         if(!actor->target) return;
4629         A_CHolyAttack3(actor);
4630 }
4631
4632
4633
4634 void A_MageAttack(mobj_t *actor)
4635 {
4636         extern void A_MStaffAttack2(mobj_t *actor);
4637
4638         if(!actor->target) return;
4639         A_MStaffAttack2(actor);
4640 }
4641
4642 void A_ClassBossHealth(mobj_t *actor)
4643 {
4644         if (netgame && !deathmatch)             // co-op only
4645         {
4646                 if (!actor->special1)
4647                 {
4648                         actor->health *= 5;
4649                         actor->special1 = true;   // has been initialized
4650                 }
4651         }
4652 }
4653
4654
4655 //===========================================================================
4656 //
4657 // A_CheckFloor - Checks if an object hit the floor
4658 //
4659 //===========================================================================
4660
4661 void A_CheckFloor(mobj_t *actor)
4662 {
4663         if(actor->z <= actor->floorz)
4664         {
4665                 actor->z = actor->floorz;
4666                 actor->flags2 &= ~MF2_LOGRAV;
4667                 P_SetMobjState(actor, actor->info->deathstate);
4668         }
4669 }
4670
4671 //============================================================================
4672 //
4673 // A_FreezeDeath
4674 //
4675 //============================================================================
4676
4677 void A_FreezeDeath(mobj_t *actor)
4678 {
4679         actor->tics = 75+P_Random()+P_Random();
4680         actor->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD;
4681         actor->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE;
4682         actor->height <<= 2;
4683         S_StartSound(actor, SFX_FREEZE_DEATH);
4684
4685         if(actor->player)
4686         {
4687                 actor->player->damagecount = 0;
4688                 actor->player->poisoncount = 0;
4689                 actor->player->bonuscount = 0;
4690                 if(actor->player == &players[consoleplayer])
4691                 {
4692                         SB_PaletteFlash(false);
4693                 }
4694         }
4695         else if(actor->flags&MF_COUNTKILL && actor->special)
4696         { // Initiate monster death actions
4697                 P_ExecuteLineSpecial(actor->special, actor->args, NULL, 0, actor);
4698         }
4699 }
4700
4701 //============================================================================
4702 //
4703 // A_IceSetTics
4704 //
4705 //============================================================================
4706
4707 void A_IceSetTics(mobj_t *actor)
4708 {
4709         int floor;
4710
4711         actor->tics = 70+(P_Random()&63);
4712         floor = P_GetThingFloorType(actor);
4713         if(floor == FLOOR_LAVA)
4714         {
4715                 actor->tics >>= 2;
4716         }
4717         else if(floor == FLOOR_ICE)
4718         {
4719                 actor->tics <<= 1;
4720         }
4721 }
4722
4723 //============================================================================
4724 //
4725 // A_IceCheckHeadDone
4726 //
4727 //============================================================================
4728
4729 void A_IceCheckHeadDone(mobj_t *actor)
4730 {
4731         if(actor->special2 == 666)
4732         {
4733                 P_SetMobjState(actor, S_ICECHUNK_HEAD2);
4734         }
4735 }
4736
4737 //============================================================================
4738 //
4739 // A_FreezeDeathChunks
4740 //
4741 //============================================================================
4742
4743 void A_FreezeDeathChunks(mobj_t *actor)
4744 {
4745         int i;
4746         mobj_t *mo;
4747         
4748         if(actor->momx || actor->momy || actor->momz)
4749         {
4750                 actor->tics = 105;
4751                 return;
4752         }
4753         S_StartSound(actor, SFX_FREEZE_SHATTER);
4754
4755         for(i = 12+(P_Random()&15); i >= 0; i--)
4756         {
4757                 mo = P_SpawnMobj(actor->x+(((P_Random()-128)*actor->radius)>>7), 
4758                         actor->y+(((P_Random()-128)*actor->radius)>>7), 
4759                         actor->z+(P_Random()*actor->height/255), MT_ICECHUNK);
4760                 P_SetMobjState(mo, mo->info->spawnstate+(P_Random()%3));
4761                 if(mo)
4762                 {
4763                         mo->momz = FixedDiv(mo->z-actor->z, actor->height)<<2;
4764                         mo->momx = (P_Random()-P_Random())<<(FRACBITS-7);
4765                         mo->momy = (P_Random()-P_Random())<<(FRACBITS-7);
4766                         A_IceSetTics(mo); // set a random tic wait
4767                 }
4768         }
4769         for(i = 12+(P_Random()&15); i >= 0; i--)
4770         {
4771                 mo = P_SpawnMobj(actor->x+(((P_Random()-128)*actor->radius)>>7), 
4772                         actor->y+(((P_Random()-128)*actor->radius)>>7), 
4773                         actor->z+(P_Random()*actor->height/255), MT_ICECHUNK);
4774                 P_SetMobjState(mo, mo->info->spawnstate+(P_Random()%3));
4775                 if(mo)
4776                 {
4777                         mo->momz = FixedDiv(mo->z-actor->z, actor->height)<<2;
4778                         mo->momx = (P_Random()-P_Random())<<(FRACBITS-7);
4779                         mo->momy = (P_Random()-P_Random())<<(FRACBITS-7);
4780                         A_IceSetTics(mo); // set a random tic wait
4781                 }
4782         }
4783         if(actor->player)
4784         { // attach the player's view to a chunk of ice
4785                 mo = P_SpawnMobj(actor->x, actor->y, actor->z+VIEWHEIGHT, MT_ICECHUNK);
4786                 P_SetMobjState(mo, S_ICECHUNK_HEAD);
4787                 mo->momz = FixedDiv(mo->z-actor->z, actor->height)<<2;
4788                 mo->momx = (P_Random()-P_Random())<<(FRACBITS-7);
4789                 mo->momy = (P_Random()-P_Random())<<(FRACBITS-7);
4790                 mo->flags2 |= MF2_ICEDAMAGE; // used to force blue palette
4791                 mo->flags2 &= ~MF2_FLOORCLIP;
4792                 mo->player = actor->player;
4793                 actor->player = NULL;
4794                 mo->health = actor->health;
4795                 mo->angle = actor->angle;
4796                 mo->player->mo = mo;
4797                 mo->player->lookdir = 0;
4798         }
4799         P_RemoveMobjFromTIDList(actor);
4800         P_SetMobjState(actor, S_FREETARGMOBJ);
4801         actor->flags2 |= MF2_DONTDRAW;
4802 }
4803
4804 //===========================================================================
4805 // Korax Variables
4806 //      special1        last teleport destination
4807 //      special2        set if "below half" script not yet run
4808 //
4809 // Korax Scripts (reserved)
4810 //      249             Tell scripts that we are below half health
4811 //      250-254 Control scripts
4812 //      255             Death script
4813 //
4814 // Korax TIDs (reserved)
4815 //      245             Reserved for Korax himself
4816 //  248         Initial teleport destination
4817 //      249             Teleport destination
4818 //      250-254 For use in respective control scripts
4819 //      255             For use in death script (spawn spots)
4820 //===========================================================================
4821 #define KORAX_SPIRIT_LIFETIME   (5*(35/5))      // 5 seconds
4822 #define KORAX_COMMAND_HEIGHT    (120*FRACUNIT)
4823 #define KORAX_COMMAND_OFFSET    (27*FRACUNIT)
4824
4825 void KoraxFire1(mobj_t *actor, int type);
4826 void KoraxFire2(mobj_t *actor, int type);
4827 void KoraxFire3(mobj_t *actor, int type);
4828 void KoraxFire4(mobj_t *actor, int type);
4829 void KoraxFire5(mobj_t *actor, int type);
4830 void KoraxFire6(mobj_t *actor, int type);
4831 void KSpiritInit(mobj_t *spirit, mobj_t *korax);
4832
4833 #define KORAX_TID                                       (245)
4834 #define KORAX_FIRST_TELEPORT_TID        (248)
4835 #define KORAX_TELEPORT_TID                      (249)
4836
4837 void A_KoraxChase(mobj_t *actor)
4838 {
4839         mobj_t *spot;
4840         int lastfound;
4841         byte args[3]={0,0,0};
4842
4843         if ((!actor->special2) &&
4844                 (actor->health <= (actor->info->spawnhealth/2)))
4845         {
4846                 lastfound = 0;
4847                 spot = P_FindMobjFromTID(KORAX_FIRST_TELEPORT_TID, &lastfound);
4848                 if (spot)
4849                 {
4850                         P_Teleport(actor, spot->x, spot->y, spot->angle, true);
4851                 }
4852
4853                 P_StartACS(249, 0, args, actor, NULL, 0);
4854                 actor->special2 = 1;    // Don't run again
4855
4856                 return;
4857         }
4858
4859         if (!actor->target) return;
4860         if (P_Random()<30)
4861         {
4862                 P_SetMobjState(actor, actor->info->missilestate);
4863         }
4864         else if (P_Random()<30)
4865         {
4866                 S_StartSound(NULL, SFX_KORAX_ACTIVE);
4867         }
4868
4869         // Teleport away
4870         if (actor->health < (actor->info->spawnhealth>>1))
4871         {
4872                 if (P_Random()<10)
4873                 {
4874                         lastfound = actor->special1;
4875                         spot = P_FindMobjFromTID(KORAX_TELEPORT_TID, &lastfound);
4876                         actor->special1 = lastfound;
4877                         if (spot)
4878                         {
4879                                 P_Teleport(actor, spot->x, spot->y, spot->angle, true);
4880                         }
4881                 }
4882         }
4883 }
4884
4885 void A_KoraxStep(mobj_t *actor)
4886 {
4887         A_Chase(actor);
4888 }
4889
4890 void A_KoraxStep2(mobj_t *actor)
4891 {
4892         S_StartSound(NULL, SFX_KORAX_STEP);
4893         A_Chase(actor);
4894 }
4895
4896 void A_KoraxBonePop(mobj_t *actor)
4897 {
4898         fixed_t x,y,z;
4899         mobj_t *mo;
4900         byte args[5];
4901
4902         args[0]=args[1]=args[2]=args[3]=args[4]=0;
4903         x=actor->x, y=actor->y, z=actor->z;
4904
4905         // Spawn 6 spirits equalangularly
4906         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT1, ANGLE_60*0, 5*FRACUNIT);
4907         if (mo) KSpiritInit(mo,actor);
4908         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT2, ANGLE_60*1, 5*FRACUNIT);
4909         if (mo) KSpiritInit(mo,actor);
4910         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT3, ANGLE_60*2, 5*FRACUNIT);
4911         if (mo) KSpiritInit(mo,actor);
4912         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT4, ANGLE_60*3, 5*FRACUNIT);
4913         if (mo) KSpiritInit(mo,actor);
4914         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT5, ANGLE_60*4, 5*FRACUNIT);
4915         if (mo) KSpiritInit(mo,actor);
4916         mo = P_SpawnMissileAngle(actor,MT_KORAX_SPIRIT6, ANGLE_60*5, 5*FRACUNIT);
4917         if (mo) KSpiritInit(mo,actor);
4918
4919         P_StartACS(255, 0, args, actor, NULL, 0);               // Death script
4920 }
4921
4922 void KSpiritInit(mobj_t *spirit, mobj_t *korax)
4923 {
4924         int i;
4925         mobj_t *tail, *next;
4926
4927         spirit->health = KORAX_SPIRIT_LIFETIME;
4928
4929         spirit->special1 = (int)korax;                          // Swarm around korax
4930         spirit->special2 = 32+(P_Random()&7);           // Float bob index
4931         spirit->args[0] = 10;                                           // initial turn value
4932         spirit->args[1] = 0;                                            // initial look angle
4933
4934         // Spawn a tail for spirit
4935         tail = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
4936         tail->special2 = (int)spirit; // parent
4937         for(i = 1; i < 3; i++)
4938         {
4939                 next = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
4940                 P_SetMobjState(next, next->info->spawnstate+1);
4941                 tail->special1 = (int)next;
4942                 tail = next;
4943         }
4944         tail->special1 = 0; // last tail bit
4945 }
4946
4947 void A_KoraxDecide(mobj_t *actor)
4948 {
4949         if (P_Random()<220)
4950         {
4951                 P_SetMobjState(actor, S_KORAX_MISSILE1);
4952         }
4953         else
4954         {
4955                 P_SetMobjState(actor, S_KORAX_COMMAND1);
4956         }
4957 }
4958
4959 void A_KoraxMissile(mobj_t *actor)
4960 {
4961         int type = P_Random()%6;
4962         int sound = SFX_NONE; /* jim initialiser added */
4963
4964         S_StartSound(actor, SFX_KORAX_ATTACK);
4965
4966         switch(type)
4967         {
4968                 case 0:
4969                         type = MT_WRAITHFX1;
4970                         sound = SFX_WRAITH_MISSILE_FIRE;
4971                         break;
4972                 case 1:
4973                         type = MT_DEMONFX1;
4974                         sound = SFX_DEMON_MISSILE_FIRE;
4975                         break;
4976                 case 2:
4977                         type = MT_DEMON2FX1;
4978                         sound = SFX_DEMON_MISSILE_FIRE;
4979                         break;
4980                 case 3:
4981                         type = MT_FIREDEMON_FX6;
4982                         sound = SFX_FIRED_ATTACK;
4983                         break;
4984                 case 4:
4985                         type = MT_CENTAUR_FX;
4986                         sound = SFX_CENTAURLEADER_ATTACK;
4987                         break;
4988                 case 5:
4989                         type = MT_SERPENTFX;
4990                         sound = SFX_CENTAURLEADER_ATTACK;
4991                         break;
4992         }
4993
4994         // Fire all 6 missiles at once
4995         S_StartSound(NULL, sound);
4996         KoraxFire1(actor, type);
4997         KoraxFire2(actor, type);
4998         KoraxFire3(actor, type);
4999         KoraxFire4(actor, type);
5000         KoraxFire5(actor, type);
5001         KoraxFire6(actor, type);
5002 }
5003
5004
5005 // Call action code scripts (250-254)
5006 void A_KoraxCommand(mobj_t *actor)
5007 {
5008         byte args[5];
5009         fixed_t x,y,z;
5010         angle_t ang;
5011         int numcommands;
5012
5013         S_StartSound(actor, SFX_KORAX_COMMAND);
5014
5015         // Shoot stream of lightning to ceiling
5016         ang = (actor->angle - ANGLE_90) >> ANGLETOFINESHIFT;
5017         x=actor->x + FixedMul(KORAX_COMMAND_OFFSET,finecosine[ang]);
5018         y=actor->y + FixedMul(KORAX_COMMAND_OFFSET,finesine[ang]);
5019         z=actor->z + KORAX_COMMAND_HEIGHT;
5020         P_SpawnMobj(x,y,z, MT_KORAX_BOLT);
5021
5022         args[0]=args[1]=args[2]=args[3]=args[4]=0;
5023
5024         if (actor->health <= (actor->info->spawnhealth >> 1))
5025         {
5026                 numcommands = 5;
5027         }
5028         else
5029         {
5030                 numcommands = 4;
5031         }
5032
5033         switch(P_Random() % numcommands)
5034         {
5035                 case 0:
5036                         P_StartACS(250, 0, args, actor, NULL, 0);
5037                         break;
5038                 case 1:
5039                         P_StartACS(251, 0, args, actor, NULL, 0);
5040                         break;
5041                 case 2:
5042                         P_StartACS(252, 0, args, actor, NULL, 0);
5043                         break;
5044                 case 3:
5045                         P_StartACS(253, 0, args, actor, NULL, 0);
5046                         break;
5047                 case 4:
5048                         P_StartACS(254, 0, args, actor, NULL, 0);
5049                         break;
5050         }
5051 }
5052
5053
5054 #define KORAX_DELTAANGLE                        (85*ANGLE_1)
5055 #define KORAX_ARM_EXTENSION_SHORT       (40*FRACUNIT)
5056 #define KORAX_ARM_EXTENSION_LONG        (55*FRACUNIT)
5057
5058 #define KORAX_ARM1_HEIGHT                       (108*FRACUNIT)
5059 #define KORAX_ARM2_HEIGHT                       (82*FRACUNIT)
5060 #define KORAX_ARM3_HEIGHT                       (54*FRACUNIT)
5061 #define KORAX_ARM4_HEIGHT                       (104*FRACUNIT)
5062 #define KORAX_ARM5_HEIGHT                       (86*FRACUNIT)
5063 #define KORAX_ARM6_HEIGHT                       (53*FRACUNIT)
5064
5065
5066 // Arm projectiles
5067 //              arm positions numbered:
5068 //                      1       top left
5069 //                      2       middle left
5070 //                      3       lower left
5071 //                      4       top right
5072 //                      5       middle right
5073 //                      6       lower right
5074
5075
5076 // Arm 1 projectile
5077 void KoraxFire1(mobj_t *actor, int type)
5078 {
5079         mobj_t *mo;
5080         angle_t ang;
5081         fixed_t x,y,z;
5082
5083         ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5084         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
5085         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
5086         z = actor->z - actor->floorclip + KORAX_ARM1_HEIGHT;
5087         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5088 }
5089
5090
5091 // Arm 2 projectile
5092 void KoraxFire2(mobj_t *actor, int type)
5093 {
5094         mobj_t *mo;
5095         angle_t ang;
5096         fixed_t x,y,z;
5097
5098         ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5099         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
5100         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
5101         z = actor->z - actor->floorclip + KORAX_ARM2_HEIGHT;
5102         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5103 }
5104
5105 // Arm 3 projectile
5106 void KoraxFire3(mobj_t *actor, int type)
5107 {
5108         mobj_t *mo;
5109         angle_t ang;
5110         fixed_t x,y,z;
5111
5112         ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5113         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
5114         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
5115         z = actor->z - actor->floorclip + KORAX_ARM3_HEIGHT;
5116         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5117 }
5118
5119 // Arm 4 projectile
5120 void KoraxFire4(mobj_t *actor, int type)
5121 {
5122         mobj_t *mo;
5123         angle_t ang;
5124         fixed_t x,y,z;
5125
5126         ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5127         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
5128         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
5129         z = actor->z - actor->floorclip + KORAX_ARM4_HEIGHT;
5130         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5131 }
5132
5133 // Arm 5 projectile
5134 void KoraxFire5(mobj_t *actor, int type)
5135 {
5136         mobj_t *mo;
5137         angle_t ang;
5138         fixed_t x,y,z;
5139
5140         ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5141         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
5142         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
5143         z = actor->z - actor->floorclip + KORAX_ARM5_HEIGHT;
5144         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5145 }
5146
5147 // Arm 6 projectile
5148 void KoraxFire6(mobj_t *actor, int type)
5149 {
5150         mobj_t *mo;
5151         angle_t ang;
5152         fixed_t x,y,z;
5153
5154         ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
5155         x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
5156         y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
5157         z = actor->z - actor->floorclip + KORAX_ARM6_HEIGHT;
5158         mo = P_SpawnKoraxMissile(x,y,z,actor, actor->target, type);
5159 }
5160
5161
5162 void A_KSpiritWeave(mobj_t *actor)
5163 {
5164         fixed_t newX, newY;
5165         int weaveXY, weaveZ;
5166         int angle;
5167
5168         weaveXY = actor->special2>>16;
5169         weaveZ = actor->special2&0xFFFF;
5170         angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
5171         newX = actor->x-FixedMul(finecosine[angle], 
5172                 FloatBobOffsets[weaveXY]<<2);
5173         newY = actor->y-FixedMul(finesine[angle],
5174                 FloatBobOffsets[weaveXY]<<2);
5175         weaveXY = (weaveXY+(P_Random()%5))&63;
5176         newX += FixedMul(finecosine[angle], 
5177                 FloatBobOffsets[weaveXY]<<2);
5178         newY += FixedMul(finesine[angle], 
5179                 FloatBobOffsets[weaveXY]<<2);
5180         P_TryMove(actor, newX, newY);
5181         actor->z -= FloatBobOffsets[weaveZ]<<1;
5182         weaveZ = (weaveZ+(P_Random()%5))&63;
5183         actor->z += FloatBobOffsets[weaveZ]<<1; 
5184         actor->special2 = weaveZ+(weaveXY<<16);
5185 }
5186
5187 void A_KSpiritSeeker(mobj_t *actor, angle_t thresh, angle_t turnMax)
5188 {
5189         int dir;
5190         int dist;
5191         angle_t delta;
5192         angle_t angle;
5193         mobj_t *target;
5194         fixed_t newZ;
5195         fixed_t deltaZ;
5196
5197         target = (mobj_t *)actor->special1;
5198         if(target == NULL)
5199         {
5200                 return;
5201         }
5202         dir = P_FaceMobj(actor, target, &delta);
5203         if(delta > thresh)
5204         {
5205                 delta >>= 1;
5206                 if(delta > turnMax)
5207                 {
5208                         delta = turnMax;
5209                 }
5210         }
5211         if(dir)
5212         { // Turn clockwise
5213                 actor->angle += delta;
5214         }
5215         else
5216         { // Turn counter clockwise
5217                 actor->angle -= delta;
5218         }
5219         angle = actor->angle>>ANGLETOFINESHIFT;
5220         actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
5221         actor->momy = FixedMul(actor->info->speed, finesine[angle]);
5222
5223         if(!(leveltime&15) 
5224                 || actor->z > target->z+(target->info->height)
5225                 || actor->z+actor->height < target->z)
5226         {
5227                 newZ = target->z+((P_Random()*target->info->height)>>8);
5228                 deltaZ = newZ-actor->z;
5229                 if(abs(deltaZ) > 15*FRACUNIT)
5230                 {
5231                         if(deltaZ > 0)
5232                         {
5233                                 deltaZ = 15*FRACUNIT;
5234                         }
5235                         else
5236                         {
5237                                 deltaZ = -15*FRACUNIT;
5238                         }
5239                 }
5240                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
5241                 dist = dist/actor->info->speed;
5242                 if(dist < 1)
5243                 {
5244                         dist = 1;
5245                 }
5246                 actor->momz = deltaZ/dist;
5247         }
5248         return;
5249 }
5250
5251
5252 void A_KSpiritRoam(mobj_t *actor)
5253 {
5254         if (actor->health-- <= 0)
5255         {
5256                 S_StartSound(actor, SFX_SPIRIT_DIE);
5257                 P_SetMobjState(actor, S_KSPIRIT_DEATH1);
5258         }
5259         else
5260         {
5261                 if (actor->special1)
5262                 {
5263                         A_KSpiritSeeker(actor, actor->args[0]*ANGLE_1,
5264                                                         actor->args[0]*ANGLE_1*2);
5265                 }
5266                 A_KSpiritWeave(actor);
5267                 if (P_Random()<50)
5268                 {
5269                         S_StartSound(NULL, SFX_SPIRIT_ACTIVE);
5270                 }
5271         }
5272 }
5273
5274 void A_KBolt(mobj_t *actor)
5275 {
5276         // Countdown lifetime
5277         if (actor->special1-- <= 0)
5278         {
5279                 P_SetMobjState(actor, S_NULL);
5280         }
5281 }
5282
5283
5284 #define KORAX_BOLT_HEIGHT               48*FRACUNIT
5285 #define KORAX_BOLT_LIFETIME             3
5286
5287 void A_KBoltRaise(mobj_t *actor)
5288 {
5289         mobj_t *mo;
5290         fixed_t z;
5291
5292         // Spawn a child upward
5293         z = actor->z + KORAX_BOLT_HEIGHT;
5294
5295         if ((z + KORAX_BOLT_HEIGHT) < actor->ceilingz)
5296         {
5297                 mo = P_SpawnMobj(actor->x, actor->y, z, MT_KORAX_BOLT);
5298                 if (mo)
5299                 {
5300                         mo->special1 = KORAX_BOLT_LIFETIME;
5301                 }
5302         }
5303         else
5304         {
5305                 // Maybe cap it off here
5306         }
5307 }
5308