diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c1242853d..828c7fc34 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES
 	g_hexen/a_heresiarch.cpp
 	g_hexen/a_hexenspecialdecs.cpp
 	g_hexen/a_iceguy.cpp
-	g_hexen/a_korax.cpp
 	g_hexen/a_magecone.cpp
 	g_hexen/a_magelightning.cpp
 	g_hexen/a_magestaff.cpp
diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp
index 7bd38ceab..3fb334cb1 100644
--- a/src/g_hexen/a_hexenmisc.cpp
+++ b/src/g_hexen/a_hexenmisc.cpp
@@ -36,7 +36,6 @@
 #include "a_heresiarch.cpp"
 #include "a_hexenspecialdecs.cpp"
 #include "a_iceguy.cpp"
-#include "a_korax.cpp"
 #include "a_magecone.cpp"
 #include "a_magelightning.cpp"
 #include "a_magestaff.cpp"
diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp
deleted file mode 100644
index 8a459ffd4..000000000
--- a/src/g_hexen/a_korax.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
-//===========================================================================
-// Korax Variables
-//	tracer		last teleport destination
-//	special2	set if "below half" script not yet run
-//
-// Korax Scripts (reserved)
-//	249		Tell scripts that we are below half health
-//	250-254	Control scripts (254 is only used when less than half health)
-//	255		Death script
-//
-// Korax TIDs (reserved)
-//	245		Reserved for Korax himself
-//  248		Initial teleport destination
-//	249		Teleport destination
-//	250-254	For use in respective control scripts
-//	255		For use in death script (spawn spots)
-//===========================================================================
-
-/*
-#include "actor.h"
-#include "info.h"
-#include "p_local.h"
-#include "p_spec.h"
-#include "s_sound.h"
-#include "a_action.h"
-#include "m_random.h"
-#include "i_system.h"
-#include "vm.h"
-#include "g_level.h"
-*/
-
-const int KORAX_SPIRIT_LIFETIME = 5*TICRATE/5;	// 5 seconds
-const int KORAX_COMMAND_HEIGHT	= 120;
-const int KORAX_COMMAND_OFFSET	= 27;
-
-const int KORAX_TID					= 245;
-const int KORAX_FIRST_TELEPORT_TID	= 248;
-const int KORAX_TELEPORT_TID		= 249;
-
-const int KORAX_DELTAANGLE			= 85;
-const int KORAX_ARM_EXTENSION_SHORT	= 40;
-const int KORAX_ARM_EXTENSION_LONG	= 55;
-
-const int KORAX_ARM1_HEIGHT			= 108;
-const int KORAX_ARM2_HEIGHT			= 82;
-const int KORAX_ARM3_HEIGHT			= 54;
-const int KORAX_ARM4_HEIGHT			= 104;
-const int KORAX_ARM5_HEIGHT			= 86;
-const int KORAX_ARM6_HEIGHT			= 53;
-
-const double KORAX_BOLT_HEIGHT		= 48.;
-const int KORAX_BOLT_LIFETIME		= 3;
-
-
-
-static FRandom pr_koraxchase ("KoraxChase");
-static FRandom pr_kspiritinit ("KSpiritInit");
-static FRandom pr_koraxdecide ("KoraxDecide");
-static FRandom pr_koraxmissile ("KoraxMissile");
-static FRandom pr_koraxcommand ("KoraxCommand");
-static FRandom pr_kspiritweave ("KSpiritWeave");
-static FRandom pr_kspiritseek ("KSpiritSeek");
-static FRandom pr_kspiritroam ("KSpiritRoam");
-static FRandom pr_kmissile ("SKoraxMissile");
-
-void A_KoraxChase (AActor *);
-void A_KoraxStep (AActor *);
-void A_KoraxStep2 (AActor *);
-void A_KoraxDecide (AActor *);
-void A_KoraxBonePop (AActor *);
-void A_KoraxMissile (AActor *);
-void A_KoraxCommand (AActor *);
-void A_KSpiritRoam (AActor *);
-void A_KBolt (AActor *);
-void A_KBoltRaise (AActor *);
-
-void KoraxFire (AActor *actor, PClassActor *type, int arm);
-void KSpiritInit (AActor *spirit, AActor *korax);
-AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type);
-
-extern void SpawnSpiritTail (AActor *spirit);
-
-//============================================================================
-//
-// A_KoraxChase
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	AActor *spot;
-
-	if ((!self->special2) && (self->health <= (self->SpawnHealth()/2)))
-	{
-		FActorIterator iterator (KORAX_FIRST_TELEPORT_TID);
-		spot = iterator.Next ();
-		if (spot != NULL)
-		{
-			P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG);
-		}
-
-		P_StartScript (self, NULL, 249, NULL, NULL, 0, 0);
-		self->special2 = 1;	// Don't run again
-
-		return 0;
-	}
-
-	if (self->target == NULL)
-	{
-		return 0;
-	}
-	if (pr_koraxchase()<30)
-	{
-		self->SetState (self->MissileState);
-	}
-	else if (pr_koraxchase()<30)
-	{
-		S_Sound (self, CHAN_VOICE, "KoraxActive", 1, ATTN_NONE);
-	}
-
-	// Teleport away
-	if (self->health < (self->SpawnHealth()>>1))
-	{
-		if (pr_koraxchase()<10)
-		{
-			FActorIterator iterator (KORAX_TELEPORT_TID);
-
-			if (self->tracer != NULL)
-			{	// Find the previous teleport destination
-				do
-				{
-					spot = iterator.Next ();
-				} while (spot != NULL && spot != self->tracer);
-			}
-
-			// Go to the next teleport destination
-			spot = iterator.Next ();
-			self->tracer = spot;
-			if (spot)
-			{
-				P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG);
-			}
-		}
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// A_KoraxBonePop
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	AActor *mo;
-	int i;
-
-	// Spawn 6 spirits equalangularly
-	for (i = 0; i < 6; ++i)
-	{
-		mo = P_SpawnMissileAngle (self, PClass::FindActor("KoraxSpirit"), DAngle(60.*i), 5.);
-		if (mo)
-		{
-			KSpiritInit (mo, self);
-		}
-	}
-
-	P_StartScript (self, NULL, 255, NULL, NULL, 0, 0);		// Death script
-	return 0;
-}
-
-//============================================================================
-//
-// KSpiritInit
-//
-//============================================================================
-
-void KSpiritInit (AActor *spirit, AActor *korax)
-{
-	spirit->health = KORAX_SPIRIT_LIFETIME;
-
-	spirit->tracer = korax;						// Swarm around korax
-	spirit->WeaveIndexZ = 32 + (pr_kspiritinit() & 7);	// Float bob index
-	spirit->args[0] = 10; 						// initial turn value
-	spirit->args[1] = 0; 						// initial look angle
-
-#if 0 // Temporarily deactivated.
-	// Spawn a tail for spirit
-	HolyTail.SpawnSpiritTail (spirit);
-#endif
-
-}
-
-//============================================================================
-//
-// A_KoraxDecide
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	if (pr_koraxdecide()<220)
-	{
-		self->SetState (self->FindState("Attack"));
-	}
-	else
-	{
-		self->SetState (self->FindState("Command"));
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// A_KoraxMissile
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	static const struct { const char *type, *sound; } choices[6] =
-	{
-		{ "WraithFX1", "WraithMissileFire" },
-		{ "Demon1FX1", "DemonMissileFire" },
-		{ "Demon2FX1", "DemonMissileFire" },
-		{ "FireDemonMissile", "FireDemonAttack" },
-		{ "CentaurFX", "CentaurLeaderAttack" },
-		{ "SerpentFX", "CentaurLeaderAttack" }
-	};
-
-	int type = pr_koraxmissile() % 6;
-	int i;
-	PClassActor *info;
-
-	S_Sound(self, CHAN_VOICE, "KoraxAttack", 1, ATTN_NORM);
-
-	info = PClass::FindActor(choices[type].type);
-	if (info == NULL)
-	{
-		I_Error("Unknown Korax missile: %s\n", choices[type].type);
-	}
-
-	// Fire all 6 missiles at once
-	S_Sound(self, CHAN_WEAPON, choices[type].sound, 1, ATTN_NONE);
-	for (i = 0; i < 6; ++i)
-	{
-		KoraxFire(self, info, i);
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// A_KoraxCommand
-//
-// Call action code scripts (250-254)
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-	DAngle ang;
-	int numcommands;
-
-	S_Sound (self, CHAN_VOICE, "KoraxCommand", 1, ATTN_NORM);
-
-	// Shoot stream of lightning to ceiling
-	ang = self->Angles.Yaw - 90;
-	DVector3 pos = self->Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT);
-	Spawn("KoraxBolt", pos, ALLOW_REPLACE);
-
-	if (self->health <= (self->SpawnHealth() >> 1))
-	{
-		numcommands = 5;
-	}
-	else
-	{
-		numcommands = 4;
-	}
-
-	P_StartScript (self, NULL, 250+(pr_koraxcommand()%numcommands), NULL, NULL, 0, 0);
-	return 0;
-}
-
-//============================================================================
-//
-// KoraxFire
-//
-// Arm projectiles
-//		arm positions numbered:
-//			1	top left
-//			2	middle left
-//			3	lower left
-//			4	top right
-//			5	middle right
-//			6	lower right
-//
-//============================================================================
-
-void KoraxFire (AActor *actor, PClassActor *type, int arm)
-{
-	static const int extension[6] =
-	{
-		KORAX_ARM_EXTENSION_SHORT,
-		KORAX_ARM_EXTENSION_LONG,
-		KORAX_ARM_EXTENSION_LONG,
-		KORAX_ARM_EXTENSION_SHORT,
-		KORAX_ARM_EXTENSION_LONG,
-		KORAX_ARM_EXTENSION_LONG
-	};
-	static const int armheight[6] =
-	{
-		KORAX_ARM1_HEIGHT,
-		KORAX_ARM2_HEIGHT,
-		KORAX_ARM3_HEIGHT,
-		KORAX_ARM4_HEIGHT,
-		KORAX_ARM5_HEIGHT,
-		KORAX_ARM6_HEIGHT
-	};
-
-	DAngle ang = actor->Angles.Yaw + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE);
-	DVector3 pos = actor->Vec3Angle(extension[arm], ang, armheight[arm] - actor->Floorclip);
-	P_SpawnKoraxMissile (pos, actor, actor->target, type);
-}
-
-//============================================================================
-//
-// A_KSpiritSeeker
-//
-//============================================================================
-
-static void A_KSpiritSeeker (AActor *actor, DAngle thresh, DAngle turnMax)
-{
-	int dir;
-	DAngle delta;
-	AActor *target;
-	double newZ;
-	double deltaZ;
-
-	target = actor->tracer;
-	if (target == NULL)
-	{
-		return;
-	}
-	dir = P_FaceMobj (actor, target, &delta);
-	if (delta > thresh)
-	{
-		delta /= 2;
-		if(delta > turnMax)
-		{
-			delta = turnMax;
-		}
-	}
-	if(dir)
-	{ // Turn clockwise
-		actor->Angles.Yaw += delta;
-	}
-	else
-	{ // Turn counter clockwise
-		actor->Angles.Yaw -= delta;
-	}
-	actor->VelFromAngle();
-
-	if (!(level.time&15) 
-		|| actor->Z() > target->Z() + target->GetDefault()->Height
-		|| actor->Top() < target->Z())
-	{
-		newZ = target->Z() + pr_kspiritseek() * target->GetDefault()->Height / 256;
-		deltaZ = newZ-actor->Z();
-
-		if (fabs(deltaZ) > 15)
-		{
-			if(deltaZ > 0)
-			{
-				deltaZ = 15;
-			}
-			else
-			{
-				deltaZ = -15;
-			}
-		}
-		actor->Vel.Z = deltaZ + actor->DistanceBySpeed(target, actor->Speed);
-	}
-	return;
-}
-
-//============================================================================
-//
-// A_KSpiritRoam
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	if (self->health-- <= 0)
-	{
-		S_Sound (self, CHAN_VOICE, "SpiritDie", 1, ATTN_NORM);
-		self->SetState (self->FindState("Death"));
-	}
-	else
-	{
-		if (self->tracer)
-		{
-			A_KSpiritSeeker(self, (double)self->args[0], self->args[0] * 2.);
-		}
-		int xyspeed = (pr_kspiritweave() % 5);
-		int zspeed = (pr_kspiritweave() % 5);
-		A_Weave(self, xyspeed, zspeed, 4., 2.);
-
-		if (pr_kspiritroam()<50)
-		{
-			S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NONE);
-		}
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// A_KBolt
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KBolt)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	// Countdown lifetime
-	if (self->special1-- <= 0)
-	{
-		self->Destroy ();
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// A_KBoltRaise
-//
-//============================================================================
-
-DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	AActor *mo;
-
-	// Spawn a child upward
-	double z = self->Z() + KORAX_BOLT_HEIGHT;
-
-	if ((z + KORAX_BOLT_HEIGHT) < self->ceilingz)
-	{
-		mo = Spawn("KoraxBolt", self->PosAtZ(z), ALLOW_REPLACE);
-		if (mo)
-		{
-			mo->special1 = KORAX_BOLT_LIFETIME;
-		}
-	}
-	else
-	{
-		// Maybe cap it off here
-	}
-	return 0;
-}
-
-//============================================================================
-//
-// P_SpawnKoraxMissile
-//
-//============================================================================
-
-AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type)
-{
-	AActor *th;
-	DAngle an;
-	double dist;
-
-	th = Spawn (type, pos, ALLOW_REPLACE);
-	th->target = source; // Originator
-	an = th->AngleTo(dest);
-	if (dest->flags & MF_SHADOW)
-	{ // Invisible target
-		an += pr_kmissile.Random2() * (45/256.);
-	}
-	th->Angles.Yaw = an;
-	th->VelFromAngle();
-	dist = dest->DistanceBySpeed(th, th->Speed);
-	th->Vel.Z = (dest->Z() - pos.Z + 30) / dist;
-	return (P_CheckMissileSpawn(th, source->radius) ? th : NULL);
-}
diff --git a/wadsrc/static/zscript/hexen/korax.txt b/wadsrc/static/zscript/hexen/korax.txt
index 16bf172a4..1c1f31712 100644
--- a/wadsrc/static/zscript/hexen/korax.txt
+++ b/wadsrc/static/zscript/hexen/korax.txt
@@ -1,5 +1,43 @@
+//===========================================================================
+// Korax Variables
+//	tracer		last teleport destination
+//	special2	set if "below half" script not yet run
+//
+// Korax Scripts (reserved)
+//	249		Tell scripts that we are below half health
+//	250-254	Control scripts (254 is only used when less than half health)
+//	255		Death script
+//
+// Korax TIDs (reserved)
+//	245		Reserved for Korax himself
+//  248		Initial teleport destination
+//	249		Teleport destination
+//	250-254	For use in respective control scripts
+//	255		For use in death script (spawn spots)
+//===========================================================================
+
 class Korax : Actor
 {
+	const KORAX_ARM_EXTENSION_SHORT	= 40;
+	const KORAX_ARM_EXTENSION_LONG	= 55;
+
+	const KORAX_ARM1_HEIGHT			= 108;
+	const KORAX_ARM2_HEIGHT			= 82;
+	const KORAX_ARM3_HEIGHT			= 54;
+	const KORAX_ARM4_HEIGHT			= 104;
+	const KORAX_ARM5_HEIGHT			= 86;
+	const KORAX_ARM6_HEIGHT			= 53;
+
+	const KORAX_FIRST_TELEPORT_TID	= 248;
+	const KORAX_TELEPORT_TID		= 249;
+
+	const KORAX_DELTAANGLE			= 85;
+
+	const KORAX_COMMAND_HEIGHT	= 120;
+	const KORAX_COMMAND_OFFSET	= 27;
+
+	const KORAX_SPIRIT_LIFETIME = 5*TICRATE/5;	// 5 seconds
+
 	Default
 	{
 		Health 5000;
@@ -24,12 +62,6 @@ class Korax : Actor
 		Obituary "$OB_KORAX";
 	}
 
-	native void A_KoraxChase();
-	native void A_KoraxDecide();
-	native void A_KoraxBonePop();
-	native void A_KoraxMissile();
-	native void A_KoraxCommand();
-
 	States
 	{
 	Spawn:
@@ -39,13 +71,11 @@ class Korax : Actor
 		KORX AAA 3 A_KoraxChase;
 		KORX B 3 A_Chase;
 		KORX BBB 3 A_KoraxChase;
-		KORX C 0 A_PlaySound("KoraxStep");
-		KORX C 3 A_Chase;
+		KORX C 3 A_KoraxStep;
 		KORX CCC 3 A_KoraxChase;
 		KORX D 3 A_Chase;
 		KORX DDD 3 A_KoraxChase;
-		KORX A 0 A_PlaySound("KoraxStep");
-		KORX A 3 A_Chase;
+		KORX A 3 A_KoraxStep;
 		Loop;
 	Pain:
 		KORX H 5 A_Pain;
@@ -79,6 +109,255 @@ class Korax : Actor
 		KORX E 5 Bright;
 		Goto See;
 	}
+	
+	
+	void A_KoraxStep()
+	{ 
+		A_PlaySound("KoraxStep"); 
+		A_Chase(); 
+	}	
+	
+	//============================================================================
+	//
+	// A_KoraxChase
+	//
+	//============================================================================
+
+
+	void A_KoraxChase()
+	{
+		if ((!special2) && (health <= (SpawnHealth()/2)))
+		{
+			ActorIterator it = ActorIterator.Create(KORAX_FIRST_TELEPORT_TID);
+			Actor spot = it.Next ();
+			if (spot != null)
+			{
+				Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG);
+			}
+			ACS_Execute(249, 0);
+			special2 = 1;	// Don't run again
+			return;
+		}
+
+		if (target == null)
+		{
+			return;
+		}
+		if (random[KoraxChase]() < 30)
+		{
+			SetState (MissileState);
+		}
+		else if (random[KoraxChase]() < 30)
+		{
+			A_PlaySound("KoraxActive", CHAN_VOICE, 1, false, ATTN_NONE);
+		}
+
+		// Teleport away
+		if (health < (SpawnHealth() >> 1))
+		{
+			if (random[KoraxChase]() < 10)
+			{
+				ActorIterator it = ActorIterator.Create(KORAX_TELEPORT_TID);
+				Actor spot;
+
+				if (tracer != null)
+				{	// Find the previous teleport destination
+					do
+					{
+						spot = it.Next ();
+					} while (spot != null && spot != tracer);
+				}
+
+				// Go to the next teleport destination
+				spot = it.Next ();
+				tracer = spot;
+				if (spot)
+				{
+					Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG);
+				}
+			}
+		}
+	}
+
+	//============================================================================
+	//
+	// A_KoraxDecide
+	//
+	//============================================================================
+
+	void A_KoraxDecide()
+	{
+		if (random[KoraxDecide]() < 220)
+		{
+			SetStateLabel ("Attack");
+		}
+		else
+		{
+			SetStateLabel ("Command");
+		}
+	}
+
+	//============================================================================
+	//
+	// A_KoraxBonePop
+	//
+	//============================================================================
+
+	void A_KoraxBonePop()
+	{
+		// Spawn 6 spirits equalangularly
+		for (int i = 0; i < 6; ++i)
+		{
+			Actor mo = SpawnMissileAngle ("KoraxSpirit", 60.*i, 5.);
+			if (mo)
+			{
+				KSpiritInit (mo);
+			}
+		}
+		ACS_Execute(255, 0);
+	}
+
+	//============================================================================
+	//
+	// KSpiritInit
+	//
+	//============================================================================
+
+	private void KSpiritInit (Actor spirit)
+	{
+		spirit.health = KORAX_SPIRIT_LIFETIME;
+
+		spirit.tracer = self;						// Swarm around korax
+		spirit.WeaveIndexZ = 32 + (random[Kspiritnit]() & 7);	// Float bob index
+		spirit.args[0] = 10; 						// initial turn value
+		spirit.args[1] = 0; 						// initial look angle
+
+		// Spawn a tail for spirit
+		HolyTail.SpawnSpiritTail (spirit);
+	}
+
+	//============================================================================
+	//
+	// A_KoraxMissile
+	//
+	//============================================================================
+
+	void A_KoraxMissile()
+	{
+		static const class<Actor> choices[] =
+		{
+			"WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX"
+		};
+		static const sound sounds[] = 
+		{
+			"WraithMissileFire", "DemonMissileFire", "DemonMissileFire", "FireDemonAttack", "CentaurLeaderAttack", "SerpentLeaderAttack"
+		};
+		int type = random[KoraxMissile]() % 6;
+
+		A_PlaySound("KoraxAttack", CHAN_VOICE);
+
+		// Fire all 6 missiles at once
+		A_PlaySound(sounds[type], CHAN_WEAPON, 1, false, ATTN_NONE);
+		class<Actor> info = choices[type];
+		for (int i = 0; i < 6; ++i)
+		{
+			KoraxFire(info, i);
+		}
+	}
+
+	//============================================================================
+	//
+	// KoraxFire
+	//
+	// Arm projectiles
+	//		arm positions numbered:
+	//			1	top left
+	//			2	middle left
+	//			3	lower left
+	//			4	top right
+	//			5	middle right
+	//			6	lower right
+	//
+	//============================================================================
+
+	void KoraxFire (Class<Actor> type, int arm)
+	{
+		static const int extension[] =
+		{
+			KORAX_ARM_EXTENSION_SHORT,
+			KORAX_ARM_EXTENSION_LONG,
+			KORAX_ARM_EXTENSION_LONG,
+			KORAX_ARM_EXTENSION_SHORT,
+			KORAX_ARM_EXTENSION_LONG,
+			KORAX_ARM_EXTENSION_LONG
+		};
+		static const int armheight[] =
+		{
+			KORAX_ARM1_HEIGHT,
+			KORAX_ARM2_HEIGHT,
+			KORAX_ARM3_HEIGHT,
+			KORAX_ARM4_HEIGHT,
+			KORAX_ARM5_HEIGHT,
+			KORAX_ARM6_HEIGHT
+		};
+
+		double ang = angle + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE);
+		Vector3 pos = Vec3Angle(extension[arm], ang, armheight[arm] - Floorclip);
+		SpawnKoraxMissile (pos, target, type);
+	}
+
+	//============================================================================
+	//
+	// P_SpawnKoraxMissile
+	//
+	//============================================================================
+
+	private void SpawnKoraxMissile (Vector3 pos, Actor dest, Class<Actor> type)
+	{
+		Actor th = Spawn (type, pos, ALLOW_REPLACE);
+		th.target = self; // Originator
+		double an = th.AngleTo(dest);
+		if (dest.bShadow)
+		{ // Invisible target
+			an += Random2[KoraxMissile]() * (45/256.);
+		}
+		th.angle = an;
+		th.VelFromAngle();
+		double dist = dest.DistanceBySpeed(th, th.Speed);
+		th.Vel.Z = (dest.pos.z - pos.Z + 30) / dist;
+		th.CheckMissileSpawn(radius);
+	}
+
+	//============================================================================
+	//
+	// A_KoraxCommand
+	//
+	// Call action code scripts (250-254)
+	//
+	//============================================================================
+
+	void A_KoraxCommand()
+	{
+		int numcommands;
+
+		A_PlaySound("KoraxCommand", CHAN_VOICE);
+
+		// Shoot stream of lightning to ceiling
+		double ang = angle - 90;
+		Vector3 pos = Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT);
+		Spawn("KoraxBolt", pos, ALLOW_REPLACE);
+
+		if (health <= (SpawnHealth() >> 1))
+		{
+			numcommands = 5;
+		}
+		else
+		{
+			numcommands = 4;
+		}
+
+		ACS_Execute(250 + (random[KoraxCommand]()%numcommands), 0);
+	}
 }
 
 class KoraxSpirit : Actor
@@ -94,8 +373,6 @@ class KoraxSpirit : Actor
 		Alpha 0.4;
 	}
 	
-	native void A_KSpiritRoam();
-	
 	States
 	{
 	Spawn:
@@ -105,10 +382,98 @@ class KoraxSpirit : Actor
 		SPIR DEFGHI 5;
 		Stop;
 	}
+	
+	//============================================================================
+	//
+	// A_KSpiritSeeker
+	//
+	//============================================================================
+
+	private void KSpiritSeeker (double thresh, double turnMax)
+	{
+		Actor target = tracer;
+		if (target == null)
+		{
+			return;
+		}
+		double dir = deltaangle(angle, AngleTo(target));
+		double delta = abs(dir);
+		if (delta > thresh)
+		{
+			delta /= 2;
+			if(delta > turnMax)
+			{
+				delta = turnMax;
+			}
+		}
+		if(dir > 0)
+		{ // Turn clockwise
+			angle += delta;
+		}
+		else
+		{ // Turn counter clockwise
+			angle -= delta;
+		}
+		VelFromAngle();
+
+		if (!(level.time&15) 
+			|| pos.z > target.pos.z + target.Default.Height
+			|| pos.z + height < target.pos.z)
+		{
+			double newZ = target.pos.z + random[KoraxRoam]() * target.Default.Height / 256;
+			double deltaZ = newZ - pos.z;
+
+			if (abs(deltaZ) > 15)
+			{
+				if(deltaZ > 0)
+				{
+					deltaZ = 15;
+				}
+				else
+				{
+					deltaZ = -15;
+				}
+			}
+			Vel.Z = deltaZ + DistanceBySpeed(target, Speed);
+		}
+	}
+
+	//============================================================================
+	//
+	// A_KSpiritRoam
+	//
+	//============================================================================
+
+	void A_KSpiritRoam()
+	{
+		if (health-- <= 0)
+		{
+			A_PlaySound("SpiritDie", CHAN_VOICE);
+			SetStateLabel ("Death");
+		}
+		else
+		{
+			if (tracer)
+			{
+				KSpiritSeeker(args[0], args[0] * 2.);
+			}
+			int xyspeed = (random[KoraxRoam]() % 5);
+			int zspeed = (random[KoraxRoam]() % 5);
+			A_Weave(xyspeed, zspeed, 4., 2.);
+
+			if (random[KoraxRoam]() < 50)
+			{
+				A_PlaySound("SpiritActive", CHAN_VOICE, 1, false, ATTN_NONE);
+			}
+		}
+	}
 }
 
 class KoraxBolt : Actor
 {
+	const KORAX_BOLT_HEIGHT		= 48.;
+	const KORAX_BOLT_LIFETIME		= 3;
+	
 	Default
 	{
 		Radius 15;
@@ -119,9 +484,6 @@ class KoraxBolt : Actor
 		RenderStyle "Add";
 	}
 	
-	native void A_KBolt();
-	native void A_KBoltRaise();
-	
 	States
 	{
 	Spawn:
@@ -130,4 +492,40 @@ class KoraxBolt : Actor
 		MLFX IJKLM 2 Bright A_KBolt;
 		Stop;
 	}
+	
+	//============================================================================
+	//
+	// A_KBolt
+	//
+	//============================================================================
+
+	void A_KBolt()
+	{
+		// Countdown lifetime
+		if (special1-- <= 0)
+		{
+			Destroy ();
+		}
+	}
+
+	//============================================================================
+	//
+	// A_KBoltRaise
+	//
+	//============================================================================
+
+	void A_KBoltRaise()
+	{
+		// Spawn a child upward
+		double z = pos.z + KORAX_BOLT_HEIGHT;
+
+		if ((z + KORAX_BOLT_HEIGHT) < ceilingz)
+		{
+			Actor mo = Spawn("KoraxBolt", (pos.xy, z), ALLOW_REPLACE);
+			if (mo)
+			{
+				mo.special1 = KORAX_BOLT_LIFETIME;
+			}
+		}
+	}
 }