Code tweak and tidy, mob counter attempt

This commit is contained in:
tenplus1 2020-05-15 13:26:34 +01:00
parent b610a81a58
commit 53cc10a16f
1 changed files with 249 additions and 149 deletions

398
api.lua
View File

@ -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)