From abc68f4dc6a58b9c2e28d85771888fb955ed8c7e Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Thu, 8 Apr 2021 02:07:15 -0400 Subject: [PATCH] Refactor spawning into it's own file --- mods/ENTITIES/mcl_mobs/api.lua | 554 ---------------------------- mods/ENTITIES/mcl_mobs/init.lua | 5 +- mods/ENTITIES/mcl_mobs/spawning.lua | 470 +++++++++++++++++++++++ mods/ENTITIES/mobs_mc/depends.txt | 1 + 4 files changed, 475 insertions(+), 555 deletions(-) create mode 100644 mods/ENTITIES/mcl_mobs/spawning.lua create mode 100644 mods/ENTITIES/mobs_mc/depends.txt diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 7ec86a332d..daa209e9e6 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -61,8 +61,6 @@ end -- Load settings local damage_enabled = minetest.settings:get_bool("enable_damage") -local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false - local disable_blood = minetest.settings:get_bool("mobs_disable_blood") local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false @@ -3931,558 +3929,6 @@ end end -- END mobs:register_mob function - - - - - - - - - - - - ---BEGIN SPAWNING ALGORITHM - - - - - - - - - - - - - - - --- count how many mobs of one type are inside an area ---[[ -local count_mobs = function(pos, mobtype) - - local num = 0 - local objs = minetest.get_objects_inside_radius(pos, aoc_range) - - for n = 1, #objs do - - local obj = objs[n]:get_luaentity() - - if obj and obj.name and obj._cmi_is_mob then - - -- count passive mobs only - if mobtype == "!passive" then - if obj.spawn_class == "passive" then - num = num + 1 - end - -- count hostile mobs only - elseif mobtype == "!hostile" then - if obj.spawn_class == "hostile" then - num = num + 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 - - return num -end -]]-- - --- global functions - -function mobs:spawn_abm_check(pos, node, name) - -- global function to add additional spawn checks - -- return true to stop spawning mob -end - - ---[[ - Custom elements changed: -name: -the mobs name - -dimension: -"overworld" -"nether" -"end" - -types of spawning: -"air" -"water" -"ground" -"lava" - -what is aoc??? - -WARNING: BIOME INTEGRATION NEEDED -> How to get biome through lua?? -]]-- - ---this is where all of the spawning information is kept -local spawn_dictionary = { - ["overworld"] = {}, - ["nether"] = {}, - ["end"] = {} -} - -function mobs:spawn_specific( - name, - dimension, - type_of_spawning, - min_light, - max_light, - interval, - chance, - aoc, - min_height, - max_height, - day_toggle, - on_spawn) - - - -- Do mobs spawn at all? - if not mobs_spawn then - return - end - - -- chance/spawn number override in minetest.conf for registered mob - local numbers = minetest.settings:get(name) - - if numbers then - numbers = numbers:split(",") - chance = tonumber(numbers[1]) or chance - aoc = tonumber(numbers[2]) or aoc - - if chance == 0 then - minetest.log("warning", string.format("[mobs] %s has spawning disabled", name)) - return - end - - minetest.log("action", - string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc)) - end - - local spawn_action - spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) - - local orig_pos = table.copy(pos) - -- is mob actually registered? - if not mobs.spawning_mobs[name] - or not minetest.registered_entities[name] then - minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!") - return - end - - -- additional custom checks for spawning mob - if mobs:spawn_abm_check(pos, node, name) == true then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!") - return - 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 - if active_object_count_wider >= max_per_block -- large-range mob cap - or (not in_class_cap) -- spawn class mob cap - or count_mobs(pos, name) >= aoc then -- per-mob mob cap - -- too many entities - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") - return - end - - -- if toggle set to nil then ignore day/night check - if day_toggle ~= nil then - - local tod = (minetest.get_timeofday() or 0) * 24000 - - if tod > 4500 and tod < 19500 then - -- daylight, but mob wants night - if day_toggle == false then - -- mob needs night - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!") - return - end - else - -- night time but mob wants day - if day_toggle == true then - -- mob needs day - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!") - return - end - end - end - - -- spawn above node - pos.y = pos.y + 1 - - -- only spawn away from player - local objs = minetest.get_objects_inside_radius(pos, 24) - - for n = 1, #objs do - - if objs[n]:is_player() then - -- player too close - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!") - return - end - end - - -- mobs cannot spawn in protected areas when enabled - if not spawn_protected - and minetest.is_protected(pos, "") then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!") - return - end - - -- are we spawning within height limits? - if pos.y > max_height - or pos.y < min_height then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!") - return - end - - -- are light levels ok? - local light = minetest.get_node_light(pos) - if not light - or light > max_light - or light < min_light then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!") - return - end - - -- do we have enough space to spawn mob? - local ent = minetest.registered_entities[name] - local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1])) - local min_x, max_x - if width_x % 2 == 0 then - max_x = math.floor(width_x/2) - min_x = -(max_x-1) - else - max_x = math.floor(width_x/2) - min_x = -max_x - end - - local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3])) - local min_z, max_z - if width_z % 2 == 0 then - max_z = math.floor(width_z/2) - min_z = -(max_z-1) - else - max_z = math.floor(width_z/2) - min_z = -max_z - end - - local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) - - for y = 0, max_y do - for x = min_x, max_x do - for z = min_z, max_z do - local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z} - if minetest.registered_nodes[node_ok(pos2).name].walkable == true then - -- inside block - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") - if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then - minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) - spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) - end - return - end - end - end - end - - -- tweak X/Y/Z spawn pos - if width_x % 2 == 0 then - pos.x = pos.x + 0.5 - end - if width_z % 2 == 0 then - pos.z = pos.z + 0.5 - end - pos.y = pos.y - 0.5 - - local mob = minetest.add_entity(pos, name) - minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) - - if on_spawn then - - local ent = mob:get_luaentity() - - on_spawn(ent, pos) - end - end - - local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider) - spawn_action(pos, node, active_object_count, active_object_count_wider, name) - end - - - --load information into the spawn dictionary - local key = #spawn_dictionary[dimension] + 1 - - spawn_dictionary[dimension][key] = {} - spawn_dictionary[dimension][key]["name"] = name - spawn_dictionary[dimension][key]["type"] = type_of_spawning - spawn_dictionary[dimension][key]["min_light"] = min_light - spawn_dictionary[dimension][key]["max_light"] = max_light - spawn_dictionary[dimension][key]["interval"] = interval - spawn_dictionary[dimension][key]["chance"] = chance - spawn_dictionary[dimension][key]["aoc"] = aoc - spawn_dictionary[dimension][key]["min_height"] = min_height - spawn_dictionary[dimension][key]["max_height"] = max_height - spawn_dictionary[dimension][key]["day_toggle"] = day_toggle - spawn_dictionary[dimension][key]["on_spawn"] = spawn_abm_action - - --[[ - minetest.register_abm({ - label = name .. " spawning", - nodenames = nodes, - neighbors = neighbors, - interval = interval, - chance = floor(max(1, chance * mobs_spawn_chance)), - catch_up = false, - action = spawn_abm_action, - }) - ]]-- -end - - --- compatibility with older mob registration --- we're going to forget about this for now -j4i ---[[ -function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle) - - mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30, - chance, active_object_count, -31000, max_height, day_toggle) -end -]]-- - - ---I'm not sure what this does but disabling it doesn't cause a crash -j4i --- Just compatibility problem with outer mob mods currently, so adding a warning and temporarily enabling back -kay27 2021-04-08 --- MarkBu's spawn function - -function mobs:spawn(def) - minetest.log("warning", "[mcl_mobs] Deprecated function call: `mobs:spawn()`. Please use mobs:spawn_specific() instead!") - local name = def.name - local nodes = def.nodes or {"group:soil", "group:stone"} --- local neighbors = def.neighbors or {"air"} - local min_light = def.min_light or 0 - local max_light = def.max_light or 15 - local interval = def.interval or 30 - local chance = def.chance or 5000 - local active_object_count = def.active_object_count or 1 - local min_height = def.min_height or -31000 - local max_height = def.max_height or 31000 - local day_toggle = def.day_toggle - local on_spawn = def.on_spawn - - --mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, - -- chance, active_object_count, min_height, max_height, day_toggle, on_spawn) - mobs:spawn_specific(name, "overworld", nodes, min_light, max_light, interval, - chance, active_object_count, min_height, max_height, day_toggle, on_spawn) - mobs:spawn_specific(name, "end", nodes, min_light, max_light, interval, - chance, active_object_count, min_height, max_height, day_toggle, on_spawn) - mobs:spawn_specific(name, "nether", nodes, min_light, max_light, interval, - chance, active_object_count, min_height, max_height, day_toggle, on_spawn) -end - - - -local axis ---inner and outer part of square donut radius -local inner = 1 -local outer = 70 -local int = {-1,1} -local position_calculation = function(pos) - - pos = vector.floor(pos) - - --this is used to determine the axis buffer from the player - axis = math.random(0,1) - - --cast towards the direction - if axis == 0 then --x - pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)] - pos.z = pos.z + math.random(-outer,outer) - else --z - pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)] - pos.x = pos.x + math.random(-outer,outer) - end - return(pos) -end - ---[[ -local decypher_limits_dictionary = { - ["overworld"] = {mcl_vars.mg_overworld_min,mcl_vars.mg_overworld_max}, - ["nether"] = {mcl_vars.mg_nether_min, mcl_vars.mg_nether_max}, - ["end"] = {mcl_vars.mg_end_min, mcl_vars.mg_end_max} -} -]]-- - -local function decypher_limits(posy) - --local min_max_table = decypher_limits_dictionary[dimension] - --return min_max_table[1],min_max_table[2] - posy = math.floor(posy) - return posy - 32, posy + 32 -end - - ---todo mob limiting ---MAIN LOOP -local timer = 15 --0 -minetest.register_globalstep(function(dtime) - timer = timer + dtime - if timer >= 15 then - timer = 0--15--0 - for _,player in ipairs(minetest.get_connected_players()) do - for i = 1,math.random(5) do - local player_pos = player:get_pos() - local _,dimension = mcl_worlds.y_to_layer(player_pos.y) - local min,max = decypher_limits(player_pos.y) - - local goal_pos = position_calculation(player_pos) - - print(dump(minetest.get_biome_data(goal_pos))) - - local mob_def = spawn_dictionary[dimension][math.random(1,#spawn_dictionary[dimension])] - - if not mob_def then --to catch a crazy error if it ever happens - minetest.log("error", "WARNING!! mob spawning attempted to index a NIL mob!") - goto continue - end - - if mob_def.type == "ground" then - - local spawning_position_list = minetest.find_nodes_in_area_under_air(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid"}) - - if #spawning_position_list <= 0 then - goto continue - end - - local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] - - spawning_position.y = spawning_position.y + 1 - - local gotten_light = minetest.get_node_light(spawning_position) - - if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then - minetest.add_entity(spawning_position, mob_def.name) - end - elseif mob_def.type == "air" then - local spawning_position_list = minetest.find_nodes_in_area(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"air"}) - - if #spawning_position_list <= 0 then - goto continue - end - - local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] - - local gotten_light = minetest.get_node_light(spawning_position) - - if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then - minetest.add_entity(spawning_position, mob_def.name) - end - elseif mob_def.type == "water" then - local spawning_position_list = minetest.find_nodes_in_area(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:water"}) - - if #spawning_position_list <= 0 then - goto continue - end - - local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] - - local gotten_light = minetest.get_node_light(spawning_position) - - if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then - minetest.add_entity(spawning_position, mob_def.name) - end - --elseif mob_def.type == "lava" then - --implement later - else -- mob_def.type is specific node name or group name - local spawning_position_list = minetest.find_nodes_in_area_under_air(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), mob_def.type) - - if #spawning_position_list <= 0 then - goto continue - end - - local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] - - spawning_position.y = spawning_position.y + 1 - - local gotten_light = minetest.get_node_light(spawning_position) - - if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then - minetest.add_entity(spawning_position, mob_def.name) - end - end - --local spawn minetest.find_nodes_in_area_under_air(vector.new(pos.x,pos.y-find_node_height,pos.z), vector.new(pos.x,pos.y+find_node_height,pos.z), {"group:solid"}) - - - ::continue:: --this is a safety catch - end - end - end -end) - - - - - - - - - - - - - ---END SPAWNING ALGORITHM - - - - - - - - - - - - - - - - - - - - -- register arrow for shoot attack function mobs:register_arrow(name, def) diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index c2d6cb21bc..69246b4706 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -4,8 +4,11 @@ local path = minetest.get_modpath(minetest.get_current_modname()) -- Mob API dofile(path .. "/api.lua") +-- Spawning Algorithm +dofile(path .. "/spawning.lua") + -- Rideable Mobs dofile(path .. "/mount.lua") -- Mob Items -dofile(path .. "/crafts.lua") +dofile(path .. "/crafts.lua") \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua new file mode 100644 index 0000000000..b56fe1cee0 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -0,0 +1,470 @@ +local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false +-- count how many mobs of one type are inside an area +--[[ +local count_mobs = function(pos, mobtype) + + local num = 0 + local objs = minetest.get_objects_inside_radius(pos, aoc_range) + + for n = 1, #objs do + + local obj = objs[n]:get_luaentity() + + if obj and obj.name and obj._cmi_is_mob then + + -- count passive mobs only + if mobtype == "!passive" then + if obj.spawn_class == "passive" then + num = num + 1 + end + -- count hostile mobs only + elseif mobtype == "!hostile" then + if obj.spawn_class == "hostile" then + num = num + 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 + + return num +end +]]-- + +-- global functions + +function mobs:spawn_abm_check(pos, node, name) + -- global function to add additional spawn checks + -- return true to stop spawning mob +end + + +--[[ + Custom elements changed: +name: +the mobs name + +dimension: +"overworld" +"nether" +"end" + +types of spawning: +"air" +"water" +"ground" +"lava" + +what is aoc??? + +WARNING: BIOME INTEGRATION NEEDED -> How to get biome through lua?? +]]-- + +--this is where all of the spawning information is kept +local spawn_dictionary = { + ["overworld"] = {}, + ["nether"] = {}, + ["end"] = {} +} + +function mobs:spawn_specific(name, dimension, type_of_spawning, min_light, max_light, interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) + -- Do mobs spawn at all? + if not mobs_spawn then + return + end + + -- chance/spawn number override in minetest.conf for registered mob + local numbers = minetest.settings:get(name) + + if numbers then + numbers = numbers:split(",") + chance = tonumber(numbers[1]) or chance + aoc = tonumber(numbers[2]) or aoc + + if chance == 0 then + minetest.log("warning", string.format("[mobs] %s has spawning disabled", name)) + return + end + + minetest.log("action", + string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc)) + end + + local spawn_action + spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) + + local orig_pos = table.copy(pos) + -- is mob actually registered? + if not mobs.spawning_mobs[name] + or not minetest.registered_entities[name] then + minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!") + return + end + + -- additional custom checks for spawning mob + if mobs:spawn_abm_check(pos, node, name) == true then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!") + return + 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 + if active_object_count_wider >= max_per_block -- large-range mob cap + or (not in_class_cap) -- spawn class mob cap + or count_mobs(pos, name) >= aoc then -- per-mob mob cap + -- too many entities + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") + return + end + + -- if toggle set to nil then ignore day/night check + if day_toggle ~= nil then + + local tod = (minetest.get_timeofday() or 0) * 24000 + + if tod > 4500 and tod < 19500 then + -- daylight, but mob wants night + if day_toggle == false then + -- mob needs night + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!") + return + end + else + -- night time but mob wants day + if day_toggle == true then + -- mob needs day + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!") + return + end + end + end + + -- spawn above node + pos.y = pos.y + 1 + + -- only spawn away from player + local objs = minetest.get_objects_inside_radius(pos, 24) + + for n = 1, #objs do + + if objs[n]:is_player() then + -- player too close + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!") + return + end + end + + -- mobs cannot spawn in protected areas when enabled + if not spawn_protected + and minetest.is_protected(pos, "") then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!") + return + end + + -- are we spawning within height limits? + if pos.y > max_height + or pos.y < min_height then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!") + return + end + + -- are light levels ok? + local light = minetest.get_node_light(pos) + if not light + or light > max_light + or light < min_light then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!") + return + end + + -- do we have enough space to spawn mob? + local ent = minetest.registered_entities[name] + local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1])) + local min_x, max_x + if width_x % 2 == 0 then + max_x = math.floor(width_x/2) + min_x = -(max_x-1) + else + max_x = math.floor(width_x/2) + min_x = -max_x + end + + local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3])) + local min_z, max_z + if width_z % 2 == 0 then + max_z = math.floor(width_z/2) + min_z = -(max_z-1) + else + max_z = math.floor(width_z/2) + min_z = -max_z + end + + local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) + + for y = 0, max_y do + for x = min_x, max_x do + for z = min_z, max_z do + local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z} + if minetest.registered_nodes[node_ok(pos2).name].walkable == true then + -- inside block + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") + if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then + minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) + spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) + end + return + end + end + end + end + + -- tweak X/Y/Z spawn pos + if width_x % 2 == 0 then + pos.x = pos.x + 0.5 + end + if width_z % 2 == 0 then + pos.z = pos.z + 0.5 + end + pos.y = pos.y - 0.5 + + local mob = minetest.add_entity(pos, name) + minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) + + if on_spawn then + + local ent = mob:get_luaentity() + + on_spawn(ent, pos) + end + end + + local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider) + spawn_action(pos, node, active_object_count, active_object_count_wider, name) + end + + + --load information into the spawn dictionary + local key = #spawn_dictionary[dimension] + 1 + + spawn_dictionary[dimension][key] = {} + spawn_dictionary[dimension][key]["name"] = name + spawn_dictionary[dimension][key]["type"] = type_of_spawning + spawn_dictionary[dimension][key]["min_light"] = min_light + spawn_dictionary[dimension][key]["max_light"] = max_light + spawn_dictionary[dimension][key]["interval"] = interval + spawn_dictionary[dimension][key]["chance"] = chance + spawn_dictionary[dimension][key]["aoc"] = aoc + spawn_dictionary[dimension][key]["min_height"] = min_height + spawn_dictionary[dimension][key]["max_height"] = max_height + spawn_dictionary[dimension][key]["day_toggle"] = day_toggle + spawn_dictionary[dimension][key]["on_spawn"] = spawn_abm_action + + --[[ + minetest.register_abm({ + label = name .. " spawning", + nodenames = nodes, + neighbors = neighbors, + interval = interval, + chance = floor(max(1, chance * mobs_spawn_chance)), + catch_up = false, + action = spawn_abm_action, + }) + ]]-- +end + + +-- compatibility with older mob registration +-- we're going to forget about this for now -j4i +--[[ +function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle) + + mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30, + chance, active_object_count, -31000, max_height, day_toggle) +end +]]-- + + +--I'm not sure what this does but disabling it doesn't cause a crash -j4i +-- MarkBu's spawn function + +function mobs:spawn(def) + --does nothing for now + --[[ + local name = def.name + local nodes = def.nodes or {"group:soil", "group:stone"} + local neighbors = def.neighbors or {"air"} + local min_light = def.min_light or 0 + local max_light = def.max_light or 15 + local interval = def.interval or 30 + local chance = def.chance or 5000 + local active_object_count = def.active_object_count or 1 + local min_height = def.min_height or -31000 + local max_height = def.max_height or 31000 + local day_toggle = def.day_toggle + local on_spawn = def.on_spawn + + mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, + chance, active_object_count, min_height, max_height, day_toggle, on_spawn) + ]]-- +end + + + +local axis +--inner and outer part of square donut radius +local inner = 1 +local outer = 70 +local int = {-1,1} +local position_calculation = function(pos) + + pos = vector.floor(pos) + + --this is used to determine the axis buffer from the player + axis = math.random(0,1) + + --cast towards the direction + if axis == 0 then --x + pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)] + pos.z = pos.z + math.random(-outer,outer) + else --z + pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)] + pos.x = pos.x + math.random(-outer,outer) + end + return(pos) +end + +--[[ +local decypher_limits_dictionary = { + ["overworld"] = {mcl_vars.mg_overworld_min,mcl_vars.mg_overworld_max}, + ["nether"] = {mcl_vars.mg_nether_min, mcl_vars.mg_nether_max}, + ["end"] = {mcl_vars.mg_end_min, mcl_vars.mg_end_max} +} +]]-- + +local function decypher_limits(posy) + --local min_max_table = decypher_limits_dictionary[dimension] + --return min_max_table[1],min_max_table[2] + posy = math.floor(posy) + return posy - 32, posy + 32 +end + +minetest.register_on_mods_loaded(function() + for _,data in pairs(minetest.registered_biomes) do + print(data.name) + end + + print(dump(spawn_dictionary)) +end) + +--todo mob limiting +--MAIN LOOP +if mobs_spawn then + local timer = 15 --0 + minetest.register_globalstep(function(dtime) + timer = timer + dtime + if timer >= 15 then + timer = 0--15--0 + for _,player in ipairs(minetest.get_connected_players()) do + for i = 1,math.random(5) do + local player_pos = player:get_pos() + local _,dimension = mcl_worlds.y_to_layer(player_pos.y) + local min,max = decypher_limits(player_pos.y) + + local goal_pos = position_calculation(player_pos) + + local gotten_biome = minetest.get_biome_data(goal_pos) + + if not gotten_biome then + goto continue --skip if in unloaded area + end + + --print(minetest.get_biome_name(gotten_biome.biome)) + + local mob_def = spawn_dictionary[dimension][math.random(1,#spawn_dictionary[dimension])] + + if not mob_def then --to catch a crazy error if it ever happens + minetest.log("error", "WARNING!! Attempted to spawn a mob that doesn't exist! Please notify developers!\nThe game will continue to run though.") + goto continue + end + + if mob_def.type == "ground" then + + local spawning_position_list = minetest.find_nodes_in_area_under_air(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid"}) + + if #spawning_position_list <= 0 then + goto continue + end + + local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] + + spawning_position.y = spawning_position.y + 1 + + local gotten_light = minetest.get_node_light(spawning_position) + + if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then + minetest.add_entity(spawning_position, mob_def.name) + end + elseif mob_def.type == "air" then + local spawning_position_list = minetest.find_nodes_in_area(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"air"}) + + if #spawning_position_list <= 0 then + goto continue + end + + local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] + + local gotten_light = minetest.get_node_light(spawning_position) + + if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then + minetest.add_entity(spawning_position, mob_def.name) + end + elseif mob_def.type == "water" then + local spawning_position_list = minetest.find_nodes_in_area(vector.new(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:water"}) + + if #spawning_position_list <= 0 then + goto continue + end + + local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] + + local gotten_light = minetest.get_node_light(spawning_position) + + if gotten_light and gotten_light >= mob_def.min_light and gotten_light <= mob_def.max_light then + minetest.add_entity(spawning_position, mob_def.name) + end + --elseif mob_def.type == "lava" then + --implement later + end + --local spawn minetest.find_nodes_in_area_under_air(vector.new(pos.x,pos.y-find_node_height,pos.z), vector.new(pos.x,pos.y+find_node_height,pos.z), {"group:solid"}) + + ::continue:: --this is a safety catch + end + end + end + end) +end \ No newline at end of file diff --git a/mods/ENTITIES/mobs_mc/depends.txt b/mods/ENTITIES/mobs_mc/depends.txt new file mode 100644 index 0000000000..674eb80940 --- /dev/null +++ b/mods/ENTITIES/mobs_mc/depends.txt @@ -0,0 +1 @@ +mcl_mobs \ No newline at end of file