From d8e120eb101987f5590398b4c2d4a00d57fe2058 Mon Sep 17 00:00:00 2001 From: rnd1 Date: Sun, 7 Feb 2016 22:31:59 +0100 Subject: [PATCH] Mobs REDO with pathfinding by rnd --- api.lua | 71 +++++++++++++++++++++++++++++++++++++++++++++++------ oerkki.lua | 2 +- warthog.lua | 2 +- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/api.lua b/api.lua index ebe02cd..4536dfe 100644 --- a/api.lua +++ b/api.lua @@ -9,6 +9,9 @@ local disable_blood = minetest.setting_getbool("mobs_disable_blood") local creative = minetest.setting_getbool("creative_mode") local spawn_protected = tonumber(minetest.setting_get("mobs_spawn_protected")) or 1 local remove_far = minetest.setting_getbool("remove_far_mobs") +-- PATHFINDING settings +local stuck_timeout = 5 -- how long before mob gets stuck in place and starts searching +local stuck_path_timeout = 15 -- how long will mob follow path before giving up -- internal functions @@ -891,6 +894,7 @@ minetest.register_entity(name, { and self.state ~= "attack" and not day_docile(self) then + -- rnd to do: if stuck then find better way local s = self.object:getpos() local p, sp, dist local player = nil @@ -1257,7 +1261,7 @@ minetest.register_entity(name, { end -- attack routines (explode, dogfight, shoot, dogshoot) - elseif self.state == "attack" then + elseif self.state == "attack" then -- rnd : to do if cant attack search better way -- calculate distance from mob and enemy local s = self.object:getpos() @@ -1302,7 +1306,7 @@ minetest.register_entity(name, { self.object:setyaw(yaw) end - if dist > self.reach then + if dist > self.reach then if not self.v_start then @@ -1385,12 +1389,12 @@ minetest.register_entity(name, { or (self.attack_type == "dogshoot" and dist <= self.reach) then if self.fly - and dist > self.reach then + and dist > self.reach then local nod = node_ok(s) - local p1 = s + local p1 = s local me_y = math.floor(p1.y) - local p2 = p + local p2 = p local p_y = math.floor(p2.y + 1) local v = self.object:getvelocity() @@ -1433,6 +1437,17 @@ minetest.register_entity(name, { end + -- rnd: new movement direction + + if self.path.stuck and self.path.way then + if #self.path.way>50 then self.path.stuck = false return end -- no paths longer than 50 + local p1 = self.path.way[1]; if not p1 then self.path.stuck = false return end + if math.abs(p1.x-s.x)+math.abs(p1.z-s.z)<0.75 then -- reached waypoint, remove it from queue + table.remove(self.path.way,1); + end + p = {x=p1.x,y=p1.y,z=p1.z}; -- set new temporary target + end + local vec = { x = p.x - s.x, y = p.y - s.y, @@ -1447,22 +1462,51 @@ minetest.register_entity(name, { if p.x > s.x then yaw = yaw + pi end - - self.object:setyaw(yaw) + + self.object:setyaw(yaw) -- rnd: look toward target end -- move towards enemy if beyond mob reach if dist > self.reach then + -- PATH FINDING by rnd + local s1 = self.path.lastpos; + if math.abs(s1.x-s.x)+math.abs(s1.z-s.z)<2 then -- rnd: almost standing still, to do: insert path finding here + self.path.stuck_timer = self.path.stuck_timer+dtime + else self.path.stuck_timer = 0; + end + self.path.lastpos = {x=s.x,y=s.y,z=s.z}; + if (self.path.stuck_timer>stuck_timeout and not self.path.stuck) or (self.path.stuck_timer>stuck_path_timeout and self.path.stuck) then -- im stuck, search for path + self.path.stuck = true; + local sheight=self.collisionbox[5]-self.collisionbox[2]; + s.x=math.floor(s.x+0.5);s.y=math.floor(s.y+0.5)-sheight;s.z=math.floor(s.z+0.5); -- round position to center of node to avoid stuck in walls, also adjust height for player models! + --minetest.chat_send_all("stuck at " .. s.x .." " .. s.y .. " " .. s.z .. ", calculating path") + local p1 = self.attack:getpos();p1.x=math.floor(p1.x+0.5);p1.y=math.floor(p1.y+0.5);p1.z=math.floor(p1.z+0.5); + --minetest.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm) + self.path.way = minetest.find_path(s, p1, 16, 2, 6,"A*_noprefetch"); --"A*_noprefetch"); + if not self.path.way then + self.path.stuck=false + minetest.sound_play(self.sounds.attack, { -- play sound to acknowledge found way + object = self.object, + max_hear_distance = self.sounds.distance + }) + --else minetest.chat_send_all("found path with length " .. #self.path.way); + end + self.path.stuck_timer=0; + end + -- END PATH FINDING + -- jump attack if (self.jump - and get_velocity(self) <= 0.5 + and get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0) or (self.object:getvelocity().y == 0 and self.jump_chance > 0) then do_jump(self) end + + if is_at_cliff(self) then @@ -1498,6 +1542,8 @@ minetest.register_entity(name, { max_hear_distance = self.sounds.distance }) end + + self.path.stuck = false; -- rnd: no more stuck -- punch player self.attack:punch(self.object, 1.0, { @@ -1769,6 +1815,15 @@ minetest.register_entity(name, { if self.health == 0 then self.health = math.random (self.hp_min, self.hp_max) end + + -- rnd: pathfinding init + + self.path = {}; + self.path.way = {};-- path to follow, table of positions + self.path.lastpos = {x=0,y=0,z=0}; + self.path.stuck = false; + self.path.stuck_timer = 0; -- if stuck for too long search for path, stuck if v.x, v.z has magnitude smaller than 0.25 for too long + self.object:set_hp(self.health) self.object:set_armor_groups({fleshy = self.armor}) diff --git a/oerkki.lua b/oerkki.lua index a6ae699..457f77d 100644 --- a/oerkki.lua +++ b/oerkki.lua @@ -32,7 +32,7 @@ mobs:register_mob("mobs:oerkki", { water_damage = 2, lava_damage = 4, light_damage = 1, - fear_height = 3, + fear_height = 6, animation = { stand_start = 0, stand_end = 23, diff --git a/warthog.lua b/warthog.lua index d30a0ed..e4e6a96 100644 --- a/warthog.lua +++ b/warthog.lua @@ -34,7 +34,7 @@ mobs:register_mob("mobs:pumba", { water_damage = 1, lava_damage = 5, light_damage = 0, - fear_height = 2, + fear_height = 6, animation = { speed_normal = 15, stand_start = 25,