Module:Skill: Difference between revisions
Jump to navigation
Jump to search
>OmegaK2 mNo edit summary |
>OmegaK2 (fixes, skill level progression) |
||
Line 6: | Line 6: | ||
local util = require('Module:Util') | local util = require('Module:Util') | ||
local mwlanguage = mw.language.getContentLanguage() | |||
-- | -- | ||
Line 76: | Line 77: | ||
property = 'Has level requirement', | property = 'Has level requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = util.html.abbr('[[Image:Level_up_icon_small.png|link=|Lvl.]]', 'Required Level', 'nounderline'), | |||
}, | }, | ||
{ | { | ||
Line 81: | Line 83: | ||
property = 'Has dexterity requirement', | property = 'Has dexterity requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = util.html.abbr('[[Image:DexterityIcon_small.png|link=|dexterity]]', 'Required Dexterity', 'nounderline'), | |||
}, | }, | ||
{ | { | ||
name = 'strength_requirement', | name = 'strength_requirement', | ||
property = 'Has | property = 'Has strength requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = util.html.abbr('[[Image:StrengthIcon_small.png|link=|strength]]', 'Required Strength', 'nounderline'), | |||
}, | }, | ||
{ | { | ||
Line 91: | Line 95: | ||
property = 'Has intelligence requirement', | property = 'Has intelligence requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = util.html.abbr('[[Image:IntelligenceIcon_small.png|link=|intelligence]]', 'Required Intelligence', 'nounderline'), | |||
}, | }, | ||
{ | { | ||
Line 96: | Line 101: | ||
property = 'Has mana multiplier', | property = 'Has mana multiplier', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Mana<br>Multiplier', | |||
}, | }, | ||
{ | { | ||
Line 101: | Line 107: | ||
property = 'Has critical strike chance', | property = 'Has critical strike chance', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Critical<br>Strike<br>Chance', | |||
}, | }, | ||
{ | { | ||
Line 106: | Line 113: | ||
property = 'Has mana cost', | property = 'Has mana cost', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Mana<br>Cost', | |||
}, | }, | ||
{ | { | ||
Line 111: | Line 119: | ||
property = 'Has damage effectiveness', | property = 'Has damage effectiveness', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Damage<br>Effectiveness', | |||
}, | }, | ||
{ | { | ||
Line 116: | Line 125: | ||
property = 'Has stored uses', | property = 'Has stored uses', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Stored<br>Uses', | |||
}, | }, | ||
{ | { | ||
Line 121: | Line 131: | ||
property = 'Has cooldown', | property = 'Has cooldown', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Cooldown', | |||
}, | }, | ||
{ | { | ||
Line 126: | Line 137: | ||
property = 'Has vaal souls requirement', | property = 'Has vaal souls requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Vaal<br>souls', | |||
}, | }, | ||
{ | { | ||
Line 131: | Line 143: | ||
property = 'Has vaal stored uses', | property = 'Has vaal stored uses', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Stored<br>Uses', | |||
}, | }, | ||
{ | { | ||
Line 136: | Line 149: | ||
property = 'Has damage multiplier', | property = 'Has damage multiplier', | ||
func = util.cast.number, | func = util.cast.number, | ||
header = 'Damage<br>Multiplier', | |||
}, | }, | ||
-- from gem experience, optional | -- from gem experience, optional | ||
Line 142: | Line 156: | ||
property = 'Has experience requirement', | property = 'Has experience requirement', | ||
func = util.cast.number, | func = util.cast.number, | ||
hide = true, | |||
}, | |||
{ | |||
name = 'stat_text', | |||
property = 'Has stat text', | |||
func = nil, | |||
hide = true, | |||
}, | |||
{ | |||
name = 'quality_stat_text', | |||
property = 'Has quality stat text', | |||
func = nil, | |||
hide = true, | |||
}, | }, | ||
} | } | ||
Line 196: | Line 223: | ||
properties[stat_type.property_prefix .. 'id'] = table.concat(stat_ids, ',') | properties[stat_type.property_prefix .. 'id'] = table.concat(stat_ids, ',') | ||
properties[stat_type.property_prefix .. 'value'] = table.concat(stat_values, ',') | properties[stat_type.property_prefix .. 'value'] = table.concat(stat_values, ',') | ||
end | |||
end | |||
function h.na(tr) | |||
tr | |||
:tag('td') | |||
:attr('class', 'table-na') | |||
:wikitext('N/A') | |||
:done() | |||
end | |||
function h.int_value_or_na(tr, value) | |||
value = tonumber(value) | |||
if value == nil then | |||
h.na(tr) | |||
else | |||
tr | |||
:tag('td') | |||
:wikitext(mwlanguage:formatNum(value)) | |||
:done() | |||
end | end | ||
end | end | ||
Line 234: | Line 281: | ||
h.map_to_arg(properties, prefix, data.map.progression) | h.map_to_arg(properties, prefix, data.map.progression) | ||
h.stats(properties, prefix) | h.stats(properties, prefix) | ||
properties['Is skill level'] = i | |||
g_frame:callParserFunction('#subobject: level' .. i , properties) | g_frame:callParserFunction('#subobject: level' .. i , properties) | ||
Line 248: | Line 296: | ||
g_args.max_level = maxlevel | g_args.max_level = maxlevel | ||
g_frame:callParserFunction('#set:', properties) | g_frame:callParserFunction('#set:', properties) | ||
end | |||
function p.progression(frame) | |||
g_args = getArgs(frame, { | |||
parentFirst = true | |||
}) | |||
g_frame = util.misc.get_frame(frame) | |||
-- | |||
g_args.stat_format = {} | |||
local prefix | |||
for i=1, 9 do | |||
prefix = 'c' .. i .. '_' | |||
local statfmt = { | |||
header = g_args[prefix .. 'header'], | |||
abbr = g_args[prefix .. 'abbr'], | |||
pattern_extract = g_args[prefix .. 'pattern_extract'], | |||
pattern_value = g_args[prefix .. 'pattern_value'], | |||
} | |||
if util.table.has_all_value(statfmt, {'header', 'abbr', 'pattern_extract', 'pattern_value'}) then | |||
break | |||
end | |||
if util.table.has_one_value(statfmt, {'header', 'abbr', 'pattern_extract', 'pattern_value'}) then | |||
error(string.format('All formatting keys must be specified for index "%s"', i)) | |||
end | |||
statfmt.header = util.html.abbr(statfmt.abbr, statfmt.header) | |||
statfmt.abbr = nil | |||
g_args.stat_format[#g_args.stat_format+1] = statfmt | |||
end | |||
local result | |||
local query | |||
local page | |||
if g_args.skill_id then | |||
query = {} | |||
query[#query+1] = string.format('[[Is skill id::%s]]', g_args.skill_id) | |||
query['limit'] = 1 | |||
result = util.smw.query(query, g_frame) | |||
if #result == 0 or #result[1] == 0 then | |||
error('Couldn\'t find a page for the specified skill id') | |||
end | |||
page = result[1][1] | |||
else | |||
page = mw.title.getCurrentTitle().prefixedText | |||
end | |||
query = {} | |||
query[#query+1] = string.format('[[-Has subobject::%s]]', page) | |||
for _, pdata in ipairs(data.map.progression) do | |||
query[#query+1] = '?' .. pdata.property | |||
end | |||
query[#query+1] = '?Is skill level' | |||
query[#query+1] = '?Has stat text' | |||
query[#query+1] = '?Has stat id' | |||
query[#query+1] = '?Has stat value' | |||
query[#query+1] = '?Has quality stat id' | |||
query[#query+1] = '?Has quality stat value' | |||
query.sort = 'Has level requirement' | |||
result = util.smw.query(query, g_frame) | |||
if #result == 0 then | |||
error('No gem level progression data found') | |||
end | |||
headers = {} | |||
for i, row in ipairs(result) do | |||
for k, v in pairs(row) do | |||
if v ~= "" then | |||
headers[k] = true | |||
end | |||
end | |||
end | |||
local tbl = mw.html.create('table') | |||
tbl:attr('class', 'wikitable GemLevelTable') | |||
local head = tbl:tag('tr') | |||
head | |||
:tag('th') | |||
:wikitext('Level') | |||
:done() | |||
for _, pdata in ipairs(data.map.progression) do | |||
-- TODO should be nil? | |||
if pdata.hide == nil and headers[pdata.property] then | |||
head | |||
:tag('th') | |||
:wikitext(pdata.header) | |||
:done() | |||
end | |||
end | |||
for _, statfmt in ipairs(g_args.stat_format) do | |||
head | |||
:tag('th') | |||
:wikitext(statfmt.header) | |||
:done() | |||
end | |||
if headers['Has experience requirement'] then | |||
head | |||
:tag('th') | |||
:wikitext(util.html.abbr('Exp.', 'Experience Needed to Level Up')) | |||
:done() | |||
:tag('th') | |||
:wikitext(util.html.abbr('Total Exp.', 'Total experience needed')) | |||
:done() | |||
end | |||
local tblrow | |||
local lastexp = 0 | |||
local experience | |||
for i, row in ipairs(result) do | |||
tblrow = tbl:tag('tr') | |||
tblrow | |||
:tag('th') | |||
:wikitext(row['Is skill level']) | |||
:done() | |||
for _, pdata in ipairs(data.map.progression) do | |||
if pdata.hide == nil and headers[pdata.property] then | |||
h.int_value_or_na(tblrow, row[pdata.property]) | |||
end | |||
end | |||
-- stats | |||
stats = util.string.split(row['Has stat text'], '<br>') | |||
for _, statfmt in ipairs(g_args.stat_format) do | |||
local match | |||
for j, stat in ipairs(stats) do | |||
match = string.match(stat, statfmt.pattern_extract) | |||
if match ~= nil then | |||
-- TODO maybe remove stat here to avoid testing against in future loops | |||
break | |||
end | |||
end | |||
if match == nil then | |||
h.na(tblrow) | |||
else | |||
tblrow | |||
:tag('td') | |||
:wikitext(string.format(statfmt.pattern_value, match[1], match[2], match[3], match[4], match[5])) | |||
:done() | |||
end | |||
end | |||
-- TODO: Quality stats, afaik no gems use this atm | |||
if headers['Has experience requirement'] then | |||
experience = tonumber(row['Has experience requirement']) | |||
if experience ~= nil then | |||
h.int_value_or_na(tblrow, experience - lastexp) | |||
lastexp = experience | |||
else | |||
h.na(tblrow) | |||
end | |||
h.int_value_or_na(tblrow, experience) | |||
end | |||
end | |||
-- TODO | |||
return tostring(tbl) | |||
end | end | ||
return p | return p |
Revision as of 14:50, 14 March 2016
Module for handling skills with Cargo support.
Implemented templates
- {{Skill}}
- {{Skill progression}}
The above documentation is transcluded from Module:Skill/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
local p = {}
local g_frame, g_args
local getArgs = require('Module:Arguments').getArgs
local util = require('Module:Util')
local mwlanguage = mw.language.getContentLanguage()
--
-- Data
--
local data = {}
data.map = {}
data.map.stats = {
{
prefix = '',
property_prefix = 'Has stat ',
},
{
prefix = 'quality_',
property_prefix = 'Has quality stat ',
},
}
data.map.static = {
-- GrantedEffects.dat
{
name = 'skill_id',
property = 'Is skill id',
func = nil,
},
{
name = 'is_support_gem',
property = 'Is support gem',
func = util.cast.bool,
},
{
name = 'support_gem_letter',
property = 'Has support gem letter',
func = nil,
},
-- Active Skills.dat
{
name = 'cast_time',
property = 'Has cast time',
func = util.cast.number,
},
{
name = 'gem_description',
property = 'Has description',
func = nil,
},
{
name = 'active_skill_name',
property = 'Has active skill name',
func = nil,
},
-- Misc data
{
name = 'stat_text',
property = 'Has stat text',
func = nil,
},
{
name = 'quality_stat_text',
property = 'Has quality stat text',
func = nil,
},
}
data.map.progression = {
{
name = 'level_requirement',
property = 'Has level requirement',
func = util.cast.number,
header = util.html.abbr('[[Image:Level_up_icon_small.png|link=|Lvl.]]', 'Required Level', 'nounderline'),
},
{
name = 'dexterity_requirement',
property = 'Has dexterity requirement',
func = util.cast.number,
header = util.html.abbr('[[Image:DexterityIcon_small.png|link=|dexterity]]', 'Required Dexterity', 'nounderline'),
},
{
name = 'strength_requirement',
property = 'Has strength requirement',
func = util.cast.number,
header = util.html.abbr('[[Image:StrengthIcon_small.png|link=|strength]]', 'Required Strength', 'nounderline'),
},
{
name = 'intelligence_requirement',
property = 'Has intelligence requirement',
func = util.cast.number,
header = util.html.abbr('[[Image:IntelligenceIcon_small.png|link=|intelligence]]', 'Required Intelligence', 'nounderline'),
},
{
name = 'mana_multiplier',
property = 'Has mana multiplier',
func = util.cast.number,
header = 'Mana<br>Multiplier',
},
{
name = 'critical_strike_chance',
property = 'Has critical strike chance',
func = util.cast.number,
header = 'Critical<br>Strike<br>Chance',
},
{
name = 'mana_cost',
property = 'Has mana cost',
func = util.cast.number,
header = 'Mana<br>Cost',
},
{
name = 'damage_effectiveness',
property = 'Has damage effectiveness',
func = util.cast.number,
header = 'Damage<br>Effectiveness',
},
{
name = 'stored_uses',
property = 'Has stored uses',
func = util.cast.number,
header = 'Stored<br>Uses',
},
{
name = 'cooldown',
property = 'Has cooldown',
func = util.cast.number,
header = 'Cooldown',
},
{
name = 'vaal_souls_requirement',
property = 'Has vaal souls requirement',
func = util.cast.number,
header = 'Vaal<br>souls',
},
{
name = 'vaal_stored_uses',
property = 'Has vaal stored uses',
func = util.cast.number,
header = 'Stored<br>Uses',
},
{
name = 'damage_multiplier',
property = 'Has damage multiplier',
func = util.cast.number,
header = 'Damage<br>Multiplier',
},
-- from gem experience, optional
{
name = 'experience',
property = 'Has experience requirement',
func = util.cast.number,
hide = true,
},
{
name = 'stat_text',
property = 'Has stat text',
func = nil,
hide = true,
},
{
name = 'quality_stat_text',
property = 'Has quality stat text',
func = nil,
hide = true,
},
}
--
-- Helper functions
--
local h = {}
function h.map_to_arg(properties, prefix, map)
local id
local val
for _, row in ipairs(map) do
id = prefix .. row.name
val = g_args[id]
if val ~= nil then
if row.func ~= nil then
val = row.func(val)
end
g_args[id] = val
properties[row.property] = val
end
end
end
function h.stats(properties, prefix)
local stat_ids
local stat_values
local stat_id
local stat_id_key
local stat_val
local stat_val_key
local type_prefix
for _, stat_type in ipairs(data.map.stats) do
type_prefix = string.format('%s%sstat', prefix, stat_type.prefix)
stat_ids = {}
stat_values = {}
for i=1, 8 do
stat_id_key = string.format('%s%s_id', type_prefix, i)
stat_val_key = string.format('%s%s_value', type_prefix, i)
stat_id = g_args[stat_id_key]
stat_val = tonumber(g_args[stat_val_key])
if stat_id == nil or stat_val == nil then
break
end
g_args[stat_val_key] = stat_val
stat_ids[#stat_ids+1] = stat_id
stat_values[#stat_values+1] = stat_val
end
g_args[type_prefix .. 's_ids'] = stat_ids
g_args[type_prefix .. 's_values'] = stat_values
properties[stat_type.property_prefix .. 'id'] = table.concat(stat_ids, ',')
properties[stat_type.property_prefix .. 'value'] = table.concat(stat_values, ',')
end
end
function h.na(tr)
tr
:tag('td')
:attr('class', 'table-na')
:wikitext('N/A')
:done()
end
function h.int_value_or_na(tr, value)
value = tonumber(value)
if value == nil then
h.na(tr)
else
tr
:tag('td')
:wikitext(mwlanguage:formatNum(value))
:done()
end
end
--
-- For Template:Skill
--
function p.skill(frame, args)
if args ~= nil then
g_args = args
else
g_args = getArgs(frame, {
parentFirst = true
})
end
g_frame = util.misc.get_frame(frame)
--
-- Args
--
local properties = {}
-- Handle static arguments
h.map_to_arg(properties, '', data.map.static)
h.map_to_arg(properties, 'static_', data.map.progression)
h.stats(properties, 'static_')
g_frame:callParserFunction('#set:', properties)
-- Handle level progression
local maxlevel
local prefix
for i=1, 30 do
properties = {}
prefix = string.format('level%s_', i)
if util.cast.boolean(prefix) then
h.map_to_arg(properties, prefix, data.map.progression)
h.stats(properties, prefix)
properties['Is skill level'] = i
g_frame:callParserFunction('#subobject: level' .. i , properties)
if g_args[prefix .. 'experience'] ~= nil and g_args[prefix .. 'experience'] > 0 then
maxlevel = i
end
end
end
properties = {
['Has maximum skill level'] = maxlevel
}
g_args.max_level = maxlevel
g_frame:callParserFunction('#set:', properties)
end
function p.progression(frame)
g_args = getArgs(frame, {
parentFirst = true
})
g_frame = util.misc.get_frame(frame)
--
g_args.stat_format = {}
local prefix
for i=1, 9 do
prefix = 'c' .. i .. '_'
local statfmt = {
header = g_args[prefix .. 'header'],
abbr = g_args[prefix .. 'abbr'],
pattern_extract = g_args[prefix .. 'pattern_extract'],
pattern_value = g_args[prefix .. 'pattern_value'],
}
if util.table.has_all_value(statfmt, {'header', 'abbr', 'pattern_extract', 'pattern_value'}) then
break
end
if util.table.has_one_value(statfmt, {'header', 'abbr', 'pattern_extract', 'pattern_value'}) then
error(string.format('All formatting keys must be specified for index "%s"', i))
end
statfmt.header = util.html.abbr(statfmt.abbr, statfmt.header)
statfmt.abbr = nil
g_args.stat_format[#g_args.stat_format+1] = statfmt
end
local result
local query
local page
if g_args.skill_id then
query = {}
query[#query+1] = string.format('[[Is skill id::%s]]', g_args.skill_id)
query['limit'] = 1
result = util.smw.query(query, g_frame)
if #result == 0 or #result[1] == 0 then
error('Couldn\'t find a page for the specified skill id')
end
page = result[1][1]
else
page = mw.title.getCurrentTitle().prefixedText
end
query = {}
query[#query+1] = string.format('[[-Has subobject::%s]]', page)
for _, pdata in ipairs(data.map.progression) do
query[#query+1] = '?' .. pdata.property
end
query[#query+1] = '?Is skill level'
query[#query+1] = '?Has stat text'
query[#query+1] = '?Has stat id'
query[#query+1] = '?Has stat value'
query[#query+1] = '?Has quality stat id'
query[#query+1] = '?Has quality stat value'
query.sort = 'Has level requirement'
result = util.smw.query(query, g_frame)
if #result == 0 then
error('No gem level progression data found')
end
headers = {}
for i, row in ipairs(result) do
for k, v in pairs(row) do
if v ~= "" then
headers[k] = true
end
end
end
local tbl = mw.html.create('table')
tbl:attr('class', 'wikitable GemLevelTable')
local head = tbl:tag('tr')
head
:tag('th')
:wikitext('Level')
:done()
for _, pdata in ipairs(data.map.progression) do
-- TODO should be nil?
if pdata.hide == nil and headers[pdata.property] then
head
:tag('th')
:wikitext(pdata.header)
:done()
end
end
for _, statfmt in ipairs(g_args.stat_format) do
head
:tag('th')
:wikitext(statfmt.header)
:done()
end
if headers['Has experience requirement'] then
head
:tag('th')
:wikitext(util.html.abbr('Exp.', 'Experience Needed to Level Up'))
:done()
:tag('th')
:wikitext(util.html.abbr('Total Exp.', 'Total experience needed'))
:done()
end
local tblrow
local lastexp = 0
local experience
for i, row in ipairs(result) do
tblrow = tbl:tag('tr')
tblrow
:tag('th')
:wikitext(row['Is skill level'])
:done()
for _, pdata in ipairs(data.map.progression) do
if pdata.hide == nil and headers[pdata.property] then
h.int_value_or_na(tblrow, row[pdata.property])
end
end
-- stats
stats = util.string.split(row['Has stat text'], '<br>')
for _, statfmt in ipairs(g_args.stat_format) do
local match
for j, stat in ipairs(stats) do
match = string.match(stat, statfmt.pattern_extract)
if match ~= nil then
-- TODO maybe remove stat here to avoid testing against in future loops
break
end
end
if match == nil then
h.na(tblrow)
else
tblrow
:tag('td')
:wikitext(string.format(statfmt.pattern_value, match[1], match[2], match[3], match[4], match[5]))
:done()
end
end
-- TODO: Quality stats, afaik no gems use this atm
if headers['Has experience requirement'] then
experience = tonumber(row['Has experience requirement'])
if experience ~= nil then
h.int_value_or_na(tblrow, experience - lastexp)
lastexp = experience
else
h.na(tblrow)
end
h.int_value_or_na(tblrow, experience)
end
end
-- TODO
return tostring(tbl)
end
return p