From 6ae37b88355cf33de64675443fbd0842043662dd Mon Sep 17 00:00:00 2001 From: TheTermos <55103816+TheTermos@users.noreply.github.com> Date: Sun, 15 Sep 2019 15:12:59 +0200 Subject: [PATCH] Delete utility.lua --- utility.lua | 1305 --------------------------------------------------- 1 file changed, 1305 deletions(-) delete mode 100644 utility.lua diff --git a/utility.lua b/utility.lua deleted file mode 100644 index 331f8e4..0000000 --- a/utility.lua +++ /dev/null @@ -1,1305 +0,0 @@ --- yaw values: --- x+ = -pi/2 --- x- = +pi/2 --- z+ = 0 --- z- = -pi ---[[ -mobkit={} - -mobkit.gravity = -9.8 -mobkit.friction = 0.4 -- less is more - -local abs = math.abs -local pi = math.pi -local floor = math.floor -local random = math.random -local sqrt = math.sqrt -local max = math.max -local min = math.min -local pow = math.pow - -local sign = function(x) - return (x<0) and -1 or 1 -end - -mobkit.terminal_velocity = sqrt(2*-mobkit.gravity*20) -- 20 meter fall = dead -mobkit.safe_velocity = sqrt(2*-mobkit.gravity*5) -- 5 m safe fall - -local abr = minetest.get_mapgen_setting('active_block_range') - -local neighbors ={ - {x=1,z=0}, - {x=1,z=1}, - {x=0,z=1}, - {x=-1,z=1}, - {x=-1,z=0}, - {x=-1,z=-1}, - {x=0,z=-1}, - {x=1,z=-1} - } - - --]] --- UTILITY FUNCTIONS - -function mobkit.dir2neighbor(dir) - dir.y=0 - dir=vector.round(vector.normalize(dir)) - for k,v in ipairs(neighbors) do - if v.x == dir.x and v.z == dir.z then return k end - end - return 1 -end - -function mobkit.neighbor_shift(neighbor,shift) -- int shift: minus is left, plus is right - return (8+neighbor+shift-1)%8+1 -end - -function mobkit.pos_shift(pos,vec) - vec.x=vec.x or 0 - vec.y=vec.y or 0 - vec.z=vec.z or 0 - return {x=pos.x+vec.x, - y=pos.y+vec.y, - z=pos.z+vec.z} -end - --- call this instead if you want feet position. -function mobkit.get_stand_pos(thing) -- thing can be luaentity or objectref. - if type(thing) == 'table' then - return mobkit.pos_shift(thing.object:get_pos(),{y=thing.collisionbox[2]+0.01}) - elseif type(thing) == 'userdata' then - local colbox = thing:get_properties().collisionbox - return mobkit.pos_shift(thing:get_pos(),{y=colbox[2]+0.01}) - end -end - -function mobkit.nodeatpos(pos) - local node = minetest.get_node_or_nil(pos) - if node then return minetest.registered_nodes[node.name] end -end - -function mobkit.get_nodename_off(pos,vec) - return minetest.get_node(mobkit.pos_shift(pos,vec)).name -end - -function mobkit.get_node_pos(pos) - return { - x=floor(pos.x+0.5), - y=floor(pos.y+0.5), - z=floor(pos.z+0.5), - } -end - -function mobkit.get_nodes_in_area(pos1,pos2,full) - local npos1=mobkit.get_node_pos(pos1) - local npos2=mobkit.get_node_pos(pos2) - local result = {} - local cnt = 0 -- safety - - local sx = (pos2.x 125 then - minetest.chat_send_all('get_nodes_in_area: area too big ') - return result - end - - until y==npos2.y - until z==npos2.z - until x==npos2.x - - return result -end - -function mobkit.get_hitbox_bottom(self) - local y = self.collisionbox[2] - local pos = self.object:get_pos() - return { - {x=pos.x+self.collisionbox[1],y=pos.y+y,z=pos.z+self.collisionbox[3]}, - {x=pos.x+self.collisionbox[1],y=pos.y+y,z=pos.z+self.collisionbox[6]}, - {x=pos.x+self.collisionbox[4],y=pos.y+y,z=pos.z+self.collisionbox[3]}, - {x=pos.x+self.collisionbox[4],y=pos.y+y,z=pos.z+self.collisionbox[6]}, - } -end - -function mobkit.get_node_height(pos) - local npos = mobkit.get_node_pos(pos) - local node = mobkit.nodeatpos(npos) - if node == nil then return nil end - - if node.walkable then - if node.drawtype == 'nodebox' then - if node.node_box.type == 'fixed' then - if type(node.node_box.fixed[1]) == 'number' then - return npos.y + node.node_box.fixed[5] ,0, false - elseif type(node.node_box.fixed[1]) == 'table' then - return npos.y + node.node_box.fixed[1][5] ,0, false - else - return npos.y + 0.5,1, false -- todo handle table of boxes - end - elseif node.node_box.type == 'leveled' then - return minetest.get_node_level(pos)/64-0.5+mobkit.get_node_pos(pos).y, 0, false - else - return npos.y + 0.5,1, false -- the unforeseen - end - else - return npos.y+0.5,1, false -- full node - end - else - local liquidflag = false - if node.drawtype == 'liquid' then liquidflag = true end - return npos.y-0.5,-1,liquidflag - end -end - --- get_terrain_height --- steps(optional) number of recursion steps; default=3 --- dir(optional) is 1=up, -1=down, 0=both; default=0 --- liquidflag(forbidden) never provide this parameter. -function mobkit.get_terrain_height(pos,steps,dir,liquidflag) --dir is 1=up, -1=down, 0=both - steps = steps or 3 - dir = dir or 0 - - local h,f,l = mobkit.get_node_height(pos) - if h == nil then return nil end - if l then liquidflag = true end - - if f==0 then - return h, liquidflag - end - - if dir==0 or dir==f then - steps = steps - 1 - if steps <=0 then return nil end - return mobkit.get_terrain_height(mobkit.pos_shift(pos,{y=f}),steps,f,liquidflag) - else - return h, liquidflag - end -end - -function mobkit.get_spawn_pos_abr(dtime,intrvl,radius,chance,reduction) - local plyrs = minetest.get_connected_players() - intrvl=1/intrvl - - if random() 1 then - -- spawn in the front arc - yaw = minetest.dir_to_yaw(vel) + random()*0.35 - 0.75 - else - -- random yaw - yaw = random()*pi*2 - pi - end - local pos = plyr:get_pos() - local dir = vector.multiply(minetest.yaw_to_dir(yaw),radius) - local pos2 = vector.add(pos,dir) - pos2.y=pos2.y-5 - local height, liquidflag = mobkit.get_terrain_height(pos2,32) - if height then - local objs = minetest.get_objects_inside_radius(pos,radius*1.1) - for _,obj in ipairs(objs) do -- count mobs in abrange - if not obj:is_player() then - local lua = obj:get_luaentity() - if lua and lua.name ~= '__builtin:item' then - chance=chance + (1-chance)*reduction -- chance reduced for every mob in range - end - end - end - if chance < random() then - pos2.y = height - objs = minetest.get_objects_inside_radius(pos2,radius*0.95) - for _,obj in ipairs(objs) do -- do not spawn if another player around - if obj:is_player() then return end - end - return pos2, liquidflag - end - end - end -end - -function mobkit.turn2yaw(self,tyaw,rate) - tyaw = tyaw or 0 --temp - rate = rate or 6 - local yaw = self.object:get_yaw() - - local diff = tyaw-yaw - local step = self.dtime*rate - - if abs(diff) pi and -1 or 1 - - local nyaw = diff < 0 and yaw+step*-dirmod or yaw+step*dirmod - - if nyaw > pi then - nyaw=nyaw-pi*2 - elseif nyaw < -pi then - nyaw=nyaw+pi*2 - end - self.object:set_yaw(nyaw) -end - -function mobkit.dir_to_rot(v,rot) - rot = rot or {x=0,y=0,z=0} - return {x = (v.x==0 and v.y==0 and v.z==0) and rot.x or math.atan2(v.y,vector.length({x=v.x,y=0,z=v.z})), - y = (v.x==0 and v.z==0) and rot.y or minetest.dir_to_yaw(v), - z=rot.z} -end - -function mobkit.isnear2d(p1,p2,thresh) - if abs(p2.x-p1.x) < thresh and abs(p2.z-p1.z) < thresh then - return true - else - return false - end -end - --- object has reached the destination if dest is in the rear half plane. -function mobkit.is_there_yet2d(pos,dir,dest) -- obj positon; facing vector; destination position - - local c = -dir.x*pos.x-dir.z*pos.z -- the constant - - if dir.z > 0 then - return dest.z <= (-dir.x*dest.x - c)/dir.z -- line equation - elseif dir.z < 0 then - return dest.z >= (-dir.x*dest.x - c)/dir.z - elseif dir.x > 0 then - return dest.x <= (-dir.z*dest.z - c)/dir.x - elseif dir.x < 0 then - return dest.x >= (-dir.z*dest.z - c)/dir.x - else - return false - end - -end - -function mobkit.isnear3d(p1,p2,thresh) - if abs(p2.x-p1.x) < thresh and abs(p2.z-p1.z) < thresh and abs(p2.y-p1.y) < thresh then - return true - else - return false - end -end - -function mobkit.is_alive(thing) -- thing can be luaentity or objectref. --- if not thing then return false end - if not mobkit.exists(thing) then return false end - if type(thing) == 'table' then return thing.hp > 0 end - if thing:is_player() then return thing:get_hp() > 0 - else - local lua = thing:get_luaentity() - local hp = lua and lua.hp or nil - return hp and hp > 0 - end -end - -function mobkit.exists(thing) - if not thing then return false end - if type(thing) == 'table' then thing=thing.object end - if type(thing) == 'userdata' then - if thing:is_player() then - if thing:get_look_horizontal() then return true end - else - if thing:get_yaw() then return true end - end - end -end - -function mobkit.hurt(luaent,dmg) - if not luaent then return false end - if type(luaent) == 'table' then - luaent.hp = (luaent.hp or 0) - dmg - end -end - -function mobkit.heal(luaent,dmg) - if not luaent then return false end - if type(luaent) == 'table' then - luaent.hp = min(luaent.max_hp,(luaent.hp or 0) + dmg) - end -end - -function mobkit.animate(self,anim) - if self.animation and self.animation[anim] then - if self._anim == anim then return end - self._anim=anim - - local aparms = {} - if #self.animation[anim] > 0 then - aparms = self.animation[anim][random(#self.animation[anim])] - else - aparms = self.animation[anim] - end - - self.object:set_animation(aparms.range,aparms.speed,0,aparms.loop) - else - self._anim = nil - end -end - -function mobkit.make_sound(self,sound) - if self.sounds and self.sounds[sound] then - minetest.sound_play(self.sounds[sound], {object=self.object}) - end -end - -function mobkit.is_neighbor_node_reachable(self,neighbor) -- todo: take either number or pos - local offset = neighbors[neighbor] - local pos=mobkit.get_stand_pos(self) - local tpos = mobkit.get_node_pos(mobkit.pos_shift(pos,offset)) - local height, liquidflag = mobkit.get_terrain_height(tpos) - - if height and abs(height-pos.y) <= self.jump_height then - tpos.y = height - height = height - pos.y - - -- don't cut corners - if neighbor % 2 == 0 then -- diagonal neighbors are even - local n2 = neighbor-1 -- left neighbor never < 0 - offset = neighbors[n2] - local t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset)) - local h2 = mobkit.get_terrain_height(t2) - if h2 and h2 - pos.y > 0.02 then return end - n2 = (neighbor+1)%8 -- right neighbor - offset = neighbors[n2] - t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset)) - h2 = mobkit.get_terrain_height(t2) - if h2 and h2 - pos.y > 0.02 then return end - end - - -- check headroom - if tpos.y+self.height-pos.y > 1 then -- if head in next node above, else no point checking headroom - local snpos = mobkit.get_node_pos(pos) - local pos1 = {x=pos.x,y=snpos.y+1,z=pos.z} -- current pos plus node up - local pos2 = {x=tpos.x,y=tpos.y+self.height,z=tpos.z} -- target head pos - - local nodes = mobkit.get_nodes_in_area(pos1,pos2,true) - - for p,node in pairs(nodes) do - if snpos.x==p.x and snpos.z==p.z then - if node.name=='ignore' or node.walkable then return end - else - if node.name=='ignore' or - (node.walkable and mobkit.get_node_height(p)>tpos.y+0.001) then return end - end - end - end - - return height, tpos, liquidflag - else - return - end -end - - -function mobkit.timer(self,s) -- returns true approx every s seconds - local t1 = floor(self.time_total) - local t2 = floor(self.time_total+self.dtime) - if t2>t1 and t2%s==0 then return true end -end - --- Memory functions. --- Stuff in memory is serialized, never try to remember objectrefs. -function mobkit.remember(self,key,val) - self.memory[key]=val - return val -end - -function mobkit.forget(self,key) - self.memory[key] = nil -end - -function mobkit.recall(self,key) - return self.memory[key] -end - --- Queue functions -function mobkit.queue_high(self,func,priority) - local maxprty = mobkit.get_queue_priority(self) - if priority > maxprty then - mobkit.clear_queue_low(self) - end - - for i,f in ipairs(self.hqueue) do - if priority > f.prty then - table.insert(self.hqueue,i,{func=func,prty=priority}) - return - end - end - table.insert(self.hqueue,{func=func,prty=priority}) -end - -function mobkit.queue_low(self,func) - table.insert(self.lqueue,func) -end - -function mobkit.is_queue_empty_low(self) - if #self.lqueue == 0 then return true - else return false end -end - -function mobkit.clear_queue_high(self) - self.hqueue = {} -end - -function mobkit.clear_queue_low(self) - self.lqueue = {} -end - -function mobkit.get_queue_priority(self) - if #self.hqueue > 0 then - return self.hqueue[1].prty - else return 0 end -end - -function mobkit.is_queue_empty_high(self) - if #self.hqueue == 0 then return true - else return false end -end - -function mobkit.get_nearby_player(self) -- returns random player if nearby or nil - for _,obj in ipairs(self.nearby_objects) do - if obj:is_player() and mobkit.is_alive(obj) then return obj end - end - return -end - -function mobkit.get_nearby_entity(self,name) -- returns random nearby entity of name or nil - for _,obj in ipairs(self.nearby_objects) do - if mobkit.is_alive(obj) and not obj:is_player() and obj:get_luaentity().name == name then return obj end - end - return -end - -function mobkit.get_closest_entity(self,name) -- returns closest entity of name or nil - local cobj = nil - local dist = abr*64 - local pos = self.object:get_pos() - for _,obj in ipairs(self.nearby_objects) do - local luaent = obj:get_luaentity() - if mobkit.is_alive(obj) and not obj:is_player() and luaent and luaent.name == name then - local opos = obj:get_pos() - local odist = abs(opos.x-pos.x) + abs(opos.z-pos.z) - if odist < dist then - dist=odist - cobj=obj - end - end - end - return cobj -end - ---[[ - -function mobkit.timer(self,s) -- returns true approx every s seconds - local t1 = floor(self.time_total) - local t2 = floor(self.time_total+self.dtime) - if t2>t1 and t2%s==0 then return true end -end - --- Memory functions. --- Stuff in memory is serialized, never try to remember objectrefs. -function mobkit.remember(self,key,val) - self.memory[key]=val - return val -end - -function mobkit.forget(self,key) - self.memory[key] = nil -end - -function mobkit.recall(self,key) - return self.memory[key] -end - --- Queue functions -function mobkit.queue_high(self,func,priority) - local maxprty = mobkit.get_queue_priority(self) - if priority > maxprty then - mobkit.clear_queue_low(self) - end - - for i,f in ipairs(self.hqueue) do - if priority > f.prty then - table.insert(self.hqueue,i,{func=func,prty=priority}) - return - end - end - table.insert(self.hqueue,{func=func,prty=priority}) -end - -function mobkit.queue_low(self,func) - table.insert(self.lqueue,func) -end - -function mobkit.is_queue_empty_low(self) - if #self.lqueue == 0 then return true - else return false end -end - -function mobkit.clear_queue_high(self) - self.hqueue = {} -end - -function mobkit.clear_queue_low(self) - self.lqueue = {} -end - -function mobkit.get_queue_priority(self) - if #self.hqueue > 0 then - return self.hqueue[1].prty - else return 0 end -end - -function mobkit.is_queue_empty_high(self) - if #self.hqueue == 0 then return true - else return false end -end - -function mobkit.get_nearby_player(self) -- returns random player if nearby or nil - for _,obj in ipairs(self.nearby_objects) do - if obj:is_player() and mobkit.is_alive(obj) then return obj end - end - return -end - -function mobkit.get_nearby_entity(self,name) -- returns random nearby entity of name or nil - for _,obj in ipairs(self.nearby_objects) do - if mobkit.is_alive(obj) and not obj:is_player() and obj:get_luaentity().name == name then return obj end - end - return -end - -function mobkit.get_closest_entity(self,name) -- returns closest entity of name or nil - local cobj = nil - local dist = abr*64 - local pos = self.object:get_pos() - for _,obj in ipairs(self.nearby_objects) do - local luaent = obj:get_luaentity() - if mobkit.is_alive(obj) and not obj:is_player() and luaent and luaent.name == name then - local opos = obj:get_pos() - local odist = abs(opos.x-pos.x) + abs(opos.z-pos.z) - if odist < dist then - dist=odist - cobj=obj - end - end - end - return cobj -end - -local function execute_queues(self) - --Execute hqueue - if #self.hqueue > 0 then - local func = self.hqueue[1].func - if func(self) then - table.remove(self.hqueue,1) - self.lqueue = {} - end - end - -- Execute lqueue - if #self.lqueue > 0 then - local func = self.lqueue[1] - if func(self) then - table.remove(self.lqueue,1) - end - end -end - -local function sensors() - local timer = 2 - local pulse = 1 - return function(self) - timer=timer-self.dtime - if timer < 0 then - - pulse = pulse + 1 -- do full range every third scan - local range = self.view_range - if pulse > 2 then - pulse = 1 - else - range = self.view_range*0.5 - end - - local pos = self.object:get_pos() ---local tim = minetest.get_us_time() - self.nearby_objects = minetest.get_objects_inside_radius(pos, range) ---minetest.chat_send_all(minetest.get_us_time()-tim) - for i,obj in ipairs(self.nearby_objects) do - if obj == self.object then - table.remove(self.nearby_objects,i) - break - end - end - timer=2 - end - end -end ----------------------------- --- LOW LEVEL QUEUE FUNCTIONS ----------------------------- - -function mobkit.lq_turn2pos(self,tpos) - local func=function(self) - local pos = self.object:get_pos() - return mobkit.turn2yaw(self, - minetest.dir_to_yaw(vector.direction(pos,tpos))) - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_idle(self,duration,anim) - anim = anim or 'stand' - local init = true - local func=function(self) - if init then - mobkit.animate(self,anim) - init=false - end - duration = duration-self.dtime - if duration <= 0 then return true end - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_dumbwalk(self,dest,speed_factor) - local timer = 3 -- failsafe - speed_factor = speed_factor or 1 - local func=function(self) - mobkit.animate(self,'walk') - timer = timer - self.dtime - if timer < 0 then return true end - - local pos = mobkit.get_stand_pos(self) - local y = self.object:get_velocity().y - - if mobkit.is_there_yet2d(pos,minetest.yaw_to_dir(self.object:get_yaw()),dest) then --- if mobkit.isnear2d(pos,dest,0.25) then - if not self.isonground or abs(dest.y-pos.y) > 0.1 then -- prevent uncontrolled fall when velocity too high --- if abs(dest.y-pos.y) > 0.1 then -- isonground too slow for speeds > 4 - self.object:set_velocity({x=0,y=y,z=0}) - end - return true - end - - if self.isonground then - local dir = vector.normalize(vector.direction({x=pos.x,y=0,z=pos.z}, - {x=dest.x,y=0,z=dest.z})) - dir = vector.multiply(dir,self.max_speed*speed_factor) --- self.object:set_yaw(minetest.dir_to_yaw(dir)) - mobkit.turn2yaw(self,minetest.dir_to_yaw(dir)) - dir.y = y - self.object:set_velocity(dir) - end - end - mobkit.queue_low(self,func) -end - --- initial velocity for jump height h, v= a*sqrt(h*2/a) ,add 20% -function mobkit.lq_dumbjump(self,height,anim) - anim = anim or 'stand' - local jump = true - local func=function(self) - local yaw = self.object:get_yaw() - if self.isonground then - if jump then - mobkit.animate(self,anim) - local dir = minetest.yaw_to_dir(yaw) - dir.y = -mobkit.gravity*sqrt((height+0.35)*2/-mobkit.gravity) - self.object:set_velocity(dir) - jump = false - else -- the eagle has landed - return true - end - else - local dir = minetest.yaw_to_dir(yaw) - local vel = self.object:get_velocity() - if self.lastvelocity.y < 0.9 then - dir = vector.multiply(dir,3) - end - dir.y = vel.y - self.object:set_velocity(dir,yaw) - end - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_jumpout(self) - local phase = 1 - local func=function(self) - local vel=self.object:get_velocity() - if phase == 1 then - vel.y=vel.y+5 - self.object:set_velocity(vel) - phase = 2 - else - if vel.y < 0 then return true end - local dir = minetest.yaw_to_dir(self.object:get_yaw()) - dir.y=vel.y - self.object:set_velocity(dir) - end - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_freejump(self) - local phase = 1 - local func=function(self) - local vel=self.object:get_velocity() - if phase == 1 then - vel.y=vel.y+6 - self.object:set_velocity(vel) - phase = 2 - else - if vel.y <= 0.01 then return true end - local dir = minetest.yaw_to_dir(self.object:get_yaw()) - dir.y=vel.y - self.object:set_velocity(dir) - end - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_jumpattack(self,height,target) - local phase=1 - local func=function(self) - if not mobkit.is_alive(target) then return true end - if self.isonground then - if phase==1 then -- collision bug workaround - local vel = self.object:get_velocity() - vel.y = -mobkit.gravity*sqrt(height*2/-mobkit.gravity) - self.object:set_velocity(vel) - mobkit.make_sound(self,'charge') - phase=2 - else - return true - end - elseif phase==2 then - local dir = minetest.yaw_to_dir(self.object:get_yaw()) - local vy = self.object:get_velocity().y - dir=vector.multiply(dir,6) - dir.y=vy - self.object:set_velocity(dir) - phase=3 - elseif phase==3 then -- in air - local twidth = target:get_properties().collisionbox[1] - local pos = self.object:get_pos() - -- calculate attack spot - local dir = minetest.yaw_to_dir(self.object:get_yaw()) - dir2 = vector.add(dir,self.attack.range+twidth) - local apos = vector.add(pos,dir2) --- local tpos = mobkit.get_stand_pos(target) --test --- tpos.y = tpos.y+height - if mobkit.isnear2d(apos,target:get_pos(),0.25) then --bite - target:punch(self.object,1,self.attack) - -- bounce off - local vy = self.object:get_velocity().y - self.object:set_velocity({x=dir.x*-3,y=vy,z=dir.z*-3}) - -- play attack sound if defined - mobkit.make_sound(self,'attack') - phase=4 - end - end - end - mobkit.queue_low(self,func) -end - -function mobkit.lq_fallover(self) - local zrot = 0 - local init = true - local func=function(self) - if init then - local vel = self.object:get_velocity() - self.object:set_velocity(mobkit.pos_shift(vel,{y=1})) - mobkit.animate(self,'stand') - init = false - end - zrot=zrot+pi*0.05 - local rot = self.object:get_rotation() - self.object:set_rotation({x=rot.x,y=rot.y,z=zrot}) - if zrot >= pi*0.5 then return true end - end - mobkit.queue_low(self,func) -end ------------------------------ --- HIGH LEVEL QUEUE FUNCTIONS ------------------------------ - -function mobkit.dumbstep(self,height,tpos,speed_factor) - if height <= 0.001 then - mobkit.lq_turn2pos(self,tpos) - mobkit.lq_dumbwalk(self,tpos,speed_factor) - else - mobkit.lq_turn2pos(self,tpos) - mobkit.lq_dumbjump(self,height) - end - mobkit.lq_idle(self,random(1,6)) -end - -function mobkit.hq_roam(self,prty) - local func=function(self) - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - local neighbor = random(8) - - local height, tpos, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor) - if height and not liquidflag then mobkit.dumbstep(self,height,tpos,0.3) end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_follow0(self,tgtobj) -- probably delete this one - local func = function(self) - if not tgtobj then return true end - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - local opos = tgtobj:get_pos() - if vector.distance(pos,opos) > 3 then - local neighbor = mobkit.dir2neighbor(vector.direction(pos,opos)) -if not neighbor then return true end --temp debug - local height, tpos = mobkit.is_neighbor_node_reachable(self,neighbor) - if height then mobkit.dumbstep(self,height,tpos) - else - for i=1,4 do --scan left - height, tpos = mobkit.is_neighbor_node_reachable(self,(8+neighbor-i-1)%8+1) - if height then mobkit.dumbstep(self,height,tpos) - break - end --scan right - height, tpos = mobkit.is_neighbor_node_reachable(self,(neighbor+i-1)%8+1) - if height then mobkit.dumbstep(self,height,tpos) - break - end - end - end - else - mobkit.lq_idle(self,1) - end - end - end - mobkit.queue_high(self,func,0) -end - -function mobkit.hq_follow(self,prty,tgtobj) - local func = function(self) - if not mobkit.is_alive(tgtobj) then return true end - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - local opos = tgtobj:get_pos() - if vector.distance(pos,opos) > 3 then - mobkit.goto_next_waypoint(self,opos) - else - mobkit.lq_idle(self,1) - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_goto(self,prty,tpos) - local func = function(self) - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - if vector.distance(pos,tpos) > 3 then - mobkit.goto_next_waypoint(self,tpos) - else - return true - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_runfrom(self,prty,tgtobj) - local init=true - local timer=6 - local func = function(self) - - if not mobkit.is_alive(tgtobj) then return true end - if init then - timer = timer-self.dtime - if timer <=0 or vector.distance(self.object:get_pos(),tgtobj:get_pos()) < 8 then - mobkit.make_sound(self,'scared') - init=false - end - return - end - - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - local opos = tgtobj:get_pos() - if vector.distance(pos,opos) < self.view_range*1.1 then - local tpos = {x=2*pos.x - opos.x, - y=opos.y, - z=2*pos.z - opos.z} - mobkit.goto_next_waypoint(self,tpos) - else - self.object:set_velocity({x=0,y=0,z=0}) - return true - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_hunt(self,prty,tgtobj) - local func = function(self) - if not mobkit.is_alive(tgtobj) then return true end - if mobkit.is_queue_empty_low(self) and self.isonground then - local pos = mobkit.get_stand_pos(self) - local opos = tgtobj:get_pos() - local dist = vector.distance(pos,opos) - if dist > self.view_range then - return true - elseif dist > 3 then - mobkit.goto_next_waypoint(self,opos) - else - mobkit.hq_attack(self,prty+1,tgtobj) - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_warn(self,prty,tgtobj) - timer=0 - tgttime = 0 - local func = function(self) - if not mobkit.is_alive(tgtobj) then return true end - local pos = mobkit.get_stand_pos(self) - local opos = tgtobj:get_pos() - local dist = vector.distance(pos,opos) - - if dist > 11 then - return true - elseif dist < 4 or timer > 12 then -- too close man --- mobkit.clear_queue_high(self) - mobkit.remember(self,'hate',tgtobj:get_player_name()) - mobkit.hq_hunt(self,prty+1,tgtobj) -- priority - else - timer = timer+self.dtime - if mobkit.is_queue_empty_low(self) then - mobkit.lq_turn2pos(self,opos) - end - -- make noise in random intervals - if timer > tgttime then - mobkit.make_sound(self,'warn') - -- if self.sounds and self.sounds.warn then - -- minetest.sound_play(self.sounds.warn, {object=self.object}) - -- end - tgttime = timer + 1.1 + random()*1.5 - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_die(self) - local timer = 5 - local start = true - local func = function(self) - if start then - mobkit.lq_fallover(self) - self.brainfunc = function(self) end -- brain dead as well - start=false - end - timer = timer-self.dtime - if timer < 0 then self.object:remove() end - end - mobkit.queue_high(self,func,100) -end - -function mobkit.hq_attack(self,prty,tgtobj) - local func = function(self) - if not mobkit.is_alive(tgtobj) then return true end - if mobkit.is_queue_empty_low(self) then - local pos = mobkit.get_stand_pos(self) --- local tpos = tgtobj:get_pos() - local tpos = mobkit.get_stand_pos(tgtobj) - local dist = vector.distance(pos,tpos) - if dist > 3 then - return true - else - mobkit.lq_turn2pos(self,tpos) - local height = tgtobj:is_player() and 0.8 or tgtobj:get_luaentity().height*0.6 - if tpos.y+height>pos.y then - mobkit.lq_jumpattack(self,tpos.y+height-pos.y,tgtobj) - else - mobkit.lq_dumbwalk(self,mobkit.pos_shift(tpos,{x=random()-0.5,z=random()-0.5})) - end - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_liquid_recovery(self,prty) -- scan for nearest land - local radius = 1 - local yaw = 0 - local func = function(self) - if not self.isinliquid then return true end - local pos=self.object:get_pos() - local vec = minetest.yaw_to_dir(yaw) - local pos2 = mobkit.pos_shift(pos,vector.multiply(vec,radius)) - local height, liquidflag = mobkit.get_terrain_height(pos2) - if height and not liquidflag then - mobkit.hq_swimto(self,prty,pos2) - return true - end - yaw=yaw+pi*0.25 - if yaw>2*pi then - yaw = 0 - radius=radius+1 - if radius > self.view_range then - self.hp = 0 - return true - end - end - end - mobkit.queue_high(self,func,prty) -end - -function mobkit.hq_swimto(self,prty,tpos) - local func = function(self) --- if not self.isinliquid and mobkit.is_queue_empty_low(self) then return true end - if not self.isinliquid and self.isonground then return true end --- local pos = self.object:get_pos() - local pos = mobkit.get_stand_pos(self) - local y=self.object:get_velocity().y - local pos2d = {x=pos.x,y=0,z=pos.z} - local dir=vector.normalize(vector.direction(pos2d,tpos)) - local yaw = minetest.dir_to_yaw(dir) - - if mobkit.timer(self,1) then ---perpendicular vectors: {-z,x};{z,-x} - local offset=self.collisionbox[1] - local pos1 = mobkit.pos_shift(mobkit.pos_shift(pos,{x=-dir.z*offset,z=dir.x*offset}),dir) - local h,l = mobkit.get_terrain_height(pos1) - if h and h>pos.y then - mobkit.lq_freejump(self) - else - local pos2 = mobkit.pos_shift(mobkit.pos_shift(pos,{x=dir.z*offset,z=-dir.x*offset}),dir) - local h,l = mobkit.get_terrain_height(pos2) - if h and h>pos.y then - mobkit.lq_freejump(self) - end - end - elseif mobkit.turn2yaw(self,yaw) then - dir.y = y - self.object:set_velocity(dir) - end - end - mobkit.queue_high(self,func,prty) -end - ------------- --- CALLBACKS ------------- - -function mobkit.default_brain(self) - if mobkit.is_queue_empty_high(self) then mobkit.hq_roam(self,0) end -end - -function mobkit.statfunc(self) - local tmptab={} - tmptab.memory = self.memory - tmptab.hp = self.hp - tmptab.texture_no = self.texture_no - return minetest.serialize(tmptab) -end - -function mobkit.actfunc(self, staticdata, dtime_s) - self.lqueue = {} - self.hqueue = {} - self.nearby_objects = {} - self.nearby_players = {} - self.pos_history = {} - self.path_dir = 1 - self.time_total = 0 - - local sdata = minetest.deserialize(staticdata) - if sdata then - for k,v in pairs(sdata) do - self[k] = v - end - end - - if self.timeout and self.timeout>0 and dtime_s > self.timeout and next(self.memory)==nil then - self.object:remove() - end - - if not self.memory then -- this is the initial activation - self.memory = {} - - -- texture variation - if #self.textures > 1 then self.texture_no = random(#self.textures) end - end - - -- apply texture - if self.texture_no then - local props = {} - props.textures = {self.textures[self.texture_no]} - self.object:set_properties(props) - end - ---hp - self.hp = self.hp or (self.max_hp or 10) ---armor - if type(self.armor_groups) ~= 'table' then - self.armor_groups={} - end - self.armor_groups.immortal = 1 - self.object:set_armor_groups(self.armor_groups) - - self.oxygen = self.oxygen or self.lung_capacity - self.lastvelocity = {x=0,y=0,z=0} - self.height = self.collisionbox[5] - self.collisionbox[2] - self.sensefunc=sensors() -end - -function mobkit.stepfunc(self,dtime) -- not intended to be modified - self.dtime = dtime --- physics comes first --- self.object:set_acceleration({x=0,y=mobkit.gravity,z=0}) - local vel = self.object:get_velocity() - --- if self.lastvelocity.y == vel.y then - if abs(self.lastvelocity.y-vel.y)<0.001 then - self.isonground = true - else - self.isonground = false - end - - -- dumb friction - if self.isonground then - self.object:set_velocity({x= vel.x> 0.2 and vel.x*mobkit.friction or 0, - y=vel.y, - z=vel.z > 0.2 and vel.z*mobkit.friction or 0}) - end - --- bounciness - if self.springiness and self.springiness > 0 then - local vnew = vector.new(vel) - - if not self.collided then -- ugly workaround for inconsistent collisions - for _,k in ipairs({'y','z','x'}) do - if vel[k]==0 and abs(self.lastvelocity[k])> 0.1 then - vnew[k]=-self.lastvelocity[k]*self.springiness - end - end - end - - if not vector.equals(vel,vnew) then - self.collided = true - else - if self.collided then - vnew = vector.new(self.lastvelocity) - end - self.collided = false - end - - self.object:set_velocity(vnew) - end - - -- buoyancy - local spos = mobkit.get_stand_pos(self) - spos.y = spos.y+0.01 - -- get surface height --- local surface = mobkit.get_node_pos(spos).y+0.5 - local surface = nil - local snodepos = mobkit.get_node_pos(spos) - local surfnode = mobkit.nodeatpos(spos) - while surfnode and surfnode.drawtype == 'liquid' do - surface = snodepos.y+0.5 - if surface > spos.y+self.height then break end - snodepos.y = snodepos.y+1 - surfnode = mobkit.nodeatpos(snodepos) - end - if surface then -- standing in liquid - self.isinliquid = true - local submergence = min(surface-spos.y,self.height) - local balance = self.buoyancy*self.height - local buoyacc = mobkit.gravity*((balance - submergence)^2/balance^2*sign(balance - submergence)) - self.object:set_acceleration({x=-vel.x,y=buoyacc-vel.y*abs(vel.y)*0.7,z=-vel.z}) - else - self.isinliquid = false - self.object:set_acceleration({x=0,y=mobkit.gravity,z=0}) - end - - - - -- local footnode = mobkit.nodeatpos(spos) - -- local headnode - -- if footnode and footnode.drawtype == 'liquid' then - - -- vel = self.object:get_velocity() - -- headnode = mobkit.nodeatpos(mobkit.pos_shift(spos,{y=self.height or 0})) -- TODO: height may be nil - -- local submergence = headnode.drawtype=='liquid' - -- and self.buoyancy-1 - -- or (self.buoyancy*self.height-(1-(spos.y+0.5)%1))^2/(self.buoyancy*self.height)^2*sign(self.buoyancy*self.height-(1-(spos.y+0.5)%1)) - - -- local buoyacc = submergence * mobkit.gravity - -- self.object:set_acceleration({x=-vel.x,y=buoyacc-vel.y*abs(vel.y)*0.5,z=-vel.z}) - - -- end - - if self.brainfunc then - -- vitals: fall damage - vel = self.object:get_velocity() - local velocity_delta = abs(self.lastvelocity.y - vel.y) - if velocity_delta > mobkit.safe_velocity then - self.hp = self.hp - floor((self.max_hp-100) * min(1, velocity_delta/mobkit.terminal_velocity)) - end - - -- vitals: oxygen - local headnode = mobkit.nodeatpos(mobkit.pos_shift(self.object:get_pos(),{y=self.collisionbox[5]})) -- node at hitbox top - if headnode and headnode.drawtype == 'liquid' then - self.oxygen = self.oxygen - self.dtime - else - self.oxygen = self.lung_capacity - end - - if self.oxygen <= 0 then self.hp=0 end -- drown - - - self:sensefunc() - self:brainfunc() - execute_queues(self) - end - - self.lastvelocity = self.object:get_velocity() - self.time_total=self.time_total+self.dtime - -end - ---]] \ No newline at end of file