Module:CombatAreas/AreaTables: Difference between revisions

From Melvor Idle
(_getDungeonRewards: Add support for Impending Darkness Event)
(Use tabs instead of spaces for indentation; _getDungeonRewards: Rework to remove redundant cape overrides)
Line 14: Line 14:


function p.getLowHighLevels(idList)
function p.getLowHighLevels(idList)
  local lowLevel = 1000000
local lowLevel = 1000000
  local highLevel = 0
local highLevel = 0
  for i, monID in Shared.skpairs(idList) do
for i, monID in Shared.skpairs(idList) do
    local monster = Monsters.getMonsterByID(monID)
local monster = Monsters.getMonsterByID(monID)
    local cmbLevel = Monsters._getMonsterCombatLevel(monster)
local cmbLevel = Monsters._getMonsterCombatLevel(monster)
    if cmbLevel < lowLevel then lowLevel = cmbLevel end
if cmbLevel < lowLevel then lowLevel = cmbLevel end
    if cmbLevel > highLevel then highLevel = cmbLevel end
if cmbLevel > highLevel then highLevel = cmbLevel end
  end
end
  return lowLevel, highLevel
return lowLevel, highLevel
end
end


function p.getCombatAreaTable()
function p.getCombatAreaTable()
  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"|Zone!!Difficulty!!Lowest Monster Level!!Highest Monster Level'
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Lowest Monster Level!!Highest Monster Level'


  for i, areaIdx in ipairs(AreaData.displayOrder.combatAreas) do
for i, areaIdx in ipairs(AreaData.displayOrder.combatAreas) do
  local area = CombatAreas.getAreaByID('combat', areaIdx)
local area = CombatAreas.getAreaByID('combat', areaIdx)
    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})
    result = result..'||'..Icons.Icon({area.name, type='combat', noicon=true})
result = result..'||'..Icons.Icon({area.name, type='combat', noicon=true})
    local diff1 = Constants.getDifficultyString(area.difficulty[1])
local diff1 = Constants.getDifficultyString(area.difficulty[1])
    local diff2 = Constants.getDifficultyString(area.difficulty[2])
local diff2 = Constants.getDifficultyString(area.difficulty[2])
    result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
    if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
    local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
    result = result..'||'..lowLvl..'||'..highLvl
result = result..'||'..lowLvl..'||'..highLvl
  end
end
result = result..'\r\n|}'


  result = result..'\r\n|}'
return result
 
  return result
end
end


function p.getSlayerAreaTable()
function p.getSlayerAreaTable()
  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"|Zone!!Difficulty!!Highest Monster Level!!Requirements!!Area Effect'
result = result..'\r\n!colspan="2"|Zone!!Difficulty!!Highest Monster Level!!Requirements!!Area Effect'


  for i, areaIdx in ipairs(AreaData.displayOrder.slayerAreas) do
for i, areaIdx in ipairs(AreaData.displayOrder.slayerAreas) do
  local area = CombatAreas.getAreaByID('slayer', areaIdx)
local area = CombatAreas.getAreaByID('slayer', areaIdx)
    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})
    result = result..'||'..Icons.Icon({area.name, type='slayer', noicon=true})
result = result..'||'..Icons.Icon({area.name, type='slayer', noicon=true})
    local diff1 = Constants.getDifficultyString(area.difficulty[1])
local diff1 = Constants.getDifficultyString(area.difficulty[1])
    local diff2 = Constants.getDifficultyString(area.difficulty[2])
local diff2 = Constants.getDifficultyString(area.difficulty[2])
    result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
result = result..'||data-sort-value="'..area.difficulty[1]..'"|'..diff1
    if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
if diff1 ~= diff2 and diff2 ~= nil then result = result..' - '..diff2 end
    local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
local lowLvl, highLvl = p.getLowHighLevels(area.monsters)
    result = result..'||'..highLvl
result = result..'||'..highLvl
result = result..'||'..CombatAreas._getAreaRequirements(area)
result = result..'|| '..CombatAreas._getAreaStat(area, 'areaEffectDesc')
end


    result = result..'||'..CombatAreas._getAreaRequirements(area)
result = result..'\r\n|}'
    result = result..'|| '..CombatAreas._getAreaStat(area, 'areaEffectDesc')
  end


  result = result..'\r\n|}'
return result
 
  return result
end
end


function p._getDungeonRewards(area, asList)
function p._getDungeonRewards(area, asList)
  if asList == nil then
if asList == nil then
    asList = true
asList = true
  elseif type(asList) == 'string' then
elseif type(asList) == 'string' then
    asList = asList.upper ~= 'FALSE'
asList = asList.upper ~= 'FALSE'
  end
end


  local bossMonster = Monsters.getMonsterByID(area.monsters[Shared.tableCount(area.monsters)])
local chr = asList and '* ' or ''
  local gpMin = bossMonster.dropCoins[1]
local rewardList = {}
  local gpMax = bossMonster.dropCoins[2] - 1
  local chestID, chestQty, theChest = nil, nil, nil
-- GP reward
  if bossMonster.lootTable ~= nil and Shared.tableCount(bossMonster.lootTable) > 0 then
if area.isEvent == nil or not area.isEvent then
  chestID = bossMonster.lootTable[1][1]
local bossMonster = Monsters.getMonsterByID(area.monsters[Shared.tableCount(area.monsters)])
  chestQty = bossMonster.lootTable[1][3]
local gpMin = bossMonster.dropCoins[1]
  theChest = Items.getItemByID(chestID)
local gpMax = bossMonster.dropCoins[2]
  end
if gpMin > 0 and gpMax > 0 then
  local chr = asList and '* ' or ''
if gpMin == gpMax then
  local rewardList = {}
table.insert(rewardList, chr .. Icons.GP(gpMin))
else
table.insert(rewardList, chr .. Icons.GP(gpMin, gpMax))
end
end
end
-- Item rewards
if type(area.rewards) == 'table' then
for i, rewardID in ipairs(area.rewards) do
local rewardItem = Items.getItemByID(rewardID)
if rewardItem == nil then
table.insert(rewardList, chr .. 'Unknown item (ID ' .. tostring(rewardID) .. ')[[Category:Pages with Script Errors]]')
else
table.insert(rewardList, chr .. Icons.Icon({rewardItem.name, type='item', qty=1}))
end
end
end
-- Event (Impending Darkness) rewards
if area.isEvent ~= nil and area.isEvent then
for i, rewardID in ipairs(AreaData.event.rewards) do
local rewardItem = Items.getItemByID(rewardID)
table.insert(rewardList, chr .. Icons.Icon({rewardItem.name, type='item', qty=1}))
end
end


  if gpMin > 0 and gpMax > 0 then
if asList then
    table.insert(rewardList, chr..Icons.GP(gpMin, gpMax))
return table.concat(rewardList, '\r\n')
  end
else
  if theChest ~= nil then
return table.concat(rewardList, '<br/>')
    table.insert(rewardList, chr..Icons.Icon({theChest.name, type='item', qty=chestQty}))
end
  end
  if area.isEvent ~= nil and area.isEvent then
  for i, rewardID in ipairs(AreaData.event.rewards) do
    local rewardItem = Items.getItemByID(rewardID)
    table.insert(rewardList, chr .. Icons.Icon({rewardItem.name, type='item', qty=1}))
  end
  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
end


function p.getDungeonRewards(frame)
function p.getDungeonRewards(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame
local areaName = frame.args ~= nil and frame.args[1] or frame
  local asList = frame.args ~= nil and frame.args[2] or true
local asList = frame.args ~= nil and frame.args[2] or true
  local area = CombatAreas.getArea(areaName)
local area = CombatAreas.getArea(areaName)
  if area == nil then
if area == nil then
    return "ERROR: Could not find an area named "..areaName..'[[Category:Pages with script errors]]'
return "ERROR: Could not find an area named "..areaName..'[[Category:Pages with script errors]]'
  end
end


  if area.type == 'dungeon' then
if area.type == 'dungeon' then
    return p._getDungeonRewards(area, asList)
return p._getDungeonRewards(area, asList)
  else
else
    return "ERROR: "..areaName.." is not a dungeon[[Category:Pages with script errors]]"
return "ERROR: "..areaName.." is not a dungeon[[Category:Pages with script errors]]"
  end
end
end
end


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, dungIdx in ipairs(AreaData.displayOrder.dungeons) do
for i, dungIdx in ipairs(AreaData.displayOrder.dungeons) do
  local dung = CombatAreas.getAreaByID('dungeon', dungIdx)
local dung = CombatAreas.getAreaByID('dungeon', dungIdx)
    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})
    result = result..'||'..Icons.Icon({dung.name, type='dungeon', noicon=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..'||data-sort-value="'..dung.difficulty[1]..'"|'..CombatAreas._getAreaStat(dung, 'difficulty')
    result = result..'||'..Shared.tableCount(dung.monsters)
result = result..'||'..Shared.tableCount(dung.monsters)
 
local boss = Monsters.getMonsterByID(dung.monsters[Shared.tableCount(dung.monsters)])
result = result..'||'..Shared.formatnum(Monsters._getMonsterCombatLevel(boss))


    local boss = Monsters.getMonsterByID(dung.monsters[Shared.tableCount(dung.monsters)])
result = result..'||'..p._getDungeonRewards(dung, false)
    result = result..'||'..Monsters._getMonsterCombatLevel(boss)
if dung.petID ~= nil then
   
local pet = Pets.getPetByID(dung.petID)
    result = result..'||'..p._getDungeonRewards(dung, false)
result = result..'||data-sort-value="'..pet.name..'"|'..Icons.Icon({pet.name, type='pet'})
    if dung.petID ~= nil then
else
      local pet = Pets.getPetByID(dung.petID)
result = result..'|| '
      result = result..'||data-sort-value="'..pet.name..'"|'..Icons.Icon({pet.name, type='pet'})
end
    else
end
      result = result..'|| '
    end
  end


  result = result..'\r\n|}'
result = result..'\r\n|}'
  return result
return result
end
end


function p._getDungeonDRTable(dung, mode, doStuns)
function p._getDungeonDRTable(dung, mode, doStuns)
  local AutoEatVals = {T1 = 0.2, T2 = 0.3, T3 = 0.4, T3W = 0.45}  
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
--NOTE: Due to Agility Obstacles, this value is a tad arbitrary
  local MaxViableHP = 1120
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
--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
local MaxViableDR = 81
  --This is the highest DR row shown. This should be higher than MaxViableDR
--This is the highest DR row shown. This should be higher than MaxViableDR
  local MaxVisibleDR = 85
local MaxVisibleDR = 85


  if doStuns == nil then
if doStuns == nil then
    doStuns = true
doStuns = true
  elseif type(doStuns) == 'string' then
elseif type(doStuns) == 'string' then
    doStuns = string.upper(doStuns) == 'TRUE'
doStuns = string.upper(doStuns) == 'TRUE'
  end
end


  --First, figure out what our max hit for each style is
--First, figure out what our max hit for each style is
  local MaxHits = { Melee = 0, Ranged = 0, Magic = 0 }
local MaxHits = { Melee = 0, Ranged = 0, Magic = 0 }
  for i, monsterID in Shared.skpairs(dung.monsters) do
for i, monsterID in Shared.skpairs(dung.monsters) do
    local monster = Monsters.getMonsterByID(monsterID)
local monster = Monsters.getMonsterByID(monsterID)
    local styleName = Constants.getCombatStyleName(monster.attackType)
local styleName = Constants.getCombatStyleName(monster.attackType)
    local maxHit = Monsters._getMonsterMaxHit(monster, doStuns)
local maxHit = Monsters._getMonsterMaxHit(monster, doStuns)
    if maxHit > MaxHits[styleName] then
if maxHit > MaxHits[styleName] then
      MaxHits[styleName] = maxHit
MaxHits[styleName] = maxHit
    end
end
  end
end


  --Then, figure out the DR row to start with
--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
--This is the DR that is one lower than the lowest possible DR for the best style
  local StyleArray = {"Melee", "Ranged", "Magic"}
local StyleArray = {"Melee", "Ranged", "Magic"}
  local EatThreshold = math.floor(MaxViableHP * AutoEatVals.T3W)
local EatThreshold = math.floor(MaxViableHP * AutoEatVals.T3W)
  local minDR = 100
local minDR = 100
  for i, playerStyle in Shared.skpairs(StyleArray) do
for i, playerStyle in Shared.skpairs(StyleArray) do
    local maxStyleDR = 0
local maxStyleDR = 0
    for enemyStyle, styleHit in Shared.skpairs(MaxHits) do
for enemyStyle, styleHit in Shared.skpairs(MaxHits) do
      if styleHit > 0 and styleHit > EatThreshold then
if styleHit > 0 and styleHit > EatThreshold then
        local styleDR = math.ceil((1 - (EatThreshold / styleHit)) * 100)
local styleDR = math.ceil((1 - (EatThreshold / styleHit)) * 100)
        styleDR = math.ceil(styleDR / Constants.getTriangleDRModifier(playerStyle, enemyStyle, mode))
styleDR = math.ceil(styleDR / Constants.getTriangleDRModifier(playerStyle, enemyStyle, mode))
        maxStyleDR = math.max(maxStyleDR, styleDR)
maxStyleDR = math.max(maxStyleDR, styleDR)
      end
end
    end
end
    minDR = math.min(minDR, maxStyleDR)
minDR = math.min(minDR, maxStyleDR)
  end
end


  minDR = minDR - 1
minDR = minDR - 1


  --Finally, build the table using those starting points
--Finally, build the table using those starting points
  local StyleHeader = "Melee!!Ranged!!Magic"
local StyleHeader = "Melee!!Ranged!!Magic"
  StyleHeader = StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader
StyleHeader = StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader


  local result = '{| class="wikitable stickyHeader"'
local result = '{| class="wikitable stickyHeader"'
  result = result..'\r\n|-class="headerRow-0"'
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!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|-class="headerRow-0"'
  result = result..'\r\n!DR %!!'..StyleHeader
result = result..'\r\n!DR %!!'..StyleHeader


  local getHpForStyle = function(playerStyle, autoEat, playerDR)  
local getHpForStyle = function(playerStyle, autoEat, playerDR)  
                         
return nil
                        end
end


  for dr = minDR, MaxVisibleDR, 1 do
for dr = minDR, MaxVisibleDR, 1 do
   
  end
end


  result = result..'\r\n|}'
result = result..'\r\n|}'


  return result
return result
end
end


function p.getDungeonDRTable(frame)
function p.getDungeonDRTable(frame)
  local dungName = frame.args ~= nil and frame.args[1] or frame[1]
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 mode = frame.args ~= nil and frame.args[2] or frame[2]
  local doStuns = frame.args ~= nil and frame.args[3] or frame[3]
local doStuns = frame.args ~= nil and frame.args[3] or frame[3]
  local dung = CombatAreas.getArea(dungName)
local dung = CombatAreas.getArea(dungName)


  if dung == nil then
if dung == nil then
    return 'ERROR: Invalid dungeon name'
return 'ERROR: Invalid dungeon name'
  end
end


  return p._getDungeonDRTable(dung, mode, doStuns)
return p._getDungeonDRTable(dung, mode, doStuns)
end
end


return p
return p

Revision as of 18:34, 8 January 2022

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, areaIdx in ipairs(AreaData.displayOrder.combatAreas) do
		local area = CombatAreas.getAreaByID('combat', areaIdx)
		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, areaIdx in ipairs(AreaData.displayOrder.slayerAreas) do
		local area = CombatAreas.getAreaByID('slayer', areaIdx)
		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..'|| '..CombatAreas._getAreaStat(area, 'areaEffectDesc')
	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 chr = asList and '* ' or ''
	local rewardList = {}
	
	-- GP reward
	if area.isEvent == nil or not area.isEvent then
		local bossMonster = Monsters.getMonsterByID(area.monsters[Shared.tableCount(area.monsters)])
		local gpMin = bossMonster.dropCoins[1]
		local gpMax = bossMonster.dropCoins[2]
		if gpMin > 0 and gpMax > 0 then
			if gpMin == gpMax then
				table.insert(rewardList, chr .. Icons.GP(gpMin))
			else
				table.insert(rewardList, chr .. Icons.GP(gpMin, gpMax))
			end
		end
	end
	
	-- Item rewards
	if type(area.rewards) == 'table' then
		for i, rewardID in ipairs(area.rewards) do
			local rewardItem = Items.getItemByID(rewardID)
			if rewardItem == nil then
				table.insert(rewardList, chr .. 'Unknown item (ID ' .. tostring(rewardID) .. ')[[Category:Pages with Script Errors]]')
			else
				table.insert(rewardList, chr .. Icons.Icon({rewardItem.name, type='item', qty=1}))
			end
		end
	end
	
	-- Event (Impending Darkness) rewards
	if area.isEvent ~= nil and area.isEvent then
		for i, rewardID in ipairs(AreaData.event.rewards) do
			local rewardItem = Items.getItemByID(rewardID)
			table.insert(rewardList, chr .. Icons.Icon({rewardItem.name, type='item', qty=1}))
		end
	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, dungIdx in ipairs(AreaData.displayOrder.dungeons) do
		local dung = CombatAreas.getAreaByID('dungeon', dungIdx)
		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..'||'..Shared.formatnum(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) 
		return nil
	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