local DEFAULTSTRENGTH = 16

freeslot("MT_BUMPER", "S_BUMPER", "S_BUMPERHIT", "SPR_BUNP")

mobjinfo[MT_BUMPER] = {
	//$Sprite BUNPA0
	//$Name Bumper
	spawnstate = S_BUMPER,
	radius = 32*FRACUNIT,
	height = 64*FRACUNIT,
	doomednum = 461,
	dispoffset = 0,
	deathstate = S_NULL,
	deathsound = sfx_s3kaa,
	flags = MF_SPECIAL|MF_NOGRAVITY|MF_DONTENCOREMAP
}

states[S_BUMPER] = {SPR_BUNP, A, -1, nil, 0, 0, S_BUMPER}
states[S_BUMPERHIT] = {SPR_BUNP, FF_ANIMATE|D, 12, nil, 1, 3, S_BUMPER}

freeslot("MT_10POINTS", "S_10POINTS")

mobjinfo[MT_10POINTS] = {
		spawnstate = S_10POINTS,
		speed = 3*FRACUNIT,
		radius = 8*FRACUNIT,
		height = 8*FRACUNIT,
		mass = 100,
		dispoffset = 1,
		flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_RUNSPAWNFUNC
}

states[S_10POINTS] = {SPR_SCOR, L, 32, A_ScoreRise, 0, 0, S_NULL}

local function bumpPlayer(bumpermo, playermo)
	--Determine the angle the player hit the bumper from.
	local horizontalAngle = R_PointToAngle2(bumpermo.x,bumpermo.y,playermo.x,playermo.y)
	local verticalAngle = R_PointToAngle2(FixedHypot(bumpermo.x,bumpermo.y),bumpermo.z+(bumpermo.height/2),FixedHypot(playermo.x,playermo.y),playermo.z+(playermo.height/2))
	
	-- This sets whether or not the player is holding the jump button.
	-- Without this line, the player can let go of the jump button to reduce the bumper's effects.
	playermo.player.jumping = false
	
	-- If the bumper was created by another object or script, the minimum strength will be determined by the DEFAULTSTRENGTH value at the top of this script.	
	local bumperStrength = DEFAULTSTRENGTH
	
	-- If the bumper was placed on the map in ZoneBuilder, the angle will determine the bumper's minimum strength.
	if bumpermo.spawnpoint.valid and bumpermo.spawnpoint.angle > 0
		bumperStrength = bumpermo.spawnpoint.angle/10
	end
	
	-- Bounce the player back slightly slower than the speed at which they hit the bumper.
	local playerVelocity = FixedHypot(playermo.player.speed, playermo.momz)
	if bumperStrength < (9*playerVelocity) / (10*FRACUNIT)
		bumperStrength = (9*playerVelocity) / (10*FRACUNIT)
	end
	
	-- Bounce the player back at the angle they hit the bumper from.
	P_SetObjectMomZ(playermo, bumperStrength*sin(verticalAngle), false)
	P_InstaThrust(playermo, horizontalAngle, bumperStrength*abs(cos(verticalAngle)))
	
	-- Show the "hit" frames and play the bumper sound (but only if the bumper is not already being hit).
	if bumpermo.state == S_BUMPER
		S_StartSound(bumpermo, bumpermo.info.deathsound)
		bumpermo.state = S_BUMPERHIT
		if bumpermo.points == nil
			bumpermo.points = 10 -- Maximum number of times the bumper can give points.
		end
		-- Only give points if the "Special" flag is not checked.
		if bumpermo.spawnpoint.valid and not (bumpermo.spawnpoint.options & MTF_OBJECTSPECIAL) and bumpermo.points > 0
			P_SpawnMobj(bumpermo.x,bumpermo.y,bumpermo.z+(bumpermo.height/2),MT_10POINTS)
			P_AddPlayerScore(playermo.player, 10)
			bumpermo.points = $1 - 1
		end
	end
	-- If "Ambush" flag is checked, the bumper will disappear after being hit.
	if not (bumpermo.spawnpoint.options & MTF_AMBUSH)
		return true
	end
end

-- This function keeps all bumpers synced up to the same frames.
-- If you want to change the bumper's animation, here is where you do it.
local function syncAnimation(bumpermo)
	if bumpermo.state == S_BUMPER
		if leveltime % 16 < 5
			bumpermo.frame = 0
		elseif leveltime % 16 < 8
			bumpermo.frame = 1
		elseif leveltime % 16 < 13
			bumpermo.frame = 2
		else
			bumpermo.frame = 1
		end
	end
end

addHook("TouchSpecial",bumpPlayer,MT_BUMPER)
addHook("MobjThinker", syncAnimation, MT_BUMPER)