freeslot("sfx_bbonce","sfx_pcheal","sfx_pcahng","sfx_pacdbj","sfx_pcrev1","sfx_pcrev2","sfx_pmsupr",
"sfx_pcjump","sfx_pacbnc","sfx_pcland","sfx_pacflp","sfx_pcflph")

sfxinfo[sfx_bbonce].caption = "Super Butt Bounce"
sfxinfo[sfx_pcheal].caption = "Health Up!"
sfxinfo[sfx_pcahng].caption = "Air Hang"
sfxinfo[sfx_pacdbj].caption = "Jump"
sfxinfo[sfx_pcrev1].caption = "Rev Roll"
sfxinfo[sfx_pcrev2].caption = "Rev Roll"
sfxinfo[sfx_pmsupr].caption = "Super Pac-man!"

sfxinfo[sfx_pcjump].caption = "Jump"
sfxinfo[sfx_pacbnc].caption = "Butt Bounce"
sfxinfo[sfx_pcland].caption = "Land"
sfxinfo[sfx_pacflp].caption = "Flip Kick"
sfxinfo[sfx_pcflph].caption = "Flip Kick hit"

freeslot(
	"MT_FLIPKICK",
	"S_FLIPKICK",
	"S_FLIPKICK1A",
	"S_FLIPKICK1B",
	"S_FLIPKICK2A",
	"S_FLIPKICK2B",
	"S_FLIPKICK3A",
	"S_FLIPKICK3B",
	"S_FLIPKICK4A",
	"S_FLIPKICK4B",
	"S_FLIPKICK5A",
	"S_FLIPKICK5B",
	"S_FLIPKICK6A",
	"S_FLIPKICK6B",
	"SPR_FLPK"
)

mobjinfo[MT_FLIPKICK] = {
	doomednum = -1,
	spawnhealth = 1,
	spawnstate = S_FLIPKICK,
	radius = 32*FRACUNIT,
	height = 32*FRACUNIT,
	flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_FLIPKICK] = {SPR_FLPK, 0|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK1A}
states[S_FLIPKICK1A] = {SPR_FLPK, 0|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK1B}
states[S_FLIPKICK1B] = {SPR_FLPK, 1|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK2A}
states[S_FLIPKICK2A] = {SPR_FLPK, 1|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK2B}
states[S_FLIPKICK2B] = {SPR_FLPK, 2|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK3A}
states[S_FLIPKICK3A] = {SPR_FLPK, 2|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK3B}
states[S_FLIPKICK3B] = {SPR_FLPK, 3|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK4A}
states[S_FLIPKICK4A] = {SPR_FLPK, 3|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK4B}
states[S_FLIPKICK4B] = {SPR_FLPK, 4|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK5A}
states[S_FLIPKICK5A] = {SPR_FLPK, 4|FF_PAPERSPRITE, 1, A_CapeChase, 0, 0, S_FLIPKICK5B}
states[S_FLIPKICK5B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_FLIPKICK6A}
states[S_FLIPKICK6A] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_FLIPKICK6B}
states[S_FLIPKICK6B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_NULL}

freeslot("S_PACMAN_AIR_HANG", "SPR2_GRND")

states[S_PACMAN_AIR_HANG] = {SPR_PLAY, SPR2_RUN_, 1, nil, 0, 0, S_PACMAN_AIR_HANG}

local function FlipKick(player)
	if (player.mo) and (player.mo.skin == "pacman") //sonic
	and player.flipkicktimer == 12
	and not (player.pflags & PF_THOKKED) and not (player.pflags & PF_USEDOWN) and not (player.powers[pw_carry])
	and not (player.panim == PA_ETC)
		player.invisiframe = 1
		S_StartSound(player.mo, sfx_pacflp)
		local flipkick = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_FLIPKICK)
		flipkick.target = player.mo
		flipkick.scale = player.mo.scale*3/2
		player.tracer = flipkick
		if (player.mo.eflags & MFE_VERTICALFLIP)
			flipkick.eflags = $|MFE_VERTICALFLIP
		end
		if not (player.mo.state == S_PLAY_TWINSPIN)
			player.mo.state = S_PLAY_TWINSPIN
		end
		player.flipkick = 1
		return true
	end
end

addHook("PlayerThink", function(player)
	if (player.mo.skin == "pacman")
		if player.flipkicktimer == nil
		or player.flipkicktimer == 0
		or P_IsObjectOnGround(player.mo)
			player.flipkicktimer = 12
			player.flipkick = 0
		end
		
		if player.flipkicktimer == 11
			player.pflags = $|PF_SPINNING
		elseif player.flipkicktimer == 10
			player.pflags = $ & ~PF_SPINNING
		end
		
		if (player.mo.state == S_PLAY_TWINSPIN)
			player.mo.tics = 1
		end
		
		if (player.flipkick == 1)
			player.charflags = skins["pacman"].flags|SF_CANBUSTWALLS
			player.flipkicktimer = $ - 1
			if P_IsObjectOnGround(player.mo)
				player.flipkick = 0
				if (player.tracer and player.tracer.valid) and player.tracer.type == MT_FLIPKICK
					P_KillMobj(player.tracer)
				end
			end
		else
			player.charflags = (skins["pacman"].flags)|SF_MARIODAMAGE
		end
	end
end)

addHook("JumpSpinSpecial", FlipKick)

local function KickCheck(sonic, inflictor, source, damage, element)
	if (sonic.player) and sonic.player.tracer and sonic.player.tracer.valid and sonic.player.tracer.health and sonic.player.tracer.type == MT_FLIPKICK
		if not (element == DMG_INSTAKILL) and not (element == DMG_DROWNED) and not (element == DMG_SPACEDROWN) and not (element == DMG_DEATHPIT) and not (element == DMG_CRUSHED) and not (element == DMG_SPECTATOR)
			if not P_IsObjectOnGround(sonic)
				return false  //do not damage player while instashield is active
			end
		end
	end
end

addHook("ShouldDamage", KickCheck)

local function KickCollide(kick, mobj) //instashield attacks function as an expanded roll hitbox and can damage things normal spins can't
	if not (kick.z-FixedMul(24*FRACUNIT, kick.scale) > mobj.z+mobj.height) and not(mobj.z-FixedMul(24*FRACUNIT, kick.scale) > kick.z+kick.height)
		if (mobj.valid and mobj.health and (mobj.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) or (mobj.flags & MF_PUSHABLE and mobj.flags & MF_SHOOTABLE)))
			P_DamageMobj(mobj, kick, kick.target)
			if ((kick.target.momz < 0) and not (kick.target.eflags & MFE_VERTICALFLIP))
				P_SetObjectMomZ(kick.target, -kick.target.momz)
			elseif ((kick.target.momz > 0) and (kick.target.eflags & MFE_VERTICALFLIP))
				P_SetObjectMomZ(kick.target, kick.target.momz)
			end
			if (mobj.info.spawnhealth > 1)
				P_InstaThrust(kick.target, kick.target.angle, -kick.target.player.speed)
			end
			S_StartSound(kick.target, sfx_pcflph)
		end
	else
		return nil
	end
end

addHook("MobjMoveCollide", KickCollide, MT_FLIPKICK)
addHook("MobjCollide", KickCollide, MT_FLIPKICK)

//Original Reusable template by Katmint.
addHook("MusicChange", function(oldname, newname)
	if consoleplayer
		local character = skins[consoleplayer.skin].name
		if character == "pacman" //skin to use custom themes
			if newname == "_super" //intercept and override jingles
				return "pmsupr"
			end
		end
	end
end)

//No super color. He has the mask and cape already, so who cares?
addHook("PlayerThink", function(player)
	if (player.mo and player.mo.skin == "pacman")
		if player.powers[pw_super] 
			player.mo.color = player.skincolor
		end
	end
end)

//No afterimages, either. The cape, mask, and sparkle are enough :)
addHook("MobjThinker", function(mo)
	if mo.skin == "pacman"
		mo.state = S_INVISIBLE
	end
end, MT_GHOST)

addHook("AbilitySpecial", function(player)
	if (player.mo and player.mo.skin == "pacman")
		player.pflags = $1|PF_THOKKED
	end
end)
//Butt-Bounce, Based off of the Sonic Lost World Bounce Attack made by MotdSpork. Boing!
//It's been modified by SuperPhanto to be more accurate
addHook("ThinkFrame", do
	for player in players.iterate
		local sonic = player.mo
		
		if (sonic and sonic.skin == "pacman") //if you're sonic..
		and sonic.player.playerstate == PST_LIVE //you alive bruh?
		and not (sonic.player.panim == PA_ETC) //allow Super Transformation to play
		and player.flipkicktimer == 12
			if sonic.player.bounceattack == nil //if the variable doesnt exist
				sonic.player.bounceattack = 0 //create variable
			end
			if sonic.player.jumpdown == nil
			or P_IsObjectOnGround(sonic)
			or not (sonic.player.cmd.buttons & BT_JUMP)
				sonic.player.jumpdown = 0
			end
			
			if sonic.player.bouncenumber == nil //if the variable doesnt exist
				sonic.player.bouncenumber = 0 //create variable
				sonic.player.justchangedbouncenumber = 0 //create variable
			end
			if P_IsObjectOnGround(sonic) //are you on the ground?
			and sonic.player.bounceattack == 0 //the player isnt bouncing
				sonic.player.bouncenumber = 0 //set it to zero!
			end
			if sonic.player.usedown == nil //if the variable doesnt exist
			or not (sonic.player.cmd.buttons & BT_JUMP) //not pressing the spin button?
				sonic.player.usedown = 0 //create variable
				sonic.player.justchangedbouncenumber = 0 //create variable
			end
			if (sonic.player.cmd.buttons & BT_JUMP)
			and P_IsObjectOnGround(sonic) //Is the player holding the spin button?
				sonic.player.usedown = 1 //Set it to one!
			end
			if sonic.player.pflags & PF_JUMPED //if the player has jumped
			and (sonic.player.pflags & PF_THOKKED) //and the player hasnt used their mid-air ability
			and not (P_IsObjectOnGround(sonic)) //and you arent on the ground.
			and sonic.player.cmd.buttons & BT_JUMP //pressing custom2?
			and sonic.player.bounceattack == 0 //checking if the custom variable it set to 0
			and sonic.player.usedown == 0 //make sure you arent holding the spin button.
			and not (sonic.player.exiting) //not...exiting the level?
			and sonic.health //you're alive?
			and not (P_PlayerInPain(sonic.player)) //not hurt are you?
			and not (sonic.eflags & MFE_SPRUNG)
				sonic.player.bounceattack = 1 //set it to one!
				if (sonic.momz*P_MobjFlip(sonic) > 0)
					P_SetObjectMomZ(sonic, 0) //make the player "shoot" downward
				end
				//P_SetObjectMomZ(sonic, FixedMul(-35*FRACUNIT, sonic.scale)) //make the player shoot downwards 
				sonic.player.pflags = $1|PF_THOKKED //force the player into a "thokked" state
			elseif (sonic.eflags & MFE_SPRUNG)
			and sonic.player.bounceattack == 1
				sonic.state = S_PLAY_SPRING
				sonic.player.bounceattack = 0
			end
			 	
			if ((sonic.eflags & MFE_JUSTHITFLOOR) or (sonic.momz*P_MobjFlip(sonic) > 0)) //you're on the ground.
			and not (sonic.player.pflags & PF_SPINNING) //you arent spinning....somehow
			and not (sonic.player.pflags & PF_STARTDASH) //you arent doing a spindash
			and not (sonic.tracer and sonic.tracer.type == MT_TUBEWAYPOINT) //not in a...zoomtube?
			and sonic.player.bounceattack == 1 //our custom variable is one right...?
			and sonic.health //is the player alive..?
			and not (P_PlayerInPain(sonic.player)) //not hurt are you?
				if sonic.player.bouncenumber == 0 //if he hasnt bounced yet
				and sonic.player.justchangedbouncenumber == 0 //if he hasnt left the ground yet
					sonic.player.justchangedbouncenumber = 1 //now he has!
					sonic.player.bouncenumber = 1 //Set this to one!
					sonic.player.pflags = $1|PF_JUMPED //forcing the player into a jumping state.
					
					if player.powers[pw_super]
						P_SetObjectMomZ(sonic, FRACUNIT*16)
						P_Earthquake(sonic, sonic, FRACUNIT*128)
						S_StartSound(sonic, sfx_bbonce) //play a sound c:
					else
						P_SetObjectMomZ(sonic, FRACUNIT*12)
						S_StartSound(sonic, sfx_pacbnc)
					end
				end
				if sonic.player.bouncenumber == 1 //if it's currently on his first bounce
				and sonic.player.justchangedbouncenumber == 0 //if he hasnt left the ground yet
				and not (P_PlayerInPain(sonic.player)) //not hurt are you?
					sonic.player.justchangedbouncenumber = 1 //now he has!
					sonic.player.bouncenumber = 2 //set this to two!
					sonic.player.pflags = $1|PF_JUMPED //forcing the player into a jumping state.
					
					if player.powers[pw_super]
						P_SetObjectMomZ(sonic, FRACUNIT*18)
						P_Earthquake(sonic, sonic, FRACUNIT*192)
						S_StartSound(sonic, sfx_bbonce) //play a sound c:
					else
						P_SetObjectMomZ(sonic, FRACUNIT*14)
						S_StartSound(sonic, sfx_pacbnc)
					end
				end
				if sonic.player.bouncenumber == 2 //if it's currently on his second bounce
				and sonic.player.justchangedbouncenumber == 0 //if he hasnt left the ground yet
				and not (P_PlayerInPain(sonic.player)) //not hurt are you?
					sonic.player.justchangedbouncenumber = 1 //now he has!
					sonic.player.bouncenumber = 3 //set it back to zero
					sonic.player.pflags = $1|PF_JUMPED //forcing the player into a jumping state
					
					if player.powers[pw_super]
						P_SetObjectMomZ(sonic, FRACUNIT*20)
						P_Earthquake(sonic, sonic, FRACUNIT*256)
						S_StartSound(sonic, sfx_bbonce) //play a sound c:
					else
						P_SetObjectMomZ(sonic, FRACUNIT*16)
						S_StartSound(sonic, sfx_pacbnc)
					end
				end
				
				if sonic.player.bouncenumber == 3 //if it's currently on his second bounce
				and sonic.player.justchangedbouncenumber == 0 //if he hasnt left the ground yet
				and not (P_PlayerInPain(sonic.player)) //not hurt are you?
					sonic.player.justchangedbouncenumber = 1 //now he has!
					sonic.player.bouncenumber = 3 //set it back to zero
					sonic.player.pflags = $1|PF_JUMPED //forcing the player into a jumping state
					
					if player.powers[pw_super]
						P_SetObjectMomZ(sonic, FRACUNIT*20)
						P_Earthquake(sonic, sonic, FRACUNIT*256)
						S_StartSound(sonic, sfx_bbonce) //play a sound c:
					else
						P_SetObjectMomZ(sonic, FRACUNIT*16)
						S_StartSound(sonic, sfx_pacbnc)
					end
				end
								
				sonic.state = S_PLAY_GLIDE
				sonic.player.bounceattack = 0 //set it back to zero.
				sonic.player.usedown = 1 //set it to one.
				sonic.player.pflags = $1 & ~PF_THOKKED //uncheck the thokked flag, allowing you to bounce again.
			end
			//some quick checks
			
			if sonic.player.bounceattack == 1 //checking our variable.
			and sonic.health //and you're alive
			and not (P_PlayerInPain(sonic.player)) //not hurt are you?
				player.powers[pw_strong] = $|STR_FLOOR|STR_SPRING
				P_SpawnThokMobj(sonic.player) //spawn the players thok object
				if not (sonic.player.panim == PA_ROLL) //checking if the players animation is it's spinning anim.
					sonic.state = S_PLAY_ROLL //force the player into a spinning state.
				end
				/*if (sonic.momz > (9000*P_MobjFlip(sonic))) // the player is going up...?  
					P_SetObjectMomZ(sonic, 0) //not anymore >.>
				end*/
			else 
				sonic.player.bounceattack = 0 //set it to 0
				player.powers[pw_strong] = $ & ~STR_FLOOR
				player.powers[pw_strong] = $ & ~STR_SPRING
			end
			if sonic.player.bounceattack == 1 //checking if hes bouncing
				P_SetObjectMomZ(sonic, FRACUNIT*-3, true)
				sonic.player.pflags = $1 & ~PF_SPINNING // you're no longer "spinning" if you were before
			end
			if not (sonic.player.pflags & PF_JUMPED) // if you are not actuallly jumping
				sonic.player.bounceattack = 0 //set this back to zero to be safe
			end
			if sonic.eflags & MFE_GOOWATER //is the player in THZ goop?
			or sonic.player.powers[pw_carry] //is the player being carried?
			//or sonic.player.pflags & PF_ROPEHANG //is the player on a ACZ ropehang?
				sonic.player.bounceattack = 0 //set to zero!
			end
			if not (sonic.player.pflags & PF_JUMPED) //if the player hasnt jumped
				sonic.player.bounceattack = 0 //set this to zero
			end
		end
	end
end)
//Prevent AutoBraking from causing skidding
addHook("PreThinkFrame", do
	for player in players.iterate
		if player.mo and player.mo.skin == "pacman"
			if (player.pflags & PF_AUTOBRAKE)
			and P_GetPlayerControlDirection(player) == 0
			and not player.skidtime
				player.charflags = $|SF_NOSKID
			else
				player.charflags = $ & ~SF_NOSKID
			end
		end
	end
end)
//Revroll, Air hang, and other stuff
addHook("ThinkFrame", do
	for player in players.iterate
		if player.mo and player.mo.skin == "pacman"
			if player.playerstate == PST_DEAD
				P_SetObjectMomZ(player.mo, gravity)
			end
			if player.powers[pw_super]
			and not player.wassuper
				S_StartSound(player.mo, sfx_pmsupr)
			end
			player.wassuper = player.powers[pw_super]
			
			if not P_IsObjectOnGround(player.mo)
				player.thrustfactor = 25
			elseif P_IsObjectOnGround(player.mo)
			and (player.pflags & PF_SPINNING)
				player.thrustfactor = 50
			elseif P_IsObjectOnGround(player.mo)
				player.thrustfactor = skins[player.mo.skin].thrustfactor
			end
			if player.powers[pw_super]
				player.normalspeed = 40*FRACUNIT
				player.thrustfactor = $*2
			end
			
			if (player.bouncenumber < 3)
			and player.mo.state == S_PLAY_GLIDE
				player.mo.tics = UINT16_MAX
			elseif player.mo.state == S_PLAY_GLIDE
				player.mo.tics = 1
			end
			if player.mo.state == S_PLAY_ROLL
				player.mo.state = S_PLAY_ROLL
			end
			if player.StartRevRoll == nil
				player.StartRevRoll = 0
			end
			if player.revrollsound == nil
				player.revrollsound = 25
			end
			if player.revrollsound == 0
				player.revrollsound = 25
			end
			if P_IsObjectOnGround(player.mo)
			and player.playerstate == PST_LIVE
			and (player.bounceattack == 0)
			and (player.cmd.buttons & BT_SPIN)
			and not player.spindown
				if not player.wasrolling
					player.StartRevRoll = 1
					S_StartSound(player.mo, sfx_pcrev1)
				else
					player.pflags = $ & ~PF_SPINNING
					player.skidtime = 12
					player.mo.state = S_PLAY_SKID
					player.mo.sprite2 = (player.powers[pw_super]) and (SPR2_GRND|FF_SPR2SUPER) or SPR2_GRND
					player.mo.tics = 12
					S_StartSound(player.mo, sfx_skid)
				end
			end
			if player.StartRevRoll == 1
			and (player.cmd.buttons & BT_SPIN)
				player.pflags = $|PF_SPINNING|PF_STARTDASH
				if not (player.dashspeed)
					player.dashspeed = player.mindash
				end
				player.revrollsound = $ - 1
				if player.revrollsound == 0
					S_StopSound(player.mo)
					S_StartSound(player.mo, sfx_pcrev2)
				end
				if player.dashspeed < player.maxdash
					player.dashspeed = $+FRACUNIT
				end
				player.mo.state = S_PLAY_SPINDASH
			elseif player.StartRevRoll == 1
			and not	(player.cmd.buttons & BT_SPIN)
				if (player.dashspeed)
					S_StopSound(player.mo)
					if not player.powers[pw_super]
						P_InstaThrust(player.mo, player.mo.angle, player.dashspeed)
					else
						P_InstaThrust(player.mo, player.mo.angle, player.dashspeed)
					end
					S_StartSound(player.mo, sfx_zoom)
					player.pflags = $|PF_SPINNING & ~PF_STARTDASH
					player.mo.state = S_PLAY_ROLL
					player.dashspeed = 0
					player.StartRevRoll = 0
				end
			end
			if player.StartRevRoll == 1
			and (player.cmd.buttons & BT_JUMP)
				if player.mo.state == S_PLAY_SPINDASH
					player.mo.state = S_PLAY_JUMP
				end
			end
			if player.StartRevRoll == 1
			and not P_IsObjectOnGround(player.mo)
				player.StartRevRoll = 0
				player.dashspeed = 0
				S_StopSound(player.mo)
			end
			if player.StartRevRoll == 0
				player.revrollsound = 25
			end
			
			if player.AirHang == nil
				player.AirHang = 0
			end
			if player.AirHangMomz == nil
				player.AirHangMomz = 10
			end
			if player.AirHangDirection == nil
				player.AirHangDirection = 0
			end
			if player.AirHangTimer == nil
				player.AirHangTimer = TICRATE
			end
			
			if player.AirHangDirection == 0
				player.AirHangMomz = $ - 1
			end
			if player.AirHangDirection == 1
				player.AirHangMomz = $ + 1
			end
			if player.AirHangMomz == 10
				player.AirHangDirection = 0
				player.AirHangMomz = $ - 1
			elseif player.AirHangMomz == -10
				player.AirHangDirection = 1
				player.AirHangMomz = $ + 1
			end
			if (player.pflags & PF_JUMPED)
			and (player.cmd.buttons & BT_SPIN)
			and not player.flipkick
			and (player.bounceattack == 0)
			and not (player.panim == PA_ETC)
				if (P_MobjFlip(player.mo) == 1 and player.mo.momz < 0)
				or (P_MobjFlip(player.mo) == -1 and player.mo.momz > 0)
					player.AirHang = 1
				end
			end
			if P_IsObjectOnGround(player.mo)
				player.AirHang = 0
				player.AirHangTimer = TICRATE
			end
			if player.AirHang == 1
			and (player.pflags & PF_JUMPED)
			and (player.cmd.buttons & BT_SPIN)
			and not player.flipkick
			and (player.bounceattack == 0)
			and player.AirHangTimer > 0
				if not player.powers[pw_super]
					player.AirHangTimer = $-1
					if player.mo.state != S_PACMAN_AIR_HANG
						player.mo.state = S_PACMAN_AIR_HANG
					end
					P_SetObjectMomZ(player.mo, player.AirHangMomz*FRACUNIT/4)
					if FixedHypot(player.mo.momx,player.mo.momy) > (player.normalspeed/4)
						P_Thrust(player.mo, R_PointToAngle2(0,0,player.mo.momx,player.mo.momy), -player.speed/10)
					end
					if player.AirHangTimer %10 == 0 
						S_StartSound(player.mo,	sfx_pcahng)
					end
				else
					if not (player.mo.state == S_PLAY_FLOAT or player.mo.state == S_PLAY_FLOAT_RUN)
					and not (player.panim == PA_ETC)
						player.mo.state = S_PLAY_FLOAT
					end
					P_SetObjectMomZ(player.mo, player.AirHangMomz*FRACUNIT/4)
				end
			elseif player.AirHang == 1
			and (player.AirHangTimer == 0 or not (player.cmd.buttons & BT_SPIN))
				player.AirHang = 0
				player.mo.state = S_PLAY_FALL
				if not player.powers[pw_super]
					player.pflags = $ & ~PF_JUMPED
				end
			end
			player.spindown = player.cmd.buttons & BT_SPIN
			player.wasrolling = player.pflags & PF_SPINNING
		end
	end
end)

//Command to toggle health system (Thanks Icezer for the base!)
COM_AddCommand("pachealth", function(player, arg)
	if arg
		if arg == "1" or arg == "true" or arg == "on"
			if io and player == consoleplayer
				local file = io.openlocal("client/pacman/health.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.pachealth = true
			CONS_Printf(player, "Pacman will now use a health system.")
		elseif arg == "0" or arg == "false" or arg == "off"
			if io and player == consoleplayer
				local file = io.openlocal("client/pacman/health.dat", "w+")
				file:write(arg)
				file:close()
			end	
			player.pachealth = false
			CONS_Printf(player, "Pacman will now use rings as protection")
		elseif player.pachealth
			CONS_Printf(player, "pachealth [on/off] - Toggles Pacman's health system. Currently on.")
		else
			CONS_Printf(player, "pachealth [on/off] - Toggles Pacman's health system. Currently off.")
		end
	elseif player.pachealth
		CONS_Printf(player, "pachealth [on/off] - Toggles Pacman's health system. Currently on.")
	else
		CONS_Printf(player, "pachealth [on/off] - Toggles Pacman's health system. Currently off.")
	end
end, 0)

addHook("PlayerSpawn", function(p)
	if p.mo and p.mo.skin == "pacman"
		p.bounceattack = nil
		p.flipkick = nil
	end
	if io and p == consoleplayer and p.pachealth == nil
		local file = io.openlocal("client/pacman/health.dat")
		if file
			local string = file:read("*a")
			if string == "1" or string == "true" or string == "on"
				COM_BufInsertText(p, "pachealth on")
			elseif string == "0" or string == "false" or string == "off" or string == nil
				COM_BufInsertText(p, "pachealth off")
			end
			file:close()
		end
	end
end)


/*
This script adds a basic health system to the player object.
Health is replenished by destroying ring monitors.
Tails Guy lua made this easier!
*/

local function calculate_hp_stat(player)
	if (player.pachealth == true)
		if not(player.mo)
			return(nil)
		elseif(player.powers[pw_carry] == CR_NIGHTSMODE)
			return(nil)
		elseif(player.mo.skin == "pacman")
			return(4)
		end
	end
end

//Initiate variables
addHook("MapLoad", function()
	for player in players.iterate do
		if player.mo and player.mo.skin == "pacman"
			player.bounceattack = nil
			player.flipkick = nil
			if (player.pachealth == true)
				player.hp_max = calculate_hp_stat(player)
				player.hp = player.hp_max
				player.hp_up = nil
			end
		end
	end
end, MT_PLAYER)

addHook("ThinkFrame", function()
	for player in players.iterate do
		if (player.pachealth == true)
			//Calculate Max HP
			if(player.mo)
				player.hp_max = calculate_hp_stat(player)
			end
			//Correct the HP value
			if(player.hp_max)
				if(player.hp == nil) or(player.hp == 0 and player.mo and player.mo.health > 0)
					player.hp = player.hp_max
				elseif not(player.mo) or(player.mo.health == 0)
					player.hp = 0
				else
					player.hp = min($,player.hp_max)
				end
			else
				player.hp_max = nil
				player.hp = nil
			end
			//Handle health-ups
			if player.hp_up == nil
				player.hp_up = 0
			end
			if player.hp_up2 == nil
				player.hp_up2 = 0
			end
			if player.hp_up2 > 0
				player.hp_up2 = $ - 1
			end
			if player.hp_up3 == nil
				player.hp_up3 = 0
			end
			if player.hp_up3 > 0
				player.hp_up3 = $ - 1
			end
			if player.hp_up >= 10
				if player.hp != player.hp_max
					S_StartSound(player.mo, sfx_pcheal)
					player.hp_up2 = 10
				end
				player.hp_up = 0
				player.hp = min(player.hp_max,$+1)
			end
			if(player.healthprev != nil)
			and player.hp
			and(player.rings > player.healthprev)
				player.hp_up = $+(player.rings - player.healthprev)
			end
			player.healthprev = player.rings
		end
	end
end)

// Fake Damage
addHook("MobjDamage", function(mobj, source, attacker, notused)
	if(mobj.valid) and(mobj.player.hp) and not(mobj.player.powers[pw_super])
	and (mobj.player.pachealth == true)
		if(source)
			if(source.player)
				P_AddPlayerScore(source.player, 50)
			elseif(attacker and attacker.player)
				P_AddPlayerScore(attacker.player, 50)
			end
		end
		if(mobj.player.powers[pw_shield])	// Shield damage
			P_DoPlayerPain(mobj.player, attacker, source)	// Do knockback stuff
			S_StartSound(mobj, sfx_altow1)
			P_RemoveShield(mobj.player)
			P_PlayerFlagBurst(mobj.player)
		else
			// Inflict damage and remove items
			mobj.player.hp = $1 - 1
			mobj.player.hp_up2 = 10
			mobj.player.hp_up3 = 10
			P_PlayerEmeraldBurst(mobj.player)
			P_PlayerWeaponAmmoBurst(mobj.player)
			P_PlayerFlagBurst(mobj.player)
			if mobj.player.hp > 0 // Non-shield non-fatal damage=
				S_StartSound(mobj,sfx_altow1)
			mobj.player.powers[pw_flashing] = 50	// Set invuln flashing
			P_DoPlayerPain(mobj.player, attacker, source)	// Set knockback
			else
				mobj.health = 0
				mobj.player.health = 0
				P_KillMobj(mobj) //Non-shield fatal damage
				if(source)
					//Have some more points!
					if(source.player)
						P_AddPlayerScore(source.player, 50)
					elseif(attacker and attacker.player)
						P_AddPlayerScore(attacker.player, 50)
					end
				end
			end
		end
		mobj.player.hp_up = 0
		// -------------------------------------
		// We're done here!
		return true
	else
		return false
	end
end, MT_PLAYER)

//HUD
local function shieldHud(v, player, cam)
	if player.mo ~= nil
	and player.mo.skin == "pacman"
	and (player.pachealth == true)
		local xpos, ypos, flags, hpIconFlags, shieldOrbIconFlags, shieldDontDraw
		xpos = 10
		ypos = 50
		flags = V_SNAPTOTOP|V_SNAPTOLEFT
		hpIconFlags = flags
		shieldOrbIconFlags = flags
		shieldDontDraw = 0
		
		//we need some sort of splitscreen thing
		local height = v.height()
		if player.mo and splitscreen and player ~= players[1]
			ypos = ($/2) - 17
		end
		
		//Hijacking that cool intermission thing by MPC
		if rawget(_G, "G_MPCIntermission")		
			if (player.intermission.exitwait <= 226)
			or (player.exiting <= 20 and player.exiting ~= 0)
				flags = flags|player.transflag
				
				if player.transflag >= V_90TRANS
					shieldDontDraw = 1
				end
			else
				shieldDontDraw = 0
			end		
		elseif G_IsSpecialStage(gamemap)
			shieldDontDraw = 1
		else
			shieldDontDraw = 0
		end	
		
		if shieldDontDraw == 0	
			//Cheese wheel - sergal head
			local hpIcon
			local hpIcon2
			local hpIcon3
			local hpIcon4
			local hpIcon2Flags
			local hpIcon3Flags
			
			
			//Stops the v.draw from spitting out a warning when changing skins
			if hpIcon == nil
				hpIcon = v.cachePatch("NULLA0")
			end
			if hpIcon2 == nil
				hpIcon2 = v.cachePatch("NULLA0")
			end
			
//			hpIcon = v.cachePatch(tostring(skins[player.mo.skin].face))
			
			if player.mo.skin == "pacman"
				if player.hp == 4
					hpIcon = v.cachePatch("PAC4")
					hpIcon3 = v.cachePatch("PAC4")
					hpIcon4 = v.cachePatch("PAC4B")
				elseif player.hp == 3
					hpIcon = v.cachePatch("PAC3")
					hpIcon3 = v.cachePatch("PAC4")
					hpIcon4 = v.cachePatch("PAC3B")
				elseif player.hp == 2
					hpIcon = v.cachePatch("PAC2")
					hpIcon3 = v.cachePatch("PAC3")
					hpIcon4 = v.cachePatch("PAC2B")
				elseif (player.hp == 1) or (player.hp == 0)
					hpIcon = v.cachePatch("PAC1")
					hpIcon3 = v.cachePatch("PAC2")
					hpIcon4 = v.cachePatch("PAC1")
				end
				if player.hp_up
					if player.hp == 4
						hpIcon2 = v.cachePatch("PAC4")
					elseif player.hp == 3
						hpIcon2 = v.cachePatch("PAC4")
					elseif player.hp == 2
						hpIcon2 = v.cachePatch("PAC3")
					elseif (player.hp == 1) or (player.hp == 0)
						hpIcon2 = v.cachePatch("PAC2")
					end
				else
					hpIcon2 = hpIcon
				end				
			else // No cheese head if not PacMan
				hpIcon = v.cachePatch("NULLA0")
				hpIcon2 = v.cachePatch("NULLA0")
			end
			if player.hp_up2
				if player.hp_up2 == 1
					hpIcon3Flags = hpIconFlags | V_90TRANS
				elseif player.hp_up2 == 2
					hpIcon3Flags = hpIconFlags | V_80TRANS
				elseif player.hp_up2 == 3
					hpIcon3Flags = hpIconFlags | V_70TRANS
				elseif player.hp_up2 == 4
					hpIcon3Flags = hpIconFlags | V_60TRANS
				elseif player.hp_up2 == 5
					hpIcon3Flags = hpIconFlags | V_50TRANS
				elseif player.hp_up2 == 6
					hpIcon3Flags = hpIconFlags | V_40TRANS
				elseif player.hp_up2 == 7
					hpIcon3Flags = hpIconFlags | V_30TRANS
				elseif player.hp_up2 == 8
					hpIcon3Flags = hpIconFlags | V_20TRANS
				elseif player.hp_up2 == 9
					hpIcon3Flags = hpIconFlags | V_10TRANS
				elseif player.hp_up2
					hpIcon3Flags = hpIconFlags
				end
			end
			if player.hp_up == 1
				hpIcon2Flags = hpIconFlags | V_90TRANS
			elseif player.hp_up == 2
				hpIcon2Flags = hpIconFlags | V_80TRANS
			elseif player.hp_up == 3
				hpIcon2Flags = hpIconFlags | V_70TRANS
			elseif player.hp_up == 4
				hpIcon2Flags = hpIconFlags | V_60TRANS
			elseif player.hp_up == 5
				hpIcon2Flags = hpIconFlags | V_50TRANS
			elseif player.hp_up == 6
				hpIcon2Flags = hpIconFlags | V_40TRANS
			elseif player.hp_up == 7
				hpIcon2Flags = hpIconFlags | V_30TRANS
			elseif player.hp_up == 8
				hpIcon2Flags = hpIconFlags | V_20TRANS
			elseif player.hp_up == 9
				hpIcon2Flags = hpIconFlags | V_10TRANS
			else
				hpIcon2Flags = hpIconFlags
			end
			if player.mo.skin ~= "pacman"
			and player.powers[pw_super]
				hpIcon = v.cachePatch("NULLA0")
			end
			
			//HP Flashing
			v.drawScaled((xpos + 6)*FRACUNIT, (ypos + 8)*FRACUNIT, FRACUNIT/2, hpIcon, hpIconFlags, v.getColormap(player.mo.skin, player.mo.color))
			v.drawScaled((xpos + 6)*FRACUNIT, (ypos + 8)*FRACUNIT, FRACUNIT/2, hpIcon2, hpIcon2Flags, v.getColormap(player.mo.skin, player.mo.color))
			if player.hp_up2
				if player.hp_up3
					v.drawScaled((xpos + 6)*FRACUNIT, (ypos + 8)*FRACUNIT, FRACUNIT/2, hpIcon3, hpIcon3Flags, v.getColormap(player.mo.skin, player.mo.color))
				else
					v.drawScaled((xpos + 6)*FRACUNIT, (ypos + 8)*FRACUNIT, FRACUNIT/2, hpIcon4, hpIcon3Flags, v.getColormap(player.mo.skin, SKINCOLOR_SUPERSILVER1))
				end
			end
			v.drawNum(xpos +30, ypos + 11, player.hp, V_SNAPTOTOP|V_SNAPTOLEFT)
		end	
	end
end
hud.add(shieldHud, player)


//Ledge Grab code provided by SMS Alfredo!

local function inputangle(player)
	if P_GetPlayerControlDirection(player) == 0
	or player.mo.flags2 & MF2_TWOD or twodlevel
		return player.drawangle
	else 
		return player.cmd.angleturn<<16 + R_PointToAngle2(0, 0, player.cmd.forwardmove*FRACUNIT, -player.cmd.sidemove*FRACUNIT)
	end
end
addHook("MobjMoveBlocked", function(mo, mobj, collideline)
	if not (mo and mo.player and mo.skin == "pacman") then return end
	local player = mo.player
		
	//Ledge Grabbing (Yes this is a Mario copy-paste job, but I can use my own code how I want!)
	if not P_IsObjectOnGround(mo) and not player.powers[pw_carry]
	and (player.cmd.forwardmove or player.cmd.sidemove) and not player.climbing
	and ( (player.pflags&PF_STARTJUMP and mo.momz*P_MobjFlip(mo) <= 0)
	or (not (player.pflags&PF_STARTJUMP) and mo.momz*P_MobjFlip(mo) <= -4*P_GetMobjGravity(mo)))
	and not (player.pflags & (PF_JUMPSTASIS|PF_SPINNING))
		local prevline = player.lastlinehit
		local prevside = player.lastsidehit
		
		player.lastlinehit = -1
		player.lastsidehit = -1
		
		P_SlideMove(mo)
		player.powers[pw_pushing] = 3
		
		local line = lines[player.lastlinehit]
		if not line and collideline
			line = collideline
			player.lastlinehit = #line
			player.lastsidehit = line.sidenum[P_PointOnLineSide(mo.x, mo.y, line)]
		end
		local side = sides[player.lastsidehit]
		if line and line.valid and side and side.valid
			local pointx, pointy = P_ClosestPointOnLine(mo.x, mo.y, line)
			local angle = R_PointToAngle2(mo.x, mo.y, pointx, pointy)
			
			local diff = inputangle(player) - angle
			diff = InvAngle(InvAngle($))
			
			if abs(diff) < ANGLE_90
			and not (line and line.backsector
			and line.backsector.ceilingpic == "F_SKY1"
			and line.frontsector
			and line.frontsector.ceilingpic == "F_SKY1"
			and (mo.z >= line.frontsector.ceilingheight
			or mo.z >= line.backsector.ceilingheight))
			and line.special != 41
				//Can we ledge grab?
				local grabbable = false
				
				//Get the side we're NOT on
				local grabside = side
				if line.frontside == side
					grabside = line.backside
				else
					grabside = line.frontside
				end
				
				//Get the sector we're grabbing onto...
				local sector = grabside and grabside.valid and grabside.sector
				if sector and sector.valid
				and sector.ceilingheight - sector.floorheight >= mo.height
				//and not (GetSecSpecial(sector.special, 1) and GetSecSpecial(sector.special, 1) <= 8)
					local thok = P_SpawnMobjFromMobj(mo,0,0,FixedDiv(mo.height, mo.scale)/2,MT_THOK)
					if thok and thok.valid
						thok.flags = $ &~ MF_NOCLIP &~ MF_NOCLIPTHING &~ MF_NOCLIPHEIGHT
						thok.tics = 1
						P_SetOrigin(thok, thok.x + P_ReturnThrustX(nil, angle, mo.scale),
						thok.y + P_ReturnThrustY(nil, angle, mo.scale), thok.z)
						
						local floor = thok.floorz
						local ceiling = thok.ceilingz
						
						//Are we in grab range?
						if ceiling - floor < mo.height
							grabbable = false
						elseif mo.eflags & MFE_VERTICALFLIP
							if mo.z - mo.height/2 < ceiling
							and mo.z + mo.height > ceiling
							and mo.z + mo.height < mo.ceilingz - mo.height*2/3
							and mo.z - mo.height > mo.floorz
							and not sector.c_slope
								mo.z = ceiling
								grabbable = true
							end
						elseif mo.z < floor
						and mo.z + mo.height*3/2 > floor
						and mo.z > mo.floorz + mo.height*2/3
						and mo.z + mo.height*2 < mo.ceilingz
						and not sector.f_slope
							mo.z = floor - mo.height
							grabbable = true
						end
						
						//Set mo.angle without changing the player's camera
						if grabbable
							local target = mo.target
							mo.target = thok
							A_FaceTarget(mo)
							mo.target = target
						end
					end
				end
				
				//Refresh
				player.glidetime = 0
				
				//Ledge Grab
				if grabbable
					player.drawangle = angle
					player.climbing = 5
					player.mo.state = S_PLAY_CLING
					
					player.charability = CA_GLIDEANDCLIMB
					player.camerascale = skins[player.skin].camerascale/2
					player.pflags = $|PF_FULLSTASIS
					
					A_ForceStop(mo)
					S_StartSound(mo, sfx_s3k4a)
					
				//Wall Slide
				else
					player.lastlinehit = prevline
					player.lastsidehit = prevside
				end
			end
		else
			player.lastlinehit = prevline
			player.lastsidehit = prevside
		end
		return true
	end
end, MT_PLAYER)


addHook("JumpSpecial", function(player)
	if player.mo and player.mo.valid and player.mo.skin == "pacman"
//Ledge grab jump
		if player.climbing
			player.climbing = 0
			player.charability = skins[player.skin].ability
			player.camerascale = skins[player.skin].camerascale
			
			//We're gonna do what's called a pro gamer move
			player.pflags = $ &~ PF_JUMPED
			player.mo.state = S_PLAY_SPRING
			player.panim = PA_DASH
			player.powers[pw_nocontrol] = player.mo.tics
			
			local ghost = P_SpawnGhostMobj(player.mo)
			player.mo.z = $ + player.mo.height*P_MobjFlip(player.mo)/2
			P_TryMove(player.mo, player.mo.x + P_ReturnThrustX(nil, player.mo.angle, player.mo.radius),
			player.mo.y + P_ReturnThrustY(nil, player.mo.angle, player.mo.radius), true)
			
			S_StartSound(player.mo, sfx_pacdbj)
			return true
		end
	end
end)

addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid and player.mo.skin == "pacman"
		if player.climbing and player.mo.health
			player.charability = CA_GLIDEANDCLIMB
			player.camerascale = skins[player.skin].camerascale/2
			player.glidetime = max($, 2)
			
			player.pflags = $ | PF_STASIS
			if player.climbing != 1
				player.pflags = $ | PF_JUMPSTASIS
			end
		elseif player.charability == CA_GLIDEANDCLIMB
			player.charability = skins[player.skin].ability
			player.camerascale = skins[player.skin].camerascale
		end
	end
end)