Module:GameData: Difference between revisions

From the Dyson Sphere Program Wiki
(Show fractionator percentage instead of time, possibly add infobox recipes?)
(Add Dark Fog drop to list of recipes making items)
 
(10 intermediate revisions by the same user not shown)
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
-- 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)
Line 24: Line 33:


function recipesMakingName(name, frame)
function recipesMakingName(name, frame)
local rtable = {
frame:expandTemplate{title='ProductionChainTable/head', args={}},
}
local item = itemByName(name)
local item = itemByName(name)
local recipes = recipesMakingByID(item.ID)
for _, recipe in ipairs(recipesMakingByID(item.ID)) do
table.insert(rtable, recipeRow(recipe, frame))
end
local vein = veinMakingByID(item.ID)
local vein = veinMakingByID(item.ID)
local gas = deduplicateGiants(gasGiantsMakingByID(item.ID))
if vein ~= nil then
return tableRecipes(item, recipes, vein, gas, frame)
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)
Line 41: Line 71:
function recipesUsingName(name, frame)
function recipesUsingName(name, frame)
local output = {}
local output = {}
local header = frame:expandTemplate{title='ProductionChainTable/head', args={}}
local item = itemByName(name)
local item = itemByName(name)
local components, buildings = recipesUsingByID(item.ID)
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(item, components, nil, nil, 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(item, buildings, nil, nil, 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
-- itemRecipes
-- print out just recipe information on how to make an item
-- intended for use in ItemInfo boxes


function funcs.itemRecipes(frame)
function funcs.itemRecipes(frame)
Line 64: Line 119:
local item = itemByName(name)
local item = itemByName(name)
local output = {}
local output = {}
for _, r in pairs(recipesMakingByID(item.ID)) do
for _, r in ipairs(recipesMakingByID(item.ID)) do
table.insert(output, itemRecipe(r, frame))
table.insert(output, itemRecipe(r, frame))
end
end
Line 71: Line 126:
table.insert(output, veinRecipe(item, vein, frame))
table.insert(output, veinRecipe(item, vein, frame))
end
end
for _, giant in pairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do
for _, giant in ipairs(deduplicateGiants(gasGiantsMakingByID(item.ID))) do
table.insert(output, gasGiantRecipe(giant, frame))
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


function tableRecipes(item, recipes, vein, gas, frame)
-- itemField
local result = {}
-- print a field from an item
for _, recipe in pairs(recipes) do
-- used to extract details about an item
local data = {
 
Building = titleCase(machines[recipe.Type]),
function funcs.itemField(frame)
Recipe = itemRecipe(recipe, frame)
return itemFieldByName(frame:getParent().args[1], frame:getParent().args[2])
}
end
if recipe.Handcraft then
function funcs.itemFieldDirect(frame)
data.Replicator = 'Yes'
return itemFieldByName(frame.args[1], frame.args[2])
else
end
data.Replicator = 'No'
 
end
function itemFieldByName(itemname, fieldname)
local tech = technologyForRecipeID(recipe.ID)
local item = itemByName(itemname)
if tech ~= nil then
return item[fieldname]
data.Technology = titleCase(tech.Name)
end
else
 
data.Technology = ''
-- make full rows and recipe data for tables
end
 
table.insert(result, '| ' .. frame:expandTemplate{title='ProductionChain', args=data})
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
end
if vein then
local productive = not recipe.NonProductive
local miner = itemByName(machines.Mine)
for i, itemid in ipairs(recipe.Items) do
local minerTech = technologyForRecipeID(recipesMakingByID(miner.ID)[1].ID)
productive = productive and itemByID(itemid).Productive
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
end
if gas then
if productive then
local collector = itemByName(machines.Gas)
rdata.Proliferator = 'Yes'
local collectorTech = technologyForRecipeID(recipesMakingByID(collector.ID)[1].ID)
else
for _, giant in pairs(gas) do
rdata.Proliferator = 'Speed'
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
end
local prefix = frame:expandTemplate{title='ProductionChainTable/head', args={}}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=rdata}
return string.format('%s\n%s\n|}', prefix, table.concat(result, '\n|-\n'))
end
end


function itemRecipe(recipe, frame)
function itemRecipe(recipe, frame)
if recipe.Type == 'Fractionate' then
return fractionateRecipe(recipe, frame)
end
local rdata = {
local rdata = {
CraftTime = string.format('%s s', tostring(recipe.TimeSpend/60)),
CraftTime = string.format('%s s', tostring(recipe.TimeSpend/60)),
Line 157: Line 214:
end
end
return frame:expandTemplate{title='ItemRecipe', args=rdata}
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
end


Line 169: Line 252:
}
}
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
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
end


Line 184: Line 291:
return frame:expandTemplate{title='ItemRecipe', args=gdata}
return frame:expandTemplate{title='ItemRecipe', args=gdata}
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)
local lame = string.lower(name)
local lame = string.lower(name)
for _, item in pairs(protosets.ItemProtoSet.dataArray) do
for _, item in ipairs(protosets.ItemProtoSet.dataArray) do
if string.lower(item.Name) == lame then
if string.lower(item.Name) == lame then
return item
return item
Line 195: 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 205: Line 363:
function recipesMakingByID(id)
function recipesMakingByID(id)
local 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 216: Line 374:
end
end
function recipesUsingByID(id)
function recipesUsingByID(id)
local components = {}
local recipes = {}
local 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 245: Line 398:


function veinMakingByID(id)
function veinMakingByID(id)
for _, vein in pairs(protosets.VeinProtoSet.dataArray) do
for _, vein in ipairs(protosets.VeinProtoSet.dataArray) do
if vein.MiningItem == id then
if vein.MiningItem == id then
return vein
return vein
Line 255: Line 408:
function gasGiantsMakingByID(id)
function gasGiantsMakingByID(id)
local giants = {}
local giants = {}
for _, planet in pairs(protosets.ThemeProtoSet.dataArray) do
for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do
for _, item in pairs(planet.GasItems) do
for _, item in ipairs(planet.GasItems) do
if item == id then
if item == id then
table.insert(giants, planet)
table.insert(giants, planet)
Line 265: Line 418:
return giants
return giants
end
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)
function deduplicateGiants(giants)
local dedup = {}
local dedup = {}
for _, planet in pairs(giants) do
for _, planet in ipairs(giants) do
new = true
new = true
for _, exist in pairs(dedup) do
for _, exist in ipairs(dedup) do
if string.lower(planet.DisplayName) == string.lower(exist.DisplayName) then
if string.lower(planet.DisplayName) == string.lower(exist.DisplayName) then
new = false
new = false
Line 280: Line 448:
return dedup
return dedup
end
end
-- display formatting


function titleCase(str)
function titleCase(str)
local start = string.gsub(str, '^%l', string.upper)
local start = string.gsub(str, '^%l', string.upper)
local title = string.gsub(start, '[-%s]%l', string.upper)
local title = string.gsub(start, '[-%s]%l', string.upper)
return title
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.