Module:Maps

local p = {} local data = require("Module:Datatable") local mathOps = require("Module:MathOps") local utils = require("Module:Utils") local c = utils -- As there is onlny one function relevant to colors I make only alias to utils Module to convenient naming "c - color" local frame = mw.getCurrentFrame local bar = "&#124;" -- code for | local nl = "\n"

--Function to convert string "true/false" to actual boolean values function resolveBoolParam(param) if type(param) ~= "string" then return utils.bool(param.args[1]) end end

--Function returning an average size across all maps stored in table maps. --If convertToMetres is set to true then result will be returned in square metres function p.getAverageMapSize(convertToMetres) convertToMetres = resolveBoolParam(convertToMetres)--utils.bool(convertToMetres) local result = 0 local sum = 0 local i = 1 while maps[i] do --going through all maps local mapTiles = maps[i].ASTiles if(type(mapTiles) ~= "table") then sum = sum + mapTiles else --in case mapTiles are described in multiple layers local j = 1 while mapTiles[j] do				sum = sum + mapTiles[j][1] --mapTiles are expected to be first parameter j = j + 1 end end i = i + 1 end if i > 1 then i = i - 1 end --as the index starts at 1 we must decrease the counter as the loop ends with incrementation of counter/index even after last map looped sum = sum / i --making average if convertToMetres then result = p.toSMetres(sum) else result = sum end return mathOps.round(result) end

--Call a function with a string parameter that will be resolved afterwards function p.getCountOfMaps return utils.getCount("map") end

function p.getCountOfRealms return utils.getCount("realm") end

--Returns the biggest map from the maps table. Size is measured in Square Tiles. --returnName: [optional parameter], String -> Boolean, flag whether function should return Name of map or size value by default function p.getBiggestMap(returnName) if returnName == nil then returnName = false elseif type(returnName) == "table" then returnName = utils.bool(returnName.args[1]) or false end local mapId = 0 local result = 0 local mapTiles local i = 1 while maps[i] do		mapTiles = maps[i].ASTiles if(type(mapTiles) ~= "table") then if mapTiles > result then result = mapTiles mapId = i			end else --in case mapTiles are described in multiple layers local j = 1 local subTotal = 0 while mapTiles[j] do				subTotal = subTotal + mapTiles[j][1] --mapTiles are expected to be first parameter j = j + 1 end if subTotal > result then result = subTotal mapId = i			end end i = i + 1 end if(returnName) then return maps[mapId].name end return result end

--Returns the smallest map from the maps table. Size is measured in Square Tiles. --returnName: [optional parameter], String -> Boolean, flag whether function should return Name of map or size value by default function p.getSmallestMap(returnName) if returnName == nil then returnName = false elseif type(returnName) == "table" then returnName = utils.bool(returnName.args[1]) or false end local mapId local result = 0 local mapTiles local i = 1 if maps[i].ASTiles then --just a avoiding assigning magic constant so using first map as a starting point result = maps[i].ASTiles mapId = 1 end while maps[i] do		mapTiles = maps[i].ASTiles if(type(mapTiles) ~= "table") then if mapTiles < result and mapTiles > 0 then result = mapTiles mapId = i			end else --in case mapTiles are described in multiple layers local j = 1 local subTotal = 0 for j, mapLayer in ipairs(mapTiles) do				subTotal = subTotal + mapLayer[1] --mapTiles are expected to be first parameter end if subTotal < result and subTotal > 0 then result = subTotal mapId = i			end end i = i + 1 end if(returnName) then return maps[mapId].name end return result end

--Returns Count of realms based on map. If the parameter is not passed function use Page name instead function p.getCountOfRealmMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local realmId = getRealmIdByMapName(map)

return p.getCountOfRealmMapByRealmId(realmId) end

function p.getCountOfRealmMapByRealmId(realmId) local result = 0 local currentMap local i = 1 while maps[i] do		currentMap = maps[i] if currentMap.realm == realmId then result = result + 1 end i = i + 1 end return result end

function p.getCountOfRealmMapsByName(realm) if type(realm) ~= "string" then realm = realm.args[1] or mw.title.getCurrentTitle.text end local realmId = p.getRealmIdByRealm(realm)

return p.getCountOfRealmMapByRealmId(realmId) end

function p.getRealmIdByRealm(realm) if type(realm) ~= "string" then realm = realm.args[1] or mw.title.getCurrentTitle.text end spec = "^(.+) %(.+%)$" --page specification, ex.: "Silent Hill (Realm)"" >> "Silent Hill"	if string.find(realm, spec) then		realm = realm:match(spec)		end	for i, realmItem in ipairs(realms) do		if realm == realmItem[1] then return realmItem.id end	end	return 0 end

--Returns Realm ID based on map name passed as a parameter function getRealmIdByMapName(map) local i = 1 local currentMap while maps[i] do		currentMap = maps[i] if currentMap.name == map then return currentMap.realm end i = i + 1 end return 0 end

--Returns Realm name based on passed map name. If the function is called without parameter the function will use Page name as a map name function p.getRealmNameByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end return getRealmNameById(getRealmIdByMapName(map)) end

--Returns Realm Name based on realm's ID function getRealmNameById(id) for _, realm in ipairs(realms) do		if realm.id == id then return realm[1] end end return "Unknown Realm" end

function p.toSMetres(number) return number * 64 end

function p.toSTiles(number) return number / 64 end

function p.getAltNameByMap(map) local result local mapId if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end mapId = getMapIndexByMapName(map) if maps[mapId].altName == maps[mapId].name or maps[mapId].altName == nil then --if Map name is the same as its main name or doesn't have it at all return empty string result = "" else result = maps[mapId].altName end return result end

function getMapIndexByMapName(map) for _, currentMap in ipairs(maps) do		if currentMap.name == map then return currentMap.id		end end return 0 end

function getMapByMapName(map) for _, currentMap in ipairs(maps) do		if currentMap.name == map then return currentMap end end return nil end

function p.displayRealmIfExist(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local altName = p.getAltNameByMap(map) local result = "" if altName ~= "" then result = "or \""..altName.."\" " end return result end

--id: [optional parameter], id of map from table maps function p.getMapName(id) if type(id) == "table" and type(id.args[1]) ~= "nil" then id = tonumber(id.args[1]) elseif type(id) == "table" then id = getMapIndexByMapName(mw.title.getCurrentTitle.text) end

return 	maps[id].name end

function p.getMapSizeByMap(map, convertToMetres) --TODO as the TealmsInfo template is planned to redisgn this part it will be needed to rewrite this function if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local mapId = getMapIndexByMapName(map) local value local areas = "" if(type(maps[mapId].ASTiles) == "table") then local i = 1 while maps[mapId].ASTiles[i] do			area = maps[mapId].ASTiles[i] if convertToMetres then value = utils.commaFormat(p.toSMetres(area[1])) else value = area[1] end areas = areas .. value .. " (" .. area[2] .. ")" if(type(maps[mapId].ASTiles[i + 1]) ~= "nil") then --areas = areas .. " ''' " .. frame:expandTemplate{title = '!'} .. " ''' "				areas = areas .. " '''" .. bar .. "''' "			end i = i + 1 end return areas else if convertToMetres then return p.toSMetres(maps[mapId].ASTiles) end return maps[mapId].ASTiles end return areas end

function p.getMapSizeByMapInSMetres(map) return p.getMapSizeByMap(map, true) end

function p.getMinHooksByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end return 	maps[getMapIndexByMapName(map)].minHooks end

function p.getMaxHooksByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local mapId = getMapIndexByMapName(map) if maps[mapId].maxHooks == nil then if maps[mapId].minHooks ~= nil then --must be separated condition if case maxHooks is nil return maps[mapId].minHooks + 5 --default difference between count of min and max of hooks end else return maps[mapId].maxHooks end end

function p.getMinPalletsByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end return maps[getMapIndexByMapName(map)].minPallets end

function p.getMaxPalletsByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end return maps[getMapIndexByMapName(map)].maxPallets end

--returns a table with Outline name(s) function p.getOutlineGrid(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local result = {} local mapId = getMapIndexByMapName(map) local i = 1 local imgIndex = isListedInImagesByMapId(mapId)

if type(maps[mapId].ASTiles) == "table" then while maps[mapId].ASTiles[i] do			if(imgIndex ~= 0) then result[i] = mapImages[imgIndex].outline[i] .. ".png" else result[i] = p.resolveOutlineNameFromGrid(mapId, i) .. ".png" end i = i + 1 end else if(imgIndex ~= 0) then result[i] = mapImages[imgIndex].outline .. ".png" else result[i] = p.resolveOutlineName(mapId) .. ".png" end end

return result end

function isListedInImagesByMapId(mapId) local i = 1 while mapImages[i] do		if(mapImages[i].id == mapId) then return i		end i = i + 1 end return 0 end

function p.resolveOutlineNameFromGrid(mapId, index) local outlineMapName = utils.resolveFileName(maps[mapId].name) local outlineSubName = utils.resolveFileName(maps[mapId].ASTiles[index][2]) return outlineMapName .. "Outline_" .. outlineSubName end

function p.resolveOutlineName(mapId) --These two functions should be merged --TODO local outlineMapName = utils.resolveFileName(maps[mapId].name) return outlineMapName .. "Outline" end

function p.resolveImageNameByMap(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local realmId = getRealmIdByMapName(map) local mapId = getMapIndexByMapName(map) local realmAbbr = realms[realmId][2] local mapAltName = "" local imgIndex = isListedInImagesByMapId(mapId) if(imgIndex ~= 0) then return mapImages[imgIndex].image .. ".png" elseif type(maps[mapId].altName) ~= "nil" then mapAltName = utils.resolveFileName(maps[mapId].altName) else --Not the happies name of variable but it works as this else branch is only for rare cases mapAltName = utils.resolveFileName(maps[mapId].name) end return "IconMap " .. realmAbbr .. " " .. mapAltName .. ".png" end

function getMapReleaseByIndex(mapIndex) return maps[mapIndex].release end

function getThemeByIndex(mapIndex) local i = 1 local mapId = maps[mapIndex].id	while themes[i] do		if themes[i].mapId == mapId then return themes[i].landmarksound .. ".ogg" end i = i + 1 end return nil end

function p.assembleRealmsInfo(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local mapObject = getMapByMapName(map) local i = 1 local mapIndex = getMapIndexByMapName(map) local paramTable = {} local outlines = p.getOutlineGrid(map)

paramTable["map"] = mapObject.name --p.getMapName(mapIndex) paramTable["altmap"] = p.getAltNameByMap(map) paramTable["image"] = p.resolveImageNameByMap(map) while outlines[i] do		paramTable["outline"..i] = outlines[i] i = i + 1 end paramTable["realm"] = "" .. p.getRealmNameByMap(map) .. "" paramTable["area"] = p.getMapSizeByMap(map) paramTable["area2"] = p.getMapSizeByMapInSMetres(map) if(type(maps[mapIndex].ASTiles) == "table") then local mapTiles = maps[mapIndex].ASTiles local areaTotal = 0 i = 1 while mapTiles[i] do			areaTotal = areaTotal + mapTiles[i][1] --mapTiles are expected to be first parameter i = i + 1 end paramTable["area3"] = areaTotal paramTable["area4"] = utils.commaFormat(p.toSMetres(areaTotal)) end paramTable["minhooks"] = mapObject.minHooks --p.getMinHooksByMap(map) paramTable["maxhooks"] = mapObject.maxHooks --p.getMaxHooksByMap(map) paramTable["minpallets"] = p.getMinPalletsByMap(map) --legacy - should be removed paramTable["maxpallets"] = p.getMaxPalletsByMap(map) --legacy - should be removed paramTable["weight"] = mapObject.weight if(type(getMapReleaseByIndex(mapIndex)) ~= "nil") then paramTable["release"] = "Patch " .. getMapReleaseByIndex(mapIndex) .. "" end local theme = getThemeByIndex(mapIndex) if(type(theme) == "string") then paramTable["landmarksound"] = theme end

mw.log(mw.dumpObject(paramTable)) return frame:expandTemplate{title = 'RealmsInfo', args = paramTable} --string.char(10) end

function p.assembleMapPageHeader(map) if type(map) ~= "string" then map = map.args[1] or mw.title.getCurrentTitle.text end local result local mapCount = p.getCountOfRealmMap(map) result = p.assembleRealmsInfo(map) result = result .. "\n\n'''" .. map .. "''' " .. p.displayRealmIfExist(map) if mapCount > 1 then result = result .. " is one of '''" .. frame:expandTemplate{title = "clr", args = {2, p.getCountOfRealmMap(map)} } .. "''' Maps" else result = result .. " is the only Map" end result = result .. " in the " .. p.getRealmNameByMap(map) .. " Realm."

return result end

function p.assembleMapsForRealms(realm) local realmId = 0 local result = "" local map local outlines local i = 1 local j = 1 if realm == nil then realmId = p.getRealmIdByRealm(mw.title.getCurrentTitle.text) elseif type(realm) == "table" then realmId = p.getRealmIdByRealm(realm.args[1] or mw.title.getCurrentTitle.text) elseif type(realm) == "string" then realmId = p.getRealmIdByRealm(realm) end if realmId == 0 then mw.log("Missing parameter \"realm\". Please add the parameter into invocation.\n\nExample: \n\n") return "Missing parameter \"realm\". Please add the parameter into invocation.\n\n'''" .. c.clr("Example", "red") .. ":''' \n\n" end result = "{| class=\"wikitable\"\n" while maps[i] do		if(maps[i].realm == realmId) then map = maps[i].name result = result .. "| " .. map .. " \n" result = result .. ""			j = 1 outlines = p.getOutlineGrid(map) while outlines[j] do --loop for cases with multiple outlines result = result .. ""				j = j + 1 end result = result .. "\n" --just for keeping the same formatting, functionally completely useless end i = i + 1 end result = result .. "|}"	mw.log(result) return result end

function p.assembleSortedMapsTableBySize local result = "" local center = "style=\"text-align:center\"" utils.sortMapsByASTiles local mapRates = p.getRatesOfMapTable local mapRate local index local bgColor

result = "{| class=\"wikitable\"\n|-" .. nl result = result .. "! Rank !! Map !! Size in square Tiles !! Size in m2\n" local i = 1 while mapRates[i] do		mapRate = mapRates[i] result = result .. "|- " .. center .. nl result = result .. "! "		if mapRate.count > 1 then --if count of maps of such size is more than one result = result .. "rowspan=\"" .. mapRate.count .. "\"| " end result = result .. i .. nl --printing map(s) Rate globalIndex = getAbsolutePosition(mapRates, i)		for index = globalIndex, globalIndex + mapRate.count - 1, 1 do --there must be -1 due to offset in lists as the globalIndex starts with at index of first map current Rate --mw.log("i: " .. i .. " | index: " .. index .. " | Map: ".. maps[index].name .. " |||| index == gobalIndex: " .. index .. " == " .. globalIndex .. " |||| mapRate.count > 1: " .. mapRate.count .. " > " .. 1) if(index > globalIndex) then --if the index is higher than starting position means if it's not the first iteration then do the trick result = result .. "|- " .. center .. nl			end bgColor = realms[maps[index].realm].color --In map must be correct realmID otherwise the code fails --mw.log(bgColor) result = result .. "| style=\"background:#" .. bgColor .. ";color:" .. utils.resolveTextColorByBackground(bgColor) .. ";\" | " .. maps[index].name .. nl --TODO complete styles if(index == globalIndex and mapRate.count > 1) then result = result .. "| rowspan=\"" .. mapRate.count .. "\"| " .. mapRate.size .. nl result = result .. "| rowspan=\"" .. mapRate.count .. "\"| " .. utils.commaFormat(p.toSMetres(mapRate.size)) .. nl			elseif (index == globalIndex) then result = result .. "| " .. mapRate.size .. nl result = result .. "| " .. utils.commaFormat(p.toSMetres(mapRate.size)) .. nl			end end i = i + 1 end result = result .. "|}"	mw.log(result) return result end

function p.getRatesOfMapTable local i = 1 local result = {} while maps[i] do --go through all maps local j = 1 local rate = nil local size = maps[i].ASTiles if type(size) == "table" then size = utils.getSumOfASTiles(maps[i].ASTiles) end while result[j] do --everytime look for if there is already the size of map logged in result table if result[j].size == size then --if so then store it and skip the rest rate = result[j] break end j = j + 1 end if rate == nil then --if such size wasn't found in rate table then create a new one, "j" doesn't have to be increased as it's already increased by last go-through of loop above result[j] = {} result[j].count = 1 --we do not store the size as the index in table will later serve as a rank (after we sort the table) result[j].size = size else result[j].count	= result[j].count + 1 -- "j" doesn't have to be decreased as the loop above breaked out before incrementation end i = i + 1

end utils.sortMapRates(result) --sorting will cause that the index serve as an rate for table return result end

--function returns an index reflecting a position in sorted maps table based on current index in mapRates table function getAbsolutePosition(mapRates, currentIndex) local i = 1 local result = 1 while i < currentIndex do		result = result + mapRates[i].count --sum count of map from every previous rate until you reach the current index i = i + 1 end

return result end

return p