//TY Alfredo!
//TY Dirk!

//Ice block
states[freeslot("S_MARIO_ICEBLOCK")] = {freeslot("SPR_MRIB"), FF_PAPERSPRITE, -1, nil, 0, 0, S_NULL}
mobjinfo[freeslot("MT_KAMEK_ICEBLOCK")] = {
	spawnstate = S_MARIO_ICEBLOCK,
	spawnhealth = 1000,
	height = 16*FRACUNIT,
	radius = 16*FRACUNIT,
	flags = MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY,
}

//Ice block thinker
addHook("MobjThinker", function(mobj)
	if not mobj.target then return end
	local target = mobj.target
	
	if not target.valid or not target.mariofrozen
		P_RemoveMobj(mobj)
		return
	end
	
	local health = target.health
	if not health then target.health = 1 end
	
	A_CapeChase(mobj, 0,0)
	target.health = health
	
	mobj.angle = mobj.movedir
	local angle = mobj.angle - ANGLE_90
	local thrust = target.radius
	P_TeleportMove(mobj, mobj.x + P_ReturnThrustX(nil, angle, thrust),
	mobj.y + P_ReturnThrustY(nil, angle, thrust), mobj.z)
	
	thrust = FixedDiv($, target.scale)
	mobj.spritexscale = thrust/32
	mobj.spriteyscale = FixedDiv(target.height, target.scale)/64
end, MT_KAMEK_ICEBLOCK)

//Special crushed enemy object type
local CRUSHTIME = TICRATE/2
local FLIPZ = 12
local FLIPH = 16

//Switch to the old object's death state
function A_MarioDeadEnemy(mobj, var1, var2)
	if not mobj.mariooldtype then mobj.mariooldtype = MT_BLUECRAWLA end
	
	local deathstate = states[mobjinfo[mobj.mariooldtype].deathstate]
	local nextdeathstate = states[deathstate.nextstate]
	
	mobj.info.deathsound = mobjinfo[mobj.mariooldtype].deathsound
	mobj.state = mobjinfo[mobj.mariooldtype].deathstate
	
	if mariomode and mobj.info.deathsound == sfx_pop
		mobj.info.deathsound = sfx_cannon
	end
end

//Mario enemy object
states[freeslot("S_MARIO_ENEMY")] = {SPR_NULL, 0, -1, A_SetFuse, CRUSHTIME, FRACUNIT, freeslot("S_MARIO_DEADENEMY")}
states[S_MARIO_DEADENEMY] = {SPR_NULL, 0, -1, A_MarioDeadEnemy, 0, 0, S_NULL}

mobjinfo[freeslot("MT_KAMEK_ENEMY")] = {
	spawnstate = S_INVISIBLE,
	deathstate = S_MARIO_ENEMY,
	painsound = sfx_mario5,
	attacksound = sfx_mario2,
	deathsound = sfx_pop,
	spawnhealth = 1,
	speed = 64*FRACUNIT,
	height = 16*FRACUNIT,
	radius = 16*FRACUNIT,
	flags = MF_SCENERY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_ENEMY,
}

//Squish em
addHook("MobjThinker", function(mobj)
	if not mobj.fuse then return end
	
	//Frozen
	if mobj.mariofrozen
		//Stop fuse
		if mobj.mariofrozen != 2
			mobj.flags = MF_PUSHABLE | MF_SOLID | MF_BOUNCE
			mobj.flags2 = MF2_SLIDEPUSH
		
			mobj.fuse = -1
			mobj.mariofrozen = 2
		end
		
		if FixedHypot(mobj.momx, mobj.momy) > mobj.scale
			mobj.friction = FRACUNIT - UINT8_MAX
		end
		MarioButteredSlope(mobj)
		
		//Water physics
		if mobj.eflags & MFE_TOUCHLAVA
			mobj.fuse = 1
		elseif mobj.eflags & MFE_UNDERWATER and not (mobj.eflags & MFE_GOOWATER)
		and mobj.momz * P_MobjFlip(mobj) <= P_GetMobjGravity(mobj) * -8
			mobj.momx = $ * 63/64
			mobj.momy = $ * 63/64
			mobj.momz = $ - P_GetMobjGravity(mobj) * 2
			P_TryMove(mobj, mobj.x, mobj.y, true)
		end
		
		//Slidin
		if (mobj.momx or mobj.momy) and P_IsObjectOnGround(mobj)
			if not S_SoundPlaying(mobj, sfx_mrslip)
				S_StartSound(mobj, sfx_mrslip)
			end
			
			local random1 = P_SignedRandom()*FixedDiv(mobj.radius, mobj.scale)/INT8_MAX
			local random2 = P_SignedRandom()*FixedDiv(mobj.radius, mobj.scale)/INT8_MAX
			
			local spark = P_SpawnMobjFromMobj(mobj, random1, random2, 0, MT_THOK)
			spark.state = S_NIGHTSPARKLE1
			spark.tics = 7
			
			spark.color = SKINCOLOR_ICY
			spark.colorized = true
		elseif S_SoundPlaying(mobj, sfx_mrslip)
			S_StopSoundByID(mobj, sfx_mrslip)
		end
		
	//Squish
	elseif mobj.fromabove
		local fuse = min(CRUSHTIME - mobj.fuse, CRUSHTIME/4)
		mobj.spritexscale = FRACUNIT + fuse * FRACUNIT/8
		mobj.spriteyscale = FRACUNIT - fuse * FRACUNIT/8
		
	//Flung
	else
		if mobj.rollangle != ANGLE_180
			mobj.rollangle = ($ - ANGLE_180)/2 + ANGLE_180
		end
		mobj.momz = $ + P_GetMobjGravity(mobj)
	end
end, MT_KAMEK_ENEMY)

//Explode after being crushed
addHook("MobjFuse", function(mobj)
	//Escape the ice first...come back here later
	if mobj.mariofrozen
		S_StartSound(mobj, sfx_mrshtr)
		mobj.flags = mobj.info.flags
		mobj.flags = $ &~ MF_NOGRAVITY &~ MF_NOCLIP &~ MF_NOCLIPHEIGHT
		mobj.flags = $ | MF_BOUNCE | MF_GRENADEBOUNCE &~ MF_SCENERY
		
		//Dumb debris
		local radius = FixedDiv(mobj.radius, mobj.scale)
		local height = FixedDiv(mobj.height, mobj.scale)
		for z = 0, 3 for i = -1, 1 for d = -1, 1
			local rock = P_SpawnMobjFromMobj(mobj, radius*2/3*d, radius*2/3*i,
			height - (height/3*z), MT_ROCKCRUMBLE9)
			if rock and rock.valid
				P_InstaThrust(rock, R_PointToAngle2(mobj.x, mobj.y, rock.x, rock.y),
				R_PointToDist2(rock.x, rock.y, mobj.x, mobj.y)/16)
				rock.fuse = TICRATE*5
			end
		end end end
		
		mobj.radius = $ / 2
		mobj.height = $ / 2
		
		P_SetObjectMomZ(mobj, FLIPZ*FRACUNIT, false)
		P_InstaThrust(mobj, mobj.angle, -FLIPH*mobj.scale/2)
		
		local coin = P_SpawnMobjFromMobj(mobj, 0,0,0, MT_FLINGCOIN)
		P_SetObjectMomZ(coin, 8*FRACUNIT, false)
		P_Thrust(coin, mobj.angle, -FRACUNIT)
		coin.fuse = MARIO_DESPAWNTIME
		coin.mariomonitorcoin = true
		
		mobj.color = mobj.mariooldcolor
		mobj.colorized = mobj.mariooldcolorized
		
		mobj.mariofrozen = 0
		mobj.fuse = CRUSHTIME
		return true
	end
	
	if mobj.mariooldtype == MT_YELLOWSHELL
		P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_YELLOWSPRING)
	elseif mobj.mariooldtype == MT_BUGGLE
		P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_EXTRALARGEBUBBLE)
	end
	
	mobj.spritexscale = FRACUNIT
	mobj.spriteyscale = FRACUNIT
	mobj.rollangle = 0
	
	mobj.momx = 0
	mobj.momy = 0
	mobj.momz = 0
	
	mobj.flags = mobj.info.flags
	mobj.state = states[$].nextstate
	return true
end, MT_KAMEK_ENEMY)

// This is the most useless damage collision in existence
addHook("MobjMoveCollide", function(mo, target)
	if mo and mo.valid and mo.mariofrozen and mo.mariofrozen > 1
	and (mo.momx or mo.momy or mo.momz)
	and target and target.valid and target.health
	and (target.flags & MF_SHOOTABLE or target.flags & MF_MISSILE
	or target.type == MT_RING or target.type == MT_COIN)
	and target.z - target.scale <= mo.z + mo.height
	and target.z + target.height + target.scale >= mo.z
		if (target.type == MT_RING or target.type == MT_COIN)
		and mo.tracer and mo.tracer.valid and mo.tracer.player
			if target.info.deathsound == sfx_rnglft
			or target.info.deathsound == sfx_rngrgh
				target.info.deathsound = sfx_itemup
			end
			if mo.tracer.player == displayplayer or mo.tracer.player == secondarydisplayplayer
				S_StartSound(mo.tracer, target.info.deathsound)
			else
				S_StartSound(target, target.info.deathsound)
			end
			A_ForceStop(target)
			P_KillMobj(target)
			P_GivePlayerRings(mo.tracer.player, 1)
		else
			P_DamageMobj(target, mo, mo.tracer)
		end
	end
end, MT_KAMEK_ENEMY)

//Destroy the ice with a ground pound or projectile
addHook("MobjCollide", function(mobj, mo)
	local player = mo and mo.valid and mo.skin == "mario" and mo.player
	if not (mobj and mobj.valid and mobj.mariofrozen and mobj.mariofrozen > 1)
	or (mo.type == MT_PLAYER and (not player or not (player.mariogroundpound or mo.state == S_PLAY_MELEE_LANDING)))
	or (mo.type != MT_PLAYER and (not (mo.flags & MF_MISSILE) or (mo.flags & MF_BOUNCE and not (mo.flags & MF_FIRE))
	or (mo.type == MT_KAMEK_FIREBALL and mo.color == MARIO_ICEFIRECOLOR)))
		return
	end
	
	if  mobj.z - mobj.scale <= mo.z + mo.height
	and mobj.z + mobj.height + mobj.scale >= mo.z
		mobj.fuse = 1
		if player and mo.state == S_PLAY_MELEE_LANDING
		and not P_IsObjectOnGround(mo)
			DoMarioHammerHit(player)
		elseif mo.flags & MF_MISSILE
			P_KillMobj(mo, mobj, mobj.tracer or mobj)
			mo.flags = $ &~ MF_MISSILE
		end
	end
end, MT_KAMEK_ENEMY)

//Destroy the ice with a wall
addHook("MobjMoveBlocked", function(mobj)
	if mobj and mobj.valid and mobj.mariofrozen and mobj.mariofrozen > 1
	and FixedHypot(mobj.momx, mobj.momy) >= FLIPH*mobj.scale
		mobj.fuse = 1
	end
end, MT_KAMEK_ENEMY)

local function SetMarioEnemy(mobj, mo, src, fromabove)
	if fromabove and (mobj.info.deathsound == sfx_mario5
	or mobj.info.deathsound == sfx_mario2) then return end
	
	local deathstate = states[mobj.info.deathstate]
	local nextdeathstate = states[deathstate.nextstate]
	
	if not (deathstate.tics
	and (not deathstate.action
	or deathstate.action == A_Scream
	or deathstate.action == A_FlickySpawn))
	and not (nextdeathstate.tics
	and (not nextdeathstate.action
	or nextdeathstate.action == A_Scream
	or nextdeathstate.action == A_FlickySpawn))
		return
	end
	
	mobj.mariooldtype = mobj.type
	mobj.type = MT_KAMEK_ENEMY
	mobj.info.spawnhealth = mobjinfo[mobj.mariooldtype].spawnhealth
	mobj.flags = mobj.info.flags
	mobj.target = src
	mobj.tracer = src
	
	states[mobj.info.deathstate].sprite = states[mobj.state].sprite
	states[mobj.info.deathstate].frame = states[mobj.state].frame
	
	mobj.fromabove = fromabove
	if mo.type == MT_KAMEK_FIREBALL and mo.color == MARIO_ICEFIRECOLOR
		S_StartSound(mobj, sfx_mrfrze)
		mobj.mariofrozen = 1
		
		mobj.mariooldcolor = mobj.color
		mobj.mariooldcolorized = mobj.colorized
		
		mobj.radius = $ * 2
		if mobj.mariooldtype != MT_CANARIVORE
		and mobj.mariooldtype != MT_POPUPTURRET
			mobj.height = max($ * 2, mobj.radius * 2)
			if mobj.mariooldtype == MT_GFZFISH
				mobj.radius = $ * 2
				mobj.height = max($, mobj.radius * 2)
			end
		end
		
		mobj.color = mo.color
		mobj.colorized = true
		
		for i = 0, 3
			local ice = P_SpawnMobjFromMobj(mobj, 0,0,0, MT_KAMEK_ICEBLOCK)
			ice.target = mobj
			ice.tracer = mobj
			ice.movedir = ANGLE_90 * i
		end
	elseif fromabove
		S_StartSound(mobj, mobj.info.painsound)
	else
		//Metal hit
		local metal = false
		local player = mo.player
		if player and not player.marioshoe 
		and not (player.pflags & PF_SPINNING) and not MarioCantMove(player)
		and (player.powers[pw_shield] == SH_GOLDFLOWER
		or player.powers[pw_shield] == SH_METAL)
			mo.state = S_PLAY_SKID
			mo.tics = TICRATE/4
			
			player.drawangle = R_PointToAngle2(mo.x, mo.y, mobj.x, mobj.y)
			P_InstaThrust(mo, player.drawangle - ANGLE_180, player.speed)
			
			metal = true
			S_StartSound(mobj, sfx_mrmeht)
		else
			S_StartSound(mobj, mobj.info.attacksound)
		end
		
		mobj.flags = $ &~ MF_NOGRAVITY &~ MF_NOCLIP &~ MF_NOCLIPHEIGHT
		mobj.flags = $ | MF_BOUNCE | MF_GRENADEBOUNCE &~ MF_SCENERY
		
		P_SetObjectMomZ(mobj, FLIPZ*FRACUNIT, false)
		P_InstaThrust(mobj, R_PointToAngle2(mo.x, mo.y, mobj.x, mobj.y), FLIPH*mobj.scale)
		
		if mo.type != MT_KAMEK_FIREBALL
			local part = P_SpawnMobjFromMobj(mobj, 0,0,0, MT_EXPLODE)
			P_TeleportMove(part, mobj.x/2 + mo.x/2, mobj.y/2 + mo.y/2, mobj.z/2 + mo.z/2)
			part.destscale = 1
			part.scalespeed = FixedMul($, part.scale)
		end
	end
	
	return true
end

//Death stuff for the fire balls
//Could've put this in the above hook but...yea no thanks
addHook("MobjDeath", function(mobj, mo, src, dmgtype)
	//Mega combo
	local player = src and src.valid and src.skin == "kamek" and src.player
	if player and player.mariomega
	and (mobj and mobj.valid and (mobj.flags & (MF_SHOOTABLE|MF_MONITOR|MF_ENEMY|MF_BOSS)
	or mobj.type == MT_SPIKE or mobj.type == MT_WALLSPIKE))
	and not (mobj.flags & MF_MONITOR and mobj.flags & MF_GRENADEBOUNCE) //Don't count gold
		local addition = 3
		if mobj.type == MT_SPIKE or mobj.type == MT_WALLSPIKE
			addition = 2
		elseif mobj.flags & (MF_ENEMY|MF_BOSS)
			addition = max(mobj.info.spawnhealth*3, $)
		end
		player.mariomegacombo = min($ + addition, 105)
	end
	
	//Detect if proper projectile
	if not (mobj and mobj.valid and mo and mo.valid
	and (mo.type == MT_FIREBALL or mo.type == MT_KAMEK_FIREBALL
	or mo.type == MT_KAMEK_ENEMY
	or (mariomode and mo.flags & MF_MISSILE)
	or (src and src.valid and src.skin == "kamek" and mo.flags & MF_MISSILE))
	and mobj.info.spawnhealth <= 1 and mobj.flags & MF_ENEMY)
		return
	end
	
	//This is dumb
	if mobj.tracer and mobj.tracer.valid
	and (mobj.type == MT_CRUSHSTACEAN or mobj.type == MT_BANPYURA)
		if mobj.type == MT_CRUSHSTACEAN
			local chain = mobj.tracer.target
			local chainnext
			while (chain)
				chainnext = chain.target
				P_RemoveMobj(chain)
				chain = chainnext
			end
		end
		S_StopSound(mobj.tracer)
		P_KillMobj(mobj.tracer, mo, src, dmgtype)
	end

	if mobj.type != MT_BIGMINE and mo.type == MT_KAMEK_FIREBALL
		if mo.type == MT_KAMEK_FIREBALL and mo.color == MARIO_GOLDFIRECOLOR
			mobj.color = mo.color
			mobj.colorized = true
			
			for i = 1, 5
				local coin = P_SpawnMobjFromMobj(mobj, 0,0,0, MT_FLINGCOIN)
				coin.fuse = MARIO_DESPAWNTIME
				//coin.mariomonitorcoin = true
				coin.target = mobj.target
				
				//Only on the 2D axis in 2D bud...
				if twodlevel
					coin.flags2 = $ | MF2_TWOD
				end

				local fa = (ANGLE_180/5*2)*i
				P_InstaThrust(coin, fa, coin.scale)
				P_SetObjectMomZ(coin, 8*FRACUNIT, false)
			end
		elseif mo.color != MARIO_ICEFIRECOLOR
			local coin = P_SpawnMobjFromMobj(mo, 0,0,0, MT_FLINGCOIN)
			if mo.target and mo.target.valid then coin.scale = mo.target.scale end
			P_SetObjectMomZ(coin, 8*FRACUNIT, false)
			P_Thrust(coin, mo.angle, FRACUNIT)
			coin.fuse = MARIO_DESPAWNTIME
			coin.mariomonitorcoin = true
		end
	end
	
	SetMarioEnemy(mobj, mo, src, false)
	
	if mo.type == MT_KAMEK_FIREBALL
		P_KillMobj(mo)
	end
end)