--LevelOS.maximize()
lOS.sysUpdate(false)
local function thegame()
local sl = shapescape.getSlides()
LevelOS.self.window.winMode = "fullscreen"
os.queueEvent("term_resize")
os.queueEvent("term_resize")
local slide = shapescape.getSlide()
local strands = {}
local f = 0.4
for k,v in pairs(colors) do
    if type(v) == "number" then
        local r,g,b = term.nativePaletteColor(v)
        term.setPaletteColor(v,r*f,g*f,b*f)
    end
end
cols = {colors.orange,colors.purple,colors.black,colors.magenta,colors.black}
--term.setPaletteColor(colors.magenta,0.00,0.00,0.00)
--term.setPaletteColor(colors.white,1,11)
local col = {0.3*1.3,0.6*1.3,0.7*1.3}
for c=1,#cols do
    local v = (#cols-(c))/#cols
    term.setPaletteColor(cols[c],col[1]*v,col[2]*v,col[3]*v)
end
term.setPaletteColor(colors.pink,term.getPaletteColor(colors.white))
term.setPaletteColor(colors.magenta,0.1,0.1,0.1)
term.setPaletteColor(colors.white,1,1,1)
local bgpalette = {}
for c=0,15 do
	bgpalette[2^c] = {term.getPaletteColor(2^c)}
end
local pth = fs.getDir(LevelOS.self.window.path)
shell.run(fs.combine(pth,"map_background.lua"))
while sl.cSlide == 1 do
	os.pullEvent()
end
os.sleep(0.5)
sl.timeF = 0
--[[local bWin = sl[1].objs[1].window
local bW,bH = bWin.getSize()
for l=1,bH do
	term.setCursorPos(1,l)
	term.blit(bWin.getLine(l))
end]]
os.queueEvent("fakeEvent")
os.pullEvent()
gen = require("gen")
dict = require("dictionary")
local snow = #dict
assets = require("assets")
os.sleep(0.1)
term.setPaletteColor(colors.magenta,118/255,92/255,72/255)
term.setPaletteColor(colors.purple,71/255,103/255,28/255)
term.setPaletteColor(colors.pink,238/255,195/255,154/255)
term.setPaletteColor(colors.orange,0.45,0.45,0.45)
local w,h = term.getSize()
local oterm = term.current()
local bwin = window.create(term.current(),1,1,w,h,false)
local useBuffer = true
local map
local rmap = {}
local objects = {}
sl.objects = objects
local ogrid = {}
local sTime = os.epoch("utc")
local debugobjects = false
local zoom = 1
local player
local outfits = {colors.brown,colors.lightGray,colors.black}
local particles = {}
local olines = {}
local pID = 1
local lifeform
local specialdebug = false
local timerlen = 0.1
if not jit then
	timerlen = 0.2
end
local debugtbl = {
	objects = function(val)
		specialdebug = not not val
	end,
	setTimerLength = function(len)
		if type(len) ~= "number" then return end
		timerlen = len
	end,
}
function readonly(str,t,k,v)
	error("Attempt to modify field '"..tostring(k).."' in read-only table '"..str.."'.",3)
end
local preloaded = false
local data = {lifeforms={},resources={wood=0,food=0,metal=0,stone=0},objectives={},houses={},tier=1}
local directions = {
	["goForward"] = {x=0,y=-1},
	["goBack"] = {x=0,y=1},
	["goLeft"] = {x=-1,y=0},
	["goRight"] = {x=1,y=0},
}

local bActions = {}
for k,v in pairs(directions) do
	bActions[k] = function(self,amount)
		if amount and (type(amount) ~= "number" or amount < 1 or amount%1 ~= 0) then
			error("Invalid amount entered! Expected integer bigger than 1, got "..tostring(amount),2)
		end
		local i = amount or 1
		self.xVel = v.x/3
		local gX = self.x+i*v.x
		local gY = self.y+i*v.y
		self.yVel = v.y/3
		if k == "goRight" then
			self.hD = "right"
		elseif k == "goLeft" then
			self.hD = "left"
		end
		local f = 1
		if gX < self.x or gY < self.y then
			f = -1
		end
		while gX*f > self.x*f or gY*f > self.y*f do
			os.pullEvent()
			if self.yVel == 0 and self.xVel == 0 then
				return false,"obstructed"
			end
		end
		self.xVel = 0
		self.yVel = 0
		self.y = gY
		self.x = gX
		return true
	end
end
bActions["Flee short"] = function(self)
	local dirs = {"goForward","goLeft","goRight","goBack"}
	for t=1,3 do
		bActions[dirs[math.random(1,4)]](self,math.random(1,10))
	end
end
bActions["Flee long"] = function(self)
	local dirs = {"goForward","goLeft","goRight","goBack"}
	for t=1,10 do
		bActions[dirs[math.random(1,4)]](self,math.random(2,5))
	end
end
local foodval = {
	["cow"] = 5,
	["peacock"] = 1,
	["sheep"] = 3,
	["rat"] = 0,
	["llama"] = 3,
}
if sl.gamedata then
	data = sl.gamedata
	map = data.map
	for k,v in pairs(data.lifeforms) do
		table.insert(objects,v)
	end
	for k,v in pairs(data.houses) do
		table.insert(objects,v)
		v[1] = assets.structures.tent[1]
		local struct = v[1]
		local w,h = #struct[1][1],#struct
		local rx,ry = v.x-math.floor(w/2),v.y-(h-1)
		v.id = #objects
		for cX=rx,rx+(w-1) do
			for cY=ry+2,ry+(h-1) do
				ogrid[cX..","..cY] = v
			end
		end
	end
	for y=1,#map[1] do
		for x=1,#map do
			if not dict[map[x][y]] then
				if map[x][y] > snow then
					dict[map[x][y]] = {name=dict[snow].name,color=dict[snow].color,color2=colors.lightGray,height=dict[snow].height+(map[x][y]-snow)}
				else
					dict[map[x][y]] = dict[1]
				end
			end
			local s = dict[map[x][y]]
			if s.name == "forest" then
				if math.random(1,20) == 7 and not ogrid[x..","..y] then
					--lUtils.renderImg(assets.terrain.tree1[math.random(1,#assets.terrain.tree1)],x-1,y-s.height-2,nil,true)
					table.insert(objects,{assets.terrain.tree1[math.random(1,#assets.terrain.tree1)],type="tree",health=1,oX=1,oY=2,x=x,y=y,wood=math.random(1,5)})
					ogrid[x..","..y] = objects[#objects]
					objects[#objects].id = #objects
				end
			end
		end
	end
	preloaded = true
else
	sl.gamedata = data
end
local devmode = false
local standardvars = {}
local function checkTier(tier)
	if tier > data.tier and not devmode then
		error("You can't use this function yet.",3)
	end
end
local function checkEnv(l)
	if not l.env then
		if not l.genEnv then
			setmetatable(l,{__index=lifeform})
		end
		l:genEnv()
	end
end
local goals = {
	{
		main = "Introduction",
		{
			txt="Summon a lifeform and make it speak",
			goals={
				{
					func=function()
						return #data.lifeforms > 0
					end,
				},
				{
					func=function()
						return #data.lifeforms > 0 and #data.lifeforms[1].speech > 0
					end,
				},
			},
		},
	},
	{
		main = "Variables",
		{
			txt="Create a string",
			goals={
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							
							for k,v in pairs(l.env) do
								if type(v) == "string" and not standardvars[k] then
									return true
								end
							end
						end
						return false
					end,
				}
			}
		},
		{
			txt="Create a number",
			goals={
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							checkEnv(l)
							for k,v in pairs(data.lifeforms[i].env) do
								if type(v) == "number" and not standardvars[k] then
									return true
								end
							end
						end
						return false
					end,
				}
			}
		},
		{
			txt="Create a boolean",
			goals={
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							checkEnv(l)
							for k,v in pairs(l.env) do
								if type(v) == "boolean" and not standardvars[k] then
									return true
								end
							end
						end
						return false
					end,
				}
			}
		},
	},
	{
		main = "Tables",
		{
			txt="Create a numerical table (array) with at least 2 values",
			goals={
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							checkEnv(l)
							for k,v in pairs(l.env) do
								if type(v) == "table" and not standardvars[k] then
									return true
								end
							end
						end
						return false
					end,
				},
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							checkEnv(l)
							for k,v in pairs(l.env) do
								if type(v) == "table" and #v >= 2 and not standardvars[k] then
									return true
								end
							end
						end
						return false
					end,
				}
			}
		},
		{
			txt="Create a table with string indexes",
			goals={
				{
					func=function()
						for i,l in pairs(data.lifeforms) do
							checkEnv(l)
							for k,v in pairs(l.env) do
								if type(v) == "table" and not standardvars[k] then
									for k1,v1 in pairs(v) do
										if type(k1) == "string" then
											return true
										end
									end
								end
							end
						end
						return false
					end,
				}
			}
		}
	},
	{
		main = "Survival",
		{
			txt="Collect wood and make shelter",
			goals={
				{
					func=function()
						return data.resources.wood > 0
					end,
				},
				{
					func=function()
						return #data.houses > 0
					end,
				},
			}
		},
		{
			txt="Hunt an animal for food",
			goals={
				{
					func=function()
						return data.resources.food > 0
					end,
				},
			}
		},
	},
}
local objectives = goals[1]
local objpresent = false
if preloaded and sl.gamedata.objectives then
	objpresent = true
end
for k,v in ipairs(goals) do
	v.id = k
	if objpresent then
		v.done = sl.gamedata.objectives[k].done
		for k1,v1 in ipairs(v) do
			v1.done = sl.gamedata.objectives[k][k1].done
			for k2,v2 in ipairs(v1.goals) do
				v2.done = sl.gamedata.objectives[k][k1][k2]
			end
		end
		objectives = goals[data.tier]
	else
		if not sl.gamedata.objectives then
			sl.gamedata.objectives = {}
		end
		sl.gamedata.objectives[k] = {}
		for k1,v1 in ipairs(v) do
			sl.gamedata.objectives[k][k1] = {}
			for k2,v2 in ipairs(v1.goals) do
				sl.gamedata.objectives[k][k1][k2] = false
			end
		end
	end
end
lifeform = {}
lifeform.__index = lifeform
local hDirs = {"left","right"}

local function pathfind(start,destination,max)
	if not start then error("Expected table in #1",2) end
	start.x = math.floor(start.x+0.5)
	start.y = math.floor(start.y+0.5)
	_G.debugstart = start
	if not map[start.x] then
		error("No map["..start.x.."]",2)
	end
	if not map[start.x][start.y] then
		error("No map["..start.x.."]["..start.y.."]",2)
	end
	if not dict[map[start.x][start.y]] then
		error("No dict["..map[start.x][start.y].."]",2)
	end
	local mdata = {[start.x..","..start.y]={had=false,height=dict[map[start.x][start.y]].height,x=start.x,y=start.y}}
	frontier = {mdata[start.x..","..start.y]}
	local directions = { -- inverse cuz yknow its where u came from not where ur going
		["goForward"] = {x=0,y=-1},
		["goBack"] = {x=0,y=1},
		["goLeft"] = {x=-1,y=0},
		["goRight"] = {x=1,y=0},
		[""] = {x=0,y=0},
	}
	local dirOrder = {
		"","goForward","goBack","goRight","goLeft"
	}
	local starttime = os.epoch("utc")
	for step=1,(max or 100) do
		local stop = false
		local ofrontier = {}
		local nfrontier = {} -- iterate through and add all to main frontier (which is cleared beforehand)
		for i=1,#frontier do
			ofrontier[i] = frontier[i]
		end
		for i,n in ipairs(ofrontier) do
			if type(n.had) == "number" and n.had < n.steps then
				n.had = n.had+1
				table.insert(nfrontier,n)
			else
				local minC = 2
				if n.x == start.x and n.y == start.y then
					minC = 1
				end
				for c=minC,5 do
				--for k,v in pairs(directions) do
					local k = dirOrder[c]
					local v = directions[k]
					if os.epoch("utc") >= starttime+5000 then
						return false
					end
					local x,y = n.x+v.x,n.y+v.y
					local index = x..","..y
					if map[x] and map[x][y] then
						local bl = dict[map[x][y]].height
						local node = mdata[index]
						if bl < n.height+2 and not node then
							local steps = 1
							if bl <= 0 then
								steps = 6
							elseif math.abs(bl-n.height) == 1 then
								if bl < 3 then
									steps = 3
								else
									steps = 5
								end
							elseif bl-n.height == 0 then
								if bl >= 4 then
									steps = 2
								end
							end
							mdata[index] = {had=1,camefrom=k,height=bl,steps=steps,x=x,y=y,stepadded=step}
							table.insert(nfrontier,mdata[index])
						end
						if type(destination) == "string" and destination == "emptySpot" and bl == 2 then
							local iW,iH = #assets.structures.construction[1][1][1],#assets.structures.construction[1]
							local rx,ry = x-math.floor(iW/2),y-(iH-1)
							local continue = true
							for cX=rx,rx+(iW-1) do
								for cY=ry+2,ry+(iH-1) do
									local index = cX..","..cY
									if not (dict[map[cX][cY]].height == 2 and not (ogrid[index] and (ogrid[index].type == "tree" or ogrid[index].type == "structure"))) then
										continue = false
										break
									end
								end
							end
							if continue then
								return {x=x,y=y}
							end
						elseif (type(destination) == "table" and destination.x == (x) and destination.y == (y)) or (type(destination) == "string" and ogrid[index] and ogrid[index].type == destination) then
							stop = true
							if destination == "tree" then
								local t = ogrid[index]
								return {id=t.id,x=t.x,y=t.y,type="tree"}
							elseif destination == "animal" then
								local t = ogrid[index]
								return {id=t.id,x=t.x,y=t.y,type=t.texture}
							end
						end
					end
				end
			end
		end
		for t=1,#frontier do
			frontier[t] = nil
		end
		for t=1,#nfrontier do
			frontier[t] = nfrontier[t]
		end
		if stop then break end
	end
	if type(destination) == "table" and mdata[destination.x..","..destination.y] then
		local route = {}
		local x,y = destination.x,destination.y
		_G.dRoute = route
		if not (x == start.x and y == start.y) then
			while true do
				local cf = mdata[x..","..y].camefrom
				--[[if route[1] and route[1][1] == cf then
					route[1][2] = route[1][2]+1
				else]]
					table.insert(route,1,{cf,1,mdata[x..","..y]})
				--end
				local d = directions[cf]
				x = x+(d.x*-1)
				y = y+(d.y*-1)
				if x == start.x and y == start.y then
					break
				end
			end
		end
		return route
	else
		_G.dMDATA = mdata
		return false
	end
end

local function distance(obj1,obj2)
	return ((obj2.x-obj1.x)^2+(obj2.y-obj1.y)^2)^0.5
end

function lifeform.genEnv(self)
	self.env = {
		print = function(...)
			--[[if duration and type(duration) ~= "number" then
				error("Duration needs to be a number!",2)
			end]]
			local dur = duration or 3
			local args = {...}
			for t=1,#args do
				args[t] = tostring(args[t])
			end
			local str = table.concat(args," ")
			table.insert(self.speech,{msg=tostring(str),dur=os.epoch("utc")+dur*1000})
		end,
		worshipTheRatGods = function()
			self.rat = true
		end,
		goForward = function(amount)
			checkTier(3)
			if amount and (type(amount) ~= "number" or amount < 1 or amount%1 ~= 0) then
				error("Invalid amount entered! Expected integer bigger than 1, got "..tostring(amount),2)
			end
			local i = amount or 1
			self.xVel = 0
			local gY = self.y-i
			self.yVel = -1/2
			self.vD = "back"
			while self.y > gY do
				os.pullEvent()
				if self.yVel == 0 then
					return false,"obstructed"
				end
			end
			self.yVel = 0
			self.y = gY
			return true
		end,
		goBack = function(amount)
			checkTier(3)
			if amount and (type(amount) ~= "number" or amount < 1 or amount%1 ~= 0) then
				error("Invalid amount entered! Expected integer bigger than 1, got "..tostring(amount),2)
			end
			local i = amount or 1
			self.xVel = 0
			local gY = self.y+i
			self.yVel = 1/2
			self.vD = "forward"
			while self.y < gY do
				os.pullEvent()
				if self.yVel == 0 then
					return false,"obstructed"
				end
			end
			self.yVel = 0
			self.y = gY
			return true
		end,
		goLeft = function(amount)
			checkTier(3)
			if amount and (type(amount) ~= "number" or amount < 1 or amount%1 ~= 0) then
				error("Invalid amount entered! Expected integer bigger than 1, got "..tostring(amount),2)
			end
			local i = amount or 1
			self.yVel = 0
			local gX = self.x-i
			self.xVel = -1/2
			self.hD = "left"
			while self.x > gX do
				os.pullEvent()
				if self.xVel == 0 then
					return false,"obstructed"
				end
			end
			self.xVel = 0
			self.x = gX
			return true
		end,
		goRight = function(amount)
			checkTier(3)
			if amount and (type(amount) ~= "number" or amount < 1 or amount%1 ~= 0) then
				error("Invalid amount entered! Expected integer bigger than 1, got "..tostring(amount),2)
			end
			local i = amount or 1
			self.yVel = 0
			local gX = self.x+i
			self.xVel = 1/2
			self.hD = "right"
			while self.x < gX do
				os.pullEvent()
				if self.xVel == 0 then
					return false,"obstructed"
				end
			end
			self.xVel = 0
			self.x = gX
			return true
		end,
		walkTo = function(x,y)
			checkTier(3)
			if type(x) == "table" then
				local o = objects[x.id]
				while o and distance(self,o) > 2 do
					x.x,x.y = o.x-self.x,o.y-self.y
					local tx,ty = math.floor(self.x+0.5),math.floor(self.y+0.5)
					local route = pathfind({x=tx,y=ty},{x=math.floor(o.x+0.5),y=math.floor(o.y+0.5)},500)
					if distance(self,o) <= 2 then
						break
					end
					if not route then _G.debugcoords = {{x=tx,y=ty},{x=o.x,y=o.y},pathfind=pathfind} error("Out of range (max 500 steps)",2) end
					self.env[route[1][1]](route[1][2])
				end
			else
				local route = pathfind({x=self.x,y=self.y},{x=self.x+x,y=self.y+y})
				if not route then error("Out of range (max 100 steps)",2) end
				for t=1,#route do
					self.env[route[t][1]](route[t][2])
				end
			end
		end,
		chop = function(tree)
			checkTier(3)
			local o = objects[tree.id]
			if distance(self,o) > 3.5 then
				self.env.walkTo(tree.x+2,tree.y+1)
			end
			while o.wood > 0 do
				self.env.sleep(0.5)
				o.oY = o.oY-1
				self.env.sleep(0.1)
				o.oY = o.oY+1
				data.resources.wood = data.resources.wood+1
				o.wood = o.wood-1
				self.hunger = self.hunger-1
				if self.hunger < 0 then
					self.health = self.health+self.hunger
					self.hurt = true
					self.hunger = 0
				end
			end
			o.oY = o.oY-1
			self.env.sleep(0.1)
			o.oY = o.oY-1
			self.env.sleep(0.1)
			ogrid[o.x..","..o.y] = nil
			objects[tree.id] = nil -- AAAAAAA IDs will breakk nooo nvm (:
		end,
		findTree = function() -- idk arguments?????????????
			checkTier(3)
			local t = pathfind({x=self.x,y=self.y},"tree",20)
			if not t then return nil end
			t.x,t.y = t.x-self.x,t.y-self.y
			return t
		end,
		hunt = function(animal)
			checkTier(3)
			local o = objects[animal.id]
			if o then
				while objects[animal.id] and o.health > 0 do
					if distance(self,o) > 2 then
						self.env.walkTo(animal)
					end
					o.hurt = true
					o.health = o.health-(math.random(3,10)) -- multiply by power in future
					o.bAction = "Flee long"
					self.env.sleep(0.5)
				end
				if objects[animal.id] then
					data.resources.food = data.resources.food+foodval[o.texture]
					ogrid[math.floor(o.x+0.5)..","..math.floor(o.y+0.5)] = nil
					objects[animal.id] = nil
				end
			end
		end,
		findAnimal = function()
			checkTier(3)
			local tx,ty = math.floor(self.x+0.5),math.floor(self.y+0.5)
			local t = pathfind({x=tx,y=ty},"animal",20)
			if not t then return nil end
			t.x,t.y = t.x-self.x,t.y-self.y
			return t
		end,
		setAction = function(action)
			if sl.data.tasks[action] then
				self.action = action
				return true
			else
				error("The action '"..tostring(action).."' does not exist!",2)
			end
			self.env.sleep(0.2)
		end,
		sleep = function(seconds)
			if type(seconds) ~= "number" or seconds < 0 then error("Invalid amount entered! Expected number bigger than 0, got "..tostring(seconds),2) end
			local i = 0
			while i < seconds do
				os.pullEvent()
				i = i+timerlen
			end
		end,
		countWood = function()
			return data.resources.wood
		end,
		countFood = function()
			return data.resources.food
		end,
		countMetal = function()
			return data.resources.metal
		end,
		devMode = function()
			devmode = true
		end,
		eat = function(amount)
			local i = amount or 1
			for t=1,i do
				if self.hunger == 100 then
					error("Already full!",2)
				elseif data.resources.food >= 1 then
					data.resources.food = data.resources.food-1
					self.env.sleep(0.1)
					for t=1,4 do
						self.hunger = self.hunger+5
						if self.hunger >= 100 then
							self.hunger = 100
							break
						end
						self.env.sleep(0.1)
					end
				else
					error("Not enough food!",2)
				end
			end
			return true
		end,
		buildHouse = function()
			if data.resources.wood < 10 then
				error("At least 10 wood is needed to build a house!",2)
			end
			local tx,ty = math.floor(self.x+0.5),math.floor(self.y+0.5)
			local spot = pathfind({x=tx,y=ty},"emptySpot",50)
			if not spot then return false end
			local walkx,walky = spot.x-self.x,spot.y-self.y
			self.env.walkTo(walkx,walky+1)
			tx,ty = math.floor(self.x+0.5),math.floor(self.y+0.5)

			local bspot = pathfind( {x=spot.x,y=spot.y}, "emptySpot", 50 )
			while bspot.x ~= spot.x or bspot.y ~= spot.y do
				spot = bspot
				walkx,walky = spot.x-self.x,spot.y-self.y
				self.env.walkTo( walkx,walky+1 )
				tx,ty = math.floor( self.x+0.5 ), math.floor( self.y+0.5 )
				bspot = pathfind( {x=spot.x,y=spot.y}, "emptySpot", 50 )
				self.env.sleep(1)
			end

			local struct = assets.structures.construction[1]
			local w,h = #struct[1][1],#struct
			local obj = {
				struct,
				type="structure",
				x=spot.x,
				y=spot.y,
				oX=math.floor(w/2),
				oY=h-1,
				type="structure",
				progress=10,
				health=0,
			}
			local rx,ry = spot.x-math.floor(w/2),spot.y-(h-1)
			table.insert(objects,obj)
			table.insert(data.houses,obj)
			obj.id = #objects
			for cX=rx,rx+(w-1) do
				for cY=ry+2,ry+(h-1) do
					ogrid[cX..","..cY] = obj
				end
			end
			while obj.progress > 0 do
				if data.resources.wood <= 0 then
					error("Not enough wood!",2)
				else
					data.resources.wood = data.resources.wood-1
				end
				obj.health = obj.health+10
				obj.progress = obj.progress-1
				obj.oX = obj.oX-1
				self.env.sleep(0.05)
				obj.oX = obj.oX+2
				self.env.sleep(0.05)
				obj.oX = obj.oX-1
				self.env.sleep(0.05)
				self.env.sleep(1)
			end
			obj[1] = assets.structures.tent[1]
			return true
		end,
		math=math,
		self = {},
		debug= {},
	}
	if #standardvars == 0 then
		for k,v in pairs(self.env) do
			standardvars[k] = true
		end
	end
	standardvars["_ENV"] = true
	local publicProperties = {
		health=true,
		action=true,
		hunger=true,
		happiness=true,
		name=true,
		firstName=true,
		lastName=true,
		rat=true,
	}
	local function sIndex(t,k)
		if publicProperties[k] then
			return self[k]
		end
	end
	setmetatable(self.env.self,{__index=sIndex,__newindex=function(t,k,v) readonly("self",t,k,v) end})
	setmetatable(self.env.debug,{__index=debugtbl,__newindex=function(t,k,v) readonly("debug",t,k,v) end})
end

function lifeform.new(texture,x,y)
	local f,l = assets.names.fnames,assets.names.lnames
	local firstName = f[math.random(1,#f)]
	local lastName = l[math.random(1,#l)]
	local lf = {
		type="human",
		texture=texture,
		vD="forward",
		hD=hDirs[math.random(#hDirs)],
		x=x,
		y=y,
		oX=1,
		oY=2,
		health=100,
		action="idle",
		hunger=80,
		happiness=80,
		speech={},
		name=firstName.." "..lastName,
		firstName=firstName,
		lastName=lastName,
	}
	setmetatable(lf,{__index=lifeform})
	lf:genEnv()
	return lf
end

local function collide(e)
    local e = lUtils.instantiate(e)
    local s = shapescape.getSlide()
    e[3] = e[3]+(self.x1-1)
    e[4] = e[4]+(self.y1-1)
    for t=#s.objs,1,-1 do
        local o = s.objs[t]
        if o ~= self and e[3] >= o.x1 and e[4] >= o.y1 and e[3] <= o.x2 and e[4] <= o.y2 then
            return true
        elseif o == self then
            return false
        end
    end
end
local function generate()
	map = gen(500,500,"continents")
	sl.gamedata.map = map
	ogrid = {}
	for y=1,#map[1] do
		for x=1,#map do
			if not dict[map[x][y]] then
				if map[x][y] > snow then
					dict[map[x][y]] = {name=dict[snow].name,color=dict[snow].color,color2=colors.lightGray,height=dict[snow].height+(map[x][y]-snow)}
				else
					dict[map[x][y]] = dict[1]
				end
			end
			local s = dict[map[x][y]]
			if s.name == "forest" then
				if math.random(1,20) == 7 then
					--lUtils.renderImg(assets.terrain.tree1[math.random(1,#assets.terrain.tree1)],x-1,y-s.height-2,nil,true)
					table.insert(objects,{assets.terrain.tree1[math.random(1,#assets.terrain.tree1)],type="tree",health=4,oX=1,oY=2,x=x,y=y,wood=math.random(1,5)})
					ogrid[x..","..y] = objects[#objects]
					objects[#objects].id = #objects
				end
			elseif oldthing and map[x] and dict[map[x][y]].name == "grass" then
				local r = math.random(1,100)
				local textures = {"knight","human"}
				local animals = {"cow","peacock",--[["rat",]]"llama","sheep"}
				local vDirs = {"forward","back"}
				local hDirs = {"left","right"}
				--[[if r == 7 then
					table.insert(objects,{type="human",texture=textures[math.random(#textures)],vD=vDirs[math.random(#vDirs)],hD=hDirs[math.random(#hDirs)],x=x,y=y,oX=1,oY=2,health=100,action="idle",hunger=100,happiness=100})
					--lUtils.renderImg(assets.human.right.forward[1],x-2,y-s.height-2,nil,true)
					--table.insert(objects,{assets.knight.right.forward[1],type="human",health=1,,x=x,y=y})
					
					ogrid[x..","..y] = objects[#objects]
				else]]if r == 24 then
					table.insert(objects,{type="animal",texture=animals[math.random(#animals)],hD=hDirs[math.random(#hDirs)],x=x,y=y,oX=3,oY=3,xVel=0,yVel=0,health=10})
					ogrid[x..","..y] = objects[#objects]
				end
			end
		end
	end
end
local function render(rx,ry)
	local slide = shapescape.getSlide()
	rmap = {}
	if useBuffer then
		term.redirect(bwin)
	end
	term.setBackgroundColor(colors.orange)
	term.clear()
	local w,h = term.getSize()
	rx = 0-rx
	ry = 0-ry
	local drawn = 0
	local had = {}
	local orows = {} -- object rows (one for every line on screen)
	if zoom == 1 then
		for k,v in pairs(objects) do
			local y = math.floor(v.y + 0.5)
			local x = math.floor(v.x + 0.5)
			local s = dict[map[x][y]]
			local ox,oy = (rx-1)+x,(ry-1)+y-s.height
			if ox >= 1 and oy >= 1-s.height and ox <= w and oy <= h then
				if v.type == "human" then
					if s.name == "shallow_water" then
						v.oY = 1
					elseif s.height == 0 then
						v.oY = 0
					else
						v.oY = 2
					end
				elseif v.type == "animal" and v.texture ~= "rat" then
					if s.name == "shallow_water" then
						v.oY = 2
					elseif s.height == 0 then
						v.oY = 1
					else
						v.oY = 3
					end
				end
				v.rx = ox
				v.ry = oy
				if not orows[y] then
					orows[y] = {}
				end
				table.insert(orows[y],v)
			end
		end
	end
	for y1=zoom,#map[1] do
		local y = math.floor(y1 + 0.5)
		lOS.debugY = {y,y1,zoom}
		for x1=zoom,#map do
			local x = math.floor(x1 + 0.5)
			lOS.debugX = {x,x1,zoom}
			local s = dict[map[x][y]]
			if not s then
				error("No dict["..tostring(map[x][y]).." (map["..tostring(x).."]["..tostring(y).."])]")
			end
			local ox,oy = (rx-1)+x,(ry-1)+y-s.height
			if zoom > 1 then
				oy = oy+s.height
			end
			ox,oy = math.floor(ox/zoom+0.5),math.floor(oy/zoom+0.5)
			if ox >= 1 and oy >= 1-s.height and ox <= w and oy <= h and not (zoom > 1 and had[ox..","..oy]) then
				if zoom == 1 and map[x][y+1] and dict[map[x][y+1]] and dict[map[x][y+1]].height < s.height then
					for t=1,s.height do
						local tx,ty = math.floor(((rx-1)+x)/zoom+0.5),math.floor(((ry-1)+y-(t-1))/zoom+0.5)
						term.setCursorPos(tx,ty)
						term.setBackgroundColor(s.color2 or s.color)
						term.write(" ")
						rmap[tx..","..ty] = {type="tile",x=x,y=y}
					end
				end
				term.setCursorPos(ox,oy)
				rmap[ox..","..oy] = {type="tile",x=x,y=y}
				if s.color == colors.white and slide.c == 7 then
					term.setBackgroundColor(colors.pink)
				elseif s.color == colors.cyan and slide.c > 3 and slide.c < 7 then
					term.setBackgroundColor(colors.orange)
				else
					term.setBackgroundColor(s.color)
				end
				term.write(" ")
				drawn = drawn+1
				had[ox..","..oy] = true
			end
		end
		if zoom > 1 then
			for k,v in pairs(data.lifeforms) do
				local x,y = v.x,v.y
				local ox,oy = (rx-1)+x,(ry-1)+y
				ox,oy = math.floor(ox/zoom+0.5),math.floor(oy/zoom+0.5)
				term.setCursorPos(ox,oy)
				term.setBackgroundColor(colors.red)
				print(" ")
			end
		elseif zoom == 1 and orows[y1] and slide.c == 3 then
			if specialdebug then
				for k,v in pairs(ogrid) do
					local x,y = tonumber(k:match("(%d+),%d+")),tonumber(k:match("%d+,(%d+)"))
					local s = dict[map[x][y]]
					local ox,oy = (rx-1)+x,(ry-1)+y-s.height
					term.setCursorPos(ox,oy)
					if v.type == "tree" then
						term.setBackgroundColor(colors.brown)
					elseif v.type == "animal" then
						term.setBackgroundColor(colors.yellow)
					elseif v.type == "structure" then
						term.setBackgroundColor(colors.red)
					else
						term.setBackgroundColor(colors.purple)
					end
					term.write("\7")
				end
			else
				for t=1,#orows[y1] do
					local o = orows[y1][t]
					if debugobjects then
						term.setBackgroundColor(dict[map[x][y]].color)
						term.setTextColor(colors.red)
						term.setCursorPos(o.rx,o.ry)
						term.write("\7")
					else
						if o.type == "human" and not o.rat then
							if (o.yVel ~= 0 and o.y%1 == 0.5) or (o.xVel ~= 0 and o.x%1 == 0.5) then
								o[1] = assets[o.texture][o.hD][o.vD][2]
							else
								o[1] = assets[o.texture][o.hD][o.vD][1]
							end
							if o.hD == "right" then
								o.oX = 1
							else
								o.oX = 2
							end
						elseif o.type == "animal" or o.rat then
							if o.rat then
								o[1] = assets.animal.rat[o.hD][1]
								o.oY = 3
							else
								o[1] = assets.animal[o.texture][o.hD][1]
							end
							if o.hD == "right" then
								o.oX = 2
							else
								o.oX = 3
							end
						end
						local tx,ty = o.rx-o.oX,o.ry-o.oY
						if sl.var.selform == o then
							if o.hD == "right" then
								term.setCursorPos(o.rx,o.ry)
							else
								term.setCursorPos(o.rx-1,o.ry)
							end
							term.setBackgroundColor(colors.red)
							term.write("  ")
						end
						if o.type == "structure" and not o[1] then
							o[1] = assets.structures.tent[1]
						end
						for tY=1,#o[1] do
							for tX=1,#o[1][tY][1] do
								rmap[(tx+(tX-1))..","..(ty+(tY-1))] = o
							end
						end
						if o.hurt then
							if not o[1].hurt then
								o[1].hurt = {}
								for iY=1,#o[1] do
									o[1].hurt[iY] = {o[1][iY][1]}
									for iL=2,3 do
										o[1].hurt[iY][iL] = o[1][iY][iL]:gsub("[^T]","e")
									end
								end
							end
							lUtils.renderImg(o[1].hurt,tx,ty,nil,true)
							o.hurt = nil
						else
							lUtils.renderImg(o[1],tx,ty,nil,true)
						end
						if o.speech and #o.speech > 0 then
							--term.setCursorPos(o.rx-5,o.ry-5)
							--lUtils.transWrite(o.speech[1].msg)
							local w = math.max(9,math.min(30,#o.speech[1].msg+2)) -- always between 9 and 30
							local lines = lUtils.wordwrap(o.speech[1].msg,29)
							lines[#lines] = nil
							local h = #lines
							local x = o.rx-math.ceil(w/2)+1
							local y = o.ry-(h+8)
							lUtils.renderImg(assets.gui.message[1],x,y,nil,true)
							lUtils.renderImg(assets.gui.message[2],x+5+w-9,y,nil,true)
							lUtils.renderImg(assets.gui.message[3],x,y+3+h,nil,true)
							lUtils.renderImg(assets.gui.message[4],x+5+w-9,y+3+h,nil,true)
							term.setBackgroundColor(colors.white)
							term.setTextColor(colors.black)
							if w > 9 then
								term.setCursorPos(x+5,y+2)
								term.write(string.rep(" ",w-9))
								term.setCursorPos(x+5,y+3+h)
								term.write(string.rep(" ",w-9))
							end
							for l=1,#lines do
								term.setCursorPos(x,y+3+(l-1))
								term.write("  "..lines[l]..string.rep(" ",w-(#lines[l]+1)))
							end
							--[[local cTime = os.epoch("utc")
							local dTime = (cTime-sTime)/1000
							o.speech[1].dur = o.speech[1].dur-dTime
							sTime = cTime]]
							if os.epoch("utc") >= o.speech[1].dur then
								table.remove(o.speech,1)
							end
						end
					end
				end
			end
--			for x=1,#map do
--				if objects[x..","..y] then
--					local o = objects[x..","..y]
--					if debugobjects then
--						term.setBackgroundColor(dict[map[x][y]].color)
--						term.setTextColor(colors.red)
--						term.setCursorPos((rx-1)+x,(ry-1)+y-dict[map[x][y]].height)
--						term.write("\7")
--					else
--						local ox,oy = (rx-1)+x-o.oX,(ry-1)+y-dict[map[x][y]].height-o.oY
--						if ox >= 1 and oy >= 1 and ox <= w and oy <= h then
--							lUtils.renderImg(o[1],ox,oy,nil,true)
--						end
--					end
--				end
--			end
		end
	end
	if slide.c == 3 then
		local rY = 7
		local iW,iH = #assets.gui.resources[1][1][1],#assets.gui.resources[1]
		local font = assets.font.futfont
		local fW,fH = #font[1][1][1],#font[1]
		lUtils.renderImg(assets.gui.resources[4],w-iW,rY,nil,true)
		local txt = tostring(data.resources.wood)
		term.setCursorPos(w-iW-(fW*#txt)-1,rY+1)
		sl.fwrite(txt,font,true)
		rY = rY+iH

		lUtils.renderImg(assets.gui.resources[5],w-iW,rY,nil,true)
		local txt = tostring(data.resources.food)
		term.setCursorPos(w-iW-(fW*#txt)-1,rY+1)
		sl.fwrite(txt,font,true)
		rY = rY+iH

		lUtils.renderImg(assets.gui.resources[6],w-iW,rY,nil,true)
		local txt = tostring(data.resources.metal)
		term.setCursorPos(w-iW-(fW*#txt)-1,rY+1)
		sl.fwrite(txt,font,true)
		rY = rY+iH
	end

	term.setCursorPos(2,2)
	if slide.c == 3 and objectives.main then
		term.setTextColor(colors.white)
		sl.fwrite(objectives.main,assets.font.futfont,true)
		objectives.done = 0
		for t=1,#objectives do
			if not objectives[t].done then
				objectives[t].done = 0
				data.objectives[objectives.id][t].done = 0
			end
			for i,g in ipairs(objectives[t].goals) do
				if not g.done and g.func() then
					g.done = true
					data.objectives[objectives.id][t][i] = true
					objectives[t].done = objectives[t].done+1
					data.objectives[objectives.id][t].done = objectives[t].done
				end
			end
			if objectives[t].done == #objectives[t].goals then
				term.setTextColor(colors.lightGray)
				lUtils.renderImg(assets.gui.checkbox[2],2,1+t*3,nil,true)
				objectives.done = objectives.done+1
				data.objectives[objectives.id].done = objectives.done
			else
				term.setTextColor(colors.white)
				lUtils.renderImg(assets.gui.checkbox[1],2,1+t*3,nil,true)
			end
			term.setCursorPos(6,t*3+2)
			lUtils.transWrite(objectives[t].txt.." "..objectives[t].done.."/"..#objectives[t].goals)
		end
		if objectives.done == #objectives then
			-- animation or some shit
			if goals[objectives.id+1] then
				objectives = goals[objectives.id+1]
				data.tier = objectives.id
			end
		end
	end

	--[[term.setCursorPos(1,1)
	term.setBackgroundColor(colors.white)
	term.setTextColor(colors.black)
	term.write("x="..rx..",y="..ry..", "..drawn.." drawn, particle#="..#particles.." power="..tostring(sl.power))
	if sl.power then
		term.write(" ("..sl.power.id..")")
	end]]
	if slide.c == 7 then
		-- draw paused logo idk
		local txt = "PAUSED"
		local font = assets.font.title
		local cW = #font[1][1][1]*#txt
		local w,h = term.getSize()
		term.setCursorPos(math.floor(w/2)-math.floor(cW/2)+1,math.floor(h/2)-15)
		sl.fwrite(txt,font,true)
	end
	if useBuffer then
		term.redirect(oterm)
		for t=1,h do
			local line = {bwin.getLine(t)}
			if particles[pID-1] or not (olines[t] and olines[t][1] == line[1] and olines[t][2] == line[2] and olines[t][3] == line[3]) then
				term.setCursorPos(1,t)
				term.blit(unpack(line))
				olines[t] = line
			end
		end
	end
	for k,v in pairs(particles) do
		local img = v.img[v.frame]
		if img then
			local w,h = #img[1][1],#img
			local x,y = v.x-math.floor(w/2),v.y-(h-1)
			lUtils.renderImg(img,x,y,nil,true)
		end
	end
end
if not preloaded then
	generate()
end
shapescape.setSlide(3)
local x,y = math.floor(250-w/2),math.floor(250-h/2)
if sl.gamedata and sl.gamedata.x and sl.gamedata.y then
	x,y = sl.gamedata.x,sl.gamedata.y
end
render(x,y)
local hold
local tID
local physics = os.startTimer(0.5) -- normally 0.1
local function particle(x,y,img,loop,duration,tFramefunc)
	local particle = {x=x,y=y,img=img,frame=1,timer=duration,loop=loop,func=tFramefunc}
	particles[pID] = particle
	pID = pID+1
end
local pTime = os.epoch("utc")
local function manageParticles()
	local time = os.epoch("utc")
	for k,v in pairs(particles) do
		--[[local img = v.img[v.frame]
		local w,h = #img[1][1],#img
		local x,y = v.x-math.floor(w/2),v.y-(h-1)
		lUtils.renderImg(img,x,y,nil,true)]]
		if v.func and v.func[v.frame] then
			v.func[v.frame](v)
		end
		v.frame = v.frame+1
		if v.frame > #v.img then
			if v.loop then
				v.frame = 1
			else
				if v.frame == #v.img+1 then
					v.frame = v.frame+1
				else
					particles[k] = nil
				end
			end
		end
		if v.duration then
			v.duration = v.duration-0.05
			if v.duration <= 0 then
				particles[k] = nil
			end
		end
	end
end
local currentslide
while true do
	local e = {os.pullEvent()}
	local s = shapescape.getSlide()
	if s.c ~= currentslide then
		if s.c == 4 or s.c == 6 then
			if s.c == 4 then
				local script = sl.data.scripts[sl.editscript]
				s.objs[6].txt = script.content
				s.objs[6].cursor.x = 1
				s.objs[6].cursor.y = 1
				s.objs[6].cursor.a = 1
				s.objs[6].scrollX = 0
				s.objs[6].scrollY = 0
				s.objs[6].state = false
			end
			sl.typing = true
			local palette = {
				[colors.orange] = {0.312,0.624,0.728},
				[colors.magenta] = {0.1,0.1,0.1},
				[colors.lightBlue] = {0.6,0.69803921568627,0.94901960784314},
				[colors.yellow] = {0.87058823529412,0.87058823529412,0.42352941176471},
				[colors.lime] = {0.49803921568627,0.8,0.098039215686275},
				[colors.pink] = {253/255,150/255,34/255},
				[colors.white] = {1,1,1},
				[colors.gray] = {0.45490196078431,0.43921568627451,0.36470588235294},
				[colors.purple] = {0.234,0.468,0.546},
				[colors.blue] = {0.2,0.4,0.8},
				[colors.brown] = {0.49803921568627,0.4,0.29803921568627},
				[colors.green] = {0.34117647058824,0.65098039215686,0.30588235294118},
				[colors.black] = {0.15686274509804,0.16078431372549,0.13725490196078},
				[colors.red] = {1,0.13725490196078,0.47843137254902},
				[colors.lightGray] = {0.6,0.6,0.6},
				[colors.cyan] = {0.69803921568627,0.4,0.89803921568627},
			}
			for k,v in pairs(palette) do
				term.setPaletteColor(k,unpack(v))
			end
		elseif s.c == 7 then
			sl.typing = true
			for k,v in pairs(bgpalette) do
				term.setPaletteColor(k,unpack(v))
			end
		elseif s.c == 3 then
			sl.typing = false
			physics = os.startTimer(timerlen)
			for t=0,15 do
				term.setPaletteColor(2^t,term.nativePaletteColor(2^t))
			end
			term.setPaletteColor(colors.magenta,0.4,0.3,0.2)
			term.setPaletteColor(colors.purple,71/255,103/255,28/255)
			term.setPaletteColor(colors.pink,238/255,195/255,154/255)
			term.setPaletteColor(colors.orange,0.45,0.45,0.45)
		end
		render(x,y)
		currentslide = s.c
	end
	w,h = term.getSize()
	if e[1] == "timer" and e[2] == physics and s.c == 3 then
		local fac = 1
		if not jit then
			fac = 2
		end
		for t=1,sl.timeF*fac do
			if player and not sl.typing then
				player.xVel = 0
				player.yVel = 0
				if lUtils.isHolding(keys.a) then
					player.xVel = -1
					player.hD = "left"
				end
				if lUtils.isHolding(keys.d) then
					player.xVel = 1
					player.hD = "right"
				end
				if lUtils.isHolding(keys.w) then
					player.yVel = -1
					player.vD = "back"
				end
				if lUtils.isHolding(keys.s) then
					player.yVel = 1
					player.vD = "forward"
				end
			end
			for k,v in pairs(objects) do
				if v.xVel and v.yVel then
					local ox,oy = math.floor(v.x+0.5),math.floor(v.y+0.5)
					local xVel,yVel = v.xVel,v.yVel
					if dict[map[ox][oy]].height <= 0 then
						xVel,yVel = xVel/2,yVel/2
					end
					local nx,ny = math.floor(v.x+xVel+0.5),math.floor(v.y+yVel+0.5)
					if map[nx] and map[nx][ny] then
						if v.type == "animal" then
							if dict[map[nx][ny]].height > 0 then
							elseif dict[map[nx][oy]].height > 0 then
								v.yVel = 0
							elseif dict[map[ox][ny]].height > 0 then
								v.xVel = 0
							else
								v.xVel = 0
								v.yVel = 0
							end
						end
					else
						v.xVel = 0
						v.yVel = 0
						xVel = 0
						yVel = 0
					end
					if (xVel ~= 0 or yVel ~= 0) and v.type == "human" then
						v.hunger = v.hunger-0.1
						if v.hunger < 0 then
							v.health = v.health+v.hunger
							v.hurt = true
							v.hunger = 0
						end
						local tx,ty = math.floor(v.x+0.5),math.floor(v.y+0.5)
						local t = pathfind({x=tx,y=ty},"animal",20)
						if t and objects[t.id] then
							t = objects[t.id]
							t.bAction = "Flee short" -- built-in action
						end
					end
					if v.type == "animal" then
						ogrid[math.floor(v.x+0.5)..","..math.floor(v.y+0.5)] = nil
					end
					v.x = v.x+xVel
					v.y = v.y+yVel
					if v.type == "animal" then
						ogrid[math.floor(v.x+0.5)..","..math.floor(v.y+0.5)] = v
					end
				end
				if v.bAction then
					if not v.cAction then
						v.cAction = {
							cor=coroutine.create(function() local ok,err = pcall(bActions[v.bAction],v) if not ok then sl.sError = err v.bAction = nil shapescape.setSlide(6) end end), -- IMPORTANT!!! ADD ERROR HANDLING!!!
						}
					end
					if v.cAction and v.cAction.cor then
						coroutine.resume(v.cAction.cor)
						if coroutine.status(v.cAction.cor) == "dead" then
							v.cAction = nil
							v.bAction = nil
						end
					end
				end
				if v.action then
					if sl.data.tasks[v.action] then
						local scr = sl.data.scripts[sl.data.tasks[v.action].script]
						if v.cAction and v.cAction.cor and v.cAction.content == scr.content then
							-- oop nothing here
						else
							if not v.env then
								if not v.genEnv then
									setmetatable(v,{__index=lifeform})
								end
								v:genEnv()
							end
							v.xVel,v.yVel = 0,0
							local func,err = load(scr.content,"@"..scr.name,nil,v.env)
							if not func then
								sl.sError = err
								v.action = "Idle"
								shapescape.setSlide(6)
							else
								v.cAction = {
									cor=coroutine.create(function() local ok,err = pcall(func) if not ok then sl.sError = err v.action = "Idle" shapescape.setSlide(6) end end), -- IMPORTANT!!! ADD ERROR HANDLING!!!
									content=scr.content,
								}
							end
						end
						if v.cAction and v.cAction.cor then
							coroutine.resume(v.cAction.cor)
							if coroutine.status(v.cAction.cor) == "dead" then
								v.cAction = nil
								v.action = "Idle"
							end
						end
					else
						v.action = "Idle"
					end
				end
			end
		end
		render(x,y)
		manageParticles()
		physics = os.startTimer(timerlen)
	elseif e[1] == "key" then
		if not sl.typing then
			local a = 4
			if lUtils.isHolding(keys.leftShift) then
				a = 8
			end
			if e[2] == keys.up then
				y = y-a
				render(x,y)
			elseif e[2] == keys.down then
				y = y+a
				render(x,y)
			elseif e[2] == keys.right then
				x = x+a
				render(x,y)
			elseif e[2] == keys.left then
				x = x-a
				render(x,y)
			elseif e[2] == keys.r then
				if lUtils.isHolding(keys.leftCtrl) then
					generate()
					render(x,y)
				else
					debugobjects = not debugobjects
					render(x,y)
				end
			elseif lUtils.isHolding(keys.leftCtrl) then
				if e[2] == keys.equals and zoom > 1 then
					for t=1,4 do
						zoom = zoom-0.2
						render(x,y)
						os.sleep(0.05)
					end
					zoom = math.floor(zoom+0.5)
					render(x,y)
				elseif e[2] == keys.minus then
					for t=1,4 do
						zoom = zoom+0.2
						render(x,y)
						os.sleep(0.05)
					end
					zoom = math.floor(zoom+0.5)
					render(x,y)
				end
			end
			sl.gamedata.x,sl.gamedata.y = x,y
		end
	elseif e[1] == "mouse_scroll" then
		if lUtils.isHolding(keys.leftCtrl) and zoom+e[2] >= 1 then
			local cx,cy = e[3]/zoom,e[4]/zoom
			-- k tis 8
			-- x coord
			-- dan zoom
			-- blok 8 staat nu op x 4
			-- dus offset + 4 om terug te komen waar ie was
			-- maar als scale van 2 naar 3
			-- dan is het anders
			-- dan x 8/2 = 4
			-- vergeleken met 8/3 = 2.66666666
			-- AGREHGHGH
			local newzoom = zoom+e[2]
			local sideRatio = e[3]/w
			local pixelDifference = (w*zoom)-(w*newzoom)
			local viewXoffset = pixelDifference*sideRatio

			local sideRatio = e[4]/h
			local pixelDifference = (h*zoom)-(h*newzoom)
			local viewYoffset = pixelDifference*sideRatio

			x = x+viewXoffset
			y = y+viewYoffset
			x,y = math.floor(x+0.5),math.floor(y+0.5)
			sl.gamedata.x,sl.gamedata.y = x,y
			zoom = newzoom
			render(x,y)
			--[[x = math.floor(x+(cx/(zoom+e[2]))+0.5)
			y = math.floor(y+(cx/(zoom+e[2]))+0.5)
			zoom = zoom+e[2]
			render(x,y)]]
		end
	elseif e[1] == "mouse_click" and not collide(e) then
		hold = {x=e[3],y=e[4],drag=false}
	elseif e[1] == "mouse_drag" and hold then
		x = x-(e[3]-hold.x)*zoom
		y = y-(e[4]-hold.y)*zoom
		sl.gamedata.x,sl.gamedata.y = x,y
		hold.x = e[3]
		hold.y = e[4]
		hold.drag = true
		if not tID then
			tID = os.startTimer(timerlen)
		end
	elseif e[1] == "timer" and e[2] == tID then
		tID = nil
		if hold then
			render(x,y)
			tID = os.startTimer(timerlen)
		end
	elseif e[1] == "mouse_up" and hold then
		if zoom == 1 and not hold.drag then
			--[[local mx = e[3]+x+1
			local my = e[4]+y+1]]
			--[[if objects[mx..","..my] then
				-- jump
				term.clear()
				print("Clicked!")
				os.sleep(0.2)
				local o = objects[mx..","..my]
				o[1] = assets.knight.left.forward[1]
				render(x,y)
				os.sleep(0.05)
				o[1] = assets.knight.right.forward[1]
				render(x,y)
				os.sleep(0.05)
				o[1] = assets.knight.right.back[1]
				render(x,y)
				os.sleep(0.05)
				o[1] = assets.knight.left.back[1]
				render(x,y)
			else]]if rmap[e[3]..","..e[4]] and not collide(e) then
				local o = rmap[e[3]..","..e[4]]
				if o.type == "tile" then
					if sl.var.selform then
						sl.var.selform = nil
						for k,v in pairs(s.objs) do
							if v == sl.statobject then
								sl.statobject.enabled = false
								table.remove(s.objs,k)
								break
							end
						end
					elseif sl.power then
						if sl.power.id == "lifeform" and #data.lifeforms <= #data.houses*2 then
							--local vDirs = {"forward","back"}
							particle(e[3],e[4],assets.particle.summon,nil,nil,{[3]=function(v) local lf = lifeform.new("human",o.x,o.y) table.insert(objects,lf) table.insert(data.lifeforms,lf) end})
						elseif sl.power.id == "animal" then
							local animals = {"cow","peacock",--[["rat",]]"llama","sheep"}
							particle(e[3],e[4],assets.particle.summon,nil,nil,{[3]=function(v) table.insert(objects,{type="animal",texture=animals[math.random(#animals)],hD=hDirs[math.random(#hDirs)],x=o.x,y=o.y,oX=3,oY=3,xVel=0,yVel=0,health=10}) ogrid[o.x..","..o.y] = objects[#objects] objects[#objects].id = #objects end})
						end
					--[[elseif e[2] == 1 then
						map[o.x][o.y] = map[o.x][o.y]-1
					else
						map[o.x][o.y] = map[o.x][o.y]+1]]
					end
					if not dict[map[o.x][o.y]] then
						if map[o.x][o.y] > snow then
							dict[map[o.x][o.y]] = {name=dict[snow].name,color=dict[snow].color,color2=colors.lightGray,height=dict[snow].height+(map[o.x][o.y]-snow)}
						end
					end
				elseif o.type == "human" --[[or o.type == "animal" ]]then
					--o[1] = assets.knight.left.forward[1]
					--[[o.vD = "forward"
					o.hD = "left"
					render(x,y)
					os.sleep(0.05)
					--o[1] = assets.knight.right.forward[1]
					o.vD = "forward"
					o.hD = "right"
					render(x,y)
					os.sleep(0.05)
					--o[1] = assets.knight.right.back[1]
					o.vD = "back"
					o.hD = "right"
					render(x,y)
					os.sleep(0.05)
					--o[1] = assets.knight.left.back[1]
					o.vD = "back"
					o.hD = "left"
					render(x,y)
					os.sleep(0.05)
					--o[1] = assets.knight.left.forward[1]
					o.vD = "forward"
					o.hD = "left"
					render(x,y)]]
					sl.var.selform = o -- selected lifeform
					if o.action == "Idle" then
						o.action = "Interact"
					end
					if not sl.statobject.enabled then
						table.insert(s.objs,sl.statobject)
						sl.statobject.enabled = true
					end
					--[[player = o
					player.xVel = 0
					player.yVel = 0]]
				end
			end
		end
		hold = nil
		render(x,y)
	elseif e[1] == "term_resize" then
		bwin.reposition(1,1,term.getSize())
		render(x,y)
	end
end
end
local ok,err = pcall(thegame)
shapescape.setSlide(1)
term.redirect(self.window)
term.setBackgroundColor(colors.black)
term.clear()
term.setCursorPos(1,1)
term.setTextColor(colors.red)
term.write(err)
while true do os.pullEvent() end