// 2.0 Brak Eggman (Black Egg) - Ported from 2.0.7
// PLEASE LOAD LUA_BECM BEFORE THIS

freeslot(
	// Sprites
	// Sounds
	// Objects
	"MT_OLDBLACKEGGMAN",
	"MT_OLDBLACKEGGMAN_HELPER",
	"MT_OLDBLACKEGGMAN_GOOPFIRE",
	"MT_OLDBLACKEGGMAN_MISSILE",
	"MT_OLDEXPLODE",
	// States
	"S_OLDBLACKEGG_STND",
	"S_OLDBLACKEGG_STND2",
	"S_OLDBLACKEGG_WALK1",
	"S_OLDBLACKEGG_WALK2",
	"S_OLDBLACKEGG_WALK3",
	"S_OLDBLACKEGG_WALK4",
	"S_OLDBLACKEGG_WALK5",
	"S_OLDBLACKEGG_WALK6",
	"S_OLDBLACKEGG_SHOOT1",
	"S_OLDBLACKEGG_SHOOT2",
	"S_OLDBLACKEGG_PAIN1",
	"S_OLDBLACKEGG_PAIN2",
	"S_OLDBLACKEGG_PAIN3",
	"S_OLDBLACKEGG_PAINREPEAT",
	"S_OLDBLACKEGG_PAIN4",
	"S_OLDBLACKEGG_PAIN5", // Originally went up to 35
	"S_OLDBLACKEGG_HITFACE1",
	"S_OLDBLACKEGG_HITFACE2",
	"S_OLDBLACKEGG_HITFACE3",
	"S_OLDBLACKEGG_HITFACE4",
	"S_OLDBLACKEGG_DIE1",
	"S_OLDBLACKEGG_DIE2",
	"S_OLDBLACKEGG_DIE3",
	"S_OLDBLACKEGG_DIE4",
	"S_OLDBLACKEGG_DIE5",
	"S_OLDBLACKEGG_MISSILE1",
	"S_OLDBLACKEGG_MISSILE2",
	"S_OLDBLACKEGG_MISSILE3",
	"S_OLDBLACKEGG_GOOP",
	"S_OLDBLACKEGG_JUMP1",
	"S_OLDBLACKEGG_JUMP2",
	"S_OLDBLACKEGG_DESTROYPLAT1",
	"S_OLDBLACKEGG_DESTROYPLAT2",
	"S_OLDBLACKEGG_DESTROYPLAT3",
	"S_OLDBLACKEGG_HELPER",
	"S_OLDBLACKEGG_GOOP1",
	"S_OLDBLACKEGG_GOOP2",
	"S_OLDBLACKEGG_GOOP3",
	"S_OLDBLACKEGG_GOOP4",
	"S_OLDBLACKEGG_GOOP5",
	"S_OLDBLACKEGG_GOOP6",
	"S_OLDBLACKEGG_GOOP7",
	"S_OLDBLACKEGG_MISSILE"
)

// 2.0 Brak Eggman

// Make a cusotmized version of A_LobShot specifically so 2.0 Brak can fire correctly
// scaled versions
function A_OldBrakLobShot(actor, var1, var2)
	if not (actor and actor.valid) then return end
	
	local locvar2 = var2 / (2^16)
	local shot, hitspot
	local an
	local z
	local dist
	local vertical, horizontal
	local airtime = (var2 & 65535)
	
	if not (actor.target and actor.target.valid) then return end
	
	A_FaceTarget(actor)
	
	shot = P_SpawnMobjFromMobj(actor, 0, 0, locvar2*FRACUNIT, var1)
	shot.scale = $/2
	
	// Keep track of where it's going to land
	local hitSpotZ = actor.target.z
	if actor.target.subsector and actor.target.subsector.valid then hitSpotZ = actor.target.subsector.sector.floorheight end
	hitspot = P_SpawnMobj(actor.target.x & (64*FRACUNIT-1), actor.target.y & (64*FRACUNIT-1), hitSpotZ, MT_THOK)
	hitspot.tics = airtime
	shot.tracer = hitspot
	
	shot.target = actor // where it came from
	
	shot.angle = actor.angle
	an = actor.angle
	
	dist = FixedHypot(actor.target.x - shot.x, actor.target.y - shot.y)
	
	horizontal = dist / airtime
	vertical = (abs(P_GetMobjGravity(actor))*airtime)/2
	
	shot.momx = FixedMul(horizontal, cos(an))
	shot.momy = FixedMul(horizontal, sin(an))
	P_SetObjectMomZ(shot, vertical)
	//shot.momz = vertical
	
	if shot.info.seesound then
		S_StartSound(shot, shot.info.seesound)
	end
	
	if hitspot and hitspot.valid then P_RemoveMobj(hitspot) end
end

// Emulate the wonky "gravity" when the player gets hurt in an "OldBrak" level in 2.0
addHook("MobjDamage", function(target, inflictor, source)
	if not (target and target.valid
	and target.player and target.player.valid) then
		return
	end
	
	if (maptol & TOL_OLDBRAK) then target.player.hitinoldbrak = true end
end, MT_PLAYER)

local function RetryAttack(mobj)
	if not (mobj and mobj.valid) then return end
	
	if mobj.threshold == 0 then // Lob cannon balls
		if mobj.z < 1056*FRACUNIT then
			A_FaceTarget(mobj)
			mobj.state = mobj.info.xdeathstate
			mobj.movecount = 7*TICRATE + P_RandomByte()
		else
			mobj.threshold = $+1
			RetryAttack(mobj)
			return // Prevents a neverending recursive loop
		end
	elseif mobj.threshold == 1 then	// Chaingun Goop
		A_FaceTarget(mobj)
		mobj.state = S_OLDBLACKEGG_SHOOT1
		
		if mobj.health > 2 then
			mobj.movecount = TICRATE + P_RandomByte()/3
		else
			mobj.movecount = TICRATE + P_RandomByte()/2
		end
	elseif mobj.threshold == 2 then // Homing Missile
		A_FaceTarget(mobj)
		mobj.state = mobj.info.missilestate
		S_StartSound(nil, sfx_beflap)
	end
	
	mobj.threshold = $+1
	mobj.threshold = $%3
	return true
end

addHook("BossThinker", function(mobj)
	if not (mobj and mobj.valid) then return end
	
	if not (mobj.target and mobj.target.valid and (mobj.target.flags & MF_SHOOTABLE))
		// look for a new target
		if P_LookForPlayers(mobj, 0, true, false) then return true end
		
		P_SetMobjStateNF(mobj, mobj.info.spawnstate)
		return true
	end
	
	if mobj.health >= 8 and (leveltime & 14) == 0 then
		local smokemobj = P_SpawnMobj(mobj.x, mobj.y, mobj.z + mobj.height, MT_SMOKE)
		smokemobj.destscale = mobj.scale
		P_SetScale(smokemobj, mobj.scale)
		smokemobj.momz = P_MobjFlip(smokemobj)*FixedMul(mobj.scale, 2*FRACUNIT)
	end
	
	if mobj.state == S_OLDBLACKEGG_STND and mobj.tics == states[mobj.state].tics then
		mobj.reactiontime = $+P_RandomByte()
		
		if mobj.health <= 2 then mobj.reactiontime = $/4 end
	elseif mobj.state == S_OLDBLACKEGG_DIE4 and mobj.tics == states[mobj.state].tics then
		mobj.health = 0
		
		// This replaces what would have been an expensive mobjs.iterate loop
		A_BossDeath(mobj, 0, 0)
	elseif mobj.state >= S_OLDBLACKEGG_WALK1
	and mobj.state <= S_OLDBLACKEGG_WALK6 then
		// Chase
		local delta
		local i
		
		if not P_IsObjectOnGround(mobj) then return true end
		
		// Self-adjust if stuck on the edge
		if mobj.tracer and mobj.tracer.valid then
			// *** I might need to use FixedMul with mobj.scale here ***
			if FixedHypot(mobj.x - mobj.tracer.x, mobj.y - mobj.tracer.y) > FixedMul(mobj.scale, 128*FRACUNIT) - mobj.radius
				P_InstaThrust(mobj, R_PointToAngle2(mobj.x, mobj.y, mobj.tracer.x, mobj.tracer.y), FixedMul(mobj.scale, FRACUNIT))
			end
		end
		
		if (mobj.flags2 & MF2_FRET) then
			mobj.state = S_OLDBLACKEGG_DESTROYPLAT1
			S_StartSound(nil, sfx_s3k53) // sfx_s3k53 is a replacement for sfx_s3k_34
			mobj.flags2 = $ & ~MF2_FRET
			return true
		end
		
		// turn towards movement direction if not there yet
		if mobj.movedir < NUMDIRS then // NUMDIRS should be 8
			mobj.angle = $ & (7 * (2^29))
			delta = mobj.angle - (mobj.movedir * (2^29))
			
			if delta > 0 then
				mobj.angle = $-ANGLE_45
			elseif delta < 0 then
				mobj.angle = $+ANGLE_45
			end
		end
		
		// Is a player on top of us?
		for player in players.iterate do
			if not player.valid or player.spectator then continue end
			if not (player.mo and player.mo.valid) then continue end
			if player.mo.health <= 0 then continue end
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius then continue end
			
			// This statement has been touched up to account for the boss's scale
			if player.mo.z > mobj.z + mobj.height - FixedMul(mobj.scale, 2*FRACUNIT)
			and player.mo.z < mobj.z + mobj.height + FixedMul(mobj.scale, 32*FRACUNIT) then
				// Punch him!
				mobj.state = mobj.info.meleestate
				S_StartSound(nil, sfx_begrnd) // warning sound
				return true
			end
		end
		
		if mobj.health <= 2
		and mobj.target
		and mobj.target.player
		and mobj.target.player.powers[pw_carry] == CR_GENERIC then
			A_FaceTarget(mobj)
			mobj.state = S_OLDBLACKEGG_SHOOT1
			mobj.movecount = TICRATE + P_RandomByte()/2
			return true
		end
		
		if mobj.reactiontime then mobj.reactiontime = $-1 end
		
		if mobj.reactiontime <= 0 and P_IsObjectOnGround(mobj) then
			// Here, we'll call P_Random() and decide what kind of attack to do
			RetryAttack(mobj)
		end
		
		// possibly choose another target
		if multiplayer and mobj.target.health <= 0 or not P_CheckSight(mobj, mobj.target)
		and P_LookForPlayers(mobj, 0, true, false) then
			return true // got a new target
		end
		
		if (leveltime & 1) then
			// chase towards player
			mobj.movecount = $-1
			// This statement has been touched up to account for the boss's scale
			if mobj.movecount < 0 or not P_Move(mobj, FixedMul(mobj.scale, mobj.info.speed)) then
				P_NewChaseDir(mobj)
			end
		end
	elseif mobj.state == S_OLDBLACKEGG_MISSILE3 and mobj.tics == states[S_OLDBLACKEGG_MISSILE3].tics then
		// set dummymo's coordinates
		local dummymo = P_SpawnMobj(mobj.target.x, mobj.target.y, mobj.target.z + FixedMul(mobj.scale, 16*FRACUNIT), MT_THOK)
		
		if not (mobj.target and mobj.target.valid) then
			mobj.state = mobj.info.spawnstate
			return true
		end
		
		A_FaceTarget(mobj)
		
		P_SpawnXYZMissile(mobj, dummymo, MT_OLDBLACKEGGMAN_MISSILE,
			mobj.x + P_ReturnThrustX(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.y + P_ReturnThrustY(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.z + FixedDiv(mobj.height, 3*FRACUNIT/2)
		)
		
		P_SpawnXYZMissile(mobj, dummymo, MT_OLDBLACKEGGMAN_MISSILE,
			mobj.x + P_ReturnThrustX(mobj, mobj.angle+ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.y + P_ReturnThrustY(mobj, mobj.angle+ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.z + FixedDiv(mobj.height, 3*FRACUNIT/2)
		)
		
		P_SpawnXYZMissile(mobj, dummymo, MT_OLDBLACKEGGMAN_MISSILE,
			mobj.x + P_ReturnThrustX(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.y + P_ReturnThrustY(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.z + mobj.height/2
		)
		
		P_SpawnXYZMissile(mobj, dummymo, MT_OLDBLACKEGGMAN_MISSILE,
			mobj.x + P_ReturnThrustX(mobj, mobj.angle+ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.y + P_ReturnThrustY(mobj, mobj.angle+ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.z + mobj.height/2
		)
		
		if dummymo and dummymo.valid then P_RemoveMobj(dummymo) end
	elseif mobj.state == S_OLDBLACKEGG_PAIN1 and mobj.tics == states[mobj.state].tics
		if mobj.health > 0 then mobj.health = $-1 end
		
		mobj.reactiontime = $/3
		
		// This might need to be changed
		if mobj.health <= 0 then
			P_KillMobj(mobj, nil, nil)
			
			// The following code is meant to be a replacement for the score adding 
			// part of A_BossDeath since the original code did not call the action. 
			// However, since the action is called in this port, this code is not needed.
			/*
			// It was a team effort
			for player in players.iterate
				// This is a bug from 2.0.7 where the player does not get rewarded points for defeating 2.0 Brak
				if not player.valid
					continue
				end
				
				P_AddPlayerScore(player, 1000)
			end
			*/
		end
	elseif mobj.state == S_OLDBLACKEGG_PAIN5 and mobj.tics == 1 then
		if mobj.health == 2 then
			// Begin platform destruction
			mobj.flags2 = $|MF2_FRET
			mobj.state = mobj.info.raisestate
		end
	elseif mobj.state == S_OLDBLACKEGG_HITFACE4 and mobj.tics == states[mobj.state].tics then
		// This is where Black Eggman hits his face.
		// If a player is on top of him, the player gets hurt.
		// But, if the player has managed to escape,
		// Black Eggman gets hurt!
		states[mobj.state].nextstate = mobj.info.painstate // Reset
		
		S_StartSound(nil, sfx_bedeen)
		
		for player in players.iterate do
			if not player.valid or player.spectator then continue end
			if not (player.mo and player.mo.valid) then continue end
			if player.mo.health <= 0 then continue end
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius + player.mo.radius then continue end
			
			if player.mo.z > mobj.z + mobj.height - mobj.scale
			and player.mo.z < mobj.z + mobj.height + 128*mobj.scale then // You can't be in the vicinity, either...
				// Punch him!
				P_DamageMobj(player.mo, mobj, mobj, 1)
				states[mobj.state].nextstate = mobj.info.spawnstate
				
				// Laugh
				S_StartSound(nil, sfx_bewar1 + (P_RandomByte() % 4))
			end
		end
	elseif mobj.state == S_OLDBLACKEGG_GOOP then
		// Lob cannon balls
		mobj.movecount = $-1
		if mobj.movecount <= 0 or not (mobj.target and mobj.target.valid) then
			mobj.state = mobj.info.spawnstate
			return true
		end
		
		if (leveltime % 15) == 1 then
			// Replace MT_CANNONBALL if it gets removed in the future
			A_OldBrakLobShot(mobj, MT_CANNONBALL, 2*TICRATE + (80<<16))
			S_StartSound(nil, sfx_begoop)
		end
	elseif mobj.state == S_OLDBLACKEGG_SHOOT2 then
		// Chaingun goop
		local missile
		
		mobj.movecount = $-1
		if mobj.movecount <= 0 or not (mobj.target and mobj.target.valid) then
			mobj.state = mobj.info.spawnstate
			return true
		end
		
		A_FaceTarget(mobj)
		
		missile = P_SpawnXYZMissile(mobj, mobj.target, MT_OLDBLACKEGGMAN_GOOPFIRE,
			mobj.x + P_ReturnThrustX(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.y + P_ReturnThrustY(mobj, mobj.angle-ANGLE_90, FixedDiv(mobj.radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj.z + FixedDiv(mobj.height, 3*FRACUNIT/2)
		)
		
		if missile then S_StopSound(missile) end
		if (leveltime & 1) then S_StartSound(nil, sfx_beshot) end
	elseif mobj.state == S_OLDBLACKEGG_JUMP1 and mobj.tics == 1 then
		local hitspot = nil
		local an
		local dist, closestdist
		local vertical, horizontal
		local airtime = 5*TICRATE
		local waypointNum = 0
		local foundgoop = false
		local closestNum
		
		// *** There's likely a less expensive way to do the following, but I'm 
		// too tired to figure it out right now...
		
		// Looks for players in goop. If you find one, try to jump on him.
		for player in players.iterate do
			if not player.valid or player.spectator then continue end
			if not (player.mo and player.mo.valid) then continue end
			if player.mo.health <= 0 then continue end
			
			// This might need to be changed if it gets removed in the future
			if player.powers[pw_carry] == CR_BRAKGOOP then
				closestNum = -1
				closestdist = 16384*FRACUNIT // Just in case...
				
				// Find waypoint he is closest to
				for mo2 in mobjs.iterate() do
					if mo2.type == MT_BOSS3WAYPOINT and mo2.spawnpoint then
						dist = FixedHypot(player.mo.x - mo2.x, player.mo.y - mo2.y)
						
						if closestNum == -1 or dist < closestdist then
							closestNum = (mo2.spawnpoint.options & 7)
							closestdist = dist
							foundgoop = true
						end
					end
				end
				waypointNum = closestNum
				break
			end
		end
		
		if not foundgoop then
			if mobj.z > 1056*FRACUNIT then
				waypointNum = 0
			else
				waypointNum = 1 + (P_RandomByte() % 4)
			end
		end
		
		// Don't jump to the center when health is low.
		// Force the player to beat you with missiles.
		if mobj.health <= 2 and waypointNum == 0 then
			waypointNum = 1 + (P_RandomByte() % 4)
		end
		
		if mobj.tracer and mobj.tracer.valid and mobj.tracer.type == MT_BOSS3WAYPOINT
		and mobj.tracer.spawnpoint and (mobj.tracer.spawnpoint.options & 7) == waypointNum then
			if (P_RandomByte() & 1) then
				waypointNum = $+1
			else
				waypointNum = $-1
			end
			
			waypointNum = $%5
			
			if waypointNum < 0 then waypointNum = 0 end
		end
		
		if waypointNum == 0 and mobj.health <= 2 then
			waypointNum = 1 + (P_RandomByte() & 1)
		end
		
		// scan the thinkers to find
		// the waypoint to use
		for mo2 in mobjs.iterate() do
			if mo2.valid and mo2.type == MT_BOSS3WAYPOINT and mo2.spawnpoint and (mo2.spawnpoint.options & 7) == waypointNum then
				hitspot = mo2
				break
			end
		end
		
		if hitspot == nil then
			print("BlackEggman unable to find waypoint " + waypointNum + "!")
			mobj.state = mobj.info.spawnstate
			return true
		end
		
		mobj.tracer = hitspot
		
		mobj.angle = R_PointToAngle2(mobj.x, mobj.y, hitspot.x, hitspot.y)
		
		an = mobj.angle
		
		dist = FixedHypot(hitspot.x - mobj.x, hitspot.y - mobj.y)
		
		horizontal = dist/airtime
		vertical = abs((P_GetMobjGravity(mobj)*airtime)/2)
		
		mobj.momx = FixedMul(horizontal, cos(an))
		mobj.momy = FixedMul(horizontal, sin(an))
		P_SetObjectMomZ(mobj, vertical, false)
		
		//mobj.momz = 10*FRACUNIT
	elseif mobj.state == S_OLDBLACKEGG_JUMP2 and P_IsObjectOnGround(mobj) then
		// BANG! onto the ground
		//local i,j
		local ns
		local x,y,z
		local mo2
		
		S_StartSound(nil, sfx_befall)
		
		z = P_MobjFlip(mobj) > 0 and mobj.floorz or mobj.ceilingz
		for j = 0, 1, 1 do
			for i = 0, 31, 1 do
				local fa = i*ANGLE_22h // Replacement for i*FINEANGLE/16
				ns = FixedMul(mobj.scale, 64*FRACUNIT)
				x = mobj.x + FixedMul(sin(fa), ns)
				y = mobj.y + FixedMul(cos(fa), ns)
				
				mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE)
				//mo2.destscale = mobj.scale
				//P_SetScale(mo2, mobj.scale)
				ns = FixedMul(mobj.scale, 16*FRACUNIT)
				mo2.momx = FixedMul(sin(fa), ns)
				mo2.momy = FixedMul(cos(fa), ns)
			end
			z = $-(FixedMul(mobj.scale, 32*FRACUNIT))
		end
		
		// Hurt player??
		for player in players.iterate do
			if not player.valid or player.spectator then continue end
			if not (player.mo and player.mo.valid) then continue end
			if player.mo.health <= 0 then continue end
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius*4 then continue end
			if player.mo.z > mobj.z + FixedMul(mobj.scale, 128*FRACUNIT) then continue end
			if player.mo.z < mobj.z - FixedMul(mobj.scale, 64*FRACUNIT) then continue end
			
			P_DamageMobj(player.mo, mobj, mobj, 1)
			
			// Laugh
			S_StartSound(nil, sfx_bewar1 + (P_RandomByte() % 4))
		end
		
		mobj.state = mobj.info.spawnstate
	elseif mobj.state == mobj.info.deathstate and mobj.tics == states[mobj.state].tics then
		S_StartSound(nil, sfx_bedie1 + (P_RandomByte() & 1))
	end
	
	return true
end, MT_OLDBLACKEGGMAN)

// REPLACE THIS WITH MobjSpawn WHEN 2.2.9 COMES OUT
// Force any rings in an "OldBrak" level to be scaled down
addHook("MapThingSpawn", function(mobj, mthing)
	if not (mobj and mobj.valid) then return end
	
	if (maptol & TOL_OLDBRAK) then// and mobj.scale ~= FRACUNIT/2
		//mobj.destscale = FRACUNIT/2
		//P_SetScale(mobj, FRACUNIT/2)
		mobj.scale = $/2
	end
end, MT_RING)

// Special thanks to Tatsuru for the tip on using MapThingSpawn instead of MobjSpawn
// for scaling objects
addHook("MapThingSpawn", function(mobj, mthing)
	if not (mobj and mobj.valid
	and mthing and mthing.valid) then
		return
	end
	
	if not (mthing.options & MTF_EXTRA) then
		if (maptol & TOL_OLDBRAK) then
			mobj.scale = $
		else
			mobj.scale = $*2
		end
	else
		if (maptol & TOL_OLDBRAK) then
			mobj.scale = $/2
		else
			mobj.scale = $
		end
	end
	
	local spawn = P_SpawnMobjFromMobj(mobj, 0, 0, FixedDiv(mobj.height, mobj.scale) - 16*FRACUNIT, MT_OLDBLACKEGGMAN_HELPER)
	spawn.target = mobj
end, MT_OLDBLACKEGGMAN)

addHook("BossDeath", function(mobj)
	if not (mobj and mobj.valid) then return end
	
	mobj.target = nil
	
	mobj.flags = $|MF_NOCLIP
	mobj.flags = $ & ~MF_SPECIAL
	
	S_StartSound(nil, sfx_befall)
	
	return true
end, MT_OLDBLACKEGGMAN)

// Prevent 2.0 Brak from being damaged by players normally
addHook("TouchSpecial", function(special, toucher)
	if not (special and special.valid
	and toucher and toucher.valid) then
		return
	end
	
	P_DamageMobj(toucher, special, special, 1) // ouch
	return true
end, MT_OLDBLACKEGGMAN)

mobjinfo[MT_OLDBLACKEGGMAN] = {
	//$Name 2.0 Brak Eggman
	//$Sprite OBRKA1
	//$Category Bosses
	//$Flags1Text Half size
	//$Flags4Text End level on death
	doomednum = 4056, // Originally 206
	spawnstate = S_OLDBLACKEGG_STND,
	spawnhealth = 8,
	seestate = S_OLDBLACKEGG_WALK1,
	reactiontime = 8*TICRATE,
	painstate = S_OLDBLACKEGG_PAIN1,
	meleestate = S_OLDBLACKEGG_HITFACE1,
	missilestate = S_OLDBLACKEGG_MISSILE1,
	deathstate = S_OLDBLACKEGG_DIE1,
	xdeathstate = S_OLDBLACKEGG_GOOP,
	//deathsound = sfx_cybdth,
	speed = 1,
	radius = 48*FRACUNIT,
	height = 160*FRACUNIT,
	damage = 1,
	flags = MF_SPECIAL|MF_BOSS,
	raisestate = S_OLDBLACKEGG_JUMP1
}

states[S_OLDBLACKEGG_STND] =	{SPR_OBRK,	A,	1,	A_SetReactionTime,	0,	0,	S_OLDBLACKEGG_STND2}
states[S_OLDBLACKEGG_STND2] =	{SPR_OBRK,	A,	7,	A_Look,				1,	0,	S_OLDBLACKEGG_STND2}

states[S_OLDBLACKEGG_WALK1] =	{SPR_OBRK,	B,	7,	nil,			0,			0,	S_OLDBLACKEGG_WALK2}
states[S_OLDBLACKEGG_WALK2] =	{SPR_OBRK,	C,	7,	nil,			0,			0,	S_OLDBLACKEGG_WALK3}
states[S_OLDBLACKEGG_WALK3] =	{SPR_OBRK,	D,	7,	A_PlaySound,	sfx_bestep,	0,	S_OLDBLACKEGG_WALK4}
states[S_OLDBLACKEGG_WALK4] =	{SPR_OBRK,	E,	7,	nil,			0,			0,	S_OLDBLACKEGG_WALK5}
states[S_OLDBLACKEGG_WALK5] =	{SPR_OBRK,	F,	7,	nil,			0,			0,	S_OLDBLACKEGG_WALK6}
states[S_OLDBLACKEGG_WALK6] =	{SPR_OBRK,	G,	7,	A_PlaySound,	sfx_bestp2,	0,	S_OLDBLACKEGG_WALK1}

states[S_OLDBLACKEGG_SHOOT1] = 	{SPR_OBRK,	H,	3,	nil,			0,			0,	S_OLDBLACKEGG_SHOOT2}
states[S_OLDBLACKEGG_SHOOT2] = 	{SPR_OBRK,	Y,	1,	A_PlaySound,	sfx_befire,	0,	S_OLDBLACKEGG_SHOOT1}

states[S_OLDBLACKEGG_PAIN1] =		{SPR_OBRK,	I,	1,	A_PlaySound,	sfx_behurt,	0,						S_OLDBLACKEGG_PAIN2}
states[S_OLDBLACKEGG_PAIN2] =		{SPR_OBRK,	Z,	1,	nil,			0,			0,						S_OLDBLACKEGG_PAIN3}
states[S_OLDBLACKEGG_PAIN3] =		{SPR_OBRK,	I,	1,	nil,			0,			0,						S_OLDBLACKEGG_PAINREPEAT}
// I might have to change var1
states[S_OLDBLACKEGG_PAINREPEAT] =	{SPR_OBRK,	Z,	0,	A_Repeat,		16,			S_OLDBLACKEGG_PAIN2,	S_OLDBLACKEGG_PAIN4}
states[S_OLDBLACKEGG_PAIN4] = 		{SPR_OBRK,	Z,	1,	nil,			0,			0,						S_OLDBLACKEGG_PAIN5}
states[S_OLDBLACKEGG_PAIN5] = 		{SPR_OBRK,	I,	1,	nil,			0,			0,						S_OLDBLACKEGG_WALK1}

states[S_OLDBLACKEGG_HITFACE1] =	{SPR_OBRK,	J,	20,	nil,	0,	0,	S_OLDBLACKEGG_HITFACE2}
states[S_OLDBLACKEGG_HITFACE2] =	{SPR_OBRK,	K,	2,	nil,	0,	0,	S_OLDBLACKEGG_HITFACE3}
states[S_OLDBLACKEGG_HITFACE3] =	{SPR_OBRK,	L,	2,	nil,	0,	0,	S_OLDBLACKEGG_HITFACE4}
states[S_OLDBLACKEGG_HITFACE4] =	{SPR_OBRK,	M,	14,	nil,	0,	0,	S_OLDBLACKEGG_PAIN1}

states[S_OLDBLACKEGG_DIE1] =	{SPR_OBRK,	N,	14,	A_Scream,		sfx_bedie2,	0,	S_OLDBLACKEGG_DIE2}
states[S_OLDBLACKEGG_DIE2] =	{SPR_OBRK,	O,	7,	nil,			0,			0,	S_OLDBLACKEGG_DIE3}
states[S_OLDBLACKEGG_DIE3] =	{SPR_OBRK,	P,	5,	nil,			0,			0,	S_OLDBLACKEGG_DIE4}
states[S_OLDBLACKEGG_DIE4] =	{SPR_OBRK,	Q,	3,	A_PlaySound,	sfx_bgxpld,	0,	S_OLDBLACKEGG_DIE5}
states[S_OLDBLACKEGG_DIE5] =	{SPR_OBRK,	R,	-1,	nil,			0,			0,	S_OLDBLACKEGG_DIE5}

states[S_OLDBLACKEGG_MISSILE1] =	{SPR_OBRK,	S,	14,	nil,			0,			0,	S_OLDBLACKEGG_MISSILE2}
states[S_OLDBLACKEGG_MISSILE2] =	{SPR_OBRK,	T,	5,	nil,			0,			0,	S_OLDBLACKEGG_MISSILE3}
states[S_OLDBLACKEGG_MISSILE3] =	{SPR_OBRK,	U,	35,	A_PlaySound,	sfx_beshot,	0,	S_OLDBLACKEGG_JUMP1}

states[S_OLDBLACKEGG_GOOP] =	{SPR_OBRK,	V,	-1,	nil,	0,	0,	S_OLDBLACKEGG_STND}

states[S_OLDBLACKEGG_JUMP1] =	{SPR_OBRK,	W,	14,	A_PlaySound,	sfx_belnch,	0,	S_OLDBLACKEGG_JUMP2}
states[S_OLDBLACKEGG_JUMP2] =	{SPR_OBRK,	X,	-1,	nil,			0,			0,	S_OLDBLACKEGG_WALK1}

states[S_OLDBLACKEGG_DESTROYPLAT1] =	{SPR_OBRK,	V,	3*TICRATE,	nil,				0,					0,	S_OLDBLACKEGG_DESTROYPLAT2}
// sfx_s3k54 was originally sfx_s3k_35
states[S_OLDBLACKEGG_DESTROYPLAT2] =	{SPR_OBRK,	V,	1,			A_PlaySound,		sfx_s3k54,			0,	S_OLDBLACKEGG_DESTROYPLAT3}
// Replace LE_BRAKPLATFORM if it gets removed in the future
states[S_OLDBLACKEGG_DESTROYPLAT3] =	{SPR_OBRK,	V,	14,			A_LinedefExecute,	LE_BRAKPLATFORM,	0,	S_OLDBLACKEGG_STND}

// 2.0 Brak Eggman Helper

// Only the player should collide with the 2.0 Brak "helper"
addHook("MobjCollide", function(thing, tmthing)
	if not (thing and thing.valid
	and tmthing and tmthing.valid) then
		return
	end
	
	if not (tmthing.player and tmthing.player.valid) then return false end
end, MT_OLDBLACKEGGMAN_HELPER)

addHook("MobjThinker", function(mobj)
	if not (mobj and mobj.valid) then return end
	
	local brak = mobj.target
	
	if not (brak and brak.valid) or brak.health <= 0 then
		P_RemoveMobj(mobj)
		return
	end
	
	local z = brak.z
	
	if (brak.eflags & MFE_VERTICALFLIP) then
		mobj.eflags = $|MFE_VERTICALFLIP
		mobj.flags2 = $|MF2_OBJECTFLIP
		z = brak.z + brak.height - mobj.height - FixedMul((160-16)*FRACUNIT, mobj.scale)
	else
		mobj.eflags = $ & ~MFE_VERTICALFLIP
		mobj.flags2 = $ & ~MF2_OBJECTFLIP
		z = brak.z + FixedMul((160-16)*FRACUNIT, mobj.scale)
	end
	
	P_TeleportMove(mobj, brak.x, brak.y, z)
	if brak.player and brak.player.valid then mobj.angle = brak.player.drawangle
	else mobj.angle = brak.angle end
	//mobj.angle = brak.player and brak.player.drawangle or brak.angle
	
	// Prevent the player from being able to stand on the helper in rare occassions
	if brak.player and brak.player.valid then
		mobj.flags = $|MF_NOCLIPHEIGHT
	else
		mobj.flags = $ & ~MF_NOCLIPHEIGHT
	end
end, MT_OLDBLACKEGGMAN_HELPER)

// Currently, this object targets the player when they bump into it from the side.
// This "bug" also happens in 2.0, so I'm keeping it as is.
mobjinfo[MT_OLDBLACKEGGMAN_HELPER] = {
	doomednum = -1,
	spawnstate = S_OLDBLACKEGG_HELPER,
	spawnhealth = 8,
	speed = 1,
	radius = 48*FRACUNIT,
	height = 32*FRACUNIT,
	damage = 1,
	flags = MF_SOLID|MF_PUSHABLE|MF_NOGRAVITY
}

states[S_OLDBLACKEGG_HELPER] =	{SPR_NULL,	0,	-1,	nil,	0,	0,	S_OLDBLACKEGG_HELPER}

// 2.0 Brak Eggman Goop

addHook("TouchSpecial", function(special, toucher)
	if not (special and special.valid
	and toucher and toucher.valid) then
		return
	end
	
	local player = toucher.player
	
	if player and player.valid then
		if not player.powers[pw_flashing] and not (player.powers[pw_ignorelatch] & (1<<15)) then
		// Original if statement from 2.0.7
		//if toucher.state != S_PLAY_PAIN and not player.powers[pw_flashing]
			toucher.momx = 0
			toucher.momy = 0
			
			if toucher.momz ~= 0 then special.momz = toucher.momz end
			
			/*
			player.powers[pw_carry] = CR_BRAKGOOP
			
			if player.powers[pw_carry] == CR_GENERIC
				toucher.tracer = nil
				player.powers[pw_carry] = CR_NONE
			end
			*/
			
			player.powers[pw_carry] = CR_BRAKGOOP
			toucher.tracer = special
			
			P_ResetPlayer(player)
			
			if special.target and special.target.valid and special.target.state == S_OLDBLACKEGG_SHOOT1
				if special.target.health <= 2 and (P_RandomByte() & 1)
					special.target.state = special.target.info.missilestate
				else
					special.target.state = special.target.info.raisestate
				end
			end
		end
	end
	return true
end, MT_OLDBLACKEGGMAN_GOOPFIRE)

addHook("ShouldDamage", function(target, inflictor, source)
	if not (target and target.valid) then return end
	
	if inflictor and inflictor.valid then
		if inflictor.type == MT_OLDBLACKEGGMAN_GOOPFIRE then
			if inflictor.x ~= target.x and inflictor.y ~= target.y 
			and target.player and target.player.valid then
				P_TeleportMove(inflictor, target.x, target.y, inflictor.z)
			end
			return false
		end
	end
end)

mobjinfo[MT_OLDBLACKEGGMAN_GOOPFIRE] = {
	doomednum = -1,
	spawnstate = S_OLDBLACKEGG_GOOP1,
	spawnhealth = 1000,
	reactiontime = 8,
	deathstate = S_OLDBLACKEGG_GOOP3,
	deathsound = sfx_ghit,
	speed = 30*FRACUNIT,
	radius = 11*FRACUNIT,
	height = 8*FRACUNIT,
	//mass = 100,
	dispoffset = 1,
	flags = MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_SPECIAL
}

// Replace SPR_BGOO if it gets removed in the future
states[S_OLDBLACKEGG_GOOP1] =	{SPR_BGOO,	A|FF_TRANS50,	2,			nil,			0,	0,	S_OLDBLACKEGG_GOOP2}
states[S_OLDBLACKEGG_GOOP2] =	{SPR_BGOO,	B|FF_TRANS50,	2,			nil,			0,	0,	S_OLDBLACKEGG_GOOP1}
states[S_OLDBLACKEGG_GOOP3] =	{SPR_BGOO,	C|FF_TRANS50,	6*TICRATE,	A_GoopSplat,	0,	0,	S_OLDBLACKEGG_GOOP4}
states[S_OLDBLACKEGG_GOOP4] =	{SPR_BGOO,	C|FF_TRANS60,	4,			nil,			0,	0,	S_OLDBLACKEGG_GOOP5}
states[S_OLDBLACKEGG_GOOP5] =	{SPR_BGOO,	C|FF_TRANS70,	4,			nil,			0,	0,	S_OLDBLACKEGG_GOOP6}
states[S_OLDBLACKEGG_GOOP6] =	{SPR_BGOO,	C|FF_TRANS80,	4,			nil,			0,	0,	S_OLDBLACKEGG_GOOP7}
states[S_OLDBLACKEGG_GOOP7] =	{SPR_BGOO,	C|FF_TRANS90,	4,			nil,			0,	0,	S_NULL}

// 2.0 Brak Eggman Missile

// Controllable missile code ported from p_user.c in 2.0.7
addHook("PlayerThink", function(player)
	if not (player and player.valid
	and player.mo and player.mo.valid) then
		return
	end
	
	// Emulate the wonky "gravity" in 2.0.7 when the player gets hit in an "Old Brak" level
	if (maptol & TOL_OLDBRAK) then
		if P_PlayerInPain(player) and player.hitinoldbrak then
			player.mo.momx = FixedMul($, FixedDiv(player.mo.scale, FRACUNIT))
			player.mo.momy = FixedMul($, FixedDiv(player.mo.scale, FRACUNIT))
			player.mo.momz = FixedMul($, FixedDiv(player.mo.scale, FRACUNIT))
			player.hitinoldbrak = false
		end
	end
	
	if player.powers[pw_carry] == CR_GENERIC then
		local item = player.mo.tracer
		
		// Controllable missile
		if item and item.valid then
			if item.type == MT_OLDBLACKEGGMAN_MISSILE then
				if player.cmd.forwardmove > 0 then
					item.momz = $+FixedMul(item.scale, FRACUNIT/4)
				elseif player.cmd.forwardmove < 0 then
					item.momz = $-FixedMul(item.scale, FRACUNIT/4)
				end
				
				// Fix for Simple controls
				if (player.pflags & PF_ANALOGMODE) then
					player.mo.angle = player.cmd.angleturn<<16
					player.mo.angle = $-FixedAngle(player.cmd.sidemove*FRACUNIT/10)
				end
				
				item.angle = player.mo.angle
				P_InstaThrust(item, item.angle, FixedMul(item.info.speed, item.scale))
				
				if P_IsObjectOnGround(player.mo) or item.health <= 0 then
					player.powers[pw_carry] = CR_NONE
					player.mo.tracer = nil
				end
			end
		else
			player.powers[pw_carry] = CR_NONE
		end
	end
end)

addHook("MobjMoveCollide", function(tmthing, thing)
	if not (tmthing and tmthing.valid
	and thing and thing.valid) then
		return
	end
	
	if tmthing.z <= thing.z + thing.height
	and thing.z <= tmthing.z + tmthing.height then
		if thing.type == MT_OLDBLACKEGGMAN
		and tmthing.target ~= thing then
			thing.state = thing.info.painstate
			return true
		end
		
		/*
		// Prevent the missile from hitting the helper
		if thing.type == MT_OLDBLACKEGGMAN_HELPER
			return false
		end
		*/
		
		if thing.player and thing.player.valid
		and (thing.player.pflags & PF_JUMPED)
		and not thing.player.powers[pw_flashing]
		and not thing.player.powers[pw_ignorelatch]
		and thing.tracer ~= tmthing
		and tmthing.target ~= thing then
			// Hop on the missile for a ride!
			thing.player.powers[pw_carry] = CR_GENERIC
			thing.player.pflags = $ & ~(PF_JUMPED|PF_NOJUMPDAMAGE)
			thing.tracer = tmthing
			tmthing.target = thing // Set owner to the player
			tmthing.tracer = nil // Disable homing-ness
			tmthing.momz = 0
			
			thing.angle = tmthing.angle
			
			// This is required for CR_GENERIC to work
			thing.tracer = tmthing
			
			return false
		elseif thing.player and thing.player.valid 
		and ((thing.player.powers[pw_carry] == CR_GENERIC) or (thing.player.pflags & PF_JUMPED)) then
			// Only explode if the player is not riding the missile
			if thing.tracer ~= tmthing and not (thing.player.pflags & PF_JUMPED) then
				P_ExplodeMissile(tmthing)
			end
			
			// Ignore
			return false
		end
	end
end, MT_OLDBLACKEGGMAN_MISSILE)

mobjinfo[MT_OLDBLACKEGGMAN_MISSILE] = {
	doomednum = -1,
	spawnstate = S_OLDBLACKEGG_MISSILE,
	spawnhealth = 1000,
	reactiontime = 8,
	deathstate = S_BOSSEXPLODE, // Replacement for S_BPLD1
	deathsound = sfx_bexpld,
	speed = 10*FRACUNIT,
	radius = 24*FRACUNIT,
	height = 24*FRACUNIT,
	//mass = 100,
	damage = 1,
	flags = MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY
}

// Replace SPR_BMSL if it gets removed in the future
states[S_OLDBLACKEGG_MISSILE] =	{SPR_BMSL,	A,	1,	nil,	0,	0,	S_OLDBLACKEGG_MISSILE}
