Module:GameData: Difference between revisions

From the Dyson Sphere Program Wiki
(Sort recipes by GridIndex)
(Add Dark Fog drop to list of recipes making items)
 
(3 intermediate revisions by the same user not shown)
Line 19: Line 19:


-- exported functions
-- 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 33: Line 37:
}
}
local item = itemByName(name)
local item = itemByName(name)
for _, recipe in pairs(recipeSort(recipesMakingByID(item.ID))) do
for _, recipe in ipairs(recipesMakingByID(item.ID)) do
table.insert(rtable, recipeRow(recipe, frame))
table.insert(rtable, recipeRow(recipe, frame))
end
end
Line 40: Line 44:
table.insert(rtable, veinRow(item, vein, frame))
table.insert(rtable, veinRow(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(rtable, gasGiantRow(item, giant, frame))
table.insert(rtable, gasGiantRow(item, giant, frame))
end
end
if isItemOcean(item.ID) then
if isItemOcean(item.ID) then
table.insert(rtable, oceanRow(item, frame))
table.insert(rtable, oceanRow(item, frame))
end
if isItemFogDrop(item) then
table.insert(rtable, fogDropRow(item, frame))
end
end
table.insert(rtable, '|}')
table.insert(rtable, '|}')
return table.concat(rtable, '\n')
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 62: Line 73:
local header = frame:expandTemplate{title='ProductionChainTable/head', args={}}
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, '=== Components ===')
end
table.insert(output, header)
table.insert(output, header)
for _, recipe in pairs(recipeSort(components)) do
for _, recipe in ipairs(components) do
table.insert(output, recipeRow(recipe, frame))
table.insert(output, recipeRow(recipe, frame))
end
end
Line 72: Line 93:
end
end
if next(buildings) then
if next(buildings) then
table.insert(output, '=== Buildings ===')
if next(components) then
table.insert(output, '=== Buildings ===')
end
table.insert(output, header)
table.insert(output, header)
for _, recipe in pairs(recipeSort(buildings)) do
for _, recipe in ipairs(buildings) do
table.insert(output, recipeRow(recipe, frame))
table.insert(output, recipeRow(recipe, frame))
end
end
Line 81: Line 104:
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 92: Line 119:
local item = itemByName(name)
local item = itemByName(name)
local output = {}
local output = {}
for _, r in pairs(recipeSort(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 99: 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
end
if isItemOcean(item.ID) then
if isItemOcean(item.ID) then
table.insert(rtable, oceanRecipe(item, frame))
table.insert(output, oceanRecipe(item, frame))
end
end
return table.concat(output, '\n')
return table.concat(output, '\n')
end
end
-- itemField
-- print a field from an item
-- used to extract details about an item


function funcs.itemField(frame)
function funcs.itemField(frame)
Line 120: Line 151:
end
end


-- make rows and recipe data for tables
-- make full rows and recipe data for tables


function recipeRow(recipe, frame)
function recipeRow(recipe, frame)
Line 141: Line 172:
else
else
rdata.Technology = ''
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
end
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=rdata}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=rdata}
Line 185: Line 225:
Technology = titleCase(extractorTech.Name),
Technology = titleCase(extractorTech.Name),
Recipe = oilRecipe(item, vein, frame),
Recipe = oilRecipe(item, vein, frame),
Proliferator='No',
}
}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oildata}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oildata}
Line 195: Line 236:
Technology = titleCase(minerTech.Name),
Technology = titleCase(minerTech.Name),
Recipe = veinRecipe(item, vein, frame),
Recipe = veinRecipe(item, vein, frame),
Proliferator='No',
}
}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=veindata}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=veindata}
Line 230: Line 272:
Replicator = 'Mine',
Replicator = 'Mine',
Technology = titleCase(collectorTech.Name),
Technology = titleCase(collectorTech.Name),
Recipe = gasGiantRecipe(giant, frame)
Recipe = gasGiantRecipe(giant, frame),
Proliferator='No',
}
}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=giantdata}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=giantdata}
Line 247: Line 290:
end
end
return frame:expandTemplate{title='ItemRecipe', args=gdata}
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
end


Line 256: Line 324:
Replicator = 'No',
Replicator = 'No',
Technology = titleCase(pumpTech.Name),
Technology = titleCase(pumpTech.Name),
Recipe = oceanRecipe(item, frame)
Recipe = oceanRecipe(item, frame),
Proliferator='No',
}
}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata}
return '|-\n| ' .. frame:expandTemplate{title='ProductionChain', args=oceandata}
Line 276: Line 345:
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 284: 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 294: 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 305: 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 recipe.GridIndex >= 2000 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 334: 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 344: 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 356: Line 420:


function isItemOcean(id)
function isItemOcean(id)
for _, planet in pairs(protosets.ThemeProtoSet.dataArray) do
for _, planet in ipairs(protosets.ThemeProtoSet.dataArray) do
if id == planet.WaterItemId then
if id == planet.WaterItemId then
return true
return true
Line 362: Line 426:
end
end
return false
return false
end
function isItemFogDrop(item)
return item.EnemyDropRange.y > 0
end
end


-- sorting/deduplication
-- sorting/deduplication
function recipeSort(recipes)
table.sort(recipes, function(a, b)
return a.GridIndex < b.GridIndex
end)
return recipes
end


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

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.