// FireDemon ---------------------------------------------------------------- class FireDemon : Actor { const FIREDEMON_ATTACK_RANGE = 64*8.; int fdstrafecount; Default { Health 80; ReactionTime 8; PainChance 1; Speed 13; Radius 20; Height 68; Mass 75; Damage 1; Monster; +DROPOFF +NOGRAVITY +FLOAT +FLOORCLIP +INVULNERABLE +TELESTOMP SeeSound "FireDemonSpawn"; PainSound "FireDemonPain"; DeathSound "FireDemonDeath"; ActiveSound "FireDemonActive"; Obituary "$OB_FIREDEMON"; Tag "$FN_FIREDEMON"; } States { Spawn: FDMN X 5 Bright; FDMN EFG 10 Bright A_Look; Goto Spawn + 1; See: FDMN E 8 Bright; FDMN F 6 Bright; FDMN G 5 Bright; FDMN F 8 Bright; FDMN E 6 Bright; FDMN G 7 Bright A_FiredRocks; FDMN HI 5 Bright; FDMN J 5 Bright A_UnSetInvulnerable; Chase: FDMN ABC 5 Bright A_FiredChase; Loop; Pain: FDMN D 0 Bright A_UnSetInvulnerable; FDMN D 6 Bright A_Pain; Goto Chase; Missile: FDMN K 3 Bright A_FaceTarget; FDMN KKK 5 Bright A_FiredAttack; Goto Chase; Crash: XDeath: FDMN M 5 A_FaceTarget; FDMN N 5 A_NoBlocking; FDMN O 5 A_FiredSplotch; Stop; Death: FDMN D 4 Bright A_FaceTarget; FDMN L 4 Bright A_Scream; FDMN L 4 Bright A_NoBlocking; FDMN L 200 Bright; Stop; Ice: FDMN R 5 A_FreezeDeath; FDMN R 1 A_FreezeDeathChunks; Wait; } //============================================================================ // Fire Demon AI // // special1 index into floatbob // fdstrafecount whether strafing or not //============================================================================ //============================================================================ // // A_FiredSpawnRock // //============================================================================ private void A_FiredSpawnRock () { Actor mo; class<Actor> rtype; switch (random[FireDemonRock](0, 4)) { case 0: rtype = "FireDemonRock1"; break; case 1: rtype = "FireDemonRock2"; break; case 2: rtype = "FireDemonRock3"; break; case 3: rtype = "FireDemonRock4"; break; case 4: default: rtype = "FireDemonRock5"; break; } double xo = (random[FireDemonRock]() - 128) / 16.; double yo = (random[FireDemonRock]() - 128) / 16.; double zo = random[FireDemonRock]() / 32.; mo = Spawn (rtype, Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo.target = self; mo.Vel.X = (random[FireDemonRock]() - 128) / 64.; mo.Vel.Y = (random[FireDemonRock]() - 128) / 64.; mo.Vel.Z = (random[FireDemonRock]() / 64.); mo.special1 = 2; // Number bounces } // Initialize fire demon fdstrafecount = 0; bJustAttacked = false; } //============================================================================ // // A_FiredRocks // //============================================================================ void A_FiredRocks() { A_FiredSpawnRock (); A_FiredSpawnRock (); A_FiredSpawnRock (); A_FiredSpawnRock (); A_FiredSpawnRock (); } //============================================================================ // // A_FiredAttack // //============================================================================ void A_FiredAttack() { if (target == null) return; Actor mo = SpawnMissile (target, "FireDemonMissile"); if (mo) A_PlaySound ("FireDemonAttack", CHAN_BODY); } //============================================================================ // // A_FiredChase // //============================================================================ void A_FiredChase() { int weaveindex = special1; double ang; double dist; if (reactiontime) reactiontime--; if (threshold) threshold--; // Float up and down AddZ(BobSin(weaveindex)); special1 = (weaveindex + 2) & 63; // Ensure it stays above certain height if (pos.Z < floorz + 64) { AddZ(2); } if(!target || !target.bShootable) { // Invalid target LookForPlayers (true); return; } // Strafe if (fdstrafecount > 0) { fdstrafecount--; } else { fdstrafecount = 0; Vel.X = Vel.Y = 0; dist = Distance2D(target); if (dist < FIREDEMON_ATTACK_RANGE) { if (random[FiredChase]() < 30) { ang = AngleTo(target); if (random[FiredChase]() < 128) ang += 90; else ang -= 90; Thrust(8, ang); fdstrafecount = 3; // strafe time } } } FaceMovementDirection (); // Normal movement if (!fdstrafecount) { if (--movecount<0 || !MonsterMove ()) { NewChaseDir (); } } // Do missile attack if (!bJustAttacked) { if (CheckMissileRange () && (random[FiredChase]() < 20)) { SetState (MissileState); bJustAttacked = true; return; } } else { bJustAttacked = false; } // make active sound if (random[FiredChase]() < 3) { PlayActiveSound (); } } //============================================================================ // // A_FiredSplotch // //============================================================================ void A_FiredSplotch() { Actor mo; mo = Spawn ("FireDemonSplotch1", Pos, ALLOW_REPLACE); if (mo) { mo.Vel.X = (random[FireDemonSplotch]() - 128) / 32.; mo.Vel.Y = (random[FireDemonSplotch]() - 128) / 32.; mo.Vel.Z = (random[FireDemonSplotch]() / 64.) + 3; } mo = Spawn ("FireDemonSplotch2", Pos, ALLOW_REPLACE); if (mo) { mo.Vel.X = (random[FireDemonSplotch]() - 128) / 32.; mo.Vel.Y = (random[FireDemonSplotch]() - 128) / 32.; mo.Vel.Z = (random[FireDemonSplotch]() / 64.) + 3; } } } // FireDemonSplotch1 ------------------------------------------------------- class FireDemonSplotch1 : Actor { Default { ReactionTime 8; Radius 3; Height 16; Mass 100; +DROPOFF +CORPSE +NOTELEPORT +FLOORCLIP } States { Spawn: FDMN P 3; FDMN P 6 A_QueueCorpse; FDMN Y -1; Stop; } } // FireDemonSplotch2 ------------------------------------------------------- class FireDemonSplotch2 : FireDemonSplotch1 { States { Spawn: FDMN Q 3; FDMN Q 6 A_QueueCorpse; FDMN Z -1; Stop; } } // FireDemonRock1 ------------------------------------------------------------ class FireDemonRock1 : Actor { Default { ReactionTime 8; Radius 3; Height 5; Mass 16; +NOBLOCKMAP +DROPOFF +MISSILE +NOTELEPORT } States { Spawn: FDMN S 4; Loop; Death: FDMN S 5 A_SmBounce; XDeath: FDMN S 200; Stop; } //============================================================================ // // A_SmBounce // //============================================================================ void A_SmBounce() { // give some more velocity (x,y,&z) SetZ(floorz + 1); Vel.Z = 2. + random[SMBounce]() / 64.; Vel.X = random[SMBounce](0, 2); Vel.Y = random[SMBounce](0, 2); } } // FireDemonRock2 ------------------------------------------------------------ class FireDemonRock2 : FireDemonRock1 { States { Spawn: FDMN T 4; Loop; Death: FDMN T 5 A_SmBounce; XDeath: FDMN T 200; Stop; } } // FireDemonRock3 ------------------------------------------------------------ class FireDemonRock3 : FireDemonRock1 { States { Spawn: FDMN U 4; Loop; Death: FDMN U 5 A_SmBounce; XDeath: FDMN U 200; Stop; } } // FireDemonRock4 ------------------------------------------------------------ class FireDemonRock4 : FireDemonRock1 { States { Spawn: FDMN V 4; Loop; Death: FDMN V 5 A_SmBounce; XDeath: FDMN V 200; Stop; } } // FireDemonRock5 ------------------------------------------------------------ class FireDemonRock5 : FireDemonRock1 { States { Spawn: FDMN W 4; Loop; Death: FDMN W 5 A_SmBounce; XDeath: FDMN W 200; Stop; } } // FireDemonMissile ----------------------------------------------------------- class FireDemonMissile : Actor { Default { ReactionTime 8; Speed 10; Radius 10; Height 6; Mass 5; Damage 1; DamageType "Fire"; Projectile; RenderStyle "Add"; DeathSound "FireDemonMissileHit"; +ZDOOMTRANS } States { Spawn: FDMB A 5 Bright; Loop; Death: FDMB BCDE 5 Bright; Stop; } }