---- Abilities ----

--Mod by SuperOfSrb2
rawset(_G,"Bark",{})

Bark.PlayerCheck = function(player)
	if player and player.mo and player.valid
		return true
	else
		return false
	end
end

Bark.BarkCheck = function(player)
	if Bark.PlayerCheck(player) and player.mo.skin == "bark"
		return true
	else
		return false
	end
end

Bark.GroundCheck = function(player, bhop)
	if bhop == nil bhop = true end
	if Bark.PlayerCheck(player)
		if P_IsObjectOnGround(player.mo)
		or (bhop and player.mo.eflags & MFE_JUSTHITFLOOR)
			return true
		else
			return false
		end
	else
		return false
	end
end

freeslot("S_PLAY_WHEELPUNCH")
freeslot("S_PLAY_WHEELFALL")
freeslot("MT_WHEELPUNCHHITBOX")
freeslot("S_WHEELPUNCHHITBOX")
freeslot("sfx_wlpnch")
sfxinfo[sfx_wlpnch].caption = "Wheel Punch"

Bark.AbilityActionable = function(player)
	--[[if player.mo.state == (S_PLAY_JUMP)
	or player.mo.state == (S_PLAY_SPRING)
	or player.mo.state == (S_PLAY_FALL)
	or player.mo.state == (S_PLAY_ROLL)]]
		if not (player.pflags & PF_THOKKED)
			return true
		else
			return false
		end
	--[[else
		return false
	end]]
end

Bark.HandleReverseGravity = function(player)
	if Bark.PlayerCheck(player)
		if player.mo.eflags & MFE_VERTICALFLIP
			player.revgrav = -1
			return true
		else
			player.revgrav = 1
			return false
		end
	end
end

Bark.GetFloorDist = function(player)
	if Bark.PlayerCheck(player)
		local floorheight = 0
		local floordist = 0
		Bark.HandleReverseGravity(player)
		if Bark.HandleReverseGravity(player)
			if player.mo.ceilingrover != nil
				floorheight = player.mo.ceilingrover.bottomheight
			else
				floorheight = player.mo.ceilingz
			end
			floordist = player.revgrav*(player.mo.z - floorheight + player.mo.height)
		else
			if player.mo.floorrover != nil
				floorheight = player.mo.floorrover.topheight
			else
				floorheight = player.mo.floorz
			end
			floordist = player.revgrav*(player.mo.z - floorheight - 0)
		end

		return floordist
	end
end

Bark.GetCeilDist = function(mo)
	if mo and mo.valid
		local floorheight = 0
		local floordist = 0
		if mo.eflags & MFE_VERTICALFLIP
			mo.revgrav = -1
		else
			mo.revgrav = 1
		end
		if mo.revgrav == 1
			if mo.ceilingrover != nil
				floorheight = mo.ceilingrover.bottomheight
			else
				floorheight = mo.ceilingz
			end
			floordist = mo.revgrav*(mo.z - floorheight)
		else
			if mo.floorrover != nil
				floorheight = mo.floorrover.topheight
			else
				floorheight = mo.floorz
			end
			floordist = mo.revgrav*(mo.z - floorheight)
		end

		return floordist
	end
end

Bark.CheckAndCrumble = function(mo,sec) //Those who consult Eclise's code for the 1000th time for Tatsuru#8938 wall breaking function
  for fof in sec.ffloors()
    if not (fof.flags & FF_EXISTS) continue end 
    if not (fof.flags & FF_BUSTUP) continue end 
    if mo.z + mo.height < fof.bottomheight continue end 
    if mo.z > fof.topheight continue end    
    EV_CrumbleChain(fof)
  end
end

addHook("AbilitySpecial", function(player)
	if Bark.BarkCheck(player)	
		if Bark.AbilityActionable(player)
			player.mo.state = S_PLAY_WHEELPUNCH
		end		
	end
end)

freeslot("S_PLAY_HAMMERDIVE")
freeslot("S_PLAY_GROUNDSLAM")
freeslot("S_PLAY_GROUNDSLAM2")
freeslot("sfx_hmdive")
sfxinfo[sfx_hmdive].caption = "Hammer Dive"

addHook("SpinSpecial", function(player)
	if Bark.BarkCheck(player)
		if player.mo.state == S_PLAY_WHEELPUNCH
			player.mo.state = S_PLAY_HAMMERDIVE
		end
		if (player.pflags & PF_THOKKED) and (player.mo.state == S_PLAY_FALL) and not (player.shielded)
			player.mo.state = S_PLAY_HAMMERDIVE
		end
	end
end)

addHook("ShieldSpecial", function(player)
	if Bark.BarkCheck(player)
		if player.powers[pw_shield] != SH_NONE
		and player.powers[pw_shield] != SH_PITY
		and player.powers[pw_shield] != SH_PINK
			player.shielded = true
		end
	end
end)

freeslot("MT_BOULDERSPAWNER")

Bark.SpawnBoulder = function(boulderspawner, player, stackoverflow)
	if P_TryMove(boulderspawner, player.mo.x + P_RandomRange(-512, 512)*FRACUNIT,player.mo.y + P_RandomRange(-512, 512)*FRACUNIT, true)
		boulderspawner.height = 1024*FRACUNIT
		local revgrav = 1
		local height = boulderspawner.height
		local checkfsky = true
		if boulderspawner.eflags & MFE_VERTICALFLIP
			revgrav = -1
			height = boulderspawner.z+(boulderspawner.height*2)
		end
		local sec = boulderspawner.subsector.sector
		for fof in sec.ffloors()
			if not (fof.flags & FF_EXISTS) continue end 
			if not (fof.flags & FF_SOLID) continue end
			if (boulderspawner.z > fof.bottomheight) and (revgrav == 1) continue end
			if (boulderspawner.z < fof.topheight) and (revgrav == -1) continue end
			if revgrav == 1
				height = fof.bottomheight - 32*FRACUNIT - boulderspawner.z
			else
				height = -1*fof.topheight + boulderspawner.height + boulderspawner.z - 32*FRACUNIT
			end
			checkfsky = false
		end
		if checkfsky
			if revgrav == 1
				if sec.ceilingpic == "F_SKY" return end
				if sec.ceilingpic == "~PIT" return end
				if sec.ceilingpic == "PIT" return end
			elseif revgrav == -1
				if sec.floorpic == "F_SKY" return end
				if sec.floorpic == "~PIT" return end
				if sec.floorpic == "PIT" return end
			end
		end
		if not P_TryMove(boulderspawner, boulderspawner.x, boulderspawner.y, true)
			local rock = P_SpawnMobjFromMobj(boulderspawner, 0, 0, height, MT_FALLINGROCK)
			rock.bark = player.mo
			rock.state = P_RandomRange(S_ROCKCRUMBLEA, S_ROCKCRUMBLEP)
			rock.target = player.mo
			P_RemoveMobj(boulderspawner)
		end
	elseif stackoverflow < 11
		Bark.SpawnBoulder(boulderspawner, player, stackoverflow + 1)
	end
end

addHook("PlayerThink", function(player)
	if Bark.BarkCheck(player)
		if player.barkstate == nil then
			player.barkstate = player.mo.state
		end
		if Bark.GroundCheck(player)
			player.shielded = false
		end
		
		if player.mo.state == S_PLAY_WHEELPUNCH --speen
		
			player.charflags = $|SF_NOSHIELDABILITY
			if player.barkangle == nil
				player.barkangle = player.drawangle
			end
			player.barkangle = $ - ANG30
			player.drawangle = player.barkangle
			Bark.HandleReverseGravity(player)
			player.mo.momz = FRACUNIT*5*player.revgrav
			local speedlimit = FRACUNIT*39
			if (player.powers[pw_sneakers] != 0)
			or (player.powers[pw_super] != 0)
				speedlimit = $*2
			end
			local thrust = FRACUNIT*20 - player.speed/4
			if player.mo.eflags & MFE_UNDERWATER then
				speedlimit = $/2
				thrust = thrust/2
			end
			if player.speed > speedlimit then
				P_Thrust(player.mo, player.mo.angle + ANGLE_180, FRACUNIT)
			end
			if player.mo.tics == TICRATE
				P_Thrust(player.mo, player.mo.angle, thrust)
				player.powers[pw_strong] = $|STR_ATTACK|STR_ANIM
				S_StartSound(player.mo, sfx_wlpnch)
			elseif not (player.cmd.buttons & BT_JUMP)
				player.mo.state = S_PLAY_WHEELFALL
			elseif player.mo.tics == TICRATE/2
				S_StartSound(player.mo, sfx_wlpnch)
			end
		
		else
			player.charflags = $ & ~SF_NOSHIELDABILITY
		end
		
		if player.mo.state == S_PLAY_WHEELFALL --Stop Spinning This Instant.
		
			player.barkangle = nil
			player.drawangle = player.mo.angle
			player.pflags = $|PF_THOKKED
			
		end
		
		if player.mo.state == S_PLAY_HAMMERDIVE --weee
		
			if player.physicsviolation == nil 
				player.physicsviolation = -5
			end
			if P_IsObjectInGoop(player.mo)
				player.physicsviolation = 0
			end
			if player.physicsviolation != nil 
				A_ZThrust(player.mo, player.physicsviolation / ((player.mo.eflags & MFE_UNDERWATER and 2) or 1))
			end
			player.barkangle = nil
			player.drawangle = player.mo.angle
			player.pflags = $|PF_THOKKED
			player.pflags = $ & ~PF_NOJUMPDAMAGE
			if player.mo.tics == TICRATE*10
				S_StartSound(player.mo, sfx_hmdive)
			end
			Bark.HandleReverseGravity(player)
			player.powers[pw_strong] = $|STR_ANIM|STR_HEAVY|STR_STOMP|STR_FLOOR|STR_SPRING|STR_SPIKE
			
		else
			player.physicsviolation = nil
		end
		
		if Bark.GroundCheck(player, false) and (player.barkstate == S_PLAY_HAMMERDIVE) and (player.playerstate != PST_DEAD) --Stop fucking jumping around.
			player.mo.state = S_PLAY_GROUNDSLAM
			S_StopSoundByID(player.mo, sfx_hmdive)
			S_StartSound(player.mo, sfx_s3k5d) --hit sfx from bark mania
			player.holdingspin = true
			Bark.HandleReverseGravity(player)
			local missile = P_SpawnPointMissile(player.mo, player.mo.x, player.mo.y, player.mo.z - player.revgrav*16*FRACUNIT, MT_WHEELPUNCHHITBOX, player.mo.x, player.mo.y, player.mo.z - player.revgrav*17*FRACUNIT)
			if missile != nil missile.radius = 192 end
			P_StartQuake(8*FRACUNIT, TICRATE/6, {player.mo.x, player.mo.y, player.mo.z}, 192*FRACUNIT*5)
		end
		
		if (player.mo.state == S_PLAY_GROUNDSLAM) -- land shattering stomp ?	
		or (player.mo.state == S_PLAY_GROUNDSLAM2)
		
			player.powers[pw_strong] = $|STR_ATTACK|STR_ANIM
			player.mo.friction = FRACUNIT/50
			player.pflags = $|PF_JUMPSTASIS
			if (player.cmd.buttons & BT_SPIN) --Continue ground slamming
			and not player.holdingspin
				if player.mo.tics < 16
					player.mo.tics = 16
				end
				player.holdingspin = true
				player.mo.state = S_PLAY_GROUNDSLAM2
			end
			
			if (player.mo.state == S_PLAY_GROUNDSLAM2) and (leveltime % 16 == 0)
				S_StopSoundByID(player.mo, sfx_s3k5d) --hit sfx from bark mania
				S_StartSound(player.mo, sfx_s3k5d) --hit sfx from bark mania
				Bark.HandleReverseGravity(player)
				local missile = P_SpawnPointMissile(player.mo, player.mo.x, player.mo.y, player.mo.z - player.revgrav*16*FRACUNIT, MT_WHEELPUNCHHITBOX, player.mo.x, player.mo.y, player.mo.z - player.revgrav*17*FRACUNIT)
				if missile != nil missile.radius = 150 end
				P_StartQuake(4*FRACUNIT, TICRATE/6, {player.mo.x, player.mo.y, player.mo.z}, 150*FRACUNIT*5)
				local boulderspawner = P_SpawnMobjFromMobj(player.mo, 0, 0, 0, MT_BOULDERSPAWNER)
				Bark.SpawnBoulder(boulderspawner, player, 0)
			end
			
			
		elseif (player.barkstate == S_PLAY_GROUNDSLAM)
		or (player.barkstate == S_PLAY_GROUNDSLAM2)
			player.pflags = $ & ~PF_JUMPSTASIS
		end
		
		if (player.mo.eflags & MFE_SPRUNG)
		and (player.barkstate == S_PLAY_HAMMERDIVE)
			S_StopSoundByID(player.mo, sfx_hmdive)
			if player.mo.state != S_PLAY_SPRING
				player.mo.state = S_PLAY_ROLL
			end
		end
			
		if player.holdingspin
		and not (player.cmd.buttons & BT_SPIN)
			player.holdingspin = false
		end
		
		player.barkstate = player.mo.state --previous state
	end
end)

addHook("MobjThinker", function(mo) --Boulders from ceiling
	if mo.bark != nil
		local missile = P_SpawnPointMissile(mo, mo.x, mo.y, mo.z - 1*FRACUNIT, MT_WHEELPUNCHHITBOX, mo.x, mo.y, mo.z - 2*FRACUNIT)
		if missile != nil
			missile.target = mo.bark
			missile.radius = 64
			missile.height = 64
		end
	end
end, MT_FALLINGROCK)