diff --git a/mods/mobs/README.txt b/mods/mobs/README.txt index 43fb832..39723ed 100755 --- a/mods/mobs/README.txt +++ b/mods/mobs/README.txt @@ -28,6 +28,13 @@ This mod contains the following additions: Changelog: +1.26- Pathfinding feature added thanks to rnd, when monsters attack they become scary smart in finding you :) +1.25- Mobs no longer spawn within 12 blocks of player or despawn within same range, spawners now have player detection, Code tidy and tweak. +1.24- Added feature where certain animals run away when punched (runaway = true in mob definition) +1.23- Added mob spawner block for admin to setup spawners in-game (place and right click to enter settings) +1.22- Added ability to name tamed animals and npc using nametags, also npc will attack anyone who punches them apart from owner +1.21- Added some more error checking to reduce serialize.h error and added height checks for falling off cliffs (thanks cmdskp) +1.20- Error checking added to remove bad mobs, out of map limit mobs and stop serialize.h error 1.19- Chickens now drop egg items instead of placing the egg, also throwing eggs result in 1/8 chance of spawning chick 1.18- Added docile_by_day flag so that monsters will not attack automatically during daylight hours unless hit first 1.17- Added 'dogshoot' attack type, shoots when out of reach, melee attack when in reach, also api tweaks and self.reach added @@ -57,4 +64,4 @@ beta- Npc mob added, kills monsters, attacks player when punched, right click wi 0.4 - Dungeon Masters and Mese Monsters have much better aim due to shoot_offset, also they can both shoot through nodes that aren't walkable (flowers, grass etc) plus new sheep sound :) 0.3 - Added LOTT's Spider mob, made Cobwebs, added KPavel's Bee with Honey and Beehives (made texture), Warthogs now have sound and can be tamed, taming of shaved sheep or milked cow with 8 wheat so it will not despawn, many bug fixes :) 0.2 - Cooking bucket of milk into cheese now returns empty bucket -0.1 - Initial Release \ No newline at end of file +0.1 - Initial Release diff --git a/mods/mobs/api.lua b/mods/mobs/api.lua index 396e911..724b2c0 100755 --- a/mods/mobs/api.lua +++ b/mods/mobs/api.lua @@ -1,4 +1,4 @@ --- Mobs Api (2nd February 2016) +-- Mobs Api (8th February 2016) mobs = {} mobs.mod = "redo" @@ -10,6 +10,11 @@ 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 enable_pathfinding = true +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 local pi = math.pi @@ -1453,6 +1458,32 @@ minetest.register_entity(name, { end + -- rnd: new movement direction + if self.path.stuck + and self.path.way then + + -- no paths longer than 50 + if #self.path.way > 50 then + self.path.stuck = false + return + end + + 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 + + -- set new temporary target + p = {x = p1.x, y = p1.y, z = p1.z} + end + local vec = { x = p.x - s.x, y = p.y - s.y, @@ -1474,6 +1505,86 @@ minetest.register_entity(name, { -- move towards enemy if beyond mob reach if dist > self.reach then + -- PATH FINDING by rnd + if enable_pathfinding then + + 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] + + -- round position to center of node to avoid stuck in walls, + -- also adjust height for player models! + 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) + + local ssight, sground + + ssight, sground = minetest.line_of_sight(s, + {x = s.x, y = s. y - 4, z = s.z}, 1) + + -- determine node above ground + if not ssight then + s.y = sground.y + 1 + end + + --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") + + if not self.path.way then + + self.path.stuck = false + + -- can't find path, play sound + if self.sounds.random then + minetest.sound_play(self.sounds.random, { + object = self.object, + max_hear_distance = self.sounds.distance + }) + end + else + -- found path, play sound + if self.sounds.attack then + minetest.sound_play(self.sounds.attack, { + object = self.object, + max_hear_distance = self.sounds.distance + }) + end + + --minetest.chat_send_all("found path with length " .. #self.path.way); + end + + self.path.stuck_timer = 0 + + end -- END if pathfinding enabled + end + -- END PATH FINDING + -- jump attack if (self.jump and get_velocity(self) <= 0.5 @@ -1519,6 +1630,9 @@ minetest.register_entity(name, { }) end + -- rnd: not stuck + self.path.stuck = false + -- punch player self.attack:punch(self.object, 1.0, { full_punch_interval = 1.0, @@ -1650,10 +1764,16 @@ minetest.register_entity(name, { local v = self.object:getvelocity() local r = 1.4 - math.min(punch_interval, 1.4) local kb = r * 5 + local up = 2 + + -- if already in air then dont go up anymore when hit + if v.y > 0 then + up = 0 + end self.object:setvelocity({ x = (dir.x or 0) * kb, - y = 2, + y = up, z = (dir.z or 0) * kb }) @@ -1689,15 +1809,16 @@ minetest.register_entity(name, { self.following = nil end - -- attack puncher and call other mobs for help if self.passive == false and self.child == false and hitter:get_player_name() ~= self.owner then - if self.state ~= "attack" then + --if self.state ~= "attack" then + -- attack whoever punched mob + self.state = "" do_attack(self, hitter) - end + --end -- alert others to the attack local obj = nil @@ -1791,6 +1912,14 @@ minetest.register_entity(name, { 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 + -- end init + self.object:set_hp(self.health) self.object:set_armor_groups({fleshy = self.armor}) self.old_y = self.object:getpos().y @@ -2108,7 +2237,8 @@ function mobs:register_arrow(name, def) local node = node_ok(pos).name - if minetest.registered_nodes[node].walkable then + --if minetest.registered_nodes[node].walkable then + if node ~= "air" then self.hit_node(self, pos, node)