diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua index 6fc600605..438935d70 100644 --- a/mods/ENTITIES/mcl_mobs/spawning.lua +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -24,25 +24,60 @@ local vector_floor = vector.floor local table_copy = table.copy local table_remove = table.remove - local pairs = pairs + +local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_spawning", false) +local function mcl_log (message) + if LOGGING_ON then + mcl_util.mcl_log (message, "[Mobs spawn]", true) + end +end + local dbg_spawn_attempts = 0 local dbg_spawn_succ = 0 local dbg_spawn_counts = {} --- range for mob count -local aoc_range = 136 + local remove_far = true +local WAIT_FOR_SPAWN_ATTEMPT = 10 +local FIND_SPAWN_POS_RETRIES = 16 +local FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN = 8 + +local MOB_SPAWN_ZONE_INNER = 24 +local MOB_SPAWN_ZONE_MIDDLE = 32 +local MOB_SPAWN_ZONE_OUTER = 128 + +-- range for mob count +local MOB_CAP_INNER_RADIUS = 32 +local aoc_range = 136 + +local MISSING_CAP_DEFAULT = 15 +local MOBS_CAP_CLOSE = 5 + +local SPAWN_MAPGEN_LIMIT = mcl_vars.mapgen_limit - 150 + local mob_cap = { - monster = tonumber(minetest.settings:get("mcl_mob_cap_monster")) or 70, - animal = tonumber(minetest.settings:get("mcl_mob_cap_animal")) or 10, + hostile = tonumber(minetest.settings:get("mcl_mob_cap_monster")) or 70, + passive = tonumber(minetest.settings:get("mcl_mob_cap_animal")) or 13, ambient = tonumber(minetest.settings:get("mcl_mob_cap_ambient")) or 15, - water = tonumber(minetest.settings:get("mcl_mob_cap_water")) or 5, --currently unused + water = tonumber(minetest.settings:get("mcl_mob_cap_water")) or 8, water_ambient = tonumber(minetest.settings:get("mcl_mob_cap_water_ambient")) or 20, --currently unused player = tonumber(minetest.settings:get("mcl_mob_cap_player")) or 75, total = tonumber(minetest.settings:get("mcl_mob_cap_total")) or 500, } +local peaceful_percentage_spawned = tonumber(minetest.settings:get("mcl_mob_peaceful_percentage_spawned")) or 35 +local peaceful_group_percentage_spawned = tonumber(minetest.settings:get("mcl_mob_peaceful_group_percentage_spawned")) or 15 +local hostile_group_percentage_spawned = tonumber(minetest.settings:get("mcl_mob_hostile_group_percentage_spawned")) or 20 + +mcl_log("Mob cap hostile: " .. mob_cap.hostile) +mcl_log("Mob cap water: " .. mob_cap.water) +mcl_log("Mob cap passive: " .. mob_cap.passive) + +mcl_log("Percentage of peacefuls spawned: " .. peaceful_percentage_spawned) +mcl_log("Percentage of peaceful spawns are group: " .. peaceful_group_percentage_spawned) +mcl_log("Percentage of hostile spawns are group: " .. hostile_group_percentage_spawned) + --do mobs spawn? local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false @@ -250,22 +285,58 @@ local function count_mobs_total(mob_type) return num end -local function count_mobs_all() - local mobs_found = {} +local function count_mobs_add_entry (mobs_list, mob_cat) + if mobs_list[mob_cat] then + mobs_list[mob_cat] = mobs_list[mob_cat] + 1 + else + mobs_list[mob_cat] = 1 + end +end + +--categorise_by can be name or type or spawn_class +local function count_mobs_all(categorise_by, pos) + local mobs_found_wide = {} + local mobs_found_close = {} + local num = 0 for _,entity in pairs(minetest.luaentities) do - if entity.is_mob then - local mob_type = entity.type -- animal / monster / npc - local mob_name = entity.name - if mobs_found[mob_name] then - mobs_found[mob_name] = mobs_found[mob_name] + 1 + if entity and entity.is_mob then + + local add_entry = false + --local mob_type = entity.type -- animal / monster / npc + local mob_cat = entity[categorise_by] + + if pos then + local mob_pos = entity.object:get_pos() + if mob_pos then + local distance = vector.distance(pos, mob_pos) + --mcl_log("distance: ".. distance) + if distance <= MOB_SPAWN_ZONE_MIDDLE then + --mcl_log("distance is close") + count_mobs_add_entry (mobs_found_close, mob_cat) + count_mobs_add_entry (mobs_found_wide, mob_cat) + add_entry = true + elseif distance <= MOB_SPAWN_ZONE_OUTER then + --mcl_log("distance is wide") + count_mobs_add_entry (mobs_found_wide, mob_cat) + add_entry = true + else + --mcl_log("mob_pos: " .. minetest.pos_to_string(mob_pos)) + end + end else - mobs_found[mob_name] = 1 + count_mobs_add_entry (mobs_found_wide, mob_cat) + add_entry = true + end + + + if add_entry then + num = num + 1 end - num = num + 1 end end - return mobs_found, num + --mcl_log("num: ".. num) + return mobs_found_close, mobs_found_wide, num end local function count_mobs_total_cap(mob_type) @@ -280,6 +351,32 @@ local function count_mobs_total_cap(mob_type) return num end +local function output_mob_stats(mob_counts, total_mobs, chat_display) + if (total_mobs) then + local total_output = "Total mobs found: " .. total_mobs + if chat_display then + minetest.log(total_output) + else + minetest.log("action", total_output) + end + + end + local detailed = "" + if mob_counts then + for k, v1 in pairs(mob_counts) do + detailed = detailed .. tostring(k) .. ": " .. tostring(v1) .. "; " + end + end + if detailed and detailed ~= "" then + if chat_display then + minetest.log(detailed) + else + minetest.log("action", detailed) + end + end +end + + -- global functions function mcl_mobs:spawn_abm_check(pos, node, name) @@ -422,18 +519,23 @@ function mcl_mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ summary_chance = summary_chance + chance end + local two_pi = 2 * math.pi local function get_next_mob_spawn_pos(pos) - local distance = math_random(25, 32) + -- TODO We should consider spawning something a little further away sporadically. + -- It would be good for sky farms and variance, rather than all being on the 24 - 32 block away radius + local distance = math_random(MOB_SPAWN_ZONE_INNER, MOB_SPAWN_ZONE_MIDDLE) local angle = math_random() * two_pi + + -- TODO Floor xoff and zoff and add 0.5 so it tries to spawn in the middle of the square. Less failed attempts. local xoff = math_round(distance * math_cos(angle)) - local yoff = math_round(distance * math_sin(angle)) - return vector.offset(pos, xoff, 0, yoff) + local zoff = math_round(distance * math_sin(angle)) + return vector.offset(pos, xoff, 0, zoff) end local function decypher_limits(posy) posy = math_floor(posy) - return posy - 32, posy + 32 + return posy - MOB_SPAWN_ZONE_MIDDLE, posy + MOB_SPAWN_ZONE_MIDDLE end --a simple helper function for mob_spawn @@ -484,7 +586,9 @@ local function has_room(self,pos) return true end -local function spawn_check(pos,spawn_def,ignore_caps) + + +local function spawn_check(pos, spawn_def) if not spawn_def then return end dbg_spawn_attempts = dbg_spawn_attempts + 1 local dimension = mcl_worlds.pos_to_dimension(pos) @@ -507,17 +611,8 @@ local function spawn_check(pos,spawn_def,ignore_caps) local is_leaf = get_item_group(gotten_node, "leaves") ~= 0 local is_bedrock = gotten_node == "mcl_core:bedrock" local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0 - local mob_count_wide = 0 - - local mob_count = 0 - if not ignore_caps then - mob_count = count_mobs(pos,32,mob_type) - mob_count_wide = count_mobs(pos,aoc_range,mob_type) - end if pos and spawn_def - and ( mob_count_wide < (mob_cap[mob_type] or 15) ) - and ( mob_count < 5 ) and pos.y >= spawn_def.min_height and pos.y <= spawn_def.max_height and spawn_def.dimension == dimension @@ -553,8 +648,7 @@ function mcl_mobs.spawn(pos,id) end -local function spawn_group(p,mob,spawn_on,group_max,group_min) - if not group_min then group_min = 1 end +local function spawn_group(p,mob,spawn_on,amount_to_spawn) local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on) local o table.shuffle(nn) @@ -562,9 +656,10 @@ local function spawn_group(p,mob,spawn_on,group_max,group_min) nn = {} table.insert(nn,p) end - for i = 1, math.random(group_min,group_max) do + + for i = 1, amount_to_spawn do local sp = vector.offset(nn[math.random(#nn)],0,1,0) - if spawn_check(nn[math.random(#nn)],mob,true) then + if spawn_check(nn[math.random(#nn)],mob) then if mob.type_of_spawning == "water" then sp = get_water_spawn(sp) end @@ -655,25 +750,113 @@ if mobs_spawn then -- Get pos to spawn, x and z are randomised, y is range - local function spawn_a_mob(pos, dimension, y_min, y_max) - --create a disconnected clone of the spawn dictionary - --prevents memory leak + local function mob_cap_space (pos, mob_type, mob_counts_close, mob_counts_wide) + + -- Some mob examples + --type = "monster", spawn_class = "hostile", + --type = "animal", spawn_class = "passive", + --local cod = { type = "animal", spawn_class = "water", + + local type_cap = mob_cap[mob_type] or MISSING_CAP_DEFAULT + local close_zone_cap = MOBS_CAP_CLOSE + + local mob_total_wide = mob_counts_wide[mob_type] + if not mob_total_wide then + --mcl_log("none of type found. set as 0") + mob_total_wide = 0 + end + + local cap_space_wide = type_cap - mob_total_wide + if cap_space_wide < 1 then + cap_space_wide = 0 + end + + local mob_total_close = mob_counts_close[mob_type] + if not mob_total_close then + --mcl_log("none of type found. set as 0") + mob_total_close = 0 + end + + local cap_space_close = close_zone_cap - mob_total_close + if cap_space_close < 1 then + cap_space_close = 0 + end + + --mcl_log("spawn_class: " .. spawn_class) + + if false and mob_type == "water" then + mcl_log("mob_type: " .. mob_type .. " and pos: " .. minetest.pos_to_string(pos)) + mcl_log("wide: " .. mob_total_wide .. "/" .. type_cap) + mcl_log("cap_space_wide: " .. cap_space_wide) + mcl_log("close: " .. mob_total_close .. "/" .. close_zone_cap) + mcl_log("cap_space_close: " .. cap_space_close) + end + + return cap_space_wide, cap_space_close + end + + local function find_spawning_position(pos, max_times) + local spawning_position + + local max_loops = 1 + if max_times then max_loops = max_times end + + local y_min, y_max = decypher_limits(pos.y) + + mcl_log("mapgen_limit: " .. SPAWN_MAPGEN_LIMIT) + local i = 0 + repeat + local goal_pos = get_next_mob_spawn_pos(pos) + + if math.abs(goal_pos.x) <= SPAWN_MAPGEN_LIMIT and math.abs(pos.y) <= SPAWN_MAPGEN_LIMIT and math.abs(goal_pos.z) <= SPAWN_MAPGEN_LIMIT then + local spawning_position_list = find_nodes_in_area_under_air( + {x = goal_pos.x, y = y_min, z = goal_pos.z}, + {x = goal_pos.x, y = y_max, z = goal_pos.z}, + {"group:solid", "group:water", "group:lava"} + ) + if #spawning_position_list > 0 then + mcl_log("Spawning positions available: " .. minetest.pos_to_string(goal_pos)) + spawning_position = spawning_position_list[math_random(1, #spawning_position_list)] + else + mcl_log("Spawning position isn't good. Do not spawn: " .. minetest.pos_to_string(goal_pos)) + end + + else + mcl_log("Pos outside mapgen limits: " .. minetest.pos_to_string(goal_pos)) + end + + + i = i + 1 + if i >= max_loops then + mcl_log("Cancel finding spawn positions at: " .. max_loops) + break + end + until spawning_position + return spawning_position + end + + local function spawn_a_mob(pos) + --create a disconnected clone of the spawn dictionary, prevents memory leak local mob_library_worker_table = table_copy(spawn_dictionary) - local goal_pos = get_next_mob_spawn_pos(pos) + + local spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES) + if not spawning_position then + minetest.log("action", "[Mobs spawn] Cannot find a valid spawn position after retries: " .. FIND_SPAWN_POS_RETRIES) + return + end + + local mob_counts_close, mob_counts_wide, total_mobs = count_mobs_all("spawn_class", spawning_position) + --output_mob_stats(mob_counts_close, total_mobs) + --output_mob_stats(mob_counts_wide) + --grab mob that fits into the spawning location --randomly grab a mob, don't exclude any possibilities - local spawning_position_list = find_nodes_in_area_under_air( - {x = goal_pos.x, y = y_min, z = goal_pos.z}, - {x = goal_pos.x, y = y_max, z = goal_pos.z}, - {"group:solid", "group:water", "group:lava"} - ) - if #spawning_position_list <= 0 then return end - local spawning_position = spawning_position_list[math_random(1, #spawning_position_list)] - perlin_noise = perlin_noise or minetest_get_perlin(noise_params) local noise = perlin_noise:get_3d(spawning_position) local current_summary_chance = summary_chance + table.shuffle(mob_library_worker_table) + while #mob_library_worker_table > 0 do local mob_chance_offset = (math_round(noise * current_summary_chance + 12345) % current_summary_chance) + 1 local mob_index = 1 @@ -684,39 +867,95 @@ if mobs_spawn then mob_chance = mob_library_worker_table[mob_index].chance step_chance = step_chance + mob_chance end - local mob_def = mob_library_worker_table[mob_index] --minetest.log(mob_def.name.." "..step_chance.. " "..mob_chance) + + local mob_def = mob_library_worker_table[mob_index] if mob_def and mob_def.name and minetest.registered_entities[mob_def.name] then - local spawn_in_group = minetest.registered_entities[mob_def.name].spawn_in_group or 4 - local spawn_in_group_min = minetest.registered_entities[mob_def.name].spawn_in_group_min or 1 - local mob_type = minetest.registered_entities[mob_def.name].type - if spawn_check(spawning_position,mob_def) then - if mob_def.type_of_spawning == "water" then - spawning_position = get_water_spawn(spawning_position) - if not spawning_position then - minetest.log("warning","[mcl_mobs] no water spawn for mob "..mob_def.name.." found at "..minetest.pos_to_string(vector.round(pos))) + + local mob_def_ent = minetest.registered_entities[mob_def.name] + --local mob_type = mob_def_ent.type + local mob_spawn_class = mob_def_ent.spawn_class + + --mcl_log("mob_spawn_class: " .. mob_spawn_class) + + local cap_space_wide, cap_space_close = mob_cap_space (spawning_position, mob_spawn_class, mob_counts_close, mob_counts_wide) + + + if cap_space_close > 0 and cap_space_wide > 0 then + --mcl_log("Cap space available") + + -- Spawn caps for animals and water creatures fill up rapidly. Need to throttle this somewhat + -- for performance and for early game challenge. We don't want to reduce hostiles though. + local spawn_hostile = (mob_spawn_class == "hostile") + local spawn_passive = (mob_spawn_class ~= "hostile") and math.random(100) < peaceful_percentage_spawned + -- or not hostile + --mcl_log("Spawn_passive: " .. tostring(spawn_passive)) + --mcl_log("Spawn_hostile: " .. tostring(spawn_hostile)) + + if (spawn_hostile or spawn_passive) and spawn_check(spawning_position,mob_def) then + if mob_def.type_of_spawning == "water" then + spawning_position = get_water_spawn(spawning_position) + if not spawning_position then + minetest.log("warning","[mcl_mobs] no water spawn for mob "..mob_def.name.." found at "..minetest.pos_to_string(vector.round(pos))) + return + end + end + if mob_def_ent.can_spawn and not mob_def_ent.can_spawn(spawning_position) then + minetest.log("warning","[mcl_mobs] mob "..mob_def.name.." refused to spawn at "..minetest.pos_to_string(vector.round(spawning_position))) return end - end - if minetest.registered_entities[mob_def.name].can_spawn and not minetest.registered_entities[mob_def.name].can_spawn(spawning_position) then - minetest.log("warning","[mcl_mobs] mob "..mob_def.name.." refused to spawn at "..minetest.pos_to_string(vector.round(spawning_position))) - return - end - --everything is correct, spawn mob - local object - if spawn_in_group and ( mob_type ~= "monster" or math.random(5) == 1 ) then - if logging then - minetest.log("action", "[mcl_mobs] A group of mob " .. mob_def.name .. " spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at " .. minetest.pos_to_string(spawning_position, 1)) - end - object = spawn_group(spawning_position,mob_def,{minetest.get_node(vector.offset(spawning_position,0,-1,0)).name},spawn_in_group,spawn_in_group_min) - else - if logging then - minetest.log("action", "[mcl_mobs] Mob " .. mob_def.name .. " spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at ".. minetest.pos_to_string(spawning_position, 1)) + --everything is correct, spawn mob + local spawn_in_group = mob_def_ent.spawn_in_group or 4 + + local spawn_group_hostile = (mob_spawn_class == "hostile") and (math.random(100) < hostile_group_percentage_spawned) + local spawn_group_passive = (mob_spawn_class ~= "hostile") and (math.random(100) < peaceful_group_percentage_spawned) + + mcl_log("spawn_group_hostile: " .. tostring(spawn_group_hostile)) + mcl_log("spawn_group_passive: " .. tostring(spawn_group_passive)) + + local spawned + if spawn_in_group and (spawn_group_hostile or spawn_group_passive) then + local group_min = mob_def_ent.spawn_in_group_min or 1 + if not group_min then group_min = 1 end + + local amount_to_spawn = math.random(group_min,spawn_in_group) + + if amount_to_spawn > cap_space_wide then + mcl_log("Spawning quantity: " .. amount_to_spawn) + mcl_log("Throttle amount to cap space: " .. cap_space_wide) + amount_to_spawn = cap_space_wide + end + + if logging then + minetest.log("action", "[mcl_mobs] A group of " ..amount_to_spawn .. " " .. mob_def.name .. " mob spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at " .. minetest.pos_to_string(spawning_position, 1)) + end + spawned = spawn_group(spawning_position,mob_def,{minetest.get_node(vector.offset(spawning_position,0,-1,0)).name}, amount_to_spawn) + else + if logging then + minetest.log("action", "[mcl_mobs] Mob " .. mob_def.name .. " spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at ".. minetest.pos_to_string(spawning_position, 1)) + end + spawned = mcl_mobs.spawn(spawning_position, mob_def.name) end - object = mcl_mobs.spawn(spawning_position, mob_def.name) + + if spawned then + --mcl_log("We have spawned") + mob_counts_close, mob_counts_wide, total_mobs = count_mobs_all("type", pos) + local new_spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN) + if new_spawning_position then + mcl_log("Setting new spawning position") + spawning_position = new_spawning_position + else + mcl_log("Cannot set new spawning position") + end + end + else + mcl_log("Spawn check failed") end + else + mcl_log("Cap space full") end + end current_summary_chance = current_summary_chance - mob_chance table_remove(mob_library_worker_table, mob_index) @@ -728,22 +967,24 @@ if mobs_spawn then local timer = 0 minetest.register_globalstep(function(dtime) + timer = timer + dtime - if timer < 10 then return end + if timer < WAIT_FOR_SPAWN_ATTEMPT then return end timer = 0 + local players = get_connected_players() local total_mobs = count_mobs_total_cap() if total_mobs > mob_cap.total or total_mobs > #players * mob_cap.player then minetest.log("action","[mcl_mobs] global mob cap reached. no cycle spawning.") return end --mob cap per player + for _, player in pairs(players) do local pos = player:get_pos() local dimension = mcl_worlds.pos_to_dimension(pos) -- ignore void and unloaded area if dimension ~= "void" and dimension ~= "default" then - local y_min, y_max = decypher_limits(pos.y) - spawn_a_mob(pos, dimension, y_min, y_max) + spawn_a_mob(pos) end end end) @@ -775,27 +1016,16 @@ function mob_class:check_despawn(pos, dtime) end end + minetest.register_chatcommand("mobstats",{ privs = { debug = true }, func = function(n,param) - minetest.chat_send_player(n,dump(dbg_spawn_counts)) + --minetest.chat_send_player(n,dump(dbg_spawn_counts)) local pos = minetest.get_player_by_name(n):get_pos() - minetest.chat_send_player(n,"mobs within 32 radius of player:"..count_mobs(pos,32)) - minetest.chat_send_player(n,"total mobs:"..count_mobs_total()) - minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts) - minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ) - - - local mob_counts, total_mobs = count_mobs_all() - if (total_mobs) then - minetest.log("action", "Total mobs found: " .. total_mobs) - end - if mob_counts then - for k, v1 in pairs(mob_counts) do - minetest.log("action", "k: " .. tostring(k)) - minetest.log("action", "v1: " .. tostring(v1)) - end - end + minetest.chat_send_player(n,"mobs: within 32 radius of player/total loaded :"..count_mobs(pos,MOB_CAP_INNER_RADIUS) .. "/" .. count_mobs_total()) + minetest.chat_send_player(n,"spawning attempts since server start:" .. dbg_spawn_succ .. "/" .. dbg_spawn_attempts) + local mob_counts_close, mob_counts_wide, total_mobs = count_mobs_all("name") -- Can use "type" + output_mob_stats(mob_counts_wide, total_mobs, true) end }) diff --git a/mods/ENTITIES/mobs_mc/cod.lua b/mods/ENTITIES/mobs_mc/cod.lua index bc65faebe..eeb1228c8 100644 --- a/mods/ENTITIES/mobs_mc/cod.lua +++ b/mods/ENTITIES/mobs_mc/cod.lua @@ -40,8 +40,8 @@ local cod = { xp_max = 3, armor = 100, rotate = 180, - spawn_in_group_min = 3, - spawn_in_group = 8, + spawn_in_group_min = 2, -- was 3 + spawn_in_group = 4, -- was 8 nerfed until we can cap them properly locally. this is a group size, not a per spawn attempt tilt_swim = true, collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3}, visual = "mesh", diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index 1ec06b44b..64f74c516 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -14,7 +14,7 @@ local cow_def = { xp_max = 3, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45}, spawn_in_group = 4, - spawn_in_group_min = 3, + spawn_in_group_min = 2, visual = "mesh", mesh = "mobs_mc_cow.b3d", textures = { { @@ -93,8 +93,8 @@ mcl_mobs.register_mob("mobs_mc:cow", cow_def) -- Mooshroom local mooshroom_def = table.copy(cow_def) mooshroom_def.description = S("Mooshroom") -mooshroom_def.spawn_in_group_min = 4 -mooshroom_def.spawn_in_group = 8 +mooshroom_def.spawn_in_group_min = 2 +mooshroom_def.spawn_in_group = 4 mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } } mooshroom_def.on_rightclick = function(self, clicker) if self:feed_tame(clicker, 1, true, false) then return end diff --git a/mods/ENTITIES/mobs_mc/dolphin.lua b/mods/ENTITIES/mobs_mc/dolphin.lua index 0e5c8e7ee..153734c39 100644 --- a/mods/ENTITIES/mobs_mc/dolphin.lua +++ b/mods/ENTITIES/mobs_mc/dolphin.lua @@ -42,8 +42,8 @@ local dolphin = { walk_chance = 100, breath_max = 120, rotate = 180, - spawn_in_group_min = 3, - spawn_in_group = 5, + spawn_in_group_min = 2, -- was 3 + spawn_in_group = 4, -- was 4. nerfed until water has own cap, and it represents max pack size rather than per spawn attempt tilt_swim = true, collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3}, visual = "mesh", diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index 7f61627bc..e0f95df4d 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -125,7 +125,7 @@ local horse = { type = "animal", spawn_class = "passive", spawn_in_group_min = 2, - spawn_in_group = 6, + spawn_in_group = 4, -- was 6. nerfed until group size is a cap rather than per spawn cycle visual = "mesh", mesh = "mobs_mc_horse.b3d", visual_size = {x=3.0, y=3.0}, diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 503f4207b..32bfc97ea 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -56,8 +56,8 @@ mcl_mobs.register_mob("mobs_mc:llama", { shoot_interval = 5.5, arrow = "mobs_mc:llamaspit", shoot_offset = 1, --3.5 *would* be a good value visually but it somehow messes with the projectiles trajectory - spawn_in_group_min = 4, - spawn_in_group = 6, + spawn_in_group_min = 2, -- was 4 + spawn_in_group = 4, -- was 6 nerfed until we can cap them properly locally. this is a group size, not a per spawn attempt head_swivel = "head.control", bone_eye_height = 11, diff --git a/mods/ENTITIES/mobs_mc/tropical_fish.lua b/mods/ENTITIES/mobs_mc/tropical_fish.lua index bb9b63f64..702c692b8 100644 --- a/mods/ENTITIES/mobs_mc/tropical_fish.lua +++ b/mods/ENTITIES/mobs_mc/tropical_fish.lua @@ -67,7 +67,7 @@ local tropical_fish = { xp_min = 1, xp_max = 3, armor = 100, - spawn_in_group = 9, + spawn_in_group = 4, -- was 9. nerfed until aquatics use own cap rather than animal, and it represents pack size, not per spawn attempt tilt_swim = true, collisionbox = {-0.2, 0.0, -0.2, 0.2, 0.1, 0.2}, visual = "mesh", diff --git a/settingtypes.txt b/settingtypes.txt index 8a891ea8e..74d3fc138 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -115,6 +115,15 @@ mobs_griefing (Mobs change blocks) bool true # If enabled, mobs won't damage particles when they got hurt. mobs_disable_blood (Disable mob damage particles) bool false +#Percentage of peaceful spawn attempts that succeed (default:35) +mcl_mob_peaceful_percentage_spawned (Peaceful percentage success) int 35 0 100 + +#Percentage of peaceful spawn attempts that are group spawns (default:15) +mcl_mob_peaceful_group_percentage_spawned (Peaceful group percentage) int 15 0 100 + +#Percentage of hostile spawn attempts that are group spawns (default:20) +mcl_mob_hostile_group_percentage_spawned (Hostile group percentage) int 20 0 100 + #Maximum amount mobs (default:500) mcl_mob_cap_total (Global mob cap) int 500 0 2048 @@ -124,8 +133,11 @@ mcl_mob_cap_player (Mob cap per player) int 75 0 2048 #Maximum amount of monsters that will spawn near a player (default:70) mcl_mob_cap_monster (Mob cap monsters) int 70 0 2048 -#Maximum amount of animals that will spawn near a player (default:10) -mcl_mob_cap_animal (Mob cap animals) int 10 0 1024 +#Maximum amount of animals that will spawn near a player (default:13) +mcl_mob_cap_animal (Mob cap animals) int 13 0 1024 + +#Maximum amount of water mobs that will spawn near a player (default:8) +mcl_mob_cap_water (Mob cap water) int 8 0 1024 #Maximum amount of ambient mobs that will spawn near a player (default:15) mcl_mob_cap_ambient (Mob cap ambient mobs) int 15 0 1024