local metals = dofile('data/metals.lua')
local affinities = dofile('data/affinities.lua')
sorcery = { lib = { class = dofile('lib/class.lua') } }
local u = {
tbl = dofile('lib/tbl.lua');
color = dofile('lib/color.lua');
str = dofile('lib/str.lua');
}
local tag = function(t,p,c)
if not c then c = p p = nil end
if p then p = ' ' .. p end
return string.format('<%s%s>%s</%s>', t,p or '',c,t)
end
local nulcat = function(a,b,c)
if a then
if b then
return a..(c or '')..b
else return a end
else return b end
end
local html_table = function(tbl,colprops,tblprop)
local html = ''
local header = true
local totalcols = 0
for k,v in ipairs(tbl) do
local t = 'td'
if header then t='th' end
html = html .. '<tr>'
for col,text in ipairs(v) do
local sp
if header then totalcols = totalcols + 1 else
if col == #v and #v < totalcols then
local colspan = 1 + (totalcols - #v)
sp = string.format('colspan="%u" ',colspan)
end
end
if colprops and colprops[col] then
html = html .. tag(t, nulcat(sp,colprops[col][header and 2 or 1],' '), text)
else
html = html .. tag(t, sp, text)
end
end
html = html .. '</tr>'
header = false
end
return tag('table',tblprop,html)
end
local function colorscale(scale)
return function(i)
local fac = math.max(scale.min,math.min(i,scale.max)) / scale.max
return u.color{
hue = scale.lowhue + ((scale.highhue - scale.lowhue) * fac);
saturation = 1;
luminosity = scale.lowlum + ((scale.highlum - scale.lowlum) * fac);
}
end
end
local propscales = {
props = {
durability = {10,88};
speed = {226,175};
maxenergy = {4,58};
level = {185,320};
sharpness = {240,351};
};
extents = {};
scalers = {};
};
for name,metal in pairs(metals) do
for _,p in pairs(u.tbl.keys(propscales.props)) do
if not propscales.extents[p] then propscales.extents[p] = {max=0} end
if metal[p] then
if metal[p] > propscales.extents[p].max then propscales.extents[p].max = metal[p] end
if propscales.extents[p].min == nil or
metal[p] < propscales.extents[p].min then propscales.extents[p].min = metal[p] end
end
end
end
for _,p in pairs(u.tbl.keys(propscales.props)) do
propscales.scalers[p] = colorscale {
min = propscales.extents[p].min;
max = propscales.extents[p].max;
lowhue = propscales.props[p][1];
highhue = propscales.props[p][2];
lowlum = 0.3, highlum = 0.8;
}
end
local function abbreviate(prop,i)
if i == nil then return '' end
local color = propscales.scalers[prop](i)
local sc = function(c,t)
return tag('span','style="color:'..c:hex()..'"',t)
end
if i >= 1000 then
return sc(color,tostring(i/1000)) .. sc(color:darken(0.2), 'k')
end
return sc(color,tostring(i))
end
local function maketbl(fn)
local mtbl = {
{'tier','name','durability','speed','sharp','reservoir','spell slots'}
}
local mnames = u.tbl.keys(metals)
table.sort(mnames, function(a,b)
local score = function(name)
local m = metals[name]
return ((m.durability or 1) * (m.speed or 1) * (m.slots and (#m.slots+1) or 1)) + (m.maxenergy or 0)
end
if metals[a].level < metals[b].level then return true end
if metals[a].level > metals[b].level then return false end
return score(a) < score(b)
end)
local tone_overrides = {
steel = u.color(230,230,230);
tin = u.color(190,190,190);
}
local cnfscale = colorscale {
min = 0.4, max = 3;
lowhue = 240, highhue = 326;
lowlum = 0.1, highlum = 0.8;
}
for idx,name in ipairs(mnames) do
local metal = metals[name]
if fn(metal) then
local tone = u.color(metal.tone):brighten(1.3)
local slots = '' if metal.slots then for _,s in pairs(metal.slots) do
if slots ~= '' then slots = slots .. ' ' end
local afflabels = {}
for _,a in pairs(s.affinity) do
local aff = affinities[a]
local c = u.color(aff.color):brighten(1.3)
afflabels[#afflabels+1] = string.format(tag('span','style="color:%s"','%s'),c:hex(),string.upper(string.sub(a,1,1)))
end
local ch = cnfscale(s.confluence):hex()
local popup = u.str.capitalize(table.concat(s.affinity,' or ')) .. string.format(' at %u%% confluence', math.floor(s.confluence*100))
slots = slots .. tag('span',
string.format('title="%s" style="display:inline-block; text-shadow: 0 1px black; cursor:help; padding: 0px 2.5px; border: 1px solid %s; background:radial-gradient(circle at 50%% 150%%, %s,transparent)"', popup, ch, ch),
table.concat(afflabels,''))
end end
if tone_overrides[name] then tone = tone_overrides[name] end
local tier = ''
if metal.level > 0 or metal.maxlevel and metal.maxlevel > 0 then
for i=1,metal.level or 0 do tier = tier .. '🛡' end
for i=1,(metal.maxlevel or metal.level or 0) - metal.level do
tier = '⛏' .. tier
end
end
local image = string.format('<img style="vertical-align:middle" width=16 height=16 src="doc/tip/textures/sorcery_%s_fragment.png">', name)
mtbl[#mtbl+1] = {
tier;
image .. ' ' .. tag('a',string.format('href="wiki?name=%s" style="color:%s"',name,tone:hex()),name);
abbreviate('durability',metal.durability);
abbreviate('speed',metal.speed);
abbreviate('sharpness',metal.sharpness);
abbreviate('maxenergy',metal.maxenergy or 0);
slots;
}
end
end
return(html_table(mtbl, {
[1] = {'align=right style="font-size:60%"','width="18%"'};
[2] = {nil,'style="text-align:left;padding-left:22px" width="21%"'};
[3] = {'align=right','width="9%"'};
[4] = {'align=right','width="9%"'};
[5] = {'align=right','width="9%"'};
[6] = {'align=right','width="9%"'};
[7] = {'align=center','style="text-align:center" width="25%"'};
}, 'style="width:80%;border-spacing: 0 5px;margin:auto"'))
end
local function genindex(out)
out:write [[
<!-- generated by util/tblgen-metals.lua -- do not edit by hand! -->
# metals
metals are materials found by mining. `sorcery` extends the properties of metals and adds many more than are included in the base game, as well as alloys, materials formed from a combination of multiple metals.
## properties
a metal is characterized by a number of key properties.
* its **durability** governs how many blocks you can mine with a tool made of this metal before the tool will break
* its **speed** determines how fast you can break blocks with a tool
* its **sharpness** determines how severe wounds inflicted with a sword made of this metal can be
* its **reservoir** is the maximum ley-charge tools can hold
* its **spell slots** control what kinds of spells can be placed on a tool, in what combination, and at what level of efficacy
## elemental metal index
these metals are found through mining in the form of ore, which can be smelted in the Furnace to purify it and turn it into ingots, which are very useful crafting ingredients.
]]
out:write(maketbl(function(m) return m.artificial ~= true end))
out:write [[
## alloy index
these metals are created by combining metals with the [Smelter](wiki?name=smelting).
]]
out:write(maketbl(function(m) return m.artificial == true end))
out:close()
end
local function conjoin(list,word)
local s
for i,w in ipairs(list) do
if s then
if i == #list then
s = s .. ', ' .. word .. ' ' .. w
else
s = s .. ', ' .. w
end
else s = w end
end
return s
end
local function gentpl(metalname)
local m = metals[metalname]
local tone = u.color(m.tone)
local origin
if m.artificial then
if m.mix and m.mix.metals then
origin = 'an alloy of ' .. conjoin(u.tbl.keys(m.mix.metals), 'and')
elseif m.sinter then
origin = 'an alloy produced by sintering ' .. conjoin(u.tbl.uniq(m.sinter), 'and') .. ' powder'
else
origin = 'an artificial metal'
end
else
origin = 'a naturally occurring element found at ' .. tostring((m.depth) / 1000) .. 'km below the surface'
end
local facts = {}
local frag_uses, ing_uses = '', ''
if m.conduct then
frag_uses = frag_uses .. tag('li', 'crafting cables')
facts[#facts+1] = 'it conducts ley current at ' .. tostring(m.conduct) .. ' thaum.'
end
if not m.no_tools then ing_uses = ing_uses .. tag('li', 'crafting tools and weapons') end
if not m.no_armor then ing_uses = ing_uses .. tag('li', 'crafting armor') end
local page = string.format(
'# %s\n' ..
'%s is %s.%s\n\n',
metalname, metalname,
origin,
(#facts ~= 0) and (' ' .. table.concat(facts,' ')) or '')
if m.artificial then
end
local img = function(p)
return string.format('<img src="doc/tip/textures/sorcery_%s.png" style="image-rendering:crisp-edges;image-rendering:pixelated;width:2em;height:2em;vertical-align:middle;">',p)
end
local nm = u.str.capitalize(metalname)
local forms = {
{'','form','produced by'};
{'',tag('strong',nm .. ' Ore'), m.artificial and 'alloying' or 'mining'};
{'',tag('ul',tag('li','can be smelted to produce ingots'))};
{'',tag('strong',nm .. ' Ingot'), 'smelting ore'};
{'',tag('ul',tag('li','used in crafting recipes') .. ing_uses)};
{img(metalname..'_fragment'), tag('strong', nm .. ' Fragment'), 'cooking ingot or powder in Furnace'};
{'',tag('ul',tag('li','used in smelting to achieve proper metal ratios in alloys') .. frag_uses)};
{img(metalname..'_powder'), tag('strong', nm .. ' Powder'), 'grinding metal in Mill'};
};
page = page ..
html_table(forms,{
[1] = {'style="text-align:right"','style="width:2em"'};
[2] = {nil, 'style="text-align:center;width:20%"'};
[3] = {'style="font-style:italic"', 'style="text-align:center"'};
},string.format('style="border-spacing:0;padding:0.5em;border:1px solid %s"', tone:hex()))
return page
end
local out
local args = {...}
if args[1] == 'test' then
genindex(io.stdout)
elseif args[1] == 'commit' then
genindex(io.popen('fossil wiki commit metals -M markdown','w'))
elseif args[1] == 'tpl' then
print(gentpl(args[2]))
else
print('usage: lua util/tblgen-metals.lua (test|commit)')
os.exit(64)
end