Module:CombatAreas: Difference between revisions

From Melvor Idle
(_getAreaRequirements: Support ShopPurchase type (again))
(getAreaPassives now works for dungeons and strongholds)
 
(15 intermediate revisions by 4 users not shown)
Line 1: Line 1:
--NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters
--NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters
local p = {}
local p = {}
local AreaData = mw.loadData('Module:CombatAreas/data')


local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')
local Common = require('Module:Common')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Shop = require('Module:Shop')


function processArea(area, index, type)
local areaMap = {
  local result = Shared.clone(area)
["combat"] = 'combatAreas',
  result.id = index - 1
["dungeon"] = 'dungeons',
  if result.name == nil then
["slayer"] = 'slayerAreas',
    result.name = result.areaName
["depth"] = 'abyssDepths',
  end
["stronghold"] = 'strongholds'
  result.type = type
}
  return result
end


function p.getArea(name)
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
  --There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
for k, areaType in pairs(areaMap) do
  for i, area in pairs(AreaData.combatAreas) do
local area = GameData.getEntityByName(areaType, name)
    if area.name == name then
if area ~= nil then
      return processArea(area, i, 'combat')
return area
    end
end
  end
end
end


  for i, area in pairs(AreaData.slayerAreas) do
function p.getAreaByID(id, areaType)
    if area.name == name then
for aType, areaKey in pairs(areaMap) do
      return processArea(area, i, 'slayer')
if areaType == nil or areaType == aType then
    end
local area = GameData.getEntityByID(areaKey, id)
  end
if area ~= nil then
 
return area
  for i, area in pairs(AreaData.dungeons) do
end
    if area.name == name then
end
      return processArea(area, i, 'dungeon')
end
    end
  end
 
  return nil
end
end


function p.getAreaByID(type, id)
function p.getAreaFilterType(name, type)
  if type == 'dungeon' then type = 'dungeons'
local areaType = areaMap[type]
  elseif type == 'combat' then type = 'combatAreas'
if areaType ~= nil then
  elseif type == 'slayer' then type = 'slayerAreas' end
return GameData.getEntityByName(areaType, name)
  return processArea(AreaData[type][id + 1], id + 1)
end
end
end


function p.getAreaFilterType(type, name)
function p.getAreas(checkFunc)
  local areaName = nil
local resultArray = 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
for i, areaType in pairs(areaMap) do
    if type == 'dungeon' then areaName = area.name
local areas = GameData.getEntities(areaType, checkFunc)
    else areaName = area.areaName end
if resultArray == nil then
resultArray = areas
else
for k, area in ipairs(areas) do
table.insert(resultArray, area)
end
end
end
if resultArray == nil then
resultArray = {}
end


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


  return nil
--Returns the expansion icon for the area if it has one
function p.getExpansionIcon(frame)
local areaName = frame.args ~= nil and frame.args[1] or frame
local area = p.getArea(areaName)
if area == nil then
return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
end
return Icons.getExpansionIcon(area.id)
end
end


function p.getAreas(checkFunc)
function p._getAreaRequirements(area)
  local resultArray = {}
local resultArray = {}
if area.entryRequirements ~= nil then
local reqText = Common.getRequirementString(area.entryRequirements)
if reqText ~= nil then
table.insert(resultArray, reqText)
end
end


  for i, area in Shared.skpairs(AreaData.combatAreas) do
if area.unlockRequirement ~= nil then
    local temp = processArea(area, i, 'combat')
-- Avoid repeating the same requirements twice, can happen for some dungeons e.g. Impending Darkness
    if checkFunc(temp) then
if area.entryRequirements == nil or mw.dumpObject(area.unlockRequirement) ~= mw.dumpObject(area.entryRequirements) then
      table.insert(resultArray, temp)
local reqText = Common.getRequirementString(area.unlockRequirement)
    end
if reqText ~= nil then
  end
table.insert(resultArray, reqText)
  for i, area in Shared.skpairs(AreaData.slayerAreas) do
end
    local temp = processArea(area, i, 'slayer')
end
    if checkFunc(temp) then
end
      table.insert(resultArray, temp)
    end
  end
  for i, area in Shared.skpairs(AreaData.dungeons) do
    local temp = processArea(area, i, 'dungeon')
    if checkFunc(temp) then
      table.insert(resultArray, temp)
    end
  end


  return resultArray
return table.concat(resultArray, '<br/>')
end
end


function p._getAreaRequirements(area)
function p.getAreaRequirementsForBox(frame)
  local result = ''
--Returns infobox formatting for requirements, or returns nothing if there are none.
  local resultArray = {}
local areaName = frame.args ~= nil and frame.args[1] or frame
  local addReqsToArray = function(reqArray, requirements)
local area = p.getArea(areaName)
      for i, reqDetails in Shared.skpairs(requirements) do
if area == nil then
        if reqDetails.type == 'Level' then
return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
          for j, lvlDetails in Shared.skpairs(reqDetails.levels) do
end
            local skill = Constants.getSkillName(lvlDetails.skill)
            table.insert(reqArray, Icons._SkillReq(skill, lvlDetails.level))
          end
        elseif reqDetails.type == 'SlayerItem' then
          local item = Items.getItemByID(reqDetails.itemID)
          table.insert(reqArray, Icons.Icon({item.name, type='item'})..' Equipped')
        elseif reqDetails.type == 'Dungeon' then
          for j, dungDetails in Shared.skpairs(reqDetails.dungeons) do
            local dung = p.getAreaByID('dungeon', dungDetails.dungeonID)
            if dungDetails.count > 1 then
              table.insert(reqArray, dungDetails.count..'x '..Icons.Icon({dung.name, type='dungeon'})..' Completions')
            else
              table.insert(reqArray, Icons.Icon({dung.name, type='dungeon'})..' Completed')
            end
          end
        elseif reqDetails.type == 'ShopPurchase' then
          local shopPurchase = Shop.processPurchase(reqDetails.category, reqDetails.id)
          if shopPurchase ~= nil then
          table.insert(reqArray, Shop._getPurchaseIcon({ shopPurchase }) .. ' Purchased')
          end
        else
          table.insert(reqArray, 'ERROR: Unknown requirement type ' .. (reqDetails.type or 'nil') .. '[[Category:Pages with script errors]]')
        end
      end
    end
 
  if area.entryRequirements ~= nil then
    addReqsToArray(resultArray, area.entryRequirements)
  end
 
  if area.unlockRequirement ~= nil then
    addReqsToArray(resultArray, { area.unlockRequirement })
  end


  result = table.concat(resultArray, '<br/>')
local reqs = p._getAreaRequirements(area)
  return result
if reqs ~= '' then
reqs = "|-\r\n|'''Requirements:'''\r\n"..reqs
end
return reqs
end
end


function p._getAreaStat(area, statName)
function p._getAreaStat(area, statName)
  if statName == 'requirements' then
if statName == 'requirements' then
    return p._getAreaRequirements(area)
return p._getAreaRequirements(area)
  elseif statName == 'areaEffectDesc' then
elseif statName == 'areaEffectDesc' then
    if area.areaEffect ~= nil and area.areaEffect then
if area.areaEffect ~= nil then
      local descText, subIdx = string.gsub(area.areaEffectDescription, '${effectValue}', area.areaEffectValue or 0)
local descText, subIdx = string.gsub(area.areaEffectDescription, '${effectValue}', area.areaEffect.magnitude or 0)
      return descText
return descText
    else
else
      return 'None'
return 'None'
    end
end
  elseif statName == 'difficulty' then
elseif statName == 'difficulty' then
    local result = Constants.getDifficultyString(area.difficulty[1])
local result = Constants.getDifficultyString(area.difficulty[1])
    if area.difficulty[2] ~= nil then
if area.difficulty[2] ~= nil then
      result = result..' - '..Constants.getDifficultyString(area.difficulty[2])
result = result..' - '..Constants.getDifficultyString(area.difficulty[2])
    end
end
    return result
return result
  end
end


  return area[statName]
return area[statName]
end
end


function p.getAreaStat(frame)
function p.getAreaStat(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame[1]
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 statName = frame.args ~= nil and frame.args[2] or frame[2]
  local area = p.getArea(areaName)
local area = p.getArea(areaName)
  if area == nil then
if area == nil then
    return "ERROR: Could not find an area named "..areaName
return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
  end
end
 
return p._getAreaStat(area, statName)
end
 
function p._isMonsterInArea(monster, area)
return (
Shared.contains(area.monsterIDs, monster.id)
-- Check for Lair of the Spider Queen random spiders
or (
Shared.contains(area.monsterIDs, 'melvorTotH:RandomSpiderLair')
and Shared.contains(GameData.rawData.spiderLairMonsters, monster.id)
)
)
end
 
function p._getMonsterAreas(monster)
-- Special handling for Lair of the Spider Queen, which has a random list of enemies
local randomSpiderCheck = Shared.contains(GameData.rawData.spiderLairMonsters, monster.id)
return p.getAreas(
function(area)
return p._isMonsterInArea(monster, area)
end)
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 Shared.printError('No area named "' .. areaName .. '" exists in the data module')
end


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


function p.getMonsterAreas(monsterID)
function p.getAreaPassives(frame)
  local areaArray = {}
local areaName = frame.args ~= nil and frame.args[1] or frame
  --There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
local area = p.getArea(areaName)
  for i, area in pairs(AreaData.combatAreas) do
if area == nil then
     if Shared.contains(area.monsters, monsterID) then
return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
      table.insert(areaArray, processArea(area, i, 'combat'))
end
 
local bossPassives = nil
local nonBossPassives = nil
if area.eventID ~= nil and area.eventID ~= '' then -- currently just Impending Darkness Event
local event = GameData.getEntityByID('combatEvents', area.eventID)
bossPassives = event.bossPassives
-- nonBossPassives = event.enemyPassives -- melvorF:ControlledAffliction is missing from GameData
else
bossPassives = area.bossOnlyPassives -- Strongholds only
nonBossPassives = area.nonBossPassives -- Dungeons only
end
 
local result = ''
 
     if type(nonBossPassives) == 'table' and not Shared.tableIsEmpty(nonBossPassives) then
    result = result .. '\r\n===Non-Boss Monster Passives==='
for i, passiveID in ipairs(nonBossPassives) do
local passive = p.getPassiveByID(passiveID)
result = result .. '\r\n* ' .. passive.name .. '\r\n** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
end
     end
     end
  end


  for i, area in pairs(AreaData.slayerAreas) do
    if type(bossPassives) == 'table' and not Shared.tableIsEmpty(bossPassives) then
    if Shared.contains(area.monsters, monsterID) then
    result = result .. '\r\n===Boss Monster Passives==='
      table.insert(areaArray, processArea(area, i, 'slayer'))
for i, passiveID in ipairs(bossPassives) do
local passive = p.getPassiveByID(passiveID)
result = result .. '\r\n* ' .. passive.name .. '\r\n** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
end
     end
     end
  end


  --Hill Giants specifically ignore dungeons to prevent the issue with Into the Mist incorrectly being listed.
if type(area.tiers) == 'table' and not Shared.tableIsEmpty(area.tiers) then
  if monsterID ~= 1 then
result = result .. '\r\n===Stronghold Tier Passives==='
    for i, area in pairs(AreaData.dungeons) do
for tierName, tierData in pairs(area.tiers) do
      if Shared.contains(area.monsters, monsterID) then
result = result .. '\r\n* ' .. tierName .. ' Tier'
        table.insert(areaArray, processArea(area, i, 'dungeon'))
for i, passiveID in ipairs(tierData.passives) do
      end
local passive = p.getPassiveByID(passiveID)
    end
result = result .. '\r\n** ' .. passive.name .. '\r\n*** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
  end
end
  return areaArray
end
end
 
return result
end
end


function p.getDungeonRequirements(frame)
function p.getPassiveByID(ID)
  local areaName = frame.args ~= nil and frame.args[1] or frame
     return GameData.getEntityByID('combatPassives', ID)
  local area = p.getArea(areaName)
  if area == nil then
     return "ERROR: Could not find an area named "..areaName
  end
 
  local result = p._getAreaStat(area, 'requirements')
  if result ~= '' then
    result = "\r\n|-\r\n|'''Requirements:'''<br/>"..result
  end
  return result
end
end


return p
return p

Latest revision as of 00:35, 2 November 2024

Data is pulled from Module:GameData/data

NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters


--NOTE: Some tables are in Module:CombatAreas/AreaTables to prevent loop from referencing Monsters
local p = {}

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')
local Common = require('Module:Common')
local Icons = require('Module:Icons')

local areaMap = {
	["combat"] = 'combatAreas',
	["dungeon"] = 'dungeons',
	["slayer"] = 'slayerAreas',
	["depth"] = 'abyssDepths',
	["stronghold"] = 'strongholds'
}

function p.getArea(name)
	--There are three types of areas but the lists are pretty short so looping all of them isn't a real issue
	for k, areaType in pairs(areaMap) do
		local area = GameData.getEntityByName(areaType, name)
		if area ~= nil then
			return area
		end
	end
end

function p.getAreaByID(id, areaType)
	for aType, areaKey in pairs(areaMap) do
		if areaType == nil or areaType == aType then
			local area = GameData.getEntityByID(areaKey, id)
			if area ~= nil then
				return area
			end
		end
	end
end

function p.getAreaFilterType(name, type)
	local areaType = areaMap[type]
	if areaType ~= nil then
		return GameData.getEntityByName(areaType, name)
	end
end

function p.getAreas(checkFunc)
	local resultArray = nil

	for i, areaType in pairs(areaMap) do
		local areas = GameData.getEntities(areaType, checkFunc)
		if resultArray == nil then
			resultArray = areas
		else
			for k, area in ipairs(areas) do
				table.insert(resultArray, area)
			end
		end
	end
	if resultArray == nil then
		resultArray = {}
	end

	return resultArray
end

--Returns the expansion icon for the area if it has one
function p.getExpansionIcon(frame)
	local areaName = frame.args ~= nil and frame.args[1] or frame
	local area = p.getArea(areaName)
	if area == nil then
		return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
	end
	
	return Icons.getExpansionIcon(area.id)
end

function p._getAreaRequirements(area)
	local resultArray = {}
	if area.entryRequirements ~= nil then
		local reqText = Common.getRequirementString(area.entryRequirements)
		if reqText ~= nil then
			table.insert(resultArray, reqText)
		end
	end

	if area.unlockRequirement ~= nil then
		-- Avoid repeating the same requirements twice, can happen for some dungeons e.g. Impending Darkness
		if area.entryRequirements == nil or mw.dumpObject(area.unlockRequirement) ~= mw.dumpObject(area.entryRequirements) then
			local reqText = Common.getRequirementString(area.unlockRequirement)
			if reqText ~= nil then
				table.insert(resultArray, reqText)
			end
		end
	end

	return table.concat(resultArray, '<br/>')
end

function p.getAreaRequirementsForBox(frame)
	--Returns infobox formatting for requirements, or returns nothing if there are none.
	local areaName = frame.args ~= nil and frame.args[1] or frame
	local area = p.getArea(areaName)
	if area == nil then
		return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
	end

	local reqs = p._getAreaRequirements(area)
	if reqs ~= '' then
		reqs = "|-\r\n|'''Requirements:'''\r\n"..reqs
	end
	return reqs
end

function p._getAreaStat(area, statName)
	if statName == 'requirements' then
		return p._getAreaRequirements(area)
	elseif statName == 'areaEffectDesc' then
		if area.areaEffect ~= nil then
			local descText, subIdx = string.gsub(area.areaEffectDescription, '${effectValue}', area.areaEffect.magnitude or 0)
			return descText
		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 Shared.printError('No area named "' .. areaName .. '" exists in the data module')
	end

	return p._getAreaStat(area, statName)
end

function p._isMonsterInArea(monster, area)
	return (
		Shared.contains(area.monsterIDs, monster.id)
		-- Check for Lair of the Spider Queen random spiders
		or (
			Shared.contains(area.monsterIDs, 'melvorTotH:RandomSpiderLair')
			and Shared.contains(GameData.rawData.spiderLairMonsters, monster.id)
		)
	)
end

function p._getMonsterAreas(monster)
	-- Special handling for Lair of the Spider Queen, which has a random list of enemies
	local randomSpiderCheck = Shared.contains(GameData.rawData.spiderLairMonsters, monster.id)
	return p.getAreas(
		function(area)
			return p._isMonsterInArea(monster, area)
		end)
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 Shared.printError('No area named "' .. areaName .. '" exists in the data module')
	end

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

function p.getAreaPassives(frame)
	local areaName = frame.args ~= nil and frame.args[1] or frame
	local area = p.getArea(areaName)
	if area == nil then
		return Shared.printError('No area named "' .. areaName .. '" exists in the data module')
	end

	local bossPassives = nil
	local nonBossPassives = nil
	if area.eventID ~= nil and area.eventID ~= '' then -- currently just Impending Darkness Event
		local event = GameData.getEntityByID('combatEvents', area.eventID)
		bossPassives = event.bossPassives
		-- nonBossPassives = event.enemyPassives -- melvorF:ControlledAffliction is missing from GameData
	else
		bossPassives = area.bossOnlyPassives -- Strongholds only
		nonBossPassives = area.nonBossPassives -- Dungeons only
	end

	local result = ''

    if type(nonBossPassives) == 'table' and not Shared.tableIsEmpty(nonBossPassives) then
    	result = result .. '\r\n===Non-Boss Monster Passives==='
		for i, passiveID in ipairs(nonBossPassives) do
			local passive = p.getPassiveByID(passiveID)
			result = result .. '\r\n* ' .. passive.name .. '\r\n** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
		end
    end

    if type(bossPassives) == 'table' and not Shared.tableIsEmpty(bossPassives) then
    	result = result .. '\r\n===Boss Monster Passives==='
		for i, passiveID in ipairs(bossPassives) do
			local passive = p.getPassiveByID(passiveID)
			result = result .. '\r\n* ' .. passive.name .. '\r\n** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
		end
    end

	if type(area.tiers) == 'table' and not Shared.tableIsEmpty(area.tiers) then
		result = result .. '\r\n===Stronghold Tier Passives==='
		for tierName, tierData in pairs(area.tiers) do
			result = result .. '\r\n* ' .. tierName .. ' Tier'
			for i, passiveID in ipairs(tierData.passives) do
				local passive = p.getPassiveByID(passiveID)
				result = result .. '\r\n** ' .. passive.name .. '\r\n*** ' .. Constants.getDescription(passive.customDescription, passive.modifiers)
			end
		end
	end

	return result
end

function p.getPassiveByID(ID)
    return GameData.getEntityByID('combatPassives', ID)
end

return p