Module:Sandbox/AuronTest/SourceTables: Difference between revisions
From Melvor Idle
m (Revert to previous revision) |
mNo edit summary |
||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local Constants = require('Module:Constants') | local Constants = require('Module:Constants') | ||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
local Items = require('Module: | local Items = require('Module:Items') | ||
local Monsters = require('Module:Monsters') | local Monsters = require('Module:Monsters') | ||
local Magic = require('Module:Magic') | |||
local Attacks = require('Module:AuronTest') | |||
function p._getSpecialAttackTable(effectDefn, categories, sourceHeaderLabel, includeSource) | |||
local spAttTable = {} | |||
local | local attacks = Attacks.getAttacks(function(attack) | ||
if effectDefn == nil then | |||
return true | |||
else | |||
return Attacks.attackHasEffect(attack, effectDefn) | |||
end | |||
end) | |||
local includeCat = {} | |||
for i, category in ipairs(categories) do | |||
includeCat[category] = true | |||
end | |||
-- Compile a list of monsters, items, spells, etc. for each included attack | |||
for i, spAtt in ipairs(attacks) do | |||
-- Monsters | |||
if includeCat['Monster'] then | |||
for j, monsterID in ipairs(spAtt.monsters) do | |||
local monster = Monsters.getMonsterByID(monsterID) | |||
local overrideChance = (monster.overrideSpecialChances ~= nil and Shared.tableCount(monster.overrideSpecialChances) > 0) | |||
local attChance = spAtt.defaultChance | |||
if overrideChance then | |||
local attIdx = nil | |||
for k, monsterAttack in ipairs(monster.specialAttacks) do | |||
local attID = (type(monsterAttack) == 'table' and monsterAttack.id) or monsterAttack | |||
if spAtt.id == attID then | |||
attIdx = k | |||
break | |||
end | |||
end | |||
if attIdx ~= nil then | |||
attChance = monster.overrideSpecialChances[attIdx] | |||
end | |||
end | |||
table.insert(spAttTable, { idx = i, source = 'Monster', sourceSort = monster.name, sourceText = Icons.Icon({ monster.name, type = 'monster' }), chance = attChance, descType = 'monster' }) | |||
end | |||
end | |||
-- Items/Weapons | |||
if includeCat['Item'] then | |||
for j, itemID in ipairs(spAtt.items) do | |||
local item = Items.getItemByID(itemID) | |||
table.insert(spAttTable, { idx = i, source = 'Weapon', sourceSort = item.name, sourceText = Icons.Icon({ item.name, type = 'item' }), chance = spAtt.defaultChance, descType = 'player' }) | |||
end | |||
end | end | ||
-- Spells | |||
if includeCat['Spell'] then | |||
for j, spellID in ipairs(spAtt.spells) do | |||
local spell = Magic.getSpellByID(spellID[1], spellID[2]) | |||
table.insert(spAttTable, { idx = i, source = 'Spell', sourceSort = spell.name, sourceText = Icons.Icon({ spell.name, type = 'spell' }), chance = spAtt.defaultChance, descType = 'player' }) | |||
end | |||
end | end | ||
end | end | ||
-- Summoning familiars. Any effects inflicted by combat familiars aren't actually special | |||
-- attacks, therefore the handling here is a bit different and outside of the above attack loop | |||
if includeCat['Familiar'] then | |||
local famIdx = Shared.tableCount(attacks) + 1 | |||
local familiars = Items.getItems(function(item) | |||
end | if item.type == 'Familiar' and Items._getItemStat(item, 'summoningMaxhit') ~= nil and item.modifiers ~= nil then | ||
local famAttack = { prehitEffects = {}, onhitEffects = { { type = 'Modifier', subtype = 'Familiar', modifiers = item.modifiers } } } | |||
if effectDefn == nil then | |||
return Shared.tableCount(Attacks.getAttackEffects(famAttack)) > 0 | |||
else | |||
return Attacks.attackHasEffect(famAttack, effectDefn) | |||
end | |||
end | |||
return false | |||
end) | |||
for j, familiar in ipairs(familiars) do | |||
-- For chance, assume the first modifier we come across has the chance, which is pretty lazy | |||
local famChance, famDesc = 0, '' | |||
for modName, modVal in pairs(familiar.modifiers) do | |||
if type(modVal) == 'table' and type(modVal[1]) == 'number' then | |||
famChance = modVal[1] | |||
elseif type(modVal) == 'number' then | |||
famChance = modVal | |||
else | |||
famChance = 0 | |||
end | |||
famDesc = Constants._getModifierText(modName, modVal, false) | |||
break | |||
end | |||
table.insert(spAttTable, { idx = famIdx, source = 'Familiar', sourceSort = familiar.name, sourceText = Icons.Icon({ familiar.name, type = 'item' }), chance = famChance or 0, descType = 'player' }) | |||
-- Slap a dummy entry into the attacks table for this familiar | |||
attacks[famIdx] = { name = familiar.name .. ' (Familiar)', description = { player = famDesc } } | |||
famIdx = famIdx + 1 | |||
end | |||
end | end | ||
-- Nothing to output if there are no row definitions | |||
if Shared.tableCount(spAttTable) == 0 then | |||
return '' | |||
if | |||
end | end | ||
-- Sort entries into desired order and generate stats to determine row spans: | |||
-- By attack index, description type (monster/player), chance, source, then source name (weapon/item/etc.) | |||
table.sort(spAttTable, function (a, b) | |||
local sortKeys = { 'idx', 'descType', 'chance', 'source', 'sourceSort' } | |||
for i, key in ipairs(sortKeys) do | |||
if a[key] ~= b[key] then | |||
return a[key] < b[key] | |||
end | |||
end | |||
return false | |||
end) | |||
-- Determine row counts for grouping/rowspans | |||
local rowCounts = {} | |||
for i, rowDefn in ipairs(spAttTable) do | |||
local idx, dt, chance = rowDefn.idx, rowDefn.descType, rowDefn.chance | |||
if | if rowCounts[idx] == nil then | ||
rowCounts[idx] = { rows = 0 } | |||
end | end | ||
if rowCounts[idx][dt] == nil then | |||
rowCounts[idx][dt] = { rows = 0 } | |||
end | end | ||
if rowCounts[idx][dt][chance] == nil then | |||
rowCounts[idx][dt][chance] = 0 | |||
end | end | ||
rowCounts[idx]['rows'] = rowCounts[idx]['rows'] + 1 | |||
rowCounts[idx][dt]['rows'] = rowCounts[idx][dt]['rows'] + 1 | |||
rowCounts[idx][dt][chance] = rowCounts[idx][dt][chance] + 1 | |||
end | end | ||
-- Generate output table | |||
local resultPart = {} | |||
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"') | |||
table.insert(resultPart, '\r\n|- class="headerRow-0"') | |||
table.insert(resultPart, '\r\n!Name!!style="min-width:225px"| ' .. sourceHeaderLabel .. (includeSource and '!!Type' or '') .. '!!Chance!!Effect') | |||
local firstRow = { idx = true, descType = true, chance = true } | |||
local prevRowVal = { idx = 0, descType = '', chance = 0 } | |||
local resetOnChange = { | |||
idx = { 'idx', 'descType', 'chance' }, | |||
descType = { 'descType', 'chance' }, | |||
chance = { 'chance' } | |||
} | |||
local rowSuffix = '' | |||
for i, spAttRow in ipairs(spAttTable) do | |||
local spIdx = spAttRow.idx | |||
local spAtt = attacks[spIdx] | |||
-- Determine if it's the first row for any of our groupings | |||
local resetKeys = {} | |||
for key, val in pairs(prevRowVal) do | |||
if spAttRow[key] ~= prevRowVal[key] then | |||
for j, keyName in ipairs(resetOnChange[key]) do | |||
resetKeys[keyName] = true | |||
end | |||
end | |||
prevRowVal[key] = spAttRow[key] | |||
end | end | ||
for key, val in pairs(firstRow) do | |||
firstRow[key] = (resetKeys[key] ~= nil) | |||
end | end | ||
table.insert(resultPart, '\r\n|-') | |||
if | if firstRow.idx then | ||
rowSuffix = (rowCounts[spIdx]['rows'] > 1 and '|rowspan="' .. rowCounts[spIdx]['rows'] .. '"') or '' | |||
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.name) | |||
end | end | ||
table.insert(resultPart, '\r\n|data-sort-value="' .. spAttRow.sourceSort .. '"| ' .. spAttRow.sourceText) | |||
if includeSource then | |||
table.insert(resultPart, '\r\n| ' .. spAttRow.source) | |||
end | end | ||
if firstRow.chance then | |||
rowSuffix = (rowCounts[spIdx][spAttRow.descType][spAttRow.chance] > 1 and 'rowspan="' .. rowCounts[spIdx][spAttRow.descType][spAttRow.chance] .. '" ') or '' | |||
if | table.insert(resultPart, '\r\n|' .. rowSuffix .. 'data-sort-value="' .. spAttRow.chance .. '" style="text-align:right;"| ' .. Shared.round(spAttRow.chance, 2, 0) .. '%') | ||
end | end | ||
if firstRow.descType then | |||
rowSuffix = (rowCounts[spIdx][spAttRow.descType]['rows'] > 1 and '|rowspan="' .. rowCounts[spIdx][spAttRow.descType]['rows'] .. '"') or '' | |||
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt['description'][spAttRow.descType]) | |||
end | end | ||
end | end | ||
table.insert(resultPart, '\r\n|}') | |||
table.insert( | |||
return table.concat(resultPart) | |||
end | end | ||
function p. | function p.getSpecialAttackTable(frame) | ||
local args = frame.args ~= nil and frame.args or frame | |||
local tableCategories = {'Monster', 'Item', 'Spell', 'Familiar'} | |||
if args[1] ~= nil and args[1] ~= '' then | |||
tableCategories = Shared.splitString(args[1], ',') | |||
local | |||
if | |||
end | end | ||
local effectName = args['effect'] | |||
local sourceHeaderLabel = args['sourceHeader'] or 'Source' | |||
local includeSource = true | |||
if args['includeSource'] ~= nil and string.lower(args['includeSource']) == 'false' then | |||
includeSource = false | |||
local | |||
end | end | ||
local | local effectDefn = nil | ||
if | if effectName ~= nil and effectName ~= '' then | ||
effectDefn = Attacks.effectDefinition[effectName] | |||
if effectDefn == nil then | |||
local validEffectNames = {} | |||
for k, v in pairs(Attacks.effectDefinition) do | |||
table.insert(validEffectNames, k) | |||
end | |||
table.sort(validEffectNames, function(a, b) return a < b end) | |||
return 'ERROR: Invalid effect name "' .. effectName .. '", must be one of: ' .. table.concat(validEffectNames, ', ') .. '[[Category:Pages with script errors]]' | |||
end | end | ||
end | end | ||
return p._getSpecialAttackTable(effectDefn, tableCategories, sourceHeaderLabel, includeSource) | |||
end | end | ||
return p | return p |
Revision as of 23:26, 9 November 2021
Documentation for this module may be created at Module:Sandbox/AuronTest/SourceTables/doc
local p = {}
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Monsters = require('Module:Monsters')
local Magic = require('Module:Magic')
local Attacks = require('Module:AuronTest')
function p._getSpecialAttackTable(effectDefn, categories, sourceHeaderLabel, includeSource)
local spAttTable = {}
local attacks = Attacks.getAttacks(function(attack)
if effectDefn == nil then
return true
else
return Attacks.attackHasEffect(attack, effectDefn)
end
end)
local includeCat = {}
for i, category in ipairs(categories) do
includeCat[category] = true
end
-- Compile a list of monsters, items, spells, etc. for each included attack
for i, spAtt in ipairs(attacks) do
-- Monsters
if includeCat['Monster'] then
for j, monsterID in ipairs(spAtt.monsters) do
local monster = Monsters.getMonsterByID(monsterID)
local overrideChance = (monster.overrideSpecialChances ~= nil and Shared.tableCount(monster.overrideSpecialChances) > 0)
local attChance = spAtt.defaultChance
if overrideChance then
local attIdx = nil
for k, monsterAttack in ipairs(monster.specialAttacks) do
local attID = (type(monsterAttack) == 'table' and monsterAttack.id) or monsterAttack
if spAtt.id == attID then
attIdx = k
break
end
end
if attIdx ~= nil then
attChance = monster.overrideSpecialChances[attIdx]
end
end
table.insert(spAttTable, { idx = i, source = 'Monster', sourceSort = monster.name, sourceText = Icons.Icon({ monster.name, type = 'monster' }), chance = attChance, descType = 'monster' })
end
end
-- Items/Weapons
if includeCat['Item'] then
for j, itemID in ipairs(spAtt.items) do
local item = Items.getItemByID(itemID)
table.insert(spAttTable, { idx = i, source = 'Weapon', sourceSort = item.name, sourceText = Icons.Icon({ item.name, type = 'item' }), chance = spAtt.defaultChance, descType = 'player' })
end
end
-- Spells
if includeCat['Spell'] then
for j, spellID in ipairs(spAtt.spells) do
local spell = Magic.getSpellByID(spellID[1], spellID[2])
table.insert(spAttTable, { idx = i, source = 'Spell', sourceSort = spell.name, sourceText = Icons.Icon({ spell.name, type = 'spell' }), chance = spAtt.defaultChance, descType = 'player' })
end
end
end
-- Summoning familiars. Any effects inflicted by combat familiars aren't actually special
-- attacks, therefore the handling here is a bit different and outside of the above attack loop
if includeCat['Familiar'] then
local famIdx = Shared.tableCount(attacks) + 1
local familiars = Items.getItems(function(item)
if item.type == 'Familiar' and Items._getItemStat(item, 'summoningMaxhit') ~= nil and item.modifiers ~= nil then
local famAttack = { prehitEffects = {}, onhitEffects = { { type = 'Modifier', subtype = 'Familiar', modifiers = item.modifiers } } }
if effectDefn == nil then
return Shared.tableCount(Attacks.getAttackEffects(famAttack)) > 0
else
return Attacks.attackHasEffect(famAttack, effectDefn)
end
end
return false
end)
for j, familiar in ipairs(familiars) do
-- For chance, assume the first modifier we come across has the chance, which is pretty lazy
local famChance, famDesc = 0, ''
for modName, modVal in pairs(familiar.modifiers) do
if type(modVal) == 'table' and type(modVal[1]) == 'number' then
famChance = modVal[1]
elseif type(modVal) == 'number' then
famChance = modVal
else
famChance = 0
end
famDesc = Constants._getModifierText(modName, modVal, false)
break
end
table.insert(spAttTable, { idx = famIdx, source = 'Familiar', sourceSort = familiar.name, sourceText = Icons.Icon({ familiar.name, type = 'item' }), chance = famChance or 0, descType = 'player' })
-- Slap a dummy entry into the attacks table for this familiar
attacks[famIdx] = { name = familiar.name .. ' (Familiar)', description = { player = famDesc } }
famIdx = famIdx + 1
end
end
-- Nothing to output if there are no row definitions
if Shared.tableCount(spAttTable) == 0 then
return ''
end
-- Sort entries into desired order and generate stats to determine row spans:
-- By attack index, description type (monster/player), chance, source, then source name (weapon/item/etc.)
table.sort(spAttTable, function (a, b)
local sortKeys = { 'idx', 'descType', 'chance', 'source', 'sourceSort' }
for i, key in ipairs(sortKeys) do
if a[key] ~= b[key] then
return a[key] < b[key]
end
end
return false
end)
-- Determine row counts for grouping/rowspans
local rowCounts = {}
for i, rowDefn in ipairs(spAttTable) do
local idx, dt, chance = rowDefn.idx, rowDefn.descType, rowDefn.chance
if rowCounts[idx] == nil then
rowCounts[idx] = { rows = 0 }
end
if rowCounts[idx][dt] == nil then
rowCounts[idx][dt] = { rows = 0 }
end
if rowCounts[idx][dt][chance] == nil then
rowCounts[idx][dt][chance] = 0
end
rowCounts[idx]['rows'] = rowCounts[idx]['rows'] + 1
rowCounts[idx][dt]['rows'] = rowCounts[idx][dt]['rows'] + 1
rowCounts[idx][dt][chance] = rowCounts[idx][dt][chance] + 1
end
-- Generate output table
local resultPart = {}
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n!Name!!style="min-width:225px"| ' .. sourceHeaderLabel .. (includeSource and '!!Type' or '') .. '!!Chance!!Effect')
local firstRow = { idx = true, descType = true, chance = true }
local prevRowVal = { idx = 0, descType = '', chance = 0 }
local resetOnChange = {
idx = { 'idx', 'descType', 'chance' },
descType = { 'descType', 'chance' },
chance = { 'chance' }
}
local rowSuffix = ''
for i, spAttRow in ipairs(spAttTable) do
local spIdx = spAttRow.idx
local spAtt = attacks[spIdx]
-- Determine if it's the first row for any of our groupings
local resetKeys = {}
for key, val in pairs(prevRowVal) do
if spAttRow[key] ~= prevRowVal[key] then
for j, keyName in ipairs(resetOnChange[key]) do
resetKeys[keyName] = true
end
end
prevRowVal[key] = spAttRow[key]
end
for key, val in pairs(firstRow) do
firstRow[key] = (resetKeys[key] ~= nil)
end
table.insert(resultPart, '\r\n|-')
if firstRow.idx then
rowSuffix = (rowCounts[spIdx]['rows'] > 1 and '|rowspan="' .. rowCounts[spIdx]['rows'] .. '"') or ''
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.name)
end
table.insert(resultPart, '\r\n|data-sort-value="' .. spAttRow.sourceSort .. '"| ' .. spAttRow.sourceText)
if includeSource then
table.insert(resultPart, '\r\n| ' .. spAttRow.source)
end
if firstRow.chance then
rowSuffix = (rowCounts[spIdx][spAttRow.descType][spAttRow.chance] > 1 and 'rowspan="' .. rowCounts[spIdx][spAttRow.descType][spAttRow.chance] .. '" ') or ''
table.insert(resultPart, '\r\n|' .. rowSuffix .. 'data-sort-value="' .. spAttRow.chance .. '" style="text-align:right;"| ' .. Shared.round(spAttRow.chance, 2, 0) .. '%')
end
if firstRow.descType then
rowSuffix = (rowCounts[spIdx][spAttRow.descType]['rows'] > 1 and '|rowspan="' .. rowCounts[spIdx][spAttRow.descType]['rows'] .. '"') or ''
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt['description'][spAttRow.descType])
end
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
function p.getSpecialAttackTable(frame)
local args = frame.args ~= nil and frame.args or frame
local tableCategories = {'Monster', 'Item', 'Spell', 'Familiar'}
if args[1] ~= nil and args[1] ~= '' then
tableCategories = Shared.splitString(args[1], ',')
end
local effectName = args['effect']
local sourceHeaderLabel = args['sourceHeader'] or 'Source'
local includeSource = true
if args['includeSource'] ~= nil and string.lower(args['includeSource']) == 'false' then
includeSource = false
end
local effectDefn = nil
if effectName ~= nil and effectName ~= '' then
effectDefn = Attacks.effectDefinition[effectName]
if effectDefn == nil then
local validEffectNames = {}
for k, v in pairs(Attacks.effectDefinition) do
table.insert(validEffectNames, k)
end
table.sort(validEffectNames, function(a, b) return a < b end)
return 'ERROR: Invalid effect name "' .. effectName .. '", must be one of: ' .. table.concat(validEffectNames, ', ') .. '[[Category:Pages with script errors]]'
end
end
return p._getSpecialAttackTable(effectDefn, tableCategories, sourceHeaderLabel, includeSource)
end
return p