(Show fractionator percentage instead of time, possibly add infobox recipes?) |
(Add support for oil seeps and oceans (water pumps)) |
||
Line 13: | Line 13: | ||
Mine='Mining Machine', | Mine='Mining Machine', | ||
Gas='Orbital Collector', | Gas='Orbital Collector', | ||
Ocean='Water Pump', | |||
Oil='Oil Extractor', | |||
} | } | ||
local OilSeepID = 7 | |||
function funcs.recipesMaking(frame) | function funcs.recipesMaking(frame) | ||
Line 28: | Line 31: | ||
local vein = veinMakingByID(item.ID) | local vein = veinMakingByID(item.ID) | ||
local gas = deduplicateGiants(gasGiantsMakingByID(item.ID)) | local gas = deduplicateGiants(gasGiantsMakingByID(item.ID)) | ||
return tableRecipes(item, recipes, vein, gas, frame) | local isocean = isItemOcean(item.ID) | ||
return tableRecipes(item, recipes, vein, gas, isocean, frame) | |||
end | end | ||
Line 45: | Line 49: | ||
if next(components) then | if next(components) then | ||
table.insert(output, '=== Components ===') | table.insert(output, '=== Components ===') | ||
table.insert(output, tableRecipes(item, components, nil, nil, frame)) | table.insert(output, tableRecipes(item, components, nil, nil, false, frame)) | ||
end | end | ||
if next(buildings) then | if next(buildings) then | ||
table.insert(output, '=== Buildings ===') | table.insert(output, '=== Buildings ===') | ||
table.insert(output, tableRecipes(item, buildings, nil, nil, frame)) | table.insert(output, tableRecipes(item, buildings, nil, nil, false, frame)) | ||
end | end | ||
return table.concat(output, '\n') | return table.concat(output, '\n') | ||
Line 77: | Line 81: | ||
end | end | ||
function tableRecipes(item, recipes, vein, gas, frame) | function funcs.itemField(frame) | ||
return itemFieldByName(frame:getParent().args[1], frame:getParent().args[2]) | |||
end | |||
function funcs.itemFieldDirect(frame) | |||
return itemFieldByName(frame.args[1], frame.args[2]) | |||
end | |||
function itemFieldByName(itemname, fieldname) | |||
local item = itemByName(itemname) | |||
return item[fieldname] | |||
end | |||
function tableRecipes(item, recipes, vein, gas, isocean, frame) | |||
local result = {} | local result = {} | ||
for _, recipe in pairs(recipes) do | for _, recipe in pairs(recipes) do | ||
Line 97: | Line 113: | ||
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=data}) | table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=data}) | ||
end | end | ||
if vein then | if vein and vein.ID == OilSeepID then -- I don't have a better test for oil right now | ||
local extractor = itemByName(machines.Oil) | |||
local extractorTech = technologyForRecipeID(recipesMakingByID(extractor.ID)[1].ID) | |||
local oildata = { | |||
Building = titleCase(extractor.Name), | |||
Replicator = 'No', | |||
Technology = titleCase(extractorTech.Name), | |||
Recipe = oilRecipe(item, vein, frame), | |||
} | |||
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=oildata}) | |||
elseif vein then | |||
local miner = itemByName(machines.Mine) | local miner = itemByName(machines.Mine) | ||
local minerTech = technologyForRecipeID(recipesMakingByID(miner.ID)[1].ID) | local minerTech = technologyForRecipeID(recipesMakingByID(miner.ID)[1].ID) | ||
Line 120: | Line 146: | ||
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=gasdata}) | table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=gasdata}) | ||
end | end | ||
end | |||
if isocean then | |||
local pump = itemByName(machines.Ocean) | |||
local pumpTech = technologyForRecipeID(recipesMakingByID(pump.ID)[1].ID) | |||
local oceandata = { | |||
Building = titleCase(pump.Name), | |||
Replicator = 'No', | |||
Technology = titleCase(pumpTech.Name), | |||
Recipe = oceanRecipe(item, frame) | |||
} | |||
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata}) | |||
end | end | ||
local prefix = frame:expandTemplate{title='ProductionChainTable/head', args={}} | local prefix = frame:expandTemplate{title='ProductionChainTable/head', args={}} | ||
Line 169: | Line 206: | ||
} | } | ||
return frame:expandTemplate{title='ItemRecipe', args=idata} | return frame:expandTemplate{title='ItemRecipe', args=idata} | ||
end | |||
function oilRecipe(item, vein, frame) | |||
local odata = { | |||
In1 = titleCase(vein.Name), | |||
In1Qty = '', | |||
Out1 = titleCase(item.Name), | |||
Out1Qty = '1', | |||
CraftTime = '?', | |||
} | |||
return frame:expandTemplate{title='ItemRecipe', args=odata} | |||
end | end | ||
Line 183: | Line 231: | ||
end | end | ||
return frame:expandTemplate{title='ItemRecipe', args=gdata} | return frame:expandTemplate{title='ItemRecipe', args=gdata} | ||
end | |||
function oceanRecipe(item, frame) | |||
local odata = { | |||
CraftTime = '1.2 s', | |||
Out1 = titleCase(item.Name), | |||
Out1Qty = 1, | |||
} | |||
return frame:expandTemplate{title='ItemRecipe', args=odata} | |||
end | end | ||
Line 264: | Line 321: | ||
end | end | ||
return giants | return giants | ||
end | |||
function isItemOcean(id) | |||
for _, planet in pairs(protosets.ThemeProtoSet.dataArray) do | |||
if id == planet.WaterItemId then | |||
return true | |||
end | |||
end | |||
return false | |||
end | end | ||
Revision as of 00:32, 28 April 2024
Source data for this module is stored at Module:GameData/protosets.json
Exported Functions
Each function in this module is exported twice: one as-is for use in templates, and once with a Direct suffix for use directly on pages using {{#invoke|GameData|functionDirect|...}}.
recipesMaking
Arguments: Item Name
Print recipes making an item, given by name. This produces a full table with headers.
Example invocation:
{{#invoke:GameData|recipesMakingDirect|Sulfuric Acid}}
Recipe | Building | Replicator? | Technology |
---|---|---|---|
![]() ![]() |
✖ | ||
![]() |
✖ |
recipesUsing
Arguments: Item Name
Print recipes using an item as an ingredient. Output is separated into two full tables: recipes which create components, and recipes which create buildings. This is selected by the CanBuild property of the produced items.
Example invocation:
{{#invoke:GameData|recipesUsingDirect|Copper Ingot}}
Components
Recipe | Building | Replicator? | Technology |
---|---|---|---|
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | N/A | |
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | N/A | |
![]() ![]() ![]() ![]() |
✖ | ||
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ |
Buildings
Recipe | Building | Replicator? | Technology |
---|---|---|---|
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ | ||
![]() ![]() ![]() ![]() |
✔ |
itemRecipes
Arguments: Item Name
Print recipes making an item. This does not produce a full table, and is intended for use in ItemInfo boxes such as at Graphene/ItemInfo.
itemField
Arguments: Item Name, Field Name
Print a field from an item, with the field to print as an argument. You can look at Module:GameData/protosets.json and scroll down or search (Ctrl+F) to the ItemProtoSet to browse fields.
Example invocation:
{{#invoke:GameData|itemFieldDirect|Magnetic Coil|Description}}
It is an extremely useful basic electromagnetic component.
{{#invoke:GameData|itemFieldDirect|Hydrogen|StackSize}}
20
local funcs = {} local protosets = mw.loadJsonData('Module:GameData/protosets.json') local machines = { Smelt='Smelter', Assemble='Assembling Machine', Refine='Oil Refinery', Chemical='Chemical Plant', Exchange='Energy Exchanger', Particle='Miniature Particle Collider', PhotonStore='Ray Receiver', Fractionate='Fractionator', Research='Matrix Lab', Mine='Mining Machine', Gas='Orbital Collector', Ocean='Water Pump', Oil='Oil Extractor', } local OilSeepID = 7 function funcs.recipesMaking(frame) return recipesMakingName(frame:getParent().args[1], frame) end function funcs.recipesMakingDirect(frame) return recipesMakingName(frame.args[1], frame) end function recipesMakingName(name, frame) local item = itemByName(name) local recipes = recipesMakingByID(item.ID) local vein = veinMakingByID(item.ID) local gas = deduplicateGiants(gasGiantsMakingByID(item.ID)) local isocean = isItemOcean(item.ID) return tableRecipes(item, recipes, vein, gas, isocean, frame) end function funcs.recipesUsing(frame) return recipesUsingName(frame:getParent().args[1], frame) end function funcs.recipesUsingDirect(frame) return recipesUsingName(frame.args[1], frame) end function recipesUsingName(name, frame) local output = {} local item = itemByName(name) local components, buildings = recipesUsingByID(item.ID) if next(components) then table.insert(output, '=== Components ===') table.insert(output, tableRecipes(item, components, nil, nil, false, frame)) end if next(buildings) then table.insert(output, '=== Buildings ===') table.insert(output, tableRecipes(item, buildings, nil, nil, false, frame)) end return table.concat(output, '\n') end function funcs.itemRecipes(frame) return itemRecipesForName(frame:getParent().args[1], frame) end function funcs.itemRecipesDirect(frame) return itemRecipesForName(frame.args[1], frame) end function itemRecipesForName(name, frame) local item = itemByName(name) local output = {} for _, r in pairs(recipesMakingByID(item.ID)) do table.insert(output, itemRecipe(r, frame)) end local vein = veinMakingByID(item.ID) if vein then table.insert(output, veinRecipe(item, vein, frame)) end for _, giant in pairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do table.insert(output, gasGiantRecipe(giant, frame)) end return table.concat(output, '\n') end function funcs.itemField(frame) return itemFieldByName(frame:getParent().args[1], frame:getParent().args[2]) end function funcs.itemFieldDirect(frame) return itemFieldByName(frame.args[1], frame.args[2]) end function itemFieldByName(itemname, fieldname) local item = itemByName(itemname) return item[fieldname] end function tableRecipes(item, recipes, vein, gas, isocean, frame) local result = {} for _, recipe in pairs(recipes) do local data = { Building = titleCase(machines[recipe.Type]), Recipe = itemRecipe(recipe, frame) } if recipe.Handcraft then data.Replicator = 'Yes' else data.Replicator = 'No' end local tech = technologyForRecipeID(recipe.ID) if tech ~= nil then data.Technology = titleCase(tech.Name) else data.Technology = '' end table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=data}) end if vein and vein.ID == OilSeepID then -- I don't have a better test for oil right now local extractor = itemByName(machines.Oil) local extractorTech = technologyForRecipeID(recipesMakingByID(extractor.ID)[1].ID) local oildata = { Building = titleCase(extractor.Name), Replicator = 'No', Technology = titleCase(extractorTech.Name), Recipe = oilRecipe(item, vein, frame), } table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=oildata}) elseif vein then local miner = itemByName(machines.Mine) local minerTech = technologyForRecipeID(recipesMakingByID(miner.ID)[1].ID) local veindata = { Building = titleCase(miner.Name), Replicator = 'Mine', Technology = titleCase(minerTech.Name), Recipe = veinRecipe(item, vein, frame), } table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=veindata}) end if gas then local collector = itemByName(machines.Gas) local collectorTech = technologyForRecipeID(recipesMakingByID(collector.ID)[1].ID) for _, giant in pairs(gas) do local gasdata = { Building = titleCase(collector.Name), Replicator = 'Mine', Technology = titleCase(collectorTech.Name), Recipe = gasGiantRecipe(giant, frame) } table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=gasdata}) end end if isocean then local pump = itemByName(machines.Ocean) local pumpTech = technologyForRecipeID(recipesMakingByID(pump.ID)[1].ID) local oceandata = { Building = titleCase(pump.Name), Replicator = 'No', Technology = titleCase(pumpTech.Name), Recipe = oceanRecipe(item, frame) } table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata}) end local prefix = frame:expandTemplate{title='ProductionChainTable/head', args={}} return string.format('%s\n%s\n|}', prefix, table.concat(result, '\n|-\n')) end function itemRecipe(recipe, frame) if recipe.Type == 'Fractionate' then return fractionateRecipe(recipe, frame) end local rdata = { CraftTime = string.format('%s s', tostring(recipe.TimeSpend/60)), } for i, itemid in ipairs(recipe.Results) do rdata[string.format('Out%d', i)] = titleCase(itemByID(itemid).Name) rdata[string.format('Out%dQty', i)] = tostring(recipe.ResultCounts[i]) end for i, itemid in ipairs(recipe.Items) do rdata[string.format('In%d', i)] = titleCase(itemByID(itemid).Name) rdata[string.format('In%dQty', i)] = tostring(recipe.ItemCounts[i]) end return frame:expandTemplate{title='ItemRecipe', args=rdata} end function fractionateRecipe(recipe, frame) local ratio = 100 * recipe.ResultCounts[1] / recipe.ItemCounts[1] local rdata = { CraftTime = tostring(ratio) .. '%', } for i, itemid in ipairs(recipe.Results) do rdata[string.format('Out%d', i)] = titleCase(itemByID(itemid).Name) rdata[string.format('Out%dQty', i)] = '1' end for i, itemid in ipairs(recipe.Items) do rdata[string.format('In%d', i)] = titleCase(itemByID(itemid).Name) rdata[string.format('In%dQty', i)] = '1' end return frame:expandTemplate{title='ItemRecipe', args=rdata} end function veinRecipe(item, vein, frame) local vname = string.gsub(vein.Name, '%sVeins$', ' Vein') local idata = { In1 = titleCase(vname), In1Qty = '1', Out1 = titleCase(item.Name), Out1Qty = '1', CraftTime = '2 s', } return frame:expandTemplate{title='ItemRecipe', args=idata} end function oilRecipe(item, vein, frame) local odata = { In1 = titleCase(vein.Name), In1Qty = '', Out1 = titleCase(item.Name), Out1Qty = '1', CraftTime = '?', } return frame:expandTemplate{title='ItemRecipe', args=odata} end function gasGiantRecipe(gas, frame) local gdata = { CraftTime = '?', In1 = titleCase(gas.DisplayName), In1Qty = '', } for i, productID in ipairs(gas.GasItems) do local product = itemByID(productID) gdata[string.format('Out%d', i)] = titleCase(product.Name) gdata[string.format('Out%dQty', i)] = '1' end return frame:expandTemplate{title='ItemRecipe', args=gdata} end function oceanRecipe(item, frame) local odata = { CraftTime = '1.2 s', Out1 = titleCase(item.Name), Out1Qty = 1, } return frame:expandTemplate{title='ItemRecipe', args=odata} end function itemByName(name) local lame = string.lower(name) for _, item in pairs(protosets.ItemProtoSet.dataArray) do if string.lower(item.Name) == lame then return item end end error('No item named ' .. name) end function itemByID(id) for _, item in pairs(protosets.ItemProtoSet.dataArray) do if item.ID == id then return item end end error('No item with ID ' .. id) end function recipesMakingByID(id) local result = {} for _, recipe in pairs(protosets.RecipeProtoSet.dataArray) do for _, itemid in pairs(recipe.Results) do if itemid == id then table.insert(result, recipe) break end end end return result end function recipesUsingByID(id) local components = {} local buildings = {} for _, recipe in pairs(protosets.RecipeProtoSet.dataArray) do for _, itemid in pairs(recipe.Items) do if itemid == id then if itemByID(recipe.Results[1]).CanBuild then table.insert(buildings, recipe) else table.insert(components, recipe) end break end end end return components, buildings end function technologyForRecipeID(id) for _, tech in pairs(protosets.TechProtoSet.dataArray) do for _, recipeid in pairs(tech.UnlockRecipes) do if recipeid == id then return tech end end end return nil end function veinMakingByID(id) for _, vein in pairs(protosets.VeinProtoSet.dataArray) do if vein.MiningItem == id then return vein end end return nil end function gasGiantsMakingByID(id) local giants = {} for _, planet in pairs(protosets.ThemeProtoSet.dataArray) do for _, item in pairs(planet.GasItems) do if item == id then table.insert(giants, planet) break end end end return giants end function isItemOcean(id) for _, planet in pairs(protosets.ThemeProtoSet.dataArray) do if id == planet.WaterItemId then return true end end return false end function deduplicateGiants(giants) local dedup = {} for _, planet in pairs(giants) do new = true for _, exist in pairs(dedup) do if string.lower(planet.DisplayName) == string.lower(exist.DisplayName) then new = false break end end if new then table.insert(dedup, planet) end end return dedup end function titleCase(str) local start = string.gsub(str, '^%l', string.upper) local title = string.gsub(start, '[-%s]%l', string.upper) return title end return funcs