forked from VoxeLibre/VoxeLibre
Added woodland mansion loot, replaced /loot with /lootchest, fixed some bugs
This commit is contained in:
parent
4867904ab1
commit
7996e210d9
|
@ -386,19 +386,26 @@ end
|
|||
|
||||
function mcl_util.drop_items_from_meta_container(listname)
|
||||
return function(pos, oldnode, oldmetadata)
|
||||
local inv, meta
|
||||
|
||||
meta = minetest.get_meta(pos)
|
||||
-- TODO: Is this check required?
|
||||
if oldmetadata and oldmetadata.inventory then
|
||||
-- process in after_dig_node callback
|
||||
local main = oldmetadata.inventory.main
|
||||
if not main then return end
|
||||
for _, stack in pairs(main) do
|
||||
drop_item_stack(pos, stack)
|
||||
end
|
||||
else
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
for i = 1, inv:get_size("main") do
|
||||
drop_item_stack(pos, inv:get_stack("main", i))
|
||||
end
|
||||
meta:from_table(oldmetadata)
|
||||
end
|
||||
|
||||
inv = meta:get_inventory()
|
||||
minetest.debug(inv:is_empty(listname))
|
||||
|
||||
-- Generate loot if not already done so
|
||||
-- FIXME: If a player digs container, they are not recognised in loot context
|
||||
vl_loot.generate_container_loot_if_exists(pos, nil, inv, listname)
|
||||
-- Drop all stacks
|
||||
for i = 1, inv:get_size(listname) do
|
||||
drop_item_stack(pos, inv:get_stack(listname, i))
|
||||
end
|
||||
-- Clear metadata if necessary
|
||||
if meta then
|
||||
meta:from_table()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,15 +34,19 @@ vl_datapacks = {
|
|||
|
||||
local function split_resource_string(resource_string)
|
||||
local match_start, _, namespace, path = string.find(resource_string, "([^%s]+)%:([^%s]+)")
|
||||
if not match_start then
|
||||
error("Invalid resource string: " .. resource_string)
|
||||
end
|
||||
return namespace, path
|
||||
return match_start, namespace, path
|
||||
end
|
||||
|
||||
function vl_datapacks.get_resource(registry, resource_string)
|
||||
local namespace, path = split_resource_string(resource_string)
|
||||
return vl_datapacks.registries[registry][namespace][path]
|
||||
-- Get resource, returns nil if resource does not exist
|
||||
-- Can be used to check if resource exists
|
||||
function vl_datapacks.get_resource(registry_name, resource_string)
|
||||
local matched, namespace, path = split_resource_string(resource_string)
|
||||
if not matched then return end
|
||||
local registry = vl_datapacks.registries[registry_name]
|
||||
if not registry then return end
|
||||
local namespace_index = registry[namespace]
|
||||
if not namespace_index then return end
|
||||
return namespace_index[path]
|
||||
end
|
||||
|
||||
for registry_name, _ in pairs(vl_datapacks.registry_specs) do
|
||||
|
|
|
@ -126,7 +126,6 @@ local function get_pool_loot(pool_table, loot_context)
|
|||
|
||||
end
|
||||
modify_stacks(pool_table.functions, loot_stacks, loot_context)
|
||||
minetest.debug("Pool's loot stacks:", dump(loot_stacks))
|
||||
return loot_stacks
|
||||
end
|
||||
|
||||
|
|
|
@ -9,18 +9,52 @@ dofile(modpath .. "/predicate.lua")
|
|||
dofile(modpath .. "/number_provider.lua")
|
||||
dofile(modpath .. "/engine.lua")
|
||||
|
||||
--[[ -- Load resources specified in `expected_resources` from `path`
|
||||
-- `strict`: whether to error if resources not found
|
||||
local function load_loot_tables(path, expected_resources, strict)
|
||||
vl_loot.load_resources_internal(path, expected_resources, vl_loot.loot_tables, strict)
|
||||
end ]]
|
||||
|
||||
-- Fisher-Yates shuffle
|
||||
local function shuffle(to_shuffle)
|
||||
for i = #to_shuffle, 2, -1 do
|
||||
local j = math.random(i)
|
||||
to_shuffle[i], to_shuffle[j] = to_shuffle[j], to_shuffle[i]
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Puts items in an inventory list into random slots.
|
||||
* inv: InvRef
|
||||
* listname: Inventory list name
|
||||
* items: table of itemstacks to add
|
||||
|
||||
- If there are fewer itemstacks than slots, random slots will be filled
|
||||
- If there are too many itemstacks, a random selection will be inserted to fill the container
|
||||
- If there are existing items in the inventory, they will be deleted
|
||||
]]
|
||||
|
||||
-- TODO: Make this deterministic
|
||||
-- TODO: Currently overwrites itemstacks, could reimplement so it only inserts into empty slots
|
||||
local function disperse_in_inventory(inv, listname, items)
|
||||
local size = inv:get_size(listname)
|
||||
|
||||
-- If there are more slots than items, should add empty itemstacks to fill container
|
||||
while size > #items do
|
||||
table.insert(items, ItemStack())
|
||||
end
|
||||
|
||||
-- Shuffle the order of items in slots
|
||||
shuffle(items)
|
||||
|
||||
-- If there are too many itemstacks, decrease to inventory size
|
||||
-- TODO: Is this needed or is it handled by set_list?
|
||||
items = {unpack(items, 1, size)}
|
||||
|
||||
-- Write the items back into the inventory
|
||||
inv:set_list(listname, items)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- loot_table: chest loot table
|
||||
-- pos: position of chest node
|
||||
-- opener: objectref of entity that opened chest
|
||||
local function get_chest_loot(loot_table, pos, opener)
|
||||
-- loot_table: container loot table
|
||||
-- pos: position of container node
|
||||
-- opener: objectref of entity that opened container
|
||||
local function get_container_loot(loot_table, pos, opener)
|
||||
-- TODO: Provide better context (there are implied fields)
|
||||
local context = {
|
||||
["this"] = opener,
|
||||
|
@ -29,28 +63,66 @@ local function get_chest_loot(loot_table, pos, opener)
|
|||
return vl_loot.engine.get_loot(loot_table, context)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("loot", {
|
||||
-- pos: integer node position of container
|
||||
-- opener: objectref of entity that opened container
|
||||
-- inventory: InvRef to put loot into
|
||||
-- listname: list to put loot into in inventory
|
||||
local function generate_container_loot_if_exists(pos, opener, inventory, listname)
|
||||
local container_meta = minetest.get_meta(pos)
|
||||
local loot_table_name = container_meta:get_string("vl_loot:loot_table")
|
||||
minetest.debug("Using loot table: " .. loot_table_name)
|
||||
-- Do nothing if this container is not a loot container/has already been looted
|
||||
if loot_table_name == "" then return end
|
||||
-- REMOVE ^^
|
||||
-- Remove loot table metadata from this container
|
||||
container_meta:set_string("vl_loot:loot_table", "")
|
||||
-- Generate loot to fill this container with
|
||||
local loot_table = vl_datapacks.get_resource("loot_table", loot_table_name)
|
||||
-- If invalid loot table, don't populate
|
||||
if not loot_table then
|
||||
minetest.log("warning", "Container had invalid loot table metadata (" .. loot_table_name .. ") at " .. vector.to_string(pos))
|
||||
return
|
||||
end
|
||||
local loot_items = get_container_loot(loot_table, pos, opener)
|
||||
-- Fill inventory
|
||||
disperse_in_inventory(inventory, listname, loot_items)
|
||||
end
|
||||
|
||||
vl_loot.generate_container_loot_if_exists = generate_container_loot_if_exists
|
||||
|
||||
if minetest.global_exists("tt") then
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
tt.register_snippet(function(itemstring, tool_caps, itemstack)
|
||||
if not itemstack then return end
|
||||
local loot_table = itemstack:get_meta():get_string("vl_loot:loot_table")
|
||||
if loot_table ~= "" then
|
||||
return S("Loot table: @1", loot_table), "#FFAA00"
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("lootchest", {
|
||||
params = "<loot table resource location>",
|
||||
privs = {["give"] = true},
|
||||
description = "Give yourself a loot chest with a specified loot table",
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
local pos = player:get_pos()
|
||||
local loot_table = vl_datapacks.get_resource("loot_table", param)
|
||||
--minetest.debug("testloot table:", dump(loot_table))
|
||||
local loot = get_chest_loot(loot_table, pos, player)
|
||||
--[[ for _, stack in ipairs(loot) do
|
||||
minetest.debug(stack:to_string())
|
||||
end ]]
|
||||
local player_inv = player:get_inventory()
|
||||
local inv_list = player_inv:get_list("main")
|
||||
for i, itemstack in ipairs(inv_list) do
|
||||
if itemstack:is_empty() then
|
||||
inv_list[i] = table.remove(loot, 1)
|
||||
if vl_datapacks.get_resource("loot_table", param) then
|
||||
local itemstack = ItemStack({
|
||||
name = "mcl_chests:chest",
|
||||
meta = {["vl_loot:loot_table"] = param,
|
||||
}
|
||||
})
|
||||
local player = minetest.get_player_by_name(name)
|
||||
local leftover = player:get_inventory():add_item("main", itemstack)
|
||||
if leftover:is_empty() then
|
||||
return true, "Gave loot chest with table: " .. param
|
||||
else
|
||||
-- Could not add to inventory
|
||||
return false, "No space in inventory"
|
||||
end
|
||||
else
|
||||
return false, "Loot table resource does not exist: " .. param
|
||||
end
|
||||
player_inv:set_list("main", inv_list)
|
||||
if #loot > 0 then
|
||||
minetest.debug("Too much loot for inventory!")
|
||||
end
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
name=vl_loot
|
||||
name=vl_loot
|
||||
optional_depends=tt
|
|
@ -401,7 +401,10 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
minetest.set_node(pos, node)
|
||||
end,
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
||||
local itemstack_meta = itemstack:get_meta()
|
||||
local node_meta = minetest.get_meta(pos)
|
||||
node_meta:set_string("name", itemstack_meta:get_string("name"))
|
||||
node_meta:set_string("vl_loot:loot_table", itemstack_meta:get_string("vl_loot:loot_table"))
|
||||
end,
|
||||
})
|
||||
|
||||
|
@ -531,10 +534,15 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
return false
|
||||
end
|
||||
end
|
||||
local name = minetest.get_meta(pos):get_string("name")
|
||||
local node_meta = minetest.get_meta(pos)
|
||||
local name = node_meta:get_string("name")
|
||||
if name == "" then
|
||||
name = S("Chest")
|
||||
end
|
||||
|
||||
local inventory = node_meta:get_inventory()
|
||||
-- TODO: Loot is generated invidually per half of double chest
|
||||
vl_loot.generate_container_loot_if_exists(pos, clicker, inventory, "main")
|
||||
|
||||
minetest.show_formspec(clicker:get_player_name(),
|
||||
sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
|
||||
|
@ -697,13 +705,22 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
return false
|
||||
end
|
||||
|
||||
local name = minetest.get_meta(pos):get_string("name")
|
||||
local node_meta = minetest.get_meta(pos)
|
||||
local other_node_meta = minetest.get_meta(pos_other)
|
||||
local name = node_meta:get_string("name")
|
||||
if name == "" then
|
||||
name = minetest.get_meta(pos_other):get_string("name")
|
||||
name = other_node_meta:get_string("name")
|
||||
end
|
||||
if name == "" then
|
||||
name = S("Large Chest")
|
||||
end
|
||||
|
||||
-- TODO: loot is generated separately per chest half
|
||||
local inventory = node_meta:get_inventory()
|
||||
vl_loot.generate_container_loot_if_exists(pos, clicker, inventory, "main")
|
||||
|
||||
local inventory_other = other_node_meta:get_inventory()
|
||||
vl_loot.generate_container_loot_if_exists(pos_other, clicker, inventory_other, "main")
|
||||
|
||||
minetest.show_formspec(clicker:get_player_name(),
|
||||
sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
|
||||
|
@ -890,13 +907,22 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
return false
|
||||
end
|
||||
|
||||
local name = minetest.get_meta(pos_other):get_string("name")
|
||||
local node_meta = minetest.get_meta(pos)
|
||||
local other_node_meta = minetest.get_meta(pos_other)
|
||||
local name = other_node_meta:get_string("name")
|
||||
if name == "" then
|
||||
name = minetest.get_meta(pos):get_string("name")
|
||||
name = node_meta:get_string("name")
|
||||
end
|
||||
if name == "" then
|
||||
name = S("Large Chest")
|
||||
end
|
||||
|
||||
-- TODO: loot is generated separately per chest half
|
||||
local inventory = node_meta:get_inventory()
|
||||
vl_loot.generate_container_loot_if_exists(pos, clicker, inventory, "main")
|
||||
|
||||
local inventory_other = other_node_meta:get_inventory()
|
||||
vl_loot.generate_container_loot_if_exists(pos_other, clicker, inventory_other, "main")
|
||||
|
||||
minetest.show_formspec(clicker:get_player_name(),
|
||||
sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
|
||||
|
|
Loading…
Reference in New Issue