Module:Skills/Cartography: Difference between revisions

From Melvor Idle
(Reference the Melvor world map by ID rather than by a numerical index - the order of maps within SkillData.Cartography.worldMaps cannot be guaranteed)
(getMasteryBonuses: Initial implementation)
(One intermediate revision by the same user not shown)
Line 9: Line 9:
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')


local MelvorMap = GameData.getEntityByID(SkillData.Cartography.worldMaps, 'melvorAoD:Melvor')
p.MelvorMap = GameData.getEntityByID(SkillData.Cartography.worldMaps, 'melvorAoD:Melvor')


function p.getPointOfInterestByID(id)
function p.getPointOfInterestByID(id)
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if POI.id == id then
if POI.id == id then
return POI
return POI
Line 26: Line 26:
return nil
return nil
end
end
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if (POI.coords.q == hex.coordinates.q and
if (POI.coords.q == hex.coordinates.q and
    POI.coords.r == hex.coordinates.r) then
    POI.coords.r == hex.coordinates.r) then
Line 36: Line 36:


function p.getPointOfInterestForDigSite(digSiteID)
function p.getPointOfInterestForDigSite(digSiteID)
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if POI.digSiteID ~= nil and POI.digSiteID == digSiteID then
if POI.digSiteID ~= nil and POI.digSiteID == digSiteID then
return POI
return POI
Line 47: Line 47:
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
name = string.gsub(name, "'", "'")
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if POI.name == name then
if POI.name == name then
return POI
return POI
Line 57: Line 57:
function p.getPointsOfInterest(checkFunc)
function p.getPointsOfInterest(checkFunc)
local result = {}
local result = {}
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if checkFunc(POI) then
if checkFunc(POI) then
table.insert(result, POI)
table.insert(result, POI)
end
end
return result
end
function p.getMasteryBonuses(checkFunc)
local result = {}
for i, bonus in pairs(p.MelvorMap.masteryBonuses) do
if checkFunc(bonus) then
table.insert(result, bonus)
end
end
end
end
Line 72: Line 82:
end
end
for i, hex in pairs(MelvorMap.hexes) do
for i, hex in pairs(p.MelvorMap.hexes) do
local coords = hex.coordinates
local coords = hex.coordinates
if coords.q == Q and coords.r == R then
if coords.q == Q and coords.r == R then
Line 165: Line 175:
:tag('th'):wikitext('Rewards')
:tag('th'):wikitext('Rewards')
local masteryBonuses = Shared.shallowClone(MelvorMap.masteryBonuses)
local masteryBonuses = Shared.shallowClone(p.MelvorMap.masteryBonuses)
table.sort(masteryBonuses, function(a, b) return a.masteredHexes < b.masteredHexes end)
table.sort(masteryBonuses, function(a, b) return a.masteredHexes < b.masteredHexes end)
for i, bonus in ipairs(masteryBonuses) do
for i, bonus in ipairs(masteryBonuses) do
Line 220: Line 230:
table.insert(tableStr, '\r\n|-\r\n!colspan="2"|Name!!Type!!X!!Y!!Requirements!!Discovery Rewards!!Discovery Modifiers!!Active Effect')
table.insert(tableStr, '\r\n|-\r\n!colspan="2"|Name!!Type!!X!!Y!!Requirements!!Discovery Rewards!!Discovery Modifiers!!Active Effect')
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
table.insert(POIs, POI)
table.insert(POIs, POI)
end
end
Line 282: Line 292:
function p._getDiscoveryRewardsTable(items)
function p._getDiscoveryRewardsTable(items)
local POIs = {}
local POIs = {}
for i, POI in ipairs(MelvorMap.pointsOfInterest) do
for i, POI in ipairs(p.MelvorMap.pointsOfInterest) do
if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
for i, reward in ipairs(POI.discoveryRewards.items) do
for i, reward in ipairs(POI.discoveryRewards.items) do
Line 372: Line 382:
function p.testDiscoveryRewards()
function p.testDiscoveryRewards()
local testTable = {}
local testTable = {}
for i, POI in pairs(MelvorMap.pointsOfInterest) do
for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
local item = Items.getItemByID(POI.discoveryRewards.items[1].id)
local item = Items.getItemByID(POI.discoveryRewards.items[1].id)

Revision as of 12:58, 2 May 2024

Documentation for this module may be created at Module:Skills/Cartography/doc

local p = {}

local Shared = require('Module:Shared')
local Constants = require('Module:Constants')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Items = require('Module:Items')
local Common = require('Module:Common')
local Icons = require('Module:Icons')

p.MelvorMap = GameData.getEntityByID(SkillData.Cartography.worldMaps, 'melvorAoD:Melvor')

function p.getPointOfInterestByID(id)
	
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if POI.id == id then
			return POI
		end
	end
	return nil
end

function p.getPointOfInterestByXY(X, Y)
	local hex = p.getHexByXY(X, Y)
	if hex == nil then
		return nil
	end
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if (POI.coords.q == hex.coordinates.q and
		    POI.coords.r == hex.coordinates.r) then
			return POI
		end
	end
	return nil
end

function p.getPointOfInterestForDigSite(digSiteID)
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if POI.digSiteID ~= nil and POI.digSiteID == digSiteID then
			return POI
		end
	end
	return nil
end

function p.getPointOfInterest(name)
	name = string.gsub(name, "%%27", "'")
	name = string.gsub(name, "&#39;", "'")
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if POI.name == name then
			return POI
		end
	end
	return nil
end

function p.getPointsOfInterest(checkFunc)
	local result = {}
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if checkFunc(POI) then
			table.insert(result, POI)
		end
	end
	return result
end

function p.getMasteryBonuses(checkFunc)
	local result = {}
	for i, bonus in pairs(p.MelvorMap.masteryBonuses) do
		if checkFunc(bonus) then
			table.insert(result, bonus)
		end
	end
	return result
end

function p.getHexByAxial(Q, R)
	--Assume if R is nil that a pair was sent in
	if R == nil then
		R = Q.r
		Q = Q.q
	end
	
	for i, hex in pairs(p.MelvorMap.hexes) do
		local coords = hex.coordinates
		if coords.q == Q and coords.r == R then
			return hex
		end
	end
	return nil
end

function p.getHexByXY(X, Y)
	local Q, R = p.convertXYToAxial(X, Y)
	return p.getHexByAxial(Q, R)
end

function p.convertXYToAxial(X, Y)
	--Assume that if Y is nil that a pair was sent in
	if Y == nil then
		Y = X.y
		X = X.x
	end
	local Q = X
	local R = Y - (X - (X % 2)) / 2
	return Q, R
end

function p.convertAxialToXY(Q, R)
	--Assume if r is nil that a pair was sent in
	if R == nil then
		R = Q.r
		Q = Q.q
	end
	local Y = R + (Q - (Q % 2)) / 2
	local X = Q
	return X, Y
end

function p._getPOIRequirements(POI)
	local Hex = p.getHexByAxial(POI.coords)
	local reqTable = {}
	local HexReqs = Common.getRequirementString(Hex.requirements, '')
	if HexReqs ~= '' then
		table.insert(reqTable, HexReqs)
	end
	if POI.hidden ~= nil then
		local POIReqs = Common.getRequirementString(POI.hidden.requirements, '')
		if POIReqs ~= '' then
			table.insert(reqTable, POIReqs)
		end
	end
	return reqTable
end

function p._getDiscoveryRewards(POI)
	local rewardTable = {}
	if POI.discoveryRewards ~= nil then
		if POI.discoveryRewards.gp ~= nil then
			table.insert(rewardTable, Icons.GP(POI.discoveryRewards.gp))
		end
		if POI.discoveryRewards.sc ~= nil then
			table.insert(rewardTable, Icons.SC(POI.discoveryRewards.sc))
		end
		if POI.discoveryRewards.items ~= nil then
			for j, reward in pairs(POI.discoveryRewards.items) do
				local item = Items.getItemByID(reward.id)
				local qty = reward.quantity
				table.insert(rewardTable, Icons.Icon({item.name, type='item', qty = qty}))
			end
		end
	end
	return rewardTable
end

function p.sortPOIByCoords(array)
	table.sort(array, function(a, b)
		local aX, aY = p.convertAxialToXY(a.coords)
		local bX, bY = p.convertAxialToXY(b.coords)
		if aX ~= bX then
			return aX < bX
		else
			return aY < bY
		end
	end)
end

function p.getHexMasteryBonusTable(frame)
	-- Build table header
	local resultTable = mw.html.create('table')
	resultTable:addClass('wikitable stickyHeaders')
	resultTable:tag('tr'):addClass('headerRow-0')
		:tag('th'):wikitext('Hexes Mastered')
		:tag('th'):wikitext('Passive Bonuses')
		:tag('th'):wikitext('Rewards')
	
	local masteryBonuses = Shared.shallowClone(p.MelvorMap.masteryBonuses)
	table.sort(masteryBonuses, function(a, b) return a.masteredHexes < b.masteredHexes end)
	for i, bonus in ipairs(masteryBonuses) do
		-- Populate passive bonuses & rewards cell text
		local modText, rewardTextPart = nil, {}
		if bonus.modifiers ~= nil and not Shared.tableIsEmpty(bonus.modifiers) then
			modText = Constants.getModifiersText(bonus.modifiers, true, false)
		end
		if bonus.items ~= nil then
			for k, itemDef in ipairs(bonus.items) do
				local item = Items.getItemByID(itemDef.id)
				if item ~= nil then
					local expIcon = Icons.getExpansionIcon(itemDef.id)
					table.insert(rewardTextPart, expIcon .. Icons.Icon({item.name, type='item', qty = itemDef.quantity}))
				end
			end
		end
		if bonus.pets ~= nil then
			for k, petID in ipairs(bonus.pets) do
				local pet = GameData.getEntityByID('pets', petID)
				if pet ~= nil then
					local expIcon = Icons.getExpansionIcon(petID)
					table.insert(rewardTextPart, expIcon .. Icons.Icon({pet.name, type='pet'}))
				end
			end
		end
		
		local row = mw.html.create('tr')
		row:tag('td'):wikitext(Shared.formatnum(bonus.masteredHexes))
		if modText == nil then
			row:tag('td')
				:addClass('table-na')
				:wikitext('None')
		else
			row:tag('td'):wikitext(modText)
		end
		if Shared.tableIsEmpty(rewardTextPart) then
			row:tag('td')
				:addClass('table-na')
				:wikitext('None')
		else
			row:tag('td'):wikitext(table.concat(rewardTextPart, '\n'))
		end
		resultTable:node(row)
	end
	return tostring(resultTable)
end

function p.getPointOfInterestTable(frame)
	local POIs = {}
	local POI_Strings = {}
	local tableStr = {}
	table.insert(tableStr, '{| class="wikitable sortable lighttable"')
	table.insert(tableStr, '\r\n|-\r\n!colspan="2"|Name!!Type!!X!!Y!!Requirements!!Discovery Rewards!!Discovery Modifiers!!Active Effect')
	
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		table.insert(POIs, POI)
	end
	p.sortPOIByCoords(POIs)
	
	for i, POI in pairs(POIs) do
		local X, Y = p.convertAxialToXY(POI.coords)
		table.insert(POI_Strings, POI.name..' ('..X..', '..Y..')')
		
		table.insert(tableStr,'\r\n|-\r\n|')
		table.insert(tableStr, Icons.Icon({POI.name, type='poi', notext='true', nolink='true', size='50'}))
		table.insert(tableStr, '||id="'..string.gsub(POI.name,' ', '')..'"|')
		--Link Dig Sites
		if POI.type == 'DigSite' then
			table.insert(tableStr, '[['..POI.name..']]')
		else
			table.insert(tableStr, POI.name)
		end
		local POIType = POI.type
		if POIType == 'DigSite' then
			POIType = 'Dig&nbsp;Site'
		else
			if POI.activeModifiers ~= nil then
				POIType = 'Active'
			elseif POI.fastTravel ~= nil then
				POIType = 'Port'
			end
		end
		table.insert(tableStr, '||'..POIType)
		table.insert(tableStr, '||'..X)
		table.insert(tableStr, '||'..Y)
		
		--Add Requirements
		table.insert(tableStr, '\r\n|')
		local reqTable= p._getPOIRequirements(POI)
		table.insert(tableStr, table.concat(reqTable, '<br/>'))
		
		--Add Discovery Rewards
		table.insert(tableStr, '\r\n|')
		local rewardTable = p._getDiscoveryRewards(POI)
		table.insert(tableStr, table.concat(rewardTable,'<br/>'))
		
		--Add Discovery Modifiers
		table.insert(tableStr, '\r\n|')
		if POI.discoveryModifiers ~= nil then
			table.insert(tableStr, Constants.getModifiersText(POI.discoveryModifiers.modifiers)..' (for '..POI.discoveryModifiers.moves..' travels)')
		end
		
		--Add Active Modifiers
		table.insert(tableStr, '\r\n|')
		if POI.activeModifiers ~= nil then
			table.insert(tableStr, Constants.getModifiersText(POI.activeModifiers))
		end
	end
	
	table.insert(tableStr, '\r\n|}')
	
	return table.concat(tableStr, '')
end

function p._getDiscoveryRewardsTable(items)
	local POIs = {}
	for i, POI in ipairs(p.MelvorMap.pointsOfInterest) do
		if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
			for i, reward in ipairs(POI.discoveryRewards.items) do
				for j, item in ipairs(items) do
					if reward.id == item.id then
						table.insert(POIs, POI)
						break
					end
				end
			end
		end
	end

	if Shared.tableIsEmpty(POIs) then
		return ''
	end
	p.sortPOIByCoords(POIs)

	-- Build the table
	local resultTable = mw.html.create('table')
	resultTable:addClass('wikitable sortable')
	resultTable:tag('tr'):addClass('headerRow-0')
		:tag('th'):wikitext('Point of Interest')
		:tag('th'):wikitext('X')
		:tag('th'):wikitext('Y')
		:tag('th'):wikitext('Requirements')
		:tag('th'):wikitext('Discovery Rewards')

	for _, POI in ipairs(POIs) do
		local X, Y = p.convertAxialToXY(POI.coords)
		local tr = mw.html.create('tr')
		tr:tag('td'):wikitext(Icons.Icon({POI.name, type='poi'}))
		tr:tag('td'):wikitext(X)
		tr:tag('td'):wikitext(Y)
		tr:tag('td'):wikitext(table.concat(p._getPOIRequirements(POI), '<br/>'))
		tr:tag('td'):wikitext(table.concat(p._getDiscoveryRewards(POI), '<br/>'))
		resultTable:node(tr)
	end
	return tostring(resultTable)
end

function p.getDiscoveryRewardsTable(frame)
	local itemNames = frame.args ~= nil and frame.args[1] or frame
	local items = {}
	for itemName in string.gmatch(itemNames, "[^,]*") do
		item = Items.getItem(itemName)
		if item ~= nil then
			table.insert(items, item)
		end
	end
	if #items == nil then
		return Shared.printError('No items found in game data for: "' .. itemNames .. '"')
	end
	local resultTable = p._getDiscoveryRewardsTable(items)
	if resultTable == '' then
		return ''
	else
		return '==POI Discovery Rewards==\n' .. resultTable
	end
end

function p.hex(frame)
	-- Default behavior, when no coords supplied
	if (frame == nil or frame.args['x'] == nil or frame.args['y'] == nil) then
		return 'Hex'
	end
	local X = tonumber(frame.args['x'])
	local Y = tonumber(frame.args['y'])
	if X == nil or Y == nil then
		return '<invalid XY format>'
	elseif X < 0 or Y < 0 or X > 31 or Y > 29 or (Y == 29 and X % 2 == 0) then
		return '<out of range (' .. X .. ',' .. Y .. ')>'
	end
	--
	local noicon = frame.args['noicon'] or false
	local coords = '<span>(' .. X .. ',' .. Y .. ')</span>'
	local hex = p.getPointOfInterestByXY(X, Y)
	-- nil means just a normal hex
	if hex == nil or hex['id'] == nil or noicon then
		return coords
	end
	-- Valid POI so consider decorations
	local notext = frame.args['notext'] or false
	local nolink = frame.args['nolink'] or false
	local poi_icon = Icons.Icon({hex['name'], type='poi', notext=notext or nil, nolink=nolink or nil, size='25'})
	return '<span>' .. poi_icon .. ' ' .. coords .. '</span>'
end

function p.testDiscoveryRewards()
	local testTable = {}
	for i, POI in pairs(p.MelvorMap.pointsOfInterest) do
		if POI.discoveryRewards ~= nil and POI.discoveryRewards.items ~= nil then
			local item = Items.getItemByID(POI.discoveryRewards.items[1].id)
			table.insert(testTable, p._getDiscoveryRewardsTable({item}))
		end
	end
	return table.concat(testTable)
end

function p.testHex()
	local testTable = {}
	for x = 0, 31 do
		for y = 0, 29 do
		    if y == 29 and x % 2 == 1 then
		    	-- no tile here
		    else
				item = p.hex({args={x=x, y=y}})
				table.insert(testTable, item)
		    end
		end
	end
	return table.concat(testTable)
end

function p.test()
	return p.getPointOfInterestTable()
end

return p