freeslot(
	"S_PILLARBOI", 
	"S_PILLARBOI_UHOH", 
	"S_PILLARBOI_DEAD", 
	"MT_PILLARBOI", 
	"S_LAPPORTAL", 
	"MT_LAPPORTAL", 
	"SPR_JOHN", 
	"SPR_JOHS", 
	"SPR_JOHD", 
	"SPR_LAP2", 
	"MT_PIZZAMASK", 
	"MT_PIZZAFACE", 
	"S_PIZZAFACE", 
	"S_PIZZAFACE_SPAWN", 
	"SPR_PZAT", 
	"SPR_SWRD", 
	"S_SWORD_SPAWN", 
	"MT_SWORD", 
	"S_PIZZAFACERECOVER", 
	"SPR_PZAR", 
	"SPR_SWDG", 
	"S_SWORD_GONE", 
	"S_GATE_CLOSED", 
	"S_GATE_OPEN", 
	"MT_GATE", 
	"SPR_GATO", 
	"SPR_GATC", 
	"SPR_SECO", 
	"SPR_SECC", 
	"S_SECRET_OPEN", 
	"S_SECRET_CLOSED", 
	"MT_SECRET", 
	"S_MACH3_DASH", 
	"MT_MACH3D", 
	"SPR_DASH", 
	"SPR_MACH", 
	"S_MACH_EFFECT", 
	"MT_MACHE", 
	"SPR_SPDL", 
	"SPR_WALL", 
	"S_SPEED_LINES", 
	"S_WALL_LINES", 
	"MT_SPDLINES", 
	"SPR_BANG", 
	"S_BANG_HIT", 
	"MT_BANG", 
	"S_GUSTAVO_GOOD", 
	"SPR_GUAB", 
	"S_SCARED", 
	"S_KNOCKED", 
	"S_PLAY_UPPERCUT1", 
	"S_PLAY_UPPERCUT2", 
	"SPR_STSP", 
	"S_SUPER_TAUNT_E", 
	"MT_STE",
	"MT_SNICK", 
	"S_SNICK", 
	"S_SNICK1", 
	"S_SNICK2", 
	"SPR_SNIK", 
	"sfx_hello"
)

local file = io.openlocal("client/PizzaBlast/HubNumber.txt", "a+")
file:close()
local file = io.openlocal("client/PizzaBlast/Noise.txt", "a+")
file:close()

local globalhubnum = 0
rawset(_G, "PizzaBlast", true)
rawset(_G, "canunlocknoise", false)

local function A_Scared(actor)
	actor.angle = actor.true_angle
	actor.sprite = actor.true_sprite
end

local function A_Knocked(actor)
	actor.sprite = actor.true_sprite
end

states[S_PILLARBOI] = {
	sprite = SPR_JOHN,
	frame = FF_ANIMATE|A,
	var1 = 11,
	var2 = 4,
	tics = -1,
	nextstate = S_PILLARBOI
}

states[S_PILLARBOI_UHOH] = {
	sprite = SPR_JOHS,
	frame = FF_ANIMATE|A,
	var1 = 4,
	var2 = 4,
	tics = -1,
	nextstate = S_PILLARBOI_UHOH
}

states[S_PILLARBOI_DEAD] = {
	sprite = SPR_JOHD,
	frame = A,
	tics = -1,
	nextstate = S_PILLARBOI_DEAD
}

states[S_LAPPORTAL] = {
	sprite = SPR_LAP2,
	frame = FF_ANIMATE|A,
	var1 = 2,
	var2 = 2,
	tics = -1
}

mobjinfo[MT_PILLARBOI] = {
	doomednum = -1,
	spawnstate = S_PILLARBOI,
	spawnhealth = 2,
	deathstate = S_PILLARBOI_DEAD,
	radius = 64*FU,
	height = 200*FU,
	flags = MF_SPECIAL|MF_ENEMY|MF_NOGRAVITY
}

mobjinfo[MT_LAPPORTAL] = {
	doomednum = 3002,
	spawnstate = S_LAPPORTAL,
	spawnhealth = 9999,
	radius = 32*FU,
	height = 130*FU,
	flags = MF_SPECIAL|MF_NOGRAVITY
}

states[S_PIZZAFACE_SPAWN] = {
    sprite = SPR_PZAT,
    frame = FF_ANIMATE|A,
    tics = -1,
    var1 = 15,
    var2 = 2,
    nextstate =	S_PIZZAFACE_SPAWN
}

mobjinfo[MT_PIZZAFACE] = {
	doomednum = -1,
	spawnstate = S_PIZZAFACE_SPAWN,
	spawnhealth = 1,
	speed = 24*FRACUNIT,
	radius = 60*FRACUNIT,
	height = 72*FRACUNIT,
	flags = MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC|MF_NOGRAVITY|MF_NOCLIP
}

mobjinfo[MT_PIZZAMASK] = {
	doomednum = -1,
	spawnstate = S_PIZZAFACE,
	spawnhealth = 1000,
	deathstate = S_NULL,
	radius = 16*FU,
	height = 48*FU,
	flags = MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC|MF_NOGRAVITY|MF_NOCLIP
}

states[S_PIZZAFACE] = {
    sprite = SPR_PZAT,
    frame = FF_ANIMATE|A,
    tics = -1,
    var1 = 15,
    var2 = 2,
    nextstate = SPR_PZAT
}

states[S_SWORD_SPAWN] = {
	sprite = SPR_SWRD,
	frame = A,
	tics = -1,
	nextstate = S_SWORD_SPAWN
}

states[S_SWORD_GONE] = {
	sprite = SPR_SWDG,
	frame = A,
	tics = -1,
	nextstate = S_SWORD_GONE
}

mobjinfo[MT_SWORD] = {
	doomednum = 3003,
	spawnstate = S_SWORD_SPAWN,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_SPECIAL
}

states[S_PIZZAFACERECOVER] = {
    sprite = SPR_PZAR,
    frame = FF_ANIMATE|A,
    tics = 18,
    var1 = 9,
    var2 = 2,
    nextstate = S_PIZZAFACE
}

states[S_GATE_CLOSED] = {
	sprite = SPR_GATC,
	frame = A,
	tics = -1,
	nextstate = S_GATE_CLOSED
}

states[S_GATE_OPEN] = {
	sprite = SPR_GATO,
	frame = A,
	tics = -1,
	nextstate = S_GATE_OPEN
}

mobjinfo[MT_GATE] = {
	doomednum = -1,
	spawnstate = S_GATE_CLOSED,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_SPECIAL
}

states[S_SECRET_OPEN] = {
	sprite = SPR_SECO,
	frame = A,
	tics = -1,
	nextstate = S_SECRET_OPEN
}

states[S_SECRET_CLOSED] = {
	sprite = SPR_SECC,
	frame = A,
	tics = -1,
	nextstate = S_SECRET_CLOSED
}

mobjinfo[MT_SECRET] = {
	doomednum = 3004,
	spawnstate = S_SECRET_OPEN,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_SPECIAL|MF_NOGRAVITY
}

states[S_MACH3_DASH] = {
	sprite = SPR_DASH,
	frame = FF_PAPERSPRITE|FF_ANIMATE|A,
	var1 = 7,
	var2 = 2,
	tics = 96,
	nextstate = S_DEATHSTATE
}

mobjinfo[MT_MACH3D] = {
	doomednum = -1,
	spawnstate = S_MACH3_DASH,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_NOGRAVITY
}

states[S_MACH_EFFECT] = {
	sprite = SPR_MACH,
	frame = FF_PAPERSPRITE|FF_ANIMATE|A,
	var1 = 0,
	var2 = 1,
	tics = 10,
	nextstate = S_DEATHSTATE
}

mobjinfo[MT_MACHE] = {
	doomednum = -1,
	spawnstate = S_MACH_EFFECT,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_NOGRAVITY
}

states[S_SPEED_LINES] = {
	sprite = SPR_SPDL,
	frame = FF_PAPERSPRITE|FF_ANIMATE|A,
	var1 = 7,
	var2 = 4,
	tics = 28,
	nextstate = S_DEATHSTATE
}

states[S_WALL_LINES] = {
	sprite = SPR_WALL,
	frame = FF_PAPERSPRITE|FF_ANIMATE|A,
	var1 = 7,
	var2 = 4,
	tics = 28,
	nextstate = S_DEATHSTATE
}

mobjinfo[MT_SPDLINES] = {
	doomednum = -1,
	spawnstate = S_SPEED_LINES,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_NOGRAVITY
}

states[S_BANG_HIT] = {
	sprite = SPR_BANG,
	frame = FF_ANIMATE|A,
	var1 = 4,
	var2 = 2,
	tics = 8,
	nextstate = S_DEATHSTATE
}

mobjinfo[MT_BANG] = {
	doomednum = -1,
	spawnstate = S_BANG_HIT,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_NOGRAVITY
}

states[S_GUSTAVO_GOOD] = {
	sprite = SPR_GUAB,
	frame = A,
	tics = -1,
	nextstate = S_GUSTAVO_GOOD
}

states[S_PLAY_UPPERCUT1] = {
	sprite = SPR_PLAY,
	frame = SPR2_SPNG|FF_ANIMATE,
	tics = 12,
	var1 = 2,
	var2 = 2,
	nextstate = S_PLAY_UPPERCUT2
}

states[S_PLAY_UPPERCUT2] = {
	sprite = SPR_PLAY,
	frame = SPR2_ROLL|FF_ANIMATE,
	tics = 20,
	var1 = 2,
	var2 = 2,
	nextstate = S_PLAY_FALL
}

states[S_SCARED] = {
	sprite = S_NULL,
	frame = A,
	tics = 1,
	action = A_Scared,
	var1 = 0,
	var2 = 0,
	nextstate = S_SCARED
}

states[S_KNOCKED] = {
	sprite = S_NULL,
	frame = A,
	tics = 1,
	action = A_Knocked,
	var1 = 0,
	var2 = 0,
	nextstate = S_KNOCKED
}

// TG in clutch

states[S_SUPER_TAUNT_E] = {
	sprite = SPR_STSP,
	frame = FF_ANIMATE|A,
	tics = 5,
	var1 = 5,
	var2 = 1,
	nextstate = S_NULL
}

mobjinfo[MT_STE] = {
	doomednum = -1,
	spawnstate = S_SUPER_TAUNT_E,
	spawnhealth = 9999,
	radius = 32*FU,
	flags = MF_NOGRAVITY
}

rawset(_G, 'hooks', {})

rawset(_G, 'addPTHook', function(name, func)
	if not hooks[name]
		hooks[name] = {}
	end
	table.insert(hooks[name], func)
end)

rawset(_G, 'executePTHook', function(name, table)
	if hooks[name]
		local return_val = nil
		for _,func in pairs(hooks[name])
			local thing = func(unpack(table))
			if not return_val
				return_val = thing
			end
		end
		return return_val
	end
end)

rawset(_G, "L_TableContains", function(table, val)
	local hasit = {}
	for _,i in pairs(table) do
		hasit[i] = true
	end
	return hasit[val]
end)

local function hubmap()
file = io.openlocal("client/PizzaBlast/HubNumber.txt", "r+") //Anti Cheat and Game Saving in one!!
local hubnum = file:read("*n")
file:seek("set")
globalhubnum = file:read("*n")
file:seek("set")
		
	if LapImpossible return end
	
	if gamemap == 100 and (hubnum == 100 or hubnum == nil)
		file:write("100")
	elseif gamemap == 101 and hubnum == 100
		file:write("101")
	elseif gamemap == 102 and hubnum == 101
		file:write("102")
	elseif gamemap == 103 and hubnum == 102
		file:write("103")
	elseif gamemap == 104 and hubnum == 103
		file:write("104")
	elseif gamemap == 105 and hubnum == 104
		file:write("105")
	elseif gamemap == 106 and hubnum == 105
		file:write("106")
	end
	if hubnum < 100
		file:write("100")
	elseif hubnum > 106
		file:write("106")
	end
	if (hubnum or globalhubnum) == nil
		file:write("100")
	end
	file:close()
end

addHook("MapLoad", hubmap)

local function hubtp()
	if gamemap >= 100 and gamemap < 107 and gamemap ~= globalhubnum and not LapImpossible
		if globalhubnum ~= nil
			G_ExitLevel(globalhubnum, 1)
		end
	end
end

addHook("ThinkFrame", hubtp)

/*Well, your reward for checking the code is the secret to unlocking the end game
COM_AddCommand("FullSave", function(player, arg)
	print "To get a full save, type pizzablast on the title screen"
	canunlocknoise = true
end)*/

COM_AddCommand("DeleteSave", function(player, arg)
	file = io.openlocal("client/PizzaBlast/HubNumber.txt", "w") //For anyone editting this, this doesn't remove all data in a file, just going into write mode cleans a file.
	file:write("100")
	file:close()
	G_ExitLevel(100, 1)
	file = io.openlocal("client/PizzaBlast/Noise.txt", "w")
	file:close()
	print ("Successfully Removed Save Data")
end, COM_ADMIN)

COM_AddCommand("exitlevel", function(player)
	G_ExitLevel(globalhubnum, 1)
end, COM_ADMIN)

addHook("ThinkFrame", function()
	for player in players.iterate()
		if not NoMoveset
			if player and player.mo.valid
				hud.disable("rings")
				hud.disable("time")
				hud.disable("lives")
			end
			gravity = FRACUNIT
			player.jumpfactor = (skins[player.mo.skin].jumpfactor*3)/2
			if (player.mo.eflags & MFE_SPRUNG)
				P_SetObjectMomZ(player.mo, (player.mo.momz/2), true)
			end
			if player.mo.state == S_UNKNOWN
				player.mo.state = S_GUSTAVO_GOOD
			end
		else
			if player and player.mo.valid
				hud.disable("rings")
				hud.disable("time")
				hud.disable("lives")
			end
			gravity = FRACUNIT/2
			player.jumpfactor = skins[player.mo.skin].jumpfactor
			if player.mo.state == S_UNKNOWN
				player.mo.state = S_GUSTAVO_GOOD
			end
		end
	end
	if PizzaBlast ~= true
		PizzaBlast = true
	end
end)

addHook("PlayerThink", function(player)
	if player.color1 == nil
		player.color1 = R_GetColorByName("After Image Red")
	end
	if player.color2 == nil
		player.color2 = R_GetColorByName("After Image Green")
	end
end)

//TG made these, said I didn't need to credit him, but uh, he's a cool dude for this
//after images!!
freeslot("SKINCOLOR_AFTERIMAGERED","SKINCOLOR_AFTERIMAGEGREEN")

skincolors[SKINCOLOR_AFTERIMAGERED] = {
    name = "After Image Red",
    ramp = {35,35,35,35,35,35,35,35,35,35,35,41,41,41,41,41},
    invcolor = SKINCOLOR_AFTERIMAGEGREEN,
    invshade = 9,
    chatcolor = V_REDMAP,
    accessible = true
}

skincolors[SKINCOLOR_AFTERIMAGEGREEN] = {
    name = "After Image Green",
    ramp = {100,100,100,100,100,100,100,100,100,100,100,191,191,191,191,191},
    invcolor = SKINCOLOR_AFTERIMAGERED,
    invshade = 9,
    chatcolor = V_GREENMAP,
    accessible = true
}

//Luigi moment
local function choosething(...)
	local args = {...}
	local choice = P_RandomRange(1,#args)
	return args[choice]
end

COM_AddCommand("TGAIColor1", function(p, arg, s)
	if not p or not p.valid
        CONS_Printf(p, "\x85"+"You don't exist yet!")
        return
	end
	
	local prevstyle
	local c
	
	if arg and R_GetColorByName(arg) != SKINCOLOR_NONE
		c = R_GetColorByName(arg)
		prevstyle = p.color1
		p.color1 = c
		if (arg == nil)
			p.ptaicolor1 = prevstyle
			if not s
				CONS_Printf(p, "\x85"+"You have to set a color for this to work.")
			end
			return
		end
		if io and p == consoleplayer
			local file = io.openlocal("client/PizzaBlast/color1.dat", "w+")
			file:write(c)
			file:close()
		end

		if not s
			CONS_Printf(p, "First Color set to "+"\x82"+arg+"\x80"+".")
		end
	else
		CONS_Printf(p, "Sets what color the first afterimage is.")
		CONS_Printf(p, "Please note that custom colors may not save!\n")
		CONS_Printf(p, "Current color is \x82" + p.color1+"\x80"+".") 
	end
end)

COM_AddCommand("TGAIColor2", function(p, arg, s)
	if not p or not p.valid
        CONS_Printf(p, "\x85"+"You don't exist yet!")
        return
	end
	
	local prevstyle
	local c

	if arg and R_GetColorByName(arg) != SKINCOLOR_NONE
		c = R_GetColorByName(arg)
		prevstyle = p.color2
		p.color2 = c
		if (arg == nil)
			p.color2 = prevstyle
			if not s
				CONS_Printf(p, "\x85"+"You have to set a color for this to work.")
			end
			return
		end
		if io and p == consoleplayer
			local file = io.openlocal("client/PizzaBlast/color2.dat", "w+")
			file:write(c)
			file:close()
		end

		if not s
			CONS_Printf(p, "Second Color set to "+"\x82"+arg+"\x80"+".")
		end
	else
		CONS_Printf(p, "Sets what color the second afterimage is.")
		CONS_Printf(p, "Please note that custom colors may not save!\n")
		CONS_Printf(p, "Current color is \x82" + p.color2+"\x80"+".") 
	end
end)

addHook("PlayerSpawn", function(p)
local file = io.openlocal("client/PizzaBlast/color1.dat")
	if file
		COM_BufInsertText(p, "TGAIColor1 \""..file:read("*a").."\" s")
	else
		COM_BufInsertText(p, "TGAIColor1 After Image Red")
	end
	local file = io.openlocal("client/PizzaBlast/color2.dat")
	if file
		COM_BufInsertText(p, "TGAIColor2 \""..file:read("*a").."\" s")
	else
		COM_BufInsertText(p, "TGAIColor2 After Image Green")
	end
end)

//Luigi done

rawset(_G, 'createafterimage', function(p)
	local afti = P_SpawnGhostMobj(p.mo)
	afti.colorized = true
	afti.fuse = 999
	afti.tics = 5
	afti.color = P_RandomRange(p.color1,p.color2)
	afti.frame = TR_TRANS10|p.mo.frame|FF_FULLBRIGHT
end)

rawset(_G, 'momz', function(p)
	if not (p.mo.eflags & MFE_VERTICALFLIP)
	and p.mo.momz < 0
	or (p.mo.eflags & MFE_VERTICALFLIP)
	and p.mo.momz > 0
		return true
	else
		return false
	end
end)

rawset(_G, "keycount", 0)

addHook("KeyDown", function(keyevent)
	if (gamestate & GS_TITLESCREEN)
		if canunlocknoise == false return end
		if keyevent.name == "p"
		and keycount == 0
			keycount = 1
			return true
		end
		if keyevent.name == "i"
		and keycount == 1
			keycount = 2
			return true
		end
		if keyevent.name == "z"
		and keycount == 2
			keycount = 3
			return true
		end
		if keyevent.name == "z"
		and keycount == 3
			keycount = 4
			return true
		end
		if keyevent.name == "a"
		and keycount == 4
			keycount = 5
			return true
		end
		if keyevent.name == "b"
		and keycount == 5
			keycount = 6
			return true
		elseif keyevent.name == "l"
		and keycount == 6
			keycount = 7
			return true
		elseif keyevent.name == "a"
		and keycount == 7
			keycount = 8
			return true
		elseif keyevent.name == "s"
		and keycount == 8
			keycount = 9
			return true
		elseif keyevent.name == "t"
		and keycount == 9
			keycount = 0
			local file = io.openlocal("client/PizzaBlast/Noise.txt", "r+")
			file:seek("set")
			file:write("1")
			file:close()
			local file = io.openlocal("client/PizzaBlast/HubNumber.txt", "r+")
			file:seek("set")
			file:write("106")
			file:close()
			S_StartSound(nil, sfx_cgot)
			print "This isn't just a full save! This is also The Noise!"
			print "The Noise is now playable using the command 'noisemode'! Thanks for playing!"
			print "Letting you know, unlike the rest of this mod, I spent like, 5 minutes on the noise, so don't expect a 1:1 like the rest of this"
		else
			keycount = 0
			return false
		end
	end
end)

addHook("PlayerSpawn", function(player)
file = io.openlocal("client/PizzaBlast/Noise.txt", "r+")
local noiseunlocked = file:read("*n")
	if noiseunlocked == nil
		file:write("0")
	end
	if noiseunlocked == 1
		player.noiseunlocked = true
	else
		player.noiseunlocked = false
	end
end)