|
|
Line 1: |
Line 1: |
| local p = {}
| |
|
| |
|
| local Shared = require('Module:Shared')
| |
| local GameData = require('Module:GameData')
| |
| local SkillData = GameData.skillData
| |
| local Common = require('Module:Common')
| |
| local Modifiers = require('Module:Modifiers')
| |
| local Attacks = require('Module:Attacks')
| |
| local Icons = require('Module:Icons')
| |
| local Items = require('Module:Items')
| |
|
| |
| p.spellBooks = {
| |
| { id = 'standard', dataID = 'attackSpells', name = 'Standard Magic', imgType = 'spell', bookID = 'melvorD:Standard' },
| |
| { id = 'ancient', dataID = 'attackSpells', name = 'Ancient Magick', imgType = 'spell', bookID = 'melvorF:Ancient' },
| |
| { id = 'archaic', dataID = 'attackSpells', name = 'Archaic Magick', imgType = 'spell', bookID = 'melvorTotH:Archaic' },
| |
| { id = 'abyssal' , dataID = 'attackSpells', name = 'Abyssal', imgType = 'spell', bookID = 'melvorItA:Abyssal' },
| |
| { id = 'curse', dataID = 'curseSpells', name = 'Curse', imgType = 'curse' },
| |
| { id = 'aurora', dataID = 'auroraSpells', name = 'Aurora', imgType = 'aurora' },
| |
| { id = 'altMagic', dataID = 'altSpells', name = 'Alt. Magic', imgType = 'spell', dataRoot = GameData.getSkillData('melvorD:Magic') }
| |
| }
| |
|
| |
| function p.getSpellBookID(sectionName)
| |
| if sectionName == 'Spell' or sectionName == 'Standard' then
| |
| return 'standard'
| |
| elseif sectionName == 'Ancient' then
| |
| return 'ancient'
| |
| elseif sectionName == 'Archaic' then
| |
| return 'archaic'
| |
| elseif sectionName == 'Abyssal' then
| |
| return 'abyssal'
| |
| elseif sectionName == 'Curse' then
| |
| return 'curse'
| |
| elseif sectionName == 'Aurora' then
| |
| return 'aurora'
| |
| elseif Shared.contains({'Alt Magic', 'Alt. Magic', 'Alternative Magic'}, sectionName) then
| |
| return 'altMagic'
| |
| else
| |
| return sectionName
| |
| end
| |
| end
| |
|
| |
| -- Retrieves all spells within the given spellbook
| |
| function p.getSpellsBySpellBook(spellBookID)
| |
| if type(spellBookID) == 'string' then
| |
| local spellBook = GameData.getEntityByID(p.spellBooks, spellBookID)
| |
| if spellBook ~= nil then
| |
| local dataRoot = spellBook.dataRoot or GameData.rawData
| |
| local spellData = dataRoot[spellBook.dataID]
| |
| if spellBook.bookID == nil then
| |
| return spellData
| |
| else
| |
| return GameData.getEntities(spellData, function(spell) return spell.spellbook == spellBook.bookID end)
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
| local spellToSpellbookIdx = {}
| |
| for bookIdx, spellBook in ipairs(p.spellBooks) do
| |
| local spells = p.getSpellsBySpellBook(spellBook.id)
| |
| for _, spell in ipairs(spells) do
| |
| spellToSpellbookIdx[spell.id] = bookIdx
| |
| end
| |
| end
| |
|
| |
| function p.getSpellBookFromSpell(spell)
| |
| local bookIdx = spellToSpellbookIdx[spell.id]
| |
| if bookIdx ~= nil then
| |
| return p.spellBooks[bookIdx]
| |
| end
| |
| end
| |
|
| |
| function p.getSpell(name, spellType)
| |
| return p.getSpellByProperty(Shared.fixPagename(name), 'name', spellType)
| |
| end
| |
|
| |
| function p.getSpellByID(spellID, spellType)
| |
| return p.getSpellByProperty(spellID, 'id', spellType)
| |
| end
| |
|
| |
| function p.getSpellByProperty(spellProperty, propertyName, spellType)
| |
| if spellType == nil then
| |
| -- Look for spell in all spellbooks
| |
| for _, spellBook in ipairs(p.spellBooks) do
| |
| local spells = p.getSpellsBySpellBook(spellBook.id)
| |
| if spells ~= nil and not Shared.tableIsEmpty(spells) then
| |
| local spell = GameData.getEntityByProperty(spells, propertyName, spellProperty)
| |
| if spell ~= nil then
| |
| return spell
| |
| end
| |
| end
| |
| end
| |
| else
| |
| local spellBookID = p.getSpellBookID(spellType)
| |
| if spellBookID ~= nil then
| |
| local spells = p.getSpellsBySpellBook(spellBookID)
| |
| if spells ~= nil and not Shared.tableIsEmpty(spells) then
| |
| return GameData.getEntityByProperty(spells, propertyName, spellProperty)
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
| --Returns the expansion icon for the spell if it has one
| |
| function p.getExpansionIcon(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
|
| |
| return Icons.getExpansionIcon(spell.id)
| |
| end
| |
|
| |
| function p._getSpellIconType(spell)
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| if spellBook == nil then
| |
| -- Pick a suitable default
| |
| return 'spell'
| |
| else
| |
| return spellBook.imgType
| |
| end
| |
| end
| |
|
| |
| function p.getSpellIconType(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return 'spell'
| |
| else
| |
| return p._getSpellIconType(spell)
| |
| end
| |
| end
| |
|
| |
| function p._getSpellIcon(spell, size)
| |
| if size == nil then size = 50 end
| |
| local imgType = p._getSpellIconType(spell)
| |
| return Icons.Icon({spell.name, type=imgType, notext=true, size=size})
| |
| end
| |
|
| |
| function p._getSpellRequirements(spell)
| |
| -- All spells have a Magic level requirement
| |
| local extraReqs = {
| |
| {
| |
| ['type'] = 'SkillLevel',
| |
| ['skillID'] = 'melvorD:Magic',
| |
| ['level'] = spell.level
| |
| }
| |
| }
| |
| if spell.abyssalLevel ~= nil and spell.abyssalLevel > 0 then
| |
| table.insert(extraReqs, {
| |
| ['type'] = 'AbyssalLevel',
| |
| ['skillID'] = 'melvorD:Magic',
| |
| ['level'] = spell.abyssalLevel
| |
| })
| |
| end
| |
| if spell.requiredItemID ~= nil then
| |
| table.insert(extraReqs, {
| |
| ['type'] = 'SlayerItem',
| |
| ['itemID'] = spell.requiredItemID
| |
| })
| |
| end
| |
|
| |
| local resultPart = {}
| |
| for i, reqs in ipairs({ extraReqs, spell.requirements }) do
| |
| local reqStr = Common.getRequirementString(reqs)
| |
| if reqStr ~= nil then
| |
| table.insert(resultPart, reqStr)
| |
| end
| |
| end
| |
|
| |
| if Shared.tableIsEmpty(resultPart) then
| |
| return 'None'
| |
| else
| |
| return table.concat(resultPart, '<br/>')
| |
| end
| |
| end
| |
|
| |
| local function formatRuneList(runes)
| |
| local runeList = {}
| |
| for i, req in ipairs(runes) do
| |
| local rune = Items.getItemByID(req.id)
| |
| if rune ~= nil then
| |
| table.insert(runeList, Icons.Icon({rune.name, type='item', notext=true, qty=req.quantity}))
| |
| end
| |
| end
| |
| return table.concat(runeList, ', ')
| |
| end
| |
|
| |
|
| |
| function p._getSpellItems(spell)
| |
| if type(spell.fixedItemCosts) == 'table' then
| |
| local resultPart = {}
| |
| for i, req in ipairs(spell.fixedItemCosts) do
| |
| local item = Items.getItemByID(req.id)
| |
| if item ~= nil then
| |
| table.insert(resultPart, Icons.Icon({item.name, type='item', qty = req.quantity}))
| |
| end
| |
| end
| |
| return table.concat(resultPart, '<br/>')
| |
| else
| |
| return ''
| |
| end
| |
| end
| |
|
| |
| function p.getSpellItems(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
| return p._getSpellItems(spell)
| |
| end
| |
|
| |
| function p._getSpellRunes(spell)
| |
| if type(spell.runesRequired) == 'table' then
| |
| local resultPart = {}
| |
| table.insert(resultPart, formatRuneList(spell.runesRequired))
| |
| if spell.runesRequiredAlt ~= nil and not Shared.tablesEqual(spell.runesRequired, spell.runesRequiredAlt) then
| |
| table.insert(resultPart, "<br/>'''OR'''<br/>" .. formatRuneList(spell.runesRequiredAlt))
| |
| end
| |
| return table.concat(resultPart)
| |
| else
| |
| return ''
| |
| end
| |
| end
| |
|
| |
| function p.getSpellRunes(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
| return p._getSpellRunes(spell)
| |
| end
| |
|
| |
| -- Generates description template data. See: altMagic.js, description()
| |
| function p._getSpellTemplateData(spell)
| |
| local templateData = nil
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| if spellBook.id == 'altMagic' then
| |
| if spell.produces ~= nil then
| |
| -- Item produced varies depending on items consumed
| |
| if spell.produces == 'Bar' then
| |
| templateData = {
| |
| ["barAmount"] = spell.productionRatio,
| |
| ["oreAmount"] = spell.specialCost.quantity
| |
| }
| |
| elseif spell.produces == 'GP' then
| |
| templateData = {
| |
| ["percent"] = spell.productionRatio * 100
| |
| }
| |
| else
| |
| local itemProduced = Items.getItemByID(spell.produces)
| |
| local spellNS, spellLocalID = GameData.getLocalID(spell.id)
| |
| if itemProduced ~= nil and itemProduced.prayerPoints ~= nil and type(spell.fixedItemCosts) == 'table' and Shared.tableCount(spell.fixedItemCosts) == 1 and spellNS ~= 'melvorAoD' then
| |
| -- Item produced is a bone and spell is not from AoD (logic from altMagic.js)
| |
| local costItem = Items.getItemByID(spell.fixedItemCosts[1].id)
| |
| if costItem ~= nil then
| |
| templateData = {
| |
| ["itemName"] = costItem.name,
| |
| ["qty1"] = spell.fixedItemCosts[1].quantity,
| |
| ["qty2"] = itemProduced.prayerPoints
| |
| }
| |
| end
| |
| end
| |
| end
| |
| end
| |
| if templateData == nil then
| |
| templateData = {
| |
| ["amount"] = spell.productionRatio,
| |
| ["percent"] = spell.productionRatio * 100,
| |
| ["specialCostQty"] = spell.specialCost.quantity
| |
| }
| |
| if type(spell.fixedItemCosts) == 'table' then
| |
| for i, fixedCost in ipairs(spell.fixedItemCosts) do
| |
| local item = Items.getItemByID(fixedCost.id)
| |
| if item ~= nil then
| |
| templateData['fixedItemName' .. (i - 1)] = item.name
| |
| templateData['fixedItemQty' .. (i - 1)] = fixedCost.quantity
| |
| end
| |
| end
| |
| end
| |
| end
| |
| end
| |
| return (templateData or {})
| |
| end
| |
|
| |
| function p._getSpellDescription(spell, inline)
| |
| if inline == nil then inline = false end
| |
| local connector = inline and '<br/>' or ' and '
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| if spell.description ~= nil then
| |
| return Shared.applyTemplateData(spell.description, p._getSpellTemplateData(spell))
| |
| elseif spell.modifiers ~= nil or spell.targetModifiers ~= nil then
| |
| local resultPart = {}
| |
| if spell.modifiers ~= nil then
| |
| table.insert(resultPart, Modifiers.getModifiersText(spell.modifiers, false, inline))
| |
| end
| |
| if spell.targetModifiers ~= nil then
| |
| local targetModText = Modifiers.getModifiersText(spell.targetModifiers, false, inline)
| |
| if inline then
| |
| table.insert(resultPart, targetModText)
| |
| else
| |
| table.insert(resultPart, 'Enemies are inflicted with:<br/>' .. targetModText)
| |
| end
| |
| end
| |
| return table.concat(resultPart, connector)
| |
| elseif spell.specialAttackID ~= nil or spell.specialAttack ~= nil then
| |
| local spAtt = Attacks.getAttackByID(spell.specialAttackID or spell.specialAttack)
| |
| if spAtt ~= nil then
| |
| return spAtt.description
| |
| end
| |
| elseif spellBook.id == 'standard' then
| |
| return 'Combat spell with a max hit of ' .. Shared.formatnum(spell.maxHit * 10)
| |
| else
| |
| return ''
| |
| end
| |
| end
| |
|
| |
| function p._getSpellStat(spell, stat)
| |
| if stat == 'bigIcon' then
| |
| return p._getSpellIcon(spell, 250)
| |
| elseif stat == 'description' then
| |
| return p._getSpellDescription(spell)
| |
| elseif stat == 'icon' then
| |
| return p._getSpellIcon(spell)
| |
| elseif stat == 'requirements' then
| |
| return p._getSpellRequirements(spell)
| |
| elseif stat == 'runes' then
| |
| return p._getSpellRunes(spell)
| |
| elseif stat == 'type' then
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| return spellBook.name
| |
| elseif stat == 'spellDamage' then
| |
| if spell.maxHit ~= nil then
| |
| return spell.maxHit * 10
| |
| else
| |
| return 0
| |
| end
| |
| end
| |
| return spell[stat]
| |
| end
| |
|
| |
| function p.getSpellStat(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame[1]
| |
| local statName = frame.args ~= nil and frame.args[2] or frame[2]
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
| return p._getSpellStat(spell, statName)
| |
| end
| |
|
| |
| function p.getOtherSpellBoxText(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
|
| |
| local result = ''
| |
|
| |
| --11/01/22: Added Spell Damage for standard & archaic spells
| |
| if spellBook.id == 'standard' or spellBook.id == 'archaic' then
| |
| result = result.."\r\n|-\r\n|'''Spell Damage:''' "..p._getSpellStat(spell, 'spellDamage')
| |
| end
| |
| --8/20/21: Changed to using the new getSpellDescription function
| |
| -- TODO: Spell descriptions need fixing, now uses combat effects rather than modifiers
| |
| local spellDesc = p._getSpellStat(spell, 'description')
| |
| if spellDesc ~= '' then
| |
| result = result.."\r\n|-\r\n|'''Description:'''<br/>"..spellDesc
| |
| end
| |
|
| |
| return result
| |
| end
| |
|
| |
| function p._getSpellCategories(spell)
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| local result = '[[Category:Spells]]'
| |
| result = result..'[[Category:' .. spellBook.name .. ']]'
| |
| return result
| |
| end
| |
|
| |
| function p.getSpellCategories(frame)
| |
| local spellName = frame.args ~= nil and frame.args[1] or frame
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| end
| |
| return p._getSpellCategories(spell)
| |
| end
| |
|
| |
| function p._getAltSpellCostText(spell)
| |
| if spell.specialCost ~= nil then
| |
| local costType = spell.specialCost.type
| |
| if costType == nil or costType == 'None' then
| |
| if type(spell.fixedItemCosts) == 'table' then
| |
| local costText = {}
| |
| for i, itemCost in ipairs(spell.fixedItemCosts) do
| |
| local item = Items.getItemByID(itemCost.id)
| |
| if item ~= nil then
| |
| table.insert(costText, Icons.Icon({item.name, type='item', qty=itemCost.quantity}))
| |
| end
| |
| end
| |
| if not Shared.tableIsEmpty(costText) then
| |
| return table.concat(costText, ', ')
| |
| end
| |
| else
| |
| return nil
| |
| end
| |
| else
| |
| local qty = Shared.formatnum(spell.specialCost.quantity)
| |
| local typeString = {
| |
| ['AnyItem'] = qty .. ' of any item',
| |
| ['BarIngredientsWithCoal'] = qty .. ' x required ores for the chosen bar',
| |
| ['BarIngredientsWithoutCoal'] = qty .. ' x required ores (except ' .. Icons.Icon({'Coal Ore', type='item'}) .. ') for the chosen bar',
| |
| ['JunkItem'] = qty .. ' of any [[Fishing#Junk|Junk]] item',
| |
| ['SuperiorGem'] = qty .. ' of any superior gem',
| |
| ['AnyNormalFood'] = qty .. ' x non-perfect food'
| |
| }
| |
| return typeString[costType]
| |
| end
| |
| end
| |
| end
| |
|
| |
| function p.getSpellsProducingItem(itemID)
| |
| -- Only need to check Alt. Magic spells
| |
| local spellList = {}
| |
|
| |
| -- Classify whether the item fits into various categories
| |
| local isBar, isShard, isGem, isSuperiorGem, isPerfectFood = false, false, false, false, false
| |
| local item = Items.getItemByID(itemID)
| |
| if item ~= nil then
| |
| isBar = not Shared.tableIsEmpty(GameData.getEntities(SkillData.Smithing.recipes,
| |
| function(recipe)
| |
| return recipe.categoryID == 'melvorD:Bars' and recipe.productID == item.id
| |
| end))
| |
| isShard = GameData.getEntityByProperty(SkillData.Magic.randomShards, 'itemID', item.id) ~= nil
| |
| isGem = GameData.getEntityByProperty('randomGems', 'itemID', itemID) ~= nil
| |
| --Runestone can't be created by Alt Magic spells that make random superior gems.
| |
| isSuperiorGem = item.type == 'Superior Gem' and item.id ~= SkillData.Mining.runestoneItemID
| |
| if item.healsFor ~= nil then
| |
| -- Item is food, but is it a product of perfect cooking?
| |
| local cookData = GameData.getSkillData('melvorD:Cooking')
| |
| if cookData ~= nil and cookData.recipes ~= nil then
| |
| isPerfectFood = GameData.getEntityByProperty(cookData.recipes, 'perfectCookID', itemID) ~= nil
| |
| end
| |
| end
| |
| end
| |
|
| |
| for i, spell in ipairs(p.getSpellsBySpellBook('altMagic')) do
| |
| local includeSpell = false
| |
| if spell.produces ~= nil then
| |
| if spell.produces == itemID then
| |
| includeSpell = true
| |
| else
| |
| includeSpell = ((isBar and spell.produces == 'Bar') or
| |
| (isShard and spell.produces == 'RandomShards') or
| |
| (isGem and spell.produces == 'RandomGem') or
| |
| (isSuperiorGem and spell.produces == 'RandomSuperiorGem') or
| |
| (isPerfectFood and spell.produces == 'PerfectFood'))
| |
| end
| |
| if includeSpell then
| |
| table.insert(spellList, spell)
| |
| end
| |
| end
| |
| end
| |
|
| |
| table.sort(spellList, function(a, b) return a.level < b.level end)
| |
| return spellList
| |
| end
| |
|
| |
| -- If includeConsumes = true, then checks for Alt. Magic spell resource consumptions as well as
| |
| -- the rune cost of spells
| |
| function p.getSpellsUsingItem(itemID, includeConsumes)
| |
| if type(includeConsumes) ~= 'boolean' then
| |
| includeConsumes = false
| |
| end
| |
| local runeKeys = { 'runesRequired', 'runesRequiredAlt' }
| |
| local spellList = {}
| |
|
| |
| -- Initialize some vars & only populate if we're including resource consumptions
| |
| local isJunkItem, isSuperiorGem, isNormalFood, isCoal, isBarIngredient = false, false, false, false, false
| |
| if includeConsumes then
| |
| local thisItem = Items.getItemByID(itemID)
| |
| local junkItemIDs = GameData.getSkillData('melvorD:Fishing').junkItemIDs
| |
| isJunkItem = Shared.contains(junkItemIDs, itemID)
| |
| isSuperiorGem = thisItem.type == 'Superior Gem'
| |
| if thisItem.healsFor ~= nil then
| |
| -- Item is food, but is it from cooking & is it normal or perfect?
| |
| local cookData = GameData.getSkillData('melvorD:Cooking')
| |
| if cookData ~= nil and cookData.recipes ~= nil then
| |
| isNormalFood = GameData.getEntityByProperty(cookData.recipes, 'productID', itemID) ~= nil
| |
| end
| |
| end
| |
| isCoal = itemID == 'melvorD:Coal_Ore'
| |
| if not isCoal then
| |
| -- Don't need to check if the item is another bar ingredient if we already know it is coal
| |
| local smithingRecipes = GameData.getSkillData('melvorD:Smithing').recipes
| |
| for i, recipe in ipairs(smithingRecipes) do
| |
| if recipe.categoryID == 'melvorD:Bars' then
| |
| for k, itemCost in ipairs(recipe.itemCosts) do
| |
| if itemCost.id == itemID then
| |
| isBarIngredient = true
| |
| break
| |
| end
| |
| end
| |
| if isBarIngredient then
| |
| break
| |
| end
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
| -- Find applicable spells
| |
| for i, spellBook in ipairs(p.spellBooks) do
| |
| local spells = p.getSpellsBySpellBook(spellBook.id)
| |
| for j, spell in ipairs(spells) do
| |
| local foundSpell = false
| |
| -- Check runes first
| |
| for k, runeKey in ipairs(runeKeys) do
| |
| if spell[runeKey] ~= nil then
| |
| for m, req in ipairs(spell[runeKey]) do
| |
| if req.id == itemID then
| |
| foundSpell = true
| |
| break
| |
| end
| |
| end
| |
| end
| |
| if foundSpell then
| |
| break
| |
| end
| |
| end
| |
| if includeConsumes and not foundSpell then
| |
| -- Check items consumed by the spell
| |
| -- Fixed costs first, as that is a well-defined list of item IDs
| |
| if spell.fixedItemCosts ~= nil then
| |
| for k, itemCost in ipairs(spell.fixedItemCosts) do
| |
| if itemCost.id == itemID then
| |
| foundSpell = true
| |
| break
| |
| end
| |
| end
| |
| end
| |
| if not foundSpell and spell.specialCost ~= nil then
| |
| local costType = spell.specialCost.type
| |
| foundSpell = (isJunkItem and costType == 'JunkItem') or
| |
| (isSuperiorGem and costType == 'AnySuperiorGem') or
| |
| (isNormalFood and costType == 'AnyNormalFood') or
| |
| ((isCoal or isBarIngredient) and costType == 'BarIngredientsWithCoal') or
| |
| (isBarIngredient and costType == 'BarIngredientsWithoutCoal')
| |
| end
| |
| end
| |
|
| |
| if foundSpell then
| |
| table.insert(spellList, spell)
| |
| end
| |
| end
| |
| end
| |
|
| |
| table.sort(spellList, function(a, b)
| |
| local bookA, bookB = p.getSpellBookFromSpell(a), p.getSpellBookFromSpell(b)
| |
| if bookA.id ~= bookB.id then
| |
| return bookA.id < bookB.id
| |
| else
| |
| return a.level < b.level
| |
| end
| |
| end)
| |
| return spellList
| |
| end
| |
|
| |
| -- The below function is included for backwards compatibility
| |
| function p.getSpellsForRune(runeID)
| |
| return p.getSpellsUsingItem(runeID, false)
| |
| end
| |
|
| |
| function p.getSpellTypeLink(spellBookID)
| |
| if spellBookID == 'standard' then
| |
| return Icons.Icon({'Standard Magic', 'Standard', img='Standard', type='spellType'})
| |
| elseif spellBookID == 'ancient' then
| |
| return Icons.Icon({'Ancient Magicks', 'Ancient', img='Ancient', type='spellType'})
| |
| elseif spellBookID == 'archaic' then
| |
| return Icons.Icon({'Archaic Magicks', 'Archaic', img='Archaic', type='spellType'})
| |
| elseif spellBookID == 'abyssal' then
| |
| return Icons.Icon({'Abyssal Magicks', 'Abyssal', img='Abyssal', type='spellType'})
| |
| elseif spellBookID == 'curse' then
| |
| return Icons.Icon({'Curses', 'Curse', img='Curse', type='spellType'})
| |
| elseif spellBookID == 'aurora' then
| |
| return Icons.Icon({'Auroras', 'Aurora', img='Aurora', type='spellType'})
| |
| elseif spellBookID == 'altMagic' then
| |
| return Icons.Icon({'Alt. Magic', type='skill'})
| |
| end
| |
| return ''
| |
| end
| |
|
| |
| function p._getSpellHeader(includeTypeColumn, includeItems, includeDamage, includeExperience)
| |
|
| |
| end
| |
|
| |
| function p._getSpellRow(spell, includeTypeColumn, includeItems, includeDamage, includeExperience)
| |
|
| |
| end
| |
|
| |
| function p._getSpellTable(spellList, includeTypeColumn)
| |
| if type(spellList) == 'table' and not Shared.tableIsEmpty(spellList) then
| |
| local includeSpellbook, includeItems, includeDamage, includeExperience = false, false, false, false
| |
| if type(includeTypeColumn) == 'boolean' then
| |
| includeSpellbook = includeTypeColumn
| |
| end
| |
| -- Check to see what columns are required
| |
| for i, spell in ipairs(spellList) do
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| if not includeItems and p._getSpellItems(spell) ~= '' then
| |
| includeItems = true
| |
| end
| |
| if not includeExperience and spellBook.id == 'altMagic' then
| |
| includeExperience = true
| |
| end
| |
| if not includeDamage and (spellBook.id == 'archaic' or spellBook.id == 'standard') then
| |
| includeDamage = true
| |
| end
| |
| end
| |
|
| |
| local spellListSorted = Shared.shallowClone(spellList)
| |
| table.sort(spellListSorted, function(a, b) return a.level < b.level end)
| |
|
| |
| ---- Header stuff ----
| |
| local html = mw.html.create('table')
| |
| :addClass('wikitable sortable stickyHeader')
| |
|
| |
| local header = html:tag('tr')
| |
| header:tag('th'):wikitext('Spell')
| |
| :attr('colspan', 2)
| |
|
| |
| if includeTypeColumn then
| |
| header:tag('th'):wikitext('Spellbook')
| |
| end
| |
| header:tag('th'):wikitext('Requirements')
| |
| header:tag('th'):wikitext('[[DLC]]')
| |
|
| |
| if includeDamage then
| |
| header:tag('th'):wikitext('Spell Dmg')
| |
| end
| |
| header:tag('th'):wikitext('Description')
| |
| --table.insert(resultPart, 'style="width:275px"| Description')
| |
|
| |
| if includeExperience then
| |
| header:tag('th'):wikitext('XP')
| |
| end
| |
|
| |
| header:tag('th'):wikitext('Runes')
| |
| :css('min-width', '90px')
| |
|
| |
| if includeItems then
| |
| header:tag('th'):wikitext('Item Cost')
| |
| end
| |
|
| |
| ---- row stuff ----
| |
| for i, spell in ipairs(spellListSorted) do
| |
| local spellBook = p.getSpellBookFromSpell(spell)
| |
| local row = html:tag('tr')
| |
| row:tag('td'):wikitext(Icons.Icon({spell.name, type=spellBook.imgType, notext=true}))
| |
| :css('text-align', 'center')
| |
| :attr('data-sort-value', spell.name)
| |
| row:tag('td'):wikitext(Icons.Icon({spell.name, type=spellBook.imgType, noicon=true}))
| |
|
| |
| if includeTypeColumn then
| |
| row:tag('td'):wikitext(p.getSpellTypeLink(spellBook.id))
| |
| :attr('data-sort-value', spellBook.id)
| |
| end
| |
|
| |
| row:tag('td'):wikitext(p._getSpellRequirements(spell))
| |
| :attr('data-sort-value', spell.level)
| |
| row:tag('td'):wikitext(Icons.getDLCColumnIcon(spell.id))
| |
| :attr('data-sort-value', Icons.getExpansionID(spell.id))
| |
| :css('text-align', 'center')
| |
|
| |
| --11/01/22: Added base damage if requested
| |
| if includeDamage then
| |
| local dmg = p._getSpellStat(spell, 'spellDamage')
| |
| if dmg > 0 then
| |
| row:tag('td'):wikitext(dmg)
| |
| :css('text-align', 'right')
| |
| else
| |
| row:tag('td'):wikitext('N/A')
| |
| :addClass('table-na')
| |
| end
| |
| end
| |
|
| |
| --8/20/21: Changed to just getting the spell's description outright
| |
| row:tag('td'):wikitext(p._getSpellStat(spell, 'description'))
| |
|
| |
| --1/4/22: haha just kidding. Now we're also getting delay between attacks for spells with special attacks
| |
| local spAttID = spell.specialAttackID or spell.specialAttack
| |
| if spAttID ~= nil then
| |
| local spAtt = Attacks.getAttackByID(spAttID)
| |
| local interval = spAtt.attackInterval
| |
| local hits = spAtt.attackCount ~= nil and spAtt.attackCount or 1
| |
| if interval ~= nil and hits > 1 then
| |
| local intervalTable = {}
| |
| table.insert(intervalTable, '<br/>(' .. Shared.round(interval / 1000, 2, 2) .. 's delay between attacks.')
| |
| if hits > 2 then
| |
| table.insert(intervalTable, ' ' .. Shared.round(interval * (hits - 1) / 1000, 2, 2) .. 's total duration.')
| |
| end
| |
| table.insert(intervalTable, ')')
| |
| row:tag('td'):wikitext(table.concat(intervalTable))
| |
| end
| |
| end
| |
| if includeExperience then
| |
| local xp = spell.baseExperience
| |
| if xp == nil or xp == 0 then
| |
| row:tag('td'):wikitext('N/A')
| |
| :addClass('table-na')
| |
| else
| |
| row:tag('td'):wikitext(xp)
| |
| :addClass('text-align', 'right')
| |
| end
| |
| end
| |
| row:tag('td'):wikitext(p._getSpellRunes(spell))
| |
| :css('text-align', 'center')
| |
| if includeItems then
| |
| row:tag('td'):wikitext(p._getSpellItems(spell))
| |
| :css('text-align', 'center')
| |
| end
| |
| end
| |
|
| |
| return tostring(html)
| |
| end
| |
| end
| |
|
| |
| function p.getSpellTableFromList(frame)
| |
| local args = frame.args ~= nil and frame.args or frame
| |
| local spellListText = args[1]
| |
| local includeSpellbook = args.includeSpellbook ~= nil and string.lower(args.includeSpellbook) == 'true'
| |
| local spellNames = Shared.splitString(spellListText, ',')
| |
| local spellList = {}
| |
| for i, spellName in ipairs(spellNames) do
| |
| local spell = p.getSpell(spellName)
| |
| if spell == nil then
| |
| return Shared.printError('No spell named "' .. spellName .. '" exists in the data module')
| |
| else
| |
| table.insert(spellList, spell)
| |
| end
| |
| end
| |
| return p._getSpellTable(spellList, includeSpellbook)
| |
| end
| |
|
| |
| function p.getSpellBookTable(frame)
| |
| local spellBook = frame.args ~= nil and frame.args[1] or frame[1]
| |
| spellBook = p.getSpellBookID(spellBook)
| |
| return p._getSpellTable(p.getSpellsBySpellBook(spellBook), false)
| |
| end
| |
|
| |
| -- Included below for backwards compatibility
| |
| function p.getStandardSpellsTable(frame)
| |
| return p._getSpellTable(p.getSpellsBySpellBook('standard'), false)
| |
| end
| |
|
| |
| function p.getAncientTable(frame)
| |
| return p._getSpellTable(p.getSpellsBySpellBook('ancient'), false)
| |
| end
| |
|
| |
| function p.getCurseTable(frame)
| |
| return p._getSpellTable(p.getSpellsBySpellBook('curse'), false)
| |
| end
| |
|
| |
| function p.getAuroraTable(frame)
| |
| return p._getSpellTable(p.getSpellsBySpellBook('aurora'), false)
| |
| end
| |
|
| |
| function p.getAltSpellsTable(frame)
| |
| return p._getSpellTable(p.getSpellsBySpellBook('altMagic'), false)
| |
| end
| |
|
| |
| return p
| |