From 53cc10a16fffcbf221bcb23ec49dab24d5f55cf3 Mon Sep 17 00:00:00 2001 From: tenplus1 Date: Fri, 15 May 2020 13:26:34 +0100 Subject: [PATCH] Code tweak and tidy, mob counter attempt --- api.lua | 398 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 149 deletions(-) diff --git a/api.lua b/api.lua index 9a3d47d..ba92e60 100644 --- a/api.lua +++ b/api.lua @@ -6,15 +6,21 @@ local use_cmi = minetest.global_exists("cmi") mobs = { mod = "redo", - version = "20200513", + version = "20200515", intllib = S, invis = minetest.global_exists("invisibility") and invisibility or {} } +-- mob table and limit (not active) +local active_mobs = 0 +local active_limit = 99 + + -- creative check local creative_cache = minetest.settings:get_bool("creative_mode") function mobs.is_creative(name) - return creative_cache or minetest.check_player_privs(name, {creative = true}) + return creative_cache or minetest.check_player_privs(name, + {creative = true}) end @@ -68,7 +74,7 @@ local aoc_range = tonumber(minetest.settings:get("active_block_range")) * 16 -- pathfinding settings local enable_pathfinding = true -local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching +local stuck_timeout = 3 -- how long before stuck mod starts searching local stuck_path_timeout = 10 -- how long will mob follow path before giving up -- default nodes @@ -337,7 +343,8 @@ function mob_class:set_animation(anim, force) self.object:set_animation({ x = self.animation[anim .. "_start"], y = self.animation[anim .. "_end"]}, - self.animation[anim .. "_speed"] or self.animation.speed_normal or 15, + self.animation[anim .. "_speed"] or + self.animation.speed_normal or 15, 0, self.animation[anim .. "_loop"] ~= false) end @@ -468,18 +475,16 @@ local ray_line_of_sight = function(self, pos1, pos2) local ray = minetest.raycast(pos1, pos2, true, false) local thing = ray:next() - while thing do - --- if thing.type == "object" --- and thing.ref ~= self.object --- and not thing.ref:is_player() then return false end + while thing do -- thing.type, thing.ref if thing.type == "node" then local name = minetest.get_node(thing.under).name if minetest.registered_items[name] - and minetest.registered_items[name].walkable then return false end + and minetest.registered_items[name].walkable then + return false + end end thing = ray:next() @@ -521,8 +526,7 @@ function mob_class:attempt_flight_correction(override) local flyable_nodes = minetest.find_nodes_in_area( {x = pos.x - 1, y = pos.y - 1, z = pos.z - 1}, - {x = pos.x + 1, y = pos.y + 1, z = pos.z + 1}, - searchnodes) + {x = pos.x + 1, y = pos.y + 1, z = pos.z + 1}, searchnodes) if #flyable_nodes < 1 then return false @@ -595,7 +599,7 @@ function mobs:yaw_to_pos(self, target, rot) end --- if self.stay_near set then check periodically for nodes and turn to face/move +-- if stay near set then check periodically for nodes and turn towards them function mob_class:do_stay_near() if not self.stay_near then return false end @@ -632,8 +636,8 @@ end -- custom particle effects -local effect = function( - pos, amount, texture, min_size, max_size, radius, gravity, glow, fall) +local effect = function(pos, amount, texture, min_size, max_size, + radius, gravity, glow, fall) radius = radius or 2 min_size = min_size or 0.5 @@ -695,7 +699,8 @@ function mob_class:item_drop() local pos = self.object:get_pos() -- check for drops function - self.drops = type(self.drops) == "function" and self.drops(pos) or self.drops + self.drops = type(self.drops) == "function" + and self.drops(pos) or self.drops -- check for nil or no drops if not self.drops or #self.drops == 0 then @@ -703,7 +708,8 @@ function mob_class:item_drop() end -- was mob killed by player? - local death_by_player = self.cause_of_death and self.cause_of_death.puncher + local death_by_player = self.cause_of_death + and self.cause_of_death.puncher and self.cause_of_death.puncher:is_player() or nil local obj, item, num @@ -752,6 +758,23 @@ function mob_class:item_drop() end +-- remove mob and descrease counter +local remove_mob = function(self, decrease) + + self.object:remove() + + if decrease then + +-- active_mobs = active_mobs - 1 + + if active_mobs < 0 then + active_mobs = 0 + end + end +--print("-- active mobs: " .. active_mobs .. " / " .. active_limit) +end + + -- check if mob is dead or only hurt function mob_class:check_for_death(cmi_cause) @@ -812,7 +835,7 @@ function mob_class:check_for_death(cmi_cause) cmi.notify_die(self.object, cmi_cause) end - self.object:remove() + remove_mob(self, true) return true end @@ -841,7 +864,8 @@ function mob_class:check_for_death(cmi_cause) cmi.notify_die(self.object, cmi_cause) end - self.object:remove() + remove_mob(self, true) + end, self) else @@ -849,7 +873,7 @@ function mob_class:check_for_death(cmi_cause) cmi.notify_die(self.object, cmi_cause) end - self.object:remove() + remove_mob(self, true) end effect(pos, 20, "tnt_smoke.png") @@ -955,10 +979,10 @@ function mob_class:do_env_damage() self.time_of_day = minetest.get_timeofday() - -- remove mob if standing inside ignore node + -- halt mob if standing inside ignore node if self.standing_in == "ignore" then - self.object:remove() + self.object:set_velocity(0) return true end @@ -975,7 +999,9 @@ function mob_class:do_env_damage() effect(pos, 5, "tnt_smoke.png") - if self:check_for_death({type = "light"}) then return true end + if self:check_for_death({type = "light"}) then + return true + end end end @@ -993,7 +1019,9 @@ function mob_class:do_env_damage() effect(pos, 5, "bubble.png", nil, nil, 1, nil) if self:check_for_death({type = "environment", - pos = pos, node = self.standing_in}) then return true end + pos = pos, node = self.standing_in}) then + return true + end end -- ignition source (fire or lava) @@ -1006,7 +1034,9 @@ function mob_class:do_env_damage() effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil) if self:check_for_death({type = "environment", pos = pos, - node = self.standing_in, hot = true}) then return true end + node = self.standing_in, hot = true}) then + return true + end end -- damage_per_second node check @@ -1017,7 +1047,9 @@ function mob_class:do_env_damage() effect(pos, 5, "tnt_smoke.png") if self:check_for_death({type = "environment", - pos = pos, node = self.standing_in}) then return true end + pos = pos, node = self.standing_in}) then + return true + end end --- suffocation inside solid node @@ -1038,7 +1070,9 @@ function mob_class:do_env_damage() self.health = self.health - damage if self:check_for_death({type = "suffocation", - pos = pos, node = self.standing_in}) then return true end + pos = pos, node = self.standing_in}) then + return true + end end return self:check_for_death({type = "unknown"}) @@ -1076,7 +1110,7 @@ function mob_class:do_jump() local nod = node_ok(pos) ---print ("standing on:", nod.name, pos.y) +--print("standing on:", nod.name, pos.y) if minetest.registered_nodes[nod.name].walkable == false then return false @@ -1102,8 +1136,8 @@ function mob_class:do_jump() local blocked = minetest.registered_nodes[nodt.name].walkable ---print ("in front:", nod.name, pos.y + 0.5) ---print ("in front above:", nodt.name, pos.y + 1.5) +--print("in front:", nod.name, pos.y + 0.5) +--print("in front above:", nodt.name, pos.y + 1.5) -- jump if standing on solid node (not snow) and not blocked above if (self.walk_chance == 0 @@ -1326,6 +1360,15 @@ function mob_class:breed() self.hornytimer = 41 ent.hornytimer = 41 + -- have we reached active mob limit + if active_mobs >= active_limit then + minetest.chat_send_player(self.owner, + S("Active Mob Limit Reached!") + .. " (" .. active_mobs + .. " / " .. active_limit .. ")") + return + end + -- spawn baby minetest.after(5, function(self, ent) @@ -1348,6 +1391,8 @@ function mob_class:breed() local ent2 = mob:get_luaentity() local textures = self.base_texture +-- active_mobs = active_mobs + 1 + -- using specific child texture (if found) if self.child_texture then textures = self.child_texture[1] @@ -1423,7 +1468,7 @@ function mob_class:replace(pos) if #minetest.find_nodes_in_area(pos, pos, what) > 0 then --- print ("replace node = ".. minetest.get_node(pos).name, pos.y) +-- print("replace node = ".. minetest.get_node(pos).name, pos.y) if self.on_replace then @@ -1602,7 +1647,7 @@ function mob_class:smart_mobs(s, p, dist, dtime) --[[ -- show path using particles if self.path.way and #self.path.way > 0 then - print ("-- path length:" .. tonumber(#self.path.way)) + print("-- path length:" .. tonumber(#self.path.way)) for _,pos in pairs(self.path.way) do minetest.add_particle({ pos = pos, @@ -1774,7 +1819,7 @@ function mob_class:general_attack() -- are we a player? if objs[n]:is_player() then - -- if player invisible or mob not setup to attack then remove from list + -- if player invisible or mob cannot attack then remove from list if self.attack_players == false or (self.owner and self.type ~= "monster") or mobs.invis[objs[n]:get_player_name()] @@ -2264,14 +2309,14 @@ function mob_class:do_states(dtime) self.blinktimer = 0 self:mob_sound(self.sounds.fuse) ---print ("=== explosion timer started", self.explosion_timer) +--print("=== explosion timer started", self.explosion_timer) -- stop timer if out of reach or direct line of sight elseif self.allow_fuse_reset and self.v_start and (dist > self.reach or not self:line_of_sight(s, p, 2)) then ---print ("=== explosion timer stopped") +--print("=== explosion timer stopped") self.v_start = false self.timer = 0 @@ -2311,7 +2356,7 @@ function mob_class:do_states(dtime) self.blinkstatus = not self.blinkstatus end ---print ("=== explosion timer", self.timer) +--print("=== explosion timer", self.timer) if self.timer > self.explosion_timer then @@ -2324,7 +2369,7 @@ function mob_class:do_states(dtime) node_break_radius = 1 end - self.object:remove() + remove_mob(self, true) if minetest.get_modpath("tnt") and tnt and tnt.boom and not minetest.is_protected(pos, "") then @@ -2343,7 +2388,9 @@ function mob_class:do_states(dtime) }) entity_physics(pos, entity_damage_radius) - effect(pos, 32, "tnt_smoke.png", nil, nil, node_break_radius, 1, 0) + + effect(pos, 32, "tnt_smoke.png", nil, nil, + node_break_radius, 1, 0) end return true @@ -2643,7 +2690,7 @@ end local tr = minetest.get_modpath("toolranks") -- deal damage and effects when mob punched -function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) +function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) -- mob health check if self.health <= 0 then @@ -2658,14 +2705,19 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) -- error checking when mod profiling is enabled if not tool_capabilities then - minetest.log("warning", "[mobs] Mod profiling enabled, damage not enabled") + minetest.log("warning", + "[mobs] Mod profiling enabled, damage not enabled") return end -- is mob protected? if self.protected and hitter:is_player() - and minetest.is_protected(self.object:get_pos(), hitter:get_player_name()) then - minetest.chat_send_player(hitter:get_player_name(), S("Mob has been protected!")) + and minetest.is_protected(self.object:get_pos(), + hitter:get_player_name()) then + + minetest.chat_send_player(hitter:get_player_name(), + S("Mob has been protected!")) + return end @@ -2710,20 +2762,20 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) damage = self.immune_to[n][2] or 0 break - -- if "all" then no tool does damage unless it's specified in list + -- if "all" then no tools deal damage unless it's specified in list elseif self.immune_to[n][1] == "all" then damage = self.immune_to[n][2] or 0 end end +--print("Mob Damage is", damage) + -- healing if damage <= -1 then self.health = self.health - floor(damage) - return + return true end ---print ("Mob Damage is", damage) - if use_cmi and cmi.notify_punch( self.object, hitter, tflp, tool_capabilities, dir, damage) then @@ -2781,7 +2833,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) local blood = self.blood_texture local amount = self.blood_amount - pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5 + pos.y = pos.y + (-self.collisionbox[2] + + self.collisionbox[5]) * .5 -- lots of damage = more blood :) if damage > 10 then @@ -2806,10 +2859,10 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) if self:check_for_death({type = "punch", puncher = hitter, hot = hot}) then - return + return true end - --[[ add healthy afterglow when hit (can cause hit lag with larger textures) + --[[ add healthy afterglow when hit (causes lag with large textures) minetest.after(0.1, function() if not self.object:get_luaentity() then return end @@ -2924,9 +2977,9 @@ function mob_class:mob_staticdata() and not self.tamed and self.lifetimer < 20000 then ---print ("REMOVED " .. self.name) +--print("REMOVED " .. self.name) - self.object:remove() + remove_mob(self, true) return minetest.serialize({remove_ok = true, static_save = true}) end @@ -2937,8 +2990,7 @@ function mob_class:mob_staticdata() self.state = "stand" -- used to rotate older mobs - if self.drawtype - and self.drawtype == "side" then + if self.drawtype and self.drawtype == "side" then self.rotate = math.rad(90) end @@ -2971,14 +3023,21 @@ end function mob_class:mob_activate(staticdata, def, dtime) -- remove monsters in peaceful mode - if self.type == "monster" - and peaceful_only then + if self.type == "monster" and peaceful_only then - self.object:remove() + remove_mob(self, true) return end + -- remove mob if not tamed and mob total reached + if active_mobs >= active_limit and not self.tamed then + + remove_mob(self) +--print("-- mob limit reached, removing " .. self.name) + return + end + -- load entity variables local tmp = minetest.deserialize(staticdata) @@ -2988,6 +3047,13 @@ function mob_class:mob_activate(staticdata, def, dtime) end end + -- add currently spawned mobs to total + -- this is buggy as it doubles count when mobs unloaded and reloaded + if self.standing_in then +-- active_mobs = active_mobs + 1 +--print("-- active mobs: " .. active_mobs .. " / " .. active_limit) + end + -- force current model into mob self.mesh = def.mesh self.base_mesh = def.mesh @@ -3002,7 +3068,8 @@ function mob_class:mob_activate(staticdata, def, dtime) def.textures = {def.textures} end - self.base_texture = def.textures and def.textures[random(1, #def.textures)] + self.base_texture = def.textures and + def.textures[random(1, #def.textures)] self.base_mesh = def.mesh self.base_size = self.visual_size self.base_colbox = self.collisionbox @@ -3022,14 +3089,12 @@ function mob_class:mob_activate(staticdata, def, dtime) local selbox = self.base_selbox -- specific texture if gotten - if self.gotten == true - and def.gotten_texture then + if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end -- specific mesh if gotten - if self.gotten == true - and def.gotten_mesh then + if self.gotten == true and def.gotten_mesh then mesh = def.gotten_mesh end @@ -3046,21 +3111,14 @@ function mob_class:mob_activate(staticdata, def, dtime) end colbox = { - self.base_colbox[1] * .5, - self.base_colbox[2] * .5, - self.base_colbox[3] * .5, - self.base_colbox[4] * .5, - self.base_colbox[5] * .5, - self.base_colbox[6] * .5 - } + self.base_colbox[1] * .5, self.base_colbox[2] * .5, + self.base_colbox[3] * .5, self.base_colbox[4] * .5, + self.base_colbox[5] * .5, self.base_colbox[6] * .5} + selbox = { - self.base_selbox[1] * .5, - self.base_selbox[2] * .5, - self.base_selbox[3] * .5, - self.base_selbox[4] * .5, - self.base_selbox[5] * .5, - self.base_selbox[6] * .5 - } + self.base_selbox[1] * .5, self.base_selbox[2] * .5, + self.base_selbox[3] * .5, self.base_selbox[4] * .5, + self.base_selbox[5] * .5, self.base_selbox[6] * .5} end if self.health == 0 then @@ -3075,15 +3133,14 @@ function mob_class:mob_activate(staticdata, def, dtime) self.path.following = false -- currently following path? self.path.stuck_timer = 0 -- if stuck for too long search for path - -- Armor groups - -- immortal=1 because we use custom health - -- handling (using "health" property) + -- Armor groups (immortal = 1 for custom damage handling) local armor if type(self.armor) == "table" then armor = table.copy(self.armor) - armor.immortal = 1 +-- armor.immortal = 1 else - armor = {immortal = 1, fleshy = self.armor} +-- armor = {immortal = 1, fleshy = self.armor} + armor = {fleshy = self.armor} end self.object:set_armor_groups(armor) @@ -3166,7 +3223,7 @@ function mob_class:mob_expire(pos, dtime) effect(pos, 15, "tnt_smoke.png", 2, 4, 2, 0) - self.object:remove() + remove_mob(self, true) return end @@ -3175,7 +3232,23 @@ end -- main mob function -function mob_class:on_step(dtime) +function mob_class:on_step(dtime, moveresult) + + --[[ moveresult contains this for physical mobs + { + touching_ground = boolean, + collides = boolean, + standing_on_object = boolean, + collisions = { + { + type = string, -- "node" or "object", + axis = string, -- "x", "y" or "z" + node_pos = vector, -- if type is "node" + object = ObjectRef, -- if type is "object" + old_velocity = vector, + new_velocity = vector, + }} + }]] if use_cmi then cmi.notify_step(self.object, dtime) @@ -3204,11 +3277,12 @@ function mob_class:on_step(dtime) self.standing_in = node_ok({ x = pos.x, y = pos.y + y_level + 0.25, z = pos.z}, "air").name ---print ("standing in " .. self.standing_in) +--print("standing in " .. self.standing_in) -- if standing inside solid block then jump to escape - if minetest.registered_nodes[self.standing_in].walkable and - minetest.registered_nodes[self.standing_in].drawtype == "normal" then + if minetest.registered_nodes[self.standing_in].walkable + and minetest.registered_nodes[self.standing_in].drawtype + == "normal" then self.object:set_velocity({ x = 0, @@ -3224,7 +3298,7 @@ function mob_class:on_step(dtime) self:set_velocity(0) end - -- check for mob expiration (0.25 instead of dtime since were in a timer) + -- has mob expired (0.25 instead of dtime since were in a timer) self:mob_expire(pos, 0.25) end @@ -3234,7 +3308,6 @@ function mob_class:on_step(dtime) end -- smooth rotation by ThomasMonroe314 - if self.delay and self.delay > 0 then if self.delay == 1 then @@ -3269,8 +3342,6 @@ function mob_class:on_step(dtime) self.object:set_yaw(yaw) end - -- end rotation - -- knockback timer if self.pause_timer > 0 then @@ -3344,7 +3415,7 @@ end -- default function when mobs are blown up with TNT function mob_class:on_blast(damage) ---print ("----- Damage", damage) +--print("-- blast damage", damage) self.object:punch(self.object, 1.0, { full_punch_interval = 1.0, @@ -3378,7 +3449,7 @@ minetest.register_entity(name, setmetatable({ do_custom = def.do_custom, jump_height = def.jump_height, drawtype = def.drawtype, -- DEPRECATED, use rotate instead - rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2 + rotate = math.rad(def.rotate or 0), -- 0=front 90=side 180=back 270=side2 glow = def.glow, lifetimer = def.lifetimer, hp_min = max(1, (def.hp_min or 5) * difficulty), @@ -3514,7 +3585,7 @@ end function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, - interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) + interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) -- Do mobs spawn at all? if not mobs_spawn then @@ -3550,12 +3621,19 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, chance = max(1, (chance * mob_chance_multiplier)), catch_up = false, - action = function(pos, node, active_object_count, active_object_count_wider) + action = function(pos, node, active_object_count, + active_object_count_wider) -- is mob actually registered? if not mobs.spawning_mobs[name] or not minetest.registered_entities[name] then ---print ("--- mob doesn't exist", name) +--print("--- mob doesn't exist", name) + return + end + + -- are we over active mob limit + if active_mobs >= active_limit then +--print("--- active mob limit reached", active_mobs, active_limit) return end @@ -3574,12 +3652,12 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, local num_mob, is_pla = count_mobs(pos, name) if not is_pla then ---print ("--- no players within active area, will not spawn " .. name) +--print("--- no players within active area, will not spawn " .. name) return end if num_mob >= aoc then ---print ("--- too many " .. name .. " in area", num_mob .. "/" .. aoc) +--print("--- too many " .. name .. " in area", num_mob .. "/" .. aoc) return end @@ -3591,13 +3669,13 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if tod > 4500 and tod < 19500 then -- daylight, but mob wants night if day_toggle == false then ---print ("--- mob needs night", name) +--print("--- mob needs night", name) return end else -- night time but mob wants day if day_toggle == true then ---print ("--- mob needs day", name) +--print("--- mob needs day", name) return end end @@ -3609,7 +3687,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, -- are we spawning within height limits? if pos.y > max_height or pos.y < min_height then ---print ("--- height limits not met", name, pos.y) +--print("--- height limits not met", name, pos.y) return end @@ -3618,14 +3696,14 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if not light or light > max_light or light < min_light then ---print ("--- light limits not met", name, light) +--print("--- light limits not met", name, light) return end -- mobs cannot spawn in protected areas when enabled if not spawn_protected and minetest.is_protected(pos, "") then ---print ("--- inside protected area", name) +--print("--- inside protected area", name) return end @@ -3636,7 +3714,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, for n = 1, #objs do if objs[n]:is_player() then ---print ("--- player too close", name) +--print("--- player too close", name) return end end @@ -3681,9 +3759,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if minetest.registered_nodes[ node_ok(pos2).name].walkable == true then - ---print ("--- not enough space to spawn", name) - +--print("--- not enough space to spawn", name) return end end @@ -3703,11 +3779,13 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, end local mob = minetest.add_entity(pos, name) ---[[ - print ("[mobs] Spawned " .. name .. " at " - .. minetest.pos_to_string(pos) .. " on " - .. node.name .. " near " .. neighbors[1]) -]] + +-- active_mobs = active_mobs + 1 + +-- print("[mobs] Spawned " .. name .. " at " +-- .. minetest.pos_to_string(pos) .. " on " +-- .. node.name .. " near " .. neighbors[1]) + if on_spawn then local ent = mob:get_luaentity() @@ -3764,7 +3842,7 @@ function mobs:register_arrow(name, def) hit_mob = def.hit_mob, hit_object = def.hit_object, drop = def.drop or false, -- drops arrow as registered item when true - collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0}, + collisionbox = def.collisionbox or {-.1, -.1, -.1, .1, .1, .1}, timer = 0, switch = 0, owner_id = def.owner_id, @@ -3784,18 +3862,15 @@ function mobs:register_arrow(name, def) local pos = self.object:get_pos() - if self.switch == 0 - or self.timer > 150 then + if self.switch == 0 or self.timer > 150 then - self.object:remove() ; -- print ("removed arrow") + self.object:remove() ; -- print("removed arrow") return end -- does arrow have a tail (fireball) - if def.tail - and def.tail == 1 - and def.tail_texture then + if def.tail and def.tail == 1 and def.tail_texture then minetest.add_particle({ pos = pos, @@ -3827,21 +3902,23 @@ function mobs:register_arrow(name, def) self.object:get_luaentity().name) end - self.object:remove() ; -- print ("hit node") + self.object:remove() ; -- print("hit node") return end end - if self.hit_player or self.hit_mob then + if self.hit_player or self.hit_mob or self.hit_object then - for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.0)) do + for _,player in pairs( + minetest.get_objects_inside_radius(pos, 1.0)) do - if self.hit_player - and player:is_player() then + if self.hit_player and player:is_player() then self:hit_player(player) - self.object:remove() ; -- print ("hit player") + + self.object:remove() ; -- print("hit player") + return end @@ -3855,7 +3932,7 @@ function mobs:register_arrow(name, def) self:hit_mob(player) - self.object:remove() ; --print ("hit mob") + self.object:remove() ; --print("hit mob") return end @@ -3868,7 +3945,7 @@ function mobs:register_arrow(name, def) self:hit_object(player) - self.object:remove(); -- print ("hit object") + self.object:remove(); -- print("hit object") return end @@ -3883,10 +3960,7 @@ end -- compatibility function function mobs:explosion(pos, radius) - - local self = {sounds = {explode = "tnt_explode"}} - - mobs:boom(self, pos, radius) + mobs:boom({sounds = {explode = "tnt_explode"}}, pos, radius) end @@ -3957,10 +4031,12 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) local pos = pointed_thing.above - -- am I clicking on something with existing on_rightclick function? + -- does existing on_rightclick function exist? local under = minetest.get_node(pointed_thing.under) local def = minetest.registered_nodes[under.name] + if def and def.on_rightclick then + return def.on_rightclick( pointed_thing.under, under, placer, itemstack) end @@ -3980,6 +4056,8 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) if not ent then return end -- sanity check +-- active_mobs = active_mobs + 1 + -- set owner if not a monster if ent.type ~= "monster" then ent.owner = placer:get_player_name() @@ -4006,10 +4084,12 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) local pos = pointed_thing.above - -- am I clicking on something with existing on_rightclick function? + -- does existing on_rightclick function exist? local under = minetest.get_node(pointed_thing.under) local def = minetest.registered_nodes[under.name] + if def and def.on_rightclick then + return def.on_rightclick( pointed_thing.under, under, placer, itemstack) end @@ -4021,6 +4101,15 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) return end + -- have we reached active mob limit + if active_mobs >= active_limit then + minetest.chat_send_player(placer:get_player_name(), + S("Active Mob Limit Reached!") + .. " (" .. active_mobs + .. " / " .. active_limit .. ")") + return + end + pos.y = pos.y + 1 local mob = minetest.add_entity(pos, mob) @@ -4028,6 +4117,8 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) if not ent then return end -- sanity check +-- active_mobs = active_mobs + 1 + -- don't set owner if monster or sneak pressed if ent.type ~= "monster" and not placer:get_player_control().sneak then @@ -4057,10 +4148,10 @@ function mobs:force_capture(self, clicker) local tmp = {} for _,stat in pairs(self) do + local t = type(stat) - if t ~= "function" - and t ~= "nil" - and t ~= "userdata" then + + if t ~= "function" and t ~= "nil" and t ~= "userdata" then tmp[_] = self[_] end end @@ -4077,15 +4168,15 @@ function mobs:force_capture(self, clicker) minetest.add_item(clicker:get_pos(), new_stack) end - self.object:remove() - self:mob_sound("default_place_node_hard") + + remove_mob(self, true) end -- capture critter (thanks to blert2112 for idea) -function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, - force_take, replacewith) +function mobs:capture_mob(self, clicker, chance_hand, chance_net, + chance_lasso, force_take, replacewith) if self.child or not clicker:is_player() @@ -4112,8 +4203,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, end -- is mob tamed? - if self.tamed == false - and force_take == false then + if self.tamed == false and force_take == false then minetest.chat_send_player(name, S("Not tamed!")) @@ -4121,8 +4211,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, end -- cannot pick up if not owner - if self.owner ~= name - and force_take == false then + if self.owner ~= name and force_take == false then minetest.chat_send_player(name, S("@1 is owner!", self.owner)) @@ -4170,7 +4259,9 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, local tmp = {} for _,stat in pairs(self) do + local t = type(stat) + if t ~= "function" and t ~= "nil" and t ~= "userdata" then @@ -4191,7 +4282,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, minetest.add_item(clicker:get_pos(), new_stack) end - self.object:remove() + remove_mob(self, true) self:mob_sound("default_place_node_hard") @@ -4199,12 +4290,14 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, -- when chance above fails or set to 0, miss! elseif chance and chance ~= 0 then + minetest.chat_send_player(name, S("Missed!")) self:mob_sound("mobs_swing") + return false - -- when chance set to nil always return a miss (used for npc walk/follow) + -- when chance is nil always return a miss (used for npc walk/follow) elseif not chance then return false end @@ -4244,7 +4337,8 @@ function mobs:protect(self, clicker) local pos = self.object:get_pos() pos.y = pos.y + self.collisionbox[2] + 0.5 - effect(self.object:get_pos(), 25, "mobs_protect_particle.png", 0.5, 4, 2, 15) + effect(self.object:get_pos(), 25, "mobs_protect_particle.png", + 0.5, 4, 2, 15) self:mob_sound("mobs_spell") @@ -4348,9 +4442,11 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame) local tag = self.nametag or "" - minetest.show_formspec(name, "mobs_nametag", "size[8,4]" + minetest.show_formspec(name, "mobs_nametag", + "size[8,4]" .. "field[0.5,1;7.5,0;name;" - .. minetest.formspec_escape(S("Enter name:")) .. ";" .. tag .. "]" + .. minetest.formspec_escape(S("Enter name:")) + .. ";" .. tag .. "]" .. "button_exit[2.5,3.5;3,1;mob_rename;" .. minetest.formspec_escape(S("Rename")) .. "]") end @@ -4425,10 +4521,14 @@ function mobs:alias_mob(old_name, new_name) on_activate = function(self, staticdata) if minetest.registered_entities[new_name] then - minetest.add_entity(self.object:get_pos(), new_name, staticdata) + + minetest.add_entity(self.object:get_pos(), + new_name, staticdata) + else +-- active_mobs = active_mobs - 1 end - self.object:remove() + remove_mob(self) end, get_staticdata = function(self)