freeslot("S_PLAY_OVERDRIVECHARGE",
 "S_PLAY_OVERDRIVEATTACK",
 "S_OVERDRIVEFX",
 "S_OVERDRIVEAURA",
 "SPR2_CHRG", 
 "SPR2_OVRD",
 "SPR_ODFX",
 "SPR_OCFX",
 "MT_OVERDRIVEFX",
 "MT_OVERDRIVEAURA",
 "sfx_movrdr",
 "sfx_mochrg",
 "sfx_moredy",
 "SKINCOLOR_SUPER_TOPAZ1",
 "SKINCOLOR_SUPER_TOPAZ2",
 "SKINCOLOR_SUPER_TOPAZ3",
 "SKINCOLOR_SUPER_TOPAZ4",
 "SKINCOLOR_SUPER_TOPAZ5")
 
skincolors[SKINCOLOR_SUPER_TOPAZ1] = {
    name = "Super Topaz 1",
    ramp = {0,0,0,0,0,80,81,82,72,72,73,73,74,75,76,67},
    invcolor = SKINCOLOR_ORANGE,
    invshade = 9,
    chatcolor = V_BLUEMAP,
    accessible = false
}
skincolors[SKINCOLOR_SUPER_TOPAZ2] = {
    name = "Super Topaz 2",
    ramp = {0,0,0,0,80,81,82,72,73,73,74,74,75,76,67,68},
    invcolor = SKINCOLOR_ORANGE,
    invshade = 9,
    chatcolor = V_BLUEMAP,
    accessible = false
}
skincolors[SKINCOLOR_SUPER_TOPAZ3] = {
    name = "Super Topaz 3",
    ramp = {0,0,0,80,81,82,72,73,74,74,75,76,67,68,69,69},
    invcolor = SKINCOLOR_ORANGE,
    invshade = 9,
    chatcolor = V_BLUEMAP,
    accessible = false
}
skincolors[SKINCOLOR_SUPER_TOPAZ4] = {
    name = "Super Topaz 4",
    ramp = {0,0,80,81,82,72,73,74,74,75,76,67,68,69,70,70},
    invcolor = SKINCOLOR_ORANGE,
    invshade = 9,
    chatcolor = V_BLUEMAP,
    accessible = false
}
skincolors[SKINCOLOR_SUPER_TOPAZ5] = {
    name = "Super Topaz 5",
    ramp = {0,80,81,82,72,73,74,74,75,76,67,68,69,70,70,46},
    invcolor = SKINCOLOR_ORANGE,
    invshade = 9,
    chatcolor = V_BLUEMAP,
    accessible = false
}

local charge = S_PLAY_OVERDRIVECHARGE
states[charge].sprite = SPR_PLAY
states[charge].frame = SPR2_CHRG
states[charge].tics = -1
states[charge].nextstate = S_PLAY_OVERDRIVECHARGE

local overdrive = S_PLAY_OVERDRIVEATTACK
states[overdrive].sprite = SPR_PLAY
states[overdrive].frame = SPR2_OVRD|FF_FULLBRIGHT|FF_ANIMATE
states[overdrive].var1 = 1
states[overdrive].var2 = 1
states[overdrive].tics = -1
states[overdrive].nextstate = S_PLAY_OVERDRIVEATTACK

mobjinfo[MT_OVERDRIVEFX] = {
	spawnstate = S_OVERDRIVEFX,
	spawnhealth = 1,
    deathstate = S_NULL,
	dispoffset = -1,
    speed = FRACUNIT,
    radius = FRACUNIT,
    height = FRACUNIT,
	flags = MF_SCENERY|MF_NOGRAVITY
}

local effect = S_OVERDRIVEFX
states[effect].sprite = SPR_OCFX
states[effect].frame = FF_FULLBRIGHT|FF_ANIMATE
states[effect].var1 = 6
states[effect].var2 = 1
states[effect].tics = -1
states[effect].nextstate = S_OVERDRIVEFX

mobjinfo[MT_OVERDRIVEAURA] = {
	spawnstate = S_OVERDRIVEAURA,
	spawnhealth = 1,
    deathstate = S_NULL,
	dispoffset = -1,
    speed = FRACUNIT,
    radius = FRACUNIT,
    height = FRACUNIT,
	flags = MF_SCENERY|MF_NOGRAVITY
}

local aura = S_OVERDRIVEAURA
states[aura].sprite = SPR_ODFX
states[aura].frame = FF_FULLBRIGHT|FF_ANIMATE
states[aura].var1 = 1
states[aura].var2 = 1
states[aura].tics = -1
states[aura].nextstate = S_OVERDRIVEAURA

sfxinfo[sfx_movrdr].caption = "Overdrive Attack"
sfxinfo[sfx_mochrg].caption = "Overdrive Charging"
sfxinfo[sfx_moredy].caption = "Overdrive Ready"


local function FlipObjectFromObject(mo, master)
  mo.flags2 = ($ & ~MF2_OBJECTFLIP) | (master.flags2 & MF2_OBJECTFLIP)
  mo.eflags = ($ & ~MFE_VERTICALFLIP) | (master.eflags & MFE_VERTICALFLIP)
end

addHook("ThinkFrame", do
	for player in players.iterate
		if player.mo and player.mo.valid and player.mo.skin == "metalsonic"
			//print(player.resetod)
			if player.overdrivechargetimer == nil
				player.overdrivechargetimer = 0
			end
			if player.overdrivepulsetimer == nil
				player.overdrivepulsetimer = 0
			end
			if player.dooverdriveattack == nil
				player.dooverdriveattack = false
			end
			if player.overdriveattacktimer == nil
				player.overdriveattacktimer = 0
			end
			if player.odstats == nil
				player.odstats = false
			end
			if player.resetod == nil
				player.resetod = false
			end
			if P_PlayerInPain(player)
			or (player.pflags & PF_SLIDING)
			or player.powers[pw_carry]
			or player.spectator
			or player.playerstate != PST_LIVE
			or not player.mo.health
			or player.panim == PA_PAIN
			or player.iseggrobo
			or (player.dirk_frozen)
			or (player.gotflag or player.gotcrystal)
			or player.powers[pw_nocontrol]
			or player.exiting
				player.resetod = true
			else
				player.resetod = false
			end
			local flip = (P_MobjFlip(player.mo) == 1) and 0 or player.mo.height+(20*FU)
			//Overdrive charge checks
			if P_IsObjectOnGround(player.mo)
			and player.resetod == false
				if player.cmd.buttons & BT_CUSTOM2 -- Is the player holding custom 2?
				and not player.dooverdriveattack
				and not ((player.mo.state == S_PLAY_SPINDASH) or (player.pflags & PF_SPINNING))
					if ((player.overdrivechargetimer < 85) and not (player.powers[pw_sneakers] or player.powers[pw_super])) --Is the charge timer below 85 without shoes/super?
					or ((player.overdrivechargetimer < 50) and (player.powers[pw_sneakers] or player.powers[pw_super]))
						player.overdrivechargetimer = $ + 1
					end
					if player.overdrivechargetimer >= 1
						player.mo.momz = 0
					end
					if not (leveltime & 3)
					and player.overdrivechargetimer >= 2
					and player.mo.state == S_PLAY_OVERDRIVECHARGE
						S_StartSound(player.mo, sfx_s3k5c)
					end
					if not player.c2down
					and ((player.overdrivechargetimer < 85) or ((player.overdrivechargetimer < 50) and (player.powers[pw_sneakers] or player.powers[pw_super])))
					and not player.dooverdriveattack
						player.c2down = true
						player.mo.state = S_PLAY_OVERDRIVECHARGE
						player.mo.momx = FixedMul($, FRACUNIT*88/100)
						player.mo.momy = FixedMul($, FRACUNIT*88/100)
						local effect = P_SpawnMobjFromMobj(player.mo, 0, 0, 17*FU, MT_OVERDRIVEFX)
						effect.source = player.mo
						S_StartSound(player.mo, sfx_mochrg)
					end
					player.pflags = $|PF_STASIS
				else
					player.c2down = false
					if player.mo.state == S_PLAY_OVERDRIVECHARGE
					and (((player.overdrivechargetimer < 85) and not (player.powers[pw_sneakers] or player.powers[pw_super])) or ((player.overdrivechargetimer < 50) and (player.powers[pw_sneakers] or player.powers[pw_super]))) --Why does this conditional need to arbitrarily be a chungus?
						player.mo.state = S_PLAY_STND
						S_StopSoundByID(player.mo, sfx_mochrg)
						S_StartSound(player.mo, sfx_kc65)
						player.overdrivechargetimer = 0
					elseif ((player.overdrivechargetimer >= 85) or ((player.overdrivechargetimer >= 50) and (player.powers[pw_sneakers] or player.powers[pw_super])))
					and player.dooverdriveattack == false
						player.dooverdriveattack = true
						S_StartSound(player.mo, sfx_movrdr)
						player.mo.state = S_PLAY_OVERDRIVEATTACK
						player.charflags = SF_MACHINE|SF_MULTIABILITY|SF_SUPER|SF_RUNONWATER|SF_CANBUSTWALLS
						player.normalspeed = 72*FRACUNIT
						player.jumpfactor = skins[player.mo.skin].jumpfactor*2
						player.charability = CA_NONE
						player.charability2 = CA2_NONE
						P_InstaThrust(player.mo, player.mo.angle, 102*FRACUNIT)
						local aura = P_SpawnMobjFromMobj(player.mo, 0, 0, 17*FU, MT_OVERDRIVEAURA)
						aura.target = player.mo
						player.overdrivechargetimer = 0
						player.odstats = true
					end
				end
				if player.c2down == true
				and player.mo.state ~= S_PLAY_OVERDRIVECHARGE
					player.overdrivechargetimer = 0
					player.pflags = $ & ~PF_STASIS
				end
				if player.dooverdriveattack
					if player.overdriveattacktimer < 3
						player.overdriveattacktimer = $ + 1
					end
				end
				if ((player.overdrivechargetimer >= 85) or ((player.overdrivechargetimer >= 50) and (player.powers[pw_sneakers] or player.powers[pw_super])))
					player.overdrivepulsetimer = $ + 1
					player.mo.frame = B|FF_FULLBRIGHT
				end
				if player.overdrivepulsetimer >= 2
					player.overdrivepulsetimer = 0
					player.mo.frame = A
				end
			end
			if not P_IsObjectOnGround(player.mo)
				player.overdrivechargetimer = 0
			end
			if player.dooverdriveattack
			and player.playerstate == PST_LIVE
			and not player.resetod
				player.mo.state = S_PLAY_OVERDRIVEATTACK
				player.mo.frame = (leveltime % 2)|FF_FULLBRIGHT
			end
			if ((player.overdrivechargetimer == 84) or ((player.overdrivechargetimer == 49) and (player.powers[pw_sneakers] or player.powers[pw_super])))
			and player.mo.state == S_PLAY_OVERDRIVECHARGE
				S_StartSound(player.mo, sfx_moredy)
			end
			if (((player.overdriveattacktimer >= 3) and (player.speed < 15*FRACUNIT)) or ((player.overdriveattacktimer >= 3) and (player.mo.state ~= S_PLAY_OVERDRIVEATTACK)))
			and player.playerstate == PST_LIVE
				player.overdriveattacktimer = 0
				player.dooverdriveattack = false
				S_StartSound(player.mo, sfx_kc65)
				player.normalspeed = 36*FRACUNIT
				player.jumpfactor = skins[player.mo.skin].jumpfactor
				player.charability = CA_FLOAT
				player.charability2 = CA2_SPINDASH
				player.charflags = SF_MACHINE|SF_MULTIABILITY|SF_SUPER|SF_DASHMODE
				player.mo.state = S_PLAY_WALK
				player.odstats = false
			end
			if player.resetod --failsafe
			and (player.dooverdriveattack or player.odstats)
				player.overdriveattacktimer = 0
				player.dooverdriveattack = false
				S_StartSound(player.mo, sfx_kc65)
				player.normalspeed = 36*FRACUNIT
				player.jumpfactor = skins[player.mo.skin].jumpfactor
				player.charability = CA_FLOAT
				player.charability2 = CA2_SPINDASH
				player.charflags = SF_MACHINE|SF_MULTIABILITY|SF_SUPER|SF_DASHMODE
				player.panim = PA_RUN
				if player.powers[pw_carry] == CR_MACESPIN --mace swings are stupid.
					player.mo.state = S_PLAY_ROLL
				end
				player.odstats = false
			end
		end
	end
end)

addHook("MobjThinker", function(mo)
    if not mo.target return end
    mo.lifetime = $ or 0
	mo.angle = mo.target.player.drawangle
	local ghost = P_SpawnGhostMobj(mo)
	ghost.rollangle = mo.rollangle
	FlipObjectFromObject(mo, mo.target)
	local flip = (P_MobjFlip(mo.target) == 1) and 0 or mo.target.height+(17*FU)
	local z = 17*mo.scale
	if mo.eflags & MFE_VERTICALFLIP
		z = -$ + mo.target.z + mo.target.height - mo.height
	else
		z = $ + mo.target.z
	end
	ghost.blendmode = AST_ADD
	P_TeleportMove(mo, mo.target.x + mo.lifetime * mo.momx, mo.target.y + mo.lifetime * mo.momy, z + mo.lifetime * mo.momz)
    mo.lifetime = $ + 1
	if mo.target.player.dooverdriveattack == false
	or mo.target.player.playerstate != PST_LIVE
		P_RemoveMobj(mo)
	end
end, MT_OVERDRIVEAURA)

addHook("MobjThinker", function(mo)
    if not mo.source return end
    mo.lifetime = $ or 0
	mo.angle = mo.source.player.drawangle
	mo.rollangle = $ + FixedAngle((FU*360)/9)
	FlipObjectFromObject(mo, mo.source)
	local flip = (P_MobjFlip(mo.source) == 1) and 0 or mo.source.height+(17*FU)
	local z = 17*mo.scale
	if mo.eflags & MFE_VERTICALFLIP
		z = -$ + mo.source.z + mo.source.height - mo.height
	else
		z = $ + mo.source.z
	end
	P_TeleportMove(mo, mo.source.x + mo.lifetime * mo.momx, mo.source.y + mo.lifetime * mo.momy, z + mo.lifetime * mo.momz)
    mo.lifetime = $ + 1
	if not mo.source.player.overdrivechargetimer
	or mo.source.state ~= S_PLAY_OVERDRIVECHARGE
	or not P_IsObjectOnGround(mo.source)
	or mo.source.player.resetod
		P_RemoveMobj(mo)
	end
end, MT_OVERDRIVEFX)

addHook("ShouldDamage", function(target, inflictor, source, damage, damagetype)
    if target and target.valid and target.skin == "metalsonic"
		if (target.player.dooverdriveattack)
		and not (damagetype & DMG_DEATHMASK)
			return false
		end
		if ((target.state == S_PLAY_OVERDRIVECHARGE) or (target.player.dooverdriveattack))
		and inflictor and inflictor.flags & MF_ENEMY|MF_BOSS
			return false
		end
	end
end, MT_PLAYER)

addHook("MobjCollide", function(spike, plmo)
    if not (plmo and plmo.valid and plmo.skin == "metalsonic") then return end
    if plmo.type ~= MT_PLAYER then return end
    if plmo.z + plmo.height < spike.z or spike.z + spike.height < plmo.z then return end
    local player = plmo.player
    if player.dooverdriveattack then
        P_KillMobj(spike, plmo, plmo)
    end
end, MT_SPIKE)

addHook("MobjCollide", function(spike, plmo)
    if not (plmo and plmo.valid and plmo.skin == "metalsonic") then return end
    if plmo.type ~= MT_PLAYER then return end
    if (plmo.z > spike.z+spike.height*4) or (spike.z > plmo.z+plmo.height*2) then return end
    local player = plmo.player
	if player.dooverdriveattack then
        P_KillMobj(spike, plmo, plmo)
    end
end, MT_WALLSPIKE)

addHook("PlayerCanDamage", function(player, mobj)
	if player.mo and player.mo.valid and player.mo.skin == "metalsonic"
		if mobj.type == MT_PLAYER return end
		if player.mo.state == S_PLAY_OVERDRIVECHARGE
		and P_IsObjectOnGround(player.mo)
		and not (player.powers[pw_super])
			P_DamageMobj(mobj, player.mo, source, 1, damagetype)
			return true
		elseif player.dooverdriveattack
		or player.powers[pw_super]
			P_DamageMobj(mobj, player.mo, source, 2, damagetype)
			return true
		end
	end
end)

addHook("MobjMoveCollide", function(metal, enemy)
	if (metal and metal.valid and metal.health and metal.skin == "metalsonic")
	and (enemy and enemy.valid and enemy.health) 
	and enemy.type == MT_PLAYER
	and not (metal == enemy)
	and not (maptol == TOL_CHAOS)
	and not (gametype == GT_COOP)
	and metal.z <= enemy.z + enemy.height*2 and metal.z + metal.height >= enemy.z
		if ((metal.state == S_PLAY_OVERDRIVECHARGE and P_IsObjectOnGround(metal)) or (metal.player.dooverdriveattack))
			P_DamageMobj(enemy, metal, source, 1)
		end
	end
end, MT_PLAYER)

addHook("PlayerSpawn", function(player)
	if player.mo and player.mo.valid and player.mo.skin == "metalsonic"
		player.overdrivechargetimer = 0
		player.overdrivepulsetimer = 0
		player.dooverdriveattack = false
		player.overdriveattacktimer = 0
		if player.odstats == true
			player.normalspeed = 36*FRACUNIT
			player.jumpfactor = skins[player.mo.skin].jumpfactor
			player.charability = CA_FLOAT
			player.charability2 = CA2_SPINDASH
			player.charflags = SF_MACHINE|SF_MULTIABILITY|SF_SUPER|SF_DASHMODE
			player.odstats = false
		end
	end
end)