>OmegaK2 |
>OmegaK2 |
Line 1: |
Line 1: |
| -- ----------------------------------------------------------------------------
| | -- |
| -- Includes | | -- Module for skill linking |
| -- ----------------------------------------------------------------------------
| | -- |
|
| |
|
| | local m_util = require('Module:Util') |
| local getArgs = require('Module:Arguments').getArgs | | local getArgs = require('Module:Arguments').getArgs |
| local m_util = require('Module:Util')
| |
| local m_game = require('Module:Game')
| |
|
| |
|
| local mwlanguage = mw.language.getContentLanguage() | | local p = {} |
| | |
| --- define here to avoid errors
| |
| local data = {}
| |
| local map = {}
| |
|
| |
|
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
| -- i18n | | -- Strings |
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
|
| |
|
| local i18n = { | | local i18n = { |
| skill_icon = 'File:%s skill icon.png', | | errors = { |
| skill_screenshot = 'File:%s skill screenshot.jpg',
| | missing_id_parameter = 'Id parameter must be specified.', |
|
| |
| infobox = {
| |
| skill_id = 'Skill Id',
| |
| active_skill_name = 'Name',
| |
| skill_icon = 'Icon',
| |
| cast_time = 'Cast Time',
| |
| item_class_restrictions = 'Item Class<br>Restrictions',
| |
| projectile_speed = 'Projectile Speed',
| |
| radius = 'Radius',
| |
| radius_secondary = 'Radius 2',
| |
| radius_tertiary = 'Radius 3',
| |
| level_requirement = 'Level Req.',
| |
| mana_multiplier = 'Mana Multiplier',
| |
| critical_strike_chance = 'Critical Strike Chance',
| |
| mana_cost = 'Mana Cost',
| |
| mana_reserved = 'Mana Reserved',
| |
| damage_effectiveness = 'Damage Effectiveness',
| |
| stored_uses = 'Stored Uses',
| |
| cooldown = 'Cooldown',
| |
| vaal_souls_requirement = m_util.html.abbr('Vaal Souls', 'Vaal Souls cost is based on the first part of the game. Multiply with 1.5 or 2 to get part 2 / end game values'),
| |
| vaal_stored_uses = 'Vaal Stored Uses',
| |
| damage_multiplier = 'Damage Multiplier',
| |
| },
| |
|
| |
| progression = {
| |
| skill_id = 'Skill Id', | |
| cast_time = 'Cast Time',
| |
| item_class_restrictions = 'Item Class<br>Restrictions',
| |
| projectile_speed = 'Projectile Speed',
| |
| radius = 'Radius',
| |
| radius_secondary = 'Radius 2',
| |
| radius_tertiary = 'Radius 3',
| |
| level_requirement = 'Level Req.',
| |
| mana_multiplier = 'Mana Multiplier',
| |
| critical_strike_chance = 'Critical Strike Chance',
| |
| mana_cost = 'Mana Cost',
| |
| mana_reserved = 'Mana Reserved',
| |
| damage_effectiveness = 'Damage Effectiveness',
| |
| stored_uses = 'Stored Uses',
| |
| cooldown = 'Cooldown',
| |
| vaal_souls_requirement = m_util.html.abbr('Vaal Souls', 'Vaal Souls cost is based on the first part of the game. Multiply with 1.5 or 2 to get part 2 / end game values'),
| |
| vaal_stored_uses = 'Vaal Stored Uses',
| |
| damage_multiplier = 'Damage Multiplier',
| |
| },
| |
|
| |
| args = {
| |
| -- skills
| |
| skill_id = 'skill_id',
| |
| is_support_gem = 'is_support_gem',
| |
| support_gem_letter = 'support_gem_letter',
| |
| cast_time = 'cast_time',
| |
| gem_description = 'gem_description',
| |
| active_skill_name = 'active_skill_name',
| |
| skill_icon = 'skill_icon',
| |
| item_class_restriction = 'item_class_restriction',
| |
| projectile_speed = 'projectile_speed',
| |
| stat_text = 'stat_text',
| |
| quality_stat_text = 'quality_stat_text',
| |
| has_percentage_mana_cost = 'has_percentage_mana_cost',
| |
| has_reservation_mana_cost = 'has_reservation_mana_cost',
| |
| radius = 'radius',
| |
| radius_description = 'radius_description',
| |
| radius_secondary = 'radius_secondary',
| |
| radius_secondary_description = 'radius_secondary_description',
| |
| radius_tertiary = 'radius_tertiary',
| |
| radius_tertiary_description = 'radius_tertiary_description',
| |
| skill_screenshot = 'skill_screenshot',
| |
| | |
| -- skill_levels
| |
| level_requirement = 'level_requirement',
| |
| dexterity_requirement = 'dexterity_requirement',
| |
| intelligence_requirement = 'intelligence_requirement',
| |
| strength_requirement = 'strength_requirement',
| |
| mana_multiplier = 'mana_multiplier',
| |
| critical_strike_chance = 'critical_strike_chance',
| |
| mana_cost = 'mana_cost',
| |
| damage_effectiveness = 'damage_effectiveness',
| |
| stored_uses = 'stored_uses',
| |
| cooldown = 'cooldown',
| |
| vaal_souls_requirement = 'vaal_souls_requirement',
| |
| vaal_stored_uses = 'vaal_stored_uses',
| |
| damage_multiplier = 'damage_multiplier',
| |
| experience = 'experience',
| |
| stat_text = 'stat_text',
| |
| quality_stat_text = 'quality_stat_text',
| |
|
| |
| -- skill_stats_per_level
| |
| id = 'id',
| |
| value = 'value',
| |
|
| |
| -- prefixes
| |
| prefix_level = 'level',
| |
| prefix_static = 'static_',
| |
| prefix_quality_stat = 'quality_',
| |
| infix_stat = 'stat'
| |
| }, | | }, |
| } | | } |
|
| |
|
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
| -- Helper functions | | -- Helper functions and globals |
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
| local h = {}
| |
|
| |
| function h.map_to_arg(tpl_args, frame, properties, prefix_in, map, level)
| |
| if map.order then
| |
| for _, key in ipairs(map.order) do
| |
| row = map.fields[key]
| |
| if row.name then
| |
| local val = tpl_args[prefix_in .. row.name]
| |
| if row.func ~= nil then
| |
| val = row.func(tpl_args, frame, val)
| |
| end
| |
| if val == nil and row.default ~= nil then
| |
| val = row.default
| |
| end
| |
| if val ~= nil then
| |
| if level ~= nil then
| |
| tpl_args.skill_levels[level][key] = val
| |
| -- Nuke variables since they're remapped to skill_levels
| |
| tpl_args[prefix_in .. row.name] = nil
| |
| else
| |
| tpl_args[row.name] = val
| |
| end
| |
| properties[row.field] = val
| |
| end
| |
| else
| |
| error(string.format('Programming error, missing field %s from order keys', key))
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
| function h.stats(tpl_args, frame, prefix_in, level)
| |
| for _, stat_type in ipairs(map.stats) do
| |
| local type_prefix = string.format('%s%s%s', prefix_in, stat_type.prefix_in, i18n.args.infix_stat)
| |
| tpl_args.skill_levels[level][stat_type.out] = {}
| |
| for i=1, 8 do
| |
| local stat_id_key = string.format('%s%s_%s', type_prefix, i, i18n.args.id)
| |
| local stat_val_key = string.format('%s%s_%s', type_prefix, i, i18n.args.value)
| |
| local stat = {
| |
| id = tpl_args[stat_id_key],
| |
| value = tonumber(tpl_args[stat_val_key]),
| |
| }
| |
| if stat.id ~= nil and stat.value ~= nil then
| |
| tpl_args.skill_levels[level][stat_type.out][#tpl_args.skill_levels[level][stat_type.out]+1] = stat
| |
|
| |
| m_util.cargo.store(frame, {
| |
| _table = map.skill_stats_per_level.table,
| |
| [map.skill_stats_per_level.fields.level.field] = level,
| |
| [map.skill_stats_per_level.fields.id.field] = stat.id,
| |
| [map.skill_stats_per_level.fields.value.field] = stat.value,
| |
| [map.skill_stats_per_level.fields.is_quality_stat.field] = stat_type.quality,
| |
| })
| |
|
| |
| -- Nuke variables since they're remapped to skill levels
| |
| tpl_args[stat_id_key] = nil
| |
| tpl_args[stat_val_key] = nil
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
| function h.na(tr)
| |
| tr
| |
| :tag('td')
| |
| :attr('class', 'table-na')
| |
| :wikitext('N/A')
| |
| :done()
| |
| end
| |
|
| |
| function h.int_value_or_na(tpl_args, frame, tr, value, pdata)
| |
| value = tonumber(value)
| |
| if value == nil then
| |
| h.na(tr)
| |
| else
| |
| value = mwlanguage:formatNum(value)
| |
| if pdata.fmt ~= nil then
| |
| if type(pdata.fmt) == 'string' then
| |
| value = string.format(pdata.fmt, value)
| |
| elseif type(pdata.fmt) == 'function' then
| |
| value = string.format(pdata.fmt(tpl_args, frame), value)
| |
| end
| |
| end
| |
| tr
| |
| :tag('td')
| |
| :wikitext(value)
| |
| :done()
| |
| end
| |
| end
| |
|
| |
| h.cast = {}
| |
| function h.cast.wrap (f)
| |
| return function(tpl_args, frame, value)
| |
| if value == nil then
| |
| return nil
| |
| else
| |
| return f(value)
| |
| end
| |
| end
| |
| end
| |
|
| |
| h.display = {}
| |
| h.display.factory = {}
| |
| function h.display.factory.value(args)
| |
| return function (tpl_args, frame)
| |
| if args.fmt then
| |
| return string.format(args.fmt, tpl_args[args.key])
| |
| else
| |
| return tpl_args[args.key]
| |
| end
| |
| end
| |
| end
| |
|
| |
| function h.display.factory.range_value(args)
| |
| return function (tpl_args, frame)
| |
| local value = {
| |
| min = tpl_args.skill_levels[0][args.key] or tpl_args.skill_levels[1][args.key],
| |
| max = tpl_args.skill_levels[0][args.key] or tpl_args.skill_levels[tpl_args.max_level][args.key],
| |
| }
| |
| -- property not set for this skill
| |
| if value.min == nil or value.max == nil then
| |
| return
| |
| end
| |
|
| |
| return m_util.html.format_value(tpl_args, frame, value, {
| |
| fmt=args.fmt or map.progression.fields[args.key].fmt,
| |
| no_color=true,
| |
| })
| |
| end
| |
| end
| |
|
| |
| function h.display.factory.radius(args)
| |
| return function (tpl_args, frame)
| |
| local radius = tpl_args['radius' .. args.key]
| |
| if radius == nil then
| |
| return
| |
| end
| |
| local description = tpl_args[string.format('radius%s_description', args.key)]
| |
| if description then
| |
| return m_util.html.abbr(radius, description)
| |
| else
| |
| return radius
| |
| end
| |
| end
| |
| end
| |
|
| |
|
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
| -- Data | | -- Page functions |
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
|
| |
|
|
| |
| map.stats = {
| |
| {
| |
| prefix_in = '',
| |
| out = 'stats',
| |
| quality = false,
| |
| },
| |
| {
| |
| prefix_in = i18n.args.prefix_quality_stat,
| |
| out = 'quality_stats',
| |
| quality = true,
| |
| },
| |
| }
| |
|
| |
| map.static = {
| |
| table = 'skill',
| |
| order = {'skill_id', 'cast_time', 'gem_description', 'active_skill_name', 'skill_icon', 'item_class_restriction', 'projectile_speed', 'stat_text', 'quality_stat_text', 'has_percentage_mana_cost', 'has_reservation_mana_cost', 'radius', 'radius_secondary', 'radius_tertiary', 'radius_description', 'radius_secondary_description', 'radius_tertiary_description', 'skill_screenshot'},
| |
| fields = {
| |
| -- GrantedEffects.dat
| |
| skill_id = {
| |
| name = i18n.args.skill_id,
| |
| field = 'skill_id',
| |
| type = 'String',
| |
| func = nil,
| |
| },
| |
| -- Active Skills.dat
| |
| cast_time = {
| |
| name = i18n.args.cast_time,
| |
| field = 'cast_time',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| },
| |
| gem_description = {
| |
| name = i18n.args.gem_description,
| |
| field = 'description',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| active_skill_name = {
| |
| name = i18n.args.active_skill_name,
| |
| field = 'active_skill_name',
| |
| type = 'String',
| |
| func = nil,
| |
| },
| |
| skill_icon = {
| |
| name = i18n.args.skill_icon,
| |
| field = 'skill_icon',
| |
| type = 'Page',
| |
| func = function(tpl_args, frame)
| |
| if tpl_args.active_skill_name then
| |
| return string.format(i18n.skill_icon, tpl_args.active_skill_name)
| |
| end
| |
| end,
| |
| },
| |
| item_class_restriction = {
| |
| name = i18n.args.item_class_restriction,
| |
| field = 'item_class_restriction',
| |
| type = 'List (,) of String',
| |
| func = function(tpl_args, frame, value)
| |
| if value == nil then
| |
| return nil
| |
| end
| |
| value = m_util.string.split(value, ', ')
| |
| for _, v in ipairs(value) do
| |
| local result = m_util.table.find_in_nested_array{value=v,key='full', tbl=m_game.constants.item.class}
| |
| if result == nil then
| |
| error(string.format('Invalid item class: %s', v))
| |
| end
| |
| end
| |
| return value
| |
| end,
| |
| },
| |
| -- Projectiles.dat - manually mapped to the skills
| |
| projectile_speed = {
| |
| name = i18n.args.projectile_speed,
| |
| field = 'projectile_speed',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| },
| |
| -- Misc data derieved from stats
| |
| stat_text = {
| |
| name = i18n.args.stat_text,
| |
| field = 'stat_text',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| quality_stat_text = {
| |
| name = i18n.args.quality_stat_text,
| |
| field = 'quality_stat_text',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| -- Misc data currently not from game data
| |
| has_percentage_mana_cost = {
| |
| name = i18n.args.has_percentage_mana_cost,
| |
| field = 'has_percentage_mana_cost',
| |
| type = 'Boolean',
| |
| func = h.cast.wrap(m_util.cast.boolean),
| |
| default = false,
| |
| },
| |
| has_reservation_mana_cost = {
| |
| name = i18n.args.has_reservation_mana_cost,
| |
| field = 'has_reservation_mana_cost',
| |
| type = 'Boolean',
| |
| func = h.cast.wrap(m_util.cast.boolean),
| |
| default = false,
| |
| },
| |
| radius = {
| |
| name = i18n.args.radius,
| |
| field = 'radius',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| },
| |
| radius_description = {
| |
| name = i18n.args.radius_description,
| |
| field = 'radius_description',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| radius_secondary = {
| |
| name = i18n.args.radius_secondary,
| |
| field = 'radius_secondary',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| },
| |
| radius_secondary_description = {
| |
| name = i18n.args.radius_secondary_description,
| |
| field = 'radius_secondary_description',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| -- not sure if any skill actually has 3 radius componets
| |
| radius_tertiary = {
| |
| name = i18n.args.radius_tertiary,
| |
| field = 'radius_tertiary',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| },
| |
| radius_tertiary_description = {
| |
| name = i18n.args.radius_tertiary_description,
| |
| field = 'radius_tertiary_description',
| |
| type = 'Text',
| |
| func = nil,
| |
| },
| |
| -- Set manually
| |
| max_level = {
| |
| field = 'max_level',
| |
| type = 'Integer',
| |
| },
| |
| html = {
| |
| field = 'html',
| |
| type = 'Text',
| |
| },
| |
| skill_screenshot = {
| |
| name = i18n.args.skill_screenshot,
| |
| field = 'skill_screenshot',
| |
| type = 'Page',
| |
| func = function(tpl_args, frame)
| |
| local ss
| |
| if tpl_args.skill_screenshot_file ~= nil then
| |
| ss = string.format('File:%s', tpl_args.skill_screenshot_file)
| |
| elseif tpl_args.skill_screenshot ~= nil then
| |
| ss = string.format(i18n.skill_screenshot, tpl_args.skill_screenshot)
| |
| elseif tpl_args.active_skill_name then
| |
| -- When this parameter is set manually, we assume/expect it to be exist, but otherwise it probably doesn't and we don't need dead links in that case
| |
| ss = string.format(i18n.skill_screenshot, tpl_args.active_skill_name)
| |
| page = mw.title.new(ss)
| |
| if page == nil or not page.exists then
| |
| ss = nil
| |
| end
| |
| end
| |
| return ss
| |
| end,
| |
| },
| |
| },
| |
| }
| |
|
| |
| map.progression = {
| |
| table = 'skill_levels',
| |
| order = {'level_requirement', 'dexterity_requirement', 'intelligence_requirement', 'strength_requirement', 'mana_multiplier', 'critical_strike_chance', 'mana_cost', 'damage_effectiveness', 'stored_uses', 'cooldown', 'vaal_souls_requirement', 'vaal_stored_uses', 'damage_multiplier', 'experience', 'stat_text', 'quality_stat_text'},
| |
| fields = {
| |
| level = {
| |
| name = nil,
| |
| field = 'level',
| |
| type = 'Integer',
| |
| func = nil,
| |
| header = nil,
| |
| },
| |
| level_requirement = {
| |
| name = i18n.args.level_requirement,
| |
| field = 'level_requirement',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = m_util.html.abbr('[[Image:Level_up_icon_small.png|link=|Lvl.]]', 'Required Level', 'nounderline'),
| |
| },
| |
| dexterity_requirement = {
| |
| name = i18n.args.dexterity_requirement,
| |
| field = 'dexterity_requirement',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = m_util.html.abbr('[[Image:DexterityIcon_small.png|link=|dexterity]]', 'Required Dexterity', 'nounderline'),
| |
| },
| |
| strength_requirement = {
| |
| name = i18n.args.strength_requirement,
| |
| field = 'strength_requirement',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = m_util.html.abbr('[[Image:StrengthIcon_small.png|link=|strength]]', 'Required Strength', 'nounderline'),
| |
| },
| |
| intelligence_requirement = {
| |
| name = i18n.args.intelligence_requirement,
| |
| field = 'intelligence_requirement',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = m_util.html.abbr('[[Image:IntelligenceIcon_small.png|link=|intelligence]]', 'Required Intelligence', 'nounderline'),
| |
| },
| |
| mana_multiplier = {
| |
| name = i18n.args.mana_multiplier,
| |
| field = 'mana_multiplier',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Mana<br>Multiplier',
| |
| fmt = '%s%%',
| |
| },
| |
| critical_strike_chance = {
| |
| name = i18n.args.critical_strike_chance,
| |
| field = 'critical_strike_chance',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Critical<br>Strike<br>Chance',
| |
| fmt = '%s%%',
| |
| },
| |
| mana_cost = {
| |
| name = i18n.args.mana_cost,
| |
| field = 'mana_cost',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = function (skill_data)
| |
| if skill_data["skill.has_reservation_mana_cost"] then
| |
| return 'Mana<br>Reserved'
| |
| else
| |
| return 'Mana<br>Cost'
| |
| end
| |
| end,
| |
| fmt = function (tpl_args, frame)
| |
| if tpl_args.has_percentage_mana_cost then
| |
| str = '%s%%'
| |
| else
| |
| str = '%s'
| |
| end
| |
|
| |
| return str
| |
| end,
| |
| },
| |
| damage_effectiveness = {
| |
| name = i18n.args.damage_effectiveness,
| |
| field = 'damage_effectiveness',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Damage<br>Effectiveness',
| |
| fmt = '%s%%',
| |
| },
| |
| stored_uses = {
| |
| name = i18n.args.stored_uses,
| |
| field = 'stored_uses',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Stored<br>Uses',
| |
| },
| |
| cooldown = {
| |
| name = i18n.args.cooldown,
| |
| field = 'cooldown',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Cooldown',
| |
| fmt = '%ss',
| |
| },
| |
| vaal_souls_requirement = {
| |
| name = i18n.args.vaal_souls_requirement,
| |
| field = 'vaal_souls_requirement',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Vaal<br>souls',
| |
| },
| |
| vaal_stored_uses = {
| |
| name = i18n.args.vaal_stored_uses,
| |
| field = 'vaal_stored_uses',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = 'Stored<br>Uses',
| |
| },
| |
| damage_multiplier = {
| |
| name = i18n.args.damage_multiplier,
| |
| field = 'damage_multiplier',
| |
| type = 'Float',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| header = m_util.html.abbr('Damage<br>Multiplier', 'Deals x% of Base Damage'),
| |
| fmt = '%s%%',
| |
| },
| |
| -- from gem experience, optional
| |
| experience = {
| |
| name = i18n.args.experience,
| |
| field = 'experience',
| |
| type = 'Integer',
| |
| func = h.cast.wrap(m_util.cast.number),
| |
| hide = true,
| |
| },
| |
| stat_text = {
| |
| name = i18n.args.stat_text,
| |
| field = 'stat_text',
| |
| type = 'Text',
| |
| func = nil,
| |
| hide = true,
| |
| },
| |
| quality_stat_text = {
| |
| name = i18n.args.quality_stat_text,
| |
| field = 'quality_stat_text',
| |
| type = 'Text',
| |
| func = nil,
| |
| hide = true,
| |
| },
| |
| }
| |
| }
| |
|
| |
| data.progression_display_order = {'level_requirement', 'dexterity_requirement', 'strength_requirement', 'intelligence_requirement', 'mana_multiplier', 'critical_strike_chance', 'mana_cost', 'damage_effectiveness', 'stored_uses', 'cooldown', 'vaal_souls_requirement', 'vaal_stored_uses', 'damage_multiplier'}
| |
|
| |
| map.skill_stats_per_level = {
| |
| table = 'skill_stats_per_level',
| |
| fields = {
| |
| level = {
| |
| field = 'level',
| |
| type = 'Integer',
| |
| },
| |
| id = {
| |
| field = 'id',
| |
| type = 'String',
| |
| },
| |
| value = {
| |
| field = 'value',
| |
| type = 'Integer',
| |
| },
| |
| is_quality_stat = {
| |
| field = 'is_quality_stat',
| |
| type = 'Boolean',
| |
| },
| |
| },
| |
| }
| |
|
| |
| data.infobox_table = {
| |
| {
| |
| header = i18n.infobox.active_skill_name,
| |
| func = h.display.factory.value{key='active_skill_name'},
| |
| },
| |
| {
| |
| header = i18n.infobox.skill_id,
| |
| func = h.display.factory.value{key='skill_id'},
| |
| },
| |
| {
| |
| header = i18n.infobox.skill_icon,
| |
| func = function (tpl_args, frame)
| |
| if tpl_args.skill_icon then
| |
| return string.format('[[%s]]', tpl_args.skill_icon)
| |
| end
| |
| end,
| |
| },
| |
| {
| |
| header = i18n.infobox.cast_time,
| |
| func = h.display.factory.value{key='cast_time'},
| |
| },
| |
| {
| |
| header = i18n.infobox.item_class_restrictions,
| |
| func = function (tpl_args, frame)
| |
| if tpl_args.item_class_restrictions == nil then
| |
| return
| |
| end
| |
| local ul = mw.html.create('ul')
| |
| for _, class in ipairs(i18n.infobox.item_class_restrictions) do
| |
| ul:tag('li')
| |
| :wikitext(string.format('[[%s]]', class))
| |
| end
| |
| return tostring(ul)
| |
| end,
| |
| },
| |
| {
| |
| header = i18n.infobox.projectile_speed,
| |
| func = h.display.factory.value{key='projectile_speed'},
| |
| },
| |
| {
| |
| header = i18n.infobox.radius,
| |
| func = h.display.factory.radius{key=''},
| |
| },
| |
| {
| |
| header = i18n.infobox.radius_secondary,
| |
| func = h.display.factory.radius{key='_secondary'},
| |
| },
| |
| {
| |
| header = i18n.infobox.radius_tertiary,
| |
| func = h.display.factory.radius{key='_tertiary'},
| |
| },
| |
| {
| |
| header = i18n.infobox.level_requirement,
| |
| func = h.display.factory.range_value{key='level_requirement'},
| |
| },
| |
| -- ingore attrbiutes?
| |
| {
| |
| header = i18n.infobox.mana_multiplier,
| |
| func = h.display.factory.range_value{key='mana_multiplier'},
| |
| },
| |
| {
| |
| header = i18n.infobox.critical_strike_chance,
| |
| func = h.display.factory.range_value{key='critical_strike_chance'},
| |
| },
| |
| {
| |
| header = i18n.infobox.mana_cost,
| |
| func = h.display.factory.range_value{key='mana_cost'},
| |
| },
| |
| {
| |
| header = i18n.infobox.damage_effectiveness,
| |
| func = h.display.factory.range_value{key='damage_effectiveness'},
| |
| },
| |
| {
| |
| header = i18n.infobox.stored_uses,
| |
| func = h.display.factory.range_value{key='stored_uses'},
| |
| },
| |
| {
| |
| header = i18n.infobox.cooldown,
| |
| func = h.display.factory.range_value{key='cooldown'},
| |
| },
| |
| {
| |
| header = i18n.infobox.svaal_souls_requirement,
| |
| func = h.display.factory.range_value{key='vaal_souls_requirement'},
| |
| },
| |
| {
| |
| header = i18n.infobox.vaal_stored_uses,
| |
| func = h.display.factory.range_value{key='vaal_stored_uses'},
| |
| },
| |
| {
| |
| header = i18n.infobox.damage_multiplier,
| |
| func = h.display.factory.range_value{key='damage_multiplier'},
| |
| },
| |
| {
| |
| header = nil,
| |
| func = h.display.factory.value{key='gem_description'},
| |
| class = 'tc -gemdesc',
| |
| },
| |
| {
| |
| header = nil,
| |
| func = h.display.factory.value{key='stat_text'},
| |
| class = 'tc -mod',
| |
| },
| |
| }
| |
|
| |
| -- ----------------------------------------------------------------------------
| |
| -- Templates
| |
| -- ----------------------------------------------------------------------------
| |
| local p = {} | | local p = {} |
|
| |
|
| p.table_skills = m_util.cargo.declare_factory{data=map.static}
| | function p.skill_infobox_link(frame) |
| p.table_skill_levels = m_util.cargo.declare_factory{data=map.progression}
| | -- Get args |
| p.table_skill_stats_per_level = m_util.cargo.declare_factory{data=map.skill_stats_per_level}
| | tpl_args = getArgs(frame, { |
| | |
| --
| |
| -- Template:Skill
| |
| --
| |
| function p.skill(frame, tpl_args) | |
| if tpl_args == nil then
| |
| tpl_args = getArgs(frame, {
| |
| parentFirst = true
| |
| })
| |
| end
| |
| frame = m_util.misc.get_frame(frame)
| |
|
| |
| --
| |
| -- Args
| |
| --
| |
| local properties
| |
|
| |
| tpl_args.skill_levels = {
| |
| [0] = {},
| |
| }
| |
|
| |
| -- Handle level progression
| |
| local i = 0
| |
| repeat
| |
| i = i + 1
| |
| local prefix = i18n.args.prefix_level .. i
| |
| local level = m_util.cast.boolean(tpl_args[prefix])
| |
| if level == true then
| |
| -- Don't need this anymore
| |
| tpl_args[prefix] = nil
| |
| tpl_args.skill_levels[i] = {}
| |
| prefix = prefix .. '_'
| |
|
| |
| if tpl_args[prefix .. i18n.args.experience] ~= nil then
| |
| tpl_args.max_level = i
| |
| end
| |
|
| |
| properties = {
| |
| _table = map.progression.table,
| |
| [map.progression.fields.level.field] = i
| |
| }
| |
| h.map_to_arg(tpl_args, frame, properties, prefix, map.progression, i)
| |
| m_util.cargo.store(frame, properties)
| |
|
| |
| h.stats(tpl_args, frame, prefix, i)
| |
| end
| |
| until level ~= true
| |
| -- If no experience is given, assume this is a non skill gem skill. | |
| tpl_args.max_level = tpl_args.max_level or (i - 1)
| |
| -- handle static progression
| |
| properties = {
| |
| _table = map.progression.table,
| |
| [map.progression.fields.level.field] = 0
| |
| }
| |
| h.map_to_arg(tpl_args, frame, properties, i18n.args.prefix_static, map.progression, 0)
| |
| m_util.cargo.store(frame, properties)
| |
|
| |
| -- Handle static arguments
| |
| properties = {
| |
| _table = map.static.table,
| |
|
| |
| [map.static.fields.max_level.field] = tpl_args.max_level
| |
| }
| |
|
| |
| h.map_to_arg(tpl_args, frame, properties, '', map.static)
| |
| h.stats(tpl_args, frame, i18n.args.prefix_static, 0)
| |
|
| |
|
| |
|
| |
| --
| |
| -- Infobox progressing
| |
| --
| |
| local infobox = mw.html.create('span')
| |
| infobox:attr('class', 'skill-box')
| |
|
| |
| -- tablular sections
| |
| local tbl = infobox:tag('table')
| |
| tbl:attr('class', 'wikitable skill-box-table')
| |
| for _, infobox_data in ipairs(data.infobox_table) do
| |
| local display = infobox_data.func(tpl_args, frame)
| |
| if display then
| |
| local tr = tbl:tag('tr')
| |
| if infobox_data.header then
| |
| tr
| |
| :tag('th')
| |
| :wikitext(infobox_data.header)
| |
| :done()
| |
| end
| |
| local td = tr:tag('td')
| |
| td:wikitext(display)
| |
| td:attr('class', infobox_data.class or 'tc -value')
| |
| if infobox_data.header == nil then
| |
| td:attr('colspan', 2)
| |
| end
| |
| end
| |
| end
| |
|
| |
| infobox = tostring(infobox)
| |
|
| |
| --
| |
| -- Store data
| |
| --
| |
| properties[map.static.fields.html.field] = infobox
| |
| m_util.cargo.store(frame, properties)
| |
|
| |
| --
| |
| --
| |
| --
| |
| local container = mw.html.create('span')
| |
| container:attr('class', 'skill-box-page-container')
| |
| container:wikitext(infobox)
| |
| if tpl_args.skill_screenshot then
| |
| container:wikitext(string.format('[[%s]]', tpl_args.skill_screenshot))
| |
| end
| |
|
| |
| return tostring(container) .. m_util.misc.add_category({'Skill data'})
| |
| end
| |
| | |
| function p.progression(frame)
| |
| local tpl_args = getArgs(frame, { | |
| parentFirst = true | | parentFirst = true |
| }) | | }) |
| frame = m_util.misc.get_frame(frame) | | frame = m_util.misc.get_frame(frame) |
| | | |
| -- | | if tpl_args.id == nil then |
| tpl_args.stat_format = {}
| | error(i18n.errors.missing_id_parameter) |
| local prefix
| |
| for i=1, 9 do
| |
| prefix = 'c' .. i .. '_'
| |
| local statfmt = {
| |
| header = tpl_args[prefix .. 'header'],
| |
| abbr = tpl_args[prefix .. 'abbr'],
| |
| pattern_extract = tpl_args[prefix .. 'pattern_extract'],
| |
| pattern_value = tpl_args[prefix .. 'pattern_value'],
| |
| counter = 0,
| |
| }
| |
| if m_util.table.has_all_value(statfmt, {'header', 'abbr', 'pattern_extract', 'pattern_value'}) then
| |
| break
| |
| end | |
|
| |
| if m_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 = m_util.html.abbr(statfmt.abbr, statfmt.header)
| |
| statfmt.abbr = nil
| |
| tpl_args.stat_format[#tpl_args.stat_format+1] = statfmt
| |
| end | | end |
| | | |
|
| | local results = m_util.cargo.query( |
| local result
| | {'skill'}, |
| local query = { | | { |
| groupBy = 'skill._pageID',
| | 'skill.html', |
| }
| | 'skill.skill_screenshot', |
| local skill_data
| | }, |
|
| |
| local fields = {
| |
| 'skill._pageName',
| |
| 'skill.has_reservation_mana_cost',
| |
| }
| |
|
| |
| if tpl_args.skill_id then
| |
| query.where = string.format('skill.skill_id="%s"', tpl_args.skill_id)
| |
| result = m_util.cargo.query({'skill'}, fields, query) | |
| if #result == 0 or #result[1] == 0 then | |
| error('Couldn\'t find a page for the specified skill id')
| |
| end
| |
| skill_data = result[1]
| |
| else
| |
| if tpl_args.page then
| |
| page = tpl_args.page | |
| else
| |
| page = mw.title.getCurrentTitle().prefixedText
| |
| end
| |
| query.where = string.format('skill._pageName="%s"', page)
| |
|
| |
| result = m_util.cargo.query({'skill'}, fields, query)
| |
| if #result == 0 then
| |
| error('Couldn\'t find the queried data on the skill page') | |
| end
| |
|
| |
| skill_data = result[1]
| |
| end
| |
|
| |
| skill_data["skill.has_reservation_mana_cost"] = h.cast.wrap(m_util.cast.boolean)(skill_data["skill.has_reservation_mana_cost"])
| |
|
| |
| query.where=string.format('skill_levels._pageName="%s"', skill_data['skill._pageName'])
| |
| fields = {}
| |
| for _, pdata in pairs(map.progression.fields) do
| |
| fields[#fields+1] = string.format('skill_levels.%s', pdata.field)
| |
| end
| |
|
| |
| result = m_util.cargo.query(
| |
| {'skill_levels'}, | |
| fields,
| |
| { | | { |
| where=string.format('skill_levels._pageName="%s" AND skill_levels.level > 0', skill_data['skill._pageName']), | | where=string.format('skill.skill_id = "%s"', tpl_args.id), |
| groupBy='skill_levels._pageID, skill_levels.level', | | limit=1, |
| orderBy='skill_levels.level ASC',
| |
| } | | } |
| ) | | ) |
| | results = results[1] |
| | | |
| if #result == 0 then
| | local container = mw.html.create('span') |
| error('No gem level progression data found')
| | container:attr('class', 'skill-box-page-container') |
| end
| | container:wikitext(results['skill.html']) |
|
| | if results['skill.skill_screenshot'] then |
| headers = {}
| | container:wikitext(string.format('[[%s]]', results['skill.skill_screenshot'])) |
| for i, row in ipairs(result) do
| |
| for k, v in pairs(row) do
| |
| headers[k] = true
| |
| end
| |
| end
| |
|
| |
| local tbl = mw.html.create('table') | |
| tbl:attr('class', 'wikitable skill-progression-table') | |
|
| |
| local head = tbl:tag('tr')
| |
| head
| |
| :tag('th')
| |
| :wikitext('Level')
| |
| :done()
| |
|
| |
| for _, key in ipairs(data.progression_display_order) do
| |
| local pdata = map.progression.fields[key]
| |
| -- TODO should be nil?
| |
| if pdata.hide == nil and headers['skill_levels.' .. pdata.field] then
| |
| local text
| |
| if type(pdata.header) == 'function' then
| |
| text = pdata.header(skill_data)
| |
| else
| |
| text = pdata.header
| |
| end
| |
| head
| |
| :tag('th')
| |
| :wikitext(text)
| |
| :done()
| |
| end
| |
| end
| |
|
| |
| for _, statfmt in ipairs(tpl_args.stat_format) do | |
| head
| |
| :tag('th')
| |
| :wikitext(statfmt.header)
| |
| :done()
| |
| end
| |
|
| |
| if headers['skill_levels.experience'] then
| |
| head
| |
| :tag('th')
| |
| :wikitext(m_util.html.abbr('Exp.', 'Experience Needed to Level Up'))
| |
| :done()
| |
| :tag('th')
| |
| :wikitext(m_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['skill_levels.level'])
| |
| :done()
| |
|
| |
| for _, key in ipairs(data.progression_display_order) do
| |
| local pdata = map.progression.fields[key]
| |
| if pdata.hide == nil and headers['skill_levels.' .. pdata.field] then
| |
| h.int_value_or_na(tpl_args, frame, tblrow, row['skill_levels.' .. pdata.field], pdata)
| |
| end
| |
| end
| |
|
| |
| -- stats
| |
| if row['skill_levels.stat_text'] then
| |
| stats = m_util.string.split(row['skill_levels.stat_text'], '<br>')
| |
| else
| |
| stats = {}
| |
| end
| |
| for _, statfmt in ipairs(tpl_args.stat_format) do | |
| local match = {}
| |
| for j, stat in ipairs(stats) do
| |
| match = {string.match(stat, statfmt.pattern_extract)}
| |
| if #match > 0 then
| |
| -- TODO maybe remove stat here to avoid testing against in future loops
| |
| break
| |
| end
| |
| end
| |
| if #match == 0 then
| |
| h.na(tblrow)
| |
| else
| |
| -- used to find broken progression (i.e. due to game updates)
| |
| statfmt.counter = statfmt.counter + 1
| |
| 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['skill_levels.experience'] then
| |
| experience = tonumber(row['skill_levels.experience'])
| |
| if experience ~= nil then
| |
| h.int_value_or_na(tpl_args, frame, tblrow, experience - lastexp, {})
| |
|
| |
| lastexp = experience
| |
| else
| |
| h.na(tblrow)
| |
| end
| |
| h.int_value_or_na(tpl_args, frame, tblrow, experience, {})
| |
| end
| |
| end
| |
|
| |
| local empty = ''
| |
|
| |
| for _, statfmt in ipairs(tpl_args.stat_format) do
| |
| if statfmt.counter == 0 then
| |
| empty = '[[Category:Pages with broken skill progression tables]]'
| |
| break
| |
| end
| |
| end | | end |
| | | |
| return empty .. tostring(tbl) | | return tostring(container) |
| end
| |
| | |
| function p.map(arg)
| |
| for key, data in pairs(map[arg].fields) do
| |
| mw.logObject(key)
| |
| end
| |
| end | | end |
|
| |
|
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
| -- Debug | | -- End |
| -- ---------------------------------------------------------------------------- | | -- ---------------------------------------------------------------------------- |
|
| |
| p._debug = {}
| |
| function p._debug.order(frame)
| |
| for _, mapping in ipairs({'static', 'progression'}) do
| |
| for _, key in ipairs(map[mapping].order) do
| |
| if map[mapping].fields[key] == nil then
| |
| mw.logObject(string.format('Missing key in %s.fields: %s', mapping, key))
| |
| end
| |
| end
| |
| for key, _ in pairs(map[mapping].fields) do
| |
| local missing = true
| |
| for _, order_key in ipairs(map[mapping].order) do
| |
| if order_key == key then
| |
| missing = false
| |
| break
| |
| end
| |
| end
| |
| if missing then
| |
| mw.logObject(string.format('Missing key in %s.order: %s', mapping, key))
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
|
| return p | | return p |