10 #define MAX_BOSS_SPOTS 8
23 static int BossSpotCount;
24 static BossSpot_t BossSpots[MAX_BOSS_SPOTS];
26 //----------------------------------------------------------------------------
28 // PROC P_InitMonsters
30 // Called at level load.
32 //----------------------------------------------------------------------------
34 void P_InitMonsters(void)
39 //----------------------------------------------------------------------------
43 //----------------------------------------------------------------------------
45 void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle)
47 if(BossSpotCount == MAX_BOSS_SPOTS)
49 I_Error("Too many boss spots.");
51 BossSpots[BossSpotCount].x = x;
52 BossSpots[BossSpotCount].y = y;
53 BossSpots[BossSpotCount].angle = angle;
57 //----------------------------------------------------------------------------
59 // PROC P_RecursiveSound
61 //----------------------------------------------------------------------------
65 void P_RecursiveSound(sector_t *sec, int soundblocks)
71 // Wake up all monsters in this sector
72 if(sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
76 sec->validcount = validcount;
77 sec->soundtraversed = soundblocks+1;
78 sec->soundtarget = soundtarget;
79 for(i = 0; i < sec->linecount; i++)
81 check = sec->lines[i];
82 if(!(check->flags&ML_TWOSIDED))
91 if(sides[check->sidenum[0]].sector == sec)
93 other = sides[check->sidenum[1]].sector;
97 other = sides[check->sidenum[0]].sector;
99 if(check->flags&ML_SOUNDBLOCK)
103 P_RecursiveSound(other, 1);
108 P_RecursiveSound(other, soundblocks);
113 //----------------------------------------------------------------------------
117 // If a monster yells at a player, it will alert other monsters to the
120 //----------------------------------------------------------------------------
122 void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
124 soundtarget = target;
126 P_RecursiveSound(emmiter->subsector->sector, 0);
129 //----------------------------------------------------------------------------
131 // FUNC P_CheckMeleeRange
133 //----------------------------------------------------------------------------
135 boolean P_CheckMeleeRange(mobj_t *actor)
145 dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y);
146 if(dist >= MELEERANGE)
150 if(!P_CheckSight(actor, mo))
154 if(mo->z > actor->z+actor->height)
155 { // Target is higher than the attacker
158 else if(actor->z > mo->z+mo->height)
159 { // Attacker is higher
165 //----------------------------------------------------------------------------
167 // FUNC P_CheckMissileRange
169 //----------------------------------------------------------------------------
171 boolean P_CheckMissileRange(mobj_t *actor)
175 if(!P_CheckSight(actor, actor->target))
179 if(actor->flags&MF_JUSTHIT)
180 { // The target just hit the enemy, so fight back!
181 actor->flags &= ~MF_JUSTHIT;
184 if(actor->reactiontime)
185 { // Don't attack yet
188 dist = (P_AproxDistance(actor->x-actor->target->x,
189 actor->y-actor->target->y)>>FRACBITS)-64;
190 if(!actor->info->meleestate)
191 { // No melee attack, so fire more frequently
194 if(actor->type == MT_IMP)
195 { // Imp's fly attack from far away
202 if(P_Random() < dist)
214 = Move in the current direction
215 = returns false if the move is blocked
219 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
220 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
222 #define MAXSPECIALCROSS 8
223 extern line_t *spechit[MAXSPECIALCROSS];
224 extern int numspechit;
226 boolean P_Move(mobj_t *actor)
232 if(actor->movedir == DI_NODIR)
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)
244 actor->z += FLOATSPEED;
248 actor->z -= FLOATSPEED;
250 actor->flags |= MF_INFLOAT;
257 actor->movedir = DI_NODIR;
261 ld = spechit[numspechit];
262 // if the special isn't a door that can be opened, return false
263 if(P_UseSpecialLine(actor, ld))
272 actor->flags &= ~MF_INFLOAT;
274 if(!(actor->flags&MF_FLOAT))
276 if(actor->z > actor->floorz)
280 actor->z = actor->floorz;
285 //----------------------------------------------------------------------------
289 // Attempts to move actor in its current (ob->moveangle) direction.
290 // If blocked by either a wall or an actor returns FALSE.
291 // If move is either clear of block only by a door, returns TRUE and sets.
292 // If a door is in the way, an OpenDoor call is made to start it opening.
294 //----------------------------------------------------------------------------
296 boolean P_TryWalk(mobj_t *actor)
302 actor->movecount = P_Random()&15;
314 dirtype_t opposite[] =
315 {DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
316 DI_NORTH, DI_NORTHWEST, DI_NODIR};
318 dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST};
320 void P_NewChaseDir (mobj_t *actor)
322 fixed_t deltax,deltay;
324 dirtype_t tdir, olddir, turnaround;
327 I_Error ("P_NewChaseDir: called with no target");
329 olddir = actor->movedir;
330 turnaround=opposite[olddir];
332 deltax = actor->target->x - actor->x;
333 deltay = actor->target->y - actor->y;
334 if (deltax>10*FRACUNIT)
336 else if (deltax<-10*FRACUNIT)
340 if (deltay<-10*FRACUNIT)
342 else if (deltay>10*FRACUNIT)
348 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
350 actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
351 if (actor->movedir != turnaround && P_TryWalk(actor))
355 // try other directions
356 if (P_Random() > 200 || abs(deltay)>abs(deltax))
363 if (d[1]==turnaround)
365 if (d[2]==turnaround)
370 actor->movedir = d[1];
371 if (P_TryWalk(actor))
372 return; /*either moved forward or attacked*/
377 actor->movedir =d[2];
378 if (P_TryWalk(actor))
382 /* there is no direct path to the player, so pick another direction */
384 if (olddir!=DI_NODIR)
386 actor->movedir =olddir;
387 if (P_TryWalk(actor))
391 if (P_Random()&1) /*randomly determine direction of search*/
393 for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++)
395 if (tdir!=turnaround)
397 actor->movedir =tdir;
398 if ( P_TryWalk(actor) )
405 for (tdir=DI_SOUTHEAST ; (int)tdir >= DI_EAST;tdir--)
407 if (tdir!=turnaround)
409 actor->movedir =tdir;
410 if ( P_TryWalk(actor) )
416 if (turnaround != DI_NODIR)
418 actor->movedir =turnaround;
419 if ( P_TryWalk(actor) )
423 actor->movedir = DI_NODIR; // can't move
426 //---------------------------------------------------------------------------
428 // FUNC P_LookForMonsters
430 //---------------------------------------------------------------------------
432 #define MONS_LOOK_RANGE (20*64*FRACUNIT)
433 #define MONS_LOOK_LIMIT 64
435 boolean P_LookForMonsters(mobj_t *actor)
441 if(!P_CheckSight(players[0].mo, actor))
442 { // Player can't see monster
446 for(think = thinkercap.next; think != &thinkercap; think = think->next)
448 if(think->function != P_MobjThinker)
449 { // Not a mobj thinker
452 mo = (mobj_t *)think;
453 if(!(mo->flags&MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
454 { // Not a valid monster
457 if(P_AproxDistance(actor->x-mo->x, actor->y-mo->y)
466 if(count++ > MONS_LOOK_LIMIT)
470 if(!P_CheckSight(actor, mo))
474 // Found a target monster
486 = If allaround is false, only look 180 degrees in front
487 = returns true if a player is targeted
491 boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
500 if(!netgame && players[0].health <= 0)
501 { // Single player game and player is dead, look for monsters
502 return(P_LookForMonsters(actor));
504 sector = actor->subsector->sector;
506 stop = (actor->lastlook-1)&3;
507 for( ; ; actor->lastlook = (actor->lastlook+1)&3 )
509 if (!playeringame[actor->lastlook])
512 if (c++ == 2 || actor->lastlook == stop)
513 return false; // done looking
515 player = &players[actor->lastlook];
516 if (player->health <= 0)
518 if (!P_CheckSight (actor, player->mo))
519 continue; // out of sight
523 an = R_PointToAngle2 (actor->x, actor->y,
524 player->mo->x, player->mo->y) - actor->angle;
525 if (an > ANG90 && an < ANG270)
527 dist = P_AproxDistance (player->mo->x - actor->x,
528 player->mo->y - actor->y);
529 // if real close, react anyway
530 if (dist > MELEERANGE)
531 continue; // behind back
534 if(player->mo->flags&MF_SHADOW)
535 { // Player is invisible
536 if((P_AproxDistance(player->mo->x-actor->x,
537 player->mo->y-actor->y) > 2*MELEERANGE)
538 && P_AproxDistance(player->mo->momx, player->mo->momy)
540 { // Player is sneaking - can't detect
544 { // Player isn't sneaking, but still didn't detect
548 actor->target = player->mo;
555 ===============================================================================
559 ===============================================================================
567 = Stay in state until a player is sighted
572 void A_Look (mobj_t *actor)
576 actor->threshold = 0; // any shot will wake up
577 targ = actor->subsector->sector->soundtarget;
578 if (targ && (targ->flags & MF_SHOOTABLE) )
580 actor->target = targ;
581 if ( actor->flags & MF_AMBUSH )
583 if (P_CheckSight (actor, actor->target))
591 if (!P_LookForPlayers (actor, false) )
594 // go into chase state
596 if (actor->info->seesound)
601 switch (actor->info->seesound)
606 sound = sfx_posit1+P_Random()%3;
610 sound = sfx_bgsit1+P_Random()%2;
613 sound = actor->info->seesound;
617 sound = actor->info->seesound;
618 if(actor->flags2&MF2_BOSS)
620 S_StartSound(NULL, sound);
624 S_StartSound(actor, sound);
627 P_SetMobjState(actor, actor->info->seestate);
636 = Actor has a melee attack, so it tries to close as fast as possible
641 void A_Chase(mobj_t *actor)
645 if(actor->reactiontime)
647 actor->reactiontime--;
650 // Modify target threshold
656 if(gameskill == sk_nightmare)
657 { // Monsters move faster in nightmare mode
658 actor->tics -= actor->tics/2;
666 // turn towards movement direction if not there yet
668 if(actor->movedir < 8)
670 actor->angle &= (7<<29);
671 delta = actor->angle-(actor->movedir << 29);
674 actor->angle -= ANG90/2;
678 actor->angle += ANG90/2;
682 if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
683 { // look for a new target
684 if(P_LookForPlayers(actor, true))
685 { // got a new target
688 P_SetMobjState(actor, actor->info->spawnstate);
693 // don't attack twice in a row
695 if(actor->flags & MF_JUSTATTACKED)
697 actor->flags &= ~MF_JUSTATTACKED;
698 if (gameskill != sk_nightmare)
699 P_NewChaseDir (actor);
704 // check for melee attack
706 if (actor->info->meleestate && P_CheckMeleeRange (actor))
708 if (actor->info->attacksound)
709 S_StartSound (actor, actor->info->attacksound);
710 P_SetMobjState (actor, actor->info->meleestate);
715 // check for missile attack
717 if (actor->info->missilestate)
719 if (gameskill < sk_nightmare && actor->movecount)
721 if (!P_CheckMissileRange (actor))
723 P_SetMobjState (actor, actor->info->missilestate);
724 actor->flags |= MF_JUSTATTACKED;
730 // possibly choose another target
732 if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
734 if (P_LookForPlayers(actor,true))
735 return; // got a new target
739 // chase towards player
741 if (--actor->movecount<0 || !P_Move (actor))
743 P_NewChaseDir (actor);
749 if(actor->info->activesound && P_Random() < 3)
751 if(actor->type == MT_WIZARD && P_Random() < 128)
753 S_StartSound(actor, actor->info->seesound);
755 else if(actor->type == MT_SORCERER2)
757 S_StartSound(NULL, actor->info->activesound);
761 S_StartSound(actor, actor->info->activesound);
766 //----------------------------------------------------------------------------
770 //----------------------------------------------------------------------------
772 void A_FaceTarget(mobj_t *actor)
778 actor->flags &= ~MF_AMBUSH;
779 actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
781 if(actor->target->flags&MF_SHADOW)
782 { // Target is a ghost
783 actor->angle += (P_Random()-P_Random())<<21;
787 //----------------------------------------------------------------------------
791 //----------------------------------------------------------------------------
793 void A_Pain(mobj_t *actor)
795 if(actor->info->painsound)
797 S_StartSound(actor, actor->info->painsound);
801 //----------------------------------------------------------------------------
805 //----------------------------------------------------------------------------
807 void A_DripBlood(mobj_t *actor)
811 mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
812 actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
813 mo->momx = (P_Random()-P_Random())<<10;
814 mo->momy = (P_Random()-P_Random())<<10;
815 mo->flags2 |= MF2_LOGRAV;
818 //----------------------------------------------------------------------------
820 // PROC A_KnightAttack
822 //----------------------------------------------------------------------------
824 void A_KnightAttack(mobj_t *actor)
830 if(P_CheckMeleeRange(actor))
832 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
833 S_StartSound(actor, sfx_kgtat2);
837 S_StartSound(actor, actor->info->attacksound);
838 if(actor->type == MT_KNIGHTGHOST || P_Random() < 40)
840 P_SpawnMissile(actor, actor->target, MT_REDAXE);
844 P_SpawnMissile(actor, actor->target, MT_KNIGHTAXE);
847 //----------------------------------------------------------------------------
851 //----------------------------------------------------------------------------
853 void A_ImpExplode(mobj_t *actor)
857 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK1);
858 mo->momx = (P_Random() - P_Random ())<<10;
859 mo->momy = (P_Random() - P_Random ())<<10;
860 mo->momz = 9*FRACUNIT;
861 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK2);
862 mo->momx = (P_Random() - P_Random ())<<10;
863 mo->momy = (P_Random() - P_Random ())<<10;
864 mo->momz = 9*FRACUNIT;
865 if(actor->special1 == 666)
866 { // Extreme death crash
867 P_SetMobjState(actor, S_IMP_XCRASH1);
871 //----------------------------------------------------------------------------
875 //----------------------------------------------------------------------------
877 void A_BeastPuff(mobj_t *actor)
881 P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
882 actor->y+((P_Random()-P_Random())<<10),
883 actor->z+((P_Random()-P_Random())<<10), MT_PUFFY);
887 //----------------------------------------------------------------------------
889 // PROC A_ImpMeAttack
891 //----------------------------------------------------------------------------
893 void A_ImpMeAttack(mobj_t *actor)
899 S_StartSound(actor, actor->info->attacksound);
900 if(P_CheckMeleeRange(actor))
902 P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
906 //----------------------------------------------------------------------------
908 // PROC A_ImpMsAttack
910 //----------------------------------------------------------------------------
912 void A_ImpMsAttack(mobj_t *actor)
918 if(!actor->target || P_Random() > 64)
920 P_SetMobjState(actor, actor->info->seestate);
923 dest = actor->target;
924 actor->flags |= MF_SKULLFLY;
925 S_StartSound(actor, actor->info->attacksound);
927 an = actor->angle >> ANGLETOFINESHIFT;
928 actor->momx = FixedMul(12*FRACUNIT, finecosine[an]);
929 actor->momy = FixedMul(12*FRACUNIT, finesine[an]);
930 dist = P_AproxDistance(dest->x-actor->x, dest->y-actor->y);
931 dist = dist/(12*FRACUNIT);
936 actor->momz = (dest->z+(dest->height>>1)-actor->z)/dist;
939 //----------------------------------------------------------------------------
941 // PROC A_ImpMsAttack2
943 // Fireball attack of the imp leader.
945 //----------------------------------------------------------------------------
947 void A_ImpMsAttack2(mobj_t *actor)
953 S_StartSound(actor, actor->info->attacksound);
954 if(P_CheckMeleeRange(actor))
956 P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
959 P_SpawnMissile(actor, actor->target, MT_IMPBALL);
962 //----------------------------------------------------------------------------
966 //----------------------------------------------------------------------------
968 void A_ImpDeath(mobj_t *actor)
970 actor->flags &= ~MF_SOLID;
971 actor->flags2 |= MF2_FOOTCLIP;
972 if(actor->z <= actor->floorz)
974 P_SetMobjState(actor, S_IMP_CRASH1);
978 //----------------------------------------------------------------------------
982 //----------------------------------------------------------------------------
984 void A_ImpXDeath1(mobj_t *actor)
986 actor->flags &= ~MF_SOLID;
987 actor->flags |= MF_NOGRAVITY;
988 actor->flags2 |= MF2_FOOTCLIP;
989 actor->special1 = 666; // Flag the crash routine
992 //----------------------------------------------------------------------------
996 //----------------------------------------------------------------------------
998 void A_ImpXDeath2(mobj_t *actor)
1000 actor->flags &= ~MF_NOGRAVITY;
1001 if(actor->z <= actor->floorz)
1003 P_SetMobjState(actor, S_IMP_CRASH1);
1007 //----------------------------------------------------------------------------
1009 // FUNC P_UpdateChicken
1011 // Returns true if the chicken morphs.
1013 //----------------------------------------------------------------------------
1015 boolean P_UpdateChicken(mobj_t *actor, int tics)
1025 actor->special1 -= tics;
1026 if(actor->special1 > 0)
1030 moType = actor->special2;
1034 oldChicken = *actor;
1035 P_SetMobjState(actor, S_FREETARGMOBJ);
1036 mo = P_SpawnMobj(x, y, z, moType);
1037 if(P_TestMobjLocation(mo) == false)
1040 mo = P_SpawnMobj(x, y, z, MT_CHICKEN);
1041 mo->angle = oldChicken.angle;
1042 mo->flags = oldChicken.flags;
1043 mo->health = oldChicken.health;
1044 mo->target = oldChicken.target;
1045 mo->special1 = 5*35; // Next try in 5 seconds
1046 mo->special2 = moType;
1049 mo->angle = oldChicken.angle;
1050 mo->target = oldChicken.target;
1051 fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1052 S_StartSound(fog, sfx_telept);
1056 //----------------------------------------------------------------------------
1058 // PROC A_ChicAttack
1060 //----------------------------------------------------------------------------
1062 void A_ChicAttack(mobj_t *actor)
1064 if(P_UpdateChicken(actor, 18))
1072 if(P_CheckMeleeRange(actor))
1074 P_DamageMobj(actor->target, actor, actor, 1+(P_Random()&1));
1078 //----------------------------------------------------------------------------
1082 //----------------------------------------------------------------------------
1084 void A_ChicLook(mobj_t *actor)
1086 if(P_UpdateChicken(actor, 10))
1093 //----------------------------------------------------------------------------
1097 //----------------------------------------------------------------------------
1099 void A_ChicChase(mobj_t *actor)
1101 if(P_UpdateChicken(actor, 3))
1108 //----------------------------------------------------------------------------
1112 //----------------------------------------------------------------------------
1114 void A_ChicPain(mobj_t *actor)
1116 if(P_UpdateChicken(actor, 10))
1120 S_StartSound(actor, actor->info->painsound);
1123 //----------------------------------------------------------------------------
1127 //----------------------------------------------------------------------------
1129 void A_Feathers(mobj_t *actor)
1135 if(actor->health > 0)
1137 count = P_Random() < 32 ? 2 : 1;
1141 count = 5+(P_Random()&3);
1143 for(i = 0; i < count; i++)
1145 mo = P_SpawnMobj(actor->x, actor->y, actor->z+20*FRACUNIT,
1148 mo->momx = (P_Random()-P_Random())<<8;
1149 mo->momy = (P_Random()-P_Random())<<8;
1150 mo->momz = FRACUNIT+(P_Random()<<9);
1151 P_SetMobjState(mo, S_FEATHER1+(P_Random()&7));
1155 //----------------------------------------------------------------------------
1157 // PROC A_MummyAttack
1159 //----------------------------------------------------------------------------
1161 void A_MummyAttack(mobj_t *actor)
1167 S_StartSound(actor, actor->info->attacksound);
1168 if(P_CheckMeleeRange(actor))
1170 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
1171 S_StartSound(actor, sfx_mumat2);
1174 S_StartSound(actor, sfx_mumat1);
1177 //----------------------------------------------------------------------------
1179 // PROC A_MummyAttack2
1181 // Mummy leader missile attack.
1183 //----------------------------------------------------------------------------
1185 void A_MummyAttack2(mobj_t *actor)
1193 //S_StartSound(actor, actor->info->attacksound);
1194 if(P_CheckMeleeRange(actor))
1196 P_DamageMobj(actor->target, actor, actor, HITDICE(2));
1199 mo = P_SpawnMissile(actor, actor->target, MT_MUMMYFX1);
1200 //mo = P_SpawnMissile(actor, actor->target, MT_EGGFX);
1203 mo->special1 = (int)actor->target;
1207 //----------------------------------------------------------------------------
1209 // PROC A_MummyFX1Seek
1211 //----------------------------------------------------------------------------
1213 void A_MummyFX1Seek(mobj_t *actor)
1215 P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*20);
1218 //----------------------------------------------------------------------------
1222 //----------------------------------------------------------------------------
1224 void A_MummySoul(mobj_t *mummy)
1228 mo = P_SpawnMobj(mummy->x, mummy->y, mummy->z+10*FRACUNIT, MT_MUMMYSOUL);
1229 mo->momz = FRACUNIT;
1232 //----------------------------------------------------------------------------
1236 //----------------------------------------------------------------------------
1238 void A_Sor1Pain(mobj_t *actor)
1240 actor->special1 = 20; // Number of steps to walk fast
1244 //----------------------------------------------------------------------------
1248 //----------------------------------------------------------------------------
1250 void A_Sor1Chase(mobj_t *actor)
1260 //----------------------------------------------------------------------------
1262 // PROC A_Srcr1Attack
1264 // Sorcerer demon attack.
1266 //----------------------------------------------------------------------------
1268 void A_Srcr1Attack(mobj_t *actor)
1278 S_StartSound(actor, actor->info->attacksound);
1279 if(P_CheckMeleeRange(actor))
1281 P_DamageMobj(actor->target, actor, actor, HITDICE(8));
1284 if(actor->health > (actor->info->spawnhealth/3)*2)
1285 { // Spit one fireball
1286 P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
1289 { // Spit three fireballs
1290 mo = P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
1295 P_SpawnMissileAngle(actor, MT_SRCRFX1, angle-ANGLE_1*3, momz);
1296 P_SpawnMissileAngle(actor, MT_SRCRFX1, angle+ANGLE_1*3, momz);
1298 if(actor->health < actor->info->spawnhealth/3)
1299 { // Maybe attack again
1301 { // Just attacked, so don't attack again
1302 actor->special1 = 0;
1305 { // Set state to attack again
1306 actor->special1 = 1;
1307 P_SetMobjState(actor, S_SRCR1_ATK4);
1313 //----------------------------------------------------------------------------
1315 // PROC A_SorcererRise
1317 //----------------------------------------------------------------------------
1319 void A_SorcererRise(mobj_t *actor)
1323 actor->flags &= ~MF_SOLID;
1324 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCERER2);
1325 P_SetMobjState(mo, S_SOR2_RISE1);
1326 mo->angle = actor->angle;
1327 mo->target = actor->target;
1330 //----------------------------------------------------------------------------
1332 // PROC P_DSparilTeleport
1334 //----------------------------------------------------------------------------
1336 void P_DSparilTeleport(mobj_t *actor)
1354 x = BossSpots[i%BossSpotCount].x;
1355 y = BossSpots[i%BossSpotCount].y;
1356 } while(P_AproxDistance(actor->x-x, actor->y-y) < 128*FRACUNIT);
1360 if(P_TeleportMove(actor, x, y))
1362 mo = P_SpawnMobj(prevX, prevY, prevZ, MT_SOR2TELEFADE);
1363 S_StartSound(mo, sfx_telept);
1364 P_SetMobjState(actor, S_SOR2_TELE1);
1365 S_StartSound(actor, sfx_telept);
1366 actor->z = actor->floorz;
1367 actor->angle = BossSpots[i%BossSpotCount].angle;
1368 actor->momx = actor->momy = actor->momz = 0;
1372 //----------------------------------------------------------------------------
1374 // PROC A_Srcr2Decide
1376 //----------------------------------------------------------------------------
1378 void A_Srcr2Decide(mobj_t *actor)
1380 static int chance[] =
1382 192, 120, 120, 120, 64, 64, 32, 16, 0
1389 if(P_Random() < chance[actor->health/(actor->info->spawnhealth/8)])
1391 P_DSparilTeleport(actor);
1395 //----------------------------------------------------------------------------
1397 // PROC A_Srcr2Attack
1399 //----------------------------------------------------------------------------
1401 void A_Srcr2Attack(mobj_t *actor)
1409 S_StartSound(NULL, actor->info->attacksound);
1410 if(P_CheckMeleeRange(actor))
1412 P_DamageMobj(actor->target, actor, actor, HITDICE(20));
1415 chance = actor->health < actor->info->spawnhealth/2 ? 96 : 48;
1416 if(P_Random() < chance)
1417 { // Wizard spawners
1418 P_SpawnMissileAngle(actor, MT_SOR2FX2,
1419 actor->angle-ANG45, FRACUNIT/2);
1420 P_SpawnMissileAngle(actor, MT_SOR2FX2,
1421 actor->angle+ANG45, FRACUNIT/2);
1425 P_SpawnMissile(actor, actor->target, MT_SOR2FX1);
1429 //----------------------------------------------------------------------------
1433 //----------------------------------------------------------------------------
1435 void A_BlueSpark(mobj_t *actor)
1440 for(i = 0; i < 2; i++)
1442 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SOR2FXSPARK);
1443 mo->momx = (P_Random()-P_Random())<<9;
1444 mo->momy = (P_Random()-P_Random())<<9;
1445 mo->momz = FRACUNIT+(P_Random()<<8);
1449 //----------------------------------------------------------------------------
1453 //----------------------------------------------------------------------------
1455 void A_GenWizard(mobj_t *actor)
1460 mo = P_SpawnMobj(actor->x, actor->y,
1461 actor->z-mobjinfo[MT_WIZARD].height/2, MT_WIZARD);
1462 if(P_TestMobjLocation(mo) == false)
1467 actor->momx = actor->momy = actor->momz = 0;
1468 P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
1469 actor->flags &= ~MF_MISSILE;
1470 fog = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TFOG);
1471 S_StartSound(fog, sfx_telept);
1474 //----------------------------------------------------------------------------
1476 // PROC A_Sor2DthInit
1478 //----------------------------------------------------------------------------
1480 void A_Sor2DthInit(mobj_t *actor)
1482 actor->special1 = 7; // Animation loop counter
1483 P_Massacre(); // Kill monsters early
1486 //----------------------------------------------------------------------------
1488 // PROC A_Sor2DthLoop
1490 //----------------------------------------------------------------------------
1492 void A_Sor2DthLoop(mobj_t *actor)
1494 if(--actor->special1)
1496 P_SetMobjState(actor, S_SOR2_DIE4);
1500 //----------------------------------------------------------------------------
1502 // D'Sparil Sound Routines
1504 //----------------------------------------------------------------------------
1506 void A_SorZap(mobj_t *actor) {S_StartSound(NULL, sfx_sorzap);}
1507 void A_SorRise(mobj_t *actor) {S_StartSound(NULL, sfx_sorrise);}
1508 void A_SorDSph(mobj_t *actor) {S_StartSound(NULL, sfx_sordsph);}
1509 void A_SorDExp(mobj_t *actor) {S_StartSound(NULL, sfx_sordexp);}
1510 void A_SorDBon(mobj_t *actor) {S_StartSound(NULL, sfx_sordbon);}
1511 void A_SorSightSnd(mobj_t *actor) {S_StartSound(NULL, sfx_sorsit);}
1513 //----------------------------------------------------------------------------
1515 // PROC A_MinotaurAtk1
1519 //----------------------------------------------------------------------------
1521 void A_MinotaurAtk1(mobj_t *actor)
1529 S_StartSound(actor, sfx_stfpow);
1530 if(P_CheckMeleeRange(actor))
1532 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
1533 if((player = actor->target->player) != NULL)
1534 { // Squish the player
1535 player->deltaviewheight = -16*FRACUNIT;
1540 //----------------------------------------------------------------------------
1542 // PROC A_MinotaurDecide
1544 // Choose a missile attack.
1546 //----------------------------------------------------------------------------
1548 #define MNTR_CHARGE_SPEED (13*FRACUNIT)
1550 void A_MinotaurDecide(mobj_t *actor)
1556 target = actor->target;
1561 S_StartSound(actor, sfx_minsit);
1562 dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
1563 if(target->z+target->height > actor->z
1564 && target->z+target->height < actor->z+actor->height
1565 && dist < 8*64*FRACUNIT
1566 && dist > 1*64*FRACUNIT
1567 && P_Random() < 150)
1569 // Don't call the state function right away
1570 P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
1571 actor->flags |= MF_SKULLFLY;
1572 A_FaceTarget(actor);
1573 angle = actor->angle>>ANGLETOFINESHIFT;
1574 actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
1575 actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
1576 actor->special1 = 35/2; // Charge duration
1578 else if(target->z == target->floorz
1579 && dist < 9*64*FRACUNIT
1580 && P_Random() < 220)
1581 { // Floor fire attack
1582 P_SetMobjState(actor, S_MNTR_ATK3_1);
1583 actor->special2 = 0;
1587 A_FaceTarget(actor);
1588 // Don't need to call P_SetMobjState because the current state
1589 // falls through to the swing attack
1593 //----------------------------------------------------------------------------
1595 // PROC A_MinotaurCharge
1597 //----------------------------------------------------------------------------
1599 void A_MinotaurCharge(mobj_t *actor)
1605 puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1606 puff->momz = 2*FRACUNIT;
1611 actor->flags &= ~MF_SKULLFLY;
1612 P_SetMobjState(actor, actor->info->seestate);
1616 //----------------------------------------------------------------------------
1618 // PROC A_MinotaurAtk2
1622 //----------------------------------------------------------------------------
1624 void A_MinotaurAtk2(mobj_t *actor)
1634 S_StartSound(actor, sfx_minat2);
1635 if(P_CheckMeleeRange(actor))
1637 P_DamageMobj(actor->target, actor, actor, HITDICE(5));
1640 mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
1643 S_StartSound(mo, sfx_minat2);
1646 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/8), momz);
1647 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/8), momz);
1648 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/16), momz);
1649 P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/16), momz);
1653 //----------------------------------------------------------------------------
1655 // PROC A_MinotaurAtk3
1657 // Floor fire attack.
1659 //----------------------------------------------------------------------------
1661 void A_MinotaurAtk3(mobj_t *actor)
1670 if(P_CheckMeleeRange(actor))
1672 P_DamageMobj(actor->target, actor, actor, HITDICE(5));
1673 if((player = actor->target->player) != NULL)
1674 { // Squish the player
1675 player->deltaviewheight = -16*FRACUNIT;
1680 mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
1683 S_StartSound(mo, sfx_minat1);
1686 if(P_Random() < 192 && actor->special2 == 0)
1688 P_SetMobjState(actor, S_MNTR_ATK3_4);
1689 actor->special2 = 1;
1693 //----------------------------------------------------------------------------
1695 // PROC A_MntrFloorFire
1697 //----------------------------------------------------------------------------
1699 void A_MntrFloorFire(mobj_t *actor)
1703 actor->z = actor->floorz;
1704 mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
1705 actor->y+((P_Random()-P_Random())<<10), ONFLOORZ, MT_MNTRFX3);
1706 mo->target = actor->target;
1707 mo->momx = 1; // Force block checking
1708 P_CheckMissileSpawn(mo);
1711 //----------------------------------------------------------------------------
1713 // PROC A_BeastAttack
1715 //----------------------------------------------------------------------------
1717 void A_BeastAttack(mobj_t *actor)
1723 S_StartSound(actor, actor->info->attacksound);
1724 if(P_CheckMeleeRange(actor))
1726 P_DamageMobj(actor->target, actor, actor, HITDICE(3));
1729 P_SpawnMissile(actor, actor->target, MT_BEASTBALL);
1732 //----------------------------------------------------------------------------
1734 // PROC A_HeadAttack
1736 //----------------------------------------------------------------------------
1738 void A_HeadAttack(mobj_t *actor)
1746 static int atkResolve1[] = { 50, 150 };
1747 static int atkResolve2[] = { 150, 200 };
1750 // Ice ball (close 20% : far 60%)
1751 // Fire column (close 40% : far 20%)
1752 // Whirlwind (close 40% : far 20%)
1753 // Distance threshold = 8 cells
1755 target = actor->target;
1760 A_FaceTarget(actor);
1761 if(P_CheckMeleeRange(actor))
1763 P_DamageMobj(target, actor, actor, HITDICE(6));
1766 dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)
1768 randAttack = P_Random();
1769 if(randAttack < atkResolve1[dist])
1771 P_SpawnMissile(actor, target, MT_HEADFX1);
1772 S_StartSound(actor, sfx_hedat2);
1774 else if(randAttack < atkResolve2[dist])
1776 baseFire = P_SpawnMissile(actor, target, MT_HEADFX3);
1777 if(baseFire != NULL)
1779 P_SetMobjState(baseFire, S_HEADFX3_4); // Don't grow
1780 for(i = 0; i < 5; i++)
1782 fire = P_SpawnMobj(baseFire->x, baseFire->y,
1783 baseFire->z, MT_HEADFX3);
1786 S_StartSound(actor, sfx_hedat1);
1788 fire->target = baseFire->target;
1789 fire->angle = baseFire->angle;
1790 fire->momx = baseFire->momx;
1791 fire->momy = baseFire->momy;
1792 fire->momz = baseFire->momz;
1794 fire->health = (i+1)*2;
1795 P_CheckMissileSpawn(fire);
1801 mo = P_SpawnMissile(actor, target, MT_WHIRLWIND);
1804 mo->z -= 32*FRACUNIT;
1805 mo->special1 = (int)target;
1806 mo->special2 = 50; // Timer for active sound
1807 mo->health = 20*TICSPERSEC; // Duration
1808 S_StartSound(actor, sfx_hedat3);
1813 //----------------------------------------------------------------------------
1815 // PROC A_WhirlwindSeek
1817 //----------------------------------------------------------------------------
1819 void A_WhirlwindSeek(mobj_t *actor)
1822 if(actor->health < 0)
1824 actor->momx = actor->momy = actor->momz = 0;
1825 P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
1826 actor->flags &= ~MF_MISSILE;
1829 if((actor->special2 -= 3) < 0)
1831 actor->special2 = 58+(P_Random()&31);
1832 S_StartSound(actor, sfx_hedat3);
1835 && (((mobj_t *)(actor->special1))->flags&MF_SHADOW))
1839 P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*30);
1842 //----------------------------------------------------------------------------
1844 // PROC A_HeadIceImpact
1846 //----------------------------------------------------------------------------
1848 void A_HeadIceImpact(mobj_t *ice)
1854 for(i = 0; i < 8; i++)
1856 shard = P_SpawnMobj(ice->x, ice->y, ice->z, MT_HEADFX2);
1858 shard->target = ice->target;
1859 shard->angle = angle;
1860 angle >>= ANGLETOFINESHIFT;
1861 shard->momx = FixedMul(shard->info->speed, finecosine[angle]);
1862 shard->momy = FixedMul(shard->info->speed, finesine[angle]);
1863 shard->momz = -.6*FRACUNIT;
1864 P_CheckMissileSpawn(shard);
1868 //----------------------------------------------------------------------------
1870 // PROC A_HeadFireGrow
1872 //----------------------------------------------------------------------------
1874 void A_HeadFireGrow(mobj_t *fire)
1877 fire->z += 9*FRACUNIT;
1878 if(fire->health == 0)
1880 fire->damage = fire->info->damage;
1881 P_SetMobjState(fire, S_HEADFX3_4);
1885 //----------------------------------------------------------------------------
1887 // PROC A_SnakeAttack
1889 //----------------------------------------------------------------------------
1891 void A_SnakeAttack(mobj_t *actor)
1895 P_SetMobjState(actor, S_SNAKE_WALK1);
1898 S_StartSound(actor, actor->info->attacksound);
1899 A_FaceTarget(actor);
1900 P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_A);
1903 //----------------------------------------------------------------------------
1905 // PROC A_SnakeAttack2
1907 //----------------------------------------------------------------------------
1909 void A_SnakeAttack2(mobj_t *actor)
1913 P_SetMobjState(actor, S_SNAKE_WALK1);
1916 S_StartSound(actor, actor->info->attacksound);
1917 A_FaceTarget(actor);
1918 P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_B);
1921 //----------------------------------------------------------------------------
1923 // PROC A_ClinkAttack
1925 //----------------------------------------------------------------------------
1927 void A_ClinkAttack(mobj_t *actor)
1935 S_StartSound(actor, actor->info->attacksound);
1936 if(P_CheckMeleeRange(actor))
1938 damage = ((P_Random()%7)+3);
1939 P_DamageMobj(actor->target, actor, actor, damage);
1943 //----------------------------------------------------------------------------
1947 //----------------------------------------------------------------------------
1949 void A_GhostOff(mobj_t *actor)
1951 actor->flags &= ~MF_SHADOW;
1954 //----------------------------------------------------------------------------
1958 //----------------------------------------------------------------------------
1960 void A_WizAtk1(mobj_t *actor)
1962 A_FaceTarget(actor);
1963 actor->flags &= ~MF_SHADOW;
1966 //----------------------------------------------------------------------------
1970 //----------------------------------------------------------------------------
1972 void A_WizAtk2(mobj_t *actor)
1974 A_FaceTarget(actor);
1975 actor->flags |= MF_SHADOW;
1978 //----------------------------------------------------------------------------
1982 //----------------------------------------------------------------------------
1984 void A_WizAtk3(mobj_t *actor)
1990 actor->flags &= ~MF_SHADOW;
1995 S_StartSound(actor, actor->info->attacksound);
1996 if(P_CheckMeleeRange(actor))
1998 P_DamageMobj(actor->target, actor, actor, HITDICE(4));
2001 mo = P_SpawnMissile(actor, actor->target, MT_WIZFX1);
2006 P_SpawnMissileAngle(actor, MT_WIZFX1, angle-(ANG45/8), momz);
2007 P_SpawnMissileAngle(actor, MT_WIZFX1, angle+(ANG45/8), momz);
2011 //----------------------------------------------------------------------------
2015 //----------------------------------------------------------------------------
2017 void A_Scream(mobj_t *actor)
2024 // Make boss death sounds full volume
2025 S_StartSound(NULL, actor->info->deathsound);
2028 // Handle the different player death screams
2029 if(actor->special1 < 10)
2030 { // Wimpy death sound
2031 S_StartSound(actor, sfx_plrwdth);
2033 else if(actor->health > -50)
2034 { // Normal death sound
2035 S_StartSound(actor, actor->info->deathsound);
2037 else if(actor->health > -100)
2038 { // Crazy death sound
2039 S_StartSound(actor, sfx_plrcdth);
2042 { // Extreme death sound
2043 S_StartSound(actor, sfx_gibdth);
2047 S_StartSound(actor, actor->info->deathsound);
2052 //---------------------------------------------------------------------------
2056 //---------------------------------------------------------------------------
2058 void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
2062 if(P_Random() > chance)
2066 mo = P_SpawnMobj(source->x, source->y,
2067 source->z+(source->height>>1), type);
2068 mo->momx = (P_Random()-P_Random())<<8;
2069 mo->momy = (P_Random()-P_Random())<<8;
2070 mo->momz = FRACUNIT*5+(P_Random()<<10);
2071 mo->flags |= MF_DROPPED;
2072 mo->health = special;
2075 //----------------------------------------------------------------------------
2077 // PROC A_NoBlocking
2079 //----------------------------------------------------------------------------
2081 void A_NoBlocking(mobj_t *actor)
2083 actor->flags &= ~MF_SOLID;
2084 // Check for monsters dropping things
2088 case MT_MUMMYLEADER:
2090 case MT_MUMMYLEADERGHOST:
2091 P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
2094 case MT_KNIGHTGHOST:
2095 P_DropItem(actor, MT_AMCBOWWIMPY, 5, 84);
2098 P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
2099 P_DropItem(actor, MT_ARTITOMEOFPOWER, 0, 4);
2102 P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
2103 P_DropItem(actor, MT_ARTIEGG, 0, 51);
2106 P_DropItem(actor, MT_AMCBOWWIMPY, 10, 84);
2109 P_DropItem(actor, MT_AMSKRDWIMPY, 20, 84);
2112 P_DropItem(actor, MT_AMPHRDWIMPY, 5, 84);
2115 P_DropItem(actor, MT_ARTISUPERHEAL, 0, 51);
2116 P_DropItem(actor, MT_AMPHRDWIMPY, 10, 84);
2123 //----------------------------------------------------------------------------
2127 // Handles a bunch of exploding things.
2129 //----------------------------------------------------------------------------
2131 void A_Explode(mobj_t *actor)
2138 case MT_FIREBOMB: // Time Bombs
2139 actor->z += 32*FRACUNIT;
2140 actor->flags &= ~MF_SHADOW;
2142 case MT_MNTRFX2: // Minotaur floor fire
2145 case MT_SOR2FX1: // D'Sparil missile
2146 damage = 80+(P_Random()&31);
2151 P_RadiusAttack(actor, actor->target, damage);
2155 //----------------------------------------------------------------------------
2159 //----------------------------------------------------------------------------
2161 void A_PodPain(mobj_t *actor)
2168 chance = P_Random();
2173 count = chance > 240 ? 2 : 1;
2174 for(i = 0; i < count; i++)
2176 goo = P_SpawnMobj(actor->x, actor->y,
2177 actor->z+48*FRACUNIT, MT_PODGOO);
2178 goo->target = actor;
2179 goo->momx = (P_Random()-P_Random())<<9;
2180 goo->momy = (P_Random()-P_Random())<<9;
2181 goo->momz = FRACUNIT/2+(P_Random()<<9);
2185 //----------------------------------------------------------------------------
2189 //----------------------------------------------------------------------------
2191 void A_RemovePod(mobj_t *actor)
2197 mo = (mobj_t *)actor->special2;
2198 if(mo->special1 > 0)
2205 //----------------------------------------------------------------------------
2209 //----------------------------------------------------------------------------
2211 #define MAX_GEN_PODS 16
2213 void A_MakePod(mobj_t *actor)
2220 if(actor->special1 == MAX_GEN_PODS)
2221 { // Too many generated pods
2227 mo = P_SpawnMobj(x, y, ONFLOORZ, MT_POD);
2228 if(P_CheckPosition(mo, x, y) == false)
2233 P_SetMobjState(mo, S_POD_GROW1);
2234 P_ThrustMobj(mo, P_Random()<<24, (fixed_t)(4.5*FRACUNIT));
2235 S_StartSound(mo, sfx_newpod);
2236 actor->special1++; // Increment generated pod count
2237 mo->special2 = (int)actor; // Link the generator to the pod
2241 //----------------------------------------------------------------------------
2245 // Kills all monsters.
2247 //----------------------------------------------------------------------------
2249 void P_Massacre(void)
2254 for(think = thinkercap.next; think != &thinkercap;
2255 think = think->next)
2257 if(think->function != P_MobjThinker)
2258 { // Not a mobj thinker
2261 mo = (mobj_t *)think;
2262 if((mo->flags&MF_COUNTKILL) && (mo->health > 0))
2264 P_DamageMobj(mo, NULL, NULL, 10000);
2269 //----------------------------------------------------------------------------
2273 // Trigger special effects if all bosses are dead.
2275 //----------------------------------------------------------------------------
2277 void A_BossDeath(mobj_t *actor)
2282 static mobjtype_t bossType[6] =
2293 { // Not a boss level
2296 if(actor->type != bossType[gameepisode-1])
2297 { // Not considered a boss in this episode
2300 // Make sure all bosses are dead
2301 for(think = thinkercap.next; think != &thinkercap; think = think->next)
2303 if(think->function != P_MobjThinker)
2304 { // Not a mobj thinker
2307 mo = (mobj_t *)think;
2308 if((mo != actor) && (mo->type == actor->type) && (mo->health > 0))
2309 { // Found a living boss
2314 { // Kill any remaining monsters
2317 dummyLine.tag = 666;
2318 EV_DoFloor(&dummyLine, lowerFloor);
2321 //----------------------------------------------------------------------------
2325 //----------------------------------------------------------------------------
2327 void A_ESound(mobj_t *mo)
2333 case MT_SOUNDWATERFALL:
2334 sound = sfx_waterfl;
2342 S_StartSound(mo, sound);
2345 //----------------------------------------------------------------------------
2347 // PROC A_SpawnTeleGlitter
2349 //----------------------------------------------------------------------------
2351 void A_SpawnTeleGlitter(mobj_t *actor)
2355 mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
2356 actor->y+((P_Random()&31)-16)*FRACUNIT,
2357 actor->subsector->sector->floorheight, MT_TELEGLITTER);
2358 mo->momz = FRACUNIT/4;
2361 //----------------------------------------------------------------------------
2363 // PROC A_SpawnTeleGlitter2
2365 //----------------------------------------------------------------------------
2367 void A_SpawnTeleGlitter2(mobj_t *actor)
2371 mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
2372 actor->y+((P_Random()&31)-16)*FRACUNIT,
2373 actor->subsector->sector->floorheight, MT_TELEGLITTER2);
2374 mo->momz = FRACUNIT/4;
2377 //----------------------------------------------------------------------------
2379 // PROC A_AccTeleGlitter
2381 //----------------------------------------------------------------------------
2383 void A_AccTeleGlitter(mobj_t *actor)
2385 if(++actor->health > 35)
2387 actor->momz += actor->momz/2;
2391 //----------------------------------------------------------------------------
2393 // PROC A_InitKeyGizmo
2395 //----------------------------------------------------------------------------
2397 void A_InitKeyGizmo(mobj_t *gizmo)
2404 case MT_KEYGIZMOBLUE:
2405 state = S_KGZ_BLUEFLOAT1;
2407 case MT_KEYGIZMOGREEN:
2408 state = S_KGZ_GREENFLOAT1;
2410 case MT_KEYGIZMOYELLOW:
2411 state = S_KGZ_YELLOWFLOAT1;
2416 mo = P_SpawnMobj(gizmo->x, gizmo->y, gizmo->z+60*FRACUNIT,
2418 P_SetMobjState(mo, state);
2421 //----------------------------------------------------------------------------
2423 // PROC A_VolcanoSet
2425 //----------------------------------------------------------------------------
2427 void A_VolcanoSet(mobj_t *volcano)
2429 volcano->tics = 105+(P_Random()&127);
2432 //----------------------------------------------------------------------------
2434 // PROC A_VolcanoBlast
2436 //----------------------------------------------------------------------------
2438 void A_VolcanoBlast(mobj_t *volcano)
2445 count = 1+(P_Random()%3);
2446 for(i = 0; i < count; i++)
2448 blast = P_SpawnMobj(volcano->x, volcano->y,
2449 volcano->z+44*FRACUNIT, MT_VOLCANOBLAST); // MT_VOLCANOBLAST
2450 blast->target = volcano;
2451 angle = P_Random()<<24;
2452 blast->angle = angle;
2453 angle >>= ANGLETOFINESHIFT;
2454 blast->momx = FixedMul(1*FRACUNIT, finecosine[angle]);
2455 blast->momy = FixedMul(1*FRACUNIT, finesine[angle]);
2456 blast->momz = (2.5*FRACUNIT)+(P_Random()<<10);
2457 S_StartSound(blast, sfx_volsht);
2458 P_CheckMissileSpawn(blast);
2462 //----------------------------------------------------------------------------
2464 // PROC A_VolcBallImpact
2466 //----------------------------------------------------------------------------
2468 void A_VolcBallImpact(mobj_t *ball)
2474 if(ball->z <= ball->floorz)
2476 ball->flags |= MF_NOGRAVITY;
2477 ball->flags2 &= ~MF2_LOGRAV;
2478 ball->z += 28*FRACUNIT;
2479 //ball->momz = 3*FRACUNIT;
2481 P_RadiusAttack(ball, ball->target, 25);
2482 for(i = 0; i < 4; i++)
2484 tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_VOLCANOTBLAST);
2485 tiny->target = ball;
2487 tiny->angle = angle;
2488 angle >>= ANGLETOFINESHIFT;
2489 tiny->momx = FixedMul(FRACUNIT*.7, finecosine[angle]);
2490 tiny->momy = FixedMul(FRACUNIT*.7, finesine[angle]);
2491 tiny->momz = FRACUNIT+(P_Random()<<9);
2492 P_CheckMissileSpawn(tiny);
2496 //----------------------------------------------------------------------------
2500 //----------------------------------------------------------------------------
2502 void A_SkullPop(mobj_t *actor)
2507 actor->flags &= ~MF_SOLID;
2508 mo = P_SpawnMobj(actor->x, actor->y, actor->z+48*FRACUNIT,
2510 //mo->target = actor;
2511 mo->momx = (P_Random()-P_Random())<<9;
2512 mo->momy = (P_Random()-P_Random())<<9;
2513 mo->momz = FRACUNIT*2+(P_Random()<<6);
2514 // Attach player mobj to bloody skull
2515 player = actor->player;
2516 actor->player = NULL;
2517 mo->player = player;
2518 mo->health = actor->health;
2519 mo->angle = actor->angle;
2521 player->lookdir = 0;
2522 player->damagecount = 32;
2525 //----------------------------------------------------------------------------
2527 // PROC A_CheckSkullFloor
2529 //----------------------------------------------------------------------------
2531 void A_CheckSkullFloor(mobj_t *actor)
2533 if(actor->z <= actor->floorz)
2535 P_SetMobjState(actor, S_BLOODYSKULLX1);
2539 //----------------------------------------------------------------------------
2541 // PROC A_CheckSkullDone
2543 //----------------------------------------------------------------------------
2545 void A_CheckSkullDone(mobj_t *actor)
2547 if(actor->special2 == 666)
2549 P_SetMobjState(actor, S_BLOODYSKULLX2);
2553 //----------------------------------------------------------------------------
2555 // PROC A_CheckBurnGone
2557 //----------------------------------------------------------------------------
2559 void A_CheckBurnGone(mobj_t *actor)
2561 if(actor->special2 == 666)
2563 P_SetMobjState(actor, S_PLAY_FDTH20);
2567 //----------------------------------------------------------------------------
2569 // PROC A_FreeTargMobj
2571 //----------------------------------------------------------------------------
2573 void A_FreeTargMobj(mobj_t *mo)
2575 mo->momx = mo->momy = mo->momz = 0;
2576 mo->z = mo->ceilingz+4*FRACUNIT;
2577 mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID);
2578 mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
2579 mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
2583 //----------------------------------------------------------------------------
2585 // PROC A_AddPlayerCorpse
2587 //----------------------------------------------------------------------------
2589 #define BODYQUESIZE 32
2590 mobj_t *bodyque[BODYQUESIZE];
2593 void A_AddPlayerCorpse(mobj_t *actor)
2595 if(bodyqueslot >= BODYQUESIZE)
2596 { // Too many player corpses - remove an old one
2597 P_RemoveMobj(bodyque[bodyqueslot%BODYQUESIZE]);
2599 bodyque[bodyqueslot%BODYQUESIZE] = actor;
2603 //----------------------------------------------------------------------------
2607 //----------------------------------------------------------------------------
2609 void A_FlameSnd(mobj_t *actor)
2611 S_StartSound(actor, sfx_hedat1); // Burn sound
2614 //----------------------------------------------------------------------------
2618 //----------------------------------------------------------------------------
2620 void A_HideThing(mobj_t *actor)
2622 //P_UnsetThingPosition(actor);
2623 actor->flags2 |= MF2_DONTDRAW;
2626 //----------------------------------------------------------------------------
2628 // PROC A_UnHideThing
2630 //----------------------------------------------------------------------------
2632 void A_UnHideThing(mobj_t *actor)
2634 //P_SetThingPosition(actor);
2635 actor->flags2 &= ~MF2_DONTDRAW;