// 2.1 Eggscalibur - Ported from 2.1.25
// PLEASE LOAD LUA_CMMN AND LUA_OMCE BEFORE THIS

freeslot(
	// Sprites
	"SPR_21EP",
	"SPR_OEFR",
	// Objects
	"MT_21JETFLAME",
	"MT_21EGGMOBILE4",
	"MT_21EGGMOBILE4_MACE",
	// States
	"S_21JETFLAME1",
	"S_21JETFLAME2",
	"S_21EGGMOBILE4_STND",
	"S_21EGGMOBILE4_LATK1",
	"S_21EGGMOBILE4_LATK2",
	"S_21EGGMOBILE4_LATK3",
	"S_21EGGMOBILE4_LATK4",
	"S_21EGGMOBILE4_LATK5",
	"S_21EGGMOBILE4_LATK6",
	"S_21EGGMOBILE4_RATK1",
	"S_21EGGMOBILE4_RATK2",
	"S_21EGGMOBILE4_RATK3",
	"S_21EGGMOBILE4_RATK4",
	"S_21EGGMOBILE4_RATK5",
	"S_21EGGMOBILE4_RATK6",
	"S_21EGGMOBILE4_RAISE1",
	"S_21EGGMOBILE4_RAISE2",
	"S_21EGGMOBILE4_RAISE3",
	"S_21EGGMOBILE4_RAISE4",
	"S_21EGGMOBILE4_RAISE5",
	"S_21EGGMOBILE4_RAISE6",
	"S_21EGGMOBILE4_RAISE7",
	"S_21EGGMOBILE4_RAISE8",
	"S_21EGGMOBILE4_RAISE9",
	"S_21EGGMOBILE4_RAISE10",
	"S_21EGGMOBILE4_PAIN",
	"S_21EGGMOBILE4_DIE1",
	"S_21EGGMOBILE4_DIE2",
	"S_21EGGMOBILE4_DIE3",
	"S_21EGGMOBILE4_DIE4",
	"S_21EGGMOBILE4_FLEE1",
	"S_21EGGMOBILE4_FLEE2",
	"S_21EGGMOBILE4_MACE"
)

// 2.1 Eggscalibur

function A_EggscaliburFlame(actor, var1, var2)
	local filler
	local jetz
	if (actor.eflags & MFE_VERTICALFLIP)
		jetz = actor.z + actor.height + FixedMul(50*FRACUNIT - mobjinfo[MT_21JETFLAME].height, actor.scale)
	else
		jetz = actor.z - FixedMul(50*FRACUNIT, actor.scale)
	end
	filler = P_SpawnMobj(actor.x, actor.y, jetz, MT_21JETFLAME)
	filler.target = actor
	// Boss 4 already uses its tracer for other things
	filler.destscale = actor.scale
	P_SetScale(filler, filler.destscale)
	if (actor.eflags & MFE_VERTICALFLIP)
		filler.eflags = $|MFE_VERTICALFLIP
		filler.flags2 = $|MF2_OBJECTFLIP
	end
end

// 2.1 Jet Flame (for Eggscalibur)

addHook("MobjThinker", function(mobj)
	if not mobj.target // if you have no target
	or (not (mobj.target.flags & MF_BOSS) and mobj.target.health <=0)
		P_RemoveMobj(mobj)
		return
	end
	
	P_TeleportMove(mobj, mobj.target.x, mobj.target.y, mobj.target.z - FixedMul(50*FRACUNIT, mobj.target.scale))
end, MT_21JETFLAME)

mobjinfo[MT_21JETFLAME] = {
	doomednum = -1,
	spawnstate = S_21JETFLAME1,
	spawnhealth = 1000,
	reactiontime = 8,
	speed = 1,
	radius = 20*FRACUNIT,
	height = 32*FRACUNIT,
	mass = DMG_FIRE,
	flags = MF_NOGRAVITY|MF_PAIN|MF_FIRE|MF_NOCLIPHEIGHT
}

states[S_21JETFLAME1] = {SPR_OEFR, FF_FULLBRIGHT|A, 1, nil, 0, 0, S_21JETFLAME2}
states[S_21JETFLAME2] = {SPR_OEFR, FF_FULLBRIGHT|B, 1, nil, 0, 0, S_21JETFLAME1}

// P_Boss4MoveCage ported from 2.1.25
local function P_21Boss4MoveCage(delta)
	local tag = 65534
	//local tag = -2
	//local snum
	
	for sector in sectors.iterate
		if sector.tag != tag
			continue
		end
		sector.floorheight = $+delta
		sector.ceilingheight = $+delta
	end
	
	for sector in sectors.iterate
		if sector.tag == tag
			return #sector
		end
	end
	
	return false
end

// P_Boss4MoveSpikeballs ported from 2.1.25
local function P_21Boss4MoveSpikeballs(mobj, angle, fz)
	local s
	local base = mobj
	local seg
	local dist = mobj.watertop+(16*(2^FRACBITS))
	local bz = mobj.watertop+(16*(2^FRACBITS))
	base = base.tracer
	while base do
		seg = base
		dist = 172*FRACUNIT
		s = 8
		while seg do
			s = $-1
			P_TeleportMove(seg, mobj.x + P_ReturnThrustX(mobj, angle, dist), mobj.y + P_ReturnThrustY(mobj, angle, dist), bz + FixedMul(fz, FixedDiv(s*(2^FRACBITS), 9*(2^FRACBITS))))
			seg = seg.hnext
			dist = $+(124*FRACUNIT)
		end
		angle = $+(ANG60*2) // Replacement for ANGLE_MAX/3 since ANGLE_MAX = -1 in Lua
		base = base.tracer
	end
end

// P_Boss4PinchSpikeballs ported from 2.1.25
local function P_21Boss4PinchSpikeballs(mobj, angle, fz)
	local s
	local base = mobj
	local seg
	local dist = mobj.watertop+(16*(2^FRACBITS))
	local bz = mobj.watertop+(16*(2^FRACBITS))
	base = base.tracer
	while base do
		seg = base
		dist = 112*FRACUNIT
		s = 10
		while seg do
			s = $-1
			P_TeleportMove(seg, seg.x, seg.y, bz + FixedMul(fz, FixedDiv(s*(2^FRACBITS), 9*(2^FRACBITS))))
			P_TryMove(seg, mobj.x + P_ReturnThrustX(mobj, angle, dist), mobj.y + P_ReturnThrustY(mobj, angle, dist), true)
			seg = seg.hnext
			dist = $+(132*FRACUNIT)
		end
		angle = $+(ANG60*2)
		base = base.tracer
	end
end

// P_Boss4DestroyCage ported from 2.1.25
local function P_21Boss4DestroyCage()
	local tag = 65534
	//local tag = -2
	local snum, nextt
	local a
	local sector, rsec
	local rover
	
	// This will be the final iteration of sector tag
	// We'll destroy the tag list as we go.
	for sector in sectors.iterate
		if sector.tag == tag
			nextt = #sector
			break
		end
	end
	
	// Destroy the FOFs.
	for sector in sectors.iterate
		for rover in sector.ffloors()
			if (rover.flags & FF_EXISTS) and rover.sector.tag == tag
				if (rover.flags & FF_RENDERALL) // checking for FF_RENDERANY.
					EV_CrumbleChain(sector, rover) // This FOF is visible to some extent? Crumble it.
				else // Completely invisible FOF
					// no longer exists (can't collide with again)
					rover.flags = $ & ~FF_EXISTS
				end
			end
		end
	end
end

// P_Boss4PopSpikeBalls ported from 2.1.25
local function P_21Boss4PopSpikeballs(mobj)
	local base = mobj.tracer
	local seg, nextt
	mobj.tracer = nil
	while base do
		nextt = base.tracer
		base.tracer = nil
		seg = base
		while seg do
			if seg.health
				P_KillMobj(seg, nil, nil)
			end
			seg = seg.hnext
		end
		base = nextt
	end
end

// Ported BossThinker behavior for 2.1 Eggscalibur from 2.1.25
addHook("BossThinker", function(mobj)
	if mobj.state == mobj.info.spawnstate
		if mobj.health > mobj.info.damage or mobj.movedir == 4
			mobj.flags2 = $ & ~MF2_FRET
		end
		mobj.reactiontime = 0 // Drop the cage immediately.
	end
	
	// Oh no, we dead? D:
	if not mobj.health
		if mobj.tracer // need to clean up!
			P_21Boss4DestroyCage() // Just in case pinch phase was skipped
			P_21Boss4PopSpikeballs(mobj)
		end
		return true
	end
	
	// movedir == battle stage:
	//   0: initialization
	//   1: phase 1 forward
	//   2: phase 1 reverse
	//   3: pinch rise
	//   4: pinch phase
	// WELCOME to your DOOM!
	if mobj.movedir == 0
		// For this stage only:
		// movecount == cage height
		// threshold == cage momz
		if mobj.movecount == 0 // Initialize stage!
			local z
			local i, arm
			local seg = mobj
			local base = mobj
			// First frame init, spawn all the things.
			mobj.watertop = mobj.z
			z = mobj.z + mobj.height/2 - mobjinfo[MT_21EGGMOBILE4_MACE].height/2
			for arm = 0, 2, 1 do
				seg = P_SpawnMobj(mobj.x, mobj.y, z, MT_21EGGMOBILE4_MACE)
				base.tracer = seg
				base = seg
				seg.target = mobj
				for i = 0, 8, 1 do
					seg.hnext = P_SpawnMobj(mobj.x, mobj.y, z, MT_21EGGMOBILE4_MACE)
					seg.hnext.hprev = seg
					seg = seg.hnext
				end
			end
			// Move the cage up to the sky.
			mobj.movecount = 800*FRACUNIT
			if not P_21Boss4MoveCage(mobj.movecount)
				mobj.movecount = 0
				mobj.threshold = 3*TICRATE
				mobj.extravalue1 = 1
				mobj.movedir = $+1 // We don't have a cage, just continue
			else
				P_21Boss4MoveSpikeballs(mobj, 0, mobj.movecount)
			end
		else // Cage slams down over Eggman's head!
			local oldz = mobj.movecount
			mobj.threshold = $-(5*FRACUNIT)
			mobj.movecount = $+mobj.threshold
			if mobj.movecount < 0
				mobj.movecount = 0
			end
			P_21Boss4MoveCage(mobj.movecount - oldz)
			P_21Boss4MoveSpikeballs(mobj, 0, mobj.movecount)
			if mobj.movecount == 0
				mobj.threshold = 3*TICRATE
				mobj.extravalue1 = 1
				P_LinedefExecute(LE_BOSS4DROP, mobj, nil)
				mobj.movedir = $+1 // Initialization complete, next phase!
			end
		end
		return true
	// Normal operation
	elseif mobj.movedir == 1 or mobj.movedir == 2
		//print("do nothing")
	// Pinch phase init!
	elseif mobj.movedir == 3
		local z
		if mobj.z < mobj.watertop+(512*(2^FRACBITS))
			mobj.momz = 8*FRACUNIT
		else
			mobj.momz = 0
			mobj.movedir = $+1
		end
		mobj.movecount = $+(400*(FRACBITS / 2))
		mobj.movecount = $%(360*FRACUNIT)
		z = mobj.z - mobj.watertop - mobjinfo[MT_21EGGMOBILE4_MACE].height - mobj.height/2
		if z < 0 // We haven't risen high enough to pull the spikeballs along yet
			P_21Boss4MoveSpikeballs(mobj, FixedAngle(mobj.movecount), 0) // So don't pull the spikeballs along yet.
		else
			P_21Boss4PinchSpikeballs(mobj, FixedAngle(mobj.movecount), z)
		end
		return true
	// Pinch phase!
	elseif mobj.movedir == 4
		if mobj.z < (mobj.watertop + ((512+128*(mobj.info.damage-mobj.health))*(2^FRACBITS)))
			mobj.momz = 8*FRACUNIT
		else
			mobj.momz = 0
		end
		mobj.movecount = $+((800+800*(mobj.info.damage-mobj.health)) * (2 ^ (FRACBITS / 2)))
		mobj.movecount = $%(360*FRACUNIT)
		P_21Boss4PinchSpikeballs(mobj, FixedAngle(mobj.movecount), mobj.z - mobj.watertop - mobjinfo[MT_21EGGMOBILE4_MACE].height - mobj.height/2)
		
		if not mobj.target or not mobj.target.health
			P_SupermanLook4Players(mobj)
		end
		A_FaceTarget(mobj)
		return true
	else // ?????
		return true
	end
	
	// Haahahahahaaa, and let the FUN.. BEGIN!
	// movedir   == arms direction
	// movecount == arms angle
	// threshold == countdown to next attack
	// reactiontime == cage raise, speed burst
	// movefactor == cage z
	// friction == turns until helm lift

	// Raise the cage!
	if mobj.reactiontime == 1
		local oldz = mobj.movefactor
		mobj.movefactor = $+(8*FRACUNIT)
		if mobj.movefactor > 128*FRACUNIT
			mobj.movefactor = 128*FRACUNIT
		end
		P_21Boss4MoveCage(mobj.movefactor - oldz)
	// Drop the cage!
	elseif mobj.movefactor
		local oldz = mobj.movefactor
		mobj.movefactor = $-(4*FRACUNIT)
		if mobj.movefactor < 0
			mobj.movefactor = 0
		end
		P_21Boss4MoveCage(mobj.movefactor - oldz)
		if not mobj.movefactor
			if mobj.health <= mobj.info.damage
				// Proceed to pinch phase!
				P_21Boss4DestroyCage()
				mobj.movedir = 3
				P_LinedefExecute(LE_PINCHPHASE, mobj, nil)
				return true
			end
			P_LinedefExecute(LE_BOSS4DROP, mobj, nil)
		end
	end
	
		local movespeed = 170 * (2 ^ (FRACBITS / 2))
		if mobj.reactiontime == 2
			movespeed = $*3
		end
		if mobj.movedir == 2
			mobj.movecount = $-movespeed
		else
			mobj.movecount = $+movespeed
		end
		
	mobj.movecount = $%(360*FRACUNIT)
	P_21Boss4MoveSpikeballs(mobj, FixedAngle(mobj.movecount), mobj.movefactor)
	
	local extravalue1Set = false
	
	// Check for attacks, always tick the timer even while animating!!
	if not (mobj.flags2 & MF2_FRET) // but pause for pain so we don't interrupt pinch phase, eep!
	and mobj.threshold <= 0 // Make sure this code still runs in the rare case that mobj.threshold goes below 0
		// 5 -> 2.5 second timer
		mobj.threshold = 5*TICRATE-(TICRATE/2)*(mobj.info.spawnhealth-mobj.health)
		if mobj.threshold < 1
			mobj.threshold = 1
		end
		
		if mobj.extravalue1 == 0
			mobj.state = mobj.info.raisestate
			mobj.extravalue1 = 3
			extravalue1Set = true
		else
			if mobj.reactiontime == 1 // Cage is raised?
				mobj.reactiontime = 0 // Drop it!
			end
			local randomValue = P_RandomKey(10)
			// Telegraph Right (Speed Up!!)
			if randomValue == 1
			or randomValue == 3
			or randomValue == 4
			or randomValue == 5
			or randomValue == 6
				mobj.state = mobj.info.missilestate
			// Telegraph left (Reverse Direction)
			else
				mobj.state = mobj.info.meleestate
			end
		end
		if not extravalue1Set
			mobj.extravalue1 = $-1
		end
	end
	mobj.threshold = $-1
	
	// Leave if animating.
	if mobj.state != mobj.info.spawnstate
		return true
	end
	
	// Map allows us to get killed despite cage being down?
	if mobj.health <= mobj.info.damage
	// Proceed to pinch phase!
		P_21Boss4DestroyCage()
		// spawn jet's flame now you're flying upwards
		// tracer is already used, so if this ever gets reached again we've got problems
		A_EggscaliburFlame(mobj, 0, 0)
		mobj.movedir = 3
		P_LinedefExecute(LE_PINCHPHASE, mobj, nil)
		return true
	end
	
	mobj.reactiontime = 0 // Drop the cage if it hasn't been dropped already.
	if not mobj.target or not mobj.target.health
		P_SupermanLook4Players(mobj)
	end
	A_FaceTarget(mobj)
	
	return true // Do not use the GenericBossThinker
end, MT_21EGGMOBILE4)

addHook("BossDeath", function(mo)
	A_21BossDeath(mo)
	return true
end, MT_21EGGMOBILE4)

mobjinfo[MT_21EGGMOBILE4] = {
	//$Name 2.1 Eggscalibur
	//$Sprite 21EPA1
	//$Category Bosses
	//$Flags4Text End level on death
	doomednum = 4043,
	spawnstate = S_21EGGMOBILE4_STND,
	spawnhealth = 8,
	painstate = S_21EGGMOBILE4_PAIN,
	painsound = sfx_odmpai,
	meleestate = S_21EGGMOBILE4_LATK1,
	missilestate = S_21EGGMOBILE4_RATK1,
	deathstate = S_21EGGMOBILE4_DIE1,
	xdeathstate = S_21EGGMOBILE4_FLEE1,
	deathsound = sfx_cybdth,
	radius = 24*FRACUNIT,
	height = 76*FRACUNIT,
	damage = 3,
	flags = MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_BOSS|MF_NOCLIPHEIGHT,
	raisestate = S_21EGGMOBILE4_RAISE1
}

states[S_21EGGMOBILE4_STND] =	{SPR_21EP,	A,	-1,	nil,	0,	0,	S_NULL}

states[S_21EGGMOBILE4_LATK1] =	{SPR_21EP,	B,	3,	nil,			0,			0,	S_21EGGMOBILE4_LATK2}
states[S_21EGGMOBILE4_LATK2] =	{SPR_21EP,	C,	15,	nil,			0,			0,	S_21EGGMOBILE4_LATK3}
states[S_21EGGMOBILE4_LATK3] =	{SPR_21EP,	D,	2,	nil,			0,			0,	S_21EGGMOBILE4_LATK4}
states[S_21EGGMOBILE4_LATK4] =	{SPR_21EP,	E,	4,	nil,			0,			0,	S_21EGGMOBILE4_LATK5}
// Replace A_Boss4Reverse with A_21Boss4Reverse if it changes in the future
states[S_21EGGMOBILE4_LATK5] =	{SPR_21EP,	E,	50,	A_Boss4Reverse,	sfx_mswing,	0,	S_21EGGMOBILE4_LATK6}
states[S_21EGGMOBILE4_LATK6] =	{SPR_21EP,	F,	2,	nil,			0,			0,	S_21EGGMOBILE4_STND}

states[S_21EGGMOBILE4_RATK1] =	{SPR_21EP,	G,	3,		nil,			0,			0,	S_21EGGMOBILE4_RATK2}
states[S_21EGGMOBILE4_RATK2] =	{SPR_21EP,	H,	15,		nil,			0,			0,	S_21EGGMOBILE4_RATK3}
states[S_21EGGMOBILE4_RATK3] =	{SPR_21EP,	I,	2,		nil,			0,			0,	S_21EGGMOBILE4_RATK4}
states[S_21EGGMOBILE4_RATK4] =	{SPR_21EP,	J,	4,		nil,			0,			0,	S_21EGGMOBILE4_RATK5}
// Replace A_Boss4SpeedUp with A_21Boss4SpeedUp if it changes in the future
states[S_21EGGMOBILE4_RATK5] =	{SPR_21EP,	J,	150,	A_Boss4SpeedUp,	sfx_mswing,	0,	S_21EGGMOBILE4_RATK6}
states[S_21EGGMOBILE4_RATK6] =	{SPR_21EP,	K,	2,		nil,			0,			0,	S_21EGGMOBILE4_STND}

// Replace A_Boss4Raise with A_21Boss4Raise if it changes in the future
states[S_21EGGMOBILE4_RAISE1] =		{SPR_21EP,	A,	20,	A_Boss4Raise,	sfx_doord1,	0,	S_21EGGMOBILE4_RAISE2}
states[S_21EGGMOBILE4_RAISE2] =		{SPR_21EP,	N,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE3}
states[S_21EGGMOBILE4_RAISE3] =		{SPR_21EP,	O,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE4}
states[S_21EGGMOBILE4_RAISE4] =		{SPR_21EP,	N,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE5}
states[S_21EGGMOBILE4_RAISE5] =		{SPR_21EP,	O,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE6}
states[S_21EGGMOBILE4_RAISE6] =		{SPR_21EP,	N,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE7}
states[S_21EGGMOBILE4_RAISE7] =		{SPR_21EP,	O,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE8}
states[S_21EGGMOBILE4_RAISE8] =		{SPR_21EP,	N,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE9}
states[S_21EGGMOBILE4_RAISE9] =		{SPR_21EP,	O,	10,	nil,			0,			0,	S_21EGGMOBILE4_RAISE10}
states[S_21EGGMOBILE4_RAISE10] =	{SPR_21EP,	N,	10,	nil,			0,			0,	S_21EGGMOBILE4_STND}

states[S_21EGGMOBILE4_PAIN] =	{SPR_21EP,	L,	24,	A_Pain,	0,	0,	S_21EGGMOBILE4_STND}

states[S_21EGGMOBILE4_DIE1] =	{SPR_21EP,	M,	8,	A_Fall,			0,	0,						S_21EGGMOBILE4_DIE2}
states[S_21EGGMOBILE4_DIE2] =	{SPR_21EP,	M,	8,	A_BossScream,	0,	MT_BOSSEXPLODE,			S_21EGGMOBILE4_DIE3}
states[S_21EGGMOBILE4_DIE3] =	{SPR_21EP,	M,	0,	A_Repeat,		12,	S_21EGGMOBILE4_DIE2,	S_21EGGMOBILE4_DIE4}
states[S_21EGGMOBILE4_DIE4] =	{SPR_21EP,	M,	-1,	A_BossDeath,	0,	0,						S_NULL}

states[S_21EGGMOBILE4_FLEE1] =	{SPR_21EP,	N,	5,	nil,	0,	0,	S_21EGGMOBILE4_FLEE2}
states[S_21EGGMOBILE4_FLEE2] =	{SPR_21EP,	O,	5,	nil,	0,	0,	S_21EGGMOBILE4_FLEE1}

// 2.1 Eggscalibur Mace

mobjinfo[MT_21EGGMOBILE4_MACE] = {
	doomednum = -1,
	spawnstate = S_21EGGMOBILE4_MACE,
	spawnhealth = 1000,
	reactiontime = 8,
	deathstate = S_BOSSEXPLODE,
	deathsound = sfx_cybdth,
	speed = 48*FRACUNIT,
	radius = 34*FRACUNIT,
	height = 68*FRACUNIT,
	mass = DMG_SPIKE,
	damage = 1,
	activesound = sfx_mswing,
	flags = MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY
}

states[S_21EGGMOBILE4_MACE] =	{SPR_21MC,	D,	-1,	nil,	0,	0,	S_NULL}
