Module:GameData: Difference between revisions

From the Dyson Sphere Program Wiki
(Count Items not Results, and actually make table rows. Found a way to not do it live. I hope. I think. If this works.)
(Add Dark Fog drop to list of recipes making items)
 
(16 intermediate revisions by the same user not shown)
Line 10: Line 10:
PhotonStore='Ray Receiver',
PhotonStore='Ray Receiver',
Fractionate='Fractionator',
Fractionate='Fractionator',
Resarch='Matrix Lab',
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)
name = frame:getParent().args[1]
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)
name = frame.args[1]
return recipesMakingName(frame.args[1], frame)
item = itemByName(name)
end
recipes = recipesMakingByID(item.ID)
 
return tableRecipes(recipes, frame)
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
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)
output = {}
return recipesUsingName(frame:getParent().args[1], frame)
name = frame:getParent().args[1]
end
item = itemByName(name)
 
components, buildings = recipesUsingByID(item.ID)
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(components) then
table.insert(output, '=== Components ===')
if next(buildings) then
table.insert(output, tableRecipes(components, frame))
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
table.insert(output, '=== Buildings ===')
if next(components) then
table.insert(output, tableRecipes(buildings, frame))
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


function funcs.recipesUsingDirect(frame)
-- itemRecipes
output = {}
-- print out just recipe information on how to make an item
name = frame.args[1]
-- intended for use in ItemInfo boxes
item = itemByName(name)
 
components, buildings = recipesUsingByID(item.ID)
function funcs.itemRecipes(frame)
if next(components) then
return itemRecipesForName(frame:getParent().args[1], frame)
table.insert(output, '=== Components ===')
end
table.insert(output, tableRecipes(components, frame))
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
end
if next(buildings) then
if isItemOcean(item.ID) then
table.insert(output, '=== Buildings ===')
table.insert(output, oceanRecipe(item, frame))
table.insert(output, tableRecipes(buildings, frame))
end
end
return table.concat(output, '\n')
return table.concat(output, '\n')
end
end


function tableRecipes(recipes, frame)
-- itemField
result = {}
-- print a field from an item
for _, recipe in pairs(recipes) do
-- used to extract details about an item
itemdata = {}
 
itemdata.CraftTime = string.format('%s s', tostring(recipe.TimeSpend/60))
function funcs.itemField(frame)
for i, itemid in ipairs(recipe.Results) do
return itemFieldByName(frame:getParent().args[1], frame:getParent().args[2])
itemdata[string.format('Out%d', i)] = itemByID(itemid).Name
end
itemdata[string.format('Out%dQty', i)] = tostring(recipe.ResultCounts[i])
function funcs.itemFieldDirect(frame)
end
return itemFieldByName(frame.args[1], frame.args[2])
for i, itemid in ipairs(recipe.Items) do
end
itemdata[string.format('In%d', i)] = itemByID(itemid).Name
 
itemdata[string.format('In%dQty', i)] = tostring(recipe.ItemCounts[i])
function itemFieldByName(itemname, fieldname)
end
local item = itemByName(itemname)
data = {
return item[fieldname]
Building = machines[recipe.Type],
end
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}
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',
}
}
if data.Handcraft then
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=veindata}
data.Replicator = 'Yes'
end
else
end
data.Replicator = 'No'
 
end
function veinRecipe(item, vein, frame)
tech = technologyForRecipeID(recipe.ID)
local vname = string.gsub(vein.Name, '%sVeins$', ' Vein')
if tech ~= nil then
local idata = {
data.Technology = tech.Name
In1 = titleCase(vname),
else
In1Qty = '1',
data.Technology = ''
Out1 = titleCase(item.Name),
end
Out1Qty = '1',
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=data})
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
end
prefix = frame:expandTemplate{title='ProductionChainTable/head', args={}}
return frame:expandTemplate{title='ItemRecipe', args=gdata}
return string.format('%s\n%s\n|}', prefix, table.concat(result, '\n|-\n'))
end
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)
for _, item in pairs(protosets.ItemProtoSet.dataArray) do
local lame = string.lower(name)
if item.Name == name then
for _, item in ipairs(protosets.ItemProtoSet.dataArray) do
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 pairs(protosets.ItemProtoSet.dataArray) do
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 pairs(protosets.RecipeProtoSet.dataArray) do
for _, recipe in ipairs(protosets.RecipeProtoSet.dataArray) do
for _, itemid in pairs(recipe.Results) do
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)
components = {}
local recipes = {}
buildings = {}
for _, recipe in ipairs(protosets.RecipeProtoSet.dataArray) do
for _, recipe in pairs(protosets.RecipeProtoSet.dataArray) do
for _, itemid in ipairs(recipe.Items) do
for _, itemid in pairs(recipe.Items) do
if itemid == id then
if itemid == id then
if itemByID(recipe.Results[1]).CanBuild then
table.insert(recipes, recipe)
table.insert(buildings, recipe)
else
table.insert(components, recipe)
end
break
break
end
end
end
end
end
end
return components, buildings
return recipes
end
end


function technologyForRecipeID(id)
function technologyForRecipeID(id)
for _, tech in pairs(protosets.TechProtoSet.dataArray) do
for _, tech in ipairs(protosets.TechProtoSet.dataArray) do
for _, recipeid in pairs(tech.UnlockRecipes) do
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


return funcs
return funcs

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
Icon Sulfuric Acid.png
4
6 s
Icon Refined Oil.png
6
Icon Stone.png
8
Icon Water.png
4
Icon Chemical Plant.pngIcon Quantum Chemical Plant.png
Tech Basic Chemical Engineering.png
Icon Sulfuric Acid.png
1
1.2 s
Icon Sulfuric Acid Ocean.png
Icon Water Pump.png
Tech Fluid Storage Encapsulation.png

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
Icon Magnetic Coil.png
2
1 s
Icon Magnet.png
2
Icon Copper Ingot.png
1
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png N/A
Icon Thruster.png
1
4 s
Icon Steel.png
2
Icon Copper Ingot.png
3
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Thruster.png
Icon Circuit Board.png
2
1 s
Icon Iron Ingot.png
2
Icon Copper Ingot.png
1
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png N/A
Icon Microcrystalline Component.png
1
2 s
Icon High-Purity Silicon.png
2
Icon Copper Ingot.png
1
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Semiconductor Material.png
Icon Particle Container.png
1
4 s
Icon Electromagnetic Turbine.png
2
Icon Copper Ingot.png
2
Icon Graphene.png
2
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Magnetic Particle Trap.png
Icon Particle Container.png
1
4 s
Icon Unipolar Magnet.png
10
Icon Copper Ingot.png
2
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Magnetic Particle Trap.png
Icon Magnum Ammo Box.png
1
1 s
Icon Copper Ingot.png
3
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Weapon System.png
Icon Shell Set.png
1
1.5 s
Icon Copper Ingot.png
9
Icon Combustible Unit.png
2
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Implosion Cannon.png
Icon Missile Set.png
1
2 s
Icon Copper Ingot.png
6
Icon Circuit Board.png
3
Icon Combustible Unit.png
2
Icon Engine.png
1
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Missile Turret.png
Icon Engine.png
1
3 s
Icon Magnetic Coil.png
1
Icon Copper Ingot.png
2
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Engine.png

Buildings

Recipe Building Replicator? Technology
Icon Solar Panel.png
1
6 s
Icon Copper Ingot.png
10
Icon High-Purity Silicon.png
10
Icon Circuit Board.png
5
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Solar Collection.png
Icon Geothermal Power Station.png
1
6 s
Icon Steel.png
15
Icon Copper Ingot.png
20
Icon Photon Combiner.png
4
Icon Super-Magnetic Ring.png
1
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Geothermal Extraction.png
Icon Jammer Tower.png
1
5 s
Icon Copper Ingot.png
12
Icon Plasma Exciter.png
9
Icon Diamond.png
6
Icon Processor.png
3
Icon Assembling Machine Mk.I.pngIcon Assembling Machine Mk.II.pngIcon Assembling Machine Mk.III.pngIcon Re-composing Assembler.png
Tech Jammer Tower.png

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
🍪 We use cookies to keep session information to provide you a better experience.