//reversi v5
//product of pastel

if (VERSION == 202) and (SUBVERSION < 14)
	local function blackout(v)
		v.drawFill()
		v.drawString(160, 100, ("this mod requires version 2.2.14 or higher"),V_REDMAP, "center")
	end
	hud.add(blackout, "title")
	hud.add(blackout, "game")
	error("Your copy of 2.2 is obsolete and not compatible with this mod. Please update to version 2.2.14 or higher.", 0)
end

if rphys then
	local function blackout(v)
		v.drawFill()
		v.drawString(160, 100, ("wrong exe"),V_REDMAP, "center")
	end
	hud.add(blackout, "title")
	hud.add(blackout, "game")
	error("This file cannot be used with the reveries exe.", 0)
end

rawset(_G, "rphys", 31)

//soc

local function SafeFreeslot(...)
	for _, item in ipairs({...})
		if rawget(_G, item) == nil
			freeslot(item)
		end
	end
end

SafeFreeslot(
	"SKINCOLOR_SUPERMAGENTA1",
	"SKINCOLOR_SUPERMAGENTA2",
	"SKINCOLOR_SUPERMAGENTA3",
	"SKINCOLOR_SUPERMAGENTA4",
	"SKINCOLOR_SUPERMAGENTA5",
	"S_REVI_AIRFIRE")
	
skincolors[SKINCOLOR_SUPERMAGENTA1] = {
    name = "Super Magenta 1",
    ramp = {0,0,0,0,0,0,0,0,0,0,200,200,176,176,177,178},
    accessible = false}

skincolors[SKINCOLOR_SUPERMAGENTA2] = {
    name = "Super Magenta 2",
    ramp = {0,200,176,176,177,177,178,178,179,179,179,179,180,180,181,181},
    accessible = false}

skincolors[SKINCOLOR_SUPERMAGENTA3] = {
    name = "Super Magenta 3",
    ramp = {176,176,177,177,178,178,179,179,179,179,180,180,181,181,182,182},
    accessible = false}

skincolors[SKINCOLOR_SUPERMAGENTA4] = {
    name = "Super Magenta 4",
    ramp = {177,178,178,179,179,179,179,180,180,181,181,182,182,183,184,185},
    accessible = false}

skincolors[SKINCOLOR_SUPERMAGENTA5] = {
    name = "Super Magenta 5",
    ramp = {178,178,179,179,179,179,180,180,181,181,182,182,183,184,185,186},
    accessible = false}

sfxinfo[sfx_mswing].caption = "Whirl"
sfxinfo[sfx_shield].caption = "Shield"
sfxinfo[sfx_cdfm35].caption = "/"
sfxinfo[sfx_s3k71].caption = "Thorn Shield"
sfxinfo[sfx_s3ka1].caption = "Droning"
sfxinfo[sfx_s3ka2].caption = "Thrust"
sfxinfo[sfx_s3kb6].caption = "Air dash"
sfxinfo[sfx_s3kcfs].caption = "Elemental rise"
sfxinfo[sfx_kc40].caption = "Jet"
sfxinfo[sfx_kc5b].caption = "Comet dash"
sfxinfo[sfx_kc65].caption = "/"

states[S_PLAY_PAIN] = {SPR_PLAY, SPR2_PAIN, 70, NULL, 0,  0, S_PLAY_FALL}
states[S_PLAY_STUN] = {SPR_PLAY, SPR2_STUN, 70, NULL, 0,  0, S_PLAY_FALL}
states[S_PLAY_FIRE_FINISH] = {SPR_PLAY, SPR2_FIRE, 5, NULL, S_PLAY_STND, 0, S_PLAY_STND}
states[S_PLAY_GLIDE_LANDING] = {SPR_PLAY, SPR2_LAND, 7, NULL, 0,  0, S_PLAY_STND}
states[S_REVI_AIRFIRE] = {SPR_PLAY, SPR2_MLEE, 7, NULL, S_REVI_AIRFIRE, 0, S_PLAY_FALL}

function P_SetObjectMomZ(mo, value, relative)
	if (mo.eflags & MFE_VERTICALFLIP)
		value = -value
	end
	value = FixedMul(value, mo.scale)
	if (relative == true)
		mo.momz = $+value
	else
		mo.momz = value	
	end
	if (mo.standingslope) and (mo.player) and not (mo.standingslope.flags & SL_NOPHYSICS) and ((mo.standingslope.normal.x != 0) or (mo.standingslope.normal.y != 0))
	and (mo.state != S_PLAY_BOUNCE_LANDING) and not P_PlayerInPain(mo.player) and not mo.player.powers[pw_tailsfly] and not (mo.reverieslaunch)
		mo.momz = $*3/4
		mo.reverieslaunch = true
	end
end

function A_ZThrust(actor, var1, var2)
	if (var2 & 65535)
		actor.momy = 0
		actor.momx = 0
	end
	P_SetObjectMomZ(actor, var1<<FRACBITS, !(var2>>FRACBITS))
end

//tables

local FRACUNIT = FRACUNIT
local FRACBITS = FRACBITS
local TICRATE = TICRATE
local greaseremover

local blacklist = {}
blacklist["sage"] = true
blacklist["heavy"] = true
blacklist["eggrobo"] = true
blacklist["modernsonic"] = true
blacklist["kiryu"] = true
blacklist["bowser"] = true
blacklist["elfilin"] = true
blacklist["xsonic"] = true
blacklist["s3sonic"] = true

local marios = {}
marios["mario"] = true
marios["luigi"] = true

local norollcontrol = {}
norollcontrol["blaze"] = true
norollcontrol["adventuresonic"] = true

if not solchars
    rawset(_G, "solchars", {})
end

//functions

local function isplayer(mo)
	if mo.player.revi
		return true
	else
		return false
	end
end

local function zpos(position, item)
	return (position.z + (position.height - FixedMul(mobjinfo[item].height, position.scale))/2)
end

local function fangfire(player)
	local pmo = player.mo
	if (player.panim != PA_ABILITY2) and not (player.pflags & PF_SPINDOWN) and not (player.pflags & PF_BOUNCING)
	and not ((player.pflags & PF_JUMPED) and not (player.pflags & PF_NOJUMPDAMAGE)) and (pmo.state != S_REVI_AIRFIRE) and (player.panim != PA_PAIN) and not player.powers[pw_carry]
		if P_IsObjectOnGround(pmo)
			pmo.state = S_PLAY_FIRE
		else
			pmo.state = S_REVI_AIRFIRE
		end
		local lockon = P_LookForEnemies(player, false, true)
		local cork = nil
		player.weapondelay = 24
		player.pflags = $ & ~PF_SPINNING
		P_Thrust(pmo, R_PointToAngle2(0, 0, player.rmomx, player.rmomy), -(FixedHypot(player.rmomx, player.rmomy))/4)
		if (lockon and lockon.valid)
			pmo.angle = R_PointToAngle2(pmo.x, pmo.y, lockon.x, lockon.y)
			cork = P_SpawnPointMissile(pmo, lockon.x, lockon.y, zpos(lockon, player.revitem), player.revitem, pmo.x, pmo.y, zpos(pmo, player.revitem))
		else
			cork = P_SpawnPointMissile(pmo, pmo.x+P_ReturnThrustX(nil, pmo.angle, FRACUNIT), pmo.y+P_ReturnThrustY(nil, pmo.angle, FRACUNIT), zpos(pmo, player.revitem), player.revitem, pmo.x, pmo.y, zpos(pmo, player.revitem))
			if (cork and cork.valid)
				cork.flags = $ & ~MF_NOGRAVITY
				cork.momx = $/2
				cork.momy = $/2
			end
			player.drawangle = pmo.angle
		end
	end
end

local function stupidbouncesectors(mobj, sector)
	for fof in sector.ffloors()
		if not (fof.fofflags & FOF_BOUNCY) and (GetSecSpecial(fof.master.frontsector.special, 1) != 15)
			continue
		end
		if not (fof.fofflags & FOF_EXISTS)
			continue
		end
		if (mobj.z+mobj.height+mobj.momz < fof.bottomheight) or (mobj.z-mobj.momz > fof.topheight)
			continue
		end
		return true
	end
end

local function revireset(player)
	player.revi.fall = false
	player.revi.speed = 0
end

//main
			
addHook("PlayerSpawn", function(player)
	if (player.revi)
		revireset(player)
	end
end)

addHook("PlayerThink", function(player)
	if not (player.revi)
		local revi = {
		fall = false,
		spring = 0,
		y = 0,
		x = 0,
		z = 0,
		speed = 0,
		glide = false}
		player.revi = revi
	end
	local pmo = player.mo
	if (player.playerstate != PST_LIVE) or not (pmo)
		return
	end
	if not player.powers[pw_carry]
		player.speed = FixedHypot(player.rmomx, player.rmomy)
	end
	if blacklist[pmo.skin]
		return
	end
	player.thrustfactor = 3
	if (pmo.eflags & MFE_SPRUNG) or P_PlayerInPain(player) or player.powers[pw_carry]
		revireset(player)
	end
	if (player.powers[pw_justlaunched]) and not P_PlayerInPain(player) and not player.powers[pw_tailsfly]
		if (player.powers[pw_justlaunched] == 1)
			if (pmo.reverieslaunch)
				pmo.momz = $*4/3
				pmo.reverieslaunch = false
				player.powers[pw_justlaunched] = 0
			else
				pmo.momz = $*2
				player.powers[pw_justlaunched] = 0
			end
		else
			pmo.momz = $*6/5
			pmo.reverieslaunch = false
			player.powers[pw_justlaunched] = 0
		end
	end
	if (P_MobjFlip(pmo)*pmo.momz > FixedMul(5<<FRACBITS, pmo.scale)) and not P_IsObjectOnGround(pmo) and not (player.secondjump)
		player.revi.fall = true
	end
	if (player.revi.fall) and (P_MobjFlip(pmo)*pmo.momz < 0) and ((player.panim == PA_WALK) or (player.panim == PA_RUN) or (player.panim == PA_DASH)) and not (player.pflags & (PF_JUMPED|PF_THOKKED))and not player.powers[pw_carry]
		pmo.state = S_PLAY_FALL
	end
	if (player.revi.spring)
		if (player.revi.spring == 1) and (P_MobjFlip(pmo)*pmo.momz < 0)
			player.revi.spring = 0
		end
		if (player.revi.spring == 2) and (player.panim != PA_ABILITY) and (player.panim != PA_ABILITY2) and (player.panim != PA_ETC)
			player.revi.spring = 0
		end
		if P_IsObjectOnGround(pmo) or P_PlayerInPain(player)
			player.revi.spring = 0
		end
	end
	if (pmo.eflags & MFE_SPRUNG) or (player.powers[pw_carry] == CR_MACESPIN) or (player.powers[pw_carry] == CR_GENERIC)
		if (P_MobjFlip(pmo)*pmo.momz > 0)
			player.revi.spring = 1
		else
			player.revi.spring = 3
		end
	end
	if (player.powers[pw_carry] == CR_DUSTDEVIL)
		player.revi.spring = 3
	end
	if stupidbouncesectors(pmo, pmo.subsector.sector) and not (player.revi.spring)
		player.revi.spring = 1
	end
	if not (P_IsObjectOnGround(pmo)) and not player.powers[pw_carry]
		if not (player.revi.spring)
			pmo.momz = $+FixedMul(P_GetMobjGravity(pmo), (abs(FixedSqrt(abs(pmo.momz))/10)))
		end
		if (pmo.standingslope) and not (pmo.standingslope.flags & SL_NOPHYSICS) and ((pmo.standingslope.normal.x != 0) or (pmo.standingslope.normal.y != 0)) and (pmo.state != S_PLAY_BOUNCE_LANDING) and not P_PlayerInPain(player) and not player.powers[pw_tailsfly]
			pmo.momz = $*3/4
			pmo.reverieslaunch = true
		end
	end
	if (player.charability == CA_FLY) and not (player.chrispy)
		if (player.fly1) and (player.panim != PA_ABILITY)
			player.fly1 = 0
		end
		if (pmo.state == S_PLAY_FLY_TIRED)
			pmo.momz = $+(P_GetMobjGravity(pmo)/2)
		end
		if (player.powers[pw_tailsfly])
			if (player.cmd.buttons & BT_JUMP) //holdfly for tails
				if (player.fly1)
					player.fly1 = max($, 3)
				else
					player.fly1 = 12
				end
			end
			local flycap = FixedMul(player.normalspeed-(2<<FRACBITS), pmo.scale)
			if (player.powers[pw_super] or player.powers[pw_sneakers])
				flycap = $*5/3
			end
			if (pmo.eflags & MFE_UNDERWATER)
				flycap = $>>1
			end
			if (player.fly1) and (player.speed > flycap)
				pmo.momy = pmo.momy*49/50
				pmo.momx = pmo.momx*49/50
			elseif (player.cmd.sidemove) or (player.cmd.forwardmove)
				if (twodlevel or (pmo.flags2 & MF2_TWOD))
					 if (player.cmd.sidemove) and (player.speed < flycap)
						P_Thrust(pmo, player.drawangle, FixedMul(FRACUNIT>>1, pmo.scale))
					end
				elseif (player.speed < flycap)
					P_Thrust(pmo, (player.cmd.angleturn<<16 + R_PointToAngle2(0, 0, player.cmd.forwardmove*FRACUNIT, -player.cmd.sidemove*FRACUNIT)), FixedMul(FRACUNIT>>1, pmo.scale))
				end
			end
		end
	end
	if (pmo.eflags & MFE_JUSTHITFLOOR) and not P_CheckDeathPitCollide(pmo)
		revireset(player)
	end
	if (player.charability == CA_BOUNCE)
		if (player.pflags & PF_BOUNCING)
			if (pmo.state == S_PLAY_BOUNCE_LANDING)
				P_SetObjectMomZ(pmo, FRACUNIT>>2, true)
			else
				pmo.movefactor = 37*FRACUNIT/20
			end
			player.normalspeed = skins[player.skin].normalspeed
			player.oldnormalspeed = player.normalspeed
			player.revi.x = pmo.momx
			player.revi.y = pmo.momy
			player.revi.z = pmo.momz
			player.revi.speed = 1
		elseif (player.revi.speed == 1) and not P_PlayerInPain(player) and not player.powers[pw_carry]
			pmo.momx = player.revi.x
			pmo.momy = player.revi.y
			pmo.momz = player.revi.z
			player.revi.speed = 0
		end
		if (pmo.skin == "fang")
			if (pmo.state == S_PLAY_FIRE) or (pmo.state == S_REVI_AIRFIRE)
				player.pflags = $|PF_FULLSTASIS
				pmo.friction = FRACUNIT
			end
			if ((player.pflags & PF_NOJUMPDAMAGE) or (P_IsObjectOnGround(pmo))) and not P_PlayerInPain(player) and not (player.powers[pw_carry]) and not (player.pflags & PF_SPINNING) and not (player.pflags & PF_BOUNCING)
				local stuckonyou = P_LookForEnemies(player, false, true)
				if (stuckonyou and stuckonyou.valid)
					P_SpawnLockOn(player, stuckonyou, S_LOCKON3)
				end
			end
			if (player.panim == PA_ABILITY2) and (player.speed > FixedMul(player.runspeed/2, pmo.scale)) and player.weapondelay%3 == 1
				S_StartSound(pmo, sfx_s3k7e, player)
				local r = pmo.radius/FRACUNIT
				P_SpawnMobjFromMobj(pmo, P_RandomRange(-r,r)<<FRACBITS, P_RandomRange(-r,r)<<FRACBITS, 0, MT_DUST)
			end
			if (pmo.state == S_REVI_AIRFIRE)
				if player.weapondelay > 21
					pmo.frame = 0
				else
					pmo.frame = 1
				end
			end
		end
	end
	if (pmo.skin == "knuckles") and not P_PlayerInPain(player)
		if (player.revi.glide) and ((player.pflags & PF_STARTJUMP) or (pmo.eflags & MFE_APPLYPMOMZ))
			player.revi.glide = false
		end
		if (player.pflags & PF_THOKKED) and (pmo.state == S_PLAY_FALL) and not (player.pflags & PF_SHIELDABILITY)
			player.revi.x = player.rmomx
			player.revi.y = player.rmomy
			player.revi.glide = true
			if (player.speed > FixedMul(player.actionspd, pmo.scale))
				pmo.momy = $*47/50
				pmo.momx = $*47/50
			end
		end
		if (player.pflags & PF_GLIDING) and P_IsObjectOnGround(pmo)
			player.revi.x = player.rmomx
			player.revi.y = player.rmomy
			player.revi.glide = true
		end
		if (pmo.state == S_PLAY_GLIDE_LANDING) and not (pmo.eflags & MFE_JUSTHITFLOOR) and (player.revi.glide) and not (pmo.eflags & MFE_APPLYPMOMZ)
			pmo.momx = player.revi.x
			pmo.momy = player.revi.y
			player.revi.glide = false
		end
		if (pmo.state == S_PLAY_CLIMB)
			if (player.cmd.forwardmove != 0)
				pmo.momz = $*6/5
			end
			if (player.cmd.sidemove != 0)
				pmo.momy = $*7/5
				pmo.momx = $*7/5
			end
		end
	end
	if (player.deltaChars) and (pmo.state == S_KRIS_SLIDE)
		pmo.momx = $*58/59
		pmo.momy = $*58/59
	end
end)

//specials

addHook("AbilitySpecial", function(player)
	if (player.pflags & PF_THOKKED)
		return false
	end
	if (player.charability == CA_FLY)
		player.revi.spring = 0
		player.fly1 = 12
		return false
	end
	if (player.mo.skin == "knuckles")
		player.revi.spring = 0
		if player.powers[pw_super]
			player.actionspd = 35<<FRACBITS
		else
			player.actionspd = 25<<FRACBITS
		end
	end
	if (player.charability == CA_BOUNCE)
		if (player.pflags & PF_NOJUMPDAMAGE) and not (player.pflags & PF_SPINNING) and (player.mo.state != S_REVI_AIRFIRE)
			player.mo.state = S_PLAY_BOUNCE
			player.pflags = $|PF_BOUNCING|PF_NOJUMPDAMAGE|PF_THOKKED & ~PF_JUMPED
			player.powers[pw_strong] = STR_BOUNCE
		end
		return true
	end
end)

addHook("SpinSpecial", function(player)
	if ((player.cmd.buttons & BT_JUMP) and not (player.pflags & PF_JUMPDOWN))
		return true
	end
	if (player.mo.skin == "fang")
		fangfire(player)
		return true
	end
end)

addHook("JumpSpecial", function(player)
	local pmo = player.mo
	if ((pmo.eflags & MFE_JUSTHITFLOOR) or P_IsObjectOnGround(pmo)) and not (player.pflags & PF_JUMPDOWN) and not (player.pflags & PF_JUMPSTASIS)
		revireset(player)
		player.pflags = $ & ~PF_SPINNING
		if (player.speed)
			pmo.momx = FixedMul($, pmo.friction)
			pmo.momy = FixedMul($, pmo.friction)
		end
	end
end)

//momentum

local dashfracs = 52<<FRACBITS //hardcoded speed adjust threshold
local maxrunfracs = 57<<FRACBITS //actually 52

addHook("PostThinkFrame", do
	for player in players.iterate
		local pmo = player.mo
		if (player.revi) and (player.normalspeed) and (pmo) and (player.playerstate == PST_LIVE) then
			local current = pmo.skin
			if blacklist[current]
				continue
			end
			local skin = skins[player.skin]
			local water = 1+(pmo.eflags&MFE_UNDERWATER)/MFE_UNDERWATER
			local grounded = P_IsObjectOnGround(pmo)
			local flatzone = ((pmo.flags2 & MF2_TWOD) or (twodlevel))
			local nspd = (grounded) and skin.normalspeed+(4<<FRACBITS) or skin.normalspeed+(2<<FRACBITS)
			local rspd = skin.normalspeed
			local friction = FixedDiv(pmo.friction,FRACUNIT)
			local divspd = FixedDiv(player.speed, pmo.scale)
			local nodrag = false
			if player.powers[pw_super] then
				divspd = $*3/5
				rspd = $*17/20
			elseif player.powers[pw_sneakers] then
				divspd = $*3/5
			end
			if (player.mindash < 42<<FRACBITS) and (player.charability2 == CA2_SPINDASH)
				player.mindash = 42<<FRACBITS
			end
			if (player.jumpfactor)
				player.jumpfactor = skin.jumpfactor+(FRACUNIT*83/200)
			end
			if (pmo.eflags & MFE_JUSTHITFLOOR)
				nspd = FixedMul($, pmo.friction)
				nodrag = true
			end
			if (player.thrustfactor) and (player.acceleration)
				player.acceleration = (pmo.eflags & MFE_UNDERWATER) and 75 or 50
				player.thrustfactor = 3
				player.accelstart = 200
			end
			player.shieldscale = max(FRACUNIT*21/20, $)
			if solchars[current] and player.solchar
				if (player.solchar.istransformed)
					player.jumpfactor = $*4/3
					nspd = $*5/3
					rspd = nspd*7/10
				end
			end
			if marios[current]
				if (player.mariopspeed >= TICRATE/2)
					player.runspeed = 17<<FRACBITS
				elseif (player.mariosize > 0)
					player.runspeed = INT32_MAX/2
				else
					player.runspeed = skin.runspeed
				end
				if (current == "luigi")
					player.accelstart = 165
					player.acceleration = (pmo.eflags & MFE_UNDERWATER) and 57 or 38 
					nspd = (grounded) and skin.normalspeed+(3<<FRACBITS) or skin.normalspeed+(1<<FRACBITS)
				end
			else
				player.runspeed = min(rspd, maxrunfracs)
			end
			if (player.speed > FixedMul(dashfracs, pmo.scale))
				player.charflags = $|SF_RUNONWATER
			elseif (player.charflags & SF_RUNONWATER) and (player.speed < FixedMul(dashfracs, pmo.scale)) and not (skin.flags & SF_RUNONWATER)
				player.charflags = $ & ~SF_RUNONWATER
			end
			if (player.chrispy)
				if not greaseremover then
					ChrispyChars.Grease = function(player) end
					ChrispyChars.HasMomentumMod = function(player) end
					greaseremover = true
				end
				if (player.reveriesFshield)
					player.chrispy.flags = $ & ~CF_DROPDASHCHARGE
				end
				if (player.chrispy.fluffy) and (player.chrispy.fluffy.mode != 2) and (player.bot != BOT_2PAI) and not (player.revi.spring)
					player.oldnormalspeed = nspd
					player.normalspeed = grounded and rspd-(FRACUNIT) or rspd-(2<<FRACBITS)
					player.runspeed = maxrunfracs
				end
				if (pmo.state == S_POINTY_BOUNCE_LANDING)
					pmo.chrispybouncereveriesadjust = true
				elseif (pmo.chrispybouncereveriesadjust)
					player.revi.spring = 1
					pmo.chrispybouncereveriesadjust = false
				end
			elseif (player.charability == CA_FLY)
				if (player.powers[pw_tailsfly]) and (player.fly1)
					player.normalspeed = nspd*2/3
					player.oldnormalspeed = 0
				elseif (player.normalspeed < rspd)
					player.normalspeed = nspd
					player.oldnormalspeed = nspd
				end
			end
			if (current == "adventuresonic") and (player.yusonictable)
				nspd = grounded and rspd or rspd-(2<<FRACBITS)
				if player.powers[pw_super] then
					player.runspeed = 34<<FRACBITS
				else
					player.runspeed = rspd-(6<<FRACBITS)
				end
				player.jumpfactor = skin.jumpfactor+(FRACUNIT*43/200)
				if (player.YuRushMode)
					rspd = (nspd<<2)
				else
					player.yusonictable.runfriction = 0
				end
				if (player.yusonictable.bouncestate == 2)
					player.revi.spring = 1
				end
				if not grounded and not player.powers[pw_carry] then
					if (player.pflags & PF_SPINNING) and not (player.pflags & PF_THOKKED)
						pmo.movefactor = $*4
					end
				end
			end
			if (current == "ray") and (player.panim == PA_ABILITY)
				player.revi.spring = 2
				player.jumpfactor = FRACUNIT
				nodrag = true
			end
			if grounded and not (pmo.eflags & MFE_JUSTHITFLOOR)
				local sustain = FixedDiv(divspd*water, friction)
				if ((player.normalspeed == player.oldnormalspeed) or (player.normalspeed <= nspd) or (player.speed > player.normalspeed)) and (player.normalspeed >= rspd)
					player.normalspeed = (player.pflags & PF_SPINNING) and nspd or max(nspd, sustain)
					player.oldnormalspeed = player.normalspeed
				end
				if not (player.pflags & PF_STARTDASH) and not flatzone
					if (player.onconveyor == 4)
						P_Thrust(pmo, R_PointToAngle2(0, 0, player.cmomx, player.cmomy), FixedMul(FRACUNIT/4, pmo.scale))
					end
					if (pmo.standingslope) and (pmo.oldz) and not (player.pflags & PF_SPINNING) and not (pmo.standingslope.flags & SL_NOPHYSICS)
						if ((pmo.z < pmo.oldz) and not (pmo.eflags & MFE_VERTICALFLIP)) or ((pmo.z > pmo.oldz) and (pmo.eflags & MFE_VERTICALFLIP)) 
							P_Thrust(pmo, R_PointToAngle2(0, 0, player.rmomx, player.rmomy), FixedMul(FRACUNIT/3, pmo.scale))
						end
					end
					if (player.pflags & PF_SPINNING) and (player.speed < FixedMul(120<<FRACBITS, pmo.scale)) and not (player.pflags & PF_THOKKED)
						if (player.speed > FixedMul(15<<FRACBITS, pmo.scale))
							pmo.momy = $*201/200
							pmo.momx = $*201/200
						else
							pmo.momy = $*199/200
							pmo.momx = $*199/200
						end
					end
				end
				pmo.oldz = pmo.z
			elseif ((player.normalspeed == player.oldnormalspeed) or (player.normalspeed <= nspd)) and (player.normalspeed >= rspd)
				player.normalspeed = nspd
				player.oldnormalspeed = player.normalspeed
			end
			if (player.pflags & PF_GLIDING) and not grounded and not (pmo.eflags & MFE_JUSTHITFLOOR)
				if (player.speed < FixedMul(player.normalspeed, pmo.scale))
					P_Thrust(pmo, pmo.angle, player.speed/180)
				end
				nodrag = true
			end
			if (player.pflags & PF_SPINNING) and not norollcontrol[current] and not (player.pflags & PF_THOKKED) and not (player.powers[pw_justsprung]) and not (player.powers[pw_carry])
				if P_IsObjectOnGround(pmo) and not (player.pflags & PF_THOKKED)
					if (player.speed > FixedMul(120<<FRACBITS, pmo.scale))
						pmo.movefactor = FRACUNIT
					else
						pmo.movefactor = (player.speed > FixedMul(70<<FRACBITS, pmo.scale)) and FRACUNIT<<2 or FRACUNIT<<3
					end
				else
					player.pflags = $|PF_THOKKED
				end
			end
			if flatzone then
				if (pmo.flags2 & MF2_TWOD)
					player.normalspeed = $*2/3
					player.runspeed = $*2/3
				end
			elseif (player.cmd.forwardmove or player.cmd.sidemove) and not (grounded) and not (nodrag) and not ((player.pflags & PF_SPINNING) and not (player.pflags & PF_THOKKED))
			and not (player.powers[pw_tailsfly]) and not (player.pflags & PF_BOUNCING) and not (player.powers[pw_carry])
				local reduce = FixedMul(player.normalspeed-(7<<FRACBITS), pmo.scale)
				local draglimit = FixedMul(player.normalspeed, pmo.scale)
				if (player.powers[pw_super]) or (player.powers[pw_sneakers])
					reduce = $*5/3
					draglimit = $*5/3
				end
				if (pmo.eflags & MFE_UNDERWATER)
					reduce = $/2
					draglimit = $/2
				end
				if (P_GetPlayerControlDirection(player) != 2)
					pmo.movefactor = 21*FRACUNIT/10
				end
				if (player.speed < reduce)
					pmo.momy = $*39/40
					pmo.momx = $*39/40
				elseif (player.speed <= draglimit)
					pmo.momy = $*19/20
					pmo.momx = $*19/20
				end
			end
			if (player.botleader) and (player.bot == BOT_2PAI)
				player.normalspeed = player.botleader.normalspeed
			end
		end
	end
end)

//cork

addHook("MobjThinker", function(cork)
	if (cork.health) and pcall(isplayer, cork.target) and (cork.target.skin == "fang")
		if not (cork.fuse)
			cork.fuse = 30
		end
		if P_IsObjectOnGround(cork) or ((cork.momx == 0) and (cork.momy == 0) and (cork.momz == 0)) or (cork.target.eflags & MFE_SPRUNG) or (cork.target.player.powers[pw_carry]) or P_PlayerInPain(cork.target.player) or (cork.target.player.playerstate != PST_LIVE)
			pcall(P_RemoveMobj, cork)
			return
		end
		if P_IsObjectOnGround(cork.target)
			cork.target.state = S_PLAY_FIRE
		else
			cork.target.state = S_REVI_AIRFIRE
		end
		if cork.target.player.powers[pw_super]
			local corkstars = P_SpawnMobjFromMobj(cork, 0, 0, cork.height/2, MT_IVSP)
			corkstars.scale = $/2
			cork.supershot = true
		end
	end
end, MT_CORK)

addHook("MobjRemoved", function(cork)
	if (cork.target) and (cork.target.skin == "fang")
		if cork.supershot
			local corkspark = P_SpawnMobjFromMobj(cork, 0, 0, 0, MT_SUPERSPARK)
			corkspark.spritexscale = $*2
			corkspark.spriteyscale = $*2
			corkspark.spriteyoffset = -12<<FRACBITS
			P_Earthquake(cork, cork.target, 256<<FRACBITS)
		else
			local corkdust = P_SpawnMobjFromMobj(cork, 0, 0, 0, MT_SPINDUST)
			A_ZThrust(corkdust, 3, FRACUNIT)
		end
	end
end, MT_CORK)
