(Forgot the table, LOL. Wish I had a better way to test this myself, but I'm doing it live.) |
(Add Dark Fog drop to list of recipes making items) |
||
(18 intermediate revisions by the same user not shown) | |||
Line 10: | Line 10: | ||
PhotonStore='Ray Receiver', |
PhotonStore='Ray Receiver', |
||
Fractionate='Fractionator', |
Fractionate='Fractionator', |
||
Research='Matrix Lab', |
|||
Mine='Mining Machine', |
|||
Gas='Orbital Collector', |
|||
Ocean='Water Pump', |
|||
Oil='Oil Extractor', |
|||
} |
} |
||
local OilSeepID = 7 |
|||
-- exported functions |
|||
-- recipesMaking |
|||
-- print out table rows of all recipes making an item with full information |
|||
-- the recipe, the building, technology to unlock it, etc. |
|||
function funcs.recipesMaking(frame) |
function funcs.recipesMaking(frame) |
||
return recipesMakingName(frame:getParent().args[1], frame) |
|||
item = itemByName(name) |
|||
recipes = recipesMakingByID(item.ID) |
|||
return tableRecipes(recipes, frame) |
|||
end |
end |
||
function funcs.recipesMakingDirect(frame) |
function funcs.recipesMakingDirect(frame) |
||
return recipesMakingName(frame.args[1], frame) |
|||
item = itemByName(name) |
|||
recipes = recipesMakingByID(item.ID) |
|||
return tableRecipes(recipes, frame) |
|||
end |
end |
||
function recipesMakingName(name, frame) |
|||
local rtable = { |
|||
frame:expandTemplate{title='ProductionChainTable/head', args={}}, |
|||
} |
|||
local item = itemByName(name) |
|||
for _, recipe in ipairs(recipesMakingByID(item.ID)) do |
|||
table.insert(rtable, recipeRow(recipe, frame)) |
|||
end |
|||
local vein = veinMakingByID(item.ID) |
|||
if vein ~= nil then |
|||
table.insert(rtable, veinRow(item, vein, frame)) |
|||
end |
|||
for _, giant in ipairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do |
|||
table.insert(rtable, gasGiantRow(item, giant, frame)) |
|||
end |
|||
if isItemOcean(item.ID) then |
|||
table.insert(rtable, oceanRow(item, frame)) |
|||
end |
|||
if isItemFogDrop(item) then |
|||
table.insert(rtable, fogDropRow(item, frame)) |
|||
end |
|||
table.insert(rtable, '|}') |
|||
return table.concat(rtable, '\n') |
|||
end |
|||
-- recipesUsing |
|||
-- print out table rows of all recipes using an item with full information, like recipesMaking |
|||
-- split output into components and buildings |
|||
function funcs.recipesUsing(frame) |
function funcs.recipesUsing(frame) |
||
return recipesUsingName(frame:getParent().args[1], frame) |
|||
output = {} |
|||
end |
|||
name = frame:getParent().args[1] |
|||
item = itemByName(name) |
|||
function funcs.recipesUsingDirect(frame) |
|||
components, buildings = recipesUsingByID(item.ID) |
|||
return recipesUsingName(frame.args[1], frame) |
|||
end |
|||
function recipesUsingName(name, frame) |
|||
local output = {} |
|||
local header = frame:expandTemplate{title='ProductionChainTable/head', args={}} |
|||
local item = itemByName(name) |
|||
local components = {} |
|||
local buildings = {} |
|||
for _, r in ipairs(recipesUsingByID(item.ID)) do |
|||
if r.GridIndex >= 2000 then |
|||
table.insert(buildings, r) |
|||
else |
|||
table.insert(components, r) |
|||
end |
|||
end |
|||
if next(components) then |
if next(components) then |
||
if next(buildings) then |
|||
table.insert(output, '=== Components ===') |
|||
table.insert(output, |
table.insert(output, '=== Components ===') |
||
end |
|||
table.insert(output, header) |
|||
for _, recipe in ipairs(components) do |
|||
table.insert(output, recipeRow(recipe, frame)) |
|||
end |
|||
table.insert(output, '|}') |
|||
end |
end |
||
if next(buildings) then |
if next(buildings) then |
||
if next(components) then |
|||
table.insert(output, '=== Buildings ===') |
|||
table.insert(output, |
table.insert(output, '=== Buildings ===') |
||
end |
|||
table.insert(output, header) |
|||
for _, recipe in ipairs(buildings) do |
|||
table.insert(output, recipeRow(recipe, frame)) |
|||
end |
|||
table.insert(output, '|}') |
|||
end |
end |
||
return table.concat(output, '\n') |
return table.concat(output, '\n') |
||
end |
end |
||
-- itemRecipes |
|||
function funcs.recipesUsingDirect(frame) |
|||
-- print out just recipe information on how to make an item |
|||
output = {} |
|||
-- intended for use in ItemInfo boxes |
|||
name = frame.args[1] |
|||
item = itemByName(name) |
|||
function funcs.itemRecipes(frame) |
|||
components, buildings = recipesUsingByID(item.ID) |
|||
return itemRecipesForName(frame:getParent().args[1], frame) |
|||
if next(components) then |
|||
end |
|||
table.insert(output, '=== Components ===') |
|||
function funcs.itemRecipesDirect(frame) |
|||
table.insert(output, tableRecipes(components, frame)) |
|||
return itemRecipesForName(frame.args[1], frame) |
|||
end |
|||
function itemRecipesForName(name, frame) |
|||
local item = itemByName(name) |
|||
local output = {} |
|||
for _, r in ipairs(recipesMakingByID(item.ID)) do |
|||
table.insert(output, itemRecipe(r, frame)) |
|||
end |
end |
||
local vein = veinMakingByID(item.ID) |
|||
if next(buildings) then |
|||
if vein then |
|||
table.insert(output, '=== Buildings ===') |
|||
table.insert(output, |
table.insert(output, veinRecipe(item, vein, frame)) |
||
end |
|||
for _, giant in ipairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do |
|||
table.insert(output, gasGiantRecipe(giant, frame)) |
|||
end |
|||
if isItemOcean(item.ID) then |
|||
table.insert(output, oceanRecipe(item, frame)) |
|||
end |
end |
||
return table.concat(output, '\n') |
return table.concat(output, '\n') |
||
end |
end |
||
-- itemField |
|||
function tableRecipes(recipes, frame) |
|||
-- print a field from an item |
|||
result = {} |
|||
-- used to extract details about an item |
|||
for _, recipe in pairs(recipes) do |
|||
itemdata = {} |
|||
function funcs.itemField(frame) |
|||
itemdata.CraftTime = string.format('%s s', tostring(recipe.TimeSpend/60)) |
|||
return itemFieldByName(frame:getParent().args[1], frame:getParent().args[2]) |
|||
for i, itemid in ipairs(recipe.Results) do |
|||
end |
|||
itemdata[string.format('Out%d', i)] = itemByID(itemid).Name |
|||
function funcs.itemFieldDirect(frame) |
|||
itemdata[string.format('Out%dQty', i)] = tostring(recipe.ResultCounts[i]) |
|||
return itemFieldByName(frame.args[1], frame.args[2]) |
|||
end |
|||
end |
|||
for i, itemid in ipairs(recipe.Items) do |
|||
itemdata[string.format('In%d', i)] = itemByID(itemid).Name |
|||
function itemFieldByName(itemname, fieldname) |
|||
itemdata[string.format('In%dQty', i)] = tostring(recipe.ResultCounts[i]) |
|||
local item = itemByName(itemname) |
|||
end |
|||
return item[fieldname] |
|||
data = { |
|||
end |
|||
Building = machines[recipe.Type], |
|||
Recipe = frame:expandTemplate{title='ItemRecipe', args=itemdata}, |
|||
-- make full rows and recipe data for tables |
|||
function recipeRow(recipe, frame) |
|||
local rdata = { |
|||
Building = titleCase(machines[recipe.Type]), |
|||
} |
|||
if recipe.Type == 'Fractionate' then |
|||
rdata.Recipe = fractionateRecipe(recipe, frame) |
|||
else |
|||
rdata.Recipe = itemRecipe(recipe, frame) |
|||
end |
|||
if recipe.Handcraft then |
|||
rdata.Replicator = 'Yes' |
|||
else |
|||
rdata.Replicator = 'No' |
|||
end |
|||
local tech = technologyForRecipeID(recipe.ID) |
|||
if tech ~= nil then |
|||
rdata.Technology = titleCase(tech.Name) |
|||
else |
|||
rdata.Technology = '' |
|||
end |
|||
local productive = not recipe.NonProductive |
|||
for i, itemid in ipairs(recipe.Items) do |
|||
productive = productive and itemByID(itemid).Productive |
|||
end |
|||
if productive then |
|||
rdata.Proliferator = 'Yes' |
|||
else |
|||
rdata.Proliferator = 'Speed' |
|||
end |
|||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=rdata} |
|||
end |
|||
function itemRecipe(recipe, frame) |
|||
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 veinRow(item, vein, frame) |
|||
if 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), |
|||
Proliferator='No', |
|||
} |
} |
||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oildata} |
|||
if data.Handcraft then |
|||
else |
|||
data.Replicator = 'Yes' |
|||
local miner = itemByName(machines.Mine) |
|||
else |
|||
local minerTech = technologyForRecipeID(recipesMakingByID(miner.ID)[1].ID) |
|||
data.Replicator = 'No' |
|||
local veindata = { |
|||
end |
|||
Building = titleCase(miner.Name), |
|||
tech = technologyForRecipeID(recipe.ID) |
|||
Replicator = 'Mine', |
|||
if tech ~= nil then |
|||
Technology = titleCase(minerTech.Name), |
|||
Recipe = veinRecipe(item, vein, frame), |
|||
else |
|||
Proliferator='No', |
|||
} |
|||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=veindata} |
|||
end |
end |
||
prefix = table.insert(result, frame:expandTemplate{title='ProductionChainTable/head', args={}}) |
|||
return string.format('%s\n%s\n|}', prefix, table.concat(result, '|-')) |
|||
end |
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 gasGiantRow(item, giant, frame) |
|||
local collector = itemByName(machines.Gas) |
|||
local collectorTech = technologyForRecipeID(recipesMakingByID(collector.ID)[1].ID) |
|||
local giantdata = { |
|||
Building = titleCase(collector.Name), |
|||
Replicator = 'Mine', |
|||
Technology = titleCase(collectorTech.Name), |
|||
Recipe = gasGiantRecipe(giant, frame), |
|||
Proliferator='No', |
|||
} |
|||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=giantdata} |
|||
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 fogDropRow(item, frame) |
|||
local fogdata = { |
|||
Building = 'Raider', |
|||
Replicator = 'No', |
|||
Recipe = fogDropRecipe(item, frame), |
|||
Proliferator = 'No', |
|||
} |
|||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=fogdata} |
|||
end |
|||
function fogDropRecipe(item, frame) |
|||
local prob = item.EnemyDropRange.y * 300 |
|||
local level = item.EnemyDropLevel * 3 |
|||
local dropMin = item.EnemyDropCount * 2 * (item.EnemyDropLevel / 10 + 1) |
|||
local dropMax = item.EnemyDropCount * 4 |
|||
local fogdata = { |
|||
CraftTime = string.format('%.2f%%', prob), |
|||
Out1 = item.Name, |
|||
Out1Qty = string.format('%.1f-%.1f', dropMin, dropMax), |
|||
In1 = 'Raider', |
|||
In1Qty = string.format('Lvl %d+', level), |
|||
} |
|||
return frame:expandTemplate{title='ItemRecipe', args=fogdata} |
|||
end |
|||
function oceanRow(item, frame) |
|||
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), |
|||
Proliferator='No', |
|||
} |
|||
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata} |
|||
end |
|||
function oceanRecipe(item, frame) |
|||
local odata = { |
|||
CraftTime = '1.2 s', |
|||
Out1 = titleCase(item.Name), |
|||
Out1Qty = 1, |
|||
In1 = titleCase(item.MiningFrom), |
|||
In1Qty = '', |
|||
} |
|||
return frame:expandTemplate{title='ItemRecipe', args=odata} |
|||
end |
|||
-- get data from protosets |
|||
function itemByName(name) |
function itemByName(name) |
||
local lame = string.lower(name) |
|||
for _, item in pairs(protosets.ItemProtoSet.dataArray) do |
|||
for _, item in ipairs(protosets.ItemProtoSet.dataArray) do |
|||
if item.Name == name then |
|||
if string.lower(item.Name) == lame then |
|||
return item |
return item |
||
end |
end |
||
Line 102: | Line 353: | ||
end |
end |
||
function itemByID(id) |
function itemByID(id) |
||
for _, item in |
for _, item in ipairs(protosets.ItemProtoSet.dataArray) do |
||
if item.ID == id then |
if item.ID == id then |
||
return item |
return item |
||
Line 111: | Line 362: | ||
function recipesMakingByID(id) |
function recipesMakingByID(id) |
||
result = {} |
local result = {} |
||
for _, recipe in |
for _, recipe in ipairs(protosets.RecipeProtoSet.dataArray) do |
||
for _, itemid in |
for _, itemid in ipairs(recipe.Results) do |
||
if itemid == id then |
if itemid == id then |
||
table.insert(result, recipe) |
table.insert(result, recipe) |
||
Line 123: | Line 374: | ||
end |
end |
||
function recipesUsingByID(id) |
function recipesUsingByID(id) |
||
local recipes = {} |
|||
for _, recipe in ipairs(protosets.RecipeProtoSet.dataArray) do |
|||
buildings = {} |
|||
for _, itemid in ipairs(recipe.Items) do |
|||
for _, itemid in pairs(recipe.Items) do |
|||
if itemid == id then |
if itemid == id then |
||
table.insert(recipes, recipe) |
|||
if itemByID(recipe.Results[1]).CanBuild then |
|||
table.insert(buildings, recipe) |
|||
else |
|||
table.insert(components, recipe) |
|||
end |
|||
break |
break |
||
end |
end |
||
end |
end |
||
end |
end |
||
return |
return recipes |
||
end |
end |
||
function technologyForRecipeID(id) |
function technologyForRecipeID(id) |
||
for _, tech in |
for _, tech in ipairs(protosets.TechProtoSet.dataArray) do |
||
for _, recipeid in |
for _, recipeid in ipairs(tech.UnlockRecipes) do |
||
if recipeid == id then |
if recipeid == id then |
||
return tech |
return tech |
||
Line 149: | Line 395: | ||
end |
end |
||
return nil |
return nil |
||
end |
|||
function veinMakingByID(id) |
|||
for _, vein in ipairs(protosets.VeinProtoSet.dataArray) do |
|||
if vein.MiningItem == id then |
|||
return vein |
|||
end |
|||
end |
|||
return nil |
|||
end |
|||
function gasGiantsMakingByID(id) |
|||
local giants = {} |
|||
for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do |
|||
for _, item in ipairs(planet.GasItems) do |
|||
if item == id then |
|||
table.insert(giants, planet) |
|||
break |
|||
end |
|||
end |
|||
end |
|||
return giants |
|||
end |
|||
function isItemOcean(id) |
|||
for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do |
|||
if id == planet.WaterItemId then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
function isItemFogDrop(item) |
|||
return item.EnemyDropRange.y > 0 |
|||
end |
|||
-- sorting/deduplication |
|||
function deduplicateGiants(giants) |
|||
local dedup = {} |
|||
for _, planet in ipairs(giants) do |
|||
new = true |
|||
for _, exist in ipairs(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 |
|||
-- display formatting |
|||
function titleCase(str) |
|||
local start = string.gsub(str, '^%l', string.upper) |
|||
local title = string.gsub(start, '[-%s]%l', string.upper) |
|||
local mk = string.gsub(title, 'MK.I', 'Mk.I') |
|||
return mk |
|||
end |
end |
||
Latest revision as of 00:07, 19 July 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 -- exported functions -- recipesMaking -- print out table rows of all recipes making an item with full information -- the recipe, the building, technology to unlock it, etc. 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 rtable = { frame:expandTemplate{title='ProductionChainTable/head', args={}}, } local item = itemByName(name) for _, recipe in ipairs(recipesMakingByID(item.ID)) do table.insert(rtable, recipeRow(recipe, frame)) end local vein = veinMakingByID(item.ID) if vein ~= nil then table.insert(rtable, veinRow(item, vein, frame)) end for _, giant in ipairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do table.insert(rtable, gasGiantRow(item, giant, frame)) end if isItemOcean(item.ID) then table.insert(rtable, oceanRow(item, frame)) end if isItemFogDrop(item) then table.insert(rtable, fogDropRow(item, frame)) end table.insert(rtable, '|}') return table.concat(rtable, '\n') end -- recipesUsing -- print out table rows of all recipes using an item with full information, like recipesMaking -- split output into components and buildings 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 header = frame:expandTemplate{title='ProductionChainTable/head', args={}} local item = itemByName(name) local components = {} local buildings = {} for _, r in ipairs(recipesUsingByID(item.ID)) do if r.GridIndex >= 2000 then table.insert(buildings, r) else table.insert(components, r) end end if next(components) then if next(buildings) then table.insert(output, '=== Components ===') end table.insert(output, header) for _, recipe in ipairs(components) do table.insert(output, recipeRow(recipe, frame)) end table.insert(output, '|}') end if next(buildings) then if next(components) then table.insert(output, '=== Buildings ===') end table.insert(output, header) for _, recipe in ipairs(buildings) do table.insert(output, recipeRow(recipe, frame)) end table.insert(output, '|}') end return table.concat(output, '\n') end -- itemRecipes -- print out just recipe information on how to make an item -- intended for use in ItemInfo boxes 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 ipairs(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 ipairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do table.insert(output, gasGiantRecipe(giant, frame)) end if isItemOcean(item.ID) then table.insert(output, oceanRecipe(item, frame)) end return table.concat(output, '\n') end -- itemField -- print a field from an item -- used to extract details about an item 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 -- make full rows and recipe data for tables function recipeRow(recipe, frame) local rdata = { Building = titleCase(machines[recipe.Type]), } if recipe.Type == 'Fractionate' then rdata.Recipe = fractionateRecipe(recipe, frame) else rdata.Recipe = itemRecipe(recipe, frame) end if recipe.Handcraft then rdata.Replicator = 'Yes' else rdata.Replicator = 'No' end local tech = technologyForRecipeID(recipe.ID) if tech ~= nil then rdata.Technology = titleCase(tech.Name) else rdata.Technology = '' end local productive = not recipe.NonProductive for i, itemid in ipairs(recipe.Items) do productive = productive and itemByID(itemid).Productive end if productive then rdata.Proliferator = 'Yes' else rdata.Proliferator = 'Speed' end return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=rdata} end function itemRecipe(recipe, frame) 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 veinRow(item, vein, frame) if 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), Proliferator='No', } return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oildata} else 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), Proliferator='No', } return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=veindata} end 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 gasGiantRow(item, giant, frame) local collector = itemByName(machines.Gas) local collectorTech = technologyForRecipeID(recipesMakingByID(collector.ID)[1].ID) local giantdata = { Building = titleCase(collector.Name), Replicator = 'Mine', Technology = titleCase(collectorTech.Name), Recipe = gasGiantRecipe(giant, frame), Proliferator='No', } return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=giantdata} 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 fogDropRow(item, frame) local fogdata = { Building = 'Raider', Replicator = 'No', Recipe = fogDropRecipe(item, frame), Proliferator = 'No', } return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=fogdata} end function fogDropRecipe(item, frame) local prob = item.EnemyDropRange.y * 300 local level = item.EnemyDropLevel * 3 local dropMin = item.EnemyDropCount * 2 * (item.EnemyDropLevel / 10 + 1) local dropMax = item.EnemyDropCount * 4 local fogdata = { CraftTime = string.format('%.2f%%', prob), Out1 = item.Name, Out1Qty = string.format('%.1f-%.1f', dropMin, dropMax), In1 = 'Raider', In1Qty = string.format('Lvl %d+', level), } return frame:expandTemplate{title='ItemRecipe', args=fogdata} end function oceanRow(item, frame) 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), Proliferator='No', } return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata} end function oceanRecipe(item, frame) local odata = { CraftTime = '1.2 s', Out1 = titleCase(item.Name), Out1Qty = 1, In1 = titleCase(item.MiningFrom), In1Qty = '', } return frame:expandTemplate{title='ItemRecipe', args=odata} end -- get data from protosets function itemByName(name) local lame = string.lower(name) for _, item in ipairs(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 ipairs(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 ipairs(protosets.RecipeProtoSet.dataArray) do for _, itemid in ipairs(recipe.Results) do if itemid == id then table.insert(result, recipe) break end end end return result end function recipesUsingByID(id) local recipes = {} for _, recipe in ipairs(protosets.RecipeProtoSet.dataArray) do for _, itemid in ipairs(recipe.Items) do if itemid == id then table.insert(recipes, recipe) break end end end return recipes end function technologyForRecipeID(id) for _, tech in ipairs(protosets.TechProtoSet.dataArray) do for _, recipeid in ipairs(tech.UnlockRecipes) do if recipeid == id then return tech end end end return nil end function veinMakingByID(id) for _, vein in ipairs(protosets.VeinProtoSet.dataArray) do if vein.MiningItem == id then return vein end end return nil end function gasGiantsMakingByID(id) local giants = {} for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do for _, item in ipairs(planet.GasItems) do if item == id then table.insert(giants, planet) break end end end return giants end function isItemOcean(id) for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do if id == planet.WaterItemId then return true end end return false end function isItemFogDrop(item) return item.EnemyDropRange.y > 0 end -- sorting/deduplication function deduplicateGiants(giants) local dedup = {} for _, planet in ipairs(giants) do new = true for _, exist in ipairs(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 -- display formatting function titleCase(str) local start = string.gsub(str, '^%l', string.upper) local title = string.gsub(start, '[-%s]%l', string.upper) local mk = string.gsub(title, 'MK.I', 'Mk.I') return mk end return funcs