// Ironlich ----------------------------------------------------------------- class Ironlich : Actor { Default { Health 700; Radius 40; Height 72; Mass 325; Speed 6; Painchance 32; Monster; +NOBLOOD +DONTMORPH +DONTSQUASH +BOSSDEATH SeeSound "ironlich/sight"; AttackSound "ironlich/attack"; PainSound "ironlich/pain"; DeathSound "ironlich/death"; ActiveSound "ironlich/active"; Obituary "$OB_IRONLICH"; HitObituary "$OB_IRONLICHHIT"; DropItem "BlasterAmmo", 84, 10; DropItem "ArtiEgg", 51, 0; } States { Spawn: LICH A 10 A_Look; Loop; See: LICH A 4 A_Chase; Loop; Missile: LICH A 5 A_FaceTarget; LICH B 20 A_LichAttack; Goto See; Pain: LICH A 4; LICH A 4 A_Pain; Goto See; Death: LICH C 7; LICH D 7 A_Scream; LICH EF 7; LICH G 7 A_NoBlocking; LICH H 7; LICH I -1 A_BossDeath; Stop; } //---------------------------------------------------------------------------- // // PROC A_LichAttack // //---------------------------------------------------------------------------- void A_LichAttack () { static const int atkResolve1[] = { 50, 150 }; static const int atkResolve2[] = { 150, 200 }; // Ice ball (close 20% : far 60%) // Fire column (close 40% : far 20%) // Whirlwind (close 40% : far 20%) // Distance threshold = 8 cells if (target == null) { return; } A_FaceTarget (); if (CheckMeleeRange ()) { int damage = random[LichAttack](1, 8) * 6; int newdam = target.DamageMobj (self, self, damage, 'Melee'); target.TraceBleed (newdam > 0 ? newdam : damage, self); return; } int dist = Distance2D(target) > 8 * 64; int randAttack = random[LichAttack](); if (randAttack < atkResolve1[dist]) { // Ice ball SpawnMissile (target, "HeadFX1"); A_PlaySound ("ironlich/attack2", CHAN_BODY); } else if (randAttack < atkResolve2[dist]) { // Fire column Actor baseFire = SpawnMissile (target, "HeadFX3"); if (baseFire != null) { baseFire.SetStateLabel("NoGrow"); for (int i = 0; i < 5; i++) { Actor fire = Spawn("HeadFX3", baseFire.Pos, ALLOW_REPLACE); if (i == 0) { A_PlaySound ("ironlich/attack1", CHAN_BODY); } if (fire != null) { fire.target = baseFire.target; fire.angle = baseFire.angle; fire.Vel = baseFire.Vel; fire.SetDamage(0); fire.health = (i+1) * 2; fire.CheckMissileSpawn (radius); } } } } else { // Whirlwind Actor mo = SpawnMissile (target, "Whirlwind"); if (mo != null) { mo.AddZ(-32); mo.tracer = target; mo.health = 20*TICRATE; // Duration A_PlaySound ("ironlich/attack3", CHAN_BODY); } } } } // Head FX 1 ---------------------------------------------------------------- class HeadFX1 : Actor { Default { Radius 12; Height 6; Speed 13; FastSpeed 20; Damage 1; Projectile; -ACTIVATEIMPACT -ACTIVATEPCROSS +THRUGHOST RenderStyle "Add"; } States { Spawn: FX05 ABC 6 BRIGHT; Loop; Death: FX05 D 5 BRIGHT A_LichIceImpact; FX05 EFG 5 BRIGHT; Stop; } //---------------------------------------------------------------------------- // // PROC A_LichIceImpact // //---------------------------------------------------------------------------- void A_LichIceImpact() { for (int i = 0; i < 8; i++) { Actor shard = Spawn("HeadFX2", Pos, ALLOW_REPLACE); if (shard != null) { shard.target = target; shard.angle = i*45.; shard.VelFromAngle(); shard.Vel.Z = -.6; shard.CheckMissileSpawn (radius); } } } } // Head FX 2 ---------------------------------------------------------------- class HeadFX2 : Actor { Default { Radius 12; Height 6; Speed 8; Damage 3; Projectile; -ACTIVATEIMPACT -ACTIVATEPCROSS RenderStyle "Add"; } States { Spawn: FX05 HIJ 6 BRIGHT; Loop; Death: FX05 DEFG 5 BRIGHT; Stop; } } // Head FX 3 ---------------------------------------------------------------- class HeadFX3 : Actor { Default { Radius 14; Height 12; Speed 10; FastSpeed 18; Damage 5; Projectile; +WINDTHRUST -ACTIVATEIMPACT -ACTIVATEPCROSS -NOBLOCKMAP RenderStyle "Add"; } States { Spawn: FX06 ABC 4 BRIGHT A_LichFireGrow; Loop; NoGrow: FX06 ABC 5 BRIGHT; Loop; Death: FX06 DEFG 5 BRIGHT; Stop; } //---------------------------------------------------------------------------- // // PROC A_LichFireGrow // //---------------------------------------------------------------------------- void A_LichFireGrow () { health--; AddZ(9.); if (health == 0) { RestoreDamage(); SetStateLabel("NoGrow"); } } } // Whirlwind ---------------------------------------------------------------- class Whirlwind : Actor { Default { Radius 16; Height 74; Speed 10; Damage 1; Projectile; -ACTIVATEIMPACT -ACTIVATEMCROSS +SEEKERMISSILE +EXPLOCOUNT +StepMissile RenderStyle "Translucent"; DefThreshold 60; Threshold 50; Alpha 0.4; } States { Spawn: FX07 DEFG 3; FX07 ABC 3 A_WhirlwindSeek; Goto Spawn+4; Death: FX07 GFED 4; Stop; } override int DoSpecialDamage (Actor target, int damage, Name damagetype) { int randVal; if (!target.bDontThrust) { target.angle += Random2[WhirlwindDamage]() * (360 / 4096.); target.Vel.X += Random2[WhirlwindDamage]() / 64.; target.Vel.Y += Random2[WhirlwindDamage]() / 64.; } if ((level.time & 16) && !target.bBoss && !target.bDontThrust) { randVal = min(160, random[WhirlwindSeek]()); target.Vel.Z += randVal / 32.; if (target.Vel.Z > 12) { target.Vel.Z = 12; } } if (!(level.time & 7)) { target.DamageMobj (null, target, 3, 'Melee'); } return -1; } //---------------------------------------------------------------------------- // // PROC A_WhirlwindSeek // //---------------------------------------------------------------------------- void A_WhirlwindSeek() { health -= 3; if (health < 0) { Vel = (0,0,0); SetStateLabel("Death"); bMissile = false; return; } if ((threshold -= 3) < 0) { threshold = 58 + (random[WhirlwindSeek]() & 31); A_PlaySound("ironlich/attack3", CHAN_BODY); } if (tracer && tracer.bShadow) { return; } A_SeekerMissile(10, 30); } }