// 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)
		return
	end
	
	A_FaceTarget(actor)
	
	/*
	if (actor.eflags & MFE_VERTICALFLIP)
		z = actor.z + actor.height - FixedMul(locvar2*FRACUNIT, actor.scale)
		//if (actor.type == MT_OLDBLACKEGGMAN)
			z = $-FixedMul(mobjinfo[var1].height, actor.scale/2)
		//else
			//z = $-FixedMul(mobjinfo[var1].height, actor.scale)
		//end
	else
		z = actor.z + FixedMul(locvar2*FRACUNIT, actor.scale)
	end
	*/
	
	shot = P_SpawnMobjFromMobj(actor, 0, 0, locvar2*FRACUNIT, var1)//P_SpawnMobj(actor.x, actor.y, z, var1)
	shot.scale = $/2
	
	//if actor.type == MT_OLDBLACKEGGMAN
		//shot.destscale = actor.scale/2
		//P_SetScale(shot, actor.scale/2)
	//else
		//shot.destscale = actor.scale
		//P_SetScale(shot, actor.scale)
	//end
	
	// 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
		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)
		return
	end
	
	if (maptol & TOL_OLDBRAK)
		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 // Lob cannon balls
		if mobj.z < 1056*FRACUNIT
			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	// Chaingun Goop
		A_FaceTarget(mobj)
		mobj.state = S_OLDBLACKEGG_SHOOT1
		
		if mobj.health > 2
			mobj.movecount = TICRATE + P_RandomByte()/3
		else
			mobj.movecount = TICRATE + P_RandomByte()/2
		end
	elseif mobj.threshold == 2 // 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)
			return true
		end
		
		P_SetMobjStateNF(mobj, mobj.info.spawnstate)
		return true
	end
	
	if mobj.health >= 8 and (leveltime & 14) == 0
		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
		mobj.reactiontime = $+P_RandomByte()
		
		if mobj.health <= 2
			mobj.reactiontime = $/4
		end
	elseif mobj.state == S_OLDBLACKEGG_DIE4 and mobj.tics == states[mobj.state].tics
		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
		// Chase
		local delta
		local i
		
		if not P_IsObjectOnGround(mobj)
			return true
		end
		
		// Self-adjust if stuck on the edge
		if mobj.tracer
			// *** 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)
			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 // NUMDIRS should be 8
			mobj.angle = $ & (7 * (2^29))
			delta = mobj.angle - (mobj.movedir * (2^29))
			
			if delta > 0
				mobj.angle = $-ANGLE_45
			elseif delta < 0
				mobj.angle = $+ANGLE_45
			end
		end
		
		// Is a player on top of us?
		for player in players.iterate
			if not player.valid or player.spectator
				continue
			end
			
			if not (player.mo and player.mo.valid)
				continue
			end
			
			if player.mo.health <= 0
				continue
			end
			
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius
				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)
				// 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
			A_FaceTarget(mobj)
			mobj.state = S_OLDBLACKEGG_SHOOT1
			mobj.movecount = TICRATE + P_RandomByte()/2
			return true
		end
		
		if mobj.reactiontime
			mobj.reactiontime = $-1
		end
		
		if mobj.reactiontime <= 0 and P_IsObjectOnGround(mobj)
			// 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)
			return true // got a new target
		end
		
		if (leveltime & 1)
			// 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))
				P_NewChaseDir(mobj)
			end
		end
	elseif mobj.state == S_OLDBLACKEGG_MISSILE3 and mobj.tics == states[S_OLDBLACKEGG_MISSILE3].tics
		// 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)
			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
			mobj.health = $-1
		end
		
		mobj.reactiontime = $/3
		
		// This might need to be changed
		if mobj.health <= 0
			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
		if mobj.health == 2
			// 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
		// 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
			if not player.valid or player.spectator
				continue
			end
			
			if not (player.mo and player.mo.valid)
				continue
			end
			
			if player.mo.health <= 0
				continue
			end
			
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius + player.mo.radius
				continue
			end
			
			if player.mo.z > mobj.z + mobj.height - mobj.scale
			and player.mo.z < mobj.z + mobj.height + 128*mobj.scale // 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
		// Lob cannon balls
		mobj.movecount = $-1
		if mobj.movecount <= 0 or not mobj.target
			mobj.state = mobj.info.spawnstate
			return true
		end
		
		if (leveltime % 15) == 1
			// 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
		// Chaingun goop
		local missile
		
		mobj.movecount = $-1
		if mobj.movecount <= 0 or not mobj.target
			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
			S_StopSound(missile)
		end
		
		if (leveltime & 1)
			S_StartSound(nil, sfx_beshot)
		end
	elseif mobj.state == S_OLDBLACKEGG_JUMP1 and mobj.tics == 1
		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
			if not player.valid or player.spectator
				continue
			end
			
			if not (player.mo and player.mo.valid)
				continue
			end
			
			if player.mo.health <= 0
				continue
			end
			
			// This might need to be changed if it gets removed in the future
			if player.powers[pw_carry] == CR_BRAKGOOP
				closestNum = -1
				closestdist = 16384*FRACUNIT // Just in case...
				
				// Find waypoint he is closest to
				for mo2 in mobjs.iterate()
					if mo2.type == MT_BOSS3WAYPOINT and mo2.spawnpoint
						dist = FixedHypot(player.mo.x - mo2.x, player.mo.y - mo2.y)
						
						if closestNum == -1 or dist < closestdist
							closestNum = (mo2.spawnpoint.options & 7)
							closestdist = dist
							foundgoop = true
						end
					end
				end
				waypointNum = closestNum
				break
			end
		end
		
		if not foundgoop
			if mobj.z > 1056*FRACUNIT
				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
			waypointNum = 1 + (P_RandomByte() % 4)
		end
		
		if mobj.tracer and mobj.tracer.type == MT_BOSS3WAYPOINT
		and mobj.tracer.spawnpoint and (mobj.tracer.spawnpoint.options & 7) == waypointNum
			if (P_RandomByte() & 1)
				waypointNum = $+1
			else
				waypointNum = $-1
			end
			
			waypointNum = $%5
			
			if waypointNum < 0
				waypointNum = 0
			end
		end
		
		if waypointNum == 0 and mobj.health <= 2
			waypointNum = 1 + (P_RandomByte() & 1)
		end
		
		// scan the thinkers to find
		// the waypoint to use
		for mo2 in mobjs.iterate()
			if mo2.type == MT_BOSS3WAYPOINT and mo2.spawnpoint and (mo2.spawnpoint.options & 7) == waypointNum
				hitspot = mo2
				break
			end
		end
		
		if hitspot == nil
			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)
		// 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
			if not player.valid or player.spectator
				continue
			end
			
			if not (player.mo and player.mo.valid)
				continue
			end
			
			if player.mo.health <= 0
				continue
			end
			
			if FixedHypot(player.mo.x - mobj.x, player.mo.y - mobj.y) > mobj.radius*4
				continue
			end
			
			if player.mo.z > mobj.z + FixedMul(mobj.scale, 128*FRACUNIT)
				continue
			end
			
			if player.mo.z < mobj.z - FixedMul(mobj.scale, 64*FRACUNIT)
				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
		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)// 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)
		return
	end
	
	if not (mthing.options & MTF_EXTRA)
		if (maptol & TOL_OLDBRAK)
			//mobj.destscale = FRACUNIT
			//P_SetScale(mobj, mobj.destscale)
			//mobj.scale = FRACUNIT
			mobj.scale = $
		else
			//mobj.destscale = 2*FRACUNIT
			//P_SetScale(mobj, mobj.destscale)
			mobj.scale = $*2
		end
	else
		if (maptol & TOL_OLDBRAK)
			//mobj.destscale = FRACUNIT/2
			//P_SetScale(mobj, mobj.destscale)
			mobj.scale = $/2
		else
			//mobj.destscale = FRACUNIT
			//P_SetScale(mobj, mobj.destscale)
			mobj.scale = $
		end
	end
	
	//local spawn = P_SpawnMobj(mobj.x, mobj.y, mobj.z+mobj.height-FixedMul(mobj.scale, 16*FRACUNIT), MT_OLDBLACKEGGMAN_HELPER)
	local spawn = P_SpawnMobjFromMobj(mobj, 0, 0, FixedDiv(mobj.height, mobj.scale) - 16*FRACUNIT, MT_OLDBLACKEGGMAN_HELPER)
	spawn.target = mobj
	//spawn.destscale = mobj.scale
	//P_SetScale(spawn, mobj.scale)
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)
		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)
		return
	end
	
	if not (tmthing.player and tmthing.player.valid)
		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
		P_RemoveMobj(mobj)
		return
	end
	
	local z = brak.z
	
	if (brak.eflags & MFE_VERTICALFLIP)
		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
		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)
		return
	end
	
	local player = toucher.player
	
	if player and player.valid
		if not player.powers[pw_flashing] and not (player.powers[pw_ignorelatch] & (1<<15))
		// 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
				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
			*/
			
			//print(leveltime)
			
			//print("Before: " + player.powers[pw_carry])
			
			player.powers[pw_carry] = CR_BRAKGOOP
			toucher.tracer = special
			
			P_ResetPlayer(player)
			
			//print("After: " + player.powers[pw_carry])
			
			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)
		return
	end
	
	if inflictor and inflictor.valid
		if inflictor.type == MT_OLDBLACKEGGMAN_GOOPFIRE
			if inflictor.x ~= target.x and inflictor.y ~= target.y and target.player and target.player.valid
				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)
		return
	end
	
	// Emulate the wonky "gravity" in 2.0.7 when the player gets hit in an "Old Brak" level
	if (maptol & TOL_OLDBRAK)
		if P_PlayerInPain(player) and player.hitinoldbrak
			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
		local item = player.mo.tracer
		
		// Controllable missile
		if item
			if item.type == MT_OLDBLACKEGGMAN_MISSILE
				if player.cmd.forwardmove > 0
					item.momz = $+FixedMul(item.scale, FRACUNIT/4)
				elseif player.cmd.forwardmove < 0
					item.momz = $-FixedMul(item.scale, FRACUNIT/4)
				end
				
				// Fix for Simple controls
				if (player.pflags & PF_ANALOGMODE)
					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
					player.powers[pw_carry] = CR_NONE
					player.mo.tracer = nil
					/*
					if (player.pflags & PF_FORCESTRAFE)
						player.pflags = $ & ~PF_FORCESTRAFE
					end
					*/
				end
			end
		else
			player.powers[pw_carry] = CR_NONE
			/*
			if (player.pflags & PF_FORCESTRAFE)
				player.pflags = $ & ~PF_FORCESTRAFE
			end
			*/
		end
	end
end)

addHook("MobjMoveCollide", function(tmthing, thing)
	if not (tmthing and tmthing.valid
	and thing and thing.valid)
		return
	end
	
	if tmthing.z < thing.z + thing.height
	and thing.z < tmthing.z + tmthing.height
		if thing.type == MT_OLDBLACKEGGMAN
		and tmthing.target ~= thing
			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.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
			// 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.powers[pw_carry] == CR_GENERIC) or (thing.player.pflags & PF_JUMPED))
			
			// Only explode if the player is not riding the missile
			if thing.tracer ~= tmthing and not (thing.player.pflags & PF_JUMPED)
				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}
