cg_plus-cd2025/inventory.lua
2020-10-05 15:28:27 -07:00

352 lines
12 KiB
Lua

local F = minetest.formspec_escape
function cg.update_filter(player, context, filter, force)
filter = filter or ""
if not force and filter:lower() == (context.cg_filter or ""):lower() then
return
end
context.cg_page = 0
context.cg_filter = filter
cg.filter_items(player, context.cg_filter)
end
function cg.update_selected_item(player, context, item, force)
if not force and item == context.cg_selected_item then
return
end
if item then
context.cg_craft_page = 0
end
context.cg_selected_item = item
context.cg_auto_menu = false
end
local function make_item_button(formspec, x, y, size, name)
if name and name ~= "" then
local groups, buttonText
if name:sub(1, 6) == "group:" then
groups = name:sub(7):split(",")
buttonText = #groups == 1 and "G" or ("G " .. #groups)
name = name:gsub(",", "/")
end
formspec[#formspec + 1] = string.format(
"item_image_button[%.2f,%.2f;%.2f,%.2f;%s;cgitem_%s;%s]",
x, y, size, size,
groups and (cg.group_stereotypes[groups[1]] or "") or name,
name:match("^%S+"), -- Keep only the item name, not the quantity.
buttonText or ""
)
if groups then
local tooltipText
if #groups == 1 then
tooltipText = F(cg.S(
"Any item in group: @1",
minetest.colorize("#72FF63", groups[1])
))
else
tooltipText = F(cg.S(
"Any item in groups: @1",
minetest.colorize("#72FF63", table.concat(groups, ", "))
))
end
formspec[#formspec + 1] = string.format("tooltip[cgitem_%s;%s]",
name, tooltipText)
end
else
formspec[#formspec + 1] = string.format(
"image[%.2f,%.2f;%.2f,%.2f;gui_hb_bg.png]",
x, y, size, size
)
end
end
local function make_item_grid(formspec, player, context)
local itemList = cg.get_item_list(player)
context.cg_page = context.cg_page or 0
-- Buttons
formspec[#formspec + 1] =
"real_coordinates[true]" ..
"image_button[3.425,5.3;0.8,0.8;cg_plus_icon_search.png;cg_search;]" ..
"image_button[4.325,5.3;0.8,0.8;cg_plus_icon_clear.png;cg_clear;]" ..
"image_button[6.625,5.3;0.8,0.8;cg_plus_icon_prev.png;cg_prev;]" ..
"image_button[9.325,5.3;0.8,0.8;cg_plus_icon_next.png;cg_next;]"
-- Search box
formspec[#formspec + 1] = string.format(
"field[0.375,5.3;2.95,0.8;cg_filter;;%s]",
F(context.cg_filter or "")
)
formspec[#formspec + 1] = "field_close_on_enter[cg_filter;false]"
-- Page number
formspec[#formspec + 1] = string.format("label[7.75,5.7;%i / %i]",
context.cg_page + 1, itemList.num_pages)
local startIdx = context.cg_page * cg.PAGE_ITEMS + 1
local item
for itemIdx = 0, cg.PAGE_ITEMS - 1 do
item = itemList.list[startIdx + itemIdx]
if item then
formspec[#formspec + 1] = string.format(
"item_image_button[%.2f,%.2f;1,1;%s;cgitem_%s;]",
(itemIdx % cg.PAGE_WIDTH) * 1.25 + 0.375,
math.floor(itemIdx / cg.PAGE_WIDTH) * 1.25 + 0.375,
item, item
)
end
end
end
local function make_craft_preview(formspec, player, context)
formspec[#formspec + 1] =
"real_coordinates[true]" ..
"image_button[9.325,0.375;0.8,0.8;" ..
"cg_plus_icon_clear.png;cg_craft_close;]" ..
"image[0.375,0.375;0.8,0.8;gui_hb_bg.png]"
local item = context.cg_selected_item
-- Item image
formspec[#formspec + 1] = string.format(
"item_image[0.375,0.375;0.8,0.8;%s]",
item
)
-- Item name
formspec[#formspec + 1] = string.format(
"label[1.5,0.6;%s]",
cg.crafts[item] and minetest.registered_items[item].description or item
)
-- No recipes label, if applicable
local crafts = cg.crafts[item]
if not crafts or #crafts == 0 then
formspec[#formspec + 1] = string.format("label[2.875,3.2;%s]",
F(cg.S("There are no recipes for this item.")))
return
end
-- Previous/next craft buttons, page number
if #crafts > 1 then
formspec[#formspec + 1] =
"image_button[2.875,5.3;0.8,0.8;" ..
"cg_plus_icon_prev.png;cg_craft_prev;]" ..
"image_button[5.575,5.3;0.8,0.8;" ..
"cg_plus_icon_next.png;cg_craft_next;]"
formspec[#formspec + 1] = string.format("label[4,5.7;%i / %i]",
context.cg_craft_page + 1, #crafts)
end
local craft = cg.parse_craft(crafts[context.cg_craft_page + 1])
local template = cg.craft_types[craft.type] or {}
-- Auto-crafting buttons
if cg.AUTOCRAFTING and template.uses_crafting_grid then
formspec[#formspec + 1] = "image_button[0.375,5.3;0.8,0.8;" ..
"cg_plus_icon_autocrafting.png;cg_auto_menu;]"
formspec[#formspec + 1] = string.format("tooltip[cg_auto_menu;%s]",
F(cg.S("Craft this recipe")))
if context.cg_auto_menu then
local num = 1
local yPos = 4.3
while true do
num = math.min(num, context.cg_auto_max)
formspec[#formspec + 1] = string.format(
"button[0.375,%.2f;0.8,0.8;cg_auto_%i;%i]",
yPos, num, num
)
formspec[#formspec + 1] = string.format(
"tooltip[cg_auto_%i;%s]",
num,
num == 1
and F(cg.S("Craft @1 item", num))
or F(cg.S("Craft @1 items", num))
)
if num < context.cg_auto_max then
num = num * 10
yPos = yPos - 1
else
break
end
end
end
end
-- Craft type/info text
formspec[#formspec + 1] = string.format("label[6.7,1.8;%s]",
template.description or "")
formspec[#formspec + 1] = string.format("label[6.7,2.4;%s]",
craft.infotext or "")
-- Draw craft item grid, feat. maths.
-- Determine max number of grid slots that could fit on one side.
-- Squares shouldn't take up more than a third of the grid area.
local gridMax = math.max(math.max(craft.grid_size.x, craft.grid_size.y), 3)
-- Determine distance between crafting grid slots.
-- <grid area side length> / (<num slots per side> - <extra padding>)
local slotDist = 3.5 / (gridMax - 0.2)
-- Determine upper-left corner of crafting squares
-- <right x of grid area> - (<grid width> - <extra padding>) * slotDist
local xOffset = 6.375 - (craft.grid_size.x - 0.2) * slotDist
-- <center y of grid area> -
-- (<grid height> - <extra padding>) * slotDist * 0.5
local yOffset = 3.2 - (craft.grid_size.y - 0.2) * slotDist * 0.5
for idx = 1, craft.grid_size.x * craft.grid_size.y do
make_item_button(
formspec,
((idx - 1) % craft.grid_size.x) * slotDist + xOffset,
math.floor((idx - 1) / craft.grid_size.y) * slotDist + yOffset,
slotDist * 0.8, -- 1 - <padding amount>
craft.items[idx]
)
end
-- Craft arrow
formspec[#formspec + 1] = string.format("image[6.625,2.7;1,1;%s]",
template.arrow_icon or "cg_plus_arrow.png")
-- Craft output
make_item_button(formspec, 7.875, 2.7, 1, craft.output)
end
--[[
sfinv registration
]]
local function page_get(self, player, context)
local formspec = {}
if context.cg_selected_item then
make_craft_preview(formspec, player, context)
else
make_item_grid(formspec, player, context)
end
return sfinv.make_formspec(player, context, table.concat(formspec), true)
end
local function page_on_player_receive_fields(self, player, context, fields)
if fields.cg_craft_close then
context.cg_selected_item = nil
context.cg_auto_menu = false
elseif fields.cg_prev and context.cg_page then
context.cg_page = context.cg_page - 1
elseif fields.cg_next and context.cg_page then
context.cg_page = context.cg_page + 1
elseif fields.cg_craft_prev and context.cg_craft_page then
context.cg_craft_page = context.cg_craft_page - 1
context.cg_auto_menu = false
elseif fields.cg_craft_next and context.cg_craft_page then
context.cg_craft_page = context.cg_craft_page + 1
context.cg_auto_menu = false
elseif fields.cg_search or fields.key_enter_field == "cg_filter" then
cg.update_filter(player, context, fields.cg_filter)
elseif fields.cg_clear then
cg.update_filter(player, context, "", true)
elseif fields.cg_auto_menu and cg.AUTOCRAFTING then
if not context.cg_auto_menu then
-- Make sure the craft is valid, in case the client is sending
-- fake formspec fields.
local crafts = cg.crafts[context.cg_selected_item] or {}
local craft = crafts[context.cg_craft_page + 1]
if craft and cg.craft_types[craft.type]
and cg.craft_types[craft.type].uses_crafting_grid then
context.cg_auto_menu = true
context.cg_auto_max = cg.auto_get_craftable(player, craft)
end
else
context.cg_auto_menu = false
end
else
for field, _ in pairs(fields) do
if field:sub(1, 7) == "cgitem_" then
local item = string.sub(field, 8)
if item:sub(1, 6) == "group:" then
if cg.GROUP_SEARCH then
cg.update_filter(player, context, item)
cg.update_selected_item(player, context, nil)
elseif cg.group_stereotypes[item:sub(7)] then
cg.update_selected_item(player, context,
cg.group_stereotypes[item:sub(7)])
end
else
cg.update_selected_item(player, context, item)
end
break
elseif field:sub(1, 8) == "cg_auto_"
and context.cg_auto_menu then
-- No need to sanity check, we already did that when
-- showing the autocrafting menu.
local num = tonumber(field:sub(9))
if num > 0 and num <= context.cg_auto_max then
cg.auto_craft(
player,
cg.crafts[context.cg_selected_item]
[context.cg_craft_page + 1],
num
)
sfinv.set_page(player, "sfinv:crafting")
end
context.cg_auto_menu = false
break
end
end
end
-- Wrap around when the player presses the next button on the last
-- page, or the previous button on the first.
if context.cg_page then
context.cg_page = context.cg_page %
math.max(cg.get_item_list(player).num_pages, 1)
end
if context.cg_craft_page then
context.cg_craft_page = context.cg_craft_page %
math.max(#(cg.crafts[context.cg_selected_item] or {}), 1)
end
-- Update the formspec.
sfinv.set_player_inventory_formspec(player, context)
end
local function page_on_leave(self, player, context)
context.cg_auto_menu = false
end
if sfinv.pages["mtg_craftguide:craftguide"] ~= nil then
-- Override MTG's crafting guide
sfinv.override_page("mtg_craftguide:craftguide", {
title = F(cg.S("Crafting Guide")),
get = page_get,
on_player_receive_fields = page_on_player_receive_fields,
on_leave = page_on_leave
})
else
sfinv.register_page("cg_plus:crafting_guide", {
title = F(cg.S("Crafting Guide")),
get = page_get,
on_player_receive_fields = page_on_player_receive_fields,
on_leave = page_on_leave
})
end