//A experimental gimmick (by Sonic1983)
//How this work:
//Put on ANY FOF in String Argument 1 this: "Crater"
//Linedef Tag - Linedef Execute's Tag after blast
//Argument 6 - Height for blasting FOF to up!
//Argument 7 - Speed of blasted FOF
//Argument 8 - Spindashable?

local craterfof = {}

addHook("NetVars", function(net)
	craterfof = net($)
end)

addHook("MapLoad", function()
	craterfof = {}
	if udmf
		for sector_fof in sectors.iterate
			if sector_fof
			and sector_fof.valid
				for rover in sector_fof.ffloors()
					if rover
					and rover.valid
						if rover.master
						and rover.master.valid
						and rover.master.stringargs[0] == "Crater"
							//1 - FOF
							//2 - Original Top Height
							//3 - Original Bottom Height
							//4 - Air Bob Thinker or not
							//5 - Gravity Speed
							//6 - Player on FOF
							//7 - Mobj
							//8 - Spindashable?
							table.insert(craterfof, {rover, rover.topheight, rover.bottomheight, false, 0, false, nil, false})
						end
					end
				end
			end
		end
	end
end)

//From Source Code
local function SlopePos(mobj, height, slope)
	if(slope)
		// Get the corner of the object that should be the highest on the slope
		local testx
		local testy
		if(slope.d.x < 0)
			testx = mobj.radius
		else
			testx = -mobj.radius
		end
		
		if(slope.d.y < 0)
			testy = mobj.radius
		else
			testy = -mobj.radius
		end
		
		if(slope.zdelta > 0)
			testx = -testx
			testy = -testy
		end
		
		testx = $1 + mobj.x
		testy = $1 + mobj.y
		return P_GetZAt(slope, testx, testy)
	else
		return height
	end
end

//From Source Code
//Slope Helper
local function SlopePos(mobj, height, slope)
	if(slope)
		// Get the corner of the object that should be the highest on the slope
		local testx
		local testy
		if(slope.d.x < 0)
			testx = mobj.radius
		else
			testx = -mobj.radius
		end
		
		if(slope.d.y < 0)
			testy = mobj.radius
		else
			testy = -mobj.radius
		end
		
		if(slope.zdelta > 0)
			testx = -testx
			testy = -testy
		end
		
		testx = $1 + mobj.x
		testy = $1 + mobj.y
		return P_GetZAt(slope, testx, testy)
	else
		return height
	end
end

//From Source Code
local function ThingOnSpecial3DFloor(mo)
	local sector
	local topheight
	local bottomheight

	sector = mo.subsector.sector

	for rover in sector.ffloors()
		if not (rover and rover.valid)
			continue
		end

		if (not (rover.flags & FF_EXISTS))
			continue
		end

		topheight = SlopePos(mo, rover.topheight, rover.t_slope)
		bottomheight = SlopePos(mo, rover.bottomheight, rover.b_slope)

		// Check the 3D floor's type...
		if (((rover.flags & FF_BLOCKPLAYER) and mo.player)
		or ((rover.flags & FF_BLOCKOTHERS) and not mo.player))
			// Thing must be on top of the floor to be affected...
			if ((rover.master.frontsector.flags & MSF_FLIPSPECIAL_FLOOR)
			and not (rover.master.frontsector.flags & MSF_FLIPSPECIAL_CEILING))
				if ((mo.eflags & MFE_VERTICALFLIP) or mo.z != topheight)
					continue
				end
			elseif ((rover.master.frontsector.flags & MSF_FLIPSPECIAL_CEILING)
			and not(rover.master.frontsector.flags & MSF_FLIPSPECIAL_FLOOR))
				if (not (mo.eflags & MFE_VERTICALFLIP)
					or mo.z + mo.height != bottomheight)
					continue
				end
			elseif (rover.master.frontsector.flags & MSF_FLIPSPECIAL_BOTH)
				if (not ((mo.eflags & MFE_VERTICALFLIP and mo.z + mo.height == bottomheight)
				or (not (mo.eflags & MFE_VERTICALFLIP) and mo.z == topheight)))
					continue
				end
			end
		else
			// Water and intangible FOFs
			if (mo.z > topheight or (mo.z + mo.height) < bottomheight)
				continue
			end
		end

		return rover.master.frontsector
	end

	return nil
end

addHook("ThinkFrame", function()
	for i = 1, #craterfof
		local rover = craterfof[i][1]
		local rover_vars = craterfof[i]
		if rover
		and rover.valid
			local line = rover.master
			if line.args[7] != 0
				rover_vars[8] = true
			end
			if rover_vars[4] == false //Air Bob
				if rover_vars[6] == true
					rover.topheight = $-FRACUNIT
					rover.bottomheight = $-FRACUNIT
				else
					rover.topheight = min($+FRACUNIT, rover_vars[2])
					rover.bottomheight = min($+FRACUNIT, rover_vars[3])
				end
				if rover.topheight <= line.args[5]*FRACUNIT
					rover_vars[4] = true
					rover_vars[5] = line.args[6]*FRACUNIT
					if line.tag
						P_LinedefExecute(line.tag, rover_vars[7])
					end
				end
			else //Jump Mode!
				rover.topheight = $+rover_vars[5]
				rover.bottomheight = $+rover_vars[5]
				rover_vars[5] = $-gravity
				if rover_vars[5] < 0
					if rover.topheight <= rover_vars[2]
						rover.topheight = rover_vars[2]
						rover.bottomheight = rover_vars[3]
						rover_vars[4] = false
						rover_vars[5] = 0
					end
				end
			end
			for player in players.iterate //Checks players on FOF
				if player.mo
				and player.mo.valid
				and player.playerstate == PST_LIVE
					if player.mo.z <= rover.topheight
					and player.mo.z+player.mo.height >= rover.bottomheight
					and ThingOnSpecial3DFloor(player.mo) == rover.sector
						if rover_vars[8] //Additional Spindash Check
							if player.pflags & PF_STARTDASH
								rover_vars[6] = true
								rover_vars[7] = player.mo
								break
							else
								rover_vars[6] = false
								rover_vars[7] = nil
							end
						else
							rover_vars[6] = true
							rover_vars[7] = player.mo
							break
						end
					else
						rover_vars[6] = false
						rover_vars[7] = nil
					end
				end
			end
		end
	end
end)