(remove property links) |
(Modifier drop down list moved to module:modifier table. Removed old mod list.) |
||
Line 53: | Line 53: | ||
sell_price_missing_argument = 'Both %s and %s must be specified', |
sell_price_missing_argument = 'Both %s and %s must be specified', |
||
}, |
}, |
||
+ | |||
− | |||
− | drop_down_table = { |
||
− | collapse_all = 'Collapse all', |
||
− | expand_all = 'Expand all', |
||
− | table_intro = 'The table below displays the available [[modifiers]] for [[item]]s such as', |
||
− | prefix = 'Prefix', |
||
− | suffix = 'Suffix', |
||
− | corrupted = 'Corrupted' |
||
− | }, |
||
} |
} |
||
Line 138: | Line 130: | ||
end |
end |
||
− | |||
− | function h.cargo_query(tpl_args) |
||
− | --[[ |
||
− | Returns a Cargo query of all the results, even if there are more |
||
− | results than the maximum query limit. It also adds popular fields. |
||
− | |||
− | tpl_args should include these keys: |
||
− | tpl_args.tables |
||
− | tpl_args.fields |
||
− | tpl_args.q_* |
||
− | |||
− | ]] |
||
− | |||
− | local tables = m_util.string.split(tpl_args.tables, ', ') |
||
− | local fields = m_util.string.split(tpl_args.fields, ', ') |
||
− | |||
− | -- Parse query arguments |
||
− | local query = { |
||
− | -- Workaround: Fix duplicates but removes other rows as well. |
||
− | groupBy = tables[1] .. '._pageID', |
||
− | limit = 5000, |
||
− | offset = 0, |
||
− | } |
||
− | for key, value in pairs(tpl_args) do |
||
− | if string.sub(key, 0, 2) == 'q_' then |
||
− | query[string.sub(key, 3)] = value |
||
− | end |
||
− | end |
||
− | |||
− | -- Add commonly used fields: |
||
− | local fields_base = { |
||
− | '_pageNamespace', |
||
− | '_pageTitle', |
||
− | '_ID', |
||
− | '_rowID', |
||
− | '_pageID', |
||
− | '_pageName' |
||
− | -- '_value' |
||
− | } |
||
− | for _, tbl in ipairs(tables) do |
||
− | for _, fld in ipairs(fields_base) do |
||
− | fields[#fields+1] = string.format('%s.%s', tbl, fld) |
||
− | end |
||
− | end |
||
− | |||
− | -- Query cargo table. If there are too many results then repeat, |
||
− | -- offset, re-query and add the remaining results: |
||
− | local results = {} |
||
− | repeat |
||
− | local result = mw.ext.cargo.query( |
||
− | table.concat(tables, ', '), |
||
− | table.concat(fields, ', '), |
||
− | query |
||
− | ) |
||
− | query.offset = query.offset + #result |
||
− | |||
− | for _,v in ipairs(result) do |
||
− | results[#results + 1] = v |
||
− | end |
||
− | until #result < query.limit |
||
− | |||
− | return results |
||
− | end |
||
-- ---------------------------------------------------------------------------- |
-- ---------------------------------------------------------------------------- |
||
Line 719: | Line 648: | ||
return tostring(container) .. m_util.misc.add_category(cats) .. '\n' .. table.concat(out) |
return tostring(container) .. m_util.misc.add_category(cats) .. '\n' .. table.concat(out) |
||
− | end |
||
− | |||
− | -- |
||
− | -- Template: SMW query mods |
||
− | -- |
||
− | |||
− | function p.query_mods(frame) |
||
− | -- Args |
||
− | g_args = getArgs(frame, { |
||
− | parentFirst = true |
||
− | }) |
||
− | g_frame = m_util.misc.get_frame(frame) |
||
− | |||
− | g_args.colspan = 4 |
||
− | |||
− | local conditions = {} |
||
− | conditions[#conditions+1] = 'concept' |
||
− | if g_args.tag then |
||
− | conditions[#conditions+1] = string.format('[[Has subobject::<q>[[-Has subobject::+]] [[Has spawn weight::>>0]] [[Has tag::%s]]</q>]]', g_args.tag) |
||
− | end |
||
− | |||
− | g_args.header_level = g_args.header_level or 2 |
||
− | |||
− | -- Fields |
||
− | local fields = {} |
||
− | fields[#fields+1] = '?Is mod' |
||
− | fields[#fields+1] = '?Has name' |
||
− | fields[#fields+1] = '?Has level requirement' |
||
− | fields[#fields+1] = '?Has mod group' |
||
− | fields[#fields+1] = '?Has stat text' |
||
− | -- parameters |
||
− | local parameters = {} |
||
− | parameters.sort = 'Has mod group, ' |
||
− | parameters.limit = 1000 -- lets see |
||
− | |||
− | local data = {} |
||
− | data.header = { |
||
− | prefix = 'Prefix', |
||
− | suffix = 'Suffix', |
||
− | } |
||
− | |||
− | local out = {} |
||
− | for _, v in ipairs({'prefix', 'suffix'}) do |
||
− | out[#out+1] = string.format('<h%i>%s</h%i>', g_args.header_level, data.header[v], g_args.header_level) |
||
− | conditions[1] = string.format('[[Concept:Spawnable named %s item mods]]', v) |
||
− | |||
− | local query |
||
− | local results |
||
− | -- |
||
− | -- Query tags |
||
− | -- |
||
− | query = {} |
||
− | query[#query+1] = string.format('[[-Has subobject::<q>%s</q>]]', table.concat(conditions, ' ')) |
||
− | query[#query+1] = '[[Has tag::+]]' |
||
− | query[#query+1] = '[[Has spawn weight::+]]' |
||
− | --query[#query+1] = '[[Has spawn weight::>>0]]' |
||
− | query[#query+1] = '?Has tag' |
||
− | query[#query+1] = '?Has spawn weight#' -- need native number |
||
− | query.limit = 1000 |
||
− | query.offset = 0 |
||
− | -- Tag order is very important |
||
− | query.sort = ', Is tag number' |
||
− | |||
− | local tags = {} |
||
− | -- this works because lua only considers nil to be false >_> |
||
− | while query.offset do |
||
− | results = m_util.smw.query(query, g_frame) |
||
− | query.offset = query.offset + #results |
||
− | -- terminates the while if enough reuslts have been fetched |
||
− | if query.offset % 1000 ~= 0 then |
||
− | query.offset = nil |
||
− | end |
||
− | |||
− | for _, row in ipairs(results) do |
||
− | local page, _ = string.gsub(row[1], '#_[%x]+', '') |
||
− | if tags[page] == nil then |
||
− | tags[page] = {} |
||
− | end |
||
− | |||
− | local text |
||
− | if tonumber(row['Has spawn weight']) > 0 then |
||
− | text = '[[File:Yes.png|yes|link=]]' |
||
− | else |
||
− | text = '[[File:No.png|no|link=]]' |
||
− | end |
||
− | |||
− | tags[page][#tags[page]+1] = string.format('%s %s', row['Has tag'], text) |
||
− | end |
||
− | end |
||
− | |||
− | -- |
||
− | -- Query mods |
||
− | -- |
||
− | query = {} |
||
− | for _, v in ipairs(conditions) do |
||
− | query[#query+1] = v |
||
− | end |
||
− | for _, v in ipairs(fields) do |
||
− | query[#query+1] = v |
||
− | end |
||
− | for k, v in pairs(parameters) do |
||
− | query[k] = v |
||
− | end |
||
− | |||
− | results = m_util.smw.query(query, g_frame) |
||
− | |||
− | local last = '' |
||
− | local tbl = '' |
||
− | for _, row in ipairs(results) do |
||
− | local current = string.gsub(row['Is mod'], '%d+.*', '%%d.*') |
||
− | if string.match(last, current) then |
||
− | h.format_mod(tbl, row, tags[row[1]]) |
||
− | else |
||
− | out[#out+1] = tostring(tbl) |
||
− | tbl = h.create_header(row) |
||
− | h.format_mod(tbl, row, tags[row[1]]) |
||
− | end |
||
− | last = row['Is mod'] |
||
− | end |
||
− | |||
− | -- add the last table |
||
− | out[#out+1] = tostring(tbl) |
||
− | end |
||
− | |||
− | return table.concat(out, '') |
||
− | end |
||
− | |||
− | function p.get_mod_domain(cargo_query) |
||
− | --[[ |
||
− | Gets the mod domain based on the item class. |
||
− | ]] |
||
− | |||
− | local out = cargo_query |
||
− | local mod_domains = game.constants.mod.domains |
||
− | |||
− | -- Set item class as key and the mod domain as value: |
||
− | local class_to_domain = { |
||
− | ['Life Flasks']=2, |
||
− | ['Mana Flasks']=2, |
||
− | ['Hybrid Flasks']=2, |
||
− | ['Utility Flasks']=2, |
||
− | ['Critical Utility Flasks']=2, |
||
− | ['Maps']=5, |
||
− | ['Jewel']=11, |
||
− | ['Leaguestones']=13, |
||
− | ['Abyss Jewel']=14, |
||
− | } |
||
− | |||
− | for i,_ in ipairs(out) do |
||
− | -- Get the domain, if it's not defined in the table assume it's |
||
− | -- in the item domain. |
||
− | out[i]['items.domain'] = class_to_domain[out[i]['items.class']] or 1 |
||
− | |||
− | -- Convert the mod domain number to understandable text: |
||
− | out[i]['items.domain_text'] = mod_domains[out[i]['items.domain']]['short_lower'] |
||
− | end |
||
− | |||
− | return out |
||
− | end |
||
− | |||
− | function p.get_item_tags(frame) |
||
− | --[[ |
||
− | This function queries for the tags of a specific item. |
||
− | ]] |
||
− | |||
− | -- Args |
||
− | local tpl_args = getArgs(frame, {parentFirst=true}) |
||
− | local frame = m_util.misc.get_frame(frame) |
||
− | |||
− | tpl_args.tables = 'items' |
||
− | tpl_args.fields = 'items.name, items.tags, items.class' |
||
− | local tbl = { |
||
− | {tpl_args.page, 'items._pageName = "%s"'}, |
||
− | {tpl_args.item, 'items.name = "%s"'}, |
||
− | } |
||
− | for _,v in ipairs(tbl) do |
||
− | if v[1] ~= nil then |
||
− | condition = string.format(v[2], v[1]) |
||
− | break |
||
− | end |
||
− | end |
||
− | tpl_args.q_where = condition |
||
− | tpl_args.q_groupBy = 'items._pageID' |
||
− | tpl_args.q_orderBy = 'items.name' |
||
− | |||
− | -- Query mods with cargo: |
||
− | results = h.cargo_query(tpl_args) |
||
− | |||
− | |||
− | |||
− | -- -- SMW workaround, remove when module:item2 is ready: |
||
− | -- local tbl = { |
||
− | -- {tpl_args.page, '[[%s]]'}, |
||
− | -- {tpl_args.item, '[[Has name::%s]]'}, |
||
− | -- } |
||
− | -- for _,v in ipairs(tbl) do |
||
− | -- if v[1] ~= nil then |
||
− | -- condition = string.format(v[2], v[1]) |
||
− | -- break |
||
− | -- end |
||
− | -- end |
||
− | -- local results = m_util.smw.query( |
||
− | -- { |
||
− | -- condition, |
||
− | -- '?Has name', |
||
− | -- '?Has tags', |
||
− | -- '?Has item class' |
||
− | -- }, |
||
− | -- frame |
||
− | -- ) |
||
− | -- for i,_ in ipairs(results) do |
||
− | -- results[i]['items.tags'] = results[i]['Has tags']:gsub('(<MANY>)', ', ') |
||
− | -- results[i]['items.class'] = results[i]['Has item class'] |
||
− | -- results[i]['items.name'] = results[i]['Has name'] |
||
− | -- results[i]['items._pageName'] = results[i][1] |
||
− | -- end |
||
− | -- -- |
||
− | |||
− | |||
− | results = p.get_mod_domain(results) |
||
− | |||
− | return results |
||
− | end |
||
− | |||
− | function p.header(str) |
||
− | --[[ |
||
− | This function replace specific numbers with a generic #. |
||
− | ]] |
||
− | |||
− | local s = table.concat(m_util.string.split(str, '%(%d+%.*%d*%-%d+%.*%d*%)'), '#') |
||
− | s = table.concat(m_util.string.split(s, '%d+%.*%d*'), '#') |
||
− | s = table.concat(m_util.string.split(s, '<br>'), ', ') |
||
− | |||
− | return s |
||
− | end |
||
− | |||
− | function p.get_spawn_chance(frame) |
||
− | --[[ |
||
− | Calculates the spawn chance of a set of mods that all have a |
||
− | spawn weight. |
||
− | ]] |
||
− | |||
− | -- Args |
||
− | local tpl_args = getArgs(frame, {parentFirst=true}) |
||
− | local frame = m_util.misc.get_frame(frame) |
||
− | |||
− | local tbl = tpl_args['tbl'] |
||
− | -- Probabilities affecting the result besides the spawn weight: |
||
− | local chance_multiplier = tonumber(tpl_args['chance_multiplier']) or 1 |
||
− | |||
− | local N = 0 |
||
− | for i,_ in ipairs(tbl) do |
||
− | -- Total number of outcomes. |
||
− | N = N + tbl[i]['spawn_weights.weight'] |
||
− | end |
||
− | |||
− | for i,_ in ipairs(tbl) do |
||
− | -- Number of ways it can happen: |
||
− | local n = tbl[i]['spawn_weights.weight'] |
||
− | |||
− | -- Truncated value: |
||
− | tbl[i]['spawn_weights.chance'] = string.format( |
||
− | "%0.2f%%", |
||
− | n/N * chance_multiplier*100 |
||
− | ) |
||
− | end |
||
− | |||
− | return tbl |
||
− | end |
||
− | |||
− | function p.drop_down_table(frame) |
||
− | --[[ |
||
− | This function queries mods that can spawn on an item. It compares |
||
− | the item tags and the spawn weight tags. If there's a match and |
||
− | the spawn weight is larger than zero, then that mod is added to a |
||
− | drop down list. |
||
− | |||
− | To Do |
||
− | * Misses forsaken masters currently. |
||
− | * Add a proper expand/collapse toggle for the entire header row so |
||
− | it reacts together with mw-collapsible. |
||
− | * Show Mod group in a better way perhaps: |
||
− | Mod group (expanded) |
||
− | # to Damage (Collapsed) |
||
− | 3 to Damage |
||
− | 5 to Damage |
||
− | |||
− | |||
− | Examples: |
||
− | Weapons |
||
− | p.drop_down_table{item = 'Rusted Hatchet', header = 'One Handed Axes'} |
||
− | p.drop_down_table{item = 'Stone Axe', header = 'Two Handed Axes'} |
||
− | |||
− | Accessories |
||
− | p.drop_down_table{item = 'Amber Amulet', header = 'Amulets'} |
||
− | |||
− | Jewels |
||
− | p.drop_down_table{item = 'Cobalt Jewel', header = 'Jewels'} |
||
− | |||
− | Armour |
||
− | p.drop_down_table{item = 'Plate Vest', header = 'Armour body armours'} |
||
− | p.drop_down_table{item = 'Iron Greaves', header = 'Armour boots'} |
||
− | p.drop_down_table{item = 'Iron Gauntlets', header = 'Armour gloves'} |
||
− | p.drop_down_table{item = 'Iron Hat', header = 'Armour helmets'} |
||
− | p.drop_down_table{item = 'Splintered Tower Shield', header = 'Armour shields'} |
||
− | |||
− | p.drop_down_table{ |
||
− | item = 'Fishing Rod', |
||
− | header = 'FISH PLEASE', |
||
− | item_tags = 'fishing_rod', |
||
− | extra_fields = 'Has spawn weight, Has spawn chance' |
||
− | } |
||
− | |||
− | = p.drop_down_table{ |
||
− | item = 'Fishing Rod', |
||
− | item_tags = 'axe, one_hand_weapon, onehand, weapon, default' |
||
− | } |
||
− | |||
− | = p.drop_down_table{ |
||
− | item = 'Vaal Blade', |
||
− | } |
||
− | |||
− | ]] |
||
− | |||
− | |||
− | -- Get template args: |
||
− | local tpl_args = getArgs(frame, {parentFirst=true}) |
||
− | local frame = m_util.misc.get_frame(frame) |
||
− | |||
− | -- Get the items tags: |
||
− | local get_item_tags = p.get_item_tags(tpl_args)[1] |
||
− | |||
− | -- For some reason cargo queried item tags, are not comma-space |
||
− | -- separated. |
||
− | local item_tags = {} |
||
− | if tpl_args.item_tags ~= nil then |
||
− | item_tags = m_util.string.split(tpl_args.item_tags, ', ') |
||
− | else |
||
− | item_tags = m_util.string.split(get_item_tags['items.tags'], ',') |
||
− | end |
||
− | -- local item_tags = m_util.string.split( |
||
− | -- tpl_args.item_tags or get_item_tags['items.tags'], |
||
− | -- ', ' |
||
− | -- ) |
||
− | |||
− | -- Create drop down lists in these sections and query in these |
||
− | -- generation types. |
||
− | local section = {} |
||
− | section = { |
||
− | [1] = { |
||
− | header = i18n.drop_down_table.prefix, |
||
− | generation_type = 1, |
||
− | }, |
||
− | [2] = { |
||
− | header = i18n.drop_down_table.suffix, |
||
− | generation_type = 2, |
||
− | }, |
||
− | [3] = { |
||
− | header = i18n.drop_down_table.corrupted, |
||
− | generation_type = 5, |
||
− | chance_multiplier = 1/4, -- See Vaal orb, for the 4 possible events. |
||
− | }, |
||
− | -- [4] = { |
||
− | -- header = 'Forsaken masters', |
||
− | -- generation_type = 'master', |
||
− | -- }, |
||
− | } |
||
− | |||
− | |||
− | -- Introductory text: |
||
− | local out = {} |
||
− | out[#out+1] = string.format( |
||
− | '==%s== \n', |
||
− | tpl_args['header'] or table.concat(item_tags, ', ') |
||
− | ) |
||
− | out[#out+1] = string.format( |
||
− | '<div style="float: right; text-align:center"><div class="mw-collapsible-collapse-all" style="cursor:pointer;">[%s]</div><hr><div class="mw-collapsible-expand-all" style="cursor:pointer;">[%s]</div></div>', |
||
− | i18n.drop_down_table.collapse_all, |
||
− | i18n.drop_down_table.expand_all |
||
− | ) |
||
− | out[#out+1] = string.format('%s %s.<br><br><br>', |
||
− | i18n.drop_down_table.table_intro, |
||
− | f_item_link{page=get_item_tags['items._pageName']} |
||
− | ) |
||
− | |||
− | local item_mods = {} |
||
− | local tableIndex = -1 |
||
− | for _, sctn in ipairs(section) do |
||
− | local container = mw.html.create('div') |
||
− | :attr('style', 'vertical-align:top; display:inline-block;') |
||
− | |||
− | -- Format the where condition: |
||
− | generation_type = sctn['generation_type'] |
||
− | local where = {} |
||
− | for _, item_tag in ipairs(item_tags) do |
||
− | where[#where+1] = string.format( |
||
− | '(spawn_weights.tag="%s" AND mods.generation_type=%s AND mods.domain=%s)', |
||
− | item_tag, |
||
− | sctn['generation_type'], |
||
− | get_item_tags['items.domain'] |
||
− | ) |
||
− | end |
||
− | |||
− | tpl_args.tables = 'mods, spawn_weights, mod_stats' |
||
− | tpl_args.fields = 'mods.name, mods.id, mods.required_level, mods.generation_type, mods.domain, mods.mod_group, mods.mod_type, mods.stat_text, mod_stats.id, spawn_weights.tag, spawn_weights.weight, spawn_weights.ordinal' |
||
− | tpl_args.q_join = 'mods._pageID=spawn_weights._pageID, mods._pageID=mod_stats._pageID' |
||
− | tpl_args.q_where = table.concat(where, ' OR ') |
||
− | tpl_args.q_groupBy = 'mods._pageID, spawn_weights.tag, spawn_weights.weight' |
||
− | tpl_args.q_orderBy = 'mods.generation_type, mods.mod_group, mods.mod_type, mods._pageName, mods.required_level, spawn_weights.ordinal' |
||
− | |||
− | local extra_fields = {} |
||
− | if tpl_args.extra_fields ~= nil then |
||
− | extra_fields = m_util.string.split(tpl_args.extra_fields, ', ') |
||
− | tpl_args.fields = string.format( |
||
− | '%s, %s', |
||
− | tpl_args.fields, |
||
− | table.concat(extra_fields, ', ') |
||
− | ) |
||
− | end |
||
− | |||
− | -- Query mods: |
||
− | results = h.cargo_query(tpl_args) |
||
− | |||
− | -- Create own list for spawn weights and group by page name: |
||
− | local spawn_weights = {} |
||
− | local results_unique = {} |
||
− | local hash = {} |
||
− | for _,v in ipairs(results) do |
||
− | if spawn_weights[v['mods._pageName']] == nil then |
||
− | spawn_weights[v['mods._pageName']] = {} |
||
− | end |
||
− | local n = #spawn_weights[v['mods._pageName']] or 0 |
||
− | spawn_weights[v['mods._pageName']][n+1] = v |
||
− | |||
− | -- Get a sorted list that only has unique page names: |
||
− | if hash[v['mods._pageName']] ~= true then |
||
− | results_unique[#results_unique+1] = v |
||
− | hash[v['mods._pageName']] = true |
||
− | end |
||
− | end |
||
− | |||
− | if #results_unique > 0 then |
||
− | item_mods[generation_type] = {} |
||
− | |||
− | -- Loop through all the modifiers from the concept pages: |
||
− | local last |
||
− | for _, v in ipairs(results_unique) do |
||
− | local pagename = v['spawn_weights._pageName'] |
||
− | |||
− | -- Loop through all the modifier tags until they match |
||
− | -- the item tags: |
||
− | local j = 0 |
||
− | local tag_match_stop |
||
− | repeat |
||
− | j = j+1 |
||
− | local mod_tag = spawn_weights[pagename][j]['spawn_weights.tag'] |
||
− | local mod_tag_weight = tonumber( |
||
− | spawn_weights[pagename][j]['spawn_weights.weight'] |
||
− | ) |
||
− | |||
− | -- Loop through the item tags until it matches the |
||
− | -- spawn weight tag and the mod tag has a value larger than |
||
− | -- zero: |
||
− | local y = 0 |
||
− | local tag_match_add = false |
||
− | repeat |
||
− | y = y+1 |
||
− | tag_match_stop = ((mod_tag == item_tags[y]) and ((mod_tag_weight or -1) >= 0)) or (spawn_weights[pagename][j] == nil) |
||
− | tag_match_add = (mod_tag == item_tags[y]) and ((mod_tag_weight or -1) > 0) |
||
− | until tag_match_stop or y == #item_tags |
||
− | |||
− | -- If there's a match then save that mod and other |
||
− | -- interesting information: |
||
− | if tag_match_add then |
||
− | |||
− | -- Assume that the mod is global then go through |
||
− | -- all the stat ids and check if any of the |
||
− | -- stats are local: |
||
− | local mod_scope = 'Global' |
||
− | for _, vv in ipairs(spawn_weights[pagename]) do |
||
− | if vv['mod_stats.id']:find('.*local.*') ~= nil then |
||
− | mod_scope = 'Local' |
||
− | end |
||
− | end |
||
− | |||
− | -- Save the matching modifier tag: |
||
− | local a = #item_mods[generation_type] |
||
− | item_mods[generation_type][a+1] = spawn_weights[pagename][j] |
||
− | |||
− | -- Save other interesting fields: |
||
− | item_mods[generation_type][a+1]['mods.scope'] = mod_scope |
||
− | item_mods[generation_type][a+1]['spawn_weight.idx_match'] = j |
||
− | item_mods[generation_type][a+1]['mods.add'] = tag_match_add |
||
− | item_mods[generation_type][a+1]['mods.stop'] = tag_match_stop |
||
− | end |
||
− | until tag_match_stop |
||
− | end |
||
− | |||
− | -- If the user wants to see the spawn chance then do the |
||
− | -- calculations and save that result as well: |
||
− | if tpl_args.spawn_chance ~= nil then |
||
− | extra_fields[#extra_fields+1] = 'spawn_weights.chance' |
||
− | item_mods[generation_type] = p.get_spawn_chance{ |
||
− | tbl = item_mods[generation_type], |
||
− | chance_multiplier = sctn['chance_multiplier'] |
||
− | } |
||
− | end |
||
− | |||
− | -- Create the drop down table with <table></table>: |
||
− | local headers = container |
||
− | headers |
||
− | :tag('h3') |
||
− | :wikitext(string.format( |
||
− | '%s', |
||
− | sctn['header'] |
||
− | ) |
||
− | ) |
||
− | :done() |
||
− | :done() |
||
− | |||
− | -- Loop through and add all matching mods to the <table>. |
||
− | local tbl, last |
||
− | for _, rows in ipairs(item_mods[generation_type]) do |
||
− | |||
− | -- If the last mod group is different to the current |
||
− | -- mod group then assume the mod isn't related and start |
||
− | -- a new drop down list: |
||
− | if rows['mods.mod_group'] ~= last then |
||
− | |||
− | -- Check through all the mods and see if there are |
||
− | -- multiple mod types within the same mod group: |
||
− | local count = {} |
||
− | for _, n in ipairs(item_mods[generation_type]) do |
||
− | |||
− | -- If the mod has the same mod group, then add |
||
− | -- the mod type to the counter. Only unique mod |
||
− | -- types matter so the number is just a dummy |
||
− | -- value: |
||
− | if n['mods.mod_group'] == rows['mods.mod_group'] then |
||
− | count[n['mods.mod_type']] = 1 |
||
− | end |
||
− | end |
||
− | |||
− | -- Calculate how many unique mod types with the |
||
− | -- same mod group there are: |
||
− | number_of_mod_types = 0 |
||
− | for _ in pairs(count) do |
||
− | number_of_mod_types = number_of_mod_types + 1 |
||
− | end |
||
− | |||
− | -- If there are multiple unique mod types with the |
||
− | -- same mod group then change the style of the drop |
||
− | -- down list to indicate it: |
||
− | if number_of_mod_types > 1 then |
||
− | tbl_caption = string.format( |
||
− | '%s', |
||
− | m_util.html.poe_color( |
||
− | 'mod', |
||
− | 'Mod group: ' .. rows['mods.mod_group'] |
||
− | ) |
||
− | ) |
||
− | else |
||
− | tbl_caption = string.format( |
||
− | '%s (%s)', |
||
− | m_util.html.poe_color( |
||
− | 'mod', |
||
− | p.header(rows['mods.stat_text']) |
||
− | ), |
||
− | rows['mods.scope'] |
||
− | ) |
||
− | end |
||
− | |||
− | -- Add class and style to the <table>: |
||
− | tableIndex = tableIndex+1 |
||
− | tbl = container:tag('table') |
||
− | tbl |
||
− | :attr('class', 'mw-collapsible mw-collapsed') |
||
− | :attr('style', |
||
− | 'text-align:left; line-height:1.60em; width:810px;' |
||
− | ) |
||
− | :tag('th') |
||
− | :attr('class', |
||
− | string.format( |
||
− | 'mw-customtoggle-%s', |
||
− | tableIndex |
||
− | ) |
||
− | ) |
||
− | :attr('style', |
||
− | 'text-align:left; line-height:1.40em; border-bottom:1pt solid dimgrey;' |
||
− | ) |
||
− | :attr('colspan', '3' .. #extra_fields) |
||
− | :wikitext(tbl_caption) |
||
− | :done() |
||
− | :done() |
||
− | end |
||
− | |||
− | -- If the mod has no name then use the mod id: |
||
− | local mod_name = rows['mods.name'] |
||
− | if mod_name == '' or mod_name == nil then |
||
− | mod_name = rows['mods.id'] |
||
− | end |
||
− | |||
− | -- Check if there are any extra properties to show in |
||
− | -- the drop down list and then add a cell for that, |
||
− | -- add this node at the end of the table row: |
||
− | local td = mw.html.create('td') |
||
− | if extra_fields ~= nil then |
||
− | for _, extra_field in ipairs(extra_fields) do |
||
− | td |
||
− | :attr('width', '*') |
||
− | :wikitext(string.format( |
||
− | '%s: %s ', |
||
− | extra_field, |
||
− | rows[extra_field] |
||
− | ) |
||
− | ) |
||
− | :done() |
||
− | end |
||
− | end |
||
− | |||
− | -- Add a table row with the interesting properties that |
||
− | -- modifier has: |
||
− | tbl |
||
− | :tag('tr') |
||
− | :attr('class', 'mw-collapsible mw-collapsed') |
||
− | :attr( |
||
− | 'id', |
||
− | string.format( |
||
− | 'mw-customcollapsible-%s', |
||
− | tableIndex |
||
− | ) |
||
− | ) |
||
− | :tag('td') |
||
− | :attr('width', '160') |
||
− | :wikitext( |
||
− | string.format( |
||
− | ' [[%s|%s]]', |
||
− | rows['mods._pageName'], |
||
− | mod_name:gsub('%s', ' ') |
||
− | ) |
||
− | ) |
||
− | :done() |
||
− | :tag('td') |
||
− | :attr('width', '1') |
||
− | :wikitext( |
||
− | string.format( |
||
− | '%s %s', |
||
− | game.level_requirement['short_upper']:gsub('%s', ' '), |
||
− | rows['mods.required_level'] |
||
− | ) |
||
− | ) |
||
− | :done() |
||
− | :tag('td') |
||
− | :attr('width', '*') |
||
− | :wikitext( |
||
− | string.format( |
||
− | '%s', |
||
− | m_util.html.poe_color( |
||
− | 'mod', |
||
− | rows['mods.stat_text']:gsub('<br>', ', ') |
||
− | ) |
||
− | ) |
||
− | ) |
||
− | :done() |
||
− | :node(td) |
||
− | :done() |
||
− | :done() |
||
− | |||
− | -- Save the last mod group for later comparison: |
||
− | last = rows['mods.mod_group'] |
||
− | end |
||
− | end |
||
− | |||
− | out[#out+1] = tostring(container) |
||
− | end |
||
− | |||
− | return table.concat(out,'') |
||
end |
end |
||
Revision as of 20:57, 10 February 2018
This Lua module is used on a very large number of pages. To avoid large-scale disruption and unnecessary server load, any changes to this module should first be tested in its /sandbox or /testcases subpages. The tested changes can then be added to this page in one single edit. Please consider discussing any changes on the talk page before implementing them. |
This module depends on the following other modules: |
Module for handling for Mods with Semantic MediaWiki support.
List of currently implemented templates
The above documentation is transcluded from Module:Mod/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.
--
-- Module for mod related templates
--
local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
local game = require('Module:Game')
local f_item_link = require('Module:Item link').item_link
local cargo = mw.ext.cargo
local p = {}
-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------
-- This section contains strings used by this module.
-- Add new strings here instead of in-code directly, this will help other
-- people to correct spelling mistakes easier and help with translation to
-- other PoE wikis.
local i18n = {
args = {
--
-- Mod template
--
-- main
id = 'id',
name = 'name',
mod_group = 'mod_group',
mod_type = 'mod_type',
domain = 'domain',
generation_type = 'generation_type',
required_level = 'required_level',
stat_text = 'stat_text',
granted_buff_id = 'granted_buff_id',
granted_buff_value = 'granted_buff_value',
granted_skill = 'granted_skill',
tags = 'tags',
-- sell price
sell_price_prefix = 'sell_price',
item_name = 'name',
amount = 'amount',
},
errors = {
--
-- Mod template
--
sell_price_duplicate_name = 'Do not specify a sell price item name multiple times. Adjust the amount instead.',
sell_price_missing_argument = 'Both %s and %s must be specified',
},
}
-- ----------------------------------------------------------------------------
-- m_utility / Helper functions
-- ----------------------------------------------------------------------------
local h = {}
-- Validate single value properties and set them
h.validate = {}
function h.validate.not_nil (args)
return function (arg)
if g_args[arg] == nil then
error(string.format('%s must not be nil', arg))
end
end
end
function h.validate.number (args)
return function (tpl_args, frame, value)
return m_util.cast.number(value, args)
end
end
function h.create_header(row)
local stat = mw.html.create('span')
local text, nsub = mw.ustring.gsub(row['Has stat text'], '%d+', '?')
stat
:attr('class', 'mod-table-header-stat')
:wikitext(text)
:done()
local mgroup = mw.html.create('span')
mgroup
:attr('class', 'mod-table-header-modgroup')
:wikitext(row['Has mod group'])
:done()
local tbl = mw.html.create('table')
tbl
:attr('class', 'wikitable mw-collapsible mw-collapsed mod-table')
:tag('tr')
:tag('th')
:attr('class', 'mod-table-header')
:attr('colspan', g_args.colspan)
:tag('span')
:attr('class', 'mod-table-header-container')
:wikitext(tostring(stat) .. tostring(mgroup))
:done()
:done()
return tbl
end
function h.format_mod(tbl, row, tags)
local tr = tbl:tag('tr')
tr
:tag('td')
:wikitext(string.format('[[%s|%s]]', row[1], row['Has name']))
:attr('class', 'mod-table-cell-name')
:done()
:tag('td')
:wikitext(row['Has level requirement'])
:attr('class', 'mod-table-cell-level')
:done()
:tag('td')
:wikitext(row['Has stat text'])
:attr('class', 'mod-table-cell-stat')
:done()
:tag('td')
:wikitext(table.concat(tags, ', '))
:attr('class', 'mod-table-cell-tags')
:done()
end
-- ----------------------------------------------------------------------------
-- Templates
-- ----------------------------------------------------------------------------
--
-- Template: Mod
--
local mod_map = {
main = {
table = 'mods',
order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
parse_order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'stat_text_raw', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
fields = {
id = {
name = i18n.args.id,
field = i18n.args.id,
type = 'String',
wikitext = 'Mod Id',
},
name = {
name = i18n.args.name,
field = i18n.args.name,
type = 'String',
wikitext = 'Name',
},
mod_group = {
name = i18n.args.mod_group,
field = i18n.args.mod_group,
type = 'String',
wikitext = 'Group',
},
mod_type = {
name = i18n.args.mod_type,
field = i18n.args.mod_type,
type = 'String',
wikitext = 'Mod type',
},
domain = {
name = i18n.args.domain,
field = i18n.args.domain,
type = 'Integer',
func = h.validate.number{min=1, max=15},
wikitext = 'Mod domain',
display = function (value)
return game.constants.mod.domains[value]['short_upper'] .. ' (Id: ' .. value .. ')'
end,
},
generation_type = {
name = i18n.args.generation_type,
field = i18n.args.generation_type,
type = 'Integer',
func = h.validate.number{min=1, max=12},
wikitext = 'Generation type',
display = function (value)
return game.constants.mod.generation_types[value]['short_upper'] .. ' (Id: ' .. value .. ')'
end,
},
required_level = {
name = i18n.args.required_level,
field = i18n.args.required_level,
type = 'Integer',
func = h.validate.number{min=0, max=100},
wikitext = 'Req. level',
},
stat_text = {
name = i18n.args.stat_text,
field = i18n.args.stat_text,
type = 'Text',
wikitext = 'Effect',
},
stat_text_raw = {
name = nil,
field = 'stat_text_raw',
type = 'Text',
func = function(tpl_args, frame)
if tpl_args.stat_text then
tpl_args.stat_text_raw = string.gsub(
-- [[x]] -> x
string.gsub(
tpl_args.stat_text, '%[%[([^%]|]+)%]%]', '%1'
),
-- [[x|y]] -> y
'%[%[[^|]+|([^%]|]+)%]%]', '%1'
)
end
return tpl_args.stat_text_raw
end
},
granted_buff_id = {
name = i18n.args.granted_buff_id,
field = i18n.args.granted_buff_id,
type = 'String',
wikitext = 'Granted Buff Id',
},
granted_buff_value = {
name = i18n.args.granted_buff_value,
field = i18n.args.granted_buff_value,
type = 'Integer',
wikitext = 'Granted Buff Value',
},
granted_skill = {
name = i18n.args.granted_skill,
field = i18n.args.granted_skill,
type = 'String',
wikitext = 'Granted Skill',
},
tags = {
name = i18n.args.tags,
field = i18n.args.tags,
type = 'List (,) of String',
wikitext = 'Tags',
func = function (tpl_args, frame, value)
if value == nil then
return {}
else
return m_util.string.split(value, ', ')
end
end,
func_cargo = function(tpl_args, frame)
return table.concat(tpl_args.tags, ',')
end,
display = function(value)
return table.concat(value, ', ')
end,
},
},
},
mod_sell_prices = {
table = 'mod_sell_prices',
order = {'name', 'amount'},
fields = {
name = {
name = i18n.args.item_name,
field = i18n.args.item_name,
type = 'String',
func = function (value) return value end,
},
amount = {
name = i18n.args.amount,
field = i18n.args.amount,
type = 'Integer',
func = tonumber,
},
},
},
}
p.table_main = m_util.cargo.declare_factory{data=mod_map.main}
p.table_mod_sell_prices = m_util.cargo.declare_factory{data=mod_map.mod_sell_prices}
function p.table_mod_stats(frame)
m_util.cargo.declare(frame, {
_table = 'mod_stats',
id = 'String',
min = 'Integer',
max = 'Integer',
})
end
-- p.mod{id = "LocalIncreasedPhysicalDamagePercentUniqueOneHandSword2", name = "", mod_group = "LocalPhysicalDamagePercent", domain = "1", generation_type = "3", required_level = "1", mod_type = "LocalPhysicalDamagePercent", stat_text = "150% increased Physical Damage", stat1_id = "local_physical_damage_+%", stat1_min = "150", stat1_max = "150"}
function p.mod(frame)
-- Get args
tpl_args = getArgs(frame, {
parentFirst = true
})
frame = m_util.misc.get_frame(frame)
--
-- Validation & semantic properties
--
-- Validate single value properties and set them
local cargo_data = {
_table = mod_map.main.table,
}
for _, key in pairs(mod_map.main.parse_order) do
data = mod_map.main.fields[key]
local value
if data.func ~= nil then
if data.name then
value = data.func(tpl_args, frame, tpl_args[data.name])
else
value = data.func(tpl_args, frame)
end
else
value = tpl_args[data.name]
end
tpl_args[key] = value
if data.field ~= nil then
if data.func_cargo then
cargo_data[data.field] = data.func_cargo(tpl_args, frame)
else
cargo_data[data.field] = value
end
end
end
m_util.cargo.store(frame, cargo_data)
-- Validate % set the stat subobjects
m_util.args.stats(tpl_args, {frame=frame})
for _, stat_data in pairs(tpl_args.stats) do
m_util.cargo.store(frame, {
_table = 'mod_stats',
id = stat_data.id,
min = stat_data.min,
max = stat_data.max,
})
end
-- Validate & set spawn weight subobjects
m_util.args.spawn_weight_list(tpl_args, {
frame=frame,
})
-- Validate & set generation weight subobjects
m_util.args.generation_weight_list(tpl_args, {
frame=frame,
})
-- Validate & set mod sell values
i = 0
local names = {}
local sell_prices = {}
repeat
i = i + 1
local id = {}
value = {}
for key, data in pairs(mod_map.mod_sell_prices.fields) do
id[key] = string.format('%s%s_%s', i18n.args.sell_price_prefix, i, data.name)
value[key] = data.func(tpl_args[id[key]])
end
if value.name == nil and value.amount == nil then
value = nil
elseif value.name ~= nil and value.amount ~= nil then
if names[value.name] then
error(i18n.errors.sell_price_duplicate_name)
else
names[value.name] = true
end
local cargo_data = {
_table = mod_map.mod_sell_prices.table,
}
for key, data in pairs(mod_map.mod_sell_prices.fields) do
cargo_data[data.field] = value[key]
end
m_util.cargo.store(frame, cargo_data)
sell_prices[#sell_prices+1] = value
else
error (string.format(i18n.errors.sell_price_missing_arguments, id.name, id.amount))
end
until value == nil
--
-- Display
--
local container = mw.html.create('div')
container
:attr('class', 'modbox')
-- core stats
local tbl = container:tag('table')
tbl
:attr('class', 'wikitable')
for _, key in ipairs(mod_map.main.order) do
local data = mod_map.main.fields[key]
local text
if data.display == nil then
text = tpl_args[key]
else
text = data.display(tpl_args[key])
end
tbl
:tag('tr')
:tag('th')
:wikitext(data.wikitext)
:done()
:tag('td')
:wikitext(text)
:done()
:done()
:done()
end
tbl
:tag('tr')
:tag('th')
:wikitext('Tags')
:done()
:tag('td')
:wikitext(table.concat(tpl_args['tags'], ', '))
:done()
:done()
:done()
-- stat table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 4)
:wikitext('Stats')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Stat Id')
:done()
:tag('th')
:wikitext('Min')
:done()
:tag('th')
:wikitext('Max')
:done()
:done()
:done()
for i=1, #tpl_args.stats do
local value = {
id = tpl_args['stat' .. i .. '_id'],
min = tpl_args['stat' .. i .. '_min'],
max = tpl_args['stat' .. i .. '_max'],
}
if value.id then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.id)
:done()
:tag('td')
:wikitext(value.min)
:done()
:tag('td')
:wikitext(value.max)
:done()
:done()
:done()
end
end
-- spawn weight table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext('Spawn Weights')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Tag')
:done()
:tag('th')
:wikitext('Weight')
:done()
:done()
:done()
i = 0
value = nil
repeat
i = i + 1
value = {
tag = tpl_args[string.format('spawn_weight%s_tag', i)],
value = tpl_args[string.format('spawn_weight%s_value', i)],
}
if value.tag then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.tag)
:done()
:tag('td')
:wikitext(value.value)
:done()
:done()
:done()
end
until value.tag == nil
-- generation weight table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext('Generation Weights')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Tag')
:done()
:tag('th')
:wikitext('Weight')
:done()
:done()
:done()
i = 0
value = nil
repeat
i = i + 1
value = {
tag = tpl_args[string.format('generation_weight%s_tag', i)],
value = tpl_args[string.format('generation_weight%s_value', i)],
}
if value.tag then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.tag)
:done()
:tag('td')
:wikitext(value.value)
:done()
:done()
:done()
end
until value.tag == nil
-- Sell prices
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 2)
:wikitext('Modifier sell price')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Item')
:done()
:done()
:done()
for i, value in ipairs(sell_prices) do
tbl
:tag('tr')
:tag('td')
:wikitext(value.amount)
:done()
:tag('td')
:wikitext(string.format('[[%s]]', value.name))
:done()
:done()
end
-- Generic messages on the page
out = {}
if mw.ustring.find(tpl_args['id'], '_') then
out[#out+1] = frame:expandTemplate{ title = 'Incorrect title', args = { title=tpl_args['id'] } } .. '\n\n\n'
end
if tpl_args['name'] then
out[#out+1] = string.format("'''%s''' is the internal id of modifier '''%s'''.\n", tpl_args['id'], tpl_args['name'])
else
out[#out+1] = string.format("'''%s''' is the internal id of an unnamed modifier.\n", tpl_args['id'], tpl_args['name'])
end
-- Categories
cats = {'Mods'}
-- Done -> output
return tostring(container) .. m_util.misc.add_category(cats) .. '\n' .. table.concat(out)
end
return p