function stage.load(map)
	if stage.loaded stage.unload() end

	if not stage.header[map]
		-- TODO: If the header isn't found, try loading it from a file by name
		console.print("WARNING: Map changed failed, stage header is missing for '"..map.."'.")
		return
	end

	local h = stage.header[map]
	if #h.title > 0
		console.debug("Loading '"..h.file.."' ("..h.title..")")
	else
		console.debug("Loading '"..h.file.."'")
	end

	camera = {
		x = 168, y = 128, -- Camera position
		slide_x = 0, -- X position in front of or behind the target to focus on, used to focus ahead of the player.
		focus = nil, -- Entity the camera is focused on.
		speed = 16 -- Camera focus speed
	}

	bk = {
		move = 4, -- Background movement/drawing type
		ticks = 0 -- Background movement ticks
	}

	if h.tiles ~= '0'
		if io.exists("Stage/Prt"..h.tiles.."2x")
			graphics[Tiles] = pbm.load("wiidata/Stage/Prt"..h.tiles.."2x",1)
		else
			graphics[Tiles] = pbm.load("Stage/Prt"..h.tiles)
		end
	end

	do
		local pxa = io.open("Stage/"..h.tiles..".pxa",IO.READ,ENDIAN.LITTLE)
		pxa:seek(0,SEEK.END)
		local len = pxa:tell()
		pxa:seek(0,SEEK.SET)
		stage.tileflags = pxa:getstr(len,true)
		pxa:close()
	end

	bk.move = h.bkMove
	graphics[bkImg] = pbm.load("bk"..h.bkImg)
	if h.npc1 ~= '0'
		graphics[Npc1] = pbm.load("Npc/Npc"..h.npc1)
	end
	if h.npc2 ~= '0'
		graphics[Npc2] = pbm.load("Npc/Npc"..h.npc2)
	end
	--console.debug("Stage graphics loaded.")

	do
		local pxm = io.open("Stage/"..h.file..".pxm",IO.READ,ENDIAN.LITTLE)
		local header = pxm:getstr(0x04,true)
		if header ~= "PXM\x10"
			console.print("WARNING: PXM header is '"..header.."'")
		end
		stage.width = pxm:getnum(2,UNSIGNED)
		stage.height = pxm:getnum(2,UNSIGNED)
		stage.tiles = pxm:getstr(stage.width*stage.height,true)
		pxm:close()
		console.debug("Stage tiles loaded.")
	end

	if stage.width <= 21*16 and stage.height <= 16*16
		bk.color = 0x000000
	end

	stage.time = 0
	stage.ents = {}
	stage.players = {}
	stage.loaded = true
end

function stage.unload()
	stage.loaded = false
	fade.reset()

	graphics[Tiles] = nil
	graphics[bkImg] = nil
	graphics[Npc1] = nil
	graphics[Npc2] = nil

	camera = nil
	bk = nil
	stage.tiles = nil
	stage.width = nil
	stage.height = nil
	stage.ents = nil
	stage.players = nil
end

-- The camera thinker. Makes the camera move.
local function camThink(self)
	-- Determine the ideal position for the camera to be at!
	local target = camera.focus or self
	local target_x = math.floor(target.x)
	local target_y = math.floor(target.y)
	if camera.focus
		camera.slide_x = 0
	else
		if self.flip
			if camera.slide_x < 64
				camera.slide_x = camera.slide_x + 1
			end
			target_x = target_x + camera.slide_x
		else
			if camera.slide_x > -64
				camera.slide_x = camera.slide_x - 1
			end
			target_x = target_x + camera.slide_x
		end
	end

	-- The actual camera movement towards the target position!
	camera.x = camera.x + (target_x - camera.x) / camera.speed
	camera.y = camera.y + (target_y - camera.y) / camera.speed

	-- This stuff locks the camera to the map bounds.
	if camera.x-160 < 8
		camera.x = 160+8
	elseif camera.x+160 > stage.width*16-8
		camera.x = stage.width*16-8-160
	end
	if camera.y-120 < 8
		camera.y = 120+8
	elseif camera.y+120 > stage.height*16-8
		camera.y = stage.height*16-8-120
	end

	-- TODO: Apply earthquake here. 8)
end

function stage.think()
	if not stage.loaded return end
	stage.time = stage.time + 1
	for k,v in pairs(stage.ents)
		NPC.think(v)
	end
	for id,self in pairs(stage.players)
		-- Everyone gets animated the same.
		if self.skin.anims[self.anim] and self.skin.anims[self.anim][self.frame][3] >= 0
			if self.ticks >= self.skin.anims[self.anim][self.frame][3]
				self.frame = self.frame+1
				if not self.skin.anims[self.anim][self.frame]
					self.frame = 1
				end
				self.ticks = 0
			else
				self.ticks = self.ticks + 1
			end
		end

		if id == 0
			self.skin.think(self)
		else
			-- No fancey thinker. No gravity.
			-- Only basic continuation of movement until stopped by collision.
		end
		-- Do the collisions here, no walk through walls skins.
		local mx,my = stage.doCollisions(self,(self.mx / 0x200),(self.my / 0x200))
		self.mx,self.my = math.floor(mx*0x200),math.floor(my*0x200)

		if id == 0
			-- Always let the server know what you're doing if it changes!
			if math.floor(self.x / 16) ~= self.net.x or math.floor(self.y / 16) ~= self.net.y
			or self.mx ~= self.net.mx or self.my ~= self.net.my
			or self.anim ~= self.net.anim or self.flip ~= self.net.flip
				net.send_move(self)
			end
		end
	end
	if stage.players[0] or camera.focus
		camThink(stage.players[0])
	end
end

local function drawTiles(screen,cx,cy,fg)
	if not graphics[Tiles] return end
	local tw = graphics[Tiles]:w()
	for y = 0,240/16
		if math.floor(cy/16)+y > stage.height-1 break end -- draw nothing to the bottom (safety precaution)
		for x = 0,320/16
			if math.floor(cy/16)+y < 0 break end -- draw nothing to the top (safety precaution)
			if math.floor(cx/16)+x > stage.width-1 break end -- draw nothing to the right (safety precaution)
			if math.floor(cx/16)+x >= 0 -- draw nothing to the left (safety precaution)
				local num = (math.floor(cx/16)+x+(math.floor(cy/16)+y)*stage.width)+1
				local tile = stage.tiles:byte(num)
				local flags = stage.tileflags:byte(tile+1)
				if (flags & 0x40 ~= 0) ~= fg
					continue
				end
				local tx = tile*16
				local ty = math.floor(tx/tw)*16
				tx = tx%tw
				screen.draw(graphics[Tiles],{tx,ty,16,16},{(x*16-cx%16),(y*16-cy%16)})
				if flags == 0x43
					screen.draw(graphics[NpcSym],{256,48,16,16},{(x*16-cx%16),(y*16-cy%16)})
				end
			end
		end
	end
end

function stage.draw(screen)
	if not stage.loaded return end
	local cx = camera.x - 160
	local cy = camera.y - 120
	drawTiles(screen,cx,cy,false)
	for k,v in pairs(stage.ents)
		NPC.draw(v,screen,cx,cy)
	end
	for k,v in pairs(stage.players)
		assert(v.skin.anims and v.skin.sheet)
		local anim = v.anim
		if not v.skin.anims[anim]
			anim = ANIM.STAND
		end
		local frame = v.skin.anims[anim][v.frame][1]
		if v.flip
			frame = v.skin.anims[anim][v.frame][2] or frame
		end
		local fw = v.skin.display[BBOX.LEFT]+v.skin.display[BBOX.RIGHT]
		local fh = v.skin.display[BBOX.TOP]+v.skin.display[BBOX.BOTTOM]
		screen.draw(v.skin.sheet,
			{frame[1],frame[2],fw,fh},
			{(math.floor(v.x)-v.skin.display[BBOX.LEFT])-cx,(math.floor(v.y)-v.skin.display[BBOX.TOP])-cy})
	end
	drawTiles(screen,cx,cy,true)
end
