Better icons, try to improve code
13
README.md
@ -1,10 +1,15 @@
|
|||||||
# Crafting Guide Plus
|
# Crafting Guide Plus
|
||||||
|
|
||||||
|
[](https://content.minetest.net/packages/random_geek/cg_plus/)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Crafting Guide Plus is a simple and intuitive crafting guide and auto-crafting mod for Minetest. CGP is compatible with
|
Crafting Guide Plus is a simple and intuitive crafting guide and auto-crafting mod for Minetest. CGP is compatible with
|
||||||
Minetest Game and any other games that use sfinv. It was built mostly from the ground up, with some inspiration from
|
Minetest Game and any other games that use sfinv. It was built mostly from the ground up, with some inspiration from
|
||||||
jp's mod as well as Unified Inventory.
|
jp's Crafting Guide, Unified Inventory, and Minetest Game's builtin crafting guide.
|
||||||
|
|
||||||
|
Note: If `mtg_craftguide` is present, CGP will override its page in the inventory. You may want to remove
|
||||||
|
`mtg_craftguide` entirely for optimization purposes.
|
||||||
|
|
||||||
## Features:
|
## Features:
|
||||||
|
|
||||||
@ -27,12 +32,8 @@ Code is licensed under the GNU LGPL v3.0. Images and other media are CC BY-SA 4.
|
|||||||
The following images are from Minetest Game, and their respective licenses apply:
|
The following images are from Minetest Game, and their respective licenses apply:
|
||||||
|
|
||||||
```
|
```
|
||||||
cg_plus_icon_autocrafting.png Based on default_tool_stonepick.png
|
cg_plus_icon_autocrafting.png Adapted from default_tool_stonepick.png
|
||||||
cg_plus_icon_clear.png From creative_clear_icon.png
|
|
||||||
cg_plus_icon_cooking.png From default_furnace_front_active.png
|
cg_plus_icon_cooking.png From default_furnace_front_active.png
|
||||||
cg_plus_icon_digging.png From default_tool_stonepick.png
|
cg_plus_icon_digging.png From default_tool_stonepick.png
|
||||||
cg_plus_icon_fuel.png From default_furnace_fire_fg.png
|
cg_plus_icon_fuel.png From default_furnace_fire_fg.png
|
||||||
cg_plus_icon_next.png From creative_next_icon.png
|
|
||||||
cg_plus_icon_prev.png From creative_prev_icon.png
|
|
||||||
cg_plus_icon_search.png From creative_search_icon.png
|
|
||||||
```
|
```
|
||||||
|
112
api.lua
@ -1,6 +1,6 @@
|
|||||||
-- TODO: aliases?
|
-- TODO: aliases?
|
||||||
|
|
||||||
local get_drops = function(item, def)
|
local function get_drops(item, def)
|
||||||
local normalDrops = {}
|
local normalDrops = {}
|
||||||
local randomDrops = {}
|
local randomDrops = {}
|
||||||
|
|
||||||
@ -13,7 +13,9 @@ local get_drops = function(item, def)
|
|||||||
local dStack, dName, dCount
|
local dStack, dName, dCount
|
||||||
|
|
||||||
for _, dropTable in ipairs(dropTables) do
|
for _, dropTable in ipairs(dropTables) do
|
||||||
if itemsLeft and itemsLeft <= 0 then break end
|
if itemsLeft and itemsLeft <= 0 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
for _, dropItem in ipairs(dropTable.items) do
|
for _, dropItem in ipairs(dropTable.items) do
|
||||||
dStack = ItemStack(dropItem)
|
dStack = ItemStack(dropItem)
|
||||||
@ -21,15 +23,20 @@ local get_drops = function(item, def)
|
|||||||
dCount = dStack:get_count()
|
dCount = dStack:get_count()
|
||||||
|
|
||||||
if dCount > 0 and dName ~= item then
|
if dCount > 0 and dName ~= item then
|
||||||
if #dropTable.items == 1 and dropTable.rarity == 1 and maxStart then
|
if #dropTable.items == 1 and dropTable.rarity == 1
|
||||||
|
and maxStart then
|
||||||
normalDrops[dName] = (normalDrops[dName] or 0) + dCount
|
normalDrops[dName] = (normalDrops[dName] or 0) + dCount
|
||||||
|
|
||||||
if itemsLeft then
|
if itemsLeft then
|
||||||
itemsLeft = itemsLeft - 1
|
itemsLeft = itemsLeft - 1
|
||||||
if itemsLeft <= 0 then break end
|
if itemsLeft <= 0 then
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if itemsLeft then maxStart = false end
|
if itemsLeft then
|
||||||
|
maxStart = false
|
||||||
|
end
|
||||||
|
|
||||||
randomDrops[dName] = (randomDrops[dName] or 0) + dCount
|
randomDrops[dName] = (randomDrops[dName] or 0) + dCount
|
||||||
end
|
end
|
||||||
@ -48,14 +55,16 @@ local get_drops = function(item, def)
|
|||||||
return normalDrops, randomDrops
|
return normalDrops, randomDrops
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.build_item_list = function()
|
function cg.build_item_list()
|
||||||
local startTime = minetest.get_us_time()
|
local startTime = minetest.get_us_time()
|
||||||
cg.items_all.list = {}
|
cg.items_all.list = {}
|
||||||
|
|
||||||
for item, def in pairs(minetest.registered_items) do
|
for item, def in pairs(minetest.registered_items) do
|
||||||
if def.description and def.description ~= "" and
|
if def.description and def.description ~= ""
|
||||||
minetest.get_item_group(item, "not_in_creative_inventory") == 0 and
|
and minetest.get_item_group(item,
|
||||||
minetest.get_item_group(item, "not_in_craft_guide") == 0 then
|
"not_in_creative_inventory") == 0
|
||||||
|
and minetest.get_item_group(item,
|
||||||
|
"not_in_craft_guide") == 0 then
|
||||||
table.insert(cg.items_all.list, item)
|
table.insert(cg.items_all.list, item)
|
||||||
cg.crafts[item] = minetest.get_all_craft_recipes(item) or {}
|
cg.crafts[item] = minetest.get_all_craft_recipes(item) or {}
|
||||||
end
|
end
|
||||||
@ -66,7 +75,11 @@ cg.build_item_list = function()
|
|||||||
for _, item in ipairs(cg.items_all.list) do
|
for _, item in ipairs(cg.items_all.list) do
|
||||||
def = minetest.registered_items[item]
|
def = minetest.registered_items[item]
|
||||||
|
|
||||||
fuel, decremented = minetest.get_craft_result({method = "fuel", width = 0, items = {ItemStack(item)}})
|
fuel, decremented = minetest.get_craft_result({
|
||||||
|
method = "fuel",
|
||||||
|
width = 0,
|
||||||
|
items = {ItemStack(item)}
|
||||||
|
})
|
||||||
|
|
||||||
if fuel.time > 0 then
|
if fuel.time > 0 then
|
||||||
table.insert(cg.crafts[item], {
|
table.insert(cg.crafts[item], {
|
||||||
@ -86,7 +99,10 @@ cg.build_item_list = function()
|
|||||||
type = "digging",
|
type = "digging",
|
||||||
width = 0,
|
width = 0,
|
||||||
items = {item},
|
items = {item},
|
||||||
output = ItemStack({name = dItem, count = dCount}):to_string()
|
output = ItemStack({
|
||||||
|
name = dItem,
|
||||||
|
count = dCount
|
||||||
|
}):to_string()
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -97,7 +113,10 @@ cg.build_item_list = function()
|
|||||||
type = "digging_chance",
|
type = "digging_chance",
|
||||||
width = 0,
|
width = 0,
|
||||||
items = {item},
|
items = {item},
|
||||||
output = ItemStack({name = dItem, count = dCount}):to_string()
|
output = ItemStack({
|
||||||
|
name = dItem,
|
||||||
|
count = dCount
|
||||||
|
}):to_string()
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -113,23 +132,29 @@ cg.build_item_list = function()
|
|||||||
table.sort(cg.items_all.list)
|
table.sort(cg.items_all.list)
|
||||||
cg.items_all.num_pages = math.ceil(#cg.items_all.list / cg.PAGE_ITEMS)
|
cg.items_all.num_pages = math.ceil(#cg.items_all.list / cg.PAGE_ITEMS)
|
||||||
|
|
||||||
minetest.log("info", string.format("[cg_plus] Finished building item list in %.3f s.",
|
minetest.log("info",
|
||||||
(minetest.get_us_time() - startTime) / 1000000))
|
string.format(
|
||||||
|
"[cg_plus] Finished building item list in %.3f s.",
|
||||||
|
(minetest.get_us_time() - startTime) / 1000000
|
||||||
|
)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.filter_items = function(player, filter)
|
function cg.filter_items(player, filter)
|
||||||
local playerName = player:get_player_name()
|
local playerName = player:get_player_name()
|
||||||
|
local playerData = cg.player_data[playerName]
|
||||||
|
|
||||||
if not filter or filter == "" then
|
if not filter or filter == "" then
|
||||||
cg.items_filtered[playerName] = nil
|
playerData.items = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.items_filtered[playerName] = {list = {}}
|
playerData.items = {list = {}}
|
||||||
|
|
||||||
|
filter = filter:lower()
|
||||||
local groupFilter = string.sub(filter, 1, 6) == "group:" and filter:sub(7)
|
local groupFilter = string.sub(filter, 1, 6) == "group:" and filter:sub(7)
|
||||||
|
|
||||||
if groupFilter and cg.group_search then
|
if groupFilter and cg.GROUP_SEARCH then
|
||||||
-- Search by group
|
-- Search by group
|
||||||
local groups = string.split(groupFilter, ",")
|
local groups = string.split(groupFilter, ",")
|
||||||
local isInGroups
|
local isInGroups
|
||||||
@ -137,7 +162,7 @@ cg.filter_items = function(player, filter)
|
|||||||
for _, item in ipairs(cg.items_all.list) do
|
for _, item in ipairs(cg.items_all.list) do
|
||||||
isInGroups = true
|
isInGroups = true
|
||||||
|
|
||||||
for idx = 1, math.min(#groups, cg.group_search_max) do
|
for idx = 1, math.min(#groups, cg.GROUP_SEARCH_MAX) do
|
||||||
if minetest.get_item_group(item, groups[idx]) == 0 then
|
if minetest.get_item_group(item, groups[idx]) == 0 then
|
||||||
isInGroups = false
|
isInGroups = false
|
||||||
break
|
break
|
||||||
@ -145,23 +170,28 @@ cg.filter_items = function(player, filter)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if isInGroups then
|
if isInGroups then
|
||||||
table.insert(cg.items_filtered[playerName].list, item)
|
table.insert(playerData.items.list, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Regular search
|
-- Regular search
|
||||||
|
local langCode = playerData.lang_code
|
||||||
|
|
||||||
for _, item in ipairs(cg.items_all.list) do
|
for _, item in ipairs(cg.items_all.list) do
|
||||||
if item:lower():find(filter, 1, true) or
|
if item:lower():find(filter, 1, true)
|
||||||
minetest.registered_items[item].description:lower():find(filter, 1, true) then
|
or minetest.get_translated_string(langCode,
|
||||||
table.insert(cg.items_filtered[playerName].list, item)
|
minetest.registered_items[item].description)
|
||||||
|
:lower():find(filter, 1, true) then
|
||||||
|
table.insert(playerData.items.list, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.items_filtered[playerName].num_pages = math.ceil(#cg.get_item_list(player).list / cg.PAGE_ITEMS)
|
playerData.items.num_pages =
|
||||||
|
math.ceil(#cg.get_item_list(player).list / cg.PAGE_ITEMS)
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.parse_craft = function(craft)
|
function cg.parse_craft(craft)
|
||||||
local type = craft.type
|
local type = craft.type
|
||||||
local template = cg.craft_types[type] or {}
|
local template = cg.craft_types[type] or {}
|
||||||
|
|
||||||
@ -185,36 +215,50 @@ cg.parse_craft = function(craft)
|
|||||||
if template.get_grid_size then
|
if template.get_grid_size then
|
||||||
newCraft.grid_size = template.get_grid_size(craft)
|
newCraft.grid_size = template.get_grid_size(craft)
|
||||||
else
|
else
|
||||||
newCraft.grid_size = {x = width, y = math.ceil(table.maxn(craft.items) / width)}
|
newCraft.grid_size = {
|
||||||
|
x = width,
|
||||||
|
y = math.ceil(table.maxn(craft.items) / width)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
if template.inherit_width then
|
if template.inherit_width then
|
||||||
-- For shapeless recipes, there is no need to modify the item list.
|
-- For shapeless recipes, there is no need to modify the item list.
|
||||||
newCraft.items = craft.items
|
newCraft.items = craft.items
|
||||||
else
|
else
|
||||||
-- The craft's width is not always the same as the grid size, so items need to be shifted around.
|
-- The craft's width is not always the same as the grid size, so items
|
||||||
|
-- need to be shifted around.
|
||||||
for idx, item in pairs(craft.items) do
|
for idx, item in pairs(craft.items) do
|
||||||
newCraft.items[idx + (newCraft.grid_size.x - width) * math.floor((idx - 1) / width)] = item
|
newCraft.items[idx + (newCraft.grid_size.x - width) *
|
||||||
|
math.floor((idx - 1) / width)] = item
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return newCraft
|
return newCraft
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.get_item_list = function(player)
|
function cg.get_item_list(player)
|
||||||
return cg.items_filtered[player:get_player_name()] or cg.items_all
|
return cg.player_data[player:get_player_name()].items or cg.items_all
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.register_craft_type = function(name, def)
|
function cg.register_craft_type(name, def)
|
||||||
cg.craft_types[name] = def
|
cg.craft_types[name] = def
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.register_group_stereotype = function(group, item)
|
function cg.register_group_stereotype(group, item)
|
||||||
cg.group_stereotypes[group] = item
|
cg.group_stereotypes[group] = item
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_mods_loaded(cg.build_item_list)
|
minetest.register_on_mods_loaded(cg.build_item_list)
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player, timed_out)
|
minetest.register_on_joinplayer(function(player)
|
||||||
cg.items_filtered[player:get_player_name()] = nil
|
local playerName = player:get_player_name()
|
||||||
|
local langCode = minetest.get_player_information(playerName).lang_code
|
||||||
|
|
||||||
|
cg.player_data[playerName] = {
|
||||||
|
lang_code = langCode
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player, timed_out)
|
||||||
|
cg.player_data[player:get_player_name()] = nil
|
||||||
end)
|
end)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
local add_or_create = function(t, i, n)
|
local function add_or_create(t, i, n)
|
||||||
t[i] = t[i] and t[i] + n or n
|
t[i] = t[i] and t[i] + n or n
|
||||||
end
|
end
|
||||||
|
|
||||||
local get_group_item = function(invCache, groups)
|
local function get_group_item(invCache, groups)
|
||||||
local maxCount = 0
|
local maxCount = 0
|
||||||
local maxItem
|
local maxItem
|
||||||
local isInGroups
|
local isInGroups
|
||||||
@ -26,11 +26,12 @@ local get_group_item = function(invCache, groups)
|
|||||||
return maxItem
|
return maxItem
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.auto_get_craftable = function(player, craft)
|
function cg.auto_get_craftable(player, craft)
|
||||||
local inv = player:get_inventory():get_list("main")
|
local inv = player:get_inventory():get_list("main")
|
||||||
local invCache = {}
|
local invCache = {}
|
||||||
|
|
||||||
-- Create a cache of the inventory with itemName = count pairs. This speeds up searching for items.
|
-- Create a cache of the inventory with itemName = count pairs.
|
||||||
|
-- This speeds up searching for items.
|
||||||
for _, stack in ipairs(inv) do
|
for _, stack in ipairs(inv) do
|
||||||
if stack:get_count() > 0 then
|
if stack:get_count() > 0 then
|
||||||
add_or_create(invCache, stack:get_name(), stack:get_count())
|
add_or_create(invCache, stack:get_name(), stack:get_count())
|
||||||
@ -51,7 +52,8 @@ cg.auto_get_craftable = function(player, craft)
|
|||||||
|
|
||||||
local gMaxItem
|
local gMaxItem
|
||||||
|
|
||||||
-- For each group, find the item in that group from the player's inventory with the largest count.
|
-- For each group, find the item in that group from the player's inventory
|
||||||
|
-- with the largest count.
|
||||||
for group, count in pairs(reqGroups) do
|
for group, count in pairs(reqGroups) do
|
||||||
gMaxItem = get_group_item(invCache, group:sub(7):split(","))
|
gMaxItem = get_group_item(invCache, group:sub(7):split(","))
|
||||||
|
|
||||||
@ -73,15 +75,16 @@ cg.auto_get_craftable = function(player, craft)
|
|||||||
|
|
||||||
-- We can't craft more than the stack_max of our ingredients.
|
-- We can't craft more than the stack_max of our ingredients.
|
||||||
if minetest.registered_items[item].stack_max then
|
if minetest.registered_items[item].stack_max then
|
||||||
craftable = math.min(craftable, minetest.registered_items[item].stack_max)
|
craftable = math.min(craftable,
|
||||||
|
minetest.registered_items[item].stack_max)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return craftable
|
return craftable
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.auto_craft = function(player, craft, num)
|
function cg.auto_craft(player, craft, num)
|
||||||
inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
|
||||||
if not inv:is_empty("craft") then
|
if not inv:is_empty("craft") then
|
||||||
-- Attempt to move items to the player's main inventory.
|
-- Attempt to move items to the player's main inventory.
|
||||||
@ -94,12 +97,16 @@ cg.auto_craft = function(player, craft, num)
|
|||||||
|
|
||||||
-- Check again, and return if not all items were moved.
|
-- Check again, and return if not all items were moved.
|
||||||
if not inv:is_empty("craft") then
|
if not inv:is_empty("craft") then
|
||||||
minetest.chat_send_player(player:get_player_name(), cg.S("Item could not be crafted!"))
|
minetest.chat_send_player(player:get_player_name(),
|
||||||
|
cg.S("Item could not be crafted!"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if craft.width > inv:get_width("craft") or table.maxn(craft.items) > inv:get_size("craft") then return end
|
if craft.width > inv:get_width("craft")
|
||||||
|
or table.maxn(craft.items) > inv:get_size("craft") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local invList = inv:get_list("main")
|
local invList = inv:get_list("main")
|
||||||
local width = craft.width == 0 and inv:get_width("craft") or craft.width
|
local width = craft.width == 0 and inv:get_width("craft") or craft.width
|
||||||
@ -107,8 +114,10 @@ cg.auto_craft = function(player, craft, num)
|
|||||||
local groupCache = {}
|
local groupCache = {}
|
||||||
|
|
||||||
for idx, item in pairs(craft.items) do
|
for idx, item in pairs(craft.items) do
|
||||||
-- Shift the indices so the items in the craft go to the right spots on the crafting grid.
|
-- Shift the indices so the items in the craft go to the right spots on
|
||||||
idx = idx + (inv:get_width("craft") - width) * math.floor((idx - 1) / width)
|
-- the crafting grid.
|
||||||
|
idx = (idx + (inv:get_width("craft") - width) *
|
||||||
|
math.floor((idx - 1) / width))
|
||||||
|
|
||||||
if item:sub(1, 6) == "group:" then
|
if item:sub(1, 6) == "group:" then
|
||||||
-- Create an inventory cache.
|
-- Create an inventory cache.
|
||||||
@ -117,32 +126,37 @@ cg.auto_craft = function(player, craft, num)
|
|||||||
|
|
||||||
for _, stack in ipairs(invList) do
|
for _, stack in ipairs(invList) do
|
||||||
if stack:get_count() > 0 then
|
if stack:get_count() > 0 then
|
||||||
add_or_create(invCache, stack:get_name(), stack:get_count())
|
add_or_create(invCache, stack:get_name(),
|
||||||
|
stack:get_count())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the most plentiful item in the group.
|
-- Get the most plentiful item in the group.
|
||||||
if not groupCache[item] then
|
if not groupCache[item] then
|
||||||
groupCache[item] = get_group_item(invCache, item:sub(7):split(","))
|
groupCache[item] = get_group_item(invCache,
|
||||||
|
item:sub(7):split(","))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Move the selected item.
|
-- Move the selected item.
|
||||||
if groupCache[item] then
|
if groupCache[item] then
|
||||||
stack = inv:remove_item("main", ItemStack({name = groupCache[item], count = num}))
|
stack = inv:remove_item("main",
|
||||||
|
ItemStack({name = groupCache[item], count = num}))
|
||||||
inv:set_stack("craft", idx, stack)
|
inv:set_stack("craft", idx, stack)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Move the item.
|
-- Move the item.
|
||||||
stack = inv:remove_item("main", ItemStack({name = item, count = num}))
|
stack = inv:remove_item("main",
|
||||||
|
ItemStack({name = item, count = num}))
|
||||||
inv:set_stack("craft", idx, stack)
|
inv:set_stack("craft", idx, stack)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
minetest.register_on_player_inventory_action(
|
||||||
|
function(player, action, inventory, inventory_info)
|
||||||
-- Hide the autocrafting menu when the player drops an item.
|
-- Hide the autocrafting menu when the player drops an item.
|
||||||
if cg.autocrafting and inventory_info.listname == "main" then
|
if cg.AUTOCRAFTING and inventory_info.listname == "main" then
|
||||||
local context = sfinv.get_or_create_context(player)
|
local context = sfinv.get_or_create_context(player)
|
||||||
|
|
||||||
if context.cg_auto_menu then
|
if context.cg_auto_menu then
|
||||||
@ -150,4 +164,5 @@ minetest.register_on_player_inventory_action(function(player, action, inventory,
|
|||||||
sfinv.set_player_inventory_formspec(player)
|
sfinv.set_player_inventory_formspec(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
42
init.lua
@ -1,8 +1,8 @@
|
|||||||
cg = {
|
cg = {
|
||||||
PAGE_WIDTH = 8,
|
PAGE_WIDTH = 8,
|
||||||
PAGE_ITEMS = 24,
|
PAGE_ITEMS = 32,
|
||||||
items_all = {},
|
items_all = {},
|
||||||
items_filtered = {},
|
player_data = {},
|
||||||
crafts = {},
|
crafts = {},
|
||||||
craft_types = {},
|
craft_types = {},
|
||||||
group_stereotypes = {},
|
group_stereotypes = {},
|
||||||
@ -10,18 +10,17 @@ cg = {
|
|||||||
|
|
||||||
local settings = minetest.settings
|
local settings = minetest.settings
|
||||||
|
|
||||||
cg.autocrafting = settings:get_bool("cg_plus_autocrafting", true)
|
cg.AUTOCRAFTING = settings:get_bool("cg_plus_autocrafting", true)
|
||||||
cg.group_search = settings:get_bool("cg_plus_group_search", true)
|
cg.GROUP_SEARCH = settings:get_bool("cg_plus_group_search", true)
|
||||||
cg.group_search_max = tonumber(settings:get("cg_plus_group_search_max")) or 5
|
cg.GROUP_SEARCH_MAX = tonumber(settings:get("cg_plus_group_search_max")) or 5
|
||||||
|
|
||||||
cg.S = minetest.get_translator("cg_plus")
|
cg.S = minetest.get_translator("cg_plus")
|
||||||
local F = minetest.formspec_escape
|
local F = minetest.formspec_escape
|
||||||
|
|
||||||
local path = minetest.get_modpath("cg_plus")
|
local path = minetest.get_modpath("cg_plus")
|
||||||
|
|
||||||
dofile(path .. "/api.lua")
|
dofile(path .. "/api.lua")
|
||||||
|
|
||||||
if cg.autocrafting then
|
if cg.AUTOCRAFTING then
|
||||||
dofile(path .. "/autocrafting.lua")
|
dofile(path .. "/autocrafting.lua")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ cg.register_craft_type("normal", {
|
|||||||
else
|
else
|
||||||
return {x = sideLen, y = sideLen}
|
return {x = sideLen, y = sideLen}
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_craft_type("shapeless", {
|
cg.register_craft_type("shapeless", {
|
||||||
@ -59,58 +58,61 @@ cg.register_craft_type("shapeless", {
|
|||||||
local sideLen = math.ceil(math.sqrt(numItems))
|
local sideLen = math.ceil(math.sqrt(numItems))
|
||||||
return {x = sideLen, y = sideLen}
|
return {x = sideLen, y = sideLen}
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_craft_type("cooking", {
|
cg.register_craft_type("cooking", {
|
||||||
description = F(cg.S("Cooking")),
|
description = F(cg.S("Cooking")),
|
||||||
inherit_width = true,
|
inherit_width = true,
|
||||||
arrow_icon = "cg_plus_arrow_small.png^cg_plus_icon_cooking.png",
|
arrow_icon = "cg_plus_arrow_bottom.png^cg_plus_icon_cooking.png",
|
||||||
|
|
||||||
get_grid_size = function(craft)
|
get_grid_size = function(craft)
|
||||||
return {x = 1, y = 1}
|
return {x = 1, y = 1}
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_infotext = function(craft)
|
get_infotext = function(craft)
|
||||||
return minetest.colorize("#FFFF00", F(cg.S("Time: @1 s", craft.width or 0)))
|
return minetest.colorize("#FFFF00",
|
||||||
end,
|
F(cg.S("Time: @1 s", craft.width or 0)))
|
||||||
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_craft_type("fuel", {
|
cg.register_craft_type("fuel", {
|
||||||
description = F(cg.S("Fuel")),
|
description = F(cg.S("Fuel")),
|
||||||
inherit_width = true,
|
inherit_width = true,
|
||||||
arrow_icon = "cg_plus_arrow_small.png^cg_plus_icon_fuel.png",
|
arrow_icon = "cg_plus_arrow_bottom.png^cg_plus_icon_fuel.png",
|
||||||
|
|
||||||
get_grid_size = function(craft)
|
get_grid_size = function(craft)
|
||||||
return {x = 1, y = 1}
|
return {x = 1, y = 1}
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_infotext = function(craft)
|
get_infotext = function(craft)
|
||||||
return minetest.colorize("#FFFF00", F(cg.S("Time: @1 s", craft.time or 0)))
|
return minetest.colorize("#FFFF00",
|
||||||
end,
|
F(cg.S("Time: @1 s", craft.time or 0)))
|
||||||
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_craft_type("digging", {
|
cg.register_craft_type("digging", {
|
||||||
description = F(cg.S("Digging")),
|
description = F(cg.S("Digging")),
|
||||||
inherit_width = true,
|
inherit_width = true,
|
||||||
arrow_icon = "cg_plus_arrow_small.png^cg_plus_icon_digging.png",
|
arrow_icon = "cg_plus_arrow_bottom.png^cg_plus_icon_digging.png",
|
||||||
|
|
||||||
get_grid_size = function(craft)
|
get_grid_size = function(craft)
|
||||||
return {x = 1, y = 1}
|
return {x = 1, y = 1}
|
||||||
end,
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_craft_type("digging_chance", {
|
cg.register_craft_type("digging_chance", {
|
||||||
description = F(cg.S("Digging@n(by chance)")),
|
description = F(cg.S("Digging@n(by chance)")),
|
||||||
inherit_width = true,
|
inherit_width = true,
|
||||||
arrow_icon = "cg_plus_arrow_small.png^cg_plus_icon_digging.png",
|
arrow_icon = "cg_plus_arrow_bottom.png^cg_plus_icon_digging.png",
|
||||||
|
|
||||||
get_grid_size = function(craft)
|
get_grid_size = function(craft)
|
||||||
return {x = 1, y = 1}
|
return {x = 1, y = 1}
|
||||||
end,
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
cg.register_group_stereotype("mesecon_conductor_craftable", "mesecons:wire_00000000_off")
|
cg.register_group_stereotype("mesecon_conductor_craftable",
|
||||||
|
"mesecons:wire_00000000_off")
|
||||||
|
|
||||||
if minetest.get_modpath("default") then
|
if minetest.get_modpath("default") then
|
||||||
cg.register_group_stereotype("stone", "default:stone")
|
cg.register_group_stereotype("stone", "default:stone")
|
||||||
|
276
inventory.lua
@ -1,33 +1,41 @@
|
|||||||
local F = minetest.formspec_escape
|
local F = minetest.formspec_escape
|
||||||
|
|
||||||
cg.update_filter = function(player, context, filter, force)
|
function cg.update_filter(player, context, filter, force)
|
||||||
if not force and (filter or "") == context.cg_filter then return end
|
filter = filter or ""
|
||||||
|
if not force and filter:lower() == (context.cg_filter or ""):lower() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
context.cg_page = 0
|
context.cg_page = 0
|
||||||
context.cg_filter = filter or ""
|
context.cg_filter = filter
|
||||||
cg.filter_items(player, context.cg_filter)
|
cg.filter_items(player, context.cg_filter)
|
||||||
end
|
end
|
||||||
|
|
||||||
cg.update_selected_item = function(player, context, item, force)
|
function cg.update_selected_item(player, context, item, force)
|
||||||
if not force and item == context.cg_selected_item then return end
|
if not force and item == context.cg_selected_item then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if item then context.cg_craft_page = 0 end
|
if item then
|
||||||
|
context.cg_craft_page = 0
|
||||||
|
end
|
||||||
|
|
||||||
context.cg_selected_item = item
|
context.cg_selected_item = item
|
||||||
context.cg_auto_menu = false
|
context.cg_auto_menu = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local make_item_button = function(formspec, x, y, size, name)
|
local function make_item_button(formspec, x, y, size, name)
|
||||||
if name and name ~= "" then
|
if name and name ~= "" then
|
||||||
local groups, buttonText
|
local groups, buttonText
|
||||||
|
|
||||||
if name:sub(1, 6) == "group:" then
|
if name:sub(1, 6) == "group:" then
|
||||||
groups = name:sub(7):split(",")
|
groups = name:sub(7):split(",")
|
||||||
buttonText = #groups > 1 and ("G " .. #groups) or "G"
|
buttonText = #groups == 1 and "G" or ("G " .. #groups)
|
||||||
name = name:gsub(",", "/")
|
name = name:gsub(",", "/")
|
||||||
end
|
end
|
||||||
|
|
||||||
formspec[#formspec + 1] = string.format("item_image_button[%.2f,%.2f;%.2f,%.2f;%s;cgitem_%s;%s]",
|
formspec[#formspec + 1] = string.format(
|
||||||
|
"item_image_button[%.2f,%.2f;%.2f,%.2f;%s;cgitem_%s;%s]",
|
||||||
x, y, size, size,
|
x, y, size, size,
|
||||||
groups and (cg.group_stereotypes[groups[1]] or "") or name,
|
groups and (cg.group_stereotypes[groups[1]] or "") or name,
|
||||||
name:match("^%S+"), -- Keep only the item name, not the quantity.
|
name:match("^%S+"), -- Keep only the item name, not the quantity.
|
||||||
@ -35,35 +43,52 @@ local make_item_button = function(formspec, x, y, size, name)
|
|||||||
)
|
)
|
||||||
|
|
||||||
if groups then
|
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]",
|
formspec[#formspec + 1] = string.format("tooltip[cgitem_%s;%s]",
|
||||||
name,
|
name, tooltipText)
|
||||||
#groups > 1 and
|
|
||||||
F(cg.S("Any item in groups: @1", minetest.colorize("#72FF63", table.concat(groups, ", ")))) or
|
|
||||||
F(cg.S("Any item in group: @1", minetest.colorize("#72FF63", groups[1])))
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
size = size * 0.8 + 0.2
|
formspec[#formspec + 1] = string.format(
|
||||||
formspec[#formspec + 1] = string.format("image[%.2f,%.2f;%.2f,%.2f;gui_hb_bg.png]", x, y, size, size)
|
"image[%.2f,%.2f;%.2f,%.2f;gui_hb_bg.png]",
|
||||||
|
x, y, size, size
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local make_item_grid = function(formspec, player, context)
|
local function make_item_grid(formspec, player, context)
|
||||||
local itemList = cg.get_item_list(player)
|
local itemList = cg.get_item_list(player)
|
||||||
context.cg_page = context.cg_page or 0
|
context.cg_page = context.cg_page or 0
|
||||||
|
|
||||||
formspec[#formspec + 1] = [[
|
-- Buttons
|
||||||
image_button[2.4,3.7;0.8,0.8;cg_plus_icon_search.png;cg_search;]
|
formspec[#formspec + 1] =
|
||||||
image_button[3.1,3.7;0.8,0.8;cg_plus_icon_clear.png;cg_clear;]
|
"real_coordinates[true]" ..
|
||||||
image_button[5.1,3.7;0.8,0.8;cg_plus_icon_prev.png;cg_prev;]
|
"image_button[3.425,5.3;0.8,0.8;cg_plus_icon_search.png;cg_search;]" ..
|
||||||
image_button[7.1,3.7;0.8,0.8;cg_plus_icon_next.png;cg_next;]
|
"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;]"
|
||||||
|
|
||||||
formspec[#formspec + 1] = string.format("label[0,0;%s]", F(cg.S("Crafting Guide")))
|
-- Search box
|
||||||
|
formspec[#formspec + 1] = string.format(
|
||||||
formspec[#formspec + 1] = string.format("field[0.3,3.9;2.5,1;cg_filter;;%s]", F(context.cg_filter or ""))
|
"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]"
|
formspec[#formspec + 1] = "field_close_on_enter[cg_filter;false]"
|
||||||
formspec[#formspec + 1] = string.format("label[6,3.8;%i / %i]", context.cg_page + 1, itemList.num_pages)
|
|
||||||
|
-- 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 startIdx = context.cg_page * cg.PAGE_ITEMS + 1
|
||||||
local item
|
local item
|
||||||
@ -72,64 +97,86 @@ local make_item_grid = function(formspec, player, context)
|
|||||||
item = itemList.list[startIdx + itemIdx]
|
item = itemList.list[startIdx + itemIdx]
|
||||||
|
|
||||||
if item then
|
if item then
|
||||||
formspec[#formspec + 1] = string.format("item_image_button[%.2f,%.2f;1,1;%s;cgitem_%s;]",
|
formspec[#formspec + 1] = string.format(
|
||||||
itemIdx % cg.PAGE_WIDTH,
|
"item_image_button[%.2f,%.2f;1,1;%s;cgitem_%s;]",
|
||||||
math.floor(itemIdx / cg.PAGE_WIDTH) + 0.5,
|
(itemIdx % cg.PAGE_WIDTH) * 1.25 + 0.375,
|
||||||
|
math.floor(itemIdx / cg.PAGE_WIDTH) * 1.25 + 0.375,
|
||||||
item, item
|
item, item
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local make_craft_preview = function(formspec, player, context)
|
local function make_craft_preview(formspec, player, context)
|
||||||
formspec[#formspec + 1] = [[
|
formspec[#formspec + 1] =
|
||||||
image_button[7.1,0.1;0.8,0.8;cg_plus_icon_prev.png;cg_craft_close;]
|
"real_coordinates[true]" ..
|
||||||
image[0.1,0.1;0.8,0.8;gui_hb_bg.png]
|
"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
|
local item = context.cg_selected_item
|
||||||
|
|
||||||
formspec[#formspec + 1] = string.format("item_image[0.1,0.1;0.8,0.8;%s]", item)
|
-- Item image
|
||||||
formspec[#formspec + 1] = string.format("label[1,0;%s]",
|
formspec[#formspec + 1] = string.format(
|
||||||
cg.crafts[item] and minetest.registered_items[item].description or item)
|
"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]
|
local crafts = cg.crafts[item]
|
||||||
|
|
||||||
if not crafts or #crafts == 0 then
|
if not crafts or #crafts == 0 then
|
||||||
formspec[#formspec + 1] = string.format("label[1,0.5;%s]", F(cg.S("There are no recipes for this item.")))
|
formspec[#formspec + 1] = string.format("label[2.875,3.2;%s]",
|
||||||
|
F(cg.S("There are no recipes for this item.")))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Previous/next craft buttons, page number
|
||||||
if #crafts > 1 then
|
if #crafts > 1 then
|
||||||
formspec[#formspec + 1] = [[
|
formspec[#formspec + 1] =
|
||||||
image_button[1.85,3.7;0.8,0.8;cg_plus_icon_prev.png;cg_craft_prev;]
|
"image_button[2.875,5.3;0.8,0.8;" ..
|
||||||
image_button[3.85,3.7;0.8,0.8;cg_plus_icon_next.png;cg_craft_next;]
|
"cg_plus_icon_prev.png;cg_craft_prev;]" ..
|
||||||
]]
|
"image_button[5.575,5.3;0.8,0.8;" ..
|
||||||
formspec[#formspec + 1] = string.format("label[2.75,3.8;%i / %i]", context.cg_craft_page + 1, #crafts)
|
"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
|
end
|
||||||
|
|
||||||
local craft = cg.parse_craft(crafts[context.cg_craft_page + 1])
|
local craft = cg.parse_craft(crafts[context.cg_craft_page + 1])
|
||||||
local template = cg.craft_types[craft.type] or {}
|
local template = cg.craft_types[craft.type] or {}
|
||||||
|
|
||||||
if cg.autocrafting and template.uses_crafting_grid then
|
-- Auto-crafting buttons
|
||||||
formspec[#formspec + 1] = "image_button[0.1,3.7;0.8,0.8;cg_plus_icon_autocrafting.png;cg_auto_menu;]"
|
if cg.AUTOCRAFTING and template.uses_crafting_grid then
|
||||||
formspec[#formspec + 1] = string.format("tooltip[cg_auto_menu;%s]", F(cg.S("Craft this recipe")))
|
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
|
if context.cg_auto_menu then
|
||||||
local num = 1
|
local num = 1
|
||||||
local yPos = 3
|
local yPos = 4.3
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
num = math.min(num, context.cg_auto_max)
|
num = math.min(num, context.cg_auto_max)
|
||||||
formspec[#formspec + 1] = string.format("button[0.1,%.2f;0.8,0.8;cg_auto_%i;%i]", yPos, num, num)
|
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(
|
formspec[#formspec + 1] = string.format(
|
||||||
"tooltip[cg_auto_%i;%s]",
|
"tooltip[cg_auto_%i;%s]",
|
||||||
num,
|
num,
|
||||||
num == 1 and F(cg.S("Craft @1 item", num)) or F(cg.S("Craft @1 items", 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
|
if num < context.cg_auto_max then
|
||||||
num = num * 10
|
num = num * 10
|
||||||
yPos = yPos - 0.7
|
yPos = yPos - 1
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@ -137,40 +184,52 @@ local make_craft_preview = function(formspec, player, context)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
formspec[#formspec + 1] = string.format("label[5,0.5;%s]", template.description or "")
|
-- Craft type/info text
|
||||||
formspec[#formspec + 1] = string.format("label[5,1;%s]", craft.infotext or "")
|
formspec[#formspec + 1] = string.format("label[6.7,1.8;%s]",
|
||||||
formspec[#formspec + 1] = string.format("image[4.75,1.5;1,1;%s]",
|
template.description or "")
|
||||||
template.arrow_icon or "cg_plus_arrow.png")
|
formspec[#formspec + 1] = string.format("label[6.7,2.4;%s]",
|
||||||
|
craft.infotext or "")
|
||||||
|
|
||||||
local slotSize = math.min(3 / math.max(craft.grid_size.x, craft.grid_size.y), 1)
|
-- Draw craft item grid, feat. maths.
|
||||||
local xOffset = 4.75 - craft.grid_size.x * slotSize
|
|
||||||
local yOffset = 2 - craft.grid_size.y * slotSize * 0.5
|
-- 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
|
for idx = 1, craft.grid_size.x * craft.grid_size.y do
|
||||||
make_item_button(formspec,
|
make_item_button(
|
||||||
(idx - 1) % craft.grid_size.x * slotSize + xOffset,
|
formspec,
|
||||||
math.floor((idx - 1) / craft.grid_size.y) * slotSize + yOffset,
|
((idx - 1) % craft.grid_size.x) * slotDist + xOffset,
|
||||||
slotSize,
|
math.floor((idx - 1) / craft.grid_size.y) * slotDist + yOffset,
|
||||||
|
slotDist * 0.8, -- 1 - <padding amount>
|
||||||
craft.items[idx]
|
craft.items[idx]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
make_item_button(formspec, 5.75, 1.5, 1, craft.output)
|
-- 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
|
end
|
||||||
|
|
||||||
sfinv.register_page("cg_plus:crafting_guide", {
|
--[[
|
||||||
title = "Crafting Guide",
|
sfinv registration
|
||||||
get = function(self, player, context)
|
]]
|
||||||
local formspec = {[[
|
|
||||||
image[0,4.75;1,1;gui_hb_bg.png]
|
local function page_get(self, player, context)
|
||||||
image[1,4.75;1,1;gui_hb_bg.png]
|
local formspec = {}
|
||||||
image[2,4.75;1,1;gui_hb_bg.png]
|
|
||||||
image[3,4.75;1,1;gui_hb_bg.png]
|
|
||||||
image[4,4.75;1,1;gui_hb_bg.png]
|
|
||||||
image[5,4.75;1,1;gui_hb_bg.png]
|
|
||||||
image[6,4.75;1,1;gui_hb_bg.png]
|
|
||||||
image[7,4.75;1,1;gui_hb_bg.png]
|
|
||||||
]]}
|
|
||||||
|
|
||||||
if context.cg_selected_item then
|
if context.cg_selected_item then
|
||||||
make_craft_preview(formspec, player, context)
|
make_craft_preview(formspec, player, context)
|
||||||
@ -179,9 +238,9 @@ sfinv.register_page("cg_plus:crafting_guide", {
|
|||||||
end
|
end
|
||||||
|
|
||||||
return sfinv.make_formspec(player, context, table.concat(formspec), true)
|
return sfinv.make_formspec(player, context, table.concat(formspec), true)
|
||||||
end,
|
end
|
||||||
|
|
||||||
on_player_receive_fields = function(self, player, context, fields)
|
local function page_on_player_receive_fields(self, player, context, fields)
|
||||||
if fields.cg_craft_close then
|
if fields.cg_craft_close then
|
||||||
context.cg_selected_item = nil
|
context.cg_selected_item = nil
|
||||||
context.cg_auto_menu = false
|
context.cg_auto_menu = false
|
||||||
@ -199,13 +258,15 @@ sfinv.register_page("cg_plus:crafting_guide", {
|
|||||||
cg.update_filter(player, context, fields.cg_filter)
|
cg.update_filter(player, context, fields.cg_filter)
|
||||||
elseif fields.cg_clear then
|
elseif fields.cg_clear then
|
||||||
cg.update_filter(player, context, "", true)
|
cg.update_filter(player, context, "", true)
|
||||||
elseif fields.cg_auto_menu and cg.autocrafting then
|
elseif fields.cg_auto_menu and cg.AUTOCRAFTING then
|
||||||
if not context.cg_auto_menu then
|
if not context.cg_auto_menu then
|
||||||
-- Make sure the craft is valid, in case the client is sending fake formspec fields.
|
-- 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 crafts = cg.crafts[context.cg_selected_item] or {}
|
||||||
local craft = crafts[context.cg_craft_page + 1]
|
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
|
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_menu = true
|
||||||
context.cg_auto_max = cg.auto_get_craftable(player, craft)
|
context.cg_auto_max = cg.auto_get_craftable(player, craft)
|
||||||
end
|
end
|
||||||
@ -218,23 +279,31 @@ sfinv.register_page("cg_plus:crafting_guide", {
|
|||||||
local item = string.sub(field, 8)
|
local item = string.sub(field, 8)
|
||||||
|
|
||||||
if item:sub(1, 6) == "group:" then
|
if item:sub(1, 6) == "group:" then
|
||||||
if cg.group_search then
|
if cg.GROUP_SEARCH then
|
||||||
cg.update_filter(player, context, item:gsub("/", ","))
|
cg.update_filter(player, context, item)
|
||||||
cg.update_selected_item(player, context, nil)
|
cg.update_selected_item(player, context, nil)
|
||||||
elseif cg.group_stereotypes[item:sub(7)] then
|
elseif cg.group_stereotypes[item:sub(7)] then
|
||||||
cg.update_selected_item(player, context, cg.group_stereotypes[item:sub(7)])
|
cg.update_selected_item(player, context,
|
||||||
|
cg.group_stereotypes[item:sub(7)])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cg.update_selected_item(player, context, item)
|
cg.update_selected_item(player, context, item)
|
||||||
end
|
end
|
||||||
|
|
||||||
break
|
break
|
||||||
elseif field:sub(1, 8) == "cg_auto_" and context.cg_auto_menu then
|
elseif field:sub(1, 8) == "cg_auto_"
|
||||||
-- No need to sanity check, we already did that when showing the autocrafting menu.
|
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))
|
local num = tonumber(field:sub(9))
|
||||||
|
|
||||||
if num > 0 and num <= context.cg_auto_max then
|
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)
|
cg.auto_craft(
|
||||||
|
player,
|
||||||
|
cg.crafts[context.cg_selected_item]
|
||||||
|
[context.cg_craft_page + 1],
|
||||||
|
num
|
||||||
|
)
|
||||||
sfinv.set_page(player, "sfinv:crafting")
|
sfinv.set_page(player, "sfinv:crafting")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -244,20 +313,39 @@ sfinv.register_page("cg_plus:crafting_guide", {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Wrap around when the player presses the next button on the last page, or the previous button on the first.
|
-- 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
|
if context.cg_page then
|
||||||
context.cg_page = context.cg_page % math.max(cg.get_item_list(player).num_pages, 1)
|
context.cg_page = context.cg_page %
|
||||||
|
math.max(cg.get_item_list(player).num_pages, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
if context.cg_craft_page then
|
if context.cg_craft_page then
|
||||||
context.cg_craft_page = context.cg_craft_page % math.max(#(cg.crafts[context.cg_selected_item] or {}), 1)
|
context.cg_craft_page = context.cg_craft_page %
|
||||||
|
math.max(#(cg.crafts[context.cg_selected_item] or {}), 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update the formspec.
|
-- Update the formspec.
|
||||||
sfinv.set_player_inventory_formspec(player, context)
|
sfinv.set_player_inventory_formspec(player, context)
|
||||||
end,
|
end
|
||||||
|
|
||||||
on_leave = function(self, player, context)
|
local function page_on_leave(self, player, context)
|
||||||
context.cg_auto_menu = false
|
context.cg_auto_menu = false
|
||||||
end,
|
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
|
||||||
|
16
locale/template.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# textdomain:cg_plus
|
||||||
|
|
||||||
|
Crafting=
|
||||||
|
Mixing=
|
||||||
|
Cooking=
|
||||||
|
Fuel=
|
||||||
|
Time: @1 s=
|
||||||
|
Digging=
|
||||||
|
Digging@n(by chance)=
|
||||||
|
Crafting Guide=
|
||||||
|
Item could not be crafted!=
|
||||||
|
Any item in group: @1=
|
||||||
|
Any item in groups: @1=
|
||||||
|
Craft @1 item=
|
||||||
|
Craft @1 items=
|
||||||
|
There are no recipes for this item.=
|
1
mod.conf
@ -1,3 +1,4 @@
|
|||||||
name = cg_plus
|
name = cg_plus
|
||||||
description = An intuitive and full-featured craft guide and autocrafting mod which is compatible with sfinv.
|
description = An intuitive and full-featured craft guide and autocrafting mod which is compatible with sfinv.
|
||||||
depends = sfinv
|
depends = sfinv
|
||||||
|
optional_depends = mtg_craftguide
|
||||||
|
BIN
textures/cg_plus_arrow_bottom.png
Normal file
After Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 170 B |
Before Width: | Height: | Size: 708 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 772 B |
Before Width: | Height: | Size: 223 B After Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 581 B After Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 167 B |