@@ -3,8 +3,10 @@ -- paper can then bound together into books, combining like -- recipes sorcery.cookbook = {} +local log = sorcery.logger('cookbook') + local constants = { -- do not show recipes for items in these groups exclude_groups = { }; @@ -54,32 +56,42 @@ local sep = string.find(id,':') if sep == nil then return nil end -- uh oh return string.sub(id, 1, sep - 1) end +local item_restrict_eval = function(name, restrict) + for _,n in pairs(constants.exclude_names) do + if string.find(name,n) ~= nil then + return false + end + end + for _,g in pairs(constants.exclude_groups) do + if minetest.get_item_group(name, g) > 0 then + return false + end + end + + local props = minetest.registered_items[name]._sorcery + local module = modofname(name) + + return not (excluded + or sorcery.lib.tbl.has(constants.blacklist_mods,module) + or (props and props.recipe and props.recipe.secret) + or (restrict and ( + (restrict.pred and restrict.pred { + mod = module, item = name, props = props + } ~= true) + or (restrict.mod and module ~= restrict.mod) + or (restrict.group and (minetest.get_item_group(name, restrict.group) == 0)) + ))) +end + local pick_builtin = function(kind) return function(restrict) -- ow ow ow ow ow ow ow local names = {} for k in pairs(minetest.registered_items) do local rec = minetest.get_craft_recipe(k) if rec.items ~= nil and (rec.method == kind or (rec.method == 'shapeless' and kind == 'normal')) then -- is this last bit necessary? - local excluded = false - for _,n in pairs(constants.exclude_names) do - if string.find(k,n) ~= nil then - excluded = true break end - end - if not excluded then for _,g in pairs(constants.exclude_groups) do - if minetest.get_item_group(k, g) > 0 then - excluded = true break end - end end - local props = minetest.registered_items[k]._sorcery - local module = modofname(k) - if not (excluded - or sorcery.lib.tbl.has(constants.blacklist_mods,module) - or (props and props.recipe and props.recipe.secret) - or (restrict and ( - (restrict.mod and module ~= restrict.mod) - or (restrict.group and (minetest.get_item_group(k, restrict.group) == 0)) - ))) then names[#names + 1] = k end + if item_restrict_eval(k, restrict) then names[#names + 1] = k end end end return names[math.random(#names)] end end @@ -222,9 +234,24 @@ {0,1}; }; pick = function(restrict) -- TODO make sure affinity restrictions match - return sorcery.register.infusions.db[math.random(#sorcery.register.infusions.db)].output + if restrict then + local t = {} + for _, i in pairs(sorcery.register.infusions.db) do + if item_restrict_eval(i.output, restrict) and not ( + -- conditions which cause failure of restriction test + (restrict.ipred and restrict.ipred { + mod = module; + infusion = i; + output = i.output; + } ~= true) + ) then t[#t+1] = i.output end + end + return select(2, sorcery.lib.tbl.pick(t)) + else + return sorcery.register.infusions.db[math.random(#sorcery.register.infusions.db)].output + end end; title = function(output) for _,i in pairs(sorcery.register.infusions.db) do if i.output == output then @@ -257,11 +284,22 @@ chance = 1; w = 1, h = 2; pick = function(restrict) cache:populate_grindables() - local i = cache.grindables[math.random(#cache.grindables)] - local pd = sorcery.itemclass.get(i, 'grindable') - return pd.powder + if restrict then + local t = {} + for _, i in pairs(cache.grindables) do + local pd = sorcery.itemclass.get(i, 'grindable') + if item_restrict_eval(pd.powder, restrict) then + t[#t+1] = pd.powder + end + end + return select(2, sorcery.lib.tbl.pick(t)) + else + local gd = cache.grindables[math.random(#cache.grindables)] + local pd = sorcery.itemclass.get(gd, 'grindable') + return pd.powder + end end; props = props_builtin; slots = { {0,1}, @@ -403,8 +441,11 @@ kind = rks[math.random(#rks)] end end + if not recipe_kinds[kind] then + log.fatalf('attempted to pick recipe of unknown kind "%s"', kind) + end return recipe_kinds[kind].pick(restrict), kind end local render_recipe = function(kind,ingredients,result,notes_right) @@ -467,8 +508,9 @@ sorcery.cookbook.setrecipe = function(stack,k,r,restrict) local meta = stack:get_meta() if not r then r,k = sorcery.cookbook.pickrecipe(k,restrict) end + if not r then return false end local t = recipe_kinds[k] meta:set_string('recipe_kind', k) meta:set_string('recipe_name', r) meta:set_string('description',