Difference between revisions of "Module:Maps"

From Dead by Daylight Wiki
Jump to: navigation, search
m
m
Line 496: Line 496:
 
paramTable["minpallets"] = p.getMinPalletsByMap(map) --legacy - should be removed
 
paramTable["minpallets"] = p.getMinPalletsByMap(map) --legacy - should be removed
 
paramTable["maxpallets"] = p.getMaxPalletsByMap(map) --legacy - should be removed
 
paramTable["maxpallets"] = p.getMaxPalletsByMap(map) --legacy - should be removed
paramTable["wegith"] = mapObject.weight
+
paramTable["weight"] = mapObject.weight
 
if(type(getMapReleaseByIndex(mapIndex)) ~= "nil") then
 
if(type(getMapReleaseByIndex(mapIndex)) ~= "nil") then
 
paramTable["release"] = "[[Patch " .. getMapReleaseByIndex(mapIndex) .. "]]"
 
paramTable["release"] = "[[Patch " .. getMapReleaseByIndex(mapIndex) .. "]]"

Revision as of 17:34, 29 March 2021


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 = "|" -- 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 .. " '''<nowiki>" .. frame:expandTemplate{title = '!'}  .. "</nowiki>''' "
				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 .. " for 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\n'''Example: '''{{#Invoke:Maps|assembleMapsForRealms|name_of_realm}}\n\n")
		return "Missing parameter \"realm\". Please add the parameter into invocation.\n\n'''" .. c.clr("Example", "red") .. ":''' {{#Invoke:Maps|assembleMapsForRealms|'''" .. c.clr("name_of_realm", "orange") .. "'''}}\n\n"
	end
	
	result = "{| class=\"wikitable\"\n"
	while maps[i] do
		if(maps[i].realm == realmId) then
			map = maps[i].name
			result = result .. "|<center>[[" .. map .. "]]</center>\n"
			result = result .. "[[File:" .. p.resolveImageNameByMap(map) .. "|center|frameless|link=" .. map .. "]]"
			
			j = 1
			outlines = p.getOutlineGrid(map)
			while outlines[j] do --loop for cases with multiple outlines
				result = result .. "[[File:" .. outlines[j] .. "|center|framelss|200px|link=" .. map .. "]]"
				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 m<sup>2</sup>\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