Module:CombatAreas: Difference between revisions

From Melvor Idle
(Added new function for auto-building dungeon monster tables)
 
(Fixed an issue with getting difficulty not working when multiple difficulties were present)
(16 intermediate revisions by 3 users not shown)
Line 1: Line 1:
--NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters
local p = {}
local p = {}


local Constants = mw.loadData('Module:Constants/data')
local AreaData = mw.loadData('Module:CombatAreas/data')
local AreaData = mw.loadData('Module:CombatAreas/data')


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 Monsters = require('Module:Monsters')
local Items = require('Module:Items')
 
function processArea(area, index, type)
  local result = Shared.clone(area)
  result.id = index - 1
  if result.name == nil then
    result.name = result.areaName
  end
  result.type = type
  return result
end


function p.getArea(name)
function p.getArea(name)
Line 13: Line 24:
   for i, area in pairs(AreaData.combatAreas) do
   for i, area in pairs(AreaData.combatAreas) do
     if area.areaName == name then
     if area.areaName == name then
       result = Shared.clone(area)
       return processArea(area, i, 'combat')
      result.id = i - 1
      return result
     end
     end
   end
   end
Line 21: Line 30:
   for i, area in pairs(AreaData.slayerAreas) do
   for i, area in pairs(AreaData.slayerAreas) do
     if area.areaName == name then
     if area.areaName == name then
       result = Shared.clone(area)
       return processArea(area, i, 'slayer')
      result.id = i - 1
      return result
     end
     end
   end
   end
Line 29: Line 36:
   for i, area in pairs(AreaData.dungeons) do
   for i, area in pairs(AreaData.dungeons) do
     if area.name == name then
     if area.name == name then
       result = Shared.clone(area)
       return processArea(area, i, 'dungeon')
      result.type = 'dungeon'
      result.id = i - 1
      return result
     end
     end
   end
   end
Line 39: Line 43:
end
end


function p.getAreaMonsterTable(frame)
function p.getAreaByID(type, id)
   local areaName = frame.args ~= nil and frame.args[1] or frame
  if type == 'dungeon' then type = 'dungeons'
   local area = p.getArea(frame)
  elseif type == 'combat' then type = 'combatAreas'
  if area == nil then
  elseif type == 'slayer' then type = 'slayerAreas' end
     return "ERROR: Could not find an area named "..areaName
  return processArea(AreaData[type][id + 1], id + 1)
end
 
function p.getAreaFilterType(type, name)
   local areaName = nil
  if type == 'dungeon' then areas = AreaData.dungeons
  elseif type == 'combat' then areas = AreaData.combatAreas
   elseif type == 'slayer' then areas = AreaData.slayerAreas
  else return nil end
 
  for i, area in pairs(areas) do
    if type == 'dungeon' then areaName = area.name
     else areaName = area.areaName end
 
    if areaName == name then
      return processArea(area, i, type)
    end
   end
   end


   if area.type == 'dungeon' then
   return nil
     return p.getDungeonMonsterTable(frame)
end
 
function p._getAreaStat(area, statName)
  if statName == 'slayerLevel' then
    return Icons._SkillReq('Slayer', area.slayerLevel)
  elseif statName == 'slayerItem' then
    if area.slayerItem ~= nil and area.slayerItem > 0 then
      local slayItem = Items.getItemByID(area.slayerItem)
      return Icons.Icon({slayItem.name, type='item'})
    else
      return 'None'
    end
  elseif statName == 'dungeonReq' then
    if area.requiresCompletion ~= nil and area.requiresCompletion >= 0 then
      local dung = p.getAreaByID('dungeon', area.requiresCompletion)
      local compCount = area.requiresCompletionCount ~= nil and area.requiresCompletionCount or 1
      if compCount > 1 then
        return compCount..'x '..Icons.Icon({dung.name, type='dungeon'})..' Completions'
      else
        return Icons.Icon({dung.name, type='dungeon'})..' Completed'
      end
    else
      return ''
    end
  elseif statName == 'areaEffectDesc' then
    if area.areaEffect ~= nil and area.areaEffect then
      return area.areaEffectDescription
     else
      return 'None'
    end
  elseif statName == 'difficulty' then
    local result = Constants.getDifficultyString(area.difficulty[1])
    if area.difficulty[2] ~= nil then
      result = result..' - '..Constants.getDifficultyString(area.difficulty[2])
    end
    return result
   end
   end


   local tableTxt = '{| class="wikitable sortable"'
   return area[statName]
  tableTxt = tableTxt..'\r\n! Name !! Combat Level !! Hitpoints !! Max Hit !! [[Combat Triangle|Combat Style]]'
  for i, monsterID in pairs(area.monsters) do
    local monster = Monsters.getMonsterByID(monsterID)
    tableTxt = tableTxt..'\r\n|-\r\n|'..Icons.Icon({monster.name, type='monster'})
    tableTxt = tableTxt..'||'..Monsters.getMonsterCombatLevel(monster.name)
    tableTxt = tableTxt..'||'..Shared.formatnum(Monsters.getMonsterHP(monster.name))
    tableTxt = tableTxt..'||'..Shared.formatnum(Monsters.getMonsterMaxHit(monster.name))
    tableTxt = tableTxt..'||'..Monsters.getMonsterStyleIcon({monster.name, nolink='true'})
  end
  tableTxt = tableTxt..'\r\n|}'
  return tableTxt
end
end


function p.getDungeonMonsterTable(frame)
function p.getAreaStat(frame)
   local areaName = frame.args ~= nil and frame.args[1] or frame
   local areaName = frame.args ~= nil and frame.args[1] or frame[1]
   local area = p.getArea(frame)
  local statName = frame.args ~= nil and frame.args[2] or frame[2]
   local area = p.getArea(areaName)
   if area == nil then
   if area == nil then
     return "ERROR: Could not find an area named "..areaName
     return "ERROR: Could not find an area named "..areaName
   end
   end


   --For Dungeons, go through and count how many of each monster are in the dungeon first
   return p._getAreaStat(area, statName)
   local monsterCounts = {}
end
   for i, monsterID in pairs(area.monsters) do
 
     if monsterCounts[monsterID] == nil then  
function p.getMonsterAreas(monsterID)
       monsterCounts[monsterID] = 1
   local areaArray = {}
    else
  --There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
      monsterCounts[monsterID] = monsterCounts[monsterID] + 1
   for i, area in pairs(AreaData.combatAreas) do
     if Shared.contains(area.monsters, monsterID) then
       table.insert(areaArray, processArea(area, i, 'combat'))
     end
     end
   end
   end


   local usedMonsters = {}
   for i, area in pairs(AreaData.slayerAreas) do
    if Shared.contains(area.monsters, monsterID) then
      table.insert(areaArray, processArea(area, i, 'slayer'))
    end
  end


   local tableTxt = '{| class="wikitable sortable"'
   --Hill Giants specifically ignore dungeons to prevent the issue with Into the Mist incorrectly being listed.
   tableTxt = tableTxt..'\r\n! Name !! Combat Level !! Hitpoints !! Max Hit !! [[Combat Triangle|Combat Style]] !! Count'
   if monsterID ~= 1 then
  for i, monsterID in pairs(area.monsters) do
    for i, area in pairs(AreaData.dungeons) do
    if not Shared.contains(usedMonsters, monsterID) then
      if Shared.contains(area.monsters, monsterID) then
      local monster = Monsters.getMonsterByID(monsterID)
        table.insert(areaArray, processArea(area, i, 'dungeon'))
      local name = monster.name
       end
      if monsterID == 51 then name = 'Spider2' end
      tableTxt = tableTxt..'\r\n|-\r\n|'..Icons.Icon({name, type='monster'})
      tableTxt = tableTxt..'||'..Monsters.getMonsterCombatLevel(name)
       tableTxt = tableTxt..'||'..Shared.formatnum(Monsters.getMonsterHP(name))
      tableTxt = tableTxt..'||'..Shared.formatnum(Monsters.getMonsterMaxHit(name))
      tableTxt = tableTxt..'||'..Monsters.getMonsterStyleIcon({name, nolink='true'})
      tableTxt = tableTxt..'||'..monsterCounts[monsterID]
      table.insert(usedMonsters, monsterID)
     end
     end
   end
   end
   tableTxt = tableTxt..'\r\n|}'
   return areaArray
   return tableTxt
end
 
function p.getDungeonRequirements(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame
  local area = p.getArea(areaName)
  if area == nil then
    return "ERROR: Could not find an area named "..areaName
  end
 
  local result = p._getAreaStat(area, 'dungeonReq')
  if result ~= '' then
    result = "\r\n|-\r\n|'''Requirements:'''<br/>"..result
  end
   return result
end
end


return p
return p

Revision as of 20:36, 12 April 2021

Data is pulled from Module:GameData/data


--NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters
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')

function processArea(area, index, type)
  local result = Shared.clone(area)
  result.id = index - 1
  if result.name == nil then
    result.name = result.areaName
  end
  result.type = type
  return result
end

function p.getArea(name)
  local result = nil
  --There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
  for i, area in pairs(AreaData.combatAreas) do
    if area.areaName == name then
      return processArea(area, i, 'combat')
    end
  end

  for i, area in pairs(AreaData.slayerAreas) do
    if area.areaName == name then
      return processArea(area, i, 'slayer')
    end
  end

  for i, area in pairs(AreaData.dungeons) do
    if area.name == name then
      return processArea(area, i, 'dungeon')
    end
  end

  return nil
end

function p.getAreaByID(type, id)
  if type == 'dungeon' then type = 'dungeons'
  elseif type == 'combat' then type = 'combatAreas'
  elseif type == 'slayer' then type = 'slayerAreas' end
  return processArea(AreaData[type][id + 1], id + 1)
end

function p.getAreaFilterType(type, name)
  local areaName = nil
  if type == 'dungeon' then areas = AreaData.dungeons
  elseif type == 'combat' then areas = AreaData.combatAreas
  elseif type == 'slayer' then areas = AreaData.slayerAreas 
  else return nil end

  for i, area in pairs(areas) do
    if type == 'dungeon' then areaName = area.name
    else areaName = area.areaName end

    if areaName == name then
      return processArea(area, i, type)
    end
  end

  return nil
end

function p._getAreaStat(area, statName)
  if statName == 'slayerLevel' then
    return Icons._SkillReq('Slayer', area.slayerLevel)
  elseif statName == 'slayerItem' then
    if area.slayerItem ~= nil and area.slayerItem > 0 then
      local slayItem = Items.getItemByID(area.slayerItem)
      return Icons.Icon({slayItem.name, type='item'})
    else
      return 'None'
    end
  elseif statName == 'dungeonReq' then
    if area.requiresCompletion ~= nil and area.requiresCompletion >= 0 then
      local dung = p.getAreaByID('dungeon', area.requiresCompletion)
      local compCount = area.requiresCompletionCount ~= nil and area.requiresCompletionCount or 1
      if compCount > 1 then
        return compCount..'x '..Icons.Icon({dung.name, type='dungeon'})..' Completions'
      else
        return Icons.Icon({dung.name, type='dungeon'})..' Completed'
      end
    else
      return ''
    end
  elseif statName == 'areaEffectDesc' then
    if area.areaEffect ~= nil and area.areaEffect then
      return area.areaEffectDescription
    else
      return 'None'
    end
  elseif statName == 'difficulty' then
    local result = Constants.getDifficultyString(area.difficulty[1])
    if area.difficulty[2] ~= nil then
      result = result..' - '..Constants.getDifficultyString(area.difficulty[2])
    end
    return result
  end

  return area[statName]
end

function p.getAreaStat(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame[1]
  local statName = frame.args ~= nil and frame.args[2] or frame[2]
  local area = p.getArea(areaName)
  if area == nil then
    return "ERROR: Could not find an area named "..areaName
  end

  return p._getAreaStat(area, statName)
end

function p.getMonsterAreas(monsterID)
  local areaArray = {}
  --There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
  for i, area in pairs(AreaData.combatAreas) do
    if Shared.contains(area.monsters, monsterID) then
      table.insert(areaArray, processArea(area, i, 'combat'))
    end
  end

  for i, area in pairs(AreaData.slayerAreas) do
    if Shared.contains(area.monsters, monsterID) then
      table.insert(areaArray, processArea(area, i, 'slayer'))
    end
  end

  --Hill Giants specifically ignore dungeons to prevent the issue with Into the Mist incorrectly being listed.
  if monsterID ~= 1 then
    for i, area in pairs(AreaData.dungeons) do
      if Shared.contains(area.monsters, monsterID) then
        table.insert(areaArray, processArea(area, i, 'dungeon'))
      end
    end
  end
  return areaArray
end

function p.getDungeonRequirements(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame
  local area = p.getArea(areaName)
  if area == nil then
    return "ERROR: Could not find an area named "..areaName
  end

  local result = p._getAreaStat(area, 'dungeonReq')
  if result ~= '' then
    result = "\r\n|-\r\n|'''Requirements:'''<br/>"..result
  end
  return result
end

return p