Add basic support for progressive mode

What’s lacking: Saving held items, a game setting.
This commit is contained in:
Jaidyn Ann 2024-08-13 20:00:52 -05:00
parent dddc857e15
commit e4d566b13a

138
init.lua
View File

@ -300,7 +300,7 @@ local function get_formspec(player)
end end
table.insert(fs, "container[0,5.6]") table.insert(fs, "container[0,5.6]")
if data.recipes then if data.recipes and #data.recipes > 0 then
recipe_fs(fs, data) recipe_fs(fs, data)
elseif data.prev_item then elseif data.prev_item then
table.insert(fs, ("label[2,1;%s]"):format(esc(data.show_usages table.insert(fs, ("label[2,1;%s]"):format(esc(data.show_usages
@ -319,12 +319,12 @@ end
local function execute_search(data) local function execute_search(data)
local filter = data.filter local filter = data.filter
if filter == "" then if filter == "" then
data.items = init_items data.items = visible_items(data)
return return
end end
data.items = {} data.items = {}
for _, item in ipairs(init_items) do for _, item in ipairs(visible_items(data)) do
local def = minetest.registered_items[item] local def = minetest.registered_items[item]
local desc = def and minetest.get_translated_string(data.lang_code, def.description) local desc = def and minetest.get_translated_string(data.lang_code, def.description)
@ -343,7 +343,7 @@ local function on_receive_fields(player, fields)
data.pagenum = 1 data.pagenum = 1
data.prev_item = nil data.prev_item = nil
data.recipes = nil data.recipes = nil
data.items = init_items data.items = visible_items(data)
return true return true
elseif (fields.key_enter_field == "filter" or fields.search) elseif (fields.key_enter_field == "filter" or fields.search)
@ -398,9 +398,9 @@ local function on_receive_fields(player, fields)
data.show_usages = nil data.show_usages = nil
end end
if data.show_usages then if data.show_usages then
data.recipes = usages_cache[item] data.recipes = known_recipes(data, usages_cache[item])
else else
data.recipes = recipes_cache[item] data.recipes = known_recipes(data, recipes_cache[item])
end end
data.prev_item = item data.prev_item = item
data.rnum = 1 data.rnum = 1
@ -415,7 +415,10 @@ minetest.register_on_joinplayer(function(player)
player_data[name] = { player_data[name] = {
filter = "", filter = "",
pagenum = 1, pagenum = 1,
items = init_items, items = {},
held_items = {},
held_groups = {},
known_items = {},
lang_code = info.lang_code lang_code = info.lang_code
} }
end) end)
@ -436,3 +439,124 @@ sfinv.register_page("mtg_craftguide:craftguide", {
end end
end end
}) })
-- ~ Progressive-mode support ~
-- [The vast majority of changes to mtg_craftguide are found here!]
function table_to_str(table)
local ret = "["
for k,v in pairs(table) do
ret = ret .. "; " .. k .. " - "
if type(v) == "table" then
ret = ret .. table_to_str(v)
else
ret = ret .. v
end
end
return ret .. "]"
end
-- Given a players data and a recipe, return whether or not that recipe
-- is “known” by the player. (That is, they have held all necessary inputs.)
function known_recipe(data, recipe)
for _,input in pairs(recipe.items) do
if (not data.held_items[input:gsub(" .*", "")]) and (not data.held_groups[input]) then
return false
end
end
return true
end
-- From a table of recipes, return a sub-table of recipes that are “known.”
function known_recipes(data, recipes)
local ret = {}
if recipes then
for _,recipe in pairs(recipes) do
if known_recipe(data, recipe) then
table.insert(ret, recipe)
end
end
end
return ret
end
-- Given a players data and an item-name, return a table of all items the
-- player should “know of” that can be crafted from that item.
function known_crafting_outputs(data, item_name)
local outputs = {}
local uses = usages_cache[item_name]
if uses then
for _,recipe in pairs(uses) do
if known_recipe(data, recipe) then
local out_name = recipe.output
out_name = out_name:gsub(" .*", "")
table.insert(outputs, out_name)
end
end
end
return outputs
end
-- Returns a table of all items that are “known” to the player; either theyve
-- been held by them, or theyre craftable using solely objects held previously.
function visible_items(data)
local ret = {}
for item,_ in pairs(data.held_items) do
table.insert(ret, item)
end
for item,_ in pairs(data.known_items) do
table.insert(ret, item)
end
return ret
end
-- To be executed whenever a player gains/picks up an item.
-- If the item is new, it is added to the players held_items table, and then
-- possible outputs from it (and other known items) are added to known_items.
function update_known_items(player, item_name)
local name = player:get_player_name()
local data = player_data[name]
if not data.held_items[item_name] then
-- Mark the new item as known.
data.held_items[item_name] = true
-- Mark the new items groups as known.
local groups = minetest.registered_items[item_name].groups
for group,rating in pairs(groups) do
if rating > 0 then
data.held_groups["group:" .. group] = true
end
end
-- Mark items craftable with this (and other) items as known.
for _,out_item_name in pairs(known_crafting_outputs(data, item_name)) do
data.known_items[out_item_name] = true
end
-- Reset item-list.
data.items = visible_items(data)
-- Notify the player.
minetest.chat_send_player(name, S("New recipes unlocked!"))
end
end
minetest.register_on_item_pickup(function(itemstack, picker)
update_known_items(picker, itemstack:get_name())
end)
minetest.register_on_player_inventory_action(function(player, action, inv, inv_info)
if action == "put" then
update_known_items(player, inv_info.stack:get_name())
end
end)
minetest.register_on_dignode(function(pos, oldnode, digger)
update_known_items(digger, oldnode.name)
end)
minetest.register_on_craft(function(itemstack, player)
update_known_items(player, itemstack:get_name())
end)