--now for the RTD "namespace"
local RTDFuncs = CDRTD.functions
local function cTrue(val)
	return (val and val ~= 0
	and val ~= "" and val ~= {})
end
local Nightmare = CV_RegisterVar({
		name = "rtd_nightmare",
		defaultvalue = "Off",
		flags = CV_NETVAR|CV_SHOWMODIF,
		PossibleValue = CV_OnOff
})
local TrueSuper = CV_RegisterVar({
		name = "rtd_truesuper",
		defaultvalue = "On",
		flags = CV_NETVAR|CV_SHOWMODIF,
		PossibleValue = CV_OnOff
})
RTDFuncs.AddHook("NetVars", function(net)
	CDRTD.SuperList = net($)
end)
local RTDWait = CV_RegisterVar({
	name = "rtd_wait",
	defaultvalue = 45,
	flags = CV_NETVAR|CV_SHOWMODIF,
	PossibleValue = {MIN = 0, MAX = 600}
})

local function TacticalNuke(s, m, i, t, e, d) -- size, mobj, intensity, time, elimination, dye
	--bomb him
	if not m.valid then return end
	P_NukeEnemies(m, m, s<<16)
	if m.player then
		local p = m.player
		if (p == displayplayer) then
			P_StartQuake(i<<16, t)
		end
		P_FlashPal(p, d, t)
	end
	if (e == true) then
		P_DamageMobj(m, nil, nil, 10000, DMG_INSTAKILL|DMG_CANHURTSELF)
	end
end
local function funcswitch(x, case)
	if not (case and #case) then return false end
	if not x or not case[x] then return case.default end
	return case[x]
end
local function isearch(tbl, val) 
	if not (tbl and #tbl) then return nil end
	for i,v in ipairs(tbl) do
		if v == val then return i end
	end
	return nil
end
local rtd ="\x82[\x81RTD\x82]\x80 "
local RTD_ShieldValList = {
	SH_PITY = 1,
	SH_WHIRLWIND = 2,
	SH_ARMAGEDDON = 3,
	SH_ATTRACT = SH_PITY|SH_PROTECTELECTRIC,
	SH_ELEMENTAL = SH_PITY|SH_PROTECTFIRE|SH_PROTECTWATER,
	SH_FLAMEAURA = SH_PITY|SH_PROTECTFIRE,
	SH_BUBBLEWRAP = SH_PITY|SH_PROTECTWATER,
	SH_THUNDERCOIN = SH_WHIRLWIND|SH_PROTECTELECTRIC,
	SH_FORCE = 256
}
local RTD_ItemsList = {
	"truesuper",
	"matchsuper",
	"invuln",
	"speed",
	"shields",
	"rings",
	"nothing",
	"selfnuke",
	"instadeath",
	"thousanddeaths"
}
local function getXSHRandom(n)
	return P_RandomKey(n) + 1
end
local weights = { 9, 36, 54, 81, 153, 207, 99, 72, 6, 1}
local cumulative = {}
local total = 0

for i = 1, #weights do
    total = $ + weights[i]
    cumulative[i] = total
end

local function weighted_roll()
    local r = getXSHRandom(total)
    for i = 1, #cumulative do
        if r <= cumulative[i] then
            return i
        end
    end
end
local RTD_ShieldList = {
	"force",
	"thundercoin",
	"attract",
	"bubblewrap",
	"flameaura",
	"armageddon",
	"whirlwind",
	"elemental",
	"pity"
}
local function isForced(bool)
	if bool then return " \x85[Forced]\x80" end
	return ""
end
local function instantCooldown(p)
	p.rtd.active = false
	p.rtd.timer = false
	p.rtd.wait = p.rtd._waittime
end
local function C_DoSuperTransform(p) -- p => player
	if (emeralds&127)~=127 then return end
	
	if (not (p.charflags & SF_SUPER)) then
		p.charflags = $|SF_SUPER
	end
	local sct
	local sc
	if not ((type(p.hyper) == "table") and cTrue(p.hyper.capable)) then
		if type(p.super) == "table" then
			sct = p.super
			sc = SuperControls
			if cTrue(sc.SFX[sct.sfx]) then
				S_StartSound(p.mo, sc.SFX[sct.sfx])
			end
		else
			S_StartSound(p.mo, sfx_supert)
		end
	end
	
	if type(sct) == "table" then
		sct.lock = true
	end

	p.powers[pw_super] = 1
	
	if (not (mapheaderinfo[gamemap].levelflags & LF_NOSSMUSIC)
	and P_IsLocalPlayer(p))
	and (type(sct) == "table" and sct.music == 1 or true) then
		if cTrue(p.supermusic) and p.supermusic ~= "DEFAULT" then
			if p.supermusic ~= "DISABLED" then
				P_PlayJingleMusic(p, p.supermusic, 0, true, JT_SUPER)
			end
		else
			P_PlayJingle(p, JT_SUPER)
		end
	end
	local zeroes = {0, 0, 0, 0, 0, 0, 0}
	p.mo.momx, p.mo.momy, p.mo.momz, p.cmomx, p.cmomy, p.rmomx, p.rmomy = unpack(zeroes)

	--// Transformation animation
	p.mo.state = S_PLAY_SUPER_TRANS1

	--// Just in case.
	if (not (mapheaderinfo[gamemap].levelflags & LF_NOSSMUSIC)) then
		p.powers[pw_extralife] = 0
		p.powers[pw_invulnerability] = 0
		p.powers[pw_sneakers] = 0
	end

	P_PlayerFlagBurst(p, false)
end
local function gameprint(s)
	if netgame then
		chatprint(rtd..s)
	else
		print(rtd..s)
	end
end
local function gameprintf(p, s)
	if netgame then
		chatprintf(p, rtd..s)
	else
		CONS_Printf(p, rtd..s)
	end
end
local RTD_ItemFuncs = {
	--truesuper
	[1] = function(p, f)
		local m = p.mo
		if not (skins[m.skin].flags & SF_SUPER) or G_CoopGametype() or not TrueSuper.value then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "matchsuper"), f)
		end
		if p.powers[pw_super] and p.rtd.active ~= "truesuper" then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "50", f)
		end
		gameprint(p.name.." rolled True Super. Run."..isForced(f or false)) -- the big one
		table.insert(CDRTD.SuperList, p.name)
		if (emeralds&127)~=127 then
			emeralds = 127
		end
		p.rtd.active = "truesuper"
		if P_IsObjectOnGround(m) then
			P_DoJump(p, true)
			P_SetOrigin(m, m.x, m.y, m.z + 32*FU)
		end
		P_StealPlayerScore(p, 50)
		p.rtd.timer = 30*TICRATE
		do
			local r = p.rings
			if r < 50 then
				p.rings = 50
			end
			C_DoSuperTransform(p)
		end
		return true
	end,
	--matchsuper
	[2] = function(p, f)
		local m = p.mo
		if p.powers[pw_super] or p.powers[pw_invulnerability] or p.powers[pw_sneakers] then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "50", f)
		end
		gameprint(p.name.." rolled Match Super."..isForced(f or false))
		p.rtd.active = "matchsuper"
		p.powers[pw_invulnerability] = 21*TICRATE
		p.powers[pw_sneakers] = 21*TICRATE
		P_PlayJingle(p, (maptol & TOL_MARIO) and JT_MINV or JT_INV)
		P_StealPlayerScore(p, 50)
		p.rtd.timer = 20*TICRATE
		return true
	end,
	--invuln
	[3] = function(p, f)
		local m = p.mo
		if p.powers[pw_super] then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "10", f)
		end
		gameprint(p.name.." rolled Invulnerability."..isForced(f or false))
		p.rtd.active = "invuln"
		p.powers[pw_invulnerability] = 21*TICRATE
		P_PlayJingle(p, (maptol & TOL_MARIO) and JT_MINV or JT_INV)
		p.rtd.timer = 20*TICRATE
		return true
	end,
	--speed
	[4] = function(p, f)
		local m = p.mo
		if p.powers[pw_super] then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "10", f)
		end
		gameprint(p.name.." rolled Speed Shoes."..isForced(f or false))
		p.rtd.active = "speed"
		p.powers[pw_sneakers] = 21*TICRATE
		P_PlayJingle(p, JT_SHOES)
		p.rtd.timer = 20*TICRATE
		return true
	end,
	--shields
	[5] = function(p, s, f)
		local m = p.mo
		local shield = s or RTD_ShieldList[getXSHRandom(#RTD_ShieldList)]
		if shield == nil then
			gameprintf(p, "Something went wrong with your shield, so you get 10 rings on us.")
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "10", f)
		end
		if p.powers[pw_shield] & ~SH_STACK then
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "rings"), "10", f)
		end
		local name
		for _,v in ipairs({"fl", "bu", "th"}) do
			if shield:sub(1,2) == v then
				name = shield:sub(1,1):upper()..shield:sub(2,-5)
				break
			end
		end
		name = $ or shield:sub(1,1):upper()..shield:sub(2)..(shield == "attract" and "ion" or "")
		gameprint(p.name.." rolled a \$name\ Shield."..isForced(f or false))
		P_SwitchShield(p, RTD_ShieldValList["SH_"..shield:upper()])
		if shield == "force" then p.powers[pw_shield] = $+(getXSHRandom(3)) end
		instantCooldown(p)
		return true
	end,
	--rings
	[6] = function(p, a, f)
		local m = p.mo
		local item = a or tostring(getXSHRandom(9999)) 
		local amt = item:match("(%d%d?%d?%d?)") --I LOVE REGEX I LOVE REGEX I LO
		if tonumber(amt) == nil then
			gameprintf(p, "Something went wrong with your rings, so you get Match Super on us.")
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "matchsuper"), f)
		end
		if tonumber(amt) > 49 and not P_RandomChance(69*FU/1000) and not f then
			amt = tostring(50)
		end
		local minus = P_RandomChance(FU/8)
		gameprint(p.name.." rolled \$(minus and "Minus " or "")..amt\ Rings."..isForced(f or false))
		S_StartSound(m, (minus and sfx_antiri or sfx_itemup))
		P_GivePlayerRings(p, tonumber(amt) * (minus and -1 or 1))
		instantCooldown(p)
		return true
	end,
	--nothing
	[7] = function(p, f)
		gameprint(p.name.." rolled nothing."..isForced(f or false))
		S_StartSound(nil, sfx_rdfail, p) --tf2 rtd reference
		instantCooldown(p)
		return true
	end,
	--selfnuke
	[8] = function(p, f)
		local m = p.mo
		gameprint(p.name.." rolled a self-nuke. Better than just dying..."..isForced(f or false))
		instantCooldown(p)
		TacticalNuke(4096, m, 60, 5, true, PAL_NUKE)
		return true
	end,
	--instadeath
	[9] = function(p, f)
		local m = p.mo
		gameprint(p.name.." rolled an instant death. Skill issue."..isForced(f or false))
		instantCooldown(p)
		P_DamageMobj(m, nil, nil, 10000, DMG_INSTAKILL)
		return true
	end,
	--thousanddeaths
	[10] = function(p, f)
		if not Nightmare.value == 0 and not f and not P_RandomChance(FU/10000) then -- you have to get REALLY unlucky to get this one.
			return RTDFuncs.CallRTD(p, isearch(RTD_ItemsList, "instadeath"), f)
		end
		gameprint(p.name.." rolled a \x8FThousand Deaths\x80. o7 in the chat."..isForced(f or false))
		p.rtd.active = "thousanddeaths"
		return true
	end,
	default = function(p)
		gameprintf(p, "Roll failed. The mod must be broken. Let the server owner know.")
		return true
	end
}
COM_AddCommand("rtd_nightmaresave", function(p, s)
	if p and p.valid then
		if type(s) == "string" then
			local check = false
			for sp in players.iterate() do
				if s == sp.name then
					if sp.rtd.active == "thousanddeaths" then
						sp.rtd.hell.save = true
						CONS_Printf(p, sp.name.." has been saved from \x8FThe Roll\x80.")
					else
						CONS_Printf(p, sp.name.." doesn't need saving.")
					end
					check = true
					break
				end
			end
			if check == true then
				return
			else
				local num = tonumber(s)
				if type(num) == "number" then
					if Math.inRange(0, #players, num) then
						local sp = players[num]
						if sp.rtd.active == "thousanddeaths" then
							sp.rtd.hell.save = true
							CONS_Printf(p, sp.name.." has been saved from \x8FThe Roll\x80.")
						else
							CONS_Printf(p, sp.name.." doesn't need saving.")
						end
						return
					end
				end
			end
			CONS_Printf(p, "Could not find player.")
		else
			if p.rtd.active == "thousanddeaths" then
				p.rtd.hell.save = true
				CONS_Printf(p, "You are now saved from \x8FThe Roll\x80.")
			else
				CONS_Printf(p, "You don't need saving.")
			end
		end
	end
end, COM_ADMIN)
COM_AddCommand("rtd_forceroll", function(p, item, spec, s)
	if p then
		if (maptol & (TOL_NIGHTS|TOL_XMAS)) then
			CONS_Printf(p, "Rolls aren't allowed in NiGHTS, forced or not.") return
		end
		if type(item) == "string" then
			local r = (not (tonumber(item) == nil) and Math.clamp(1, #RTD_ItemsList, tonumber(item)) or isearch(RTD_ItemsList, item:lower()))
			local roll = false
			if type(s) == "string" then
				local check = false
				for sp in players.iterate() do
					if s == sp.name then
						if not (sp.rtd.active or sp.rtd.wait) then
							local ext = {rings = true, shields = true}
							if ext[RTD_ItemsList[r]] == true then
								roll = RTDFuncs.CallRTD(sp, r, spec or nil, true)
							else
								roll = RTDFuncs.CallRTD(sp, r, true)
							end
							CONS_Printf(p, "RTD \$RTD_ItemsList[roll]\ forced for \$sp.name\.")
							if (RTD_ItemsList[roll] == "thousanddeaths") then
								CONS_Printf(p, "You are\x85 beyond\x80 evil.")
							end
						else
							CONS_Printf(p, "RTD either active or on cooldown for \$sp.name\, wait.")
						end
						check = true
						break
					end
				end
				if check == true then
					return
				else
					local num = tonumber(s)
					if type(num) == "number" then
						if Math.inRange(0, #players, num) then
							local sp = players[num]
							if not (sp.rtd.active or sp.rtd.wait) then
								local ext = {rings = true, shields = true}
								if ext[RTD_ItemsList[r]] == true then
									roll = RTDFuncs.CallRTD(sp, r, spec or nil, true)
								else
									roll = RTDFuncs.CallRTD(sp, r, true)
								end
								CONS_Printf(p, "RTD \$RTD_ItemsList[roll]\ forced for \$sp.name\.")
								if (RTD_ItemsList[roll] == "thousanddeaths") then
									CONS_Printf(p, "You are\x85 beyond\x80 evil.")
								end
							else
								CONS_Printf(p, "RTD either active or on cooldown for \$sp.name\, wait.")
							end
							return
						end
					end
				end
				CONS_Printf(p, "Could not find player.")
			else
				if not (p.rtd.active or p.rtd.wait) then
					local ext = {rings = true, shields = true}
					if ext[RTD_ItemsList[r]] == true then
						roll = RTDFuncs.CallRTD(p, r, spec or nil, true)
					else
						roll = RTDFuncs.CallRTD(p, r, true)
					end
					CONS_Printf(p, "RTD \$RTD_ItemsList[roll]\ forced.")
					if (RTD_ItemsList[roll] == "thousanddeaths") then
						CONS_Printf(p, "Why would you do this to yourself?")
					end
				else
					CONS_Printf(p, "RTD either active or on cooldown, wait.")
				end
			end
		else
			CONS_Printf(p, "Arguments:")
			CONS_Printf(p, "rtd_forceroll ITEM [EXTRA] [PLAYER]")
			CONS_Printf(p, "\"ITEM\" must be included (and can either be the name or number of the roll item)")
			CONS_Printf(p, "\"EXTRA\" can be included to specify an exact outcome for certain rolls.")
			CONS_Printf(p, "If you want to force a roll for someone else, include their name. (optional)")
		end
	end
end, COM_ADMIN)
COM_AddCommand("rtd_fixwait", function(p, s)
	if (p and p.valid) then
		if type(s) == "string" then
			local check = false
			for sp in players.iterate() do
				if s == sp.name then
					instantCooldown(sp)
					CONS_Printf(p, "Fixed \$sp.name\'s RTD wait successfully")
					check = true
					break
				end
			end
			if check == true then
				return
			else
				local num = tonumber(a)
				if type(num) == "number" then
					if Math.inRange(0, #players, num) then
						local sp = players[num]
						instantCooldown(sp)
						CONS_Printf(p, "Fixed \$sp.name\'s RTD wait successfully")
						return
					end
				end
			end
			CONS_Printf(p, "Could not find player")
		else
			instantCooldown(p)
			CONS_Printf(p, "RTD wait fixed successfully")
		end
	end
end, COM_ADMIN)
function RTDFuncs.CallRTD(p, num, s, f)
	local special = f and s or false
	local forced = (not f) and s or f or false
	local roll = num or weighted_roll()
	local ret = funcswitch(roll, RTD_ItemFuncs)
	if type(ret) == "function" then
		if not special then
			ret(p, forced)
		else
			ret(p, special, forced)
		end
	end
	return roll
end
COM_AddCommand("rtd_roll", function(p)
	if type(p.rtd) ~= "table" then return end
	if (p and p.valid) then
		if not ((p.mo and p.mo.valid) and (p.playerstate == PST_LIVE)) then
			CONS_Printf(p, rtd.."You cannot roll the dice while dead or spectating.") return
		end
		if p.rtd.active ~= false then
			CONS_Printf(p, rtd.."Wait until your roll is over.") return
		end
		if type(p.rtd.wait) == "number" then
			CONS_Printf(p, rtd.."You must wait \$p.rtd.wait/TICRATE\ seconds to roll again.") return
		end
		if (maptol & (TOL_NIGHTS|TOL_XMAS)) then
			CONS_Printf(p, rtd.."Sorry, no rolling in NiGHTS.") return
		end
		RTDFuncs.CallRTD(p)
	end
end)
RTDFuncs.AddHook("PlayerThink", function(p)
	if type(p.rtd) ~= "table" then
		p.rtd = {
			_waittime = 45*TICRATE,
			wait = false,
			active = false,
			timer = 0,
			hell = {
				save = false,
				deathcounter = 0
			}
		}
		if netgame then
			chatprintf(p, rtd.."Welcome to the server!")
			chatprintf(p, rtd.."To Roll The Dice, type \"/rtd\" in the chat.")
		else
			CONS_Printf(p, rtd.."To Roll The Dice, use the \"rtd_roll\" command.")
		end
	end
end)
RTDFuncs.AddHook("PlayerThink", function(p)
	if type(p.rtd) ~= "table" then return end
	if p.rtd._waittime ~= RTDWait.value*TICRATE then
		p.rtd._waittime = RTDWait.value*TICRATE
	end
end)
local function C_GetPlayerColor(p)
	if (G_GametypeHasTeams() and cTrue(p.ctfteam)) then
		if (p.ctfteam == 1) then
			return skincolor_redteam
		elseif (p.ctfteam == 2) then
			return skincolor_blueteam
		end
	end
	return p.skincolor
end
local function C_DoSuperDetransform(p) -- p => player
	p.powers[pw_emeralds] = 0 --// lost the power stones
	P_SpawnGhostMobj(p.mo)

	if (p.charflags & SF_SUPER) then
		p.charflags = $&~SF_SUPER
	end
	p.powers[pw_super] = 0
	p.charability = skins[p.mo.skin].ability

	--// Restore color
	if (p.powers[pw_shield] & SH_STACK) then
		p.mo.color = SKINCOLOR_WHITE
	else
		p.mo.color = C_GetPlayerColor(p)
	end

	if (not G_CoopGametype()) then
		p.powers[pw_flashing] = flashingtics-1
	end

	if (p.mo.sprite2 & FF_SPR2SUPER) then
		p.mo.state = $
	end

	--// Resume normal music if you"re the console player
	P_RestoreMusic(p)

	--// If you had a shield, restore its visual significance.
	P_SpawnShieldOrb(p)
end
local function checkPronouns(p)
	if not cTrue(p.pronouns) then return 'their' end
	if p.pronouns[3]:sub(-3) == 'ers' then return p.pronouns[3]:sub(1, -2) end
	return p.pronouns[3]
end
RTDFuncs.AddHook("PlayerThink", function(p)
	if type(p.rtd) ~= "table" then return end
	local m = p.mo
	if p.rtd.active and (p.playerstate ~= PST_LIVE) then
		if m and m.valid then p.rtd.timer = false end
		if p.rtd.active == "thousanddeaths" then return end
		gameprint(p.name.." died during \$checkPronouns(p)\ roll...")
		if p.rtd.active == "truesuper" then
			C_DoSuperDetransform(p)
			table.remove(CDRTD.SuperList, isearch(CDRTD.SuperList, p.name))
		end
		if p.rtd.active == "matchsuper" then
			p.powers[pw_invulnerability] = 0
			p.powers[pw_sneakers] = 0
			if (p.powers[pw_shield] & SH_STACK) then
				p.mo.color = SKINCOLOR_WHITE
			else
				p.mo.color = C_GetPlayerColor(p)
			end
			P_RestoreMusic(p)
			P_SpawnShieldOrb(p)
		end
		if p.rtd.active == "invuln" then
			p.powers[pw_invulnerability] = 0
			if (p.powers[pw_shield] & SH_STACK) then
				p.mo.color = SKINCOLOR_WHITE
			else
				p.mo.color = C_GetPlayerColor(p)
			end
			P_RestoreMusic(p)
			P_SpawnShieldOrb(p)
		end
		if p.rtd.active == "speed" then
			p.powers[pw_sneakers] = 0
			P_RestoreMusic(p)
		end
		instantCooldown(p)
	end
	if type(p.rtd.timer) == "number" then
		p.rtd.timer = $-1
		if (p.rtd.timer <= 0) then
			p.rtd.timer = false
			if p.rtd.active == "truesuper" then -- RTD true super matters first
				C_DoSuperDetransform(p)
				p.charability = skins[m.skin].ability
				table.remove(CDRTD.SuperList, isearch(CDRTD.SuperList, p.name))
				gameprint(p.name.."'s True Super wore off.")
			end
			if p.rtd.active == "matchsuper" then
				p.powers[pw_invulnerability] = 0
				p.powers[pw_sneakers] = 0
				if (p.powers[pw_shield] & SH_STACK) then
					p.mo.color = SKINCOLOR_WHITE
				else
					p.mo.color = C_GetPlayerColor(p)
				end
				P_RestoreMusic(p)
				P_SpawnShieldOrb(p)
				gameprint(p.name.."'s Match Super wore off.")
			end
			if p.rtd.active == "invuln" then
				p.powers[pw_invulnerability] = 0
				if (p.powers[pw_shield] & SH_STACK) then
					p.mo.color = SKINCOLOR_WHITE
				else
					p.mo.color = C_GetPlayerColor(p)
				end
				P_RestoreMusic(p)
				P_SpawnShieldOrb(p)
				gameprint(p.name.."'s Invulnerability wore off.")
			end
			if p.rtd.active == "speed" then
				p.powers[pw_sneakers] = 0
				P_RestoreMusic(p)
				gameprint(p.name.."'s Speed Shoes wore off.")
			end
			instantCooldown(p)
		end
	end
	if p.rtd.active == "truesuper" and not cTrue(p.powers[pw_super]) then -- level forced you out of your super form
		p.charability = skins[m.skin].ability
		table.remove(CDRTD.SuperList, isearch(CDRTD.SuperList, p.name))
		instantCooldown(p)
		gameprint(p.name.."'s True Super ended prematurely.")
	end
	if p.rtd.active == "matchsuper"
	and not cTrue(p.powers[pw_invulnerability] | p.powers[pw_sneakers]) then
		if (p.powers[pw_shield] & SH_STACK) then
			p.mo.color = SKINCOLOR_WHITE
		else
			p.mo.color = C_GetPlayerColor(p)
		end
		P_RestoreMusic(p)
		instantCooldown(p)
		gameprint(p.name.."'s Match Super ended prematurely.")
	end
	if p.rtd.active == "invuln" and not cTrue(p.powers[pw_invulnerability]) then
		if (p.powers[pw_shield] & SH_STACK) then
			p.mo.color = SKINCOLOR_WHITE
		else
			p.mo.color = C_GetPlayerColor(p)
		end
		P_RestoreMusic(p)
		instantCooldown(p)
		gameprint(p.name.."'s Invulnerability ended prematurely.")
	end
	if p.rtd.active == "speed" and not cTrue(p.powers[pw_sneakers]) then
		P_RestoreMusic(p)
		instantCooldown(p)
		gameprint(p.name.."'s Speed Shoes ended prematurely.")
	end
	if type(p.rtd.wait) == "number" then
		p.rtd.wait = $-1
		if (p.rtd.wait <= 0) then
			p.rtd.wait = false
		end
	end
end)
RTDFuncs.AddHook("PlayerThink", function(p)
	if type(p.rtd) ~= "table" then return end
	if p.rtd.active ~= "truesuper" then return end
	if (p.mo.state >= S_PLAY_SUPER_TRANS1
	and p.mo.state <= S_PLAY_SUPER_TRANS6) then return end
	if ((leveltime % TICRATE) == 0) then
		p.rings = $+1
	end
end)
RTDFuncs.AddHook("PlayerThink", function(p) -- gotta feel bad for these peeps
	if type(p.rtd) ~= "table" then return end
	if p.rtd.active ~= "thousanddeaths" then return end
	if p.rtd.hell.save == true then
		instantCooldown(p)
		p.rtd.hell.deathcounter = 0
		p.rtd.hell.save = false
		gameprint(p.name.." has been freed!") return -- thanks admin!
	end
	if (p.playerstate == PST_LIVE) then
		P_KillMobj(p.mo, nil, nil, DMG_INSTAKILL|DMG_CANHURTSELF) -- die
		p.rtd.hell.deathcounter = $+1
		if p.rtd.hell.deathcounter >= 1000 then -- yes, it really is a thousand deaths
			instantCooldown(p)
			p.rtd.hell.deathcounter = 0
			gameprint(p.name.." is free once again!") -- this will take forever
		end
	end
end)
--little something to prevent super transformation
local SuperTransform = P_DoSuperTransformation
rawset(_G, "P_DoSuperTransformation", function(p, gr)
	if type(p.rtd) == "table" then
		if p.rtd.active ~= "truesuper"
		and not G_CoopGametype()
		and TrueSuper.value then
			return
		end
	end
	SuperTransform(p, gr)
end)
--and here's the backup
RTDFuncs.AddHook("PreThinkFrame", function()
	for p in players.iterate() do
		if type(p.rtd) ~= "table" then continue end
		if p.rtd.active ~= "truesuper"
		and not G_CoopGametype()
		and TrueSuper.value
		and p.powers[pw_super] then
			C_DoSuperDetransform(p)
			gameprintf(p, "Nice try.") -- no super 4 u
		end
	end
end)
RTDFuncs.AddHook("PlayerMsg", function(p, msgtype, _, msg)
	if type(p.rtd) ~= "table" then return end
	if (msgtype) then return end
	local check = msg:lower()
	if (check == "/rtd") then
		if not ((p.mo and p.mo.valid) and (p.playerstate == PST_LIVE)) then
			gameprintf(p, "You cannot roll the dice while dead or spectating.") return true
		end
		if (maptol & (TOL_NIGHTS|TOL_XMAS)) then
			gameprintf(p, "Sorry, no rolling in NiGHTS.") return true
		end
		if p.rtd.active then
			gameprintf(p, "Wait until your roll is over.") return true
		end
		if type(p.rtd.wait) == "number" then
			gameprintf(p, "You must wait \$p.rtd.wait/TICRATE\ seconds to roll again.") return true
		end
		RTDFuncs.CallRTD(p) return true
	end
end)
-------------------------------------
--        Oh hey, HUD stuff        --
-------------------------------------
local function trceil(x)
	if type(x) ~= "number" then return 0 end
	if x == 0 then return 0 end
	return FixedCeil(x*FU/TICRATE)/FU
end
RTDFuncs.AddHook("HUD", function(v, p) -- so you can still see how many rings you have stored
	if type(p.rtd) ~= "table" then return end
	if p.rtd.timer == false then return end
	local snaps = V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS
	local rx = (not (CV_FindVar("timerres").string == "Mania") and hudinfo[HUD_RINGSNUM].x or hudinfo[HUD_RINGSNUMTICS].x) -- hehe
	local timer = v.cachePatch("STTTIMER") -- my own creation
	v.draw(hudinfo[HUD_RINGS].x, hudinfo[HUD_RINGS].y + 16, timer, snaps)
	v.drawNum(rx, hudinfo[HUD_RINGSNUM].y + 16, trceil(p.rtd.timer or 0), snaps)
end, "game")