From ec6eb517262793c7f0d589be5406b9a7071e5bc1 Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Wed, 7 Apr 2021 02:39:15 -0400 Subject: [PATCH] Massively overhaul spawning algorithm for mobs --- mods/ENTITIES/mcl_mobs/api.lua | 156 +++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 6 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 49c8edeaf..d85633421 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -4026,7 +4026,14 @@ types of spawning: 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, @@ -4043,10 +4050,6 @@ function mobs:spawn_specific( on_spawn) - - - print(name, dump(nodes)) - -- Do mobs spawn at all? if not mobs_spawn then return @@ -4067,7 +4070,6 @@ function mobs:spawn_specific( minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc)) - end local spawn_action @@ -4232,6 +4234,24 @@ function mobs:spawn_specific( 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, @@ -4241,18 +4261,24 @@ function mobs:spawn_specific( 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) local name = def.name @@ -4271,9 +4297,127 @@ function mobs:spawn(def) 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 + + +--todo mob limiting +--MAIN LOOP +local timer = 0 +minetest.register_globalstep(function(dtime) + timer = timer + dtime + if timer >= 15 then + timer = 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 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 + 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)