crafting: rework of crafting prediction as grid lookup

This commit is contained in:
Alexander Weber 2017-04-30 01:25:29 +02:00
parent f7c87eebc5
commit 4f56841aad
2 changed files with 133 additions and 21 deletions

View File

@ -172,6 +172,74 @@ function crecipe_class:get_with_placeholder(player, inventory_tab)
return recipe
end
-----------------------------------------------------
-- crecipes: Check if recipe contains only items provided in reference_items
-----------------------------------------------------
function crecipe_class:is_craftable_by_items(reference_items)
local item_ok = false
for _, entry in pairs(self._items) do
item_ok = false
for _, itemdef in pairs(entry.items) do
if reference_items[itemdef.name] then
item_ok = true
end
end
if item_ok == false then
break
end
end
return item_ok
end
-----------------------------------------------------
-- crecipes: Check if the items placed in grid matches the recipe
-----------------------------------------------------
function crecipe_class:check_craftable_by_grid(grid)
-- only "normal" recipes supported
if self.recipe_type ~= "normal" then
return false
end
for i = 1, 9 do
local grid_item = grid[i]:get_name()
-- check only fields filled in crafting grid
if grid_item and grid_item ~= "" then
-- check if item defined in recipe at this place
local item_ok = false
local recipe_item
-- default case - 3x3 crafting grid
local width = self._recipe.width
if not width or width == 0 or width == 3 then
recipe_item = self._recipe.items[i]
else
-- complex case - recalculate to the 3x3 crafting grid
local x = math.fmod(i,3)
if x <= width then
local y = math.floor((i-1)/3+1)
local coord = (y-1)*width+x
recipe_item = self._recipe.items[coord]
end
end
if not recipe_item or recipe_item == "" then
return false
end
-- check if it is a compatible item
for _, itemdef in pairs(self._items[recipe_item].items) do
if itemdef.name == grid_item then
item_ok = true
break
end
end
if not item_ok then
return false
end
end
end
return true
end
-----------------------------------------------------
-- Recipe class functions
-----------------------------------------------------
@ -190,7 +258,6 @@ function crecipes.new(recipe)
def._items = {}
setmetatable(def, crecipe_class)
def.__index = crecipe_class
print(dump(def))
return def
end
@ -219,25 +286,26 @@ function crecipes.get_recipes_craftable(playername, reference_items)
local all = crecipes.get_revealed_recipes_with_items(playername, reference_items)
local craftable = {}
for recipe, crecipe in pairs(all) do
local item_ok = false
for _, entry in pairs(crecipe._items) do
item_ok = false
for _, itemdef in pairs(entry.items) do
if reference_items[itemdef.name] then
item_ok = true
end
end
if item_ok == false then
break
end
end
if item_ok == true then
craftable[recipe] = true
if crecipe:is_craftable_by_items(reference_items) then
craftable[recipe] = crecipe
end
end
return craftable
end
-----------------------------------------------------
-- Get all recipes that match to already placed items on crafting grid
-----------------------------------------------------
function crecipes.get_recipes_started_craft(playername, grid, reference_items)
local all = crecipes.get_revealed_recipes_with_items(playername, reference_items)
local craftable = {}
for recipe, crecipe in pairs(all) do
if crecipe:check_craftable_by_grid(grid) then
craftable[recipe] = crecipe
end
end
return craftable
end
-----------------------------------------------------
-- Add an Item to the cache

View File

@ -165,6 +165,7 @@ end
local function update_from_recipelist(state, recipelist)
local duplicate_index_tmp = {}
local craftable_itemlist = {}
local clear_recipe_preview = true
for recipe, _ in pairs(recipelist) do
local def = cache.crecipes[recipe].out_item
@ -181,8 +182,21 @@ local function update_from_recipelist(state, recipelist)
duplicate_index_tmp[def.name] = entry
table.insert(entry.recipes, recipe)
table.insert(craftable_itemlist, entry)
if not state.param.crafting_recipes_preview_listentry then
clear_recipe_preview = true
elseif def.name == state.param.crafting_recipes_preview_listentry.item then
clear_recipe_preview = false
end
end
end
-- reset crafting preview if not in list
if clear_recipe_preview then
state.param.crafting_recipes_preview_listentry = {}
update_crafting_preview(state)
end
-- update the groups selection
state.param.crafting_grouped_items = ui_tools.get_list_grouped(craftable_itemlist)
update_group_selection(state, true)
end
@ -193,7 +207,6 @@ end
local function do_lookup_item(state, playername, lookup_item)
state.param.crafting_items_in_inventory = state.param.invobj:get_items()
state.param.crafting_items_in_inventory[lookup_item] = true -- prefer in recipe preview
local state = smart_inventory.get_page_state("crafting", playername)
-- get all craftable recipes with lookup-item as ingredient. Add recipes of lookup item to the list
local recipes = cache.crecipes.get_revealed_recipes_with_items(playername, {[lookup_item] = true })
update_from_recipelist(state, recipes)
@ -246,6 +259,8 @@ local function create_lookup_inv(state, name)
end,
on_put = function(inv, listname, index, stack, player)
pinv:set_stack(plistname, index, stack)
local name = player:get_player_name()
local state = smart_inventory.get_page_state("crafting", name)
do_lookup_item(state, name, stack:get_name())
-- we are outsite of usual smartfs processing. So trigger the formspec update byself
@ -453,14 +468,43 @@ minetest.register_craft_predict(function(stack, player, old_craft_grid, craft_in
return
end
local item = stack:get_name()
if state.param.crafting_predict_item ~= item then
state.param.crafting_predict_item = item
-- get all grid items for reference
local reference_items = {}
local items_hash = ""
for _, stack in ipairs(old_craft_grid) do
local name = stack:get_name()
if name and name ~= "" then
reference_items[name] = true
items_hash=items_hash.."|"..name
else
items_hash=items_hash.."|empty"
end
end
if stack:is_empty() then
if items_hash ~= state.param.survival_grid_items_hash then
state.param.survival_grid_items_hash = items_hash
if not next(reference_items) then
state:get("craftable"):submit("not used fieldname", name)
else
do_lookup_item(state, name, item)
-- update the grid with matched recipe items
state.param.survival_proposal_mode = "grid"
state:get("search"):setText("") -- reset search field because of mode change
local recipes = cache.crecipes.get_recipes_started_craft(name, old_craft_grid, reference_items)
update_from_recipelist(state, recipes)
-- update crafting preview if something craftable selected
if not stack:is_empty() then
local item = stack:get_name()
state.param.crafting_recipes_preview_selected = 1
state.param.crafting_recipes_preview_listentry = {
itemdef = minetest.registered_items[item],
item = item
}
update_crafting_preview(state)
if state:get("info_tog"):getId() == 1 then
state:get("info_tog"):submit()
end
end
end
smartfs.inv[name]:show()
end