Module:MapLocations

De ARK Wiki
Aller à la navigation Aller à la recherche
Template-info.png Documentation

Affiche une carte avec un ou plusieurs marqueurs selon les coordonnées données.

Paramètres

Tous optionnels

Paramètre Par défaut Description
map Map The Island.jpg Nom de fichier de la carte
mapsize 300 Taille de carte en px
markersize 10 Taille du marqueur en px
markercolor #f40
markericon Nom de fichier de l'icône par défaut
opacity 1 Opacité des marqueurs
text Texte affiché sous la carte
float Côté où la carte s'aligne (left/right)
borderCoordT 7.2 Coordonnées du haut
borderCoordR 92.8 Coordonnées de droite
borderCoordB 92.8 Coordonnées du bas
borderCoordL 7.2 Coordonnées de la gauche

Les lieux doivent être donnés par des valeurs séparées par des virgules et doivent être dans cet ordre (seules les lat et lon sont obligatoires) lat,lon,markersize,markercolor,markertooltip,markericon[,markericon2[,markericon3...]]. Les paramètres laissés en blanc seront donnés par défaut. Par ex. écrire 20,50,,green pour un marqueur vert en (20/50) avec la taille par défaut.

  • Les virgules ne sont pas autorisées dans le titre du texte (elles brisent le format)
  • Un signe égal doit être écrit {{=}}, une barre verticale doit être écrite {{!}}.

Exemple

{{MapLocations|30,50|20,80,20}}
The Island Topographic Map.jpg
{{MapLocations|40,50|30,80|text=Tellement de points|80,50,30,yellow,Je suis un marqueur jaune!|opacity=0.7|50,50,5|markercolor=green|mapsize=200|10,10,5}}
The Island Topographic Map.jpg
tant de points

local json_ordered = require('Module:JsonOrdered')
local p = {}

local function dump(o)
  if type(o) == 'table' then
     local s = '{ '
     for k,v in pairs(o) do
        if type(k) ~= 'number' then k = '"'..k..'"' end
        s = s .. '['..k..'] = ' .. dump(v) .. ','
     end
     return s .. '} '
  else
     return tostring(o)
  end
end


local function processMap(map, schema)
  local borderCoords = {t=0,r=100,b=100,l=0}
  if schema == true then
    if map == 'The Island' then map = 'The Island Map.jpg'
    elseif map == 'The Center' then map = 'The Center Map.jpg'
    elseif map == 'Scorched Earth' then map = 'Scorched Earth Map.jpg'
    elseif map == 'Ragnarok' then map = 'Ragnarok Map.jpg'
    elseif map == 'Aberration' then map = 'Aberration Map.jpg'
    elseif map == 'Extinction' then map = 'Extinction Map.jpg'
    elseif map == "Valguero" then map = "Valguero Map.jpg"
    elseif map == 'Genesis: Part 1' then map = 'Genesis Part 1 Map.jpg'
    elseif map == "Crystal Isles" then map = "Crystal Isles Map.jpg"
    elseif map == 'Genesis: Part 2' then map = 'Genesis Part 2 Map.jpg'
    elseif map == 'Lost Island' then map = 'Lost Island Map.jpg'
    elseif map == 'Fjordur' then map = 'Fjordur Map.jpg'
    else 
      schema = false
    end
  end
  if schema == nil or schema == false then
    -- if the map is given as just the name, apply the default map-file
    if map == 'The Island' then map = 'The Island Topographic Map.jpg'
    elseif map == 'The Center' then map = 'The Center Topographic Map.jpg'
    elseif map == 'Scorched Earth' then map = 'Scorched Earth Topographic Map.jpg'
    elseif map == 'Ragnarok' then map = 'Ragnarok Topographic Map.jpg'
    elseif map == 'Aberration' then map = 'Aberration Topographic Map.jpg'
    elseif map == 'Extinction' then map = 'Extinction Topographic Map.jpg'
    elseif map == "Valguero" then map = "Valguero Topographic Map.jpg"
    elseif map == 'Genesis: Part 1' then map = 'Genesis Part 1 Topographic Map.jpg'
    elseif map == "Crystal Isles" then map = "Crystal Isles Topographic Map.jpg"
    elseif map == 'Genesis: Part 2' then map = 'Genesis Part 2 Map.jpg'
    elseif map == 'Lost Island' then map = 'Lost Island Topographic Map.jpg'
    elseif map == 'Fjordur' then map = 'Fjordur Topographic Map.jpg'
    elseif map == 'Fjordur Midgard' then map = 'Fjordur Topographic Map.jpg'
    elseif map == 'Fjordur Asgard' then map = 'Fjordur Asgard Topographic Map.jpg'
    elseif map == 'Fjordur Jotunheim' then map = 'Fjordur Jotunheim Topographic Map.jpg'
    elseif map == 'Fjordur Vanaheim' then map = 'Fjordur Vanaheim Topographic Map.jpg'
    end
  end
  -- use the default borders of the chosen map
  if map == 'The Island Topographic Map.jpg' then
    borderCoords = {t=7.2,r=92.8,b=92.8,l=7.2}
  elseif map == 'The Center Topographic Map.jpg' then
    borderCoords = {t=-2.5,r=104.5,b=101.0,l=1.0}
  elseif map == 'The Center Map.jpg' then
    borderCoords = {t=-7.5,r=108.1,b=106.7,l=-3.9}
  elseif map == 'Scorched Earth Topographic Map.jpg' then
    borderCoords = {t=7.2,r=92.8,b=92.8,l=7.2}
  elseif map == 'Ragnarok Topographic Map.jpg' then
    borderCoords = {t=11,r=89,b=89,l=11}
  elseif map == 'Ragnarok Ocean Topographic Map.jpg' then
    borderCoords = {t=-2.6,r=102.4,b=102.4,l=-2.6}
  elseif map == 'Ragnarok Map.png' then
    borderCoords = {t=0.0,r=100.0,b=100.0,l=0.0}
  elseif map == 'Aberration Topographic Map.jpg' then
    borderCoords = {t=7.2,r=92.8,b=92.8,l=7.2}
  elseif map == 'Extinction Topographic Map.jpg' then
    borderCoords = {t=7.2,r=92.8,b=92.8,l=7.2}
  elseif map == 'Crystal Isles Topographic Map.jpg' then
    -- [ 10.5, 14 ],
    -- [ 86  , 87 ],
    borderCoords = {t=10.5,r=87,b=86,l=14}
  elseif map == 'Genesis: Part 1 Topographic Map.jpg' then
    borderCoords = {t=11.5,r=88.5,b=88.5,l=11.5}
  elseif map == 'Fjordur Asgard Topographic Map.jpg' then
    -- [ 17.47, 5.11  ],
    -- [ 68.93, 56.57 ],
    borderCoords = {t=17.47,r=56.57,b=68.93,l=5.11}
  elseif map == 'Fjordur Jotunheim Topographic Map.jpg' then
    -- [ 54.48, 21.35 ],
    -- [ 97.36, 64.23 ]
    borderCoords = {t=54.48,r=64.23,b=97.36,l=21.35}
  elseif map == 'Fjordur Vanaheim Topographic Map.jpg' then
    -- [ -9.15, 62.5 ],
    -- [ 33.73, 105.38 ]
    borderCoords = {t=-9.15,r=105.38,b=33.73,l=62.5}
  end
  return map, borderCoords
end

-- lat, lon, markersize, markercolor, markertext, markericon(s)
local function decodMarker(l)
  local parts = {}
  for part in string.gmatch(l..',', "([^,]*),") do -- split avec la , comme séparteur
    table.insert(parts,part:match("^%s*(.-)%s*\n*$")) -- trim espace + retour chariot
  end
  local marker = {}
  marker.lat = parts[1]
  marker.lon = parts[2]
  if #parts > 2 and string.len(parts[3])>0 then -- markersize
    marker.ms = parts[3]
  else
    marker.ms = 10
  end
  if #parts > 3 and string.len(parts[4])>0 then -- markercolor
    marker.mc = parts[4]
  else
    marker.mc = 'red'
  end
  if #parts > 4 and string.len(parts[5])>0 then -- markertext
    marker.mt = parts[5]
  end
  local i=5
  if #parts > 5 then
    marker.mis = {}
    while #parts > i do
      marker.mis[i-4] = parts[i+1]
      i = i + 1
    end
  end
  return marker
end

local function buildMarkerCircle(mapsize, borderCoords, lat, lon, ms, mc, opacity, bc, mt)
  return '<div style="position:absolute;line-height:0;left:'.. 100*((lon-borderCoords.l)/(borderCoords.r-borderCoords.l) - ms/(2*mapsize)) ..'%;top:'.. 100*((lat-borderCoords.t)/(borderCoords.b-borderCoords.t) - ms/(2*mapsize)) ..'%;padding:0;width:'..ms..'px;height:'..ms..'px;border-radius:50%;background-color:'..mc..';border:1px solid '..bc..';opacity:'..opacity..'" title="'..mt..'"></div>'
end

local function buildMarkerIcon(mapsize, borderCoords, lat, lon, ms, opacity, mt, mis)
  return '<div style="position:absolute;line-height:0;left:'.. 100*((lon-borderCoords.l)/(borderCoords.r-borderCoords.l) - ms/(2*mapsize)) ..'%;top:'.. 100*((lat-borderCoords.t)/(borderCoords.b-borderCoords.t) - ms/(2*mapsize)) ..'%;padding:0;opacity:'..opacity..'" title="'..mt..'"><div style="position:absolute">[[File:'..table.concat(mis,'|'..ms..'px]]</div><div style="position:absolute">[[File:')..'|'..ms..'px]]</div></div>'
end

--[[
maplocations

Cette fonction convertie les données pour la classe HTML 'mapLocations'

Usage :
{{#invoke: MapLocations | maplocations}}

Paramètres :
	ensemble de paramètres
	voir le modèle 'Arkitexure map'
]]
function p.maplocations( f )
  local args = f:getParent().args
  -- set default values (borderCoords are for top, right, bottom, left)
  local map, borderCoords, mapsize, markersize, markercolor, markericon, opacity, text, float = 'The Island Topographic Map.jpg', {t=0,r=100,b=100,l=0}, 300, 10, '#f40','', 1, '', ''

  -- get values from parameters
  if args.map ~= nil then
    map, borderCoords = processMap(args.map)
  end
  if args.mapsize ~= nil then
    mapsize = args.mapsize
  end
  if args.markersize ~= nil and tonumber(args.markersize) ~= nil and tonumber(args.markersize) >= 0 then
    markersize = tonumber(args.markersize)
  end
  if args.markercolor ~= nil and type(args.markercolor) == "string" and #args.markercolor > 0 then
    markercolor = args.markercolor
  end
  if args.markericon ~= nil then
    markericon = args.markericon
  end
  if args.opacity ~= nil then
    opacity = args.opacity
  end
  if args.text ~= nil then
    text = args.text
  end
  if args.float ~= nil then
    float = args.float
  end
  if args.borderCoordT ~= nil then
    borderCoords.t = args.borderCoordT
  end
  if args.borderCoordR ~= nil then
    borderCoords.r = args.borderCoordR
  end
  if args.borderCoordB ~= nil then
    borderCoords.b = args.borderCoordB
  end
  if args.borderCoordL ~= nil then
    borderCoords.l = args.borderCoordL
  end

  -- variables for a single marker: lat, lon, ms (markersize), mc (markercolor), mt (markertext/title/tooltip), mis (markericons)
  local locations, lat, lon, ms, mc, mt, mis = {}, 0, 0, 0, '','', {}
  for _,l in ipairs(args) do
    ms = markersize
    mc = markercolor
    mis = {}
    mis[1] = markericon
    local parts,i = {},0
    for part in string.gmatch(l..',', "([^,]*),") do
      table.insert(parts,part:match "^%s*(.-)%s*$")
    end

    if #parts > 1 then
      lat = parts[1]
      lon = parts[2]
      mt = 'lat '..lat..', lon '..lon
      if #parts > 2 and string.len(parts[3])>0 then
        ms = parts[3]
        parts[3] = nil
      end
      if #parts > 3 and string.len(parts[4])>0 then
        mc = parts[4]
      end
      if #parts > 4 and string.len(parts[5])>0 then
        mt = parts[5]..'&#010;'..mt -- mt = parts[5] + \n + mt
      end
      i=5
      while #parts > i do
        mis[i-4] = parts[i+1]
        i = i + 1
      end
      if #mis > 0 and string.len(mis[1]) > 0 then
        table.insert(locations,buildMarkerIcon(mapsize, borderCoords, lat, lon, ms, opacity, mt, mis))
      else
        table.insert(locations,buildMarkerCircle(mapsize, borderCoords, lat, lon, ms, mc, opacity, 'black', mt))
      end
    end
  end
  local subtitle = ''
  if text ~= '' then
    subtitle = '\n|-\n| align="middle" | '..text
  end
  return '{| class="mapLocations" style="float:'..float..'"\n|-\n|<div class="noviewer" style="position: relative;width:'..mapsize..'px;height:'..mapsize..'px">'..table.concat(locations)..'[[File:'..map..'|'..mapsize..'px]]</div>'..subtitle..'\n|}'
end

local function trim(s)
	return s:match'^()%s*$' and '' or s:match'^%s*(.*%S)'
end

local function split(s)
	local ret = {}
	for v in string.gmatch(s, "([^,]*),?") do
		table.insert(ret, v)
	end
	return ret
end

--[[
buildMarkerPosStr

Cette fonction convertie la chaine d'entrée au format '<lat>, <lon>, ...' en 'Lat <lat>°, Lon <lon>°'

Usage :
{{#invoke:MapLocations|buildMarkerPosStr|string}}

]]
function p.buildMarkerPosStr(frame)
	local txt = frame.args[1]
	if not txt or txt == "" then
		return ""
	end
	-- '<lat>, <lon>' en 'Lat <lat>&deg;, Lon <lon>&deg;'
	-- possible input is the marker string for maplocations: '<lat>, <lon>, <ms>, <mc>, <mt>, <mis>'
	local pos = {}
	local items = split(txt)
	for k, v in pairs(items) do
		if k < 3 then
			v = trim(v)
			table.insert(pos, v)
		end
	end
	return string.format("Lat %s&deg;, Lon %s&deg;", pos[1], pos[2])
end

--[[
buildMarkerLabel

Cette fonction convertie la chaine d'entrée au format '<lat>, <lon>, <ms>, <mc>, <mt>, <mis>' en '<mc><mt>' ou '<mis><mt>'

Usage :
{{#invoke:MapLocations|buildMarkerLabel|string}}

]]
function p.buildMarkerLabel(frame)
	local txt = frame.args[1]
	if not txt or txt == "" then
		return ""
	end
	-- possible input is the marker string for maplocations: '<lat>, <lon>, <ms>, <mc>, <mt>, <mis>'
	-- output '<mc><mt>' or  output '<mis><mt>'
	local mt, mc, ms, mis
	local items = split(txt)
	for k, v in pairs(items) do
		if k == 3 then
			ms = trim(v)
			if #ms == 0 then
				ms = nil
			end
		elseif k == 4 then
			mc = trim(v)
			if #mc == 0 then
				mc = nil
			end
		elseif k == 5 then
			mt = trim(v)
			if #mt == 0 then
				mt = nil
			end
		elseif k == 6 then
			mis = trim(v)
			if #mis== 0 then
				mis = nil
			end
		end
	end
	if ms == nil then
		ms = '10'
	end
	local output = ""
	if mis ~= nil then
		output = string.format('[[File:%s|%spx]]&nbsp;&ensp;', mis, ms)
	elseif mc ~= nil then
		output = string.format('<div style="{{#var:dotstyle}}; background-color:%s;"></div>&nbsp;&ensp;', mc)
	end
	if mt == nil then
		mt = "Localisation"
	end
	return output .. mt
end

-- Supprime "Lieux d'apparition:" ou "Apparition: "
local function filterSpawnName(label)
  local str = string.gsub(label, "Lieux d'apparition: ", '')
  if str == label then
    str = string.gsub(label, "Apparition: ", '')
  end
  return str
end

local function extractSubMapName(map_name)
  -- Fjordur Asgard => {Fjordur, Asgard}
  local idx = string.find(map_name, ' ')
  if idx ~= nil then
    return string.sub(map_name, 1, idx-1), string.sub(map_name, idx+1)
  end
  return nil
end

-- Table des définitons des groupes normés
local global_groups_def
local function getObeliskList(map_name, titans)
  local result = {}
  local obelisk_title = mw.title.new('Donnée:Cartes/Obélisques '..map_name)
  if obelisk_title.exists == true then
    local obelisk_table = mw.text.jsonDecode(obelisk_title:getContent())
    for group, location in pairs(obelisk_table.markers) do
      local odef = global_groups_def[group]
      if odef ~= nil then
        -- test si marqueur ou icon
        local bc, mt, icon
        local mc = odef['fillColor']
        if mc then
          bc = odef['borderColor']
        else -- titan
          icon = odef['icon']
        end
        mt = odef['name']
        if icon == nil or titans then -- si icon alors seulement si titans autorisés
          for _, pos in pairs(location) do
            local obitem = { fill = mc, border = bc, name = mt, pos = pos, icon = {icon}}
            table.insert(result,obitem)
          end
        end
      end
    end
  end
  return result
end

--[[
mapPlayerSpawnLocations

Cette fonction affiche les marqueurs d'un fichier de donnée d'arrivée de joueur en json (Donnée:Cartes/ApparitionJoueur <map>)

Usage :
{{#invoke:MapLocations|mapPlayerSpawnLocations
|map=<map name>      for example map=The Island
|mapsize=<size>      for example mapsize=550
|maptopo=<true/false>
|no_obelisk=<true/false>
|PlayerTeleport=<true/false>
}}

]]
function p.mapPlayerSpawnLocations(frame)
  -- process map
  local subtitle = ''
  local maptopo = false
  if frame.args.maptopo == "true" then
    maptopo = true
  end
  local map_name = frame.args.map
  local map, borderCoords = processMap(map_name, not maptopo)
  map_name = string.gsub(map_name, ':', '')
  local ms = 10
  local mapsize = 200
  if frame.args.mapsize ~= nil then
   	mapsize = frame.args.mapsize
  end
  -- Chargement des définitons des groupes normés
  global_groups_def = mw.text.jsonDecode(mw.title.new('Donnée:Cartes/Définitions des groupes normés'):getContent()).groups
  local locations = {}
  -- read obelisk locations
  local no_obelisk = false
  if frame.args.no_obelisk == "true" then
    no_obelisk = true
  end
  if no_obelisk == false then
    local obelisk_list = getObeliskList(map_name)
    for _, obelisk in ipairs(obelisk_list) do
      table.insert(locations,buildMarkerCircle(mapsize, borderCoords, obelisk.pos.lat, obelisk.pos.lon, 20, obelisk.fill, 1, obelisk.border, obelisk.name))
    end
  end
  if frame.args.PlayerTeleport == "true" then
    -- read PlayerTeleport (Fjordur)
    local base_map_name, playerTeleport = extractSubMapName(map_name)
    local table_data = mw.text.jsonDecode(mw.title.new('Donnée:Cartes/Exploration/'..base_map_name..' ('..playerTeleport..')'):getContent())
    for group, marker_list in pairs(table_data.markers) do
      if string.find(group, 'obelisk-') ~= nil then
        local group_info = table_data.groups[group] or global_groups_def[group]
        if group_info ~= nil then
          local mc = group_info.fillColor
          local bc = group_info.borderColor or '#fff'
          for _, pos in pairs(marker_list) do
            local mt = string.format("lat %3.1f, lon %3.1f %s", pos.lat, pos.lon, filterSpawnName(group_info.name))
            table.insert(locations,buildMarkerCircle(mapsize, borderCoords, pos.lat, pos.lon, 20, mc, 1, bc, mt))  
          end
        end
      elseif string.find(group, 'PlayerTeleport') ~= nil then
        local group_info = table_data.groups[group]
        if group_info ~= nil then
          local mc = group_info.fillColor
          local bc = group_info.borderColor or '#fff'
          for _, pos in pairs(marker_list) do
            local mt = string.format("lat %3.1f, lon %3.1f %s", pos.lat, pos.lon, filterSpawnName(group_info.name))
            table.insert(locations,buildMarkerCircle(mapsize, borderCoords, pos.lat, pos.lon, ms, mc, 1, bc, mt))  
          end
        end
      end
    end
  else
    -- read ApparitionJoueur
    local table_data = mw.text.jsonDecode(mw.title.new('Donnée:Cartes/ApparitionJoueur '..map_name):getContent())
    for group, spawns in pairs(table_data.markers) do
      local group_info = table_data.groups[group]
      local mc = group_info.fillColor
      local bc = group_info.borderColor
      for _, pos in pairs(spawns) do
        local mt = string.format("lat %3.1f, lon %3.1f %s", pos.lat, pos.lon, filterSpawnName(group_info.name))
        table.insert(locations,buildMarkerCircle(mapsize, borderCoords, pos.lat, pos.lon, ms, mc, 1, bc, mt))
      end
    end
  end
  local float = ''
	return '{| class="mapLocations" style="float:'..float..'"\n|-\n|<div class="noviewer" style="position: relative;width:'..mapsize..'px;height:'..mapsize..'px">'..table.concat(locations)..'[[File:'..map..'|'..mapsize..'px]]</div>'..subtitle..'\n|}'
end

--[[
mapPlayerSpawnRegions

Cette fonction affiche la liste des régions d'arrivée à partir d'un fichier de donnée d'arrivée de joueur en json (Donnée:Cartes/ApparitionJoueur <map>)

Usage :
{{#invoke:MapLocations|mapPlayerSpawnRegions|map}}

]]
function p.mapPlayerSpawnRegions(frame)
  local map_name = string.gsub(frame.args.map, ':', '')
  local table_data = json_ordered.decode(mw.title.new('Donnée:Cartes/ApparitionJoueur ' .. map_name):getContent())
  local region_list = {'{| cellpadding="3"'}
  for group, group_info in pairs(table_data.groups) do
    local color = group_info.fillColor
    table.insert(region_list, '|-\n| <div style="display:inline-block; padding:0; width:15px; height:15px; margin:-3px; border-radius:50%; background-color:' .. color .. ';border:1px solid black;"></div>\n| ' .. filterSpawnName(group_info.name))
  end
  table.insert(region_list, '|}')
  return table.concat(region_list, '\n')
end

--[[
mapObeliskLocations

Cette fonction affiche les Obélisques à partir d'un fichier de donnée d'Obélisque en json (Donnée:Cartes/Obélisques <map>)

Usage :
{{#invoke:MapLocations|mapObeliskLocations
|map=<map name>      exemple: map=The Island
|mapsize=<size>      exemple: mapsize=550
|maptopo=<true/false>
|titans=<true/false> pour Extinction
|<marker>            même syntaxe qu'avec location
}}

]]
function p.mapObeliskLocations(frame)
  -- process map
  local subtitle = ''
  local maptopo = false
  if frame.args.maptopo == "true" then
    maptopo = true
  end
  local titans = false
  if frame.args.titans == "true" then
    titans = true
  end
  local map_name = frame.args.map
  local map, borderCoords = processMap(map_name, not maptopo)
  map_name = string.gsub(map_name, ':', '')
  local ms = 10
  local mapsize = 200
  if frame.args.mapsize ~= nil then
   	mapsize = frame.args.mapsize
  end
  -- Chargement des définitons des groupes normés
  global_groups_def = mw.text.jsonDecode(mw.title.new('Donnée:Cartes/Définitions des groupes normés'):getContent()).groups
  local locations = {}
  local obelisk_list = getObeliskList(map_name, titans)
  for _, obelisk in ipairs(obelisk_list) do
    local mt = string.format("%s&#010;lat %3.1f, lon %3.1f", filterSpawnName(obelisk.name), obelisk.pos.lat, obelisk.pos.lon)
    if obelisk.fill then
      table.insert(locations,buildMarkerCircle(mapsize, borderCoords, obelisk.pos.lat, obelisk.pos.lon, 20, obelisk.fill, 1, obelisk.border, mt))
    else
      table.insert(locations,buildMarkerIcon(mapsize, borderCoords, obelisk.pos.lat, obelisk.pos.lon, 35, 1, mt, obelisk.icon))
    end
  end
  -- décodage liste des marqueurs
  for _,l in ipairs(frame.args) do
    local marker = decodMarker(l)
    local mt = ""
    if marker.mt then
    	mt = string.format("%s&#010;lat %3.1f, lon %3.1f", marker.mt, marker.lat, marker.lon)
    else
    	mt = string.format("lat %3.1f, lon %3.1f", marker.lat, marker.lon)
    end
    if marker.mis then
      table.insert(locations,buildMarkerIcon(mapsize, borderCoords, marker.lat, marker.lon, marker.ms, 1, mt, marker.mis))
    else
      table.insert(locations,buildMarkerCircle(mapsize, borderCoords, marker.lat, marker.lon, marker.ms, marker.mc, 1, 'black', mt))
    end
  end
  local float = ''
  return '{| class="mapLocations" style="float:'..float..'"\n|-\n|<div class="noviewer" style="position: relative;width:'..mapsize..'px;height:'..mapsize..'px">'..table.concat(locations)..'[[File:'..map..'|'..mapsize..'px]]</div>'..subtitle..'\n|}'
end

return p