Implement per-class mob cap

This commit is contained in:
Wuzzy 2020-04-11 02:46:03 +02:00
parent 8e06e4e8b2
commit 47cda09073
42 changed files with 96 additions and 18 deletions

View File

@ -7,6 +7,12 @@ mobs.version = "20180531" -- don't rely too much on this, rarely updated, if eve
local MAX_MOB_NAME_LENGTH = 30 local MAX_MOB_NAME_LENGTH = 30
local MOB_CAP = {}
MOB_CAP.hostile = 70
MOB_CAP.passive = 10
MOB_CAP.ambient = 15
MOB_CAP.water = 15
-- Localize -- Localize
local S = minetest.get_translator("mcl_mobs") local S = minetest.get_translator("mcl_mobs")
@ -3369,6 +3375,7 @@ minetest.register_entity(name, {
_cmi_is_mob = true, _cmi_is_mob = true,
-- MCL2 extensions -- MCL2 extensions
spawn_class = def.spawn_class,
ignores_nametag = def.ignores_nametag or false, ignores_nametag = def.ignores_nametag or false,
rain_damage = def.rain_damage or 0, rain_damage = def.rain_damage or 0,
glow = def.glow, glow = def.glow,
@ -3413,33 +3420,48 @@ end -- END mobs:register_mob function
-- count how many mobs of one type are inside an area -- count how many mobs of one type are inside an area
local count_mobs = function(pos, type) local count_mobs = function(pos, mobtype)
local num_type = 0 local num = 0
local num_total = 0
local objs = minetest.get_objects_inside_radius(pos, aoc_range) local objs = minetest.get_objects_inside_radius(pos, aoc_range)
for n = 1, #objs do for n = 1, #objs do
if not objs[n]:is_player() then local obj = objs[n]:get_luaentity()
local obj = objs[n]:get_luaentity() if obj and obj.name and obj._cmi_is_mob then
-- count mob type and add to total also -- count passive mobs only
if obj and obj.name and obj.name == type then if mobtype == "!passive" then
if obj.spawn_class == "passive" then
num_type = num_type + 1 num = num + 1
num_total = num_total + 1 end
-- count hostile mobs only
-- add to total mobs elseif mobtype == "!hostile" then
elseif obj and obj.name and obj.health ~= nil then if obj.spawn_class == "hostile" then
num = num + 1
num_total = num_total + 1 end
-- count ambient mobs only
elseif mobtype == "!ambient" then
if obj.spawn_class == "ambient" then
num = num + 1
end
-- count water mobs only
elseif mobtype == "!water" then
if obj.spawn_class == "water" then
num = num + 1
end
-- count mob type
elseif mobtype and obj.name == mobtype then
num = num + 1
-- count total mobs
elseif not mobtype then
num = num + 1
end end
end end
end end
return num_type, num_total return num
end end
@ -3494,9 +3516,21 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
return return
end end
-- count nearby mobs in same spawn class
local entdef = minetest.registered_entities[name]
local spawn_class = entdef and entdef.spawn_class
if not spawn_class then
if entdef.type == "monster" then
spawn_class = "hostile"
else
spawn_class = "passive"
end
end
local in_class_cap = count_mobs(pos, "!"..spawn_class) < MOB_CAP[spawn_class]
-- do not spawn if too many of same mob in area -- do not spawn if too many of same mob in area
if active_object_count_wider >= max_per_block if active_object_count_wider >= max_per_block -- large-range mob cap
or count_mobs(pos, name) >= aoc then or (not in_class_cap) -- spawn class mob cap
or count_mobs(pos, name) >= aoc then -- per-mob mob cap
-- too many entities -- too many entities
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!")
return return

View File

@ -226,6 +226,8 @@ functions needed for the mob to work properly which contains the following:
MineClone 2 extensions: MineClone 2 extensions:
'spawn_class' Classification of mod for the spawning algorithm:
"hostile", "passive", "ambient" or "water"
'ignores_nametag' if true, mob cannot be named by nametag 'ignores_nametag' if true, mob cannot be named by nametag
'rain_damage' damage per second if mob is standing in rain (default: 0) 'rain_damage' damage per second if mob is standing in rain (default: 0)
'sunlight_damage' holds the damage per second inflicted to mobs when they 'sunlight_damage' holds the damage per second inflicted to mobs when they

View File

@ -6,6 +6,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:agent", { mobs:register_mob("mobs_mc:agent", {
type = "npc", type = "npc",
spawn_class = "passive",
passive = true, passive = true,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,

View File

@ -4,6 +4,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:bat", { mobs:register_mob("mobs_mc:bat", {
type = "animal", type = "animal",
spawn_class = "ambient",
can_despawn = true, can_despawn = true,
passive = true, passive = true,
hp_min = 6, hp_min = 6,

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:blaze", { mobs:register_mob("mobs_mc:blaze", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3},

View File

@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:chicken", { mobs:register_mob("mobs_mc:chicken", {
type = "animal", type = "animal",
spawn_class = "passive",
hp_min = 4, hp_min = 4,
hp_max = 4, hp_max = 4,

View File

@ -4,6 +4,7 @@ local S = minetest.get_translator("mobs_mc")
local cow_def = { local cow_def = {
type = "animal", type = "animal",
spawn_class = "passive",
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45}, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45},

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:creeper", { mobs:register_mob("mobs_mc:creeper", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3},

View File

@ -6,6 +6,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:enderdragon", { mobs:register_mob("mobs_mc:enderdragon", {
type = "monster", type = "monster",
spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
attacks_animals = true, attacks_animals = true,
walk_chance = 100, walk_chance = 100,

View File

@ -168,6 +168,7 @@ local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
mobs:register_mob("mobs_mc:enderman", { mobs:register_mob("mobs_mc:enderman", {
-- TODO: Endermen should be classified as passive -- TODO: Endermen should be classified as passive
type = "monster", type = "monster",
spawn_class = "passive",
passive = false, passive = false,
pathfinding = 1, pathfinding = 1,
hp_min = 40, hp_min = 40,

View File

@ -6,6 +6,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:endermite", { mobs:register_mob("mobs_mc:endermite", {
type = "monster", type = "monster",
spawn_class = "hostile",
passive = false, passive = false,
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:ghast", { mobs:register_mob("mobs_mc:ghast", {
type = "monster", type = "monster",
spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
group_attack = true, group_attack = true,
hp_min = 10, hp_min = 10,

View File

@ -8,6 +8,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:guardian", { mobs:register_mob("mobs_mc:guardian", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 30, hp_min = 30,
hp_max = 30, hp_max = 30,
breath_max = -1, breath_max = -1,

View File

@ -8,6 +8,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:guardian_elder", { mobs:register_mob("mobs_mc:guardian_elder", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 80, hp_min = 80,
hp_max = 80, hp_max = 80,
breath_max = -1, breath_max = -1,

View File

@ -84,6 +84,7 @@ end
-- Horse -- Horse
local horse = { local horse = {
type = "animal", type = "animal",
spawn_class = "passive",
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_horse.b3d", mesh = "mobs_mc_horse.b3d",
visual_size = {x=3.0, y=3.0}, visual_size = {x=3.0, y=3.0},

View File

@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:iron_golem", { mobs:register_mob("mobs_mc:iron_golem", {
type = "npc", type = "npc",
spawn_class = "passive",
passive = true, passive = true,
hp_min = 100, hp_min = 100,
hp_max = 100, hp_max = 100,

View File

@ -26,6 +26,7 @@ local carpets = {
mobs:register_mob("mobs_mc:llama", { mobs:register_mob("mobs_mc:llama", {
type = "animal", type = "animal",
spawn_class = "passive",
hp_min = 15, hp_min = 15,
hp_max = 30, hp_max = 30,
passive = false, passive = false,

View File

@ -28,6 +28,7 @@ end
-- Ocelot -- Ocelot
local ocelot = { local ocelot = {
type = "animal", type = "animal",
spawn_class = "passive",
can_despawn = true, can_despawn = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,

View File

@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:parrot", { mobs:register_mob("mobs_mc:parrot", {
type = "npc", type = "npc",
spawn_class = "passive",
pathfinding = 1, pathfinding = 1,
hp_min = 6, hp_min = 6,
hp_max = 6, hp_max = 6,

View File

@ -4,6 +4,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:pig", { mobs:register_mob("mobs_mc:pig", {
type = "animal", type = "animal",
spawn_class = "passive",
runaway = true, runaway = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,

View File

@ -9,6 +9,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:polar_bear", { mobs:register_mob("mobs_mc:polar_bear", {
type = "animal", type = "animal",
spawn_class = "passive",
runaway = false, runaway = false,
passive = false, passive = false,
hp_min = 30, hp_min = 30,

View File

@ -4,6 +4,7 @@ local S = minetest.get_translator("mobs_mc")
local rabbit = { local rabbit = {
type = "animal", type = "animal",
spawn_class = "passive",
passive = true, passive = true,
reach = 1, reach = 1,
@ -74,6 +75,7 @@ mobs:register_mob("mobs_mc:rabbit", rabbit)
-- The killer bunny (Only with spawn egg) -- The killer bunny (Only with spawn egg)
local killer_bunny = table.copy(rabbit) local killer_bunny = table.copy(rabbit)
killer_bunny.type = "monster" killer_bunny.type = "monster"
killer_bunny.spawn_class = "hostile"
killer_bunny.attack_type = "dogfight" killer_bunny.attack_type = "dogfight"
killer_bunny.specific_attack = { "player", "mobs_mc:wolf", "mobs_mc:dog" } killer_bunny.specific_attack = { "player", "mobs_mc:wolf", "mobs_mc:dog" }
killer_bunny.damage = 8 killer_bunny.damage = 8

View File

@ -44,6 +44,7 @@ local gotten_texture = { "blank.png", "mobs_mc_sheep.png" }
--mcsheep --mcsheep
mobs:register_mob("mobs_mc:sheep", { mobs:register_mob("mobs_mc:sheep", {
type = "animal", type = "animal",
spawn_class = "passive",
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,

View File

@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:shulker", { mobs:register_mob("mobs_mc:shulker", {
type = "monster", type = "monster",
spawn_class = "hostile",
attack_type = "shoot", attack_type = "shoot",
shoot_interval = 0.5, shoot_interval = 0.5,
arrow = "mobs_mc:shulkerbullet", arrow = "mobs_mc:shulkerbullet",

View File

@ -6,6 +6,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:silverfish", { mobs:register_mob("mobs_mc:silverfish", {
type = "monster", type = "monster",
spawn_class = "hostile",
passive = false, passive = false,
group_attack = true, group_attack = true,
reach = 1, reach = 1,

View File

@ -14,6 +14,7 @@ local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
local skeleton = { local skeleton = {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
breath_max = -1, breath_max = -1,

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:witherskeleton", { mobs:register_mob("mobs_mc:witherskeleton", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
breath_max = -1, breath_max = -1,

View File

@ -57,6 +57,7 @@ end
-- Slime -- Slime
local slime_big = { local slime_big = {
type = "monster", type = "monster",
spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
group_attack = { "mobs_mc:slime_big", "mobs_mc:slime_small", "mobs_mc:slime_tiny" }, group_attack = { "mobs_mc:slime_big", "mobs_mc:slime_small", "mobs_mc:slime_tiny" },
hp_min = 16, hp_min = 16,
@ -156,6 +157,7 @@ mobs:spawn_specific("mobs_mc:slime_big", mobs_mc.spawn.solid, {"air"}, 0, minete
-- Magma cube -- Magma cube
local magma_cube_big = { local magma_cube_big = {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 16, hp_min = 16,
hp_max = 16, hp_max = 16,
collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02}, collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02},

View File

@ -22,6 +22,7 @@ local gotten_texture = {
mobs:register_mob("mobs_mc:snowman", { mobs:register_mob("mobs_mc:snowman", {
type = "npc", type = "npc",
spawn_class = "passive",
passive = true, passive = true,
hp_min = 4, hp_min = 4,
hp_max = 4, hp_max = 4,

View File

@ -14,6 +14,7 @@ local S = minetest.get_translator("mobs_mc")
local spider = { local spider = {
type = "monster", type = "monster",
spawn_class = "hostile",
passive = false, passive = false,
docile_by_day = true, docile_by_day = true,
attack_type = "dogfight", attack_type = "dogfight",

View File

@ -8,6 +8,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:squid", { mobs:register_mob("mobs_mc:squid", {
type = "animal", type = "animal",
spawn_class = "water",
can_despawn = true, can_despawn = true,
passive = true, passive = true,
hp_min = 10, hp_min = 10,

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:vex", { mobs:register_mob("mobs_mc:vex", {
type = "monster", type = "monster",
spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
passive = false, passive = false,
attack_type = "dogfight", attack_type = "dogfight",

View File

@ -908,6 +908,7 @@ end)
mobs:register_mob("mobs_mc:villager", { mobs:register_mob("mobs_mc:villager", {
type = "npc", type = "npc",
spawn_class = "passive",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3},

View File

@ -13,6 +13,7 @@ local pr = PseudoRandom(os.time()*666)
mobs:register_mob("mobs_mc:evoker", { mobs:register_mob("mobs_mc:evoker", {
type = "monster", type = "monster",
spawn_class = "hostile",
physical = true, physical = true,
pathfinding = 1, pathfinding = 1,
hp_min = 24, hp_min = 24,

View File

@ -8,6 +8,7 @@ local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
mobs:register_mob("mobs_mc:illusioner", { mobs:register_mob("mobs_mc:illusioner", {
type = "monster", type = "monster",
spawn_class = "hostile",
attack_type = "shoot", attack_type = "shoot",
shoot_interval = 2.5, shoot_interval = 2.5,
shoot_offset = 1.5, shoot_offset = 1.5,

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:vindicator", { mobs:register_mob("mobs_mc:vindicator", {
type = "monster", type = "monster",
spawn_class = "hostile",
physical = false, physical = false,
pathfinding = 1, pathfinding = 1,
hp_min = 24, hp_min = 24,

View File

@ -14,6 +14,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:villager_zombie", { mobs:register_mob("mobs_mc:villager_zombie", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
breath_max = -1, breath_max = -1,

View File

@ -14,6 +14,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:witch", { mobs:register_mob("mobs_mc:witch", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 26, hp_min = 26,
hp_max = 26, hp_max = 26,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3},

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:wither", { mobs:register_mob("mobs_mc:wither", {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_max = 300, hp_max = 300,
hp_min = 300, hp_min = 300,
armor = 80, armor = 80,

View File

@ -20,6 +20,7 @@ end
-- Wolf -- Wolf
local wolf = { local wolf = {
type = "animal", type = "animal",
spawn_class = "passive",
can_despawn = true, can_despawn = true,
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,

View File

@ -40,6 +40,7 @@ table.insert(drops_zombie, {
local zombie = { local zombie = {
type = "monster", type = "monster",
spawn_class = "hostile",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
breath_max = -1, breath_max = -1,

View File

@ -14,6 +14,7 @@ local pigman = {
-- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked -- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked
type = "animal", type = "animal",
passive = false, passive = false,
spawn_class = "passive",
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
breath_max = -1, breath_max = -1,