aliveai.main=function(self, dtime)
	if aliveai.systemfreeze==1 then
		if self.floating==0 then
			self.object:set_acceleration({x=0,y=0,z =0})
		end
		self.object:set_velocity({x=0,y=0,z=0})
		return self
	end

	if aliveai.bots_delay2>aliveai.max_delay then
		if self.old==0 or (self.old==1 and aliveai.bots_delay2>aliveai.max_delay*1.2) then aliveai.max(self) end
		return self
	end

	if aliveai.botdelay(self,1) then return self end
	aliveai.bot(self, dtime)
	aliveai.botdelay(self)
end

aliveai.bot=function(self, dtime)
	aliveai.bots_delay=aliveai.bots_delay+dtime
	self.timer=self.timer+dtime
	self.timerfalling=self.timerfalling+dtime
	if self.timerfalling>0.2 then aliveai.falling(self) end
	if self.turnlook and aliveai.turnlook(self,dtime) then return self end
	if self.timer<=self.time then return self end
	self.timer=0


--betweens

	if aliveai.dying(self) then return self end
	if not aliveai.dmgbynode(self) then return self end
	if self.step(self,dtime) or self.controlled==1 then return self end
	if aliveai.sleep(self) then return self end
	aliveai.jumping(self)-- if need to jump
	if aliveai.fight(self) then return self end
	if aliveai.fly(self) then return self end

	if aliveai.come(self) then return self end
	if aliveai.folowing(self) then return self end
	aliveai.searchobjects(self)
	if aliveai.need_helper(self) then return self end	-- give stuff
	if aliveai.light(self) then return self end
	if aliveai.node_handler(self) then return self end
	if aliveai.timer(self) then return self end		-- remove monsters
	if aliveai.rndgoal(self) then return self end
	
	aliveai.msghandler(self)
	

	aliveai.pickup(self)-- if can pick up items

	if aliveai.lookaround(self) then return self end

--betweens helpers
	if self.isrnd and self.pickupgoto then return self end
--events
	if self.mine then
		aliveai.mine(self)
		return self
	end
	if self.findspace then
		aliveai.findspace(self)
		return self
	end
	if self.build then
		aliveai.build(self)
		return self
	end
--tasks
	if self.task=="build" then
		aliveai.task_build(self)
		return self
	end
--task create


	if self.task1(self) then return self end
	if self.task2(self) then return self end
	if self.task3(self) then return self end
	if self.task4(self) then return self end
	if self.task5(self) then return self end

	if self.task=="" then
		aliveai.rndwalk(self)
	end
	return self
end


aliveai.do_nothing=function(self)
	return
end

aliveai.create_bot=function(def)
	if not def then def={} end
	def.name=def.name or "bot"
	def.mod_name=minetest.get_current_modname()
	def.spawn_y=def.spawn_y or 1
	if aliveai.smartshop and def.on_step==nil then def.on_step=aliveai.use_smartshop end
	if not def.click then def.click=aliveai.give_to_bot end

	def.texture=def.texture or "character.png"

	if def.type and def.dropbones~=1 then
		def.dropbones=0
	end

	local itemtexture=def.texture
	if type(def.texture)=="table" and type(def.texture[1])=="string" then itemtexture=def.texture[1] end

	if aliveai.armor_3d and not def.visual and not def.texture[2] then
		if def.type and def.type~="npc" then
			def.usearmor=0
		else
			def.texture={def.texture,"aliveai_air.png","aliveai_air.png",def.texture,}
			def.mesh=aliveai.armor_3d
			def.animation={}
			def.animation["stand"]={x=0, y=79,speed=30,loop=0}
			def.animation["lay"]={x=162,y=166,speed=30,loop=0}
			def.animation["walk"]={x=168, y=187, speed=30,loop=0}
			def.animation["mine"]={x=189, y=198, speed=30,loop=0}
			def.animation["walk_mine"]={x=200, y=219, speed=30,loop=0}
			def.animation["sit"]={x=81, y=160, speed=30,loop=0}
		end
	elseif type(def.texture)~="table" then
		def.texture={def.texture}
	end

	if def.animation and (def.visual==nil or def.visual=="mesh") then
		for i, v in pairs(def.animation) do
			if i=="attack" or i=="fight" then i="mine" end
			def.animation[i].x=def.animation[i].x or 0
			def.animation[i].y=def.animation[i].y or 0
			def.animation[i].speed=def.animation[i].speed or 0
			def.animation[i].loop=def.animation[i].loop or 0
		end
	end

	aliveai.registered_bots[def.name]={
		name=def.name,
		mod_name=def.mod_name,
		bot=def.mod_name ..":" .. def.name,
		type=def.type or "npc",
		item=def.mod_name ..":" .. def.name .. "_spawner",
		textures=def.texture,
		dead="",
		spawn_y=def.spawn_y,
		team=def.team or aliveai.default_team
	}

if not def.visual or def.visual=="mesh" then
	if def.texture~=nil and type(def.texture)=="string" then def.texture={def.texture} end
	minetest.register_node(def.mod_name ..":" .. def.name .."_spawner", {
		description = def.name .." spawner",
	--	wield_image=itemtexture  or "character.png",
		wield_scale={x=0.2,y=0.2,z=0.2},
		tiles=def.texture,
		drawtype="mesh",
		mesh=def.mesh or aliveai.character_preview_model,
		paramtype="light",
		visual_scale=0.1,
		on_place = function(itemstack, user, pointed_thing)
			if pointed_thing.type=="node" then
				local pos=aliveai.roundpos(pointed_thing.above)
				pos.y=pos.y+0.5 + def.spawn_y
				minetest.add_entity(pos, def.mod_name ..":" .. def.name):set_yaw(math.random(0,6.28))
				itemstack:take_item()
			end
			return itemstack
		end,
	})
else
	minetest.register_craftitem(def.mod_name ..":" .. def.name .."_spawner", {
		description = def.name .." spawner",
		inventory_image = itemtexture or "character.png",
		on_place = function(itemstack, user, pointed_thing)
			if pointed_thing.type=="node" then
				local pos=aliveai.roundpos(pointed_thing.above)
				pos.y=pos.y+0.5 + def.spawn_y
				minetest.add_entity(pos, def.mod_name ..":" .. def.name):set_yaw(math.random(0,6.28))
				itemstack:take_item()
			end
			return itemstack
		end,
	})
end

def.drop_dead_body=def.drop_dead_body or 1
if def.texture~=nil and type(def.texture)=="string" then def.texture={def.texture} end

minetest.register_entity(def.mod_name ..":" .. def.name,{
	hp_max = def.hp or 20,
	physical = true,
	weight = 5,
	collisionbox = def.collisionbox or {-0.35,-1.0,-0.35,0.35,0.8,0.35}, -- new box {-0.35,0,-0.35,0.35,1.8,0.35}
	visual = def.visual or "mesh",
	visual_size = def.visual_size or {x=1,y=1},
	mesh = def.mesh or aliveai.character_model,
	textures = def.texture,
	colors = {},
	spritediv = {x=1, y=1},
	initial_sprite_basepos = {x=0, y=0},
	is_visible = true,
	makes_footstep_sound = true,
	automatic_rotate = false,
	visual=def.visual or "mesh",
on_rightclick=function(self, clicker,name)
		self.click(self,clicker)
	end,
on_punch=function(self, puncher, time_from_last_punch, tool_capabilities, dir)
		local pos=self.object:get_pos()
		if self.destroy or minetest.get_node({x=pos.x,y=pos.y-2,z=pos.z}).name=="ignore" then
			self.object:remove()
			aliveai.max(self,true)
			return self
		end
		tool_capabilities.damage_groups.fleshy=tool_capabilities.damage_groups.fleshy or 1
		local mindmg=tool_capabilities.damage_groups.fleshy>=self.mindamage
		local dmg=0
		
		if tool_capabilities and tool_capabilities.damage_groups and tool_capabilities.damage_groups.fleshy then
			if not self.hp then self.hp=0 end
			if mindmg==true then
				self.hp=self.hp-tool_capabilities.damage_groups.fleshy
				self.object:set_hp(self.hp)
				dmg=tool_capabilities.damage_groups.fleshy
				self.mood=self.mood-2
			end
		end


		if dir~=nil and mindmg==true then
			local v={x = dir.x*3,y = self.object:get_velocity().y,z = dir.z*3}
			self.object:set_velocity(v)
			local r=math.random(1,99)
			self.sleeping=nil
			self.onpunch_r=r
			minetest.after(1, function(self,v,r)
					if self and self.object and self.hp>0 and self.onpunch_r==r and aliveai.samepos(aliveai.roundpos(self.object:get_velocity()),aliveai.roundpos(v)) then
						self.object:set_velocity({x = 0,y = self.object:get_velocity().y,z = 0})
					end
			end, self,v,r)
		end

		if mindmg==true then
			aliveai.showhp(self)
		end
-- death

		if self.dying then
			if self.hp<=0 then
				aliveai.dying(self,2)
			else
				return self
			end
		end

		if self.object:get_hp()<=0 and not (self.dead or self.dying) then
			local pos=self.object:get_pos()
			if self.drop_dead_body==1 then
				aliveai.showstatus(self,"drop dead body")
				aliveai.stand(self)
				aliveai.dying(self,1)
			end
			self.death(self,puncher,pos)
			aliveai.invdropall(self)
			aliveai.max(self,true)
			return self
		end

		self.punched(self,puncher,dmg)

		if aliveai.armor and self.armor then aliveai.armor(self,{dmg=true}) end

		if self.path then
			aliveai.exitpath(self)
		end
		minetest.after(2, function(self)
			aliveai.eat(self)
		end,self)
		if not aliveai.same_bot(self,puncher) then
			local known=aliveai.getknown(self,puncher)
			if known=="member" then
				aliveai.known(self,puncher,"")
				if math.random(1,3)==1 then aliveai.say(self,"I dont like you anymore") end
				return self
			elseif self.escape==1 and known=="fly" or self.fighting~=1 then
				if self.temper>-5 then
					self.temper=self.temper-0.3
				end
				if math.random(1,3)==1 then aliveai.sayrnd(self,"ahh") end
				self.fly=puncher
				aliveai.known(self,puncher,"fly")
			elseif self.fighting==1 then
				if self.temper<5 then
					self.temper=self.temper+1
				end
				self.fight=puncher
				aliveai.known(self,puncher,"fight")
				if math.random(1,3)==1 then aliveai.sayrnd(self,"ouch") end
			end
				aliveai.lookat(self,puncher:get_pos())
			return self
		end

		if math.random(1,3)==1 then aliveai.sayrnd(self,"ouch") end
		return self
	end,
on_activate=function(self, staticdata)
		if staticdata=="destroy_on_load" then self.object:remove() return end

		self.self_definitions(self)

		if staticdata~="" then
			local r=aliveai.convertdata(staticdata)
			self.inv={}
			self.ignore_item={}
			self.ignore_nodes={}
			self.known={}
			self.old=r.old
			self.mood=r.mood
			self.team=r.team
			self.namecolor=r.namecolor
			self.known=r.known
			self.inv=r.inv
			self.ignore_item=r.ignore_item
			self.ignore_nodes=r.ignore_ingnore_nodes
			self.task=r.task
			self.taskstep=r.taskstep
			self.botname=r.botname
			self.start_with_items=""
			self.dmg=r.dmg
			self.floating=r.floating
			self.sleeping=r.sleeping
			self.attention_nodes=r.attention_nodes
			if r.savetool then self.tools=r.tools self.savetool=1 self.tool_near=1 end
			if r.home then self.home=r.home end
			if r.resources then self.resources=r.resources end

			for i, v in pairs(r) do
local name=i

				if string.find(name,"storge")==1 then
name=string.gsub(name,"storge", "save__")
end

				if string.find(name,"save__")==1 then
					self[name]=v
				end
			end

			if r.hp then self.object:set_hp(r.hp) end

			if r.dying then
				self.dying=r.dying
				minetest.after(0.1, function(self)
					aliveai.anim(self,"lay")
				end, self)
			end

			for i, s in pairs(aliveai.loaddata) do
				s(self,r)
			end

			aliveai.showstatus(self,"loaded")
		end
		if self.attention_nodes==nil then self.attention_nodes={} end
		if self.inv==nil then self.inv={} end
		if self.ignore_item==nil  then self.ignore_item={} end

		self.move={x=0,y=0,z=0,speed=1}
		aliveai.anim(self,"stand")

		aliveai.floating(self,self.floating)

		if self.botname=="" then self.botname=aliveai.genname() end
		if self.namecolor~="" then self.object:set_properties({nametag=self.botname,nametag_color="#" .. self.namecolor}) end
		if self.start_with_items~="" and type(self.start_with_items)=="table" then
			for i, s in pairs(self.start_with_items) do
				aliveai.invadd(self,i,s,true)
			end
			self.start_with_items=""
		end

		self.delay_average={time=0}

		aliveai.max(self)

		if self.old~=1 then
			self.spawn(self)
			aliveai.showstatus(self,"new bot spawned")
			if self.type=="npc" and math.random(1, aliveai.get_random_stuff_chance)==1 then
				local itmnum=0
				for i, v in pairs(minetest.registered_items) do
					if math.random(1,20)==1 then
						if minetest.get_all_craft_recipes(i) and i~="air" then
							self.inv[i]=1
							itmnum=itmnum+1
							if itmnum>9 then break end
						end
					end
				end
			end
		else
			self.on_load(self)
			aliveai.showstatus(self,"bot loaded")
		end
		self.lastitem_name="wooden planks"
		self.talking_to="you"
		self.lastitem_count=1
		self.hp=self.object:get_hp()

		if aliveai.creative=="true" then
			self.creative=1
			self.superbuild=1
		end

		return self
	end,
get_staticdata = function(self)
		aliveai.max(self)
		if (self.isfalling and self.kill_deep_falling==1) or self.dead then
			return "destroy_on_load"
		end
		local r={inv=self.inv,old=1,hp=self.object:get_hp(),
			task=self.task,
			taskstep=self.taskstep,
			ignore_item=self.ignore_item,
			known=self.known,
			ignore_nodes=self.ignore_ingnore_nodes,
			botname=self.botname,
			dmg=self.dmg,
			mood=self.mood,
			team=self.team,
			namecolor=self.namecolor,
			floating=self.floating,
			attention_nodes=self.attention_nodes,
			}
		if self.sleeping then r.sleeping=self.sleeping end
		if self.home then r.home=self.home end
		if self.resources then r.resources=self.resources end
		if self.savetool then r.tools=self.tools r.savetool=1 end
		if self.start_with_items then r.start_with_items="" end
		if self.dying then r.dying=self.dying end

		for i, v in pairs(self) do
			if string.find(i,"storge")==1 or string.find(i,"save__")==1 then
				r[i]=v
			end
		end

		for i, s in pairs(aliveai.savedata) do
			local rr=s(self,r)
			if rr then
				for i1, s2 in pairs(rr) do
					r[i1]=s2
				end
			end
		end

		return aliveai.convertdata(r)
	end,
on_step=aliveai.main,
	botname=def.botname or "",
	namecolor= def.name_color or "ffffff",
	timerfalling= 0,
	aliveai= true,
	old= 0,
	temper= 0,
	mood=10,
	rnd= 0,
	isrnd= false,
	done="",
	taskstep= 0,
	task= "",
	pathn= 1,
	anim= "",
	timer= 0,
	time= 1,
	otime= 1,
	timer3= 0,
	delaytimer=0,
	delaytimer2=0,
--define
	arm= def.arm or 5,
	dmg= def.dmg or 1,
	dropbones= def.dropbones or 1,
	superbuild= def.superbuild or 0,
	house=def.house or "",
	creative=def.creative or "",
	leader=def.leader or 0,
	team= def.team or aliveai.default_team,
	visual= def.visual or "mesh",
	basey= def.basey or 0.7, -- new -0.3
	damage_by_blocks= def.damage_by_blocks or 1,
	kill_deep_falling= def.kill_deep_falling or 1,
	crafting= def.crafting or 1,
	avoidy= def.avoid_height or 6,
	drop_dead_body=def.drop_dead_body or 1,
	type= def.type or "npc",
	distance= def.distance or 15,
	tools= def.tools or "",
	tool_index=def.tool_index or 1,
	tool_reuse=def.tool_reuse or 0,
	tool_chance= def.tool_chance or 5,
	tool_see= def.tool_see or 1,
	tool_near= def.tool_near or 0,
	escape= def.escape or 1,
	fighting= def.fighting or 1,
	attack_players= def.attack_players or 0,
	attack_chance= def.attack_chance or 10,
	smartfight= def.smartfight or 1,
	usearmor=def.usearmor or 1,
	building= def.building or 1,
	pickuping= def.pickuping or 1,
	attacking= def.attacking or 0,
	coming= def.coming or 1,
	work_helper= def.work_helper or 0,
	coming_players= def.coming_players or 1,
	talking= def.talking or 1,
	stealing= def.stealing or 0,
	steal_chance= def.steal_chance or 0,
	start_with_items= def.start_with_items or "",
	light= def.light or 1,
	hugwalk= def.hugwalk or 0,
	lowestlight= def.lowest_light or 10,
	lightdamage=def.hurts_by_light or 1,
	annoyed_by_staring= def.annoyed_by_staring or 1,
	drowning= def.drowning or 1,
	mindamage=def.mindamage or 0,
--animation
	animation=def.animation or {
		stand={x=1,y=39,speed=30},
		walk={x=41,y=61,speed=30},
		mine={x=65,y=75,speed=30},
		hugwalk={x=80,y=99,speed=30},
		lay={x=113,y=123,speed=0},
		sit={x=101,y=111,speed=0},
	},
--functions


	on_chat= def.on_chat or aliveai.do_nothing,
	on_spoken_to= def.on_spoken_to or aliveai.on_spoken_to,
	on_fighting= def.on_fighting or aliveai.do_nothing,
	on_escaping= def.on_escaping or aliveai.do_nothing,
	on_punching= def.on_punching or aliveai.do_nothing,
	on_punch_hit= def.on_punch_hit or aliveai.do_nothing,
	on_detect_enemy= def.on_detect_enemy or aliveai.do_nothing,
	on_detecting_enemy= def.on_detecting_enemy or aliveai.do_nothing,
	death= def.death or aliveai.do_nothing,
	spawn= def.spawn or aliveai.do_nothing,
	on_load= def.on_load or aliveai.do_nothing,
	on_random_walk= def.on_random_walk or aliveai.do_nothing,
	click= def.click or aliveai.do_nothing,
	punched= def.on_punched or aliveai.do_nothing,
	on_meet= def.on_meet or aliveai.do_nothing,
	step= def.on_step or aliveai.do_nothing,
	on_dig= def.on_dig or aliveai.do_nothing,
	on_blow=def.on_blow or aliveai.do_nothing,
--tasks
	task1= def.task1 or aliveai.task_build,
	task2= def.task2 or aliveai.task_stay_at_home,
	task3= def.task3 or aliveai.task_farming,
	task4= def.task4 or aliveai.do_nothing,
	task5= def.task5 or aliveai.do_nothing,

	floating= def.floating or 0,

	self_definitions = function(self)
		if def.self and type(def.self)=="table" then
			for i, s in pairs(def.self) do
				if not self[i] then
					self[i]=s
				end
			end
		end
	end,
})


if not aliveai.spawning then
	aliveai.loaded(def.mod_name ..":" .. def.name)
	return
end

def.spawn_in= def.spawn_in or "air"
def.spawn_chance= def.spawn_chance or 1000
def.check_spawn_space= def.check_spawn_space or 1

if def.light==nil then def.light=1 end
if def.lowest_light==nil then def.lowest_light=10 end
 
minetest.register_abm({
	nodenames = def.spawn_on or {"group:spreading_dirt_type","group:sand","default:snow"},
	interval = def.spawn_interval or 30,
	chance = def.spawn_chance,
	action = function(pos)
		if aliveai.systemfreeze==1 then
			return
		end
		local pos1={x=pos.x,y=pos.y+1,z=pos.z}
		local pos2={x=pos.x,y=pos.y+2,z=pos.z}
		local l=minetest.get_node_light(pos1)
		if l==nil then return true end
		if aliveai.random(1,def.spawn_chance)==1
		and (def.light==0 
		or (def.light>0 and l>=def.lowest_light) 
		or (def.light<0 and l<=def.lowest_light)) then
			if aliveai.check_spawn_space==false or def.check_spawn_space==0 or (minetest.get_node(pos1).name==def.spawn_in and minetest.get_node(pos2).name==def.spawn_in) then
				aliveai.newbot=true
				pos1.y=pos1.y+def.spawn_y
				minetest.add_entity(pos1, def.mod_name ..":" .. def.name):set_yaw(math.random(0,6.28))
			end
		end
	end,
})
aliveai.loaded(def.mod_name ..":" .. def.name)
end


aliveai.loaded=function(name)
	if not aliveai.loaded_objects then
		aliveai.loaded_objects=0
		minetest.after(5, function()
			aliveai.loaded_objects=nil
		end)
	end
	aliveai.loaded_objects=aliveai.loaded_objects+1
	print("[aliveai] loaded " .. aliveai.loaded_objects .. ": " .. name)
end


minetest.register_craftitem("aliveai:npcspawner", {
	description=minetest.colorize("black", "Random npc spawner") .. minetest.get_background_escape_sequence("pink"),
	--description = "Random npc spawner",
	inventory_image ="aliveai_rnd.png",
		on_place = function(itemstack, user, pointed_thing)
			if pointed_thing.type=="node" then
				local pos=aliveai.roundpos(pointed_thing.above)
				local list={}
				local ii=1
				for i, v in pairs(aliveai.registered_bots) do
					if v.type=="npc" then
						list[ii]={y=v.spawn_y,name=v.name}
						ii=ii+1
					end
				end
				local bot=list[aliveai.random(1,ii)]
				if not bot then return end
				pos.y=pos.y+bot.y
				minetest.add_entity(pos, aliveai.registered_bots[bot.name].bot):set_yaw(math.random(0,6.28))
				itemstack:take_item()
			end
			return itemstack
		end,
	})

minetest.register_craftitem("aliveai:teampawner", {
	--description = "Random npc team " .. aliveai.default_team .." spawner",
	description=minetest.colorize("white", "Random team " .. aliveai.default_team .." spawner") .. minetest.get_background_escape_sequence("purple"),
	inventory_image ="aliveai_rnd.png",
		on_place = function(itemstack, user, pointed_thing)
			if pointed_thing.type=="node" then
				local pos=aliveai.roundpos(pointed_thing.above)
				local list={}
				local ii=1
				for i, v in pairs(aliveai.registered_bots) do
					if v.type=="npc" and v.team==aliveai.default_team then
						list[ii]={y=v.spawn_y,name=v.name}
						ii=ii+1
					end
				end
				local bot=list[aliveai.random(1,ii)]
				if not bot then return end
				pos.y=pos.y+bot.y
				minetest.add_entity(pos, aliveai.registered_bots[bot.name].bot):set_yaw(math.random(0,6.28))
				itemstack:take_item()
			end
			return itemstack
		end,
	})

