
// I seriously feel like this needs Multiplayer support.

freeslot("MT_WAITICO", "S_WAITICO", "SPR_WICO")

states[S_WAITICO] = {
	sprite = SPR_SPRY,
	frame = 0,
	tics = -1,
	nextstate = S_NULL
}

mobjinfo[MT_WAITICO] = {
	spawnstate = S_WAITICO,
	spawnhealth = 1,
	seestate = S_WAITICO,
	seesound = sfx_none,
	reactiontime = TICRATE,
	attacksound = sfx_none,
	painstate = S_WAITICO,
	painchance = 0,
	painsound = sfx_none,
	deathstate = S_NULL,
	xdeathstate = S_NULL,
	deathsound = sfx_none,
	speed = 10,
	radius = 16*FRACUNIT,
	height = 16*FRACUNIT,
	dispoffset = 0,
	mass = 100,
	damage = 0,
	activesound = sfx_none,
	flags = MF_SCENERY,
	raisestate = S_NULL
}

G_AddGametype({
	name = "Dungeon Crawler MP",
    identifier = "dcmp",
    typeoflevel = TOL_COOP,
    rules = GTR_CAMPAIGN|GTR_FRIENDLY|GTR_HURTMESSAGES|GTR_SPAWNENEMIES|GTR_CUTSCENES|GTR_LIVES|GTR_NOSPECTATORSPAWN,
    intermissiontype = int_none,
    headercolor = 28,
    description = "Want to play Dungeon Crawler with your Friends? Make sure to use this Gametype!"
})

// Note to self: It's TOL_DCMP, not TOL_DUNGEONCRAWLERMP

// Arrays, don't worry about the Map format since maps are now made in-game!
// Honestly all this code is kinda unorganized.. oh well!

// Maps Format

// 0: Floor
// 1: Wall
// 2: Sword Chest
// 3: Shield Chest
// 4: Potion Chest
// 5: Trap Chest
// 8: Ladder
// 9: Player Spawn Location

local map1 = {
9,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,1,1,0,2,0,1,0,1,0,0,4,1,0,0,0,1,0,1,0,1,1,1,0,0,1,1,0,1,0,0,0,1,5,0,1,0,0,1,1,1,0,1,1,0,0,0,1,1,0,0,0,0,8,0,1,0,1,5,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,
}

local map2 = {
8,0,0,0,0,0,0,0,0,4,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,0,9,0,1,0,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,1,1,1,5,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,4,3,0,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,
}

local map3 = {
0,0,0,0,0,0,0,0,0,9,0,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,3,1,1,1,0,1,4,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,5,1,1,1,0,1,2,0,0,0,0,0,0,0,0,0,0,8,1,0,1,0,1,0,1,1,1,
}

local map4 = {
9,0,0,0,0,0,0,0,0,0,1,1,1,1,1,5,1,1,1,0,0,0,0,8,1,0,0,0,0,0,0,1,4,1,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,4,1,0,5,1,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
}

local map5 = {
2,1,8,1,1,1,1,1,1,1,0,1,0,1,5,0,0,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,0,1,1,0,1,1,1,0,0,0,0,1,9,0,1,0,0,0,0,1,1,1,1,1,1,0,1,0,0,1,0,0,0,4,1,4,1,0,0,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
}

local map6 = {
9,0,0,0,0,0,0,0,1,4,0,1,1,1,1,5,1,1,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,5,0,0,0,0,1,0,1,0,0,1,0,1,8,0,0,0,0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,0,0,2,1,0,0,1,1,1,5,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
}

local map7 = {
3,0,0,0,0,0,0,0,0,8,0,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,1,4,0,0,1,1,1,0,9,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,4,0,0,0,0,1,0,0,0,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,
}

local map8 = {
0,0,0,1,1,1,1,8,1,1,0,9,0,1,1,1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,0,3,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,0,0,1,0,0,0,0,0,0,
}

local map9 = {
8,0,0,0,1,1,0,0,0,4,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,5,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,2,0,0,5,1,1,0,0,0,9,
}

local map10 = {
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,9,0,0,0,0,0,0,0,0,0,0,
}

local maps = {map1, map2, map3, map4, map5, map6, map7, map8, map9, map10}

// Swords Format
// "X": Name of the weapon.
// X: Damage of the weapon.

local nothing = {"Nothing", 0} 
local dagger = {"Dagger", 1}
local smallsword = {"Small Sword", 2}
local broadsword = {"Broadsword", 4}
local greatsword = {"Greatsword", 8}
local mastersword = {"Master Sword", 16}
local goldensword = {"Golden Sword", 32}
local ultimasword = {"Ultima Sword", 64}

local swords = {nothing, dagger, smallsword, broadsword, greatsword, mastersword, goldensword, ultimasword}

// Shields format, same as swords except damage is now defense.

local nothingagain = {"Nothing", 0}
local potlid = {"Pot Lid", 15}
local smallshield = {"Small Shield", 45}
local shield = {"Shield", 75}
local metalshield = {"Metal Shield", 105}
local mirrorshield = {"Mirror Shield", 135}
local hallofshield = {"Hall o'Shield", 165}

local shields = {nothingagain, potlid, smallshield, shield, metalshield, mirrorshield, hallofshield}

// Healing format, same as the last two.

local smallhppotion = {"Small HP Potion", 35}
local hppotion = {"HP Potion", 75}
local bighppotion = {"Big HP Potion", 125}
local ultrahppotion = {"Ult. HP Potion", 350}

local potions = {smallhppotion, hppotion, bighppotion, ultrahppotion}

local hptable = {
	[MT_BLUECRAWLA] = 10,
	[MT_REDCRAWLA] = 12,
	[MT_JETTGUNNER] = 24,
	[MT_SPINCUSHION] = 8,
	[MT_EGGGUARD] = 24,
	[MT_FACESTABBER] = 32,
	[MT_EGGMOBILE] = 125,
}
local dmgtable = {
	[MT_BLUECRAWLA] = 25,
	[MT_REDCRAWLA] = 35,
	[MT_JETTGUNNER] = 35,
	[MT_SPINCUSHION] = 40,
	[MT_EGGGUARD] = 35,
	[MT_FACESTABBER] = 45,
	[MT_EGGMOBILE] = 34,
}

// Thanks LJ Sonic, this is very useful.
local function blockToSector(x, y)
    return R_PointInSubsector(x * 64*FRACUNIT - FRACUNIT, y * 64*FRACUNIT - FRACUNIT).sector
end

local function P_BuildMap(p)
	if p.rpg
		for pl in players.iterate
			//P_SaveFile(pl)
			pl.pflags = $|PF_NOCLIP
		end
		p.rpg.map = maps[p.rpg.floor]
		p.rpg.bossspawned = false
		for r=1,10
			for c=1,10
				local block = blockToSector(c, r)
				block.floorheight = 0
				if p.rpg.floor == #maps
					block.ceilingheight = 128*FRACUNIT
				else
					block.ceilingheight = 64*FRACUNIT
				end
				for s in sectors.iterate
					if p.rpg.floor < #maps - ((#maps/2) + (#maps/4))
						local floor = "GFZFLR01"
						local texture = 1495
						s.floorpic = floor
						s.ceilingpic = floor
						for i=0,3
							local l = s.lines[i]
							l.frontside.bottomtexture = texture
							if l.backside
								l.backside.bottomtexture = texture
							end
						end
					elseif p.rpg.floor < #maps - (#maps/4)
						local floor = "THZFLR24"
						local texture = 2290
						s.floorpic = floor
						s.ceilingpic = floor
						for i=0,3
							local l = s.lines[i]
							l.frontside.bottomtexture = texture
							if l.backside
								l.backside.bottomtexture = texture
							end
						end
					elseif p.rpg.floor < #maps
						local floor = "CEZFLR06"
						local texture = 3100
						s.floorpic = floor
						s.ceilingpic = floor
						for i=0,3
							local l = s.lines[i]
							l.frontside.bottomtexture = texture
							if l.backside
								l.backside.bottomtexture = texture
							end
						end
					else
						local floor = "ERZRCKF1"
						local texture = 2500
						s.floorpic = floor
						s.ceilingpic = floor
						for i=0,3
							local l = s.lines[i]
							l.frontside.bottomtexture = texture
							if l.backside
								l.backside.bottomtexture = texture
							end
						end
					end
				end
				if p.rpg.map[block.tag] == 1
					if p.rpg.floor == #maps
						block.floorheight = 128*FRACUNIT
					else
						block.floorheight = 64*FRACUNIT
					end
				elseif p.rpg.map[block.tag] == 2
					P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_ARMAGEDDON_BOX)
				elseif p.rpg.map[block.tag] == 3
					P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_FORCE_BOX)
				elseif p.rpg.map[block.tag] == 4
					P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_RING_BOX)
				elseif p.rpg.map[block.tag] == 5
					P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_EGGMAN_BOX)
				elseif p.rpg.map[block.tag] == 8
					P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_YELLOWSPRING)
				elseif p.rpg.map[block.tag] == 9
					P_TeleportMove(p.mo, c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0)
				elseif p.rpg.map[block.tag] == 0
					if p.rpg.floor < #maps - ((#maps/2) + (#maps/4))
						if P_RandomRange(1,8) == 7
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_REDCRAWLA)
						elseif P_RandomRange(1,8) == 3
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_BLUECRAWLA)
						end
					elseif p.rpg.floor < #maps - (#maps/4)
						if P_RandomRange(1,10) == 1
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_JETTGUNNER)
						elseif P_RandomRange(1,10) == 5
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_SPINCUSHION)
						end
					elseif p.rpg.floor < #maps
						if P_RandomRange(1,12) == 2
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_EGGGUARD)
						elseif P_RandomRange(1,12) == 8
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_FACESTABBER)
						end
					else
						if (not p.rpg.bossspawned) and (c == 5) and (r == 5)
							P_SpawnMobj(c*(64*FRACUNIT)-32*FRACUNIT, r*(64*FRACUNIT)-32*FRACUNIT, 0, MT_EGGMOBILE)
							p.rpg.bossspawned = true
						end
					end
				end
			end
		end
		
		if p.rpg.floor < #maps - ((#maps/2) + (#maps/4))
			S_ChangeMusic("lowflr", true, p)
		elseif p.rpg.floor < #maps - (#maps/4)
			S_ChangeMusic("midflr", true, p)
		elseif p.rpg.floor < #maps
			S_ChangeMusic("hiflr", true, p)
		else
			S_ChangeMusic("rpboss", true, p)
		end
		
		for pl in players.iterate
			pl.spawncoords = {p.mo.x, p.mo.y, p.mo.subsector.sector.floorheight}
			pl.pflags = $ & ~PF_NOCLIP
			pl.rpg.mpwaiting = false
			P_TeleportMove(pl.mo, p.mo.x, p.mo.y, p.mo.z)
		end
	end	
end

local challenges = {
	{0, "None", 0},
	{1, "Minimal Kills", 1*#maps},
	{2, "Minimal Level", 1*(#maps/2)},
	{3, "No Equipment", 1, 1},
	{4, "Genocide", (5*#maps)+25}
}

local charstats = {
	{100, 2, 10}, // Sonic
	{120, 1, 11}, // Tails
	{70, 5, 7}, // Knuckles
	{90, 4, 8}, // Amy
	{50, 6, 6}, // Fang
	{100, 2, 10}, // Metal Sonic
	{90, 4, 8}, // Other Characters
}

local function P_RPGVars(p)
	if p.rpg == nil
		p.rpg = {}
		
		p.rpg.floor = 1
		p.rpg.map = maps[p.rpg.floor]
		p.rpg.bossspawned = false
		
		local skin = skins[p.mo.skin]
	
		if #skin > 6
			skin = 7
		else
			skin = #skin
		end
		
		local vars = charstats[skin+1]
		
		p.continues = 1
		p.lives = 3
		p.rpg.level = 1
		p.rpg.xp = 0
		if gametype ~= GT_DCMP
			p.rpg.nextxp = 100
		else
			p.rpg.nextxp = 50
		end
		p.rpg.maxhp = vars[1]
		p.rpg.baseatk = vars[2]
		p.rpg.basedef = vars[3]
		
		p.rpg.swordnum = 2
		p.rpg.shieldnum = 2
		p.rpg.inventory = {potions[1]}
		
		p.rpg.challenge = challenges[1][1]
		p.rpg.kills = 0
		p.rpg.mpwaiting = false
	end
	
	if p.rpg.challenge ~= challenges[1][1]
		p.lives = 1
		p.continues = 0
		p.xtralife = 0
	end
	
	//local savefile = io.openlocal("dungeonsave.txt", "r+")
	
	if savefile ~= nil
		savefile:close()
		//P_LoadFile(p)
	else
		//P_SaveFile(p)
	end
		
	p.rpg.hp = p.rpg.maxhp 
	if p.mo and p.mo.valid
		p.mo.scale = FRACUNIT/4
	end
	
end

COM_AddCommand("challenge", function(p, arg)
	if arg
		if challenges[tonumber(arg)+1] ~= nil
			if p.rpg.challenge == challenges[1][1]
				CONS_Printf(p, "You chose "+challenges[tonumber(arg)+1][2]+" as your challenge!")
				p.rpg = nil
				for mob in mobjs.iterate()
					if mob.type ~= MT_PLAYER
						P_RemoveMobj(mob)
					end
				end
				P_RPGVars(p)
				p.rpg.challenge = challenges[tonumber(arg)+1][1]
				P_RPGVars(p)
				if p.rpg.challenge == challenges[2][1]
					challenges[2][3] = 2*#maps
					CONS_Printf(p, "Don't kill more than "+challenges[2][3]+" enemies or else!")
				elseif p.rpg.challenge == challenges[3][1]
					challenges[3][3] = (#maps/2)
					CONS_Printf(p, "Don't let your level reach more than "+challenges[3][3]+" or else!")
				elseif p.rpg.challenge == challenges[5][1]
					challenges[5][3] = (5*#maps)+25
					CONS_Printf(p, "Kill at least "+challenges[5][3]+" enemies before the Boss or else!")
				end
				P_BuildMap(p)
			else
				CONS_Printf(p, "You can't change your challenge!")
			end
		else
			CONS_Printf(p, "\nChallenges: Want more difficulty in your Dungeon? Use this!\nYou can't change challenges until you exit the dungeon!\n\n0 - None.\n1 - Minimal Kills - You can't kill more than "+tostring(challenges[2][3])+" enemies!\n2 - Minimal Level - Your Level can't be any higher than "+tostring(challenges[3][3])+"!\n3 - No Equipment - You have no equipment making you weaker!\n4 - \x85Genocide\x80 - Kill at least \x85"+challenges[5][3]+"\x80 enemies! \x85=>\n")
		end
	else
		CONS_Printf(p, "\nChallenges: Want more difficulty in your Dungeon? Use this!\nYou can't change challenges until you exit the dungeon!\n\n0 - None.\n1 - Minimal Kills - You can't kill more than "+tostring(challenges[2][3])+" enemies!\n2 - Minimal Level - Your Level can't be any higher than "+tostring(challenges[3][3])+"!\n3 - No Equipment - You have no equipment making you weaker!\n4 - \x85Genocide\x80 - Kill at least \x85"+challenges[5][3]+"\x80 enemies! \x85=>\n")
	end
end)

local function P_LoadArray(p, filename)
	local thing = io.open(filename, "r+")
	local stringy = thing:read("*a")
	print(stringy)
	local maparray = {}
	for i=0,10
		local array = {}
		for k=0,20
			if string.sub(stringy, k, k) ~= ","
				table.insert(maparray, tonumber(string.sub(stringy, k+(20*i), k+(20*i))))
			end
		end
	end
	table.insert(maps, #maps, maparray)
	thing:close()
end

COM_AddCommand("addgamefloor", function(p, arg)
	if p == server
		local testfile = io.open(arg, "r+")
		local oldmapnum = #maps
		
		if testfile ~= nil
			P_LoadArray(p, arg)
		else
			CONS_Printf(p, "There is no file with this filename!")
		end

		if #maps > oldmapnum
			for pl in players.iterate
				p.rpg.totalmaps = #maps
				p.rpg.tempmaparray = maps
			end
			challenges[2][3] = 2*#maps
			challenges[3][3] = (#maps/2)
			challenges[5][3] = (5*#maps)+25
			CONS_Printf(p, "Updated the challenge requirements.")
		end
	end
end)

local levelupstats = {
	{6, 3, 7}, // Sonic
	{7, 4, 8}, // Tails
	{4, 8, 4}, // Knuckles
	{5, 5, 7}, // Amy
	{4, 7, 4}, // Fang
	{6, 4, 7}, // Metal Sonic
	{5, 5, 7}, // Other Characters
}

local function P_LevelUp(p)
	local skin = skins[p.mo.skin]
	
	if #skin > 6
		skin = 7
	else
		skin = #skin
	end
	
	local vars = levelupstats[skin+1]
	
	if p.rpg.level < 999
		p.rpg.level = $ + 1
		p.rpg.xp = 0
		if gametype ~= GT_DCMP
			p.rpg.nextxp = $ + (75 * p.rpg.level)
		else
			p.rpg.nextxp = $ + (25 * p.rpg.level)
		end
		p.rpg.maxhp = $ + (vars[1] * p.rpg.level)
		p.rpg.baseatk = $ + (vars[2] * p.rpg.level)
		p.rpg.basedef = $ + (vars[3] * p.rpg.level)
		p.rpg.hp = p.rpg.maxhp
	end
end

local function P_LevelDown(p)
	local skin = skins[p.mo.skin]
	
	if #skin > 6
		skin = 7
	else
		skin = #skin
	end
	
	local vars = levelupstats[skin+1]
	
	if p.rpg.level > 1
		p.rpg.level = $ - 1
		p.rpg.xp = 0
		if gametype ~= GT_DCMP
			p.rpg.nextxp = $ - (75 * p.rpg.level)
		else
			p.rpg.nextxp = $ - (25 * p.rpg.level)
		end
		p.rpg.maxhp = $ - (vars[1] * p.rpg.level)
		p.rpg.baseatk = $ - (vars[2] * p.rpg.level)
		p.rpg.basedef = $ - (vars[3] * p.rpg.level)
		p.rpg.hp = p.rpg.maxhp
	end
end

COM_AddCommand("levelup", function(p, arg, arg2)
	if p == server
		if p.rpg
			arg2 = tonumber(arg2)
			for i=1,tonumber(arg)
				if players[arg2] ~= nil
					if players[arg2].rpg.level < 999
						P_LevelUp(players[arg2])
					end
				else
					if p.rpg.level < 999
						P_LevelUp(p)
					end
				end
			end
		end
	end
end)

COM_AddCommand("leveldown", function(p, arg, arg2)
	if p == server
		if p.rpg
			arg2 = tonumber(arg2)
			for i=1,tonumber(arg)
				if players[arg2] ~= nil
					if players[arg2].rpg.level > 1
						P_LevelDown(players[arg2])
					end
				else
					if p.rpg.level > 1
						P_LevelDown(p)
					end
				end
			end
		end
	end
end)


COM_AddCommand("swordtype", function(p, arg, arg2)
	if p == server
		if p.rpg
			arg = tonumber(arg)
			arg2 = tonumber(arg2)
			if swords[arg] ~= nil
				if players[arg2] ~= nil
					players[arg2].rpg.swordnum = arg
				else
					p.rpg.swordnum = arg
				end
			else
				CONS_Printf(p, "Invalid Sword ID!")
			end
		end
	end
end)

COM_AddCommand("shieldtype", function(p, arg, arg2)
	if p == server
		if p.rpg
			arg = tonumber(arg)
			arg2 = tonumber(arg2)
			if shields[arg] ~= nil
				if players[arg2] ~= nil
					players[arg2].rpg.shieldnum = arg
				else
					p.rpg.shieldnum = arg
				end
			else
				CONS_Printf(p, "Invalid Shield ID!")
			end
		end
	end
end)

COM_AddCommand("loadgamefloor", function(p, arg)
	if p == server
		if maps[tonumber(arg)] ~= nil
			p.rpg.floor = tonumber(arg)
			for mob in mobjs.iterate()
				if (mob.type == MT_YELLOWSPRING) or (mob.type == MT_EGGMAN_BOX) or (mob.type == MT_ARMAGEDDON_BOX) or (mob.type == MT_FORCE_BOX) or (mob.type == MT_RING_BOX) or (mob.flags & MF_ENEMY) or (mob.flags & MF_BOSS)
					P_RemoveMobj(mob)
				end
			end
			P_BuildMap(p)
			return false
		else
			if arg == "last"
				p.rpg.floor = #maps
				for mob in mobjs.iterate()
					if (mob.type == MT_YELLOWSPRING) or (mob.type == MT_EGGMAN_BOX) or (mob.type == MT_ARMAGEDDON_BOX) or (mob.type == MT_FORCE_BOX) or (mob.type == MT_RING_BOX) or (mob.flags & MF_ENEMY) or (mob.flags & MF_BOSS)
						P_RemoveMobj(mob)
					end
				end
				P_BuildMap(p)
				return false
			else
				CONS_Printf(p, "Invalid floor number!")
			end
		end
	end
end)

addHook("PlayerSpawn", function(p)
	if mapheaderinfo[gamemap].lvlttl == "Dungeon Crawler"
	
		p.pflags = $|PF_NOCLIP
	
		P_RPGVars(p)
		
		if (not p.spawn) and (p == server)
			P_BuildMap(p)
			p.spawn = true
		end
		
		if server.spawncoords ~= nil
			P_TeleportMove(p.mo, server.spawncoords[1], server.spawncoords[2], server.spawncoords[3])
		end
		
		p.pflags = $ & ~PF_NOCLIP
	
	end
end)

addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid
		if p.rpg
			p.powers[pw_shield] = SH_NONE
			p.rings = 1		
			if gametype == GT_DCMP
				if p.rpg.totalmaps and (not p == server)
					if p.rpg.totalmaps > #maps
						maps = p.rpg.tempmaparray
						p.rpg.tempmaparray = {}
						challenges[2][3] = 2*#maps
						challenges[3][3] = (#maps/2)
						challenges[5][3] = (5*#maps)+25
					end
				end
				if p.rpg.waitingicon and p.rpg.waitingicon.valid
					if p.rpg.curwaitfloor ~= p.rpg.floor
						P_RemoveMobj(p.rpg.waitingicon)
						p.rpg.waitingicon = nil
						p.rpg.mpwaiting = false
					else
						p.rpg.waitingicon.scale = FRACUNIT/8
						p.rpg.waitingicon.momz = 0
						P_TeleportMove(p.rpg.waitingicon, p.mo.x, p.mo.y, p.mo.z + p.mo.height + 8*FRACUNIT)
						if p == server
							local playerscompleted = 0
							local totalplayers = 0
							
							for pl in players.iterate
								totalplayers = $ + 1
								if pl.rpg.mpwaiting
									playerscompleted = $ + 1
								end
							end
							
							if playerscompleted == totalplayers
								if maps[p.rpg.floor+1] == nil
									for pl in players.iterate
										G_ExitLevel(1100, 0)
										return true
									end
								end
								for mob in mobjs.iterate()
									if mob.type ~= MT_PLAYER
										P_RemoveMobj(mob)
									end
								end
								for pl in players.iterate
									pl.rpg.floor = $ + 1
									P_RPGVars(pl)
									p.rpg.mpwaiting = false
								end
								P_BuildMap(p)
							end
						end
					end
				end
			end
			if (p.mo.eflags & MFE_SPRUNG)
				if gametype == GT_DCMP
					p.rpg.mpwaiting = true
					if not p.rpg.waitingicon
						p.rpg.curwaitfloor = p.rpg.floor
						p.rpg.waitingicon = P_SpawnMobj(p.mo.x, p.mo.y, p.mo.z + p.mo.height + 8*FRACUNIT, MT_WAITICO)
					end
				else
					if maps[p.rpg.floor+1] == nil
						for pl in players.iterate
							G_ExitLevel(1100, 0)
							return true
						end
					end
					for mob in mobjs.iterate()
						if mob.type ~= MT_PLAYER
							P_RemoveMobj(mob)
						end
					end
					for pl in players.iterate
						pl.rpg.floor = $ + 1
						P_RPGVars(pl)
					end
					P_BuildMap(p)
				end
				
				if p == server
					local playerscompleted = 0
					local totalplayers = 0
					
					for pl in players.iterate
						totalplayers = $ + 1
						if pl.rpg.mpwaiting
							playerscompleted = $ + 1
						end
					end
					
					if playerscompleted == totalplayers
						if maps[p.rpg.floor+1] == nil
							for pl in players.iterate
								G_ExitLevel(1100, 0)
								return true
							end
						end
						for mob in mobjs.iterate()
							if mob.type ~= MT_PLAYER
								P_RemoveMobj(mob)
							end
						end
						for pl in players.iterate
							pl.rpg.floor = $ + 1
							P_RPGVars(pl)
							p.rpg.mpwaiting = false
						end
						P_BuildMap(p)
					end
				end
			end
			if p.rpg.xp >= p.rpg.nextxp
				P_LevelUp(p)
			end
			if not (p.cmd.buttons & BT_CUSTOM3)
				p.c3ready = true
				p.c3tap = false
			elseif p.c3ready
				p.c3ready = false
				p.c3tap = true
			else
				p.c3tap = false
			end
			
			p.rpg.sword = swords[p.rpg.swordnum]
			p.rpg.shield = shields[p.rpg.shieldnum]
			
			if p.rpg.challenge
				if p.rpg.challenge == challenges[2][1]
					if p.rpg.kills > challenges[2][3]
						P_DamageMobj(p.mo, nil, nil, 100, DMG_INSTAKILL)
					end
				elseif p.rpg.challenge == challenges[3][1]
					if p.rpg.level > challenges[3][3]
						P_DamageMobj(p.mo, nil, nil, 100, DMG_INSTAKILL)
					end
				elseif p.rpg.challenge == challenges[4][1]
					p.rpg.swordnum = 1
					p.rpg.shieldnum = 1
				elseif p.rpg.challenge == challenges[5][1]
					if (p.rpg.kills < challenges[5][3]) and (p.rpg.floor == #maps)
						P_DamageMobj(p.mo, nil, nil, 100, DMG_INSTAKILL)
					end
				end
			end
			
			if p.c3tap
				if p.rpg.hp < p.rpg.maxhp
					local inv = p.rpg.inventory
					if #inv > 0
						local item = inv[#inv]
						p.rpg.hp = $+item[2]
						table.remove(inv, #inv)
					else
						S_StartSound(p.mo, sfx_lose, p)
					end
				else
					S_StartSound(p.mo, sfx_lose, p)
				end
			end
			
			if p.rpg.maxhp > 999999*2
				p.rpg.maxhp = 999999*2
			end
			
			if p.rpg.basedef > 99999*2
				p.rpg.basedef = 99999*2
			end
			
			if p.rpg.baseatk > 99999*2
				p.rpg.baseatk = 99999*2
			end
			
			if p.rpg.level > 999
				p.rpg.level = 999
			end
			
			if p.rpg.hp > p.rpg.maxhp
				p.rpg.hp = p.rpg.maxhp
			end
			if p.rpg.hp < 1
				p.rpg.hp = 0
				P_DamageMobj(p.mo, nil, nil, 100, DMG_INSTAKILL)
				S_ChangeMusic("DEATH", false, p)
			end
		end
	end
end)

addHook("MobjSpawn", function(mo)
	if (mo.flags & MF_MONITOR) or (mo.type == MT_YELLOWSPRING)
		mo.scale = FRACUNIT/2
	else
		mo.scale = FRACUNIT/4
	end
	if (mo.flags & MF_ENEMY)
		for p in players.iterate
			if p.rpg
				mo.scale = FRACUNIT/4
				mo.customhp = hptable[mo.type]*p.rpg.floor
				mo.health = 2
			end
		end
	elseif (mo.flags & MF_BOSS)
		for p in players.iterate
			if p.rpg
				if mo.type == MT_CYBRAKDEMON
					mo.scale = FRACUNIT/2
				else
					mo.scale = FRACUNIT/4
				end
				mo.color = SKINCOLOR_RED
				mo.colorized = true
				mo.customhp = hptable[mo.type]*p.rpg.floor
				mo.health = 2
				mo.spawnhp = mo.customhp
			end
		end
	end
end)

addHook("MobjThinker", function(mo)
	if (mo.flags & MF_BOSS)
		mo.health = 2
	end
end)

addHook("MobjDamage", function(mo, inf, src, dmg, dmgtype)
	if mo and mo.valid
		if src and src.valid
			if mo.player
				if mo.player.rpg
					if (src.flags & MF_ENEMY) or (src.flags & MF_BOSS)
						local dmg = (dmgtable[src.type] * mo.player.rpg.floor) - (mo.player.rpg.basedef + mo.player.rpg.shield[2])
						if dmg > 0
							mo.player.rpg.hp = $ - dmg
						else
							S_StartSound(mo, sfx_s3k81, mo.player)
							P_InstaThrust(src, mo.angle, 5*FRACUNIT)
							return false
						end
					else
						if dmgtype == DMG_INSTAKILL
							return true
						else
							mo.player.rpg.hp = $ - (P_RandomRange(2, 5) * mo.player.rpg.floor)
						end
					end
				end
			end
		end
	end
end, MT_PLAYER)

addHook("MobjDeath", function(mo, inf, src)
	if (mo.flags & MF_ENEMY)
		if src and src.valid
			if src.type == MT_PLAYER
				if src.player
					if src.player.rpg
						src.player.rpg.xp = $ + (P_RandomRange(10,15) * src.player.rpg.floor)
						src.player.rpg.kills = $ + 1
					end
				end
			end
		end
	end
end)

addHook("MobjDamage", function(mo, inf, src)
	if (mo.flags & MF_ENEMY) or (mo.flags & MF_BOSS)
		if (src and src.valid) and (mo and mo.valid)
			if src.player
				if src.player.rpg
					mo.customhp = $ - (src.player.rpg.sword[2] + src.player.rpg.baseatk)
					
					if mo.customhp < 1
						mo.customhp = 0
						if mo and mo.valid
							if (mo.flags & MF_BOSS) or (mo.type == MT_DRAGONBOMBER)
								src.player.rpg.xp = $ + (P_RandomRange(200,250) * src.player.rpg.floor)
								mo.state = S_DEATHSTATE
								P_SpawnMobj(mo.x, mo.y, mo.z, MT_YELLOWSPRING)
								P_RemoveMobj(mo)
							else
								P_KillMobj(mo, nil, src)
							end
						end
					end
					
					if mo and mo.valid
						if (mo.flags & MF_ENEMY) and (mo.type ~= MT_DRAGONBOMBER)
							return true
						end
					end
					
				end
			end
		end
	end
end)

addHook("MobjDeath", function(mo, inf, src)
	if src and src.valid
		if src.type == MT_PLAYER
			if src.player and src.player.valid
				if src.player.rpg
					if src.player.rpg.swordnum < #swords
						src.player.rpg.swordnum = $ + 1
					end
					
					local block = blockToSector(mo.x, mo.y)
					src.player.rpg.map[block.tag] = 0		
				end
			end
		end
	end
end, MT_ARMAGEDDON_BOX)

addHook("MobjDeath", function(mo, inf, src)
	if src and src.valid
		if src.type == MT_PLAYER
			if src.player and src.player.valid
				if src.player.rpg
					local inv = src.player.rpg.inventory
					if #inv < 5
						if src.player.rpg.floor < #maps - ((#maps/2) + (#maps/4))
							table.insert(inv, potions[P_RandomRange(1,2)])
						elseif src.player.rpg.floor < #maps - (#maps/4)
							table.insert(inv, potions[P_RandomRange(1,3)])
						else
							table.insert(inv, potions[P_RandomRange(1,4)])
						end
					end
							
					local block = blockToSector(mo.x, mo.y)
					src.player.rpg.map[block.tag] = 0		
				end
			end
		end
	end
end, MT_RING_BOX)

addHook("MobjDeath", function(mo, inf, src)
	if src and src.valid
		if src.type == MT_PLAYER
			if src.player and src.player.valid
				if src.player.rpg
					if src.player.rpg.shieldnum < #shields
						src.player.rpg.shieldnum = $ + 1
					end
					
					local block = blockToSector(mo.x, mo.y)
					src.player.rpg.map[block.tag] = 0	
				end
			end
		end
	end
end, MT_FORCE_BOX)

addHook("MobjDeath", function(mo, inf, src)
	if src and src.valid
		if src.type == MT_PLAYER
			if src.player and src.player.valid
				if src.player.rpg
					src.player.rpg.hp = $ - P_RandomRange(5,15)*src.player.rpg.floor
				end
			end
		end
	end
end, MT_EGGMAN_BOX)

hud.add(function(v, p)
		if mapheaderinfo[gamemap].lvlttl == "Dungeon Crawler"
			if p.rpg
				hud.disable("lives")
				hud.disable("score")
				hud.disable("rings")
				hud.disable("time")
				
				if gametype == GT_DCMP
					if p.rpg.mpwaiting
						v.drawString(4, 33, "Waiting on:", nil, "thin")
						local playerthing = 1
						for pl in players.iterate
							if not pl.rpg.mpwaiting
								v.drawString(4, 37+(playerthing*4), pl.name, skincolors[pl.mo.color].chatcolor, "small")
								playerthing = $ + 1
							end
						end
					end
				end
				
				v.drawString(4, 4, "\x85HP: \x80"+p.rpg.hp+"/"+p.rpg.maxhp+" \x83Lives: \x80"+p.lives)
				v.drawFill(4, 14, ((90*p.rpg.maxhp/p.rpg.maxhp*90)/90)+4, 8, 44)
				v.drawFill(6, 16, (p.rpg.hp*90/p.rpg.maxhp*90)/90, 4, 33)
				if p.rpg.challenge == challenges[3][1]
					if p.rpg.level < (challenges[3][3]/2) - (challenges[3][3]/8)
						v.drawString(4, 23, "LV. \x83"+p.rpg.level+"\x80     XP: "+p.rpg.xp+"/"+p.rpg.nextxp, nil, "small")
					elseif p.rpg.level < challenges[3][3] - (challenges[3][3]/4)
						v.drawString(4, 23, "LV. \x82"+p.rpg.level+"\x80     XP: "+p.rpg.xp+"/"+p.rpg.nextxp, nil, "small")
					elseif p.rpg.level < challenges[3][3]
						v.drawString(4, 23, "LV. \x85"+p.rpg.level+"\x80     XP: "+p.rpg.xp+"/"+p.rpg.nextxp, nil, "small")
					else
						v.drawString(4, 23, "LV. \x86"+p.rpg.level+"\x80     XP: "+p.rpg.xp+"/"+p.rpg.nextxp, nil, "small")
					end
				else
					v.drawString(4, 23, "LV. "+p.rpg.level+"     XP: "+p.rpg.xp+"/"+p.rpg.nextxp, nil, "small")
				end
				v.drawFill(4, 27, (100*p.rpg.nextxp/p.rpg.nextxp*100)/100, 2, 8)
				v.drawFill(4, 27, (p.rpg.xp*100/p.rpg.nextxp*100)/100, 2, 129)
				for mo in mobjs.iterate()
					if (mo.flags & MF_BOSS)
						v.drawString(160-49, 180-4, "\x85 BOSS:")
						v.drawFill(160-45, 200-16, ((90*mo.spawnhp/mo.spawnhp*90)/90)+4, 8, 44)
						v.drawFill(160-43, 200-14, (mo.customhp*90/mo.spawnhp*90)/90, 4, 33)
					end
				end
				v.drawFill((320-64),16,4*12,4*12,0)
				v.drawString(320-40, 4, "Floor "+p.rpg.floor+"/"+#maps, nil, "thin-center")
				for r=1,10
					for c=1,10
						local block = blockToSector(c, r)
						if (p.rpg.map[block.tag] == 0) or (p.rpg.map[block.tag] == 9)
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,31)
						elseif p.rpg.map[block.tag] == 1
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,0)
						elseif p.rpg.map[block.tag] == 2
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,54)
						elseif p.rpg.map[block.tag] == 3
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,153)
						elseif p.rpg.map[block.tag] == 4
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,115)
						elseif p.rpg.map[block.tag] == 5
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,35)
						elseif p.rpg.map[block.tag] == 8
							v.drawFill((320-64)+c*4,(5*12)-r*4,4,4,182)
						end
						v.drawFill((320-64)+(((p.mo.x/FRACUNIT/64)+1)*4),(5*12)-(((p.mo.y/FRACUNIT/64)+1)*4),4,4,73)
					end
				end
				
				v.drawFill(0, 200-64, 86, 64, 0)
				v.drawFill(0, 200-62, 84, 62, 31)
				v.drawFill(320-86, 200-64, 86, 64, 0)
				v.drawFill(320-84, 200-62, 84, 62, 31)
				if p.rpg.challenge == challenges[2][1]
					if p.rpg.kills < (challenges[2][3]/2) - (challenges[2][3]/4)
						v.drawString(1, 200-72, "Enemies Killed: \x83"+p.rpg.kills, nil, "thin")
					elseif p.rpg.kills < (challenges[2][3]/2) + (challenges[2][3]/4)
						v.drawString(1, 200-72, "Enemies Killed: \x82"+p.rpg.kills, nil, "thin")
					elseif p.rpg.kills < challenges[2][3] 
						v.drawString(1, 200-72, "Enemies Killed: \x85"+p.rpg.kills, nil, "thin")
					else
						v.drawString(1, 200-72, "Enemies Killed: \x86"+p.rpg.kills, nil, "thin")
					end
				elseif p.rpg.challenge == challenges[5][1]
					if p.rpg.kills < (challenges[5][3]/4) - (challenges[5][3]/8)
						v.drawString(1, 200-72, "Enemies Killed: \x86"+p.rpg.kills, nil, "thin")
					elseif p.rpg.kills < (challenges[5][3]/2) - (challenges[5][3]/8)
						v.drawString(1, 200-72, "Enemies Killed: \x85"+p.rpg.kills, nil, "thin")
					elseif p.rpg.kills < challenges[5][3]
						v.drawString(1, 200-72, "Enemies Killed: \x82"+p.rpg.kills, nil, "thin")
					elseif p.rpg.kills >= challenges[5][3]
						v.drawString(1, 200-72, "Enemies Killed: \x83"+p.rpg.kills, nil, "thin")
					end
				else
					v.drawString(1, 200-72, "Enemies Killed: "+p.rpg.kills, nil, "thin")
				end
				v.drawString(320-83, 200-60, p.name, nil, "thin")
				v.drawString(320-83, 200-40, "ATK: "+tostring(tonumber(p.rpg.baseatk)+tonumber(p.rpg.sword[2]))+" ("+p.rpg.baseatk+")", nil, "thin")
				v.drawString(320-83, 200-30, "DEF: "+tostring(tonumber(p.rpg.basedef)+tonumber(p.rpg.shield[2]/3))+" ("+p.rpg.basedef+")", nil, "thin")
				v.drawString(320-83, 200-20, "WPN: "+p.rpg.sword[1], nil, "thin")
				v.drawString(320-83, 200-10, "SHD: "+p.rpg.shield[1], nil, "thin")
				
				for i=1,5
					if p.rpg.inventory[i] ~= nil
						local item = p.rpg.inventory[i]
						v.drawString(1, (152-24)+(i*12), item[1], nil, "thin") 
					end
				end
			end
		else
			hud.enable("lives")
		end
end)