aliveai/aliveai/event.lua

1558 lines
45 KiB
Lua

aliveai.folowing=function(self)
if self.folow then
local p=self.folow:get_pos()
if math.random(1,10)==1 or self.mood<0 or not (p and aliveai.visiable(self,p) and aliveai.distance(self,p)<self.distance) then
self.folow=nil
aliveai.stand(self)
return
elseif self.falllook then
aliveai.lookat(self,p)
aliveai.stand(self)
elseif aliveai.distance(self.object:get_pos(),p)>3 then
aliveai.lookat(self,p)
aliveai.walk(self)
elseif self.falllook then
aliveai.lookat(self,p)
aliveai.stand(self)
end
return self
end
end
aliveai.sleep=function(self,set)
if self.type~="npc" then return end
if self.sleeptimer then
if self.sleeptimer>0 and self.sleeping then
self.sleeptimer=self.sleeptimer-1
return self
else
self.sleeptimer=nil
end
end
if set==2 then
aliveai.exitpath(self)
aliveai.stand(self)
self.sleeping=1
aliveai.anim(self,"lay")
self.sleeptimer=60
self.object:set_velocity({x=0,y=-3,z =0})
aliveai.showstatus(self,"sleep")
return self
end
if set==1 then
local pos=aliveai.roundpos(self.object:get_pos())
local pos2=aliveai.roundpos(self.object:get_pos())
pos.y=pos.y-1
local n = minetest.get_node(pos)
if n.param2==1 then
self.object:set_pos({x=pos2.x+0.5,y=pos2.y,z=pos2.z})
self.object:set_yaw(math.pi*0.5)
elseif n.param2==3 then
self.object:set_pos({x=pos2.x-0.5,y=pos2.y,z=pos2.z})
self.object:set_yaw(math.pi+1.5)
elseif n.param2==0 then
self.object:set_pos({x=pos2.x,y=pos2.y,z=pos2.z+0.5})
self.object:set_yaw(math.pi*1)
else
self.object:set_pos({x=pos2.x,y=pos2.y,z=pos2.z-0.5})
self.object:set_yaw(math.pi*0)
end
return
end
if not self.sleeping and math.random(1,10)~=1 then return end
if self.bedpath and self.path then
aliveai.path(self)
if self.done=="path" or (math.random(1,5)==1 and aliveai.distance(self,self.bedpath)<self.arm) then
aliveai.exitpath(self)
for ob, ob in ipairs(minetest.get_objects_inside_radius(self.bedpath, 1)) do
if (aliveai.is_bot(ob) and ob:get_luaentity().sleeping) or ob:is_player() then
self.bedpath=nil
return
end
end
self.sleeping=1
self.object:set_pos(self.bedpath)
self.bedpath=nil
aliveai.anim(self,"lay")
aliveai.sleep(self,1)
self.sleeptimer=10
aliveai.showstatus(self,"sleep")
return self
end
end
local t=minetest.get_timeofday()
local sl=((self.light>0 and (t>=0.8 or t<0.2)) or (self.light<0 and (t<=0.8 and t>0.2)))
if not self.sleeping and sl==true then
local l=minetest.get_node_light(self.object:get_pos())
if (self.light>0 and l>=self.lowestlight) or (self.light<0 and l<=self.lowestlight) then
aliveai.showstatus(self,"check for beds")
local pos=aliveai.roundpos(self.object:get_pos())
for i, s in pairs(aliveai.beds) do
local n=minetest.find_node_near(pos, self.distance,aliveai.beds)
if n then
n.y=n.y+1
for ob, ob in ipairs(minetest.get_objects_inside_radius(n, 1)) do
if (aliveai.is_bot(ob) and ob:get_luaentity().sleeping) or ob:is_player() then return end
end
local p=aliveai.creatpath(self,pos,n)
if p then
self.path=p
self.bedpath=n
end
end
end
end
elseif self.sleeping and sl==false then
self.sleeping=nil
aliveai.stand(self)
elseif self.sleeping then
self.sleeptimer=10
aliveai.anim(self,"lay")
return self
end
end
aliveai.dying=function(self,set)
if set and set==1 then
if self.drop_dead_body==0 or self.hp_max>100 then return end
aliveai.exitpath(self)
aliveai.anim(self,"lay")
self.talking_restore=self.talking
self.talking=0
self.object:set_acceleration({x=0,y=-10,z =0})
self.object:set_velocity({x=0,y=-3,z =0})
aliveai.invdropall(self)
if self.hp<=self.hp_max*-1 then
aliveai.dying(self,2)
return self
end
self.dying={step=self.hp_max+self.hp,try=self.hp+self.hp_max/2}
self.hp=self.hp_max/2
self.object:set_hp(self.hp)
elseif set and set==2 then
if self.drop_dead_body==0 then
if self.hp_max<101 then aliveai.punchdmg(self,self.hp_max) end
return
end
minetest.after(0.1, function(self)
if self.object:get_luaentity() then
aliveai.exitpath(self)
aliveai.anim(self,"lay")
end
end, self)
self.namecolor=""
self.object:set_properties({nametag=""})
self.talking=0
self.type=""
self.hp=self.hp_max
self.object:set_hp(self.hp)
self.dying=nil
self.dead=20
elseif set and set==3 and (self.dying or self.dead) then
self.dying={step=0,try=self.hp_max*2}
self.dead=nil
end
if self.dying then
self.object:set_velocity({x=0,y=self.object:get_velocity().y,z=0})
if self.hp<=self.hp_max*-1 then
aliveai.dying(self,2)
return self
end
self.dying.try=self.dying.try+math.random(-1,1)
self.dying.step=self.dying.step-1
aliveai.showtext(self,(self.dying.try+self.hp) .."/".. self.hp_max,"ff5500")
if self.dying.step<1 and self.dying.try+self.hp>=self.hp_max then
local h=math.random(1,5)
self.dying=nil
self.hp=h
self.object:set_hp(h)
self.talking=self.talking_restor
self.talking_restor=nil
aliveai.stand(self)
aliveai.showtext(self,"")
return self
elseif self.dying.step<1 and self.dying.try+self.hp<self.hp_max then
aliveai.dying(self,2)
return self
end
aliveai.dmgbynode(self)
return self
elseif self.dead then
self.dead=self.dead-1
if self.dead<0 then
local pos=self.object:get_pos()
pos.y=pos.y-1
if minetest.get_item_group(minetest.get_node(pos).name, "igniter")>0 then
minetest.add_particlespawner({
amount = 10,
time =0.2,
minpos = {x=pos.x-1, y=pos.y, z=pos.z-1},
maxpos = {x=pos.x+1, y=pos.y, z=pos.z+1},
minvel = {x=0, y=0, z=0},
maxvel = {x=0, y=math.random(3,6), z=0},
minacc = {x=0, y=2, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 3,
minsize = 3,
maxsize = 8,
texture = "default_item_smoke.png",
collisiondetection = true,
})
end
aliveai.spawnbones(self)
self.destroy=1
aliveai.kill(self)
end
return self
end
end
aliveai.rndgoal=function(self)
if not self.isrnd or self.build or math.random(1,50)~=1 then return end
if self.rndgoal and self.path then
aliveai.path(self)
if self.done=="path" or (math.random(1,10)==1 and aliveai.distance(self,self.rndgoal)<self.arm) then
self.done=""
self.rndgoal=nil
aliveai.showstatus(self,"random goal success")
end
return self
end
local p1=aliveai.random_pos(self)
if p1 then
local p2=aliveai.neartarget(self,p1)
if p2 then
local pos=aliveai.roundpos(self.object:get_pos())
pos.y=pos.y-1
local p3=aliveai.creatpath(self,pos,p2)
if p3 then
self.path=p3
self.rndgoal=p1
aliveai.showstatus(self,"random goal")
aliveai.showpath(p3,1,true)
return self
end
end
end
end
aliveai.node_handler=function(self)
local keep
if self.nodehandler and self.path then
aliveai.path(self)
if self.done=="path" then
self.mood=self.mood+1
if type(self.nodehandler.handler)=="table" then
self.nodehandler.handler.func(self,self.nodehandler.pos,self.nodehandler.handler.item,self.nodehandler.handler.pos)
end
if type(self.nodehandler.handler)=="function" then
self.nodehandler.handler(self,self.nodehandler.pos)
end
if self.nodehandler.handler=="dig" then
aliveai.stand(self)
aliveai.lookat(self,self.nodehandler.pos)
aliveai.dig(self,self.nodehandler.pos)
keep=true
self.time=self.otime
end
if aliveai.mesecons and self.nodehandler.handler=="mesecon_on" then
mesecon.receptor_on(self,self.nodehandler.pos)
end
if aliveai.mesecons and self.nodehandler.handler=="mesecon_off" then
mesecon.receptor_off(self,self.nodehandler.pos)
end
if aliveai.mesecons and self.nodehandler.handler=="punch" then
local n=minetest.get_node(self.nodehandler.pos)
if self.nodehandler.name==n.name and
minetest.registered_nodes[n.name] and
minetest.registered_nodes[n.name].on_rightclick then
minetest.after(0.1, function(self)
aliveai.clearinventory(self)
end,self)
minetest.registered_nodes[n.name].on_rightclick(self.nodehandler.pos,n,aliveai.createuser(self))
end
end
if not keep then
self.done=""
self.nodehandler=nil
return
end
end
end
if self.mood<10 then return end
if (not keep and math.random(1,20)~=1) and not aliveai.constant_node_testing then return end
aliveai.showstatus(self,"handling nodes")
local p3
local pos=self.object:get_pos()
local pt={x=pos.x,y=pos.y-1,z=pos.z}
for i, s in pairs(aliveai.nodes_handler) do
if minetest.get_node(pt).name==i then
self.path={pt}
self.nodehandler={name=i,handler=s,pos=pt}
self.done="path"
return self
end
local p=minetest.find_node_near(pos, self.arm,i)
if p and aliveai.visiable(self,p) then
local p2=aliveai.neartarget(self,p)
if p2 then
local p3=aliveai.creatpath(self,pos,p2)
if p3 then
self.path=p3
self.nodehandler={name=i,handler=s,pos=p}
return self
end
end
end
end
end
aliveai.stuckinblock=function(self)
local posl=self.object:get_pos()
local n=minetest.get_node({x=posl.x,y=posl.y,z=posl.z})
local stuck=1
local p2={}
local arm=math.floor(self.arm)+1
self.object:set_yaw(math.random(0,6.28))
aliveai.walk(self)
if minetest.registered_nodes[n.name] and minetest.registered_nodes[n.name].walkable then
local p
for i=1,arm,1 do
p={x=posl.x,y=posl.y+i,z=posl.z}
n=minetest.get_node(p)
local n2=minetest.registered_nodes[n.name]
if (i==arm and n2 and n2.walkable) or minetest.is_protected(p,"") or minetest.get_meta(p):get_string("owner")~="" then
stuck=2
elseif n2 and n2.walkable then
p2[i]=p
elseif n2 and not n2.walkable then
break
end
end
end
if stuck==1 then
for i=1,#p2,1 do
if not aliveai.dig(self,p2[i]) then
stuck=2
break
end
end
end
if stuck==2 then
aliveai.punchdmg(self.object,1)
aliveai.showstatus(self,"stuck inside block")
end
return nil
end
aliveai.need_helper=function(self)
if self.mood>0 and self.help_need then
if self.done=="come" then
self.done=""
if not self.help_need:get_luaentity() or aliveai.gethp(self.help_need)<=0 then self.help_need=nil return end
for item, n in pairs(self.inv) do
if not minetest.registered_tools[item] then
aliveai.invadd(self.help_need:get_luaentity(),item,n)
aliveai.invadd(self,item,-n)
end
end
aliveai.showstatus(self,"gave " .. self.help_need:get_luaentity().botname .." stuff",3)
aliveai.known(self,self.help_need,"member")
self.help_need=nil
return self
end
return
end
if self.work_helper==0 or self.coming~=1 or self.building~=1 or math.random(1,50)~=1 then return end
aliveai.max(self,true)
local pos=self.object:get_pos()
local self_inv=0
local ob_inv=0
local give
local ob2
for item, n in pairs(self.inv) do
if not minetest.registered_tools[item] then
self_inv=self_inv+n
end
end
if self_inv<10 then return end
for i, ob in pairs(aliveai.active) do
ob2=ob:get_luaentity()
if ob2 and ob2.need and ob2.building==1 and ob2.botname~=self.botname and ob2.team==self.team and aliveai.distance(self,ob2.object:get_pos())<self.distance*3 then
local inv=0
for item, n in pairs(ob2.inv) do
inv=inv+n
end
if inv>ob_inv then
ob_inv=inv
give=ob
end
end
end
if ob_inv>self_inv and give then
self.help_need=give
self.come=give
self.zeal=5
aliveai.showstatus(self,"give " .. give:get_luaentity().botname .." stuff")
return self
end
end
aliveai.steal=function(self,ste)
local known=aliveai.getknown(self,ste)
if self.mood<1 or self.stealing~=1 or known=="member" or not ste:is_player() then return self end
aliveai.showstatus(self,"stealing")
local inv=ste:get_inventory()
local ix=0
for i=1,8,1 do
local stack=inv:get_stack("main",i)
if i~=ste:get_wield_index() and stack:get_name()~="" then ix=i end
if ix~=0 and math.random(1,2)==1 then break end
end
if ix>0 then
local stack=inv:get_stack("main",ix)
aliveai.invadd(self,stack:get_name(),stack:get_count())
inv:set_stack("main",ix,nil)
if math.random(1,5)==1 then
self.fight=ste
aliveai.known(self,ste,"fight")
self.temper=0.5
else
aliveai.known(self,ste,"fly")
end
aliveai.punch(self,ste,1)
return self
end
end
aliveai.light=function(self)
if self.gotolight and self.path then
aliveai.path(self)
if self.done~="" then
self.done=""
self.gotolight=nil
aliveai.stand(self)
aliveai.rndwalk(self)
return self
end
local l=minetest.get_node_light(self.object:get_pos()) or 0
if (self.light>0 and l>=self.lowestlight) or (self.light<0 and l<=self.lowestlight) then
aliveai.exitpath(self)
end
return self
end
if self.isrnd==false or self.path then
return
elseif self.light==0 or math.random(1,10)~=1 then
return
end
if aliveai.max_path_delay>aliveai.max_path_delay_time then
return nil
end
aliveai.showstatus(self,"check light")
local pos=aliveai.roundpos(self.object:get_pos())
pos.y=pos.y-1
local l=minetest.get_node_light(pos)
if l==nil or (self.light>0 and l>=self.lowestlight) or (self.light<0 and l<=self.lowestlight) then
return
end
aliveai.showstatus(self,"escape light")
local radius=self.distance
local olight=l
local light=l
local lightpos
local traped=false
local maxpath=0
for r = 1, radius do
if traped and self.lightdamage==1 and ((self.light>0 and pos.y<0) or (self.light<0 and pos.y>0)) then
aliveai.stuckinblock(self)
end
traped=true
for y = -r, r do
for x = -r, r do
for z = -r, r do
if y==-r or y==r or x==-r or x==r or z==-r or z==r then
local p={x=pos.x+x,y=pos.y+y,z=pos.z+z}
local node=minetest.get_node(p)
if not minetest.registered_nodes[node.name] then return nil end
if minetest.registered_nodes[node.name].walkable==false then
traped=false
local p2={x=pos.x+x,y=pos.y+y-1,z=pos.z+z}
local p3={x=pos.x+x,y=pos.y+y+1,z=pos.z+z}
local node2=minetest.get_node(p2)
local node3=minetest.get_node(p3)
local l2=minetest.get_node_light(p)
if not (self.light and light and l2) then return end
if not (minetest.registered_nodes[node2.name] and minetest.registered_nodes[node3.name]) then return end
if ((self.light>0 and l2>light) or (self.light<0 and l2<light))
and minetest.registered_nodes[node2.name].walkable
and minetest.registered_nodes[node3.name].walkable==false
and (aliveai.visiable(self,p) or (maxpath<9 and math.random(1,20)==1 and aliveai.creatpath(self,pos,p,nil,true))) then
maxpath=maxpath+1
aliveai.showpath(p,2)
light=minetest.get_node_light(p)
lightpos=p
if ((self.light>0 and light>=15) or (self.light<0 and light<=0)) then
break
end
end
end
else
z=r
end
end
end
end
end
if not lightpos then
if self.lightdamage==1 and ((self.light>0 and pos.y<0) or (self.light<0 and pos.y>0)) then
aliveai.punchdmg(self.object,1)
end
if self.lightdamage==0 or aliveai.enable_build==false then return self end
for i, v in pairs(self.inv) do
if minetest.registered_nodes[i] and minetest.registered_nodes[i].light_source>0 then
aliveai.place(self,pos,i)
return self
end
end
return nil
end
local path=aliveai.creatpath(self,pos,lightpos,nil,true)
if path then
aliveai.showstatus(self,"go to light: " .. olight .." " .. light)
aliveai.rndwalk(self,false)
self.path=path
self.gotolight=true
return self
end
end
aliveai.searchhelp=function(self)
if self.coming==1 then
aliveai.showstatus(self,"search help")
local pos=self.object:get_pos()
local d=aliveai.distance(self,pos)
local obs
if self.leader==1 then
obs=aliveai.active
else
obs=minetest.get_objects_inside_radius(pos, self.distance)
end
for _, ob in ipairs(obs) do
if ob and aliveai.team(ob)==self.team and not aliveai.same_bot(self,ob) and (aliveai.is_bot(ob) or ob:is_player()) and (self.leader==1 or aliveai.visiable(self,ob:get_pos())) and not aliveai.is_invisiable(ob) then
local known=aliveai.getknown(self,ob)
if known~="fight" and known~="fly" then
if ob:is_player() then
aliveai.say(self,ob:get_player_name() .." come")
else
aliveai.msg[ob:get_luaentity().botname]={name=self.botname,msg=ob:get_luaentity().botname .." come"}
aliveai.say(self,ob:get_luaentity().botname .." come")
end
if self.leader==1 then
aliveai.known(ob:get_luaentity(),self.fight,"fight")
ob:get_luaentity().fight=self.fight
ob:get_luaentity().temper=ob:get_luaentity().temper+2
elseif math.random(1,3)==1 then
return self
end
end
end
end
return self
end
end
aliveai.searchobjects=function(self)
if (self.fight or self.fly or self.come) or (self.attacking==0 and self.mood<0) or aliveai.random(1,self.attack_chance)~=1 then
return
end
local pos=self.object:get_pos()
local d=aliveai.distance(self,pos)
local rndob
local d=self.distance
aliveai.showstatus(self,"search objects")
for i=0,1,1 do
for iob, ob in ipairs(minetest.get_objects_inside_radius(pos, self.distance)) do
if i==1 then
if rndob then
ob=rndob
else
return self
end
end
local en=ob:get_luaentity()
if aliveai.gethp(ob)>0 and aliveai.visiable(self,ob:get_pos()) and (aliveai.viewfield(self,ob) or aliveai.distance(self,ob:get_pos())<self.arm) and ((aliveai.team(ob)~=self.team and not aliveai.is_bot(ob)) or (en and en.itemstring==nil and en.type and en.type~="" and en.team~=self.team and en.botname~=self.botname)) and not aliveai.is_invisiable(ob) then
local known=aliveai.getknown(self,ob)
local enemy
if (en and en.type=="monster" or aliveai.is_bot(ob)) or ob:is_player() then
enemy=true
end
if math.random(1,2)+i==1 then
rndob=ob
elseif (aliveai.team_fight==true or (en and en.type=="animal") or known=="fight") and (self.attacking==1 or enemy or known=="fight" or (known==nil and self.object:get_hp()<self.hp_max and not (self.attack_players==0 and ob:is_player()))) then
if aliveai.team(ob)=="nuke" or (en and en.mindamage and en.mindamage>self.dmg and not self.tools) then
aliveai.flee_from(self,ob)
return self
end
self.temper=2
self.fight=ob
self.on_detect_enemy(self,self.fight)
if enemy or known=="fight" or math.random(1,3)==1 then
aliveai.sayrnd(self,"come here")
return self
end
elseif known=="come" then
self.zeal=2
self.come=ob
return self
elseif known=="fly" then
self.temper=-0.3
self.fly=ob
aliveai.sayrnd(self,"ahh")
aliveai.searchhelp(self)
return self
elseif self.coming==1 and known=="member" and aliveai.distance(self,ob:get_pos())>7 then
self.come=ob
self.zeal=5
return self
end
end
end
d=1
end
end
aliveai.known=function(self,ob,typ)
if not ob then return end
if not self.known then self.known={} end
local name
if ob:is_player() then
name=ob:get_player_name()
elseif ob:get_luaentity() and ob:get_luaentity().aliveai and ob:get_luaentity().botname then
name=ob:get_luaentity().botname
elseif ob:get_luaentity() then
name=ob:get_luaentity().name
else
return ""
end
if typ~="" then
self.known[name]=typ
else
self.known[name]=nil
end
end
aliveai.getknown=function(self,ob,typ)
if not ob then return "" end
if not self.known then self.known={} end
local name
if ob:is_player() then
name=ob:get_player_name()
elseif ob:get_luaentity() and ob:get_luaentity().aliveai and ob:get_luaentity().botname then
name=ob:get_luaentity().botname
elseif ob:get_luaentity() then
name=ob:get_luaentity().name
else
return ""
end
if not typ then return self.known[name] end
return self.known[name]==typ
end
aliveai.come=function(self)
if self.zeal and self.zeal>0 then
self.zeal=self.zeal-0.02
if self.zeal<=0 then self.zeal=nil self.come=nil end
elseif self.coming==1 and not self.come and math.random(1,40)==1 then
local pos=aliveai.roundpos(self.object:get_pos())
for _, ob in ipairs(minetest.get_objects_inside_radius(pos, 50)) do
local en=ob:get_luaentity()
if en and en.aliveai and en.botname~=self.botname and en.team==self.team then
if aliveai.distance(self,ob:get_pos())<self.distance then
self.come=nil
self.zeal=nil
return
end
aliveai.known(self,ob,"come")
self.come=ob
self.zeal=3
end
end
end
if self.coming==1 and self.come and (self.come:get_luaentity() or self.come:is_player()) then
local pos=aliveai.roundpos(self.object:get_pos())
local cpos=aliveai.roundpos(self.come:get_pos())
local d=aliveai.distance(self,cpos)
local see=aliveai.visiable(self,cpos)
pos.y=pos.y-1
-- path and see
if self.come and self.path then
-- makes the bot dont stuck into walls
if (self.pathwait and self.pathwait<=self.pathn) then
aliveai.exitpath(self)
self.pathwait=nil
elseif see and d<self.arm*2 and not self.pathwait then
self.pathwait=self.pathn+2
aliveai.path(self)
return self
else
aliveai.path(self)
return self
end
-- path
elseif self.come and self.done~="" then
self.done=""
end
-- search
if d<50 and self.zeal>0 then
if see then
-- walking to
aliveai.rndwalk(self,false)
if d>2 and not self.path then
aliveai.lookat(self,cpos)
aliveai.walk(self)
return self
elseif not self.path then
-- meet
aliveai.stand(self)
aliveai.lookat(self,cpos)
if self.come_give then
if self.come:is_player() then
self.come:get_inventory():add_item("main", self.come_give .." " .. self.come_give_num)
elseif aliveai.is_bot(self.come) then
aliveai.invadd(self.come:get_luaentity(),self.come_give,self.come_give_num)
end
aliveai.invadd(self,self.come_give,self.come_give_num*-1)
self.come_give=nil
self.come_give_num=nil
end
self.on_meet(self,self.zeal)
aliveai.showstatus(self,"meet",1)
aliveai.known(self,self.come,"")
self.come=nil
self.zeal=nil
aliveai.searchobjects(self)
aliveai.showstatus(self,"came",3)
self.done="come"
return self
end
else
-- create path
local path=aliveai.creatpath(self,pos,cpos,d)
if path then
aliveai.rndwalk(self,false)
self.path=path
aliveai.path(self)
aliveai.showstatus(self,"path",3)
return self
else
-- rnd walk
self.zeal=self.zeal-0.01
aliveai.rndwalk(self)
return self
end
end
else
-- abort come
self.zeal=0
aliveai.rndwalk(self,false)
self.come=nil
return self
end
end
return nil
end
aliveai.flee_from=function(self,ob)
if self.escape~=1 then return end
self.time=self.otime
aliveai.known(self,ob,"fly")
self.fly=ob
self.fight=nil
self.temper=-3
self.fight_hp=nil
aliveai.sayrnd(self,"ahh","",1)
aliveai.fly(self)
return self
end
aliveai.fly=function(self)
if self.fly and self.fly_path and self.path then
aliveai.path(self)
return self
elseif self.fly and self.done~="" then
self.done=""
self.fly_path=nil
aliveai.stand(self)
elseif self.temper<0 then
self.temper=self.temper+0.01
if self.temper>=0 then
self.temper=0
self.fly=nil
elseif self.temper>-1 and self.object:get_hp()>=self.hp_max then
self.temper=5
self.fight=self.fly
self.fly=nil
self.time=self.otime
return self
end
end
if self.fly and self.temper<0 and aliveai.visiable(self,self.fly:get_pos()) then
self.object:set_yaw(self.object:get_yaw()+3.14)
if not aliveai.viewfield(self,self.fly) then return self end
self.on_escaping(self,self.fly)
local pos1=self.object:get_pos()
local pos2=self.fly:get_pos()
pos1.y=pos1.y-1
aliveai.lookat(self,pos2)
local yaw=self.object:get_yaw()+3.14
self.object:set_yaw(yaw)
aliveai.walk(self,2)
aliveai.showstatus(self,"fly " .. self.temper,1)
if math.random(1,5)==1 then
aliveai.sayrnd(self,"ahh")
aliveai.searchhelp(self)
end
for i=1,self.arm,1 do
local zr=math.sin(yaw)*i
local xr=math.cos(yaw)* (i*-1)
local zl=zr*-1
local xl=xr*-1
local z=self.move.z
local x=self.move.x
if aliveai.def({x=pos1.x+xr+x,y=pos1.y,z=pos1.z+zr+z},"walkable")==false
and aliveai.def({x=pos1.x+xr+x,y=pos1.y+1,z=pos1.z+zr+z},"walkable")==false
and not aliveai.visiable({x=pos1.x+xr+x,y=pos1.y+1,z=pos1.z+zr+z},self.fly:get_pos()) then
local path=aliveai.creatpath(self,pos1,{x=pos1.x+math.floor(xr+x+0.5),y=pos1.y,z=pos1.z+math.floor(zr+z+0.5)})
if path then
self.path=path
self.fly_path=1
aliveai.path(self)
aliveai.showstatus(self,"hide",3)
return self
end
elseif aliveai.def({x=pos1.x+xl+x,y=pos1.y,z=pos1.z+zl+z},"walkable")==false
and aliveai.def({x=pos1.x+xl+x,y=pos1.y+1,z=pos1.z+zl+z},"walkable")==false
and not aliveai.visiable({x=pos1.x+xl+x,y=pos1.y+1,z=pos1.z+zl+z},self.fly:get_pos()) then
pos1=aliveai.roundpos(pos1)
local path=aliveai.creatpath(self,pos1,{x=pos1.x+math.floor(xl+x+0.5),y=pos1.y,z=pos1.z+math.floor(zl+z+0.5)})
if path then
self.path=path
self.fly_path=1
aliveai.path(self)
aliveai.showstatus(self,"hide",3)
return self
end
end
end
local mx=self.move.x/2
local mz=self.move.z/2
if aliveai.def({x=pos1.x+mx,y=pos1.y+1,z=pos1.z+mz},"walkable") and
aliveai.def({x=pos1.x+mx,y=pos1.y+2,z=pos1.z+mz},"walkable") then
local x=pos1.x+mx
local z=pos1.z+mz
for i=0,self.distance,1 do
local p1={x=x,y=pos1.y+i,z=z}
if aliveai.def(p1,"walkable")==false
and aliveai.def({x=x,y=pos1.y+i+1,z=z},"walkable")==false
and aliveai.def({x=pos1.x,y=pos1.y+i,z=pos1.z},"walkable")==false
and aliveai.def({x=pos1.x,y=pos1.y+i+1,z=pos1.z},"walkable")==false then
local path=aliveai.creatpath(self,pos1,p1,self.distance)
if path then
aliveai.rndwalk(self,false)
self.path=path
self.fly_path=1
aliveai.path(self)
return self
end
break
end
end
local r={}
r[1]=aliveai.random(yaw-2.5,yaw)
r[2]=aliveai.random(yaw,yaw+2.5)
self.object:set_yaw(r[aliveai.random(1,2)])
aliveai.walk(self,2)
return self
end
return self
end
return nil
end
aliveai.fight=function(self)
if self.temper>0 then
self.temper=self.temper-0.02
if self.temper<=0 or (self.fight and aliveai.gethp(self.fight)<=0) then
self.temper=0
self.fight=nil
self.backup=nil
self.time=self.otime
self.seen=nil
end
end
if self.fighting==1 and (self.fight and (self.fight:get_luaentity() or self.fight:is_player())) then
if self.fight_hp==nil then self.fight_hp=self.object:get_hp()/2 end
local pos=aliveai.roundpos(self.object:get_pos())
local fpos=aliveai.roundpos(self.fight:get_pos())
local d=aliveai.distance(self,fpos)
local see=aliveai.visiable(self,fpos)
local vy
if self.fight:get_luaentity() then
vy=self.fight:get_velocity().y
else
vy=self.fight:get_player_velocity().y
end
pos.y=pos.y-1
-- fly from
if self.escape==1 and self.object:get_hp()<self.fight_hp then
aliveai.flee_from(self,self.fight)
aliveai.searchhelp(self)
return self
end
-- path and see
if self.fight and self.path then
-- makes the bot dont stuck into walls
if self.pathwait and self.pathwait<=self.pathn then
aliveai.exitpath(self)
self.pathwait=nil
elseif see and d<self.arm*2 and not self.pathwait then
self.pathwait=self.pathn+2
aliveai.path(self)
return self
else
aliveai.path(self)
return self
end
-- path
elseif self.fight and self.done~="" then
self.done=""
end
self.time=self.otime
-- search
if d<self.distance and self.temper>0 then
self.on_detecting_enemy(self)
if see and self.seen or aliveai.viewfield(self,self.fight) then
self.seen=true
if aliveai.is_invisiable(self.fight) then
self.fight=nil
return
end
-- attack
aliveai.rndwalk(self,false)
if d>self.arm and vy>-2 then
aliveai.lookat(self,fpos)
aliveai.walk(self,2)
if self.tool_see==1 and aliveai.random(1,self.tool_chance)==1 then
aliveai.use(self)
end
aliveai.showstatus(self,"attack",1)
if math.random(1,100)==1 then
aliveai.sayrnd(self,"come here")
end
return self
else
-- fight
self.time=0.2
aliveai.stand(self)
aliveai.lookat(self,fpos)
self.on_fighting(self,self.fight)
if self.type=="npc" and aliveai.is_bot(self.fight) and self.fight:get_luaentity().mindamage>self.dmg then
aliveai.flee_from(self,self.fight)
return self
end
if aliveai.random(1,math.floor(6-self.temper)+0.5)==1 then
self.on_punching(self,self.fight)
if self.tool_near==1 and aliveai.random(1,self.tool_chance)==1 then
aliveai.use(self)
else
aliveai.anim(self,"mine")
aliveai.punch(self,self.fight,self.dmg)
self.on_punch_hit(self,self.fight)
end
local hp=aliveai.gethp(self.fight)
if hp<=0 then
aliveai.known(self,self.fight,"")
self.fight=nil
self.fight_hp=nil
self.backup=nil
self.time=self.otime
aliveai.stand(self)
aliveai.sayrnd(self,"got you")
elseif not self.backup then
self.backup=1
aliveai.searchhelp(self)
end
return self
elseif self.smartfight==1 and self.temper>1 then
local yaw=self.object:get_yaw()
aliveai.lookat(self,fpos)
self.object:set_yaw(aliveai.random(yaw*0.5,yaw*1.5))
aliveai.walk(self,2)
if math.random(1,3)==1 and self.object:get_velocity().y==0 then
self.object:set_velocity({x = self.move.x*4, y = 5.2, z =self.move.z*4})
elseif math.random(1,3)==1 then
local yu1={x=fpos.x,y=fpos.y-2,z=fpos.z}
local ny1=minetest.get_node(yu1)
local ny2=minetest.get_node({x=fpos.x,y=fpos.y-3,z=fpos.z})
if ny1 and ny2 and aliveai.def(ny2.name,"walkable")==false and aliveai.def(ny1.name,"walkable") then
aliveai.dig(self,yu1)
end
end
return self
end
aliveai.showstatus(self,"punch " .. self.temper,1)
return self
end
-- if not see
else
self.seen=nil
-- create path
local path=aliveai.creatpath(self,pos,fpos,d)
if path then
aliveai.rndwalk(self,false)
self.path=path
aliveai.path(self)
aliveai.showstatus(self,"path",3)
return self
else
-- rnd walk
aliveai.rndwalk(self)
return self
end
end
else
-- abort fight
self.temper=0
aliveai.rndwalk(self,false)
self.time=self.otime
self.fight=nil
self.backup=nil
return self
end
end
return nil
end
aliveai.findspace=function(self)
if self.task=="build" then
if self.path then
aliveai.path(self)
return self
else
aliveai.rndwalk(self)
end
aliveai.rndwalk(self,false)
local pos=self.object:get_pos()
pos.y=pos.y+0.5
pos=aliveai.roundpos(pos)
if math.random(1,5)==1 and self.done~="findspace" then
if not self.build_x then
aliveai.showstatus(self,"Error: void build_x")
aliveai.kill(self)
return self
end
local look_for_free_space=aliveai.lookforfreespace(pos,self.build_x,self.build_x+10,self.build_x,self.build_y)
if look_for_free_space then
local path=aliveai.creatpath(self,pos,look_for_free_space,self.build_x+10)
if path then
aliveai.showstatus(self,"found space, goto",3)
self.path=path
self.done="findspace"
aliveai.path(self)
end
end
end
if self.done~="findspace" and not aliveai.checkarea({x=pos.x,y=pos.y-1,z=pos.z},"air",self.build_x,1) and aliveai.checkarea(pos,"air",self.build_x,self.build_y) then
aliveai.showstatus(self,"found space",3)
self.done="findspace"
self.taskstep=self.taskstep+1
self.findspace=nil
aliveai.stand(self)
end
end
return self
end
aliveai.build=function(self)
if not self.build then
return self
end
local pos=aliveai.roundpos(self.object:get_pos())
if not self.build.path then
if type(self.build_pos)~="table" then
self.build_pos=pos
end
self.build.path=aliveai.buildpath(self)
if self.build.path==nil then
self.build_step=0
aliveai.showstatus(self,"buildpath mess, restart process")
end
return self
end
if self.path then
local p=aliveai.path(self)
if p==nil then
aliveai.rndwalk(self)
if math.random(1,5)==1 then
aliveai.exitpath(self)
end
aliveai.showstatus(self,"path rnd")
return self
end
if math.random(1,5)==1 and aliveai.distance(self,self.build.path[self.build_step].pos)<=self.arm then
aliveai.exitpath(self)
self.done="path"
aliveai.rndwalk(self,false)
aliveai.showstatus(self,"path skip")
end
return self
end
if self.done=="path" and self.build then
-- reset
aliveai.rndwalk(self,false)
self.time=self.otime
self.rnd=0
self.done=""
aliveai.stand(self)
-- check if can place, or ignore or exit building
if not aliveai.invhave(self,self.build.path[self.build_step].node,1) then
local node1=self.build.path[self.build_step].node
local node2=self.build.path[self.build_step].node
if node1==node2 then
self.ignore_item[node1]=1
self.build_step=self.build_step+1
aliveai.showstatus(self,"ignore " .. node1)
else
self.build_type=""
self.build.path={} --[self.build_step]
aliveai.showstatus(self,"abort building, no enough materials")
return self
end
if not self.build.path[self.build_step] or self.build.path[self.build_step].node~=node1 then return self end
end
-- keep build
aliveai.lookat(self,self.build.path[self.build_step].pos)
local place=aliveai.place(self,self.build.path[self.build_step].pos,self.build.path[self.build_step].node)
if self.build.skiptolater then
self.build.skiptolatercurr=self.build_step
self.build_step=self.build.skiptolater
self.build.skiptolater=nil
aliveai.showstatus(self,"place last")
elseif self.build.skiptolatercurr then
self.build_step=self.build.skiptolatercurr
self.build.skiptolatercurr=nil
else
self.build_step=self.build_step+1
end
end
if not self.build.path[self.build_step] or not self.build.path[self.build_step].pos then
aliveai.showstatus(self,"build done",3)
aliveai.stand(self)
self.build=nil
self.done="build"
self.taskstep=self.taskstep+1
return self
end
if aliveai.distance(self,self.build.path[self.build_step].pos)<=self.arm or self.superbuild==1 then
aliveai.rndwalk(self,false)
self.time=0.2
aliveai.stand(self)
self.done="path"
return self
end
local ii=self.build_step
for i=ii,ii+1000,1 do
if self.build.path[i] then
if not self.ignore_item[self.build.path[i].node] then
self.build_step=i
break
end
else
self.build_step=i
return self
end
end
local pn=aliveai.neartarget(self,self.build.path[self.build_step].pos,1,0)
if pn~=nil then
aliveai.showpath(pn,3)
local p=aliveai.creatpath(self,pos,self.build.path[self.build_step].pos)
aliveai.showstatus(self,"find path")
if p~=nil then
aliveai.showstatus(self,"path")
self.path=p
return self
else
aliveai.showstatus(self,"find path rnd " .. self.rnd,1)
aliveai.buildproblem(self)
return self
end
else
aliveai.showstatus(self,"find near target, rnd " .. self.rnd,1)
aliveai.buildproblem(self)
return self
end
return self
end
aliveai.buildproblem=function(self)
self.rnd=self.rnd+1
if aliveai.distance(self,self.build.path[self.build_step].pos)<=self.arm then -- if near the node
aliveai.stand(self)
self.done="path"
return self
end
if self.rnd>=4 then
self.rnd=0
if self.build.skiptolater then -- skip old node
self.build_step=self.build_step+1
self.build.skiptolater=nil
aliveai.showstatus(self,"skip old node",1)
return self
end
aliveai.showstatus(self,"skip to later")
self.build.skiptolater=self.build_step -- skip node to later
self.build_step=self.build_step+1
self.mood=self.mood-1
return self
end
aliveai.rndwalk(self)
return self
end
aliveai.mineproblem=function(self)
if not self.ignoreminechange then
aliveai.showstatus(self,"Error: void ignoremine")
aliveai.kill(self)
return self
end
if self.ignoremineitem=="" or not self.need[self.ignoremineitem] then
local item
for name, need in pairs(self.need) do
item=need.item
break
end
if not item then self.need=nil end
self.ignoremineitem=item
self.ignoreminetime=0
self.ignoreminechange=aliveai.invhave(self,item,0,true)
end
self.ignoreminetime=self.ignoreminetime+1
if self.ignoreminetime>self.ignoreminetimer then
if self.ignoreminechange==aliveai.invhave(self,self.ignoremineitem,0,true) then --if time out and dont have more
self.ignore_item[self.ignoremineitem]=1
self.mood=self.mood-1
self.need[self.ignoremineitem]=nil
aliveai.showstatus(self,"ignoring item: " .. self.ignoremineitem)
if #self.need==0 then self.need=nil end
end
self.ignoreminetime=0
self.ignoremineitem=""
end
return self
end
aliveai.mine=function(self)
if not self.need then
self.mine.target=self.object:get_pos()
self.mine.status="dig"
end
if not self.ignoreminetime then
aliveai.showstatus(self,"Error: void ignoremine timer")
aliveai.kill(self)
return self
end
local pos=self.object:get_pos()
--search-------------------------------------
if not self.path and self.mine.status=="search" then
if math.random(1,5)~=1 then return self end
--look for needed nodes
aliveai.showstatus(self,"searching")
aliveai.mineproblem(self)
if not self.need then
self.mine.target=self.object:get_pos()
self.mine.status="dig"
return self
end
for _, need in pairs(self.need) do
local p
if need.type=="node" and need.search~="" then
p=aliveai.findnode(self,need.search,self.mine.ignore)
aliveai.showstatus(self,"need: " .. need.item .." " .. need.num .." search " ..need.search .." have: " .. aliveai.invhave(self,need.item,0,true).." time: " .. self.ignoreminetime)
end
if aliveai.invhave(self,need.item,need.num) then
if aliveai.haveneed(self) then
self.mine.status="search"
return self
else
self.mine=nil
self.done="mine"
self.taskstep=self.taskstep+1
aliveai.stand(self)
aliveai.showstatus(self,"mine done",3)
self.mood=self.mood+5
return self
end
else
aliveai.showstatus(self,"need: " .. need.item .." " .. need.num .." search " ..need.search .." have: " .. aliveai.invhave(self,need.item,0,true).." time: " .. self.ignoreminetime)
if math.random(1,1000)==1 then
if need.search=="" then
aliveai.say(self,"i need " .. need.item .. " " .. need.num)
else
aliveai.say(self,"i need " .. need.item .." " .. need.num.. " " .. " or " .. need.search)
end
end
end
if p and p.pos then
if aliveai.distance(self,p.pos)<self.arm and aliveai.visiable(self,p.pos) then
self.time=self.otime
self.done="path"
self.mine.status="dig"
self.mine.target=p.pos
aliveai.rndwalk(self,false)
break
end
self.path=p.path
self.mine.target=p.pos
self.mine.status="goto"
aliveai.showstatus(self,"path")
aliveai.rndwalk(self,false)
break
elseif p then
self.mine.ignore=p
end
end
if self.mine.status=="search" then
aliveai.rndwalk(self)
return self
end
end
--goto-------------------------------------
if self.mine.status=="goto" then
local p=aliveai.path(self)
if p==nil or self.path==nil then
aliveai.exitpath(self)
self.mine.status="search"
aliveai.showstatus(self,"path failed")
self.mood=self.mood-1
return self
end
if aliveai.visiable(self,self.mine.target) and
(self.done=="path" and aliveai.distance(self,self.mine.target)<self.arm) or
(math.random(1,10)==1 and aliveai.distance(self,self.mine.target)<self.arm) then
self.time=self.otime
self.done=""
self.mine.status="dig"
self.mood=self.mood+1
aliveai.exitpath(self)
end
end
--dig-------------------------------------
if self.mine.status=="dig" then
self.resources=self.mine.target
aliveai.stand(self)
aliveai.lookat(self,self.mine.target)
if not self.mine.delay then self.mine.delay=0 end
if self.mine.delay<1 then
self.mine.delay=self.mine.delay+0.5
return self
end
self.mine.delay=0
aliveai.dig(self,self.mine.target)
if aliveai.haveneed(self) then
self.mine.status="search"
self.mood=self.mood+1
else
self.mood=self.mood+5
self.mine=nil
self.ignore_item={}
self.done="mine"
self.taskstep=self.taskstep+1
aliveai.showstatus(self,"mine done",3)
end
end
return self
end
aliveai.exitpath=function(self)
self.time=self.otime
self.pathn=1
self.path=nil
self.path_bridge=nil
self.path_tower=nil
self.path_timer=nil
aliveai.stand(self)
return self
end
aliveai.path=function(self)
self.time=self.otime
if self.path then
if not self.path_timer then self.path_timer=0 end
self.path_timer=self.path_timer+1
self.time=0.1
local pos=self.object:get_pos()
pos.y=pos.y-(self.basey)
if not self.path_bridge and aliveai.samepos(aliveai.roundpos(pos),self.path[self.pathn]) then
if self.path[self.pathn] then
self.path_timer=0
-- build tower
if self.path_tower and self.path[self.pathn+1] and self.path[self.pathn+1].y>pos.y
and self.path[self.pathn+2] and self.path[self.pathn+2].y>pos.y
and self.path[self.pathn+2].x==pos.x and self.path[self.pathn+2].z==pos.z then
aliveai.stand(self)
local stuff=self.path_tower
if stuff=="" then
for i, v in pairs(self.inv) do
if minetest.registered_nodes[i] and minetest.registered_nodes[i].walkable then
stuff=i
break
end
end
end
if aliveai.place(self,pos,stuff) then
self.pathn=self.pathn+1
else
self.path_tower=nil
end
return self
elseif self.path_tower and self.path[self.pathn+2]==nil then
aliveai.exitpath(self)
return self
end
--if path blocked
local n=minetest.get_node(self.path[self.pathn]).name
aliveai.lookat(self,self.path[self.pathn])
aliveai.walk(self)
self.pathn=self.pathn+1
local nn=self.path[self.pathn]
if nn==nil then return self end
if aliveai.def(nn,"walkable") or (self.visual=="mesh" and aliveai.def({x=nn.x,y=nn.y+1,z=nn.z},"walkable")) then
if aliveai.group({x=nn.x,y=nn.y-1,z=nn.z},"aliveai_door")>0 then
self.path[self.pathn]={x=nn.x,y=nn.y-1,z=nn.z}
aliveai.open_door(self,self.path[self.pathn])
return true
end
aliveai.exitpath(self)
aliveai.showstatus(self,"path blocked")
self.object:set_yaw(math.random(0,6.28))
aliveai.walk(self)
self.mood=self.mood-1
return
end
end
elseif self.path[self.pathn]==nil then
self.done="path"
aliveai.exitpath(self)
else
local pos=self.object:get_pos()
if aliveai.def(pos,"climbable") then
aliveai.stand(self)
self.path_timer=0
return self
elseif self.path_timer>30 then
aliveai.jumping(self)
if not self.path_timer then self.path_timer=0 end
if self.path_timer>60 then
aliveai.exitpath(self)
aliveai.showstatus(self,"path timeout")
return self
end
aliveai.showstatus(self,"path problem")
elseif self.path[self.pathn] and self.path[self.pathn].y>pos.y+3 then
aliveai.exitpath(self)
aliveai.showstatus(self,"fell from path")
elseif self.path_bridge and self.path[self.pathn] then
-- bridge
pos=self.object:get_pos()
pos=aliveai.roundpos(pos)
pos.y=pos.y-1
local p3=self.path[self.pathn]
if self.object:get_velocity().y==0 and aliveai.def({x=p3.x,y=p3.y-1,z=p3.z},"walkable")==false then
local stuff=self.path_bridge
if stuff=="" then
for i, v in pairs(self.inv) do
if minetest.registered_nodes[i] and minetest.registered_nodes[i].walkable then
stuff=i
break
end
end
end
aliveai.place(self,{x=p3.x,y=p3.y-1,z=p3.z},stuff)
end
if aliveai.samepos(pos,p3) then
aliveai.stand(self)
self.pathn=self.pathn+1
self.path_timer=0
return self
else
if p3.y>pos.y then
aliveai.jump(self)
end
aliveai.lookat(self,p3)
aliveai.walk(self)
end
return self
else
if self.path_tower and self.path[self.pathn].y>pos.y then
return self
end
aliveai.lookat(self,self.path[self.pathn])
aliveai.walk(self)
end
end
return self
else
return self
end
end