diff --git a/mods/CORE/mcl_loot/init.lua b/mods/CORE/mcl_loot/init.lua index f7eff3f64..3b52e3655 100644 --- a/mods/CORE/mcl_loot/init.lua +++ b/mods/CORE/mcl_loot/init.lua @@ -98,3 +98,57 @@ function mcl_loot.get_multi_loot(multi_loot_definitions, pr) end return items end + +--[[ +Returns a table of length `max_slot` and all natural numbers between 1 and `max_slot` +in a random order. +]] +local function get_random_slots(max_slot) + local slots = {} + for s=1, max_slot do + slots[s] = s + end + local slots_out = {} + while #slots > 0 do + local r = math.random(1, #slots) + table.insert(slots_out, slots[r]) + table.remove(slots, r) + end + for s=1, #slots_out do + print(slots_out[s]) + end + return slots_out +end + +--[[ +Puts items in an inventory list into random slots. +* inv: InvRef +* listname: Inventory list name +* items: table of items to add + +Items will be added from start of the table to end. +If the inventory already has occupied slots, or is +too small, placement of some items might fail. +]] +function mcl_loot.fill_inventory(inv, listname, items) + local size = inv:get_size(listname) + local slots = get_random_slots(size) + local leftovers = {} + -- 1st pass: Add items into random slots + for i=1, math.min(#items, size) do + local item = items[i] + local slot = slots[i] + local old_item = inv:get_stack(listname, slot) + local leftover = old_item:add_item(item) + inv:set_stack(listname, slot, old_item) + if not leftover:is_empty() then + table.insert(leftovers, item) + end + end + -- 2nd pass: If some items couldn't be added in first pass, + -- try again in a non-random fashion + for l=1, math.min(#leftovers, size) do + inv:add_item(listname, leftovers[l]) + end + -- If there are still items left, tough luck! +end diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index f23c33bfb..dc19a6e19 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -366,9 +366,7 @@ minetest.register_on_generated(function(minp, maxp) local meta = minetest.get_meta(cpos) local inv = meta:get_inventory() local items = get_loot() - for i=1, math.min(#items, inv:get_size("main")) do - inv:set_stack("main", i, ItemStack(items[i])) - end + mcl_loot.fill_inventory(inv, "main", items) end -- Mob spawners are placed seperately, too diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 552691bf4..e98deddae 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -188,9 +188,7 @@ mcl_structures.generate_igloo_basement = function(pos, orientation) local meta = minetest.get_meta(chest_pos) local inv = meta:get_inventory() inv:set_size("main", 9*3) - for i=1, #lootitems do - inv:add_item("main", lootitems[i]) - end + mcl_loot.fill_inventory(inv, "main", lootitems) end return success end @@ -401,9 +399,7 @@ mcl_structures.generate_desert_temple = function(pos) local meta = minetest.get_meta(chests[c]) local inv = meta:get_inventory() inv:set_size("main", 9*3) - for i=1, #lootitems do - inv:add_item("main", lootitems[i]) - end + mcl_loot.fill_inventory(inv, "main", lootitems) end -- Initialize pressure plates and randomly remove up to 5 plates diff --git a/mods/MAPGEN/tsm_railcorridors/init.lua b/mods/MAPGEN/tsm_railcorridors/init.lua index d6de8198a..6812125eb 100644 --- a/mods/MAPGEN/tsm_railcorridors/init.lua +++ b/mods/MAPGEN/tsm_railcorridors/init.lua @@ -377,9 +377,7 @@ local function PlaceChest(pos, param2) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local items = tsm_railcorridors.get_treasures(pr) - for i=1, math.min(#items, inv:get_size("main")) do - inv:set_stack("main", i, ItemStack(items[i])) - end + mcl_loot.fill_inventory(inv, "main", items) end end