Module:Common: Difference between revisions

From Melvor Idle
(New module, attempting to avoid module requirement loops when modules which require many modules also have functions which are desired by other modules)
(No difference)

Revision as of 22:50, 9 September 2023

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

-- This module contains common functions which interact with or interpret game data
-- in some form. Functions here may be applicable to various aspects of the game
-- (e.g. monsters, shop, dungeons, pets, items, and so on) and are contained here
-- to avoid loops when requiring modules.

-- Any functions which have no reliance upon, or relevance to game data are better suited
-- for [[Module:Shared]].

-- This module should _never_ require other modules which rely upon [[Module:GameData]]

local p = {}

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

-- getSkillName: Given a valid namespaced skill ID, returns that skill's name
function p.getSkillName(skillID)
	local skill = GameData.getSkillData(skillID)
	if skill ~= nil then
		return skill.name
	end
end

-- getSkillID: Given a valid skill name, returns that skill's namespaced ID
function p.getSkillID(skillName)
	for i, skillData in ipairs(GameData.rawData.skillData) do
		if skillData.data.name == skillName then
			return skillData.skillID
		end
	end
end

-- getPurchaseName: Given a purchase from shop data, returns the name of that purchase
function p.getPurchaseName(purch)
	if purch.customName ~= nil then
		return purch.customName
	elseif purch.contains ~= nil then
		local item = nil
		if purch.contains.items ~= nil and not Shared.tableIsEmpty(purch.contains.items) then
			item = GameData.getEntityByID('items', purch.contains.items[1].id)
		elseif purch.contains.itemCharges ~= nil and not Shared.tableIsEmpty(purch.contains.itemCharges) then
			item = GameData.getEntityByID('items', purch.contains.itemCharges.id)
		end
		if item ~= nil then
			return item.name
		end
		if purch.contains.petID ~= nil then
			local pet = GameData.getEntityByID('pets', purch.contains.petID)
			if pet ~= nil then
				return pet.name
			end
		end
	end
	return ''
end

-- getPurchaseType: Given a purchase from shop data, returns the type of that purchase (based on
-- the purchase's contents)
function p.getPurchaseType(purchase)
	if purchase.contains == nil then
		return 'Unknown'
	elseif purchase.contains.petID ~= nil then
		return 'Pet'
	elseif purchase.contains.itemCharges ~= nil then
		return 'Item'
	elseif purchase.contains.modifiers ~= nil or purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0 then
		return 'Upgrade'
	elseif purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
		return 'Item Bundle'
	else
		return 'Item'
	end
end

-- getPurchaseIcon: Accepts the same arguments as Icons.Icon(), except the first parameter is a
-- shop purchase rather than the icon/linked page name
function p.getPurchaseIcon(iconArgs)
	local purchase = iconArgs[1]
	local purchaseName = p.getPurchaseName(purchase)
	local purchType = p.getPurchaseType(purchase)
	-- Amend iconArgs before passing to Icons.Icon()
	iconArgs[1] = purchaseName
	iconArgs['type'] = (purchType == 'Item Bundle' and 'item') or string.lower(purchType)

	return Icons.Icon(iconArgs)
end

-- getRequirementString: Given requirements from something such as a shop purchase or dungeon,
-- returns human readable wikitext for those requirements. If there are no requirements, returns
-- the value specified by valueIfNone instead
function p.getRequirementString(reqs, valueIfNone)
	if reqs == nil or Shared.tableIsEmpty(reqs) then
		return valueIfNone
	end

	local reqArray = {}
	for i, req in ipairs(reqs) do
		if req.type == 'AllSkillLevels' then
			local reqText = 'Level ' .. req.level .. ' in all skills'
			if req.exceptions ~= nil and not Shared.tableIsEmpty(req.exceptions) then
				local exceptSkills = {}
				for i, skillID in ipairs(req.exceptions) do
					local skillName = p.getSkillName(skillID)
					if skillName ~= nil then
						table.insert(exceptSkills, Icons.Icon({skillName, type='skill'}))
					end
				end
				reqText = reqText .. ' except for ' .. table.concat(exceptSkills, ', ')
			end
			table.insert(reqArray, reqText)
		elseif req.type == 'ArchaeologyItemsDonated' then
			table.insert(reqArray, 'Donate ' .. Shared.formatnum(req.count) .. ' Artefacts to the Museum in ' .. Icons.Icon({'Archaeology', type='skill'}))
		elseif req.type == 'CartographyPOIDiscovery' then
			local map = GameData.getEntityByID(GameData.skillData.Cartography.worldMaps, req.worldMapID)
			if map ~= nil then
				local poiPart = {}
				for j, poiID in ipairs(req.poiIDs) do
					local poi = GameData.getEntityByID(map.pointsOfInterest, poiID)
					if poi ~= nil then
						table.insert(poiPart, Icons.Icon({poi.name, type='poi'}))
					else
						table.insert(poiPart, Shared.printError('Could not find POI with ID ' .. poiID))
					end
				end
				table.insert(reqArray, 'Discover ' .. table.concat(poiPart, ', '))
			end
		elseif req.type == 'Completion' then
			local ns = GameData.getEntityByName('namespaces', req.namespace)
			if ns ~= nil then
				table.insert(reqArray, req.percent .. '% ' .. ns.displayName .. ' Completion')
			end
		elseif req.type == 'DungeonCompletion' then
			local dung = GameData.getEntityByID('dungeons', req.dungeonID)
			if dung ~= nil then
				local dungStr = 'Complete ' .. Icons.Icon({dung.name, type='dungeon'})
				if req.count > 1 then
					dungStr = dungStr .. ' ' .. Shared.formatnum(req.count) .. ' times'
				end
				table.insert(reqArray, dungStr)
			end
		elseif req.type == 'ItemFound' then
			local item = GameData.getObjectByID('items', req.itemID)
			if item ~= nil then
				table.insert(reqArray, 'Find ' .. Icons.Icon({item.name, type='item'}))
			end
		elseif req.type == 'ShopPurchase' then
			local shopPurch = GameData.getEntityByID('shopPurchases', req.purchaseID)
			if shopPurch ~= nil then
				table.insert(reqArray, p.getPurchaseIcon({ shopPurch }) .. ' Purchased')
			end
		elseif req.type == 'SkillLevel' then
			local skillName = p.getSkillName(req.skillID)
			if skillName ~= nil then
				table.insert(reqArray, Icons._SkillReq(skillName, req.level))
			end
		elseif req.type == 'SlayerItem' then
			local item = GameData.getEntityByID('items', req.itemID)
			if item ~= nil then
				table.insert(reqArray, Icons.Icon({item.name, type='item'}) .. ' Equipped')
			end
		elseif req.type == 'SlayerTask' then
			table.insert(reqArray, 'Complete ' .. Shared.formatnum(req.count) .. ' ' .. req.tier .. ' Slayer Tasks')
		elseif req.type == 'TownshipBuilding' then
			local tsData = GameData.getSkillData('melvorD:Township')
			if tsData ~= nil and tsData.buildings ~= nil then
				local building = GameData.getEntityByID(tsData.buildings, req.buildingID)
				if building ~= nil then
					table.insert(reqArray, 'Have ' .. Shared.formatnum(req.count) .. ' ' .. building.name .. ' actively built in Township')
				end
			end
		elseif req.type == 'TownshipTask' then
			table.insert(reqArray, 'Complete ' .. Shared.formatnum(req.count) .. ' Township Tasks')
		else
			table.insert(reqArray, Shared.printError('Unknown requirement: ' .. (req.type or 'nil')))
		end
	end

	if Shared.tableIsEmpty(reqArray) then
		return valueIfNone
	else
		return table.concat(reqArray, '<br/>')
	end
end

return p