function dotasks()
	local motorpower = 0
	local powerusage = 0
	
	local delthese = {}
	
	for i,foe in ipairs(foes) do
		local x,y = MF_getpos(foe.id)
		
		if (x < -128) or (x > screenw + 128) or (y < -128) or (y > screenh + 128) then
			table.insert(delthese, foe.id)
		end
	end
	
	for i,v in ipairs(delthese) do
		deletefoe(v)
	end
	
	delthese = {}
	
	for i,item in ipairs(items) do
		local x,y = MF_getvalue(item.id,XTILE),MF_getvalue(item.id,YTILE)
		local tileid = gettileid(x,y)
		
		if (map.rooms[tileid] ~= nil) then
			MF_setvalue(item.id,SWIM,0)
		else
			MF_setvalue(item.id,SWIM,1)
		end
		
		local x,y = MF_getpos(item.id)
		
		if (x < -128) or (x > screenw + 128) or (y < -128) or (y > screenh + 128) then
			table.insert(delthese, item.id)
		end
	end
	
	for i,v in ipairs(delthese) do
		delete(v)
	end
	
	for i,struct in ipairs(structs) do
		local stype = MF_getstring(struct.id,TYPE)
		local powered = MF_getvalue(struct.id,POWERED)
		
		if (powered == 1) then
			powerusage = powerusage + 1
		end
		
		if (stype == "GARDEN") and (struct.status < 2400) and (powered == 1) then
			struct.status = struct.status + 1
			
			MF_setframe(struct.id,math.floor(struct.status / 600))
		elseif (stype == "GENERATOR") and (struct.status < 200) and (powered == 1) then
			struct.status = struct.status + 1
		elseif (stype == "ROTOR") and (powered == 1) then
			motorpower = motorpower + 1
		end
	end
	
	MF_setvalue(GDATA,MOTORPOWER,motorpower)
	MF_setvalue(GDATA,POWERUSAGE,powerusage)
	
	for i,unit in ipairs(units) do
		local unitid = unit.id
		local task = MF_getstring(unitid,TASK)
		local subtask = MF_getstring(unitid,SUBTASK)
		local pathing = MF_getvalue(unitid,PATHSTEP)
		local forced = false
		
		local x,y = MF_getvalue(unitid,XTILE),MF_getvalue(unitid,YTILE)
		local tileid = gettileid(x,y)
		
		if (map.rooms[tileid] ~= nil) then
			MF_setvalue(unitid,SWIM,0)
		else
			MF_setvalue(unitid,SWIM,1)
		end
		
		unit.sleep = unit.sleep + 1
		unit.food = unit.food + 1
		if (pathing == 0) and (unit.wait == 0) and (unit.work == 0) then
			if (unit.sleep > 7200) and (task ~= "SLEEP") and (task ~= "EAT") then
				cancel(unit,0)
				
				if (string.len(unit.actualtask) == 0) then
					unit.actualtask = task
				end
				
				task = "SLEEP"
				MF_setstring(unitid,TASK,"SLEEP")
				subtask = ""
				forced = true
			elseif (unit.food > 7200) and (MF_getvalue(GDATA,FOOD) > 0) and (task ~= "SLEEP") and (task ~= "EAT") then
				cancel(unit,0)
				
				if (string.len(unit.actualtask) == 0) then
					unit.actualtask = task
				end
				
				task = "EAT"
				MF_setstring(unitid,TASK,"EAT")
				subtask = ""
				forced = true
			end
		end
		
		local taskdata = tasklist[task] or {}
		local staskdata = taskdata.subtasks or {}
		local subtaskdata = staskdata[subtask] or {}
		
		if (subtask ~= "") and (pathing == 0) and (unit.wait == 0) and (unit.work == 0) then
			if (subtaskdata.finish ~= nil) then
				--MF_alert("Finished " .. task .. ", " .. subtask)
				subtaskdata.finish(unit)
			end
			
			subtask = unit.nexttask or ""
			MF_setstring(unitid,SUBTASK,subtask)
			unit.nexttask = ""
			
			if (string.len(subtask) > 0) then
				subtaskdata = staskdata[subtask] or {}
				dosubtask(unit,task,subtask,subtaskdata.nexttask or "")
			end
		end
		
		if (task == "IDLE") and (unit.wait == 0) and (unit.work == 0) and (pathing == 0) then
			unit.idle = true
		end
		
		if ((task ~= "IDLE") or forced) and (unit.wait == 0) and (unit.work == 0) then
			if task_idling(unit) or forced then
				local dothis = taskdata.defaultsubtask
				subtaskdata = staskdata[dothis] or {}
				
				if (dothis == nil) then
					MF_setstring(unit.id,TASK,"IDLE")
					cancel(unit)
				else
					dosubtask(unit,task,dothis,subtaskdata.nexttask or "")
				end
			end
		elseif (unit.wait > 0) and (pathing == 0) then
			unit.wait = unit.wait - 1
		elseif (unit.work > 0) and (pathing == 0) then
			unit.work = unit.work - 1
		end
		
		if unit.idle and (unit.wait == 0) and (unit.work == 0) and (pathing == 0) then
			local equip = MF_getvalue(unit.id,EQUIP)
			
			if (equip ~= 0) then
				local style = MF_getstring(equip,TYPE)
				
				if (style == "GEAR") then
					if (string.len(unit.actualtask) == 0) then
						unit.actualtask = MF_getstring(unit.id,TASK)
					end
					
					cancel(unit,0)
					MF_setstring(unit.id,TASK,"GEAR")
					MF_setstring(unit.id,SUBTASK,"RETURNGEAR")
					unit.nexttask = ""
					
					task = MF_getstring(unit.id,TASK)
					subtask = MF_getstring(unit.id,SUBTASK)
					dosubtask(unit,task,subtask,unit.nexttask)
				end
			end
		end
	end
end

function pickup(unit,itemid)
	MF_setvalue(unit.id,CARRY,itemid)
	MF_setvalue(unit.id,TARGET,0)
	MF_setvalue(itemid,CARRY,unit.id)
end

function equip(unit,itemid)
	MF_setvalue(unit.id,EQUIP,itemid)
	MF_setvalue(unit.id,TARGET,0)
	MF_setvalue(itemid,CARRY,0)
	MF_setvalue(itemid,EQUIP,unit.id)
end

function reserve(unit,itemid)
	MF_setvalue(unit.id,TARGET,itemid)
	MF_setvalue(itemid,USER,unit.id)
	unit.work = 1
end

function release(unit)
	local target = MF_getvalue(unit.id,TARGET)
	MF_setvalue(unit.id,TARGET,0)
	MF_setvalue(target,USER,0)
end

function drop(unit)
	local carry = MF_getvalue(unit.id,CARRY)
	if (carry ~= 0) then
		MF_setvalue(unit.id,CARRY,0)
		MF_setvalue(carry,CARRY,0)
	end
end

function unequip(unit)
	local carry = MF_getvalue(unit.id,EQUIP)
	if (carry ~= 0) then
		MF_setvalue(unit.id,EQUIP,0)
		MF_setvalue(carry,EQUIP,0)
	end
end

function goget_item(unit,itype,giveup_)
	local i,uw = findpath_toitem(unit,itype)
	local giveup = true
	if (giveup_ ~= nil) then
		giveup = giveup_
	end
	
	if uw and (itype ~= "GEAR") then
		local equip = MF_getvalue(unit.id,EQUIP)
		local name = ""
		
		if (equip ~= 0) then
			name = MF_getstring(equip,TYPE)
		end
		
		if (name ~= "GEAR") then
			if (string.len(unit.actualtask) == 0) then
				unit.actualtask = MF_getstring(unit.id,TASK)
			end
			cancel(unit,0)
			unit.idle = false
			MF_setstring(unit.id,TASK,"GEAR")
			MF_setstring(unit.id,SUBTASK,"GETGEAR")
			unit.nexttask = ""
			dosubtask(unit,MF_getstring(unit.id,TASK),MF_getstring(unit.id,SUBTASK),unit.nexttask)
			return false,uw
		end
	end
	
	if (i ~= nil) then
		MF_setvalue(unit.id,TARGET,i.id)
		MF_setvalue(i.id,CARRY,-1)
		
		return true,uw
	else
		if giveup then
			cancel(unit)
		end
		
		return false,uw
	end
end

function goget_struct(unit,itype,reserve_,minstatus_)
	local reserve = reserve_ or false
	local minstatus = minstatus_ or 0
	
	local i,uw = findpath_tostruct(unit,itype,minstatus)
	
	if uw and (itype ~= "GEAR") then
		local equip = MF_getvalue(unit.id,EQUIP)
		local name = ""
		
		if (equip ~= 0) then
			name = MF_getstring(equip,TYPE)
		end
		
		if (name ~= "GEAR") then
			if (string.len(unit.actualtask) == 0) then
				unit.actualtask = MF_getstring(unit.id,TASK)
			end
			cancel(unit,0)
			unit.idle = false
			MF_setstring(unit.id,TASK,"GEAR")
			MF_setstring(unit.id,SUBTASK,"GETGEAR")
			unit.nexttask = ""
			dosubtask(unit,MF_getstring(unit.id,TASK),MF_getstring(unit.id,SUBTASK),unit.nexttask)
			return false,uw
		end
	end
	
	if (i ~= nil) then
		MF_setvalue(unit.id,TARGET,i.id)
		
		if reserve then
			MF_setvalue(i.id,USER,-1)
		end
		
		return true,uw
	else
		cancel(unit)
		
		return false,uw
	end
end

function goget_damaged(unit)
	local i,uw = findpath_todamaged(unit)
	
	if uw and (itype ~= "GEAR") then
		local equip = MF_getvalue(unit.id,EQUIP)
		local name = ""
		
		if (equip ~= 0) then
			name = MF_getstring(equip,TYPE)
		end
		
		if (name ~= "GEAR") then
			if (string.len(unit.actualtask) == 0) then
				unit.actualtask = MF_getstring(unit.id,TASK)
			end
			cancel(unit,0)
			unit.idle = false
			MF_setstring(unit.id,TASK,"GEAR")
			MF_setstring(unit.id,SUBTASK,"GETGEAR")
			unit.nexttask = ""
			dosubtask(unit,MF_getstring(unit.id,TASK),MF_getstring(unit.id,SUBTASK),unit.nexttask)
			return false,uw
		end
	end
	
	if (i ~= nil) then
		MF_setvalue(unit.id,TARGET,i.id)
		
		return true,uw
	else
		cancel(unit)
		
		return false,uw
	end
end

function cancel(unit,wait_)
	local target = MF_getvalue(unit.id,TARGET)
	local carry = MF_getvalue(unit.id,CARRY)
	
	local wait = wait_ or 50
	
	if (target ~= 0) then
		MF_setvalue(unit.id,TARGET,0)
		MF_setvalue(target,USER,0)
	end
	
	if (carry ~= 0) then
		MF_setvalue(unit.id,CARRY,0)
		MF_setvalue(carry,CARRY,0)
	end
	
	MF_setstring(unit.id,SUBTASK,"")
	MF_setstring(unit.id,PATH,"")
	MF_setvalue(unit.id,PATHSTEP,0)
	unit.nexttask = ""
	unit.wait = wait
	unit.work = 0
	unit.idle = true
end

function cancel_id(id)
	local carry = MF_getvalue(id,CARRY)
	local equip = MF_getvalue(id,EQUIP)
	
	if (carry ~= 0) then
		MF_setvalue(id,CARRY,0)
		MF_setvalue(carry,CARRY,0)
	end
	
	if (equip ~= 0) then
		MF_setvalue(id,EQUIP,0)
		MF_setvalue(equip,EQUIP,0)
	end
	
	for i,v in ipairs(units) do
		local target = MF_getvalue(v.id,TARGET)
		if (target == id) then
			cancel(v)
		end
	end
end

function dosubtask(unit,task_,subtask,nexttask)
	MF_setstring(unit.id,SUBTASK,subtask)
	unit.nexttask = nexttask or ""
	
	local task = task_ or MF_getstring(unit.id,TASK)
	local taskdata = tasklist[task] or {}
	taskdata = taskdata.subtasks or {}
	
	if (taskdata[subtask] ~= nil) then
		unit.idle = false
		local subtaskdata = taskdata[subtask]
		subtaskdata.func(unit)
	end
end

function task_idling(unit)
	local unitid = unit.id
	local task = MF_getstring(unitid,TASK)
	local subtask = MF_getstring(unitid,SUBTASK)
	
	if (subtask == "") or (task == "IDLE") or (task == "") then
		return true
	else
		local taskdata = tasklist[task] or {}
		local tdata = taskdata.subtasks or {}
		
		if (tdata[subtask] == nil) then
			return true
		end
	end
	
	return false
end