Module:Pets: Difference between revisions
From Melvor Idle
ByteFoolish (talk | contribs) m (Fix acquired by links for boss pets in pet table) |
m (Add Superior Tier only note to stronghold pet drops) |
||
(60 intermediate revisions by 4 users not shown) | |||
Line 2: | Line 2: | ||
local p = {} | local p = {} | ||
local Shared = require( "Module:Shared" ) | local Shared = require( "Module:Shared" ) | ||
local Constants = require('Module:Constants') | |||
local GameData = require('Module:GameData') | |||
local Modifiers = require('Module:Modifiers') | |||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
local | local Num = require('Module:Number') | ||
local areaDataKeys = { 'combatAreas', 'slayerAreas', 'dungeons', 'strongholds', 'abyssDepths' } | |||
-- Compute combat pet sources once for use later | |||
local function getCombatPetSources() | |||
local result = {} | |||
for _, key in ipairs(areaDataKeys) do | |||
local areas = GameData.getEntities(key, | |||
function(area) | |||
-- Lazy exclusion of event namespaces | |||
local areaNS, areaLocalID = Shared.getLocalID(area.id) | |||
if areaNS == 'melvorBirthday2023' or areaNS == 'melvorAprilFools2024' then | |||
return false | |||
end | |||
return area.pet ~= nil | |||
end | |||
) | |||
for i, area in ipairs(areas) do | |||
result[area.pet.petID] = { | |||
id = area.id, | |||
name = area.name, | |||
type = area.type, | |||
isCombat = true, | |||
weight = area.pet.weight, | |||
fixedChance = (area.fixedPetClears ~= nil and area.fixedPetClears) or area.pet.weight == 1 | |||
} | |||
end | |||
end | |||
return result | |||
end | |||
local CombatPetSources = getCombatPetSources() | |||
function p.getPetByID(ID) | function p.getPetByID(ID) | ||
return GameData.getEntityByID('pets', ID) | |||
end | end | ||
function p.getPet(name) | function p.getPet(name) | ||
return GameData.getEntityByName('pets', Shared.fixPagename(name)) | |||
end | |||
function p.getPets(checkFunc) | |||
return GameData.getEntities('pets', checkFunc) | |||
end | |||
--Returns the expansion icon for the pet if it has one | |||
function p.getExpansionIcon(frame) | |||
local petName = frame.args ~= nil and frame.args[1] or frame | |||
local pet = p.getPet(petName) | |||
if pet == nil then | |||
return Shared.printError('No pet named "' .. petName .. '" exists in the data module') | |||
end | |||
return Icons.getExpansionIcon(pet.id) | |||
end | |||
function p._getPetSource(pet) | |||
if CombatPetSources ~= nil and CombatPetSources[pet.id] ~= nil then | |||
return CombatPetSources[pet.id] | |||
else | |||
local skillID = p._getPetSkill(pet) | |||
if skillID ~= nil then | |||
local skillName = Constants.getSkillName(skillID) | |||
return { id = skillID, name = skillName, type = 'skill', isCombat = false } | |||
end | |||
end | |||
end | end | ||
function p. | function p._getPetSourceText(pet) | ||
local sourceOverrides = { | |||
-- useIcon: true if Source has an associated icon, false otherwise | |||
['Ripper the Reindeer'] = { text = '[[Events#Christmas Event 2020|Christmas Event 2020]]', useIcon = false }, | |||
['Festive Chio'] = { text = '[[Holiday Event 2021]]', useIcon = false }, | |||
['Festive Cool Rock'] = { text = '[[Holiday Event 2021]]', useIcon = false }, | |||
['Jerry the Giraffe'] = { text = '[[Golbin Raid|Golbin Raid Shop]]', useIcon = false }, | |||
['Preston the Platypus'] = { text = '[[Golbin Raid|Golbin Raid Shop]]', useIcon = false }, | |||
['Ty'] = { text = 'Mastery', useIcon = true }, | |||
['Golden Golbin'] = { text = Icons.Icon({'Golbin', type='monster'}) .. ' kills', useIcon = false}, | |||
['Saki'] = { text = 'Mastery', useIcon = true } | |||
} | |||
local petSourceText = nil | |||
local iconType = nil | |||
local useIcon = true | |||
local override = sourceOverrides[pet.name] | |||
if override ~= nil then | |||
petSourceText = override.text | |||
if override.useIcon ~= nil then | |||
useIcon = override.useIcon | |||
end | |||
end | |||
if petSourceText == nil then | |||
local petSource = p._getPetSource(pet) | |||
if petSource ~= nil then | |||
if petSource.isCombat then | |||
iconType = (petSource.type == 'dungeon' and 'dungeon') or 'combatArea' | |||
else | |||
iconType = petSource.type | |||
end | |||
petSourceText = petSource.name | |||
else | |||
useIcon = false | |||
petSourceText = '' | |||
end | |||
end | |||
if useIcon then | |||
return Icons.Icon({petSourceText, type=iconType}) | |||
else | |||
return petSourceText | |||
end | |||
end | end | ||
function p. | function p._getPetEffect(pet) | ||
local modKeys = {'modifiers', 'enemyModifiers'} | |||
local effects = {} | |||
for i, key in ipairs(modKeys) do | |||
if pet[key] ~= nil and not Shared.tableIsEmpty(pet[key]) then | |||
local preText = (key == 'enemyModifiers' and 'All enemies have: ' or '') | |||
table.insert(effects, preText .. Modifiers.getModifiersText(pet[key], false)) | |||
end | |||
end | |||
if Shared.tableIsEmpty(effects) then | |||
return 'None' | |||
else | |||
return table.concat(effects, '<br/>') | |||
end | |||
end | end | ||
function p. | function p._getPetChance(pet) | ||
local source = p._getPetSource(pet) | |||
if source ~= nil and source.weight ~= nil then | |||
-- Pet is from a dungeon or combat/slayer area | |||
if source.fixedChance then | |||
return 'Guaranteed after ' .. Num.formatnum(source.weight) .. (source.weight == 1 and ' clear' or ' clears') | |||
else | |||
return '1 in ' .. Num.formatnum(source.weight) .. ' (' .. Num.round(100 / source.weight, 2, 2) .. '%)' | |||
end | |||
else | |||
-- Skill pet or other | |||
return 'See: [[Pets#Acquiring Pets|Acquiring Pets]]' | |||
end | |||
end | end | ||
function p. | function p._getPetSkill(pet) | ||
local skillOverrides = { | |||
['melvorD:Ty'] = nil, | |||
['melvorF:Mark'] = 'melvorD:Summoning' | |||
} | |||
if skillOverrides[pet.id] ~= nil then | |||
return skillOverrides[pet.id] | |||
else | |||
return pet.skillID | |||
end | |||
end | end | ||
function p. | function p._getPetTable(pets) | ||
if type(pets) ~= 'table' or Shared.tableIsEmpty(pets) then | |||
return nil | |||
end | |||
local html = mw.html.create('table') | |||
:addClass('wikitable') | |||
html:tag('tr') | |||
:tag('th'):wikitext('Pet') | |||
:tag('th'):wikitext('Name') | |||
:tag('th'):wikitext('[[DLC]]') | |||
:tag('th'):wikitext('Effect') | |||
for i, pet in ipairs(pets) do | |||
html:tag('tr') | |||
:tag('td'):wikitext(Icons.Icon({pet.name, type='pet', notext=true})) | |||
:css('text-align', 'center') | |||
:tag('td'):wikitext('[[' .. pet.name .. ']]') | |||
:tag('td'):wikitext(Icons.getDLCColumnIcon(pet.id)) | |||
:css('text-align', 'center') | |||
:tag('td'):wikitext(p._getPetEffect(pet)) | |||
end | |||
return tostring(html) | |||
end | |||
function p.getPetTableBySkill(frame) | |||
local skillName = frame.args ~= nil and frame.args[1] or frame | |||
local skillID = Constants.getSkillID(skillName) | |||
if skillID == nil then | |||
error("SkillID not found for skill: " .. skillName) | |||
else | |||
local pets = p.getPets(function(pet) return p._getPetSkill(pet) == skillID end) | |||
if pets == nil or Shared.tableIsEmpty(pets) then | |||
return '' | |||
else | |||
return p._getPetTable(pets) | |||
end | |||
end | |||
end | |||
function p.getPetSidebar(frame) | |||
local args = frame.args ~= nil and frame.args or frame | |||
local result = nil | |||
local name = (args.name ~= nil and args.name ~= '') and args.name or args[1] | |||
local pet = p.getPet(name) | |||
if pet == nil then | |||
return Shared.printError('No pet named "' .. (name or 'Unknown') .. '" exists in the data module') | |||
end | |||
local effect = (args.effect ~= nil and args.effect ~= '') and args.effect or p._getPetEffect(pet) | |||
local completionReq = (pet.ignoreCompletion ~= nil and pet.ignoreCompletion) and 'No' or 'Yes' | |||
local dropChance = p._getPetChance(pet) | |||
result = '{| class="wikitable infobox"\r\n|-\r\n' | |||
result = result..'! ' .. Icons.getExpansionIcon(pet.id) .. name .. '\r\n|-\r\n| ' | |||
result = result..'style="text-align: center;"|' .. Icons.Icon({name, type='pet', size='250', notext=true}) | |||
result = result.."\r\n|-\r\n|'''Pet ID:''' "..pet.id | |||
result = result.."\r\n|-\r\n|'''Source:''' "..p._getPetSourceText(pet) | |||
if dropChance ~= nil then | |||
result = result.."\r\n|-\r\n|'''Drop Chance:''' "..dropChance | |||
end | |||
result = result.."\r\n|-\r\n| style =\"width: 250px;\"|'''Effect:''' "..effect | |||
result = result .. "\r\n|-\r\n|'''Part of 100% Completion:''' " .. completionReq .. "\r\n|}" | |||
return result | |||
end | |||
function p.getPetPageTable() | |||
local html = mw.html.create('table') | |||
:addClass('wikitable sortable lighttable stickyHeader') | |||
html:tag('tr'):addClass('headerRow-0') | |||
:tag('th'):attr('colspan', '2') | |||
:wikitext('Pet') | |||
:tag('th'):wikitext('[[DLC]]') | |||
:tag('th'):wikitext('Acquired From') | |||
:tag('th'):wikitext('Effect') | |||
for i, thisPet in ipairs(GameData.rawData.pets) do | |||
html:tag('tr') | |||
:tag('td'):addClass('table-img') | |||
:attr('data-sort-value', thisPet.name) | |||
:wikitext(Icons.Icon({thisPet.name, type='pet', notext=true})) | |||
:css('text-align', 'center') | |||
:tag('td'):wikitext('[[' .. thisPet.name .. ']]') | |||
:tag('td'):wikitext(Icons.getDLCColumnIcon(thisPet.id)) | |||
:css('text-align', 'center') | |||
:attr('data-sort-value', Icons.getExpansionID(thisPet.id)) | |||
:tag('td'):wikitext(p._getPetSourceText(thisPet)) | |||
:tag('td'):wikitext(p._getPetEffect(thisPet)) | |||
end | end | ||
return tostring(html) | |||
end | end | ||
function p. | function p.getDungeonBoxPetText(frame) | ||
local dungeonName = frame.args ~= nil and frame.args[1] or frame | |||
local dung = nil | |||
for i, key in ipairs(areaDataKeys) do | |||
dung = GameData.getEntityByName(key, dungeonName) | |||
if dung ~= nil then | |||
break | |||
end | |||
end | |||
if dung == nil then | |||
return Shared.printError('No dungeon named "' .. dungeonName .. '" exists in the data module') | |||
end | |||
if dung.pet ~= nil then | |||
local pet = p.getPetByID(dung.pet.petID) | |||
if pet ~= nil then | |||
local result = "\r\n|-\r\n|'''[[Pets#Boss Pets|Pet]]:'''<br/>" | |||
result = result..Icons.Icon({pet.name, type='pet'}) | |||
result = result.."\r\n|-\r\n|'''Pet Drop Chance:'''<br/>"..p._getPetChance(pet) | |||
if dung.type == 'stronghold' then | |||
result = result..' - Superior Tier only' | |||
end | |||
return result | |||
end | |||
end | |||
end | end | ||
return p | return p |
Latest revision as of 22:43, 7 August 2024
Data for this page is stored in Module:GameData/data
--This module contains all sorts of functions for getting data on pets
local p = {}
local Shared = require( "Module:Shared" )
local Constants = require('Module:Constants')
local GameData = require('Module:GameData')
local Modifiers = require('Module:Modifiers')
local Icons = require('Module:Icons')
local Num = require('Module:Number')
local areaDataKeys = { 'combatAreas', 'slayerAreas', 'dungeons', 'strongholds', 'abyssDepths' }
-- Compute combat pet sources once for use later
local function getCombatPetSources()
local result = {}
for _, key in ipairs(areaDataKeys) do
local areas = GameData.getEntities(key,
function(area)
-- Lazy exclusion of event namespaces
local areaNS, areaLocalID = Shared.getLocalID(area.id)
if areaNS == 'melvorBirthday2023' or areaNS == 'melvorAprilFools2024' then
return false
end
return area.pet ~= nil
end
)
for i, area in ipairs(areas) do
result[area.pet.petID] = {
id = area.id,
name = area.name,
type = area.type,
isCombat = true,
weight = area.pet.weight,
fixedChance = (area.fixedPetClears ~= nil and area.fixedPetClears) or area.pet.weight == 1
}
end
end
return result
end
local CombatPetSources = getCombatPetSources()
function p.getPetByID(ID)
return GameData.getEntityByID('pets', ID)
end
function p.getPet(name)
return GameData.getEntityByName('pets', Shared.fixPagename(name))
end
function p.getPets(checkFunc)
return GameData.getEntities('pets', checkFunc)
end
--Returns the expansion icon for the pet if it has one
function p.getExpansionIcon(frame)
local petName = frame.args ~= nil and frame.args[1] or frame
local pet = p.getPet(petName)
if pet == nil then
return Shared.printError('No pet named "' .. petName .. '" exists in the data module')
end
return Icons.getExpansionIcon(pet.id)
end
function p._getPetSource(pet)
if CombatPetSources ~= nil and CombatPetSources[pet.id] ~= nil then
return CombatPetSources[pet.id]
else
local skillID = p._getPetSkill(pet)
if skillID ~= nil then
local skillName = Constants.getSkillName(skillID)
return { id = skillID, name = skillName, type = 'skill', isCombat = false }
end
end
end
function p._getPetSourceText(pet)
local sourceOverrides = {
-- useIcon: true if Source has an associated icon, false otherwise
['Ripper the Reindeer'] = { text = '[[Events#Christmas Event 2020|Christmas Event 2020]]', useIcon = false },
['Festive Chio'] = { text = '[[Holiday Event 2021]]', useIcon = false },
['Festive Cool Rock'] = { text = '[[Holiday Event 2021]]', useIcon = false },
['Jerry the Giraffe'] = { text = '[[Golbin Raid|Golbin Raid Shop]]', useIcon = false },
['Preston the Platypus'] = { text = '[[Golbin Raid|Golbin Raid Shop]]', useIcon = false },
['Ty'] = { text = 'Mastery', useIcon = true },
['Golden Golbin'] = { text = Icons.Icon({'Golbin', type='monster'}) .. ' kills', useIcon = false},
['Saki'] = { text = 'Mastery', useIcon = true }
}
local petSourceText = nil
local iconType = nil
local useIcon = true
local override = sourceOverrides[pet.name]
if override ~= nil then
petSourceText = override.text
if override.useIcon ~= nil then
useIcon = override.useIcon
end
end
if petSourceText == nil then
local petSource = p._getPetSource(pet)
if petSource ~= nil then
if petSource.isCombat then
iconType = (petSource.type == 'dungeon' and 'dungeon') or 'combatArea'
else
iconType = petSource.type
end
petSourceText = petSource.name
else
useIcon = false
petSourceText = ''
end
end
if useIcon then
return Icons.Icon({petSourceText, type=iconType})
else
return petSourceText
end
end
function p._getPetEffect(pet)
local modKeys = {'modifiers', 'enemyModifiers'}
local effects = {}
for i, key in ipairs(modKeys) do
if pet[key] ~= nil and not Shared.tableIsEmpty(pet[key]) then
local preText = (key == 'enemyModifiers' and 'All enemies have: ' or '')
table.insert(effects, preText .. Modifiers.getModifiersText(pet[key], false))
end
end
if Shared.tableIsEmpty(effects) then
return 'None'
else
return table.concat(effects, '<br/>')
end
end
function p._getPetChance(pet)
local source = p._getPetSource(pet)
if source ~= nil and source.weight ~= nil then
-- Pet is from a dungeon or combat/slayer area
if source.fixedChance then
return 'Guaranteed after ' .. Num.formatnum(source.weight) .. (source.weight == 1 and ' clear' or ' clears')
else
return '1 in ' .. Num.formatnum(source.weight) .. ' (' .. Num.round(100 / source.weight, 2, 2) .. '%)'
end
else
-- Skill pet or other
return 'See: [[Pets#Acquiring Pets|Acquiring Pets]]'
end
end
function p._getPetSkill(pet)
local skillOverrides = {
['melvorD:Ty'] = nil,
['melvorF:Mark'] = 'melvorD:Summoning'
}
if skillOverrides[pet.id] ~= nil then
return skillOverrides[pet.id]
else
return pet.skillID
end
end
function p._getPetTable(pets)
if type(pets) ~= 'table' or Shared.tableIsEmpty(pets) then
return nil
end
local html = mw.html.create('table')
:addClass('wikitable')
html:tag('tr')
:tag('th'):wikitext('Pet')
:tag('th'):wikitext('Name')
:tag('th'):wikitext('[[DLC]]')
:tag('th'):wikitext('Effect')
for i, pet in ipairs(pets) do
html:tag('tr')
:tag('td'):wikitext(Icons.Icon({pet.name, type='pet', notext=true}))
:css('text-align', 'center')
:tag('td'):wikitext('[[' .. pet.name .. ']]')
:tag('td'):wikitext(Icons.getDLCColumnIcon(pet.id))
:css('text-align', 'center')
:tag('td'):wikitext(p._getPetEffect(pet))
end
return tostring(html)
end
function p.getPetTableBySkill(frame)
local skillName = frame.args ~= nil and frame.args[1] or frame
local skillID = Constants.getSkillID(skillName)
if skillID == nil then
error("SkillID not found for skill: " .. skillName)
else
local pets = p.getPets(function(pet) return p._getPetSkill(pet) == skillID end)
if pets == nil or Shared.tableIsEmpty(pets) then
return ''
else
return p._getPetTable(pets)
end
end
end
function p.getPetSidebar(frame)
local args = frame.args ~= nil and frame.args or frame
local result = nil
local name = (args.name ~= nil and args.name ~= '') and args.name or args[1]
local pet = p.getPet(name)
if pet == nil then
return Shared.printError('No pet named "' .. (name or 'Unknown') .. '" exists in the data module')
end
local effect = (args.effect ~= nil and args.effect ~= '') and args.effect or p._getPetEffect(pet)
local completionReq = (pet.ignoreCompletion ~= nil and pet.ignoreCompletion) and 'No' or 'Yes'
local dropChance = p._getPetChance(pet)
result = '{| class="wikitable infobox"\r\n|-\r\n'
result = result..'! ' .. Icons.getExpansionIcon(pet.id) .. name .. '\r\n|-\r\n| '
result = result..'style="text-align: center;"|' .. Icons.Icon({name, type='pet', size='250', notext=true})
result = result.."\r\n|-\r\n|'''Pet ID:''' "..pet.id
result = result.."\r\n|-\r\n|'''Source:''' "..p._getPetSourceText(pet)
if dropChance ~= nil then
result = result.."\r\n|-\r\n|'''Drop Chance:''' "..dropChance
end
result = result.."\r\n|-\r\n| style =\"width: 250px;\"|'''Effect:''' "..effect
result = result .. "\r\n|-\r\n|'''Part of 100% Completion:''' " .. completionReq .. "\r\n|}"
return result
end
function p.getPetPageTable()
local html = mw.html.create('table')
:addClass('wikitable sortable lighttable stickyHeader')
html:tag('tr'):addClass('headerRow-0')
:tag('th'):attr('colspan', '2')
:wikitext('Pet')
:tag('th'):wikitext('[[DLC]]')
:tag('th'):wikitext('Acquired From')
:tag('th'):wikitext('Effect')
for i, thisPet in ipairs(GameData.rawData.pets) do
html:tag('tr')
:tag('td'):addClass('table-img')
:attr('data-sort-value', thisPet.name)
:wikitext(Icons.Icon({thisPet.name, type='pet', notext=true}))
:css('text-align', 'center')
:tag('td'):wikitext('[[' .. thisPet.name .. ']]')
:tag('td'):wikitext(Icons.getDLCColumnIcon(thisPet.id))
:css('text-align', 'center')
:attr('data-sort-value', Icons.getExpansionID(thisPet.id))
:tag('td'):wikitext(p._getPetSourceText(thisPet))
:tag('td'):wikitext(p._getPetEffect(thisPet))
end
return tostring(html)
end
function p.getDungeonBoxPetText(frame)
local dungeonName = frame.args ~= nil and frame.args[1] or frame
local dung = nil
for i, key in ipairs(areaDataKeys) do
dung = GameData.getEntityByName(key, dungeonName)
if dung ~= nil then
break
end
end
if dung == nil then
return Shared.printError('No dungeon named "' .. dungeonName .. '" exists in the data module')
end
if dung.pet ~= nil then
local pet = p.getPetByID(dung.pet.petID)
if pet ~= nil then
local result = "\r\n|-\r\n|'''[[Pets#Boss Pets|Pet]]:'''<br/>"
result = result..Icons.Icon({pet.name, type='pet'})
result = result.."\r\n|-\r\n|'''Pet Drop Chance:'''<br/>"..p._getPetChance(pet)
if dung.type == 'stronghold' then
result = result..' - Superior Tier only'
end
return result
end
end
end
return p