Spawning: fix random weighted choice

This commit is contained in:
bakawun 2023-11-23 00:11:13 +01:00
parent 59c5d54cbe
commit 402e4e7b79

40
mods/ENTITIES/mcl_mobs/spawning.lua Normal file → Executable file

@ -613,8 +613,8 @@ function mcl_mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_
spawn_dictionary[key]["check_position"] = check_position spawn_dictionary[key]["check_position"] = check_position
summary_chance = summary_chance + chance summary_chance = summary_chance + chance
end
end
local two_pi = 2 * math.pi local two_pi = 2 * math.pi
local function get_next_mob_spawn_pos(pos) local function get_next_mob_spawn_pos(pos)
@ -973,9 +973,21 @@ if mobs_spawn then
return spawning_position return spawning_position
end end
local cumulative_chance = nil
local mob_library_worker_table = nil
local function initialize_spawn_data()
if not mob_library_worker_table then
mob_library_worker_table = table_copy(spawn_dictionary)
end
if not cumulative_chance then
cumulative_chance = 0
for k, v in pairs(mob_library_worker_table) do
cumulative_chance = cumulative_chance + v.chance
end
end
end
local function spawn_a_mob(pos, cap_space_hostile, cap_space_non_hostile) local function spawn_a_mob(pos, cap_space_hostile, cap_space_non_hostile)
--create a disconnected clone of the spawn dictionary, prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary)
local spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES) local spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES)
if not spawning_position then if not spawning_position then
@ -992,18 +1004,25 @@ if mobs_spawn then
perlin_noise = perlin_noise or minetest_get_perlin(noise_params) perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
local noise = perlin_noise:get_3d(spawning_position) local noise = perlin_noise:get_3d(spawning_position)
local current_summary_chance = summary_chance local current_summary_chance = summary_chance
local spawn_loop_counter = #mob_library_worker_table
table.shuffle(mob_library_worker_table) while spawn_loop_counter > 0 do
table.shuffle(mob_library_worker_table)
while #mob_library_worker_table > 0 do local mob_chance_offset = math_random(1, cumulative_chance)
local mob_chance_offset = (math_round(noise * current_summary_chance + 12345) % current_summary_chance) + 1
local mob_index = 1 local mob_index = 1
local mob_chance = mob_library_worker_table[mob_index].chance local mob_chance = mob_library_worker_table[mob_index].chance
local step_chance = mob_chance local step_chance = mob_chance
while step_chance < mob_chance_offset do while step_chance < mob_chance_offset do
mob_index = mob_index + 1 mob_index = mob_index + 1
mob_chance = mob_library_worker_table[mob_index].chance if mob_index <= #mob_library_worker_table then
step_chance = step_chance + mob_chance mob_chance = mob_library_worker_table[mob_index].chance
step_chance = step_chance + mob_chance
else
step_chance = 1000000
end
end
if mob_index > #mob_library_worker_table then
mob_index = 1
end end
--minetest.log(mob_def.name.." "..step_chance.. " "..mob_chance) --minetest.log(mob_def.name.." "..step_chance.. " "..mob_chance)
@ -1089,7 +1108,7 @@ if mobs_spawn then
end end
current_summary_chance = current_summary_chance - mob_chance current_summary_chance = current_summary_chance - mob_chance
table_remove(mob_library_worker_table, mob_index) spawn_loop_counter = spawn_loop_counter - 1
end end
end end
@ -1101,6 +1120,7 @@ if mobs_spawn then
timer = timer + dtime timer = timer + dtime
if timer < WAIT_FOR_SPAWN_ATTEMPT then return end if timer < WAIT_FOR_SPAWN_ATTEMPT then return end
initialize_spawn_data()
timer = 0 timer = 0
local players = get_connected_players() local players = get_connected_players()