11 #define MAX_BOSS_SPOTS 8
24 static int BossSpotCount;
25 static BossSpot_t BossSpots[MAX_BOSS_SPOTS];
27 //----------------------------------------------------------------------------
29 // PROC P_InitMonsters
31 // Called at level load.
33 //----------------------------------------------------------------------------
35 void P_InitMonsters(void)
40 //----------------------------------------------------------------------------
44 //----------------------------------------------------------------------------
46 void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle)
48 if(BossSpotCount == MAX_BOSS_SPOTS)
50 I_Error("Too many boss spots.");
52 BossSpots[BossSpotCount].x = x;
53 BossSpots[BossSpotCount].y = y;
54 BossSpots[BossSpotCount].angle = angle;
58 //----------------------------------------------------------------------------
60 // PROC P_RecursiveSound
62 //----------------------------------------------------------------------------
66 void P_RecursiveSound(sector_t *sec, int soundblocks)
72 // Wake up all monsters in this sector
73 if(sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
77 sec->validcount = validcount;
78 sec->soundtraversed = soundblocks+1;
79 sec->soundtarget = soundtarget;
80 for(i = 0; i < sec->linecount; i++)
82 check = sec->lines[i];
83 if(!(check->flags&ML_TWOSIDED))
92 if(sides[check->sidenum[0]].sector == sec)
94 other = sides[check->sidenum[1]].sector;
98 other = sides[check->sidenum[0]].sector;
100 if(check->flags&ML_SOUNDBLOCK)
104 P_RecursiveSound(other, 1);
109 P_RecursiveSound(other, soundblocks);
114 //----------------------------------------------------------------------------
118 // If a monster yells at a player, it will alert other monsters to the
121 //----------------------------------------------------------------------------
123 void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
125 soundtarget = target;
127 P_RecursiveSound(emmiter->subsector->sector, 0);
130 //----------------------------------------------------------------------------
132 // FUNC P_CheckMeleeRange
134 //----------------------------------------------------------------------------
136 boolean P_CheckMeleeRange(mobj_t *actor)
146 dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y);
147 if(dist >= MELEERANGE)
151 if(!P_CheckSight(actor, mo))
155 if(mo->z > actor->z+actor->height)
156 { // Target is higher than the attacker
159 else if(actor->z > mo->z+mo->height)
160 { // Attacker is higher
166 //----------------------------------------------------------------------------
168 // FUNC P_CheckMissileRange
170 //----------------------------------------------------------------------------
172 boolean P_CheckMissileRange(mobj_t *actor)
176 if(!P_CheckSight(actor, actor->target))
180 if(actor->flags&MF_JUSTHIT)
181 { // The target just hit the enemy, so fight back!
182 actor->flags &= ~MF_JUSTHIT;
185 if(actor->reactiontime)
186 { // Don't attack yet
189 dist = (P_AproxDistance(actor->x-actor->target->x,
190 actor->y-actor->target->y)>>FRACBITS)-64;
191 if(!actor->info->meleestate)
192 { // No melee attack, so fire more frequently
195 if(actor->type == MT_IMP)
196 { // Imp's fly attack from far away
203 if(P_Random() < dist)
215 = Move in the current direction
216 = returns false if the move is blocked
220 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
221 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
223 #define MAXSPECIALCROSS 8
224 extern line_t *spechit[MAXSPECIALCROSS];
225 extern int numspechit;
227 boolean P_Move(mobj_t *actor)
233 if(actor->movedir == DI_NODIR)
237 tryx = actor->x+actor->info->speed*xspeed[actor->movedir];
238 tryy = actor->y+actor->info->speed*yspeed[actor->movedir];
239 if(!P_TryMove(actor, tryx, tryy))
240 { // open any specials
241 if(actor->flags&MF_FLOAT && floatok)
242 { // must adjust height
243 if(actor->z < tmfloorz)
245 actor->z += FLOATSPEED;
249 actor->z -= FLOATSPEED;
251 actor->flags |= MF_INFLOAT;
258 actor->movedir = DI_NODIR;
262 ld = spechit[numspechit];
263 // if the special isn't a door that can be opened, return false
264 if(P_UseSpecialLine(actor, ld))
273 actor->flags &= ~MF_INFLOAT;
275 if(!(actor->flags&MF_FLOAT))
277 if(actor->z > actor->floorz)
281 actor->z = actor->floorz;
286 //----------------------------------------------------------------------------
290 // Attempts to move actor in its current (ob->moveangle) direction.
291 // If blocked by either a wall or an actor returns FALSE.
292 // If move is either clear of block only by a door, returns TRUE and sets.
293 // If a door is in the way, an OpenDoor call is made to start it opening.
295 //----------------------------------------------------------------------------
297 boolean P_TryWalk(mobj_t *actor)
303 actor->movecount = P_Random()&15;
315 dirtype_t opposite[] =
316 {DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
317 DI_NORTH, DI_NORTHWEST, DI_NODIR};
319 dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST};
321 void P_NewChaseDir (mobj_t *actor)
323 fixed_t deltax,deltay;
325 dirtype_t tdir, olddir, turnaround;
328 I_Error ("P_NewChaseDir: called with no target");
330 olddir = actor->movedir;
331 turnaround=opposite[olddir];
333 deltax = actor->target->x - actor->x;
334 deltay = actor->target->y - actor->y;
335 if (deltax>10*FRACUNIT)
337 else if (deltax<-10*FRACUNIT)
341 if (deltay<-10*FRACUNIT)
343 else if (deltay>10*FRACUNIT)
349 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
351 actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
352 if (actor->movedir != turnaround && P_TryWalk(actor))
356 // try other directions
357 if (P_Random() > 200 || abs(deltay)>abs(deltax))
364 if (d[1]==turnaround)
366 if (d[2]==turnaround)
371 actor->movedir = d[1];
372 if (P_TryWalk(actor))
373 return; /*either moved forward or attacked*/
378 actor->movedir =d[2];
379 if (P_TryWalk(actor))
383 /* there is no direct path to the player, so pick another direction */
385 if (olddir!=DI_NODIR)
387 actor->movedir =olddir;
388 if (P_TryWalk(actor))
392 if (P_Random()&1) /*randomly determine direction of search*/
394 for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++)
396 if (tdir!=turnaround)
398 actor->movedir =tdir;
399 if ( P_TryWalk(actor) )
406 for (tdir=DI_SOUTHEAST ; (int)tdir >= DI_EAST;tdir--)
408 if (tdir!=turnaround)
410 actor->movedir =tdir;
411 if ( P_TryWalk(actor) )
417 if (turnaround != DI_NODIR)
419 actor->movedir =turnaround;
420 if ( P_TryWalk(actor) )
424 actor->movedir = DI_NODIR; // can't move
427 //---------------------------------------------------------------------------
429 // FUNC P_LookForMonsters
431 //---------------------------------------------------------------------------
433 #define MONS_LOOK_RANGE (20*64*FRACUNIT)
434 #define MONS_LOOK_LIMIT 64
436 boolean P_LookForMonsters(mobj_t *actor)
442 if(!P_CheckSight(players[0].mo, actor))
443 { // Player can't see monster
447 for(think = thinkercap.next; think != &thinkercap; think = think->next)
449 if(think->function != P_MobjThinker)
450 { // Not a mobj thinker
453 mo = (mobj_t *)think;
454 if(!(mo->flags&MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
455 { // Not a valid monster
458 if(P_AproxDistance(actor->x-mo->x, actor->y-mo->y)
467 if(count++ > MONS_LOOK_LIMIT)
471 if(!P_CheckSight(actor, mo))
475 // Found a target monster
487 = If allaround is false, only look 180 degrees in front
488 = returns true if a player is targeted
492 boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
501 if(!netgame && players[0].health <= 0)
502 { // Single player game and player is dead, look for monsters
503 return(P_LookForMonsters(actor));
505 sector = actor->subsector->sector;
507 stop = (actor->lastlook-1)&3;
508 for( ; ; actor->lastlook = (actor->lastlook+1)&3 )
510 if (!playeringame[actor->lastlook])
513 if (c++ == 2 || actor->lastlook == stop)
514 return false; // done looking
516 player = &players[actor->lastlook];
517 if (player->health <= 0)
519 if (!P_CheckSight (actor, player->mo))
520 continue; // out of sight
524 an = R_PointToAngle2 (actor->x, actor->y,
525 player->mo->x, player->mo->y) - actor->angle;
526 if (an > ANG90 && an < ANG270)
528 dist = P_AproxDistance (player->mo->x - actor->x,
529 player->mo->y - actor->y);
530 // if real close, react anyway
531 if (dist > MELEERANGE)
532 continue; // behind back
535 if(player->mo->flags&MF_SHADOW)
536 { // Player is invisible
537 if((P_AproxDistance(player->mo->x-actor->x,
538 player->mo->y-actor->y) > 2*MELEERANGE)
539 && P_AproxDistance(player->mo->momx, player->mo->momy)
541 { // Player is sneaking - can't detect
545 { // Player isn't sneaking, but still didn't detect
549 actor->target = player->mo;
556 ===============================================================================
560 ===============================================================================
568 = Stay in state until a player is sighted
573 void A_Look (mobj_t *actor)
577 actor->threshold = 0; // any shot will wake up
578 targ = actor->subsector->sector->soundtarget;
579 if (targ && (targ->flags & MF_SHOOTABLE) )
581 actor->target = targ;
582 if ( actor->flags & MF_AMBUSH )
584 if (P_CheckSight (actor, actor->target))
592 if (!P_LookForPlayers (actor, false) )
595 // go into chase state
597 if (actor->info->seesound)
602 switch (actor->info->seesound)
607 sound = sfx_posit1+P_Random()%3;
611 sound = sfx_bgsit1+P_Random()%2;
614 sound = actor->info->seesound;
618 sound = actor->info->seesound;
619 if(actor->flags2&MF2_BOSS)
621 S_StartSound(NULL, sound);
625 S_StartSound(actor, sound);
628 P_SetMobjState(actor, actor->info->seestate);
637 = Actor has a melee attack, so it tries to close as fast as possible
642 void A_Chase(mobj_t *actor)
646 if(actor->reactiontime)
648 actor->reactiontime--;
651 // Modify target threshold
657 if(gameskill == sk_nightmare)
658 { // Monsters move faster in nightmare mode
659 actor->tics -= actor->tics/2;
667 // turn towards movement direction if not there yet
669 if(actor->movedir < 8)
671 actor->angle &= (7<<29);
672 delta = actor->angle-(actor->movedir << 29);
675 actor->angle -= ANG90/2;
679 actor->angle += ANG90/2;
683 if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
684 { // look for a new target
685 if(P_LookForPlayers(actor, true))
686 { // got a new target
689 P_SetMobjState(actor, actor->info->spawnstate);
694 // don't attack twice in a row
696 if(actor->flags & MF_JUSTATTACKED)
698 actor->flags &= ~MF_JUSTATTACKED;
699 if (gameskill != sk_nightmare)
700 P_NewChaseDir (actor);
705 // check for melee attack
707 if (actor->info->meleestate && P_CheckMeleeRange (actor))
709 if (actor->info->attacksound)
710 S_StartSound (actor, actor->info->attacksound);
711 P_SetMobjState (actor, actor->info->meleestate);
716 // check for missile attack
718 if (actor->info->missilestate)
720 if (gameskill < sk_nightmare && actor->movecount)
722 if (!P_CheckMissileRange (actor))
724 P_SetMobjState (actor, actor->info->missilestate);
725 actor->flags |= MF_JUSTATTACKED;
731 // possibly choose another target
733 if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
735 if (P_LookForPlayers(actor,true))
736 return; // got a new target
740 // chase towards player
742 if (--actor->movecount<0 || !P_Move (actor))
744 P_NewChaseDir (actor);
750 if(actor->info->activesound && P_Random() < 3)
752 if(actor->type == MT_WIZARD && P_Random() < 128)
754 S_StartSound(actor, actor->info->seesound);
756 else if(actor->type == MT_SORCERER2)
758 S_StartSound(NULL, actor->info->activesound);
762 S_StartSound(actor, actor->info->activesound);
767 //----------------------------------------------------------------------------
771 //----------------------------------------------------------------------------
773 void A_FaceTarget(mobj_t *actor)
779 actor->flags &= ~MF_AMBUSH;
780 actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
782 if(actor->target->flags&MF_SHADOW)
783 { // Target is a ghost
784 actor->angle += (P_Random()-P_Random())<<21;
788 //----------------------------------------------------------------------------
792 //----------------------------------------------------------------------------
794 void A_Pain(mobj_t *actor)
796 if(actor->info->painsound)
798 S_StartSound(actor, actor->info->painsound);
802 //----------------------------------------------------------------------------
806 //----------------------------------------------------------------------------
808 void A_DripBlood(mobj_t *actor)
812 mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
813 actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
814 mo->momx = (P_Random()-P_Random())<<10;
815 mo->momy = (P_Random()-P_Random())<<10;
816 mo->flags2 |= MF2_LOGRAV;
819 //----------------------------------------------------------------------------
821 // PROC A_KnightAttack
823 //----------------------------------------------------------------------------
825 void A_KnightAttack(mobj_t *actor)
831 if(P_CheckMeleeRange(actor))
833 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
834 S_StartSound(actor, sfx_kgtat2);
838 S_StartSound(actor, actor->info->attacksound);
839 if(actor->type == MT_KNIGHTGHOST || P_Random() < 40)
841 P_SpawnMissile(actor, actor->target, MT_REDAXE);
845 P_SpawnMissile(actor, actor->target, MT_KNIGHTAXE);
848 //----------------------------------------------------------------------------
852 //----------------------------------------------------------------------------
854 void A_ImpExplode(mobj_t *actor)
858 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK1);
859 mo->momx = (P_Random() - P_Random ())<<10;
860 mo->momy = (P_Random() - P_Random ())<<10;
861 mo->momz = 9*FRACUNIT;
862 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK2);
863 mo->momx = (P_Random() - P_Random ())<<10;
864 mo->momy = (P_Random() - P_Random ())<<10;
865 mo->momz = 9*FRACUNIT;
866 if(actor->special1 == 666)
867 { // Extreme death crash
868 P_SetMobjState(actor, S_IMP_XCRASH1);
872 //----------------------------------------------------------------------------
876 //----------------------------------------------------------------------------
878 void A_BeastPuff(mobj_t *actor)
882 P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
883 actor->y+((P_Random()-P_Random())<<10),
884 actor->z+((P_Random()-P_Random())<<10), MT_PUFFY);
888 //----------------------------------------------------------------------------
890 // PROC A_ImpMeAttack
892 //----------------------------------------------------------------------------
894 void A_ImpMeAttack(mobj_t *actor)
900 S_StartSound(actor, actor->info->attacksound);
901 if(P_CheckMeleeRange(actor))
903 P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
907 //----------------------------------------------------------------------------
909 // PROC A_ImpMsAttack
911 //----------------------------------------------------------------------------
913 void A_ImpMsAttack(mobj_t *actor)
919 if(!actor->target || P_Random() > 64)
921 P_SetMobjState(actor, actor->info->seestate);
924 dest = actor->target;
925 actor->flags |= MF_SKULLFLY;
926 S_StartSound(actor, actor->info->attacksound);
928 an = actor->angle >> ANGLETOFINESHIFT;
929 actor->momx = FixedMul(12*FRACUNIT, finecosine[an]);
930 actor->momy = FixedMul(12*FRACUNIT, finesine[an]);
931 dist = P_AproxDistance(dest->x-actor->x, dest->y-actor->y);
932 dist = dist/(12*FRACUNIT);
937 actor->momz = (dest->z+(dest->height>>1)-actor->z)/dist;
940 //----------------------------------------------------------------------------
942 // PROC A_ImpMsAttack2
944 // Fireball attack of the imp leader.
946 //----------------------------------------------------------------------------
948 void A_ImpMsAttack2(mobj_t *actor)
954 S_StartSound(actor, actor->info->attacksound);
955 if(P_CheckMeleeRange(actor))
957 P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
960 P_SpawnMissile(actor, actor->target, MT_IMPBALL);
963 //----------------------------------------------------------------------------
967 //----------------------------------------------------------------------------
969 void A_ImpDeath(mobj_t *actor)
971 actor->flags &= ~MF_SOLID;
972 actor->flags2 |= MF2_FOOTCLIP;
973 if(actor->z <= actor->floorz)
975 P_SetMobjState(actor, S_IMP_CRASH1);
979 //----------------------------------------------------------------------------
983 //----------------------------------------------------------------------------
985 void A_ImpXDeath1(mobj_t *actor)
987 actor->flags &= ~MF_SOLID;
988 actor->flags |= MF_NOGRAVITY;
989 actor->flags2 |= MF2_FOOTCLIP;
990 actor->special1 = 666; // Flag the crash routine
993 //----------------------------------------------------------------------------
997 //----------------------------------------------------------------------------
999 void A_ImpXDeath2(mobj_t *actor)
1001 actor->flags &= ~MF_NOGRAVITY;
1002 if(actor->z <= actor->floorz)
1004 P_SetMobjState(actor, S_IMP_CRASH1);
1008 //----------------------------------------------------------------------------
1010 // FUNC P_UpdateChicken
1012 // Returns true if the chicken morphs.
1014 //----------------------------------------------------------------------------
1016 boolean P_UpdateChicken(mobj_t *actor, int tics)
1026 actor->special1 -= tics;
1027 if(actor->special1 > 0)
1031 moType = actor->special2;
1035 oldChicken = *actor;
1036 P_SetMobjState(actor, S_FREETARGMOBJ);
1037 mo = P_SpawnMobj(x, y, z, moType);
1038 if(P_TestMobjLocation(mo) == false)
1041 mo = P_SpawnMobj(x, y, z, MT_CHICKEN);
1042 mo->angle = oldChicken.angle;
1043 mo->flags = oldChicken.flags;
1044 mo->health = oldChicken.health;
1045 mo->target = oldChicken.target;
1046 mo->special1 = 5*35; // Next try in 5 seconds
1047 mo->special2 = moType;
1050 mo->angle = oldChicken.angle;
1051 mo->target = oldChicken.target;
1052 fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1053 S_StartSound(fog, sfx_telept);
1057 //----------------------------------------------------------------------------
1059 // PROC A_ChicAttack
1061 //----------------------------------------------------------------------------
1063 void A_ChicAttack(mobj_t *actor)
1065 if(P_UpdateChicken(actor, 18))
1073 if(P_CheckMeleeRange(actor))
1075 P_DamageMobj(actor->target, actor, actor, 1+(P_Random()&1));
1079 //----------------------------------------------------------------------------
1083 //----------------------------------------------------------------------------
1085 void A_ChicLook(mobj_t *actor)
1087 if(P_UpdateChicken(actor, 10))
1094 //----------------------------------------------------------------------------
1098 //----------------------------------------------------------------------------
1100 void A_ChicChase(mobj_t *actor)
1102 if(P_UpdateChicken(actor, 3))
1109 //----------------------------------------------------------------------------
1113 //----------------------------------------------------------------------------
1115 void A_ChicPain(mobj_t *actor)
1117 if(P_UpdateChicken(actor, 10))
1121 S_StartSound(actor, actor->info->painsound);
1124 //----------------------------------------------------------------------------
1128 //----------------------------------------------------------------------------
1130 void A_Feathers(mobj_t *actor)
1136 if(actor->health > 0)
1138 count = P_Random() < 32 ? 2 : 1;
1142 count = 5+(P_Random()&3);
1144 for(i = 0; i < count; i++)
1146 mo = P_SpawnMobj(actor->x, actor->y, actor->z+20*FRACUNIT,
1149 mo->momx = (P_Random()-P_Random())<<8;
1150 mo->momy = (P_Random()-P_Random())<<8;
1151 mo->momz = FRACUNIT+(P_Random()<<9);
1152 P_SetMobjState(mo, S_FEATHER1+(P_Random()&7));
1156 //----------------------------------------------------------------------------
1158 // PROC A_MummyAttack
1160 //----------------------------------------------------------------------------
1162 void A_MummyAttack(mobj_t *actor)
1168 S_StartSound(actor, actor->info->attacksound);
1169 if(P_CheckMeleeRange(actor))
1171 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
1172 S_StartSound(actor, sfx_mumat2);
1175 S_StartSound(actor, sfx_mumat1);
1178 //----------------------------------------------------------------------------
1180 // PROC A_MummyAttack2
1182 // Mummy leader missile attack.
1184 //----------------------------------------------------------------------------
1186 void A_MummyAttack2(mobj_t *actor)
1194 //S_StartSound(actor, actor->info->attacksound);
1195 if(P_CheckMeleeRange(actor))
1197 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
1200 mo = P_SpawnMissile(actor, actor->target, MT_MUMMYFX1);
1201 //mo = P_SpawnMissile(actor, actor->target, MT_EGGFX);
1204 mo->special1 = (int)actor->target;
1208 //----------------------------------------------------------------------------
1210 // PROC A_MummyFX1Seek
1212 //----------------------------------------------------------------------------
1214 void A_MummyFX1Seek(mobj_t *actor)
1216 P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*20);
1219 //----------------------------------------------------------------------------
1223 //----------------------------------------------------------------------------
1225 void A_MummySoul(mobj_t *mummy)
1229 mo = P_SpawnMobj(mummy->x, mummy->y, mummy->z+10*FRACUNIT, MT_MUMMYSOUL);
1230 mo->momz = FRACUNIT;
1233 //----------------------------------------------------------------------------
1237 //----------------------------------------------------------------------------
1239 void A_Sor1Pain(mobj_t *actor)
1241 actor->special1 = 20; // Number of steps to walk fast
1245 //----------------------------------------------------------------------------
1249 //----------------------------------------------------------------------------
1251 void A_Sor1Chase(mobj_t *actor)
1261 //----------------------------------------------------------------------------
1263 // PROC A_Srcr1Attack
1265 // Sorcerer demon attack.
1267 //----------------------------------------------------------------------------
1269 void A_Srcr1Attack(mobj_t *actor)
1279 S_StartSound(actor, actor->info->attacksound);
1280 if(P_CheckMeleeRange(actor))
1282 P_DamageMobj(actor->target, actor, actor, HITDICE(8));
1285 if(actor->health > (actor->info->spawnhealth/3)*2)
1286 { // Spit one fireball
1287 P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
1290 { // Spit three fireballs
1291 mo = P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
1296 P_SpawnMissileAngle(actor, MT_SRCRFX1, angle-ANGLE_1*3, momz);
1297 P_SpawnMissileAngle(actor, MT_SRCRFX1, angle+ANGLE_1*3, momz);
1299 if(actor->health < actor->info->spawnhealth/3)
1300 { // Maybe attack again
1302 { // Just attacked, so don't attack again
1303 actor->special1 = 0;
1306 { // Set state to attack again
1307 actor->special1 = 1;
1308 P_SetMobjState(actor, S_SRCR1_ATK4);
1314 //----------------------------------------------------------------------------
1316 // PROC A_SorcererRise
1318 //----------------------------------------------------------------------------
1320 void A_SorcererRise(mobj_t *actor)
1324 actor->flags &= ~MF_SOLID;
1325 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCERER2);
1326 P_SetMobjState(mo, S_SOR2_RISE1);
1327 mo->angle = actor->angle;
1328 mo->target = actor->target;
1331 //----------------------------------------------------------------------------
1333 // PROC P_DSparilTeleport
1335 //----------------------------------------------------------------------------
1337 void P_DSparilTeleport(mobj_t *actor)
1355 x = BossSpots[i%BossSpotCount].x;
1356 y = BossSpots[i%BossSpotCount].y;
1357 } while(P_AproxDistance(actor->x-x, actor->y-y) < 128*FRACUNIT);
1361 if(P_TeleportMove(actor, x, y))
1363 mo = P_SpawnMobj(prevX, prevY, prevZ, MT_SOR2TELEFADE);
1364 S_StartSound(mo, sfx_telept);
1365 P_SetMobjState(actor, S_SOR2_TELE1);
1366 S_StartSound(actor, sfx_telept);
1367 actor->z = actor->floorz;
1368 actor->angle = BossSpots[i%BossSpotCount].angle;
1369 actor->momx = actor->momy = actor->momz = 0;
1373 //----------------------------------------------------------------------------
1375 // PROC A_Srcr2Decide
1377 //----------------------------------------------------------------------------
1379 void A_Srcr2Decide(mobj_t *actor)
1381 static int chance[] =
1383 192, 120, 120, 120, 64, 64, 32, 16, 0
1390 if(P_Random() < chance[actor->health/(actor->info->spawnhealth/8)])
1392 P_DSparilTeleport(actor);
1396 //----------------------------------------------------------------------------
1398 // PROC A_Srcr2Attack
1400 //----------------------------------------------------------------------------
1402 void A_Srcr2Attack(mobj_t *actor)
1410 S_StartSound(NULL, actor->info->attacksound);
1411 if(P_CheckMeleeRange(actor))
1413 P_DamageMobj(actor->target, actor, actor, HITDICE(20));
1416 chance = actor->health < actor->info->spawnhealth/2 ? 96 : 48;
1417 if(P_Random() < chance)
1418 { // Wizard spawners
1419 P_SpawnMissileAngle(actor, MT_SOR2FX2,
1420 actor->angle-ANG45, FRACUNIT/2);
1421 P_SpawnMissileAngle(actor, MT_SOR2FX2,
1422 actor->angle+ANG45, FRACUNIT/2);
1426 P_SpawnMissile(actor, actor->target, MT_SOR2FX1);
1430 //----------------------------------------------------------------------------
1434 //----------------------------------------------------------------------------
1436 void A_BlueSpark(mobj_t *actor)
1441 for(i = 0; i < 2; i++)
1443 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SOR2FXSPARK);
1444 mo->momx = (P_Random()-P_Random())<<9;
1445 mo->momy = (P_Random()-P_Random())<<9;
1446 mo->momz = FRACUNIT+(P_Random()<<8);
1450 //----------------------------------------------------------------------------
1454 //----------------------------------------------------------------------------
1456 void A_GenWizard(mobj_t *actor)
1461 mo = P_SpawnMobj(actor->x, actor->y,
1462 actor->z-mobjinfo[MT_WIZARD].height/2, MT_WIZARD);
1463 if(P_TestMobjLocation(mo) == false)
1468 actor->momx = actor->momy = actor->momz = 0;
1469 P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
1470 actor->flags &= ~MF_MISSILE;
1471 fog = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TFOG);
1472 S_StartSound(fog, sfx_telept);
1475 //----------------------------------------------------------------------------
1477 // PROC A_Sor2DthInit
1479 //----------------------------------------------------------------------------
1481 void A_Sor2DthInit(mobj_t *actor)
1483 actor->special1 = 7; // Animation loop counter
1484 P_Massacre(); // Kill monsters early
1487 //----------------------------------------------------------------------------
1489 // PROC A_Sor2DthLoop
1491 //----------------------------------------------------------------------------
1493 void A_Sor2DthLoop(mobj_t *actor)
1495 if(--actor->special1)
1497 P_SetMobjState(actor, S_SOR2_DIE4);
1501 //----------------------------------------------------------------------------
1503 // D'Sparil Sound Routines
1505 //----------------------------------------------------------------------------
1507 void A_SorZap(mobj_t *actor) {S_StartSound(NULL, sfx_sorzap);}
1508 void A_SorRise(mobj_t *actor) {S_StartSound(NULL, sfx_sorrise);}
1509 void A_SorDSph(mobj_t *actor) {S_StartSound(NULL, sfx_sordsph);}
1510 void A_SorDExp(mobj_t *actor) {S_StartSound(NULL, sfx_sordexp);}
1511 void A_SorDBon(mobj_t *actor) {S_StartSound(NULL, sfx_sordbon);}
1512 void A_SorSightSnd(mobj_t *actor) {S_StartSound(NULL, sfx_sorsit);}
1514 //----------------------------------------------------------------------------
1516 // PROC A_MinotaurAtk1
1520 //----------------------------------------------------------------------------
1522 void A_MinotaurAtk1(mobj_t *actor)
1530 S_StartSound(actor, sfx_stfpow);
1531 if(P_CheckMeleeRange(actor))
1533 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
1534 if((player = actor->target->player) != NULL)
1535 { // Squish the player
1536 player->deltaviewheight = -16*FRACUNIT;
1541 //----------------------------------------------------------------------------
1543 // PROC A_MinotaurDecide
1545 // Choose a missile attack.
1547 //----------------------------------------------------------------------------
1549 #define MNTR_CHARGE_SPEED (13*FRACUNIT)
1551 void A_MinotaurDecide(mobj_t *actor)
1557 target = actor->target;
1562 S_StartSound(actor, sfx_minsit);
1563 dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
1564 if(target->z+target->height > actor->z
1565 && target->z+target->height < actor->z+actor->height
1566 && dist < 8*64*FRACUNIT
1567 && dist > 1*64*FRACUNIT
1568 && P_Random() < 150)
1570 // Don't call the state function right away
1571 P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
1572 actor->flags |= MF_SKULLFLY;
1573 A_FaceTarget(actor);
1574 angle = actor->angle>>ANGLETOFINESHIFT;
1575 actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
1576 actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
1577 actor->special1 = 35/2; // Charge duration
1579 else if(target->z == target->floorz
1580 && dist < 9*64*FRACUNIT
1581 && P_Random() < 220)
1582 { // Floor fire attack
1583 P_SetMobjState(actor, S_MNTR_ATK3_1);
1584 actor->special2 = 0;
1588 A_FaceTarget(actor);
1589 // Don't need to call P_SetMobjState because the current state
1590 // falls through to the swing attack
1594 //----------------------------------------------------------------------------
1596 // PROC A_MinotaurCharge
1598 //----------------------------------------------------------------------------
1600 void A_MinotaurCharge(mobj_t *actor)
1606 puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1607 puff->momz = 2*FRACUNIT;
1612 actor->flags &= ~MF_SKULLFLY;
1613 P_SetMobjState(actor, actor->info->seestate);
1617 //----------------------------------------------------------------------------
1619 // PROC A_MinotaurAtk2
1623 //----------------------------------------------------------------------------
1625 void A_MinotaurAtk2(mobj_t *actor)
1635 S_StartSound(actor, sfx_minat2);
1636 if(P_CheckMeleeRange(actor))
1638 P_DamageMobj(actor->target, actor, actor, HITDICE(5));
1641 mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
1644 S_StartSound(mo, sfx_minat2);
1647 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/8), momz);
1648 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/8), momz);
1649 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/16), momz);
1650 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/16), momz);
1654 //----------------------------------------------------------------------------
1656 // PROC A_MinotaurAtk3
1658 // Floor fire attack.
1660 //----------------------------------------------------------------------------
1662 void A_MinotaurAtk3(mobj_t *actor)
1671 if(P_CheckMeleeRange(actor))
1673 P_DamageMobj(actor->target, actor, actor, HITDICE(5));
1674 if((player = actor->target->player) != NULL)
1675 { // Squish the player
1676 player->deltaviewheight = -16*FRACUNIT;
1681 mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
1684 S_StartSound(mo, sfx_minat1);
1687 if(P_Random() < 192 && actor->special2 == 0)
1689 P_SetMobjState(actor, S_MNTR_ATK3_4);
1690 actor->special2 = 1;
1694 //----------------------------------------------------------------------------
1696 // PROC A_MntrFloorFire
1698 //----------------------------------------------------------------------------
1700 void A_MntrFloorFire(mobj_t *actor)
1704 actor->z = actor->floorz;
1705 mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
1706 actor->y+((P_Random()-P_Random())<<10), ONFLOORZ, MT_MNTRFX3);
1707 mo->target = actor->target;
1708 mo->momx = 1; // Force block checking
1709 P_CheckMissileSpawn(mo);
1712 //----------------------------------------------------------------------------
1714 // PROC A_BeastAttack
1716 //----------------------------------------------------------------------------
1718 void A_BeastAttack(mobj_t *actor)
1724 S_StartSound(actor, actor->info->attacksound);
1725 if(P_CheckMeleeRange(actor))
1727 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
1730 P_SpawnMissile(actor, actor->target, MT_BEASTBALL);
1733 //----------------------------------------------------------------------------
1735 // PROC A_HeadAttack
1737 //----------------------------------------------------------------------------
1739 void A_HeadAttack(mobj_t *actor)
1747 static int atkResolve1[] = { 50, 150 };
1748 static int atkResolve2[] = { 150, 200 };
1751 // Ice ball (close 20% : far 60%)
1752 // Fire column (close 40% : far 20%)
1753 // Whirlwind (close 40% : far 20%)
1754 // Distance threshold = 8 cells
1756 target = actor->target;
1761 A_FaceTarget(actor);
1762 if(P_CheckMeleeRange(actor))
1764 P_DamageMobj(target, actor, actor, HITDICE(6));
1767 dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)
1769 randAttack = P_Random();
1770 if(randAttack < atkResolve1[dist])
1772 P_SpawnMissile(actor, target, MT_HEADFX1);
1773 S_StartSound(actor, sfx_hedat2);
1775 else if(randAttack < atkResolve2[dist])
1777 baseFire = P_SpawnMissile(actor, target, MT_HEADFX3);
1778 if(baseFire != NULL)
1780 P_SetMobjState(baseFire, S_HEADFX3_4); // Don't grow
1781 for(i = 0; i < 5; i++)
1783 fire = P_SpawnMobj(baseFire->x, baseFire->y,
1784 baseFire->z, MT_HEADFX3);
1787 S_StartSound(actor, sfx_hedat1);
1789 fire->target = baseFire->target;
1790 fire->angle = baseFire->angle;
1791 fire->momx = baseFire->momx;
1792 fire->momy = baseFire->momy;
1793 fire->momz = baseFire->momz;
1795 fire->health = (i+1)*2;
1796 P_CheckMissileSpawn(fire);
1802 mo = P_SpawnMissile(actor, target, MT_WHIRLWIND);
1805 mo->z -= 32*FRACUNIT;
1806 mo->special1 = (int)target;
1807 mo->special2 = 50; // Timer for active sound
1808 mo->health = 20*TICSPERSEC; // Duration
1809 S_StartSound(actor, sfx_hedat3);
1814 //----------------------------------------------------------------------------
1816 // PROC A_WhirlwindSeek
1818 //----------------------------------------------------------------------------
1820 void A_WhirlwindSeek(mobj_t *actor)
1823 if(actor->health < 0)
1825 actor->momx = actor->momy = actor->momz = 0;
1826 P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
1827 actor->flags &= ~MF_MISSILE;
1830 if((actor->special2 -= 3) < 0)
1832 actor->special2 = 58+(P_Random()&31);
1833 S_StartSound(actor, sfx_hedat3);
1836 && (((mobj_t *)(actor->special1))->flags&MF_SHADOW))
1840 P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*30);
1843 //----------------------------------------------------------------------------
1845 // PROC A_HeadIceImpact
1847 //----------------------------------------------------------------------------
1849 void A_HeadIceImpact(mobj_t *ice)
1855 for(i = 0; i < 8; i++)
1857 shard = P_SpawnMobj(ice->x, ice->y, ice->z, MT_HEADFX2);
1859 shard->target = ice->target;
1860 shard->angle = angle;
1861 angle >>= ANGLETOFINESHIFT;
1862 shard->momx = FixedMul(shard->info->speed, finecosine[angle]);
1863 shard->momy = FixedMul(shard->info->speed, finesine[angle]);
1864 shard->momz = -.6*FRACUNIT;
1865 P_CheckMissileSpawn(shard);
1869 //----------------------------------------------------------------------------
1871 // PROC A_HeadFireGrow
1873 //----------------------------------------------------------------------------
1875 void A_HeadFireGrow(mobj_t *fire)
1878 fire->z += 9*FRACUNIT;
1879 if(fire->health == 0)
1881 fire->damage = fire->info->damage;
1882 P_SetMobjState(fire, S_HEADFX3_4);
1886 //----------------------------------------------------------------------------
1888 // PROC A_SnakeAttack
1890 //----------------------------------------------------------------------------
1892 void A_SnakeAttack(mobj_t *actor)
1896 P_SetMobjState(actor, S_SNAKE_WALK1);
1899 S_StartSound(actor, actor->info->attacksound);
1900 A_FaceTarget(actor);
1901 P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_A);
1904 //----------------------------------------------------------------------------
1906 // PROC A_SnakeAttack2
1908 //----------------------------------------------------------------------------
1910 void A_SnakeAttack2(mobj_t *actor)
1914 P_SetMobjState(actor, S_SNAKE_WALK1);
1917 S_StartSound(actor, actor->info->attacksound);
1918 A_FaceTarget(actor);
1919 P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_B);
1922 //----------------------------------------------------------------------------
1924 // PROC A_ClinkAttack
1926 //----------------------------------------------------------------------------
1928 void A_ClinkAttack(mobj_t *actor)
1936 S_StartSound(actor, actor->info->attacksound);
1937 if(P_CheckMeleeRange(actor))
1939 damage = ((P_Random()%7)+3);
1940 P_DamageMobj(actor->target, actor, actor, damage);
1944 //----------------------------------------------------------------------------
1948 //----------------------------------------------------------------------------
1950 void A_GhostOff(mobj_t *actor)
1952 actor->flags &= ~MF_SHADOW;
1955 //----------------------------------------------------------------------------
1959 //----------------------------------------------------------------------------
1961 void A_WizAtk1(mobj_t *actor)
1963 A_FaceTarget(actor);
1964 actor->flags &= ~MF_SHADOW;
1967 //----------------------------------------------------------------------------
1971 //----------------------------------------------------------------------------
1973 void A_WizAtk2(mobj_t *actor)
1975 A_FaceTarget(actor);
1976 actor->flags |= MF_SHADOW;
1979 //----------------------------------------------------------------------------
1983 //----------------------------------------------------------------------------
1985 void A_WizAtk3(mobj_t *actor)
1991 actor->flags &= ~MF_SHADOW;
1996 S_StartSound(actor, actor->info->attacksound);
1997 if(P_CheckMeleeRange(actor))
1999 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
2002 mo = P_SpawnMissile(actor, actor->target, MT_WIZFX1);
2007 P_SpawnMissileAngle(actor, MT_WIZFX1, angle-(ANG45/8), momz);
2008 P_SpawnMissileAngle(actor, MT_WIZFX1, angle+(ANG45/8), momz);
2012 //----------------------------------------------------------------------------
2016 //----------------------------------------------------------------------------
2018 void A_Scream(mobj_t *actor)
2025 // Make boss death sounds full volume
2026 S_StartSound(NULL, actor->info->deathsound);
2029 // Handle the different player death screams
2030 if(actor->special1 < 10)
2031 { // Wimpy death sound
2032 S_StartSound(actor, sfx_plrwdth);
2034 else if(actor->health > -50)
2035 { // Normal death sound
2036 S_StartSound(actor, actor->info->deathsound);
2038 else if(actor->health > -100)
2039 { // Crazy death sound
2040 S_StartSound(actor, sfx_plrcdth);
2043 { // Extreme death sound
2044 S_StartSound(actor, sfx_gibdth);
2048 S_StartSound(actor, actor->info->deathsound);
2053 //---------------------------------------------------------------------------
2057 //---------------------------------------------------------------------------
2059 void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
2063 if(P_Random() > chance)
2067 mo = P_SpawnMobj(source->x, source->y,
2068 source->z+(source->height>>1), type);
2069 mo->momx = (P_Random()-P_Random())<<8;
2070 mo->momy = (P_Random()-P_Random())<<8;
2071 mo->momz = FRACUNIT*5+(P_Random()<<10);
2072 mo->flags |= MF_DROPPED;
2073 mo->health = special;
2076 //----------------------------------------------------------------------------
2078 // PROC A_NoBlocking
2080 //----------------------------------------------------------------------------
2082 void A_NoBlocking(mobj_t *actor)
2084 actor->flags &= ~MF_SOLID;
2085 // Check for monsters dropping things
2089 case MT_MUMMYLEADER:
2091 case MT_MUMMYLEADERGHOST:
2092 P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
2095 case MT_KNIGHTGHOST:
2096 P_DropItem(actor, MT_AMCBOWWIMPY, 5, 84);
2099 P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
2100 P_DropItem(actor, MT_ARTITOMEOFPOWER, 0, 4);
2103 P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
2104 P_DropItem(actor, MT_ARTIEGG, 0, 51);
2107 P_DropItem(actor, MT_AMCBOWWIMPY, 10, 84);
2110 P_DropItem(actor, MT_AMSKRDWIMPY, 20, 84);
2113 P_DropItem(actor, MT_AMPHRDWIMPY, 5, 84);
2116 P_DropItem(actor, MT_ARTISUPERHEAL, 0, 51);
2117 P_DropItem(actor, MT_AMPHRDWIMPY, 10, 84);
2124 //----------------------------------------------------------------------------
2128 // Handles a bunch of exploding things.
2130 //----------------------------------------------------------------------------
2132 void A_Explode(mobj_t *actor)
2139 case MT_FIREBOMB: // Time Bombs
2140 actor->z += 32*FRACUNIT;
2141 actor->flags &= ~MF_SHADOW;
2143 case MT_MNTRFX2: // Minotaur floor fire
2146 case MT_SOR2FX1: // D'Sparil missile
2147 damage = 80+(P_Random()&31);
2152 P_RadiusAttack(actor, actor->target, damage);
2156 //----------------------------------------------------------------------------
2160 //----------------------------------------------------------------------------
2162 void A_PodPain(mobj_t *actor)
2169 chance = P_Random();
2174 count = chance > 240 ? 2 : 1;
2175 for(i = 0; i < count; i++)
2177 goo = P_SpawnMobj(actor->x, actor->y,
2178 actor->z+48*FRACUNIT, MT_PODGOO);
2179 goo->target = actor;
2180 goo->momx = (P_Random()-P_Random())<<9;
2181 goo->momy = (P_Random()-P_Random())<<9;
2182 goo->momz = FRACUNIT/2+(P_Random()<<9);
2186 //----------------------------------------------------------------------------
2190 //----------------------------------------------------------------------------
2192 void A_RemovePod(mobj_t *actor)
2198 mo = (mobj_t *)actor->special2;
2199 if(mo->special1 > 0)
2206 //----------------------------------------------------------------------------
2210 //----------------------------------------------------------------------------
2212 #define MAX_GEN_PODS 16
2214 void A_MakePod(mobj_t *actor)
2221 if(actor->special1 == MAX_GEN_PODS)
2222 { // Too many generated pods
2228 mo = P_SpawnMobj(x, y, ONFLOORZ, MT_POD);
2229 if(P_CheckPosition(mo, x, y) == false)
2234 P_SetMobjState(mo, S_POD_GROW1);
2235 P_ThrustMobj(mo, P_Random()<<24, (fixed_t)(4.5*FRACUNIT));
2236 S_StartSound(mo, sfx_newpod);
2237 actor->special1++; // Increment generated pod count
2238 mo->special2 = (int)actor; // Link the generator to the pod
2242 //----------------------------------------------------------------------------
2246 // Kills all monsters.
2248 //----------------------------------------------------------------------------
2250 void P_Massacre(void)
2255 for(think = thinkercap.next; think != &thinkercap;
2256 think = think->next)
2258 if(think->function != P_MobjThinker)
2259 { // Not a mobj thinker
2262 mo = (mobj_t *)think;
2263 if((mo->flags&MF_COUNTKILL) && (mo->health > 0))
2265 P_DamageMobj(mo, NULL, NULL, 10000);
2270 //----------------------------------------------------------------------------
2274 // Trigger special effects if all bosses are dead.
2276 //----------------------------------------------------------------------------
2278 void A_BossDeath(mobj_t *actor)
2283 static mobjtype_t bossType[6] =
2294 { // Not a boss level
2297 if(actor->type != bossType[gameepisode-1])
2298 { // Not considered a boss in this episode
2301 // Make sure all bosses are dead
2302 for(think = thinkercap.next; think != &thinkercap; think = think->next)
2304 if(think->function != P_MobjThinker)
2305 { // Not a mobj thinker
2308 mo = (mobj_t *)think;
2309 if((mo != actor) && (mo->type == actor->type) && (mo->health > 0))
2310 { // Found a living boss
2315 { // Kill any remaining monsters
2318 dummyLine.tag = 666;
2319 EV_DoFloor(&dummyLine, lowerFloor);
2322 //----------------------------------------------------------------------------
2326 //----------------------------------------------------------------------------
2328 void A_ESound(mobj_t *mo)
2334 case MT_SOUNDWATERFALL:
2335 sound = sfx_waterfl;
2343 S_StartSound(mo, sound);
2346 //----------------------------------------------------------------------------
2348 // PROC A_SpawnTeleGlitter
2350 //----------------------------------------------------------------------------
2352 void A_SpawnTeleGlitter(mobj_t *actor)
2356 mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
2357 actor->y+((P_Random()&31)-16)*FRACUNIT,
2358 actor->subsector->sector->floorheight, MT_TELEGLITTER);
2359 mo->momz = FRACUNIT/4;
2362 //----------------------------------------------------------------------------
2364 // PROC A_SpawnTeleGlitter2
2366 //----------------------------------------------------------------------------
2368 void A_SpawnTeleGlitter2(mobj_t *actor)
2372 mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
2373 actor->y+((P_Random()&31)-16)*FRACUNIT,
2374 actor->subsector->sector->floorheight, MT_TELEGLITTER2);
2375 mo->momz = FRACUNIT/4;
2378 //----------------------------------------------------------------------------
2380 // PROC A_AccTeleGlitter
2382 //----------------------------------------------------------------------------
2384 void A_AccTeleGlitter(mobj_t *actor)
2386 if(++actor->health > 35)
2388 actor->momz += actor->momz/2;
2392 //----------------------------------------------------------------------------
2394 // PROC A_InitKeyGizmo
2396 //----------------------------------------------------------------------------
2398 void A_InitKeyGizmo(mobj_t *gizmo)
2405 case MT_KEYGIZMOBLUE:
2406 state = S_KGZ_BLUEFLOAT1;
2408 case MT_KEYGIZMOGREEN:
2409 state = S_KGZ_GREENFLOAT1;
2411 case MT_KEYGIZMOYELLOW:
2412 state = S_KGZ_YELLOWFLOAT1;
2417 mo = P_SpawnMobj(gizmo->x, gizmo->y, gizmo->z+60*FRACUNIT,
2419 P_SetMobjState(mo, state);
2422 //----------------------------------------------------------------------------
2424 // PROC A_VolcanoSet
2426 //----------------------------------------------------------------------------
2428 void A_VolcanoSet(mobj_t *volcano)
2430 volcano->tics = 105+(P_Random()&127);
2433 //----------------------------------------------------------------------------
2435 // PROC A_VolcanoBlast
2437 //----------------------------------------------------------------------------
2439 void A_VolcanoBlast(mobj_t *volcano)
2446 count = 1+(P_Random()%3);
2447 for(i = 0; i < count; i++)
2449 blast = P_SpawnMobj(volcano->x, volcano->y,
2450 volcano->z+44*FRACUNIT, MT_VOLCANOBLAST); // MT_VOLCANOBLAST
2451 blast->target = volcano;
2452 angle = P_Random()<<24;
2453 blast->angle = angle;
2454 angle >>= ANGLETOFINESHIFT;
2455 blast->momx = FixedMul(1*FRACUNIT, finecosine[angle]);
2456 blast->momy = FixedMul(1*FRACUNIT, finesine[angle]);
2457 blast->momz = (2.5*FRACUNIT)+(P_Random()<<10);
2458 S_StartSound(blast, sfx_volsht);
2459 P_CheckMissileSpawn(blast);
2463 //----------------------------------------------------------------------------
2465 // PROC A_VolcBallImpact
2467 //----------------------------------------------------------------------------
2469 void A_VolcBallImpact(mobj_t *ball)
2475 if(ball->z <= ball->floorz)
2477 ball->flags |= MF_NOGRAVITY;
2478 ball->flags2 &= ~MF2_LOGRAV;
2479 ball->z += 28*FRACUNIT;
2480 //ball->momz = 3*FRACUNIT;
2482 P_RadiusAttack(ball, ball->target, 25);
2483 for(i = 0; i < 4; i++)
2485 tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_VOLCANOTBLAST);
2486 tiny->target = ball;
2488 tiny->angle = angle;
2489 angle >>= ANGLETOFINESHIFT;
2490 tiny->momx = FixedMul(FRACUNIT*.7, finecosine[angle]);
2491 tiny->momy = FixedMul(FRACUNIT*.7, finesine[angle]);
2492 tiny->momz = FRACUNIT+(P_Random()<<9);
2493 P_CheckMissileSpawn(tiny);
2497 //----------------------------------------------------------------------------
2501 //----------------------------------------------------------------------------
2503 void A_SkullPop(mobj_t *actor)
2508 actor->flags &= ~MF_SOLID;
2509 mo = P_SpawnMobj(actor->x, actor->y, actor->z+48*FRACUNIT,
2511 //mo->target = actor;
2512 mo->momx = (P_Random()-P_Random())<<9;
2513 mo->momy = (P_Random()-P_Random())<<9;
2514 mo->momz = FRACUNIT*2+(P_Random()<<6);
2515 // Attach player mobj to bloody skull
2516 player = actor->player;
2517 actor->player = NULL;
2518 mo->player = player;
2519 mo->health = actor->health;
2520 mo->angle = actor->angle;
2522 player->lookdir = 0;
2523 player->damagecount = 32;
2526 //----------------------------------------------------------------------------
2528 // PROC A_CheckSkullFloor
2530 //----------------------------------------------------------------------------
2532 void A_CheckSkullFloor(mobj_t *actor)
2534 if(actor->z <= actor->floorz)
2536 P_SetMobjState(actor, S_BLOODYSKULLX1);
2540 //----------------------------------------------------------------------------
2542 // PROC A_CheckSkullDone
2544 //----------------------------------------------------------------------------
2546 void A_CheckSkullDone(mobj_t *actor)
2548 if(actor->special2 == 666)
2550 P_SetMobjState(actor, S_BLOODYSKULLX2);
2554 //----------------------------------------------------------------------------
2556 // PROC A_CheckBurnGone
2558 //----------------------------------------------------------------------------
2560 void A_CheckBurnGone(mobj_t *actor)
2562 if(actor->special2 == 666)
2564 P_SetMobjState(actor, S_PLAY_FDTH20);
2568 //----------------------------------------------------------------------------
2570 // PROC A_FreeTargMobj
2572 //----------------------------------------------------------------------------
2574 void A_FreeTargMobj(mobj_t *mo)
2576 mo->momx = mo->momy = mo->momz = 0;
2577 mo->z = mo->ceilingz+4*FRACUNIT;
2578 mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID);
2579 mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
2580 mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
2584 //----------------------------------------------------------------------------
2586 // PROC A_AddPlayerCorpse
2588 //----------------------------------------------------------------------------
2590 #define BODYQUESIZE 32
2591 mobj_t *bodyque[BODYQUESIZE];
2594 void A_AddPlayerCorpse(mobj_t *actor)
2596 if(bodyqueslot >= BODYQUESIZE)
2597 { // Too many player corpses - remove an old one
2598 P_RemoveMobj(bodyque[bodyqueslot%BODYQUESIZE]);
2600 bodyque[bodyqueslot%BODYQUESIZE] = actor;
2604 //----------------------------------------------------------------------------
2608 //----------------------------------------------------------------------------
2610 void A_FlameSnd(mobj_t *actor)
2612 S_StartSound(actor, sfx_hedat1); // Burn sound
2615 //----------------------------------------------------------------------------
2619 //----------------------------------------------------------------------------
2621 void A_HideThing(mobj_t *actor)
2623 //P_UnsetThingPosition(actor);
2624 actor->flags2 |= MF2_DONTDRAW;
2627 //----------------------------------------------------------------------------
2629 // PROC A_UnHideThing
2631 //----------------------------------------------------------------------------
2633 void A_UnHideThing(mobj_t *actor)
2635 //P_SetThingPosition(actor);
2636 actor->flags2 &= ~MF2_DONTDRAW;