Module:CombatAreas/AreaTables: Difference between revisions
From Melvor Idle
(_getDungeonRewards: Safely handle cases where boss monsters have no loot table) |
(getSlayerAreaTable: Fix area effect descriptions; Use in-game display order for all zone tables) |
||
Line 30: | Line 30: | ||
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Lowest Monster Level!!Highest Monster Level' | result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Lowest Monster Level!!Highest Monster Level' | ||
for i, area in ipairs(AreaData.combatAreas) do | |||
for i, area in | |||
result = result..'\r\n|-' | result = result..'\r\n|-' | ||
result = result..'\r\n|'..Icons.Icon({area.name, type='combat', size='50', notext=true}) | result = result..'\r\n|'..Icons.Icon({area.name, type='combat', size='50', notext=true}) | ||
Line 67: | Line 52: | ||
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Highest Monster Level!!Requirements!!Area Effect' | result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Highest Monster Level!!Requirements!!Area Effect' | ||
for i, area in ipairs(AreaData.slayerAreas) do | |||
for i, area in | |||
result = result..'\r\n|-' | result = result..'\r\n|-' | ||
result = result..'\r\n|'..Icons.Icon({area.name, type='slayer', size='50', notext=true}) | result = result..'\r\n|'..Icons.Icon({area.name, type='slayer', size='50', notext=true}) | ||
Line 96: | Line 66: | ||
result = result..'||' | result = result..'||' | ||
if area.areaEffectDescription ~= nil then | if area.areaEffectDescription ~= nil then | ||
result = result..area.areaEffectDescription | result = result .. string.gsub(area.areaEffectDescription, '${effectValue}', area.areaEffectValue or 0) | ||
end | end | ||
end | end | ||
Line 159: | Line 129: | ||
function p.getDungeonTable(frame) | function p.getDungeonTable(frame) | ||
local result = '{| class="wikitable sortable stickyHeader"' | local result = '{| class="wikitable sortable stickyHeader"' | ||
result = result..'\r\n|-class="headerRow-0"' | result = result..'\r\n|-class="headerRow-0"' | ||
result = result..'\r\n!colspan="2"|Dungeon!!Difficulty!!Monsters!!Boss Level!!Reward(s)!!Boss Pet' | result = result..'\r\n!colspan="2"|Dungeon!!Difficulty!!Monsters!!Boss Level!!Reward(s)!!Boss Pet' | ||
for i, dung in ipairs(AreaData.dungeons) do | |||
for i, dung in | |||
result = result..'\r\n|-' | result = result..'\r\n|-' | ||
result = result..'\r\n|data-sort-value="'..dung.name..'"|'..Icons.Icon({dung.name, type='dungeon', size='50', notext=true}) | result = result..'\r\n|data-sort-value="'..dung.name..'"|'..Icons.Icon({dung.name, type='dungeon', size='50', notext=true}) |
Revision as of 23:45, 13 November 2021
Documentation for this module may be created at Module:CombatAreas/AreaTables/doc
--Splitting this out so I can make Module:Monsters calls (Monsters calls CombatAreas, so this prevents a loop)
local p = {}
local AreaData = mw.loadData('Module:CombatAreas/data')
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 CombatAreas = require('Module:CombatAreas')
local Pets = require('Module:Pets')
function p.getLowHighLevels(idList)
local lowLevel = 1000000
local highLevel = 0
for i, monID in Shared.skpairs(idList) do
local monster = Monsters.getMonsterByID(monID)
local cmbLevel = Monsters._getMonsterCombatLevel(monster)
if cmbLevel < lowLevel then lowLevel = cmbLevel end
if cmbLevel > highLevel then highLevel = cmbLevel end
end
return lowLevel, highLevel
end
function p.getCombatAreaTable()
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Lowest Monster Level!!Highest Monster Level'
for i, area in ipairs(AreaData.combatAreas) do
result = result..'\r\n|-'
result = result..'\r\n|'..Icons.Icon({area.name, type='combat', size='50', notext=true})
result = result..'||'..Icons.Icon({area.name, type='combat', noicon=true})
local diff1 = Constants.getDifficultyString(area.difficulty[1])
local diff2 = Constants.getDifficultyString(area.difficulty[2])
result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
result = result..'||'..lowLvl..'||'..highLvl
end
result = result..'\r\n|}'
return result
end
function p.getSlayerAreaTable()
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Highest Monster Level!!Requirements!!Area Effect'
for i, area in ipairs(AreaData.slayerAreas) do
result = result..'\r\n|-'
result = result..'\r\n|'..Icons.Icon({area.name, type='slayer', size='50', notext=true})
result = result..'||'..Icons.Icon({area.name, type='slayer', noicon=true})
local diff1 = Constants.getDifficultyString(area.difficulty[1])
local diff2 = Constants.getDifficultyString(area.difficulty[2])
result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
result = result..'||'..highLvl
result = result..'||'..CombatAreas._getAreaRequirements(area)
result = result..'||'
if area.areaEffectDescription ~= nil then
result = result .. string.gsub(area.areaEffectDescription, '${effectValue}', area.areaEffectValue or 0)
end
end
result = result..'\r\n|}'
return result
end
function p._getDungeonRewards(area, asList)
if asList == nil then
asList = true
elseif type(asList) == 'string' then
asList = asList.upper ~= 'FALSE'
end
local bossMonster = Monsters.getMonsterByID(area.monsters[Shared.tableCount(area.monsters)])
local gpMin = bossMonster.dropCoins[1]
local gpMax = bossMonster.dropCoins[2] - 1
local chestID, chestQty, theChest = nil, nil, nil
if bossMonster.lootTable ~= nil and Shared.tableCount(bossMonster.lootTable) > 0 then
chestID = bossMonster.lootTable[1][1]
chestQty = bossMonster.lootTable[1][3]
theChest = Items.getItemByID(chestID)
end
local chr = asList and '* ' or ''
local rewardList = {}
if gpMin > 0 and gpMax > 0 then
table.insert(rewardList, chr..Icons.GP(gpMin, gpMax))
end
if theChest ~= nil then
table.insert(rewardList, chr..Icons.Icon({theChest.name, type='item', qty=chestQty}))
end
if area.name == 'Volcanic Cave' then
table.insert(rewardList, chr..Icons.Icon({'Fire Cape', type='item', qty=1}))
elseif area.name == 'Infernal Stronghold' then
table.insert(rewardList, chr..Icons.Icon({'Infernal Cape', type='item', qty=1}))
end
if asList then
return table.concat(rewardList, '\r\n')
else
return table.concat(rewardList, '<br/>')
end
end
function p.getDungeonRewards(frame)
local areaName = frame.args ~= nil and frame.args[1] or frame
local asList = frame.args ~= nil and frame.args[2] or true
local area = CombatAreas.getArea(areaName)
if area == nil then
return "ERROR: Could not find an area named "..areaName..'[[Category:Pages with script errors]]'
end
if area.type == 'dungeon' then
return p._getDungeonRewards(area, asList)
else
return "ERROR: "..areaName.." is not a dungeon[[Category:Pages with script errors]]"
end
end
function p.getDungeonTable(frame)
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|-class="headerRow-0"'
result = result..'\r\n!colspan="2"|Dungeon!!Difficulty!!Monsters!!Boss Level!!Reward(s)!!Boss Pet'
for i, dung in ipairs(AreaData.dungeons) do
result = result..'\r\n|-'
result = result..'\r\n|data-sort-value="'..dung.name..'"|'..Icons.Icon({dung.name, type='dungeon', size='50', notext=true})
result = result..'||'..Icons.Icon({dung.name, type='dungeon', noicon=true})
result = result..'||data-sort-value="'..dung.difficulty[1]..'"|'..CombatAreas._getAreaStat(dung, 'difficulty')
result = result..'||'..Shared.tableCount(dung.monsters)
local boss = Monsters.getMonsterByID(dung.monsters[Shared.tableCount(dung.monsters)])
result = result..'||'..Monsters._getMonsterCombatLevel(boss)
result = result..'||'..p._getDungeonRewards(dung, false)
if dung.petID ~= nil then
local pet = Pets.getPetByID(dung.petID)
result = result..'||data-sort-value="'..pet.name..'"|'..Icons.Icon({pet.name, type='pet'})
else
result = result..'|| '
end
end
result = result..'\r\n|}'
return result
end
function p._getDungeonDRTable(dung, mode, doStuns)
local AutoEatVals = {T1 = 0.2, T2 = 0.3, T3 = 0.4, T3W = 0.45}
--NOTE: Due to Agility Obstacles, this value is a tad arbitrary
local MaxViableHP = 1120
--This is the highest DR to list as possible. Value might be slightly off right now, currently just setting up value for testing
local MaxViableDR = 81
--This is the highest DR row shown. This should be higher than MaxViableDR
local MaxVisibleDR = 85
if doStuns == nil then
doStuns = true
elseif type(doStuns) == 'string' then
doStuns = string.upper(doStuns) == 'TRUE'
end
--First, figure out what our max hit for each style is
local MaxHits = { Melee = 0, Ranged = 0, Magic = 0 }
for i, monsterID in Shared.skpairs(dung.monsters) do
local monster = Monsters.getMonsterByID(monsterID)
local styleName = Constants.getCombatStyleName(monster.attackType)
local maxHit = Monsters._getMonsterMaxHit(monster, doStuns)
if maxHit > MaxHits[styleName] then
MaxHits[styleName] = maxHit
end
end
--Then, figure out the DR row to start with
--This is the DR that is one lower than the lowest possible DR for the best style
local StyleArray = {"Melee", "Ranged", "Magic"}
local EatThreshold = math.floor(MaxViableHP * AutoEatVals.T3W)
local minDR = 100
for i, playerStyle in Shared.skpairs(StyleArray) do
local maxStyleDR = 0
for enemyStyle, styleHit in Shared.skpairs(MaxHits) do
if styleHit > 0 and styleHit > EatThreshold then
local styleDR = math.ceil((1 - (EatThreshold / styleHit)) * 100)
styleDR = math.ceil(styleDR / Constants.getTriangleDRModifier(playerStyle, enemyStyle, mode))
maxStyleDR = math.max(maxStyleDR, styleDR)
end
end
minDR = math.min(minDR, maxStyleDR)
end
minDR = minDR - 1
--Finally, build the table using those starting points
local StyleHeader = "Melee!!Ranged!!Magic"
StyleHeader = StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader
local result = '{| class="wikitable stickyHeader"'
result = result..'\r\n|-class="headerRow-0"'
result = result..'\r\n!Pre-Triangle DR!!colspan=3|AE T3 + Wasteful!!colspan=3|Auto Eat Tier 3!!colspan=3|Auto Eat Tier 2!!colspan=3|Auto Eat Tier 1'
result = result..'\r\n|-class="headerRow-0"'
result = result..'\r\n!DR %!!'..StyleHeader
local getHpForStyle = function(playerStyle, autoEat, playerDR)
end
for dr = minDR, MaxVisibleDR, 1 do
end
result = result..'\r\n|}'
return result
end
function p.getDungeonDRTable(frame)
local dungName = frame.args ~= nil and frame.args[1] or frame[1]
local mode = frame.args ~= nil and frame.args[2] or frame[2]
local doStuns = frame.args ~= nil and frame.args[3] or frame[3]
local dung = CombatAreas.getArea(dungName)
if dung == nil then
return 'ERROR: Invalid dungeon name'
end
return p._getDungeonDRTable(dung, mode, doStuns)
end
return p