Module:Localisations

De Poképédia
Aller à la navigation Aller à la recherche

Fonction « pokemon »[modifier]

Cette fonction sert à générer automatiquement un tableau de localisations pour les Pokémon.

Comment ça fonctionne ?[modifier]

Dans les pages de lieux, comme Carmin sur Mer ou Route 204, sont définis des tableaux de rencontre, à l'aide du Module:Tableau Pokémon. Ces données, en plus de renseigner les Pokémon disponibles dans le lieu, peuvent ensuite être agrégées automatiquement par un outil externe. Cet outil permet de mettre à jour une base de données de localisations, disponible ici.

Comment modifier un tableau de localisations ?[modifier]

Pour plus d'informations sur le sujet, référez-vous à cette page.

S'il y a une erreur ou une information manquante dans un tableau de localisations sur la page d'un Pokémon, c'est que l'erreur est aussi présente dans la page du lieu correspondant. Dans ce cas, il est nécessaire de modifier la page du lieu en question, ce qui mettra à jour les bases de données (et donc les tableaux de localisations) avec les informations corrigées ou ajoutées au prochain passage de l'outil externe qui les remplit. Dans tous les cas, les bases de données évoquées dans la section précédente n'ont pas vocation à être manuellement modifiées. Pour plus d'informations, consulter cette page, ou contacter Matt.(d).

Paramètres[modifier]

Légende des icônes
Certains paramètres sont accompagnés d'une ou plusieurs icône indiquant leur(s) caractéristique(s) :
 : Ce paramètre est facultatif, et n'a donc pas besoin d'être systématiquement défini.
 : Ce paramètre classe automatiquement l'article dans une catégorie.
 : Ce paramètre influe sur les données sémantiques présentes en pied de page.
  • paramètre non nommé  : permet de forcer le nom du Pokémon à partir duquel former le tableau. Par défaut, le nom est réglé sur celui de la page en cours ({{PAGENAME}}).
  • type  : la couleur de fond du tableau. Par défaut, elle est égale à la couleur du premier type du Pokémon.
  • ids  : permet de spécifier un ou plusieurs identifiants, séparés par un slash entouré d'espaces  / . Les identifiants sont ceux utilisés dans les tableaux pour préciser des formes spécifiques, au sens du Module:Ressources/infosPokemon. Par exemple, pour afficher les localisations de Sancoki, on pourra indiquer ids=Sancoki forme(Occident) nom(Mer Occident) / Sancoki forme(Orient) nom(Mer Orient). Pour savoir les identifiants utilisés dans un jeu, utiliser la fonction pokeliste.
  • génération  : permet de définir une génération pour les jeux indiqués. Par défaut, la génération est 8. Sur les pages du type "XXX/Génération Y", la génération par défaut est Y. Indiquer génération=toutes permet d'afficher toutes les générations dans un seul tableau, même si cette option n'a pas vocation à figurer dans des articles.

Exemples d'utilisation[modifier]

Exemple général[modifier]

{{#invoke:Localisations|pokemon}}

sur la page « Étourmi/Génération 4 » donne :

VersionsLocalisationsDétails
Diamant et PerleRoute 201, Route 202, Route 203, Route 204, Route 209, Route 212, Grand Marais, Lac Vérité
PlatineRoute 201, Route 202, Route 203, Route 204, Lac Vérité
Or HeartGold et Argent SoulSilverArgenta
Ce tableau est généré automatiquement. Pour que son contenu soit modifié, il faut modifier les pages de lieux. Informations détaillées sur cette page.
LieuNiveauTaux
Pokémon Diamant et Perle
MatinJourNuit
Route 201 – Hautes herbes2–350 %50 %40 %
Route 201 – En insérant Vert Feuille24 %
Route 201 – En insérant Rubis24 %
Route 201 – En insérant Saphir24 %
Route 201 – En insérant Émeraude24 %
Route 202 – Hautes herbes330 %40 %30 %
Route 203 – Hautes herbes4–635 %45 %35 %
Route 204 (zone sud) – Hautes herbes425 %35 %25 %
Route 204 (zone nord) – Hautes herbes625 %35 %25 %
Route 209 – Hautes herbes1620 %
Route 212 (partie nord) – Hautes herbes1620 %
Grand Marais (Pokémon apparaissant tous les jours) – Hautes herbes22–2610 %10 %
Lac Vérité – Hautes herbes2–450 %50 %40 %
LieuNiveauTaux
Pokémon Platine
MatinJourNuit
Route 201 – Hautes herbes2–350 %50 %40 %
Route 202 – Hautes herbes2–320 %30 %20 %
Route 203 – Hautes herbes4–725 %
Route 203 – Hautes herbes510 %10 %
Route 204 (zone nord) – Hautes herbes9–1125 %
Route 204 (zone sud) – Hautes herbes4–625 %
Lac Vérité – Hautes herbes2–450 %
LieuNiveauTaux
Pokémon Or HeartGold et Argent SoulSilver
Argenta – Coup d'Boule (arbres isolés près de la Route 2)VariableVariable

Exemple avec des identifiants[modifier]

Pour afficher toutes les formes de Vivaldaim dans un même tableau :

{{#invoke:Localisations|pokemon|ids=Vivaldaim / Vivaldaim forme(Printemps) / Vivaldaim forme(Été) / Vivaldaim forme(Automne) / Vivaldaim forme(Hiver)}}

sur la page « Vivadaim/Génération 5 » donne :

VersionsLocalisationsDétails
Noir et BlancRoute 6, Route 7, Tour Dragospire
Noir 2 et Blanc 2Route 6, Route 7
Ce tableau est généré automatiquement. Pour que son contenu soit modifié, il faut modifier les pages de lieux. Informations détaillées sur cette page.
FormeLieuNiveauTaux
Pokémon Noir et Blanc
PrintempsÉtéAutomneHiver
Vivaldaim (Forme Printemps)Route 6 – Hautes herbes22–2435 %
Vivaldaim (Forme Printemps)Route 6 – Herbes sombres26–2835 %
Vivaldaim (Forme Été)Route 6 – Hautes herbes22–2435 %
Vivaldaim (Forme Été)Route 6 – Herbes sombres26–2835 %
Vivaldaim (Forme Automne)Route 6 – Hautes herbes22–2435 %
Vivaldaim (Forme Automne)Route 6 – Herbes sombres26–2835 %
Vivaldaim (Forme Hiver)Route 6 – Hautes herbes22–2435 %
Vivaldaim (Forme Hiver)Route 6 – Herbes sombres26–2835 %
Vivaldaim (Forme Été)Route 7 – Longues herbes2620 %
Vivaldaim (Forme Été)Route 7 – Longues herbes sombres30–3220 %
Vivaldaim (Forme Printemps)Route 7 – Longues herbes2620 %
Vivaldaim (Forme Printemps)Route 7 – Longues herbes sombres30–3220 %
Vivaldaim (Forme Hiver)Route 7 – Longues herbes2620 %
Vivaldaim (Forme Hiver)Route 7 – Longues herbes sombres30–3220 %
Vivaldaim (Forme Automne)Route 7 – Longues herbes2620 %
Vivaldaim (Forme Automne)Route 7 – Longues herbes sombres30–3220 %
Vivaldaim (Forme Hiver)Tour Dragospire (entrée) – Hautes herbes30–3330 %
Vivaldaim (Forme Automne)Tour Dragospire (entrée) – Hautes herbes30–3330 %
Vivaldaim (Forme Printemps)Tour Dragospire (entrée) – Hautes herbes30–3330 %
Vivaldaim (Forme Été)Tour Dragospire (entrée) – Hautes herbes30–3330 %
Vivaldaim (Forme Printemps)Tour Dragospire (extérieur) – Hautes herbes31–3230 %
Vivaldaim (Forme Hiver)Tour Dragospire (extérieur) – Hautes herbes31–3230 %
Vivaldaim (Forme Automne)Tour Dragospire (extérieur) – Hautes herbes31–3230 %
Vivaldaim (Forme Été)Tour Dragospire (extérieur) – Hautes herbes31–3230 %
FormeLieuNiveauTaux
Pokémon Noir 2 et Blanc 2
PrintempsÉtéAutomneHiver
Vivaldaim (Forme Hiver)Route 6 – Hautes herbes23–2530 %
Vivaldaim (Forme Hiver)Route 6 – Herbes sombres26–2830 %
Vivaldaim (Forme Été)Route 6 – Hautes herbes23–2530 %
Vivaldaim (Forme Été)Route 6 – Herbes sombres26–2830 %
Vivaldaim (Forme Automne)Route 6 – Hautes herbes23–2530 %
Vivaldaim (Forme Automne)Route 6 – Herbes sombres26–2830 %
Vivaldaim (Forme Printemps)Route 6 – Hautes herbes23–2530 %
Vivaldaim (Forme Printemps)Route 6 – Herbes sombres26–2830 %
Vivaldaim (Forme Automne)Route 7 – Longues herbes3020 %
Vivaldaim (Forme Automne)Route 7 – Longues herbes sombres3320 %
Vivaldaim (Forme Été)Route 7 – Longues herbes3020 %
Vivaldaim (Forme Été)Route 7 – Longues herbes sombres3320 %
Vivaldaim (Forme Printemps)Route 7 – Longues herbes3020 %
Vivaldaim (Forme Printemps)Route 7 – Longues herbes sombres3320 %
Vivaldaim (Forme Hiver)Route 7 – Longues herbes3020 %
Vivaldaim (Forme Hiver)Route 7 – Longues herbes sombres3320 %

Utiliser la fonction pokeliste pour savoir quels identifiants utiliser.

Fonction « pokeliste »[modifier]

Cette fonction renvoie un tableau triable, qui sert à donner un point de vue global des Pokémon trouvables directement dans un certain jeu. Elle n'a pas vocation à être utilisée directement dans les articles, mais plutôt à se rendre compte des identifiants utilisés, au sens du Module:Ressources/infosPokemon.

Paramètres[modifier]

  • jeu : l'abréviation du jeu dont on souhaite voir la liste des Pokémon trouvables.

Exemple d'utilisation[modifier]

{{#invoke:Localisations|pokeliste|jeu=J}}

donne :

infosPokemonPokémonLieux
0142 PtéraPtéraLaboratoire de Cramois'Île
0037 GoupixGoupixCasino de Céladopole
0120 StariStariChenal 20, Bourg Palette, Îles Écume, Chenal 19, Carmin sur Mer, Chenal 21, Cramois'Île
0075 GravalanchGravalanchCaverne Azurée, Route Victoire
0080 FlagadossFlagadossÎles Écume
0040 GrodoudouGrodoudouCasino de Céladopole
0118 PoissirènePoissirèneRoute 11, Parc Safari, Chenal 20, Caverne Azurée, Route 23, Route 22, Parc Safari, Route 25, Bourg Palette, Arène d'Azuria, Îles Écume, Jadielle, Parc Safari, Chenal 19, Carmin sur Mer, Route 18, Chenal 21, Route 10, Route 6, Route 24, Azuria, Cramois'Île, Route 17, Route 13, Route 12, Parc Safari, Céladopole, Parmanie
0113 LeveinardLeveinardParc Safari, Caverne Azurée, Parc Safari
0044 OrtideOrtideCaverne Azurée, Route 14, Route 15, Route 13, Route 12
0063 AbraAbraRoute 7, Route 5, Casino de Céladopole, Route 6, Route 8
0043 MystherbeMystherbeRoute 25, Route 14, Route 24, Route 15, Route 13, Route 12
0128 TaurosTaurosParc Safari, Parc Safari
0056 FérosingeFérosingeRoute 23, Route 3, Route 22, Route 4
0088 TadmorvTadmorvManoir Pokémon, Centrale abandonnée
0137 PorygonPorygonCasino de Céladopole
0133 ÉvoliÉvoliRésidence Céladon
0123 InsécateurInsécateurParc Safari, Parc Safari, Casino de Céladopole
0112 RhinoférosRhinoférosCaverne Azurée, Laboratoire de Cramois'Île
0035 MéloféeMéloféeMont Sélénite
0020 RattatacRattatacRoute 11, Route 16, Manoir Pokémon, Route 9, Route 18, Chenal 21, Route 10
0032 Nidoran♂Nidoran♂Parc Safari, Route 22, Parc Safari, Route 2, Parc Safari, Route 9, Route 10, Parc Safari
0111 RhinocorneRhinocorneCaverne Azurée, Parc Safari, Parc Safari
0130 LéviatorLéviatorParmanie
0061 TêtarteTêtarteRoute 23, Route 22
0104 OsselaitOsselaitParc Safari, Parc Safari, Tour Pokémon, Parc Safari
0114 SaquedeneuSaquedeneuParc Safari, Parc Safari
0100 VoltorbeVoltorbeCentrale abandonnée
0079 RamolossRamolossÎles Écume
0046 ParasParasParc Safari, Mont Sélénite
0101 ÉlectrodeÉlectrodeCentrale abandonnée
0066 MachocMachocGrotte Sombre, Route 10
0122 M. MimeM. MimeRoute 2
0145 ÉlecthorÉlecthorCentrale abandonnée
0116 HypotrempeHypotrempeRoute 11, Carmin sur Mer, Route 10, Route 13, Route 12
0117 HypocéanHypocéanRoute 13, Route 12
0083 CanartichoCanartichoRoute 13, Route 12
0042 NosferaltoNosferaltoCaverne Azurée, Îles Écume, Route Victoire
0147 MinidracoMinidracoParc Safari, Parc Safari, Parc Safari, Parc Safari
0105 OssatueurOssatueurParc Safari, Tour Pokémon, Parc Safari
0085 DodrioDodrioRoute 17
0064 KadabraKadabraRoute 8
0148 DracoDracoParc Safari
0047 ParasectParasectCaverne Azurée, Parc Safari, Route 18
0074 RacaillouRacaillouGrotte Sombre, Route Victoire, Mont Sélénite
0057 ColossingeColossingeRoute 23
0143 RonflexRonflexRoute 16, Route 12
0030 NidorinaNidorinaParc Safari, Route 23, Parc Safari, Route 9
0119 PoissoroyPoissoroyCaverne Azurée, Route 24, Azuria
0069 ChétiflorChétiflorRoute 25, Route 14, Route 24, Route 15, Route 13, Route 12
0102 NoeunoeufNoeunoeufParc Safari, Parc Safari, Parc Safari, Parc Safari
0144 ArtikodinArtikodinÎles Écume
0098 KrabbyKrabbyRoute 25, Îles Écume, Route 10
0028 SablaireauSablaireauCaverne Azurée
0086 OtariaOtariaÎles Écume
0025 PikachuPikachuLaboratoire Pokémon du Professeur Chen
0131 LokhlassLokhlassSylphe SARL
0050 TaupiqueurTaupiqueurGrotte Taupiqueur
0151 MewMewRoute 24
0055 AkwakwakAkwakwakRoute 6
0054 PsykokwakPsykokwakRoute 6
0010 ChenipanChenipanForêt de Jade
0081 MagnétiMagnétiRoute 10, Centrale abandonnée
0073 TentacruelTentacruelChenal 20, Chenal 19, Chenal 21
0108 ExcelangueExcelangueCaverne Azurée
0089 GrotadmorvGrotadmorvLaboratoire de Cramois'Île, Manoir Pokémon, Centrale abandonnée
0146 SulfuraSulfuraRoute Victoire
0048 MimitossMimitossRoute 25, Route 14, Route 24, Route 15
0093 SpectrumSpectrumTour Pokémon
0106 KickleeKickleeDojo de Safrania
0049 AéromiteAéromiteCaverne Azurée, Route 14, Route 15
0140 KabutoKabutoLaboratoire de Cramois'Île
0092 FantominusFantominusTour Pokémon
0027 SabeletteSabeletteRoute 3, Route 4, Mont Sélénite
0090 KokiyasKokiyasCarmin sur Mer, Route 18, Route 17
0041 NosferaptiNosferaptiGrotte Sombre, Îles Écume, Route Victoire, Mont Sélénite
0138 AmonitaAmonitaLaboratoire de Cramois'Île
0051 TriopikeurTriopikeurRoute 11, Grotte Taupiqueur
0060 PtitardPtitardRoute 11, Parc Safari, Chenal 20, Caverne Azurée, Route 23, Route 22, Parc Safari, Route 25, Bourg Palette, Arène d'Azuria, Îles Écume, Jadielle, Parc Safari, Chenal 19, Carmin sur Mer, Route 18, Chenal 21, Route 10, Route 6, Route 24, Azuria, Cramois'Île, Route 17, Route 13, Route 12, Parc Safari, Céladopole, Parmanie
0058 CaninosCaninosManoir Pokémon
0099 KrabbossKrabbossRoute 25, Îles Écume, Route 10
0007 CarapuceCarapuceCarmin sur Mer
0132 MétamorphMétamorphCaverne Azurée, Manoir Pokémon
0004 SalamècheSalamècheRoute 24
0021 PiafabecPiafabecRoute 16, Route 3, Route 22, Route 4, Route 9, Route 18
0001 BulbizarreBulbizarreAzuria
0077 PonytaPonytaRoute 17
0096 SoporifikSoporifikRoute 11
0115 KangourexKangourexParc Safari
0129 MagicarpeMagicarpeRoute 11, Parc Safari, Chenal 20, Caverne Azurée, Route 23, Route 22, Parc Safari, Route 25, Bourg Palette, Arène d'Azuria, Îles Écume, Jadielle, Parc Safari, Chenal 19, Carmin sur Mer, Route 4, Route 18, Chenal 21, Route 10, Route 6, Route 24, Azuria, Cramois'Île, Route 17, Route 13, Route 12, Parc Safari, Céladopole, Parmanie
0150 MewtwoMewtwoCaverne Azurée
0087 LamantineLamantineLaboratoire de Cramois'Île, Îles Écume
0072 TentacoolTentacoolRoute 11, Chenal 20, Bourg Palette, Chenal 19, Carmin sur Mer, Route 18, Chenal 21, Cramois'Île, Route 17, Route 13
0082 MagnétonMagnétonCentrale abandonnée
0084 DoduoDoduoRoute 16, Route 18, Route 17
0039 RondoudouRondoudouRoute 7, Route 5, Route 6, Route 8
0067 MachopeurMachopeurRoute 5, Route Victoire
0022 RapasdepicRapasdepicRoute 23, Route 16, Route 9, Route 18, Route 17
0029 Nidoran♀Nidoran♀Parc Safari, Route 22, Parc Safari, Route 2, Parc Safari, Route 9, Route 10, Parc Safari
0019 RattataRattataRoute 7, Route 11, Route 16, Route 3, Route 22, Route 5, Route 2, Manoir Pokémon, Route 4, Route 9, Route 1, Route 18, Chenal 21, Route 10, Route 6, Route 8
0017 RoucoupsRoucoupsRoute 7, Route 11, Forêt de Jade, Route 25, Route 5, Route 14, Chenal 21, Route 6, Route 24, Route 8, Route 15, Route 13, Route 12
0033 NidorinoNidorinoRoute 23, Parc Safari, Route 9, Parc Safari
0016 RoucoolRoucoolRoute 7, Route 11, Forêt de Jade, Route 25, Route 5, Route 2, Route 1, Chenal 21, Route 6, Route 24, Route 8, Route 13, Route 12
0011 ChrysacierChrysacierForêt de Jade
0095 OnixOnixGrotte Sombre, Route Victoire
0127 ScarabruteScarabruteParc Safari, Casino de Céladopole, Parc Safari
0107 TygnonTygnonDojo de Safrania
0070 BoustiflorBoustiflorCaverne Azurée, Route 14, Route 15, Route 13, Route 12

local p = {}
local ressources = {
	["infosPokemon"] = require("Module:Ressources/infosPokemon")
}
local game_to_game_long = require("Module:Data/NomsJeux")
local subareas = require("Module:Localisations/sousZones")

function p.pokemon(frame)
	local maths = require("Module:Maths")

	local result = {}
	local result_header = {}
	local full_table = {}
	
	local pokemon = frame.args[1]
	local generation
	if pokemon == nil or pokemon == ""
	then pokemon = frame:getParent():getTitle()
		local title_split = mw.text.split(pokemon, "/")
		pokemon = title_split[1]	-- remove the subpages
		if title_split[2]
		then generation = mw.ustring.gsub(title_split[2], "Génération ", "")
		end
	end
	
	local pokemon_ids = frame.args["ids"]
	local multiple_ids = false
	if pokemon_ids
	then pokemon_ids = mw.text.split(pokemon_ids, " / ")
		if pokemon_ids[2] then multiple_ids = true end
	else pokemon_ids = {pokemon}
	end
	local replacement_ids = {
		[" d'Alola"] = "Alola",
		[" de Galar"] = "Galar",
		[" de Hisui"] = "Hisui",
		[" de Paldea"] = "Paldea",
		["Méga%-"] = "Méga",
		[" Gigamax"] = "Gigamax"
	}
	for i, id in pairs(pokemon_ids) do
		local j = 1
		for replacing, replaced in pairs(replacement_ids) do
			-- Les éléments entre parenthèses, notamment les liens, ne doivent pas être remplacés ;
			-- on ne remplace que ce qui est avant l'éventuelle première parenthèse
			if mw.ustring.find(pokemon_ids[i], replacing) and not(mw.ustring.find(pokemon_ids[i], "%(") and mw.ustring.find(pokemon_ids[i], replacing) > mw.ustring.find(pokemon_ids[i], "%("))
			then pokemon_ids[i] = mw.ustring.gsub(pokemon_ids[i], replacing, "") .. " forme(" .. replaced .. ")"
			end
		end
	end
	
	local pokemon_type = frame.args["type"]
	if not pokemon_type
	then local data_types = require("Module:Data/TypesPokémon")
		for replacing, replaced in pairs(replacement_ids) do
			if mw.ustring.find(pokemon, replacing)
			then local pokemon_without_form = mw.ustring.gsub(pokemon, replacing, "")
				local form = replaced
				local pokemon_types = data_types[pokemon_without_form]
				if pokemon_types
				then local pokemon_types_form = pokemon_types[form]
					if pokemon_types_form
					then pokemon_type = pokemon_types_form[1]
					else pokemon_type = pokemon_types[1][1]
					end
				else pokemon_type = ""
				end
				break
			end
		end
		if not pokemon_type
		then local pokemon_types = data_types[pokemon]
			if pokemon_types
			then pokemon_type = pokemon_types[1][1]
			else pokemon_type = ""
			end
		end
	end
	pokemon_type = mw.ustring.lower(pokemon_type)
	
	
	local generation_to_games = {
		{"RB", "J"},
		{"OA", "C"},
		{"RS", "RFVF", "E"},
		{"DP", "Pt", "HGSS"},
		{"NB", "N2B2"},
		{"XY", "ROSA"},
		{"SL", "USUL", "LGPE"},
		{"EB", "DEPS", "LPA"},
		{"EV"}
	}
	
	local games = {}
	if frame.args["génération"] then generation = frame.args["génération"] end
	if generation == "toutes"
	then
		local n = 1
		local g = 1
		while generation_to_games[g] do
			local i = 1
			local gen_games = generation_to_games[g]
			
			while gen_games[i] do
				games[n] = gen_games[i]
				n = n + 1
				i = i + 1
			end
			g = g + 1
		end
	else
		if not tonumber(generation) then generation = 8 else generation = tonumber(generation) end
		
		games = generation_to_games[generation]
		if games == nil
		then return "<i>Erreur : numéro de génération invalide.</i>"
		end
	end
	
	if frame.args["jeux"] then games = mw.text.split(frame.args["jeux"], ", ") end
	
	
	
	local borders = {}
	local game_displays = {}
	local game_links = {}
	local locdatas = {}
	for _, game in pairs(games) do
		borders[game] =  frame:expandTemplate{title='Bordure', args={game}}
		game_displays[game] = game_to_game_long[game]
		local game_link = game_to_game_long[game]
		if game ~= "LPA"
		then game_link = "Pokémon " .. game_to_game_long[game]
		end
		game_links[game] = game_link
		table.insert(locdatas, require("Module:Localisations/Données/" .. game_link))
	end
	
	
	local places = {}
	local game_id = 1
	local first_game = nil
	for _, game in pairs(games) do
		if game_id == 1 then first_game = game end
		
		local game_has_place = false
		for place_name, pokemon_list in pairs(locdatas[game_id]) do
			for _, pokemon_id in pairs(pokemon_ids) do
				local place_info = pokemon_list[pokemon_id]
				if place_info
				then table.insert(places, {["id"] = pokemon_id, ["game_id"] = game_id, ["game"] = game, ["name"] = place_name, ["contents"] = place_info})
					game_has_place = true
				end
			end
		end
		
		if not game_has_place
		then table.insert(places, {["game_id"] = game_id, ["game"] = game, ["name"] = "", ["contents"] = nil})
		end
		
		game_id = game_id + 1
	end
	
	local remove_accents = require("Module:Ressources/enleverAccents")
	table.sort(places, function(x,y)
		if x.game_id ~= y.game_id
		then return x.game_id < y.game_id
		else local x_placename = mw.text.split(mw.text.split(x.name, "@")[1], "|")[1]
			local y_placename = mw.text.split(mw.text.split(y.name, "@")[1], "|")[1]
			local x_placeid = subareas.get_subarea_id_from_place(x_placename)
			local y_placeid = subareas.get_subarea_id_from_place(y_placename)
			if x_placeid ~= y_placeid
			then return x_placeid < y_placeid
			else x_routenumber = tonumber(tostring(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(x_placename, "%(.-%).-", ""), "Route ", ""), "Chenal ", ""), "Antre ", "")))
				y_routenumber = tonumber(tostring(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(y_placename, "%(.-%).-", ""), "Route ", ""), "Chenal ", ""), "Antre ", "")))
		
				if x_routenumber
				then if y_routenumber
					then return x_routenumber < y_routenumber
					else return true
					end
				else if y_routenumber
					then return false
					else return remove_accents(x.name) < remove_accents(y.name)
					end
				end
			end
		end
	end)
	
	-- subrate precomputation
	local subrates = require("Module:Tableau Pokémon/sousTaux")

	local subarea_subrates_list = {}
	local colspan_rates = {}
	local reduced_colspan_rates = {} -- in case total colspan exceeds the 1000 limit
	local colspan_rates_decomposed = {}
	local max_rates = {}
	for _, game in pairs(games) do
		subarea_subrates_list[game] = {}
		colspan_rates[game] = 1
		reduced_colspan_rates[game] = 1
		colspan_rates_decomposed[game] = {}
		max_rates[game] = 1
	end
	
	local i = 1
	local last_place = nil
	local last_subarea = nil
	local last_game_id = nil
	local last_game = nil
	local current_subarea_has_subrates = false
	
	local rates_width = {}
	local base_rate_width = 45
	for game, _ in pairs(max_rates) do
		rates_width[game] = base_rate_width
	end
	
	function add_to_subrates(game, subarea, subarea_has_subrates)
		if subarea == nil then subarea = "" end
		
		if subarea_has_subrates
		then local subrates_subarea = subrates.raccourcis[mw.ustring.lower(subarea)]

			if subrates_subarea == nil
			then subrates_subarea = subrates[game]
			end
			
			local count = 1
			if subrates_subarea ~= nil
			then 
				while subrates_subarea[1][count + 1] do
					count = count + 1
				end
				local new_colspan_rates = maths.lcm(colspan_rates[game], count)
				colspan_rates[game] = new_colspan_rates
				table.insert(colspan_rates_decomposed[game], count)
				
				reduced_colspan_rates[game] = math.floor(colspan_rates[game] / (math.floor((new_colspan_rates - 1) / 1000) + 1))
				
				local minwidth = subrates_subarea.minwidth
				if not minwidth then minwidth = base_rate_width end
				
				rates_width[game] = math.max(rates_width[game], minwidth * count)
			end
			if not max_rates[game] or max_rates[game] < count then max_rates[game] = count end
			subarea_subrates_list[game][subarea] = {["subrates"] = subrates_subarea, ["number"] = count}
		else subarea_subrates_list[game][subarea] = {["subrates"] = nil, ["number"] = 0}
		end
	end
	
	
	-- actual subrate precomputation
	local current_game
	local current_subarea
	while places[i] do
		local current_place_id = places[i]["name"]
		local current_place_split = mw.text.split(current_place_id, "@")
		local current_place = current_place_split[1]
		local current_game_id = places[i]["game_id"]
		
		current_game = places[i]["game"]
		current_subarea = subareas.get_subarea_from_place(mw.text.split(current_place, "|")[1])
		if last_place == nil or subareas.get_subarea_id_from_place(last_place) ~= subareas.get_subarea_id_from_place(current_place) or last_game_id ~= current_game_id
		then if last_place ~= nil
			then add_to_subrates(last_game, last_subarea, current_subarea_has_subrates)
			end
			current_subarea_has_subrates = false
		end
		last_place = current_place
		last_subarea = current_subarea
		last_game = current_game
		last_game_id = current_game_id
		
		local place_info = places[i]["contents"]
		
		if place_info
		then local j = 1
			while not current_subarea_has_subrates and place_info[j] do
				if not place_info[j]["taux"]
				then current_subarea_has_subrates = true
				end
				j = j + 1
			end
		end
		i = i + 1
	end
	add_to_subrates(current_game, current_subarea, current_subarea_has_subrates)
	
	-- locations
	local current_game_locations = {}
	local current_game_locations_first_subarea = {}
	local current_game_full_locations = {}
	local current_subarea_full_locations = {}
	local seen_games_place = nil
	local number_subareas = 0
	local last_place = nil
	local current_game = nil
	local current_game_id = nil

	local last_game_id = nil
	local places_end = false
	local is_there_full_table = false
	local is_there_full_table_game = false
	local i = 1
	while true do
		last_game = current_game
		last_game_id = current_game_id
			
		if not places[i]
		then places_end = true
		else 
			current_game = places[i]["game"]
			current_game_id = places[i]["game_id"]
		end
		
		if places_end or last_game_id ~= current_game_id
		then 
			local full_table_header = {}
			
			if last_game_id ~= nil then
				-- game specifier in the simplified table, at the end of last area locations
				if last_game ~= first_game
				then table.insert(result, '</td></tr>')
				end
				table.insert(result, '<tr><td rowspan="' .. number_subareas .. '" class="' .. borders[last_game] .. '">[[' .. game_links[last_game] .. '|' .. game_displays[last_game] .. ']]</td>')
				
				-- if all encounters in the place are restricted to a single game of the two
				if seen_games_place and seen_games_place ~= "all" then table.insert(current_game_locations, frame:expandTemplate{title='Sup', args={seen_games_place}}) end
				seen_games_place = nil
				table.insert(current_game_locations, '</span></td>')
			
				if is_there_full_table_game
				then local form_header = ""
					if multiple_ids then form_header = "<th>Forme</th>" end
					table.insert(full_table_header, '<table class="tableaustandard centre ' .. pokemon_type .. '"><tbody><tr>' .. form_header
						.. '<th width="450px">Lieu</th><th width="50px">Niveau</th><th colspan="' .. reduced_colspan_rates[last_game] .. '" >Taux</th></tr>')
					
					local left_cell_colspan = 2
					if multiple_ids then left_cell_colspan = 3 end
						
					if colspan_rates[last_game] > 1
					then
						table.insert(full_table_header, '<tr><td style="padding:0px;border:0px" colspan="' .. left_cell_colspan .. '"></td>')
						local current_colspan = 0
						local factorize = reduced_colspan_rates[last_game] * 2 > rates_width[last_game]
						local is_multiple
						
						for c = 1, reduced_colspan_rates[last_game] do
							current_colspan = current_colspan + 1
							is_multiple = false
							
							local factor = 1
							if factorize
							then for _, fac in pairs(colspan_rates_decomposed[last_game]) do
									if fac ~= 1 and c % (reduced_colspan_rates[last_game] / fac) == 0
									then factor = fac
										is_multiple = true
										break
									end
								end
							end
							
							if not factorize or is_multiple
							then local colspan_text = ""
								if current_colspan ~= 1 then colspan_text = ' colspan="' .. current_colspan .. '"' end
								table.insert(full_table_header, '<td style="padding:0px;border:0px"' .. colspan_text .. '></td>')
								current_colspan = 0
							end
						end
						table.insert(full_table_header, '</tr>')
					end
					
					table.insert(full_table_header, '<tr><td colspan="' .. left_cell_colspan + reduced_colspan_rates[last_game] .. '" class="' .. borders[last_game] .. '"><b>' .. frame:expandTemplate{title='Jeu', args={last_game}} .. '</b></td></tr>')
				end
				
				table.insert(current_game_full_locations, table.concat(current_subarea_full_locations, ""))
				table.insert(full_table_header, table.concat(current_game_full_locations, ""))
				table.insert(full_table, table.concat(full_table_header, ""))
				table.insert(full_table, '</tbody></table></div>')
				
			end
			
			if is_there_full_table_game
			then if number_subareas == 1
				then current_game_locations_first_subarea = current_game_locations
					current_game_locations = {}
				end
				table.insert(current_game_locations_first_subarea,
					'<td rowspan="' .. number_subareas .. '"><button type="button" name="tauxdétaillés-' .. last_game .. '" value="afficher" title="[–]">[+]</button></td></th>')
				
			else table.insert(current_game_locations, "</th>")
			end
			
			table.insert(current_game_locations_first_subarea, table.concat(current_game_locations, ""))
			table.insert(result, table.concat(current_game_locations_first_subarea, ""))
			
			current_game_locations = {}
			current_game_locations_first_subarea = {}
			current_game_full_locations = {}
			current_subarea_full_locations = {}
			
			table.insert(current_game_locations, '<td>')
			
			number_subareas = 0
			
			if places_end
			then 
				break
			else
				-- row to specify the game, at the end of last area full locations; only if the game has places
				is_there_full_table_game = (places[i]["name"] ~= "")
				if is_there_full_table_game
				then is_there_full_table = true
					table.insert(full_table, '\n<div class="tauxdétaillés-' .. current_game .. '">')
				end
			end
			
			last_place = nil
		end
		
		local place_name = places[i]["name"]
		local place_name_split = mw.text.split(place_name, "@")
		local place_link_split = mw.text.split(place_name_split[1], "|")
		local place_link = place_link_split[1]
		
		local place_link_display
		if place_link_split[2]
		then place_link_display = '[[' .. place_link_split[1] .. '|' .. place_link_split[2] .. ']]'
		else local place_link_filtered = mw.ustring.gsub(place_link, " %(.-%)", "")
			if place_link_filtered == place_link
			then place_link_display = '[[' .. place_link .. ']]'
			else place_link_display = '[[' .. place_link .. '|' .. place_link_filtered .. ']]'
			end
		end
		
		local place_suffix = ""
		
		if place_name_split[2]
		then place_suffix = " (" .. place_name_split[2] .. ")"
		end
		
		local comma_string = ""
		local subarea = subareas.get_subarea_from_place(mw.text.split(place_link, "|")[1])
		local subarea_text
		if subarea then subarea_text = subarea else subarea_text = "" end
		
		if last_place ~= place_link
		then if last_place ~= nil
			then 
				-- if all encounters in the place are restricted to a single game of the two
				if seen_games_place and seen_games_place ~= "all" then table.insert(current_game_locations, frame:expandTemplate{title='Sup', args={seen_games_place}}) end
				seen_games_place = nil
				table.insert(current_game_locations, '</span>')
			end
			
			if last_place == nil or subareas.get_subarea_id_from_place(last_place) ~= subareas.get_subarea_id_from_place(place_link)
			then 
				if last_place ~= nil
				then table.insert(current_game_locations, '</td>')
					if number_subareas == 1
					then current_game_locations_first_subarea = current_game_locations
						current_game_locations = {'</tr><tr><td>'}
					else table.insert(current_game_locations, '</tr><tr><td>')
					end
				end
				table.insert(current_game_full_locations, table.concat(current_subarea_full_locations, ""))
				current_subarea_full_locations = {}
				local subarea_text = subarea
				if not subarea then subarea_text = "" end
				local subrates_list = subarea_subrates_list[current_game][subarea_text]
				
				number_subareas = number_subareas + 1
				
				if subarea or (subrates_list and subrates_list.subrates)
				then
					local colspan_th = 2
					if multiple_ids then colspan_th = 3 end
					if subarea
					then local link_subarea = subareas.get_link(subarea)
						table.insert(current_game_locations, link_subarea .. " : ")
						if not (subrates_list and subrates_list.subrates) then colspan_th = colspan_th + reduced_colspan_rates[current_game] end
						table.insert(current_subarea_full_locations, "<tr><th colspan='" .. colspan_th .. "'>" .. link_subarea .. "</th>")
					else table.insert(current_subarea_full_locations, '<tr><td style="background:transparent" colspan="' .. colspan_th .. '"></td>')
					end
					
					if subrates_list
					then local colspan_local = math.floor(reduced_colspan_rates[current_game] / subrates_list.number)
						local width_local = math.floor(rates_width[current_game] / subrates_list.number)
						
						for s = 1, subrates_list.number do
							if subrates_list.subrates
							then local subrate_s = subrates_list.subrates[1][s]
								table.insert(current_subarea_full_locations, '<td class="' .. subrates_list.subrates[3][s] .. '" width="' .. width_local .. 'px" colspan="' .. colspan_local .. '">')
								if subrates_list.subrates["no_icon"]
								then table.insert(current_subarea_full_locations, subrate_s .. '</td>')
								else table.insert(current_subarea_full_locations, '[[Fichier:Icône ' .. subrate_s .. ' ' .. current_game .. '.png|' .. subrate_s .. '|link=' .. subrates_list.subrates[4][1] .. '|x25px]]</td>')
								end
							end
						end
					end
					table.insert(current_subarea_full_locations, '</tr>')
				end
				
			else comma_string = ", "
			end
			last_place = place_link
			
			if places[i]["name"] == ""
			then 
				local unavailable_sentence = "<i>Indisponible</i>"
				-- if current_game == "EV" then unavailable_sentence = "<i>À compléter</i>" end
				
				local unavailable_table = require("Module:Localisations/Données/" .. game_links[current_game] .. "/Indisponibles")
				local custom_unavailable_sentence = false
				for _, pokemon_id in pairs(pokemon_ids) do
					local unavailable_sentence_tmp = unavailable_table[pokemon_id]
					
					if unavailable_sentence_tmp
					then unavailable_sentence = unavailable_sentence_tmp
						custom_unavailable_sentence = true
						break
					end
				end
				
				if not custom_unavailable_sentence
				then local unavailable_sentence_tmp = unavailable_table[pokemon]
					if unavailable_sentence_tmp
					then unavailable_sentence = unavailable_sentence_tmp
					end
				end
				
				-- template expansion
				local template = mw.ustring.gsub(unavailable_sentence, "(.*){{(.-)|(.-)}}(.*)", "%2")
				if template and template ~= unavailable_sentence
				then local arg = mw.ustring.gsub(unavailable_sentence, "(.*){{(.-)|(.-)}}(.*)", "%3")
					local template_expanded = frame:expandTemplate{title=template, args={arg}}
					unavailable_sentence = mw.ustring.gsub(unavailable_sentence, "(.*){{(.-)|(.-)}}(.*)", "%1" .. template_expanded .. "%4")
				end
					
				current_game_locations = {'<td>' .. unavailable_sentence .. '</td><td></td>'}
			else table.insert(current_game_locations, comma_string .. '<span style="white-space:nowrap">' .. place_link_display)
				-- '</span>' is added after the end of the rate calculation, to add a possible {{Sup|.}} after the rate
			end
			
		end
		
		
		
		function add_rate(rate, rate_precision, colspan, class, notes)
			local seen_games_here = nil
			local found_notes = false
			
			rate = mw.ustring.gsub(rate, "-", "—")
			rate = mw.text.split(rate, ", ")
			if tonumber(rate[1])
			then rate[1] = string.gsub(rate[1], "%.", ",") .. "&nbsp;%"
			else rate[1] = mw.ustring.gsub(rate[1], "{{!}}", "|")
			end
			if rate[1] == "Fixe" then rate[1] = "[[Fichier:Icône Fixe.svg|class=imagenoire|27px|Fixe]]" end
			
			table.insert(current_subarea_full_locations, "<td")
			if class then table.insert(current_subarea_full_locations, ' class="' .. class .. '"') end
			if colspan then table.insert(current_subarea_full_locations, ' colspan="' .. colspan .. '"') end
			table.insert(current_subarea_full_locations, '>' .. rate[1])
			
			local k = 2
			while rate[k] do	-- Gestion des taux spécifiques à des jeux
				if tonumber(rate[k])
				then table.insert(current_subarea_full_locations, "<br>" .. string.gsub(rate[k], "%.", ",") .. "&nbsp;%")
				else table.insert(current_subarea_full_locations, frame:expandTemplate{title='Sup', args={rate[k]}})
					if seen_games_here and seen_games_here ~= rate[k] then seen_games_here = "all" else seen_games_here = rate[k] end
				end
				k = k + 1
			end
			if notes and string.sub(notes, 1, 9) == "Exclusif "
			then found_notes = true
				local game = string.sub(notes, 10, string.find(notes, ".", 11))
				table.insert(current_subarea_full_locations, frame:expandTemplate{title='Sup', args={game}})
				if seen_games_here and seen_games_here ~= game then seen_games_here = "all" else seen_games_here = game end
			end
			if rate_precision then table.insert(current_subarea_full_locations, '<br><small><i>' .. rate_precision .. '</i></small>') end
			table.insert(current_subarea_full_locations, "</td>")
			
			-- might want rework if there is a trio of games at some point
			if rate[2] or rate[1] ~= "—" or found_notes
			then if seen_games_place and seen_games_place ~= seen_games_here
				then seen_games_place = "all"
				else seen_games_place = seen_games_here
				end
			end
		end
		
		local place_info = places[i]["contents"]
		if place_info
		then local j = 1
			while place_info[j] do
				local id = places[i]["id"]
				local milieu = place_info[j]["milieu"]
				local emplacement = place_info[j]["emplacement"]
				
				if milieu
				then milieu = mw.ustring.gsub(milieu, "<br>", " ")
					milieu_split = mw.ustring.gsub(milieu, ',', '')
				else milieu = ""
				end
				
				-- précision de localisation par rapport au "milieu"
				if emplacement
				then emplacement = ', ' .. mw.ustring.gsub(emplacement, "<br>", " ")
				else emplacement = ""
				end
				
				local endroit_unsplit = mw.text.split(milieu, ",, ")
				local prefixe_endroit = endroit_unsplit[2] -- éventuellement nil
				local endroit = mw.text.split(endroit_unsplit[1], ",")
				local endroit_untouched = endroit[1]
				if prefixe_endroit == nil
				then prefixe_endroit = ""
				else prefixe_endroit = prefixe_endroit .. " "
					endroit[1] = mw.ustring.lower(mw.ustring.sub(endroit[1],1,1)) .. mw.ustring.sub(endroit[1],2,endroit[1]:len())
					-- on a mis la première lettre de l'endroit en minuscule, puisqu'elle est précédée de prefixe_endroit
				end
				endroit[1] = mw.ustring.gsub(endroit[1], " %([^%)]*%)", "")
				-- on retire les parenthèses des milieux, elles ne servent qu'à spécifier l'image, inutile ici
				
				if endroit[2] == nil then endroit[2] = "" end
				endroit[1] = mw.ustring.gsub(endroit[1], " – ", ", ")
				endroit[2] = mw.ustring.gsub(endroit[2], " – ", ", ")
				
				endroit[2] = mw.ustring.gsub(endroit[2], "{{!}}", "|")
				local template_replacement = endroit[2]:gsub(".*{{(.-)|(.-)}}.*", "%1") -- sert à process les modèles, qu'ils utilisent "|" ou "{{!}}"
				local templates_replaced = 0
				while template_replacement ~= endroit[2] and templates_replaced < 4 do -- pour empêcher une boucle infinie en cas de pépin, 4 modèles max devraient suffire
					local arg_template_teplacement = endroit[2]:gsub(".*{{(.-)|(.-)}}.*", "%2")
					
					local template_result = frame:expandTemplate{title=template_replacement, args={arg_template_teplacement}}
					endroit[2] = endroit[2]:gsub("(.*){{(.-)|(.-)}}(.*)", "%1" .. template_result .. "%4")
					
					local template_replacement = endroit[2]:gsub(".*{{(.-)|(.-)}}.*", "%1")
					templates_replaced = templates_replaced + 1
				end
				
				milieu = prefixe_endroit .. endroit[1] .. endroit[2] .. emplacement
				if milieu ~= "" then milieu = " – " .. milieu end
				
				table.insert(current_subarea_full_locations, "<tr>")
				if multiple_ids
				then if id
					then table.insert(current_subarea_full_locations, "<td>" .. ressources.infosPokemon(id, "miniature") .. "</td>")
					else table.insert(current_subarea_full_locations, "<td></td>")
					end
				end
				table.insert(current_subarea_full_locations, "<td>" .. place_link_display .. place_suffix .. milieu .. '</td><td>')
				
				local level = place_info[j]["niveau"]
				if level then level = mw.ustring.gsub(level, "-", "–") else level = "—" end
				level = mw.text.split(level, ", ")
				
				table.insert(current_subarea_full_locations, '<span style="white-space:nowrap">' .. level[1])
				local k = 2
				while level[k] do
					level_k = mw.ustring.gsub(level[k], "–", "")
					if tonumber(level_k)
					then table.insert(current_subarea_full_locations, '</span><br><span style="white-space:nowrap">' .. level[k])
					else table.insert(current_subarea_full_locations, frame:expandTemplate{title='Sup', args={level[k]}})
					end
					k = k + 1
				end
				table.insert(current_subarea_full_locations, "</span></td>")
				
				local rate = place_info[j]["taux"]
				if rate
				then local rate_precision = place_info[j]["précision-taux"]
					local notes = place_info[j]["notes"]
					add_rate(rate, rate_precision, reduced_colspan_rates[current_game], nil, notes)
					
				else local subarea_info = subarea_subrates_list[current_game][subarea_text]
					local notes = place_info[j]["notes"]
					if subarea_info.subrates
					then local colspan_local = math.floor(reduced_colspan_rates[current_game] / subarea_info.number)
						for s = 1, subarea_info.number do
							local subrate_s = place_info[j][subarea_info.subrates[2][s]]
							if not subrate_s then subrate_s = "—" end
							local subrate_s_precision = place_info[j]["précision-" .. subarea_info.subrates[2][s]]
							add_rate(subrate_s, subrate_s_precision, colspan_local, subarea_info.subrates[3][s], notes)
						end
					else add_rate("—", nil, reduced_colspan_rates[current_game], nil, notes)
					end
						
				end
				table.insert(current_subarea_full_locations, "</tr>")
				
				j = j + 1
			end
		end
		
		i = i + 1
	end
	table.insert(result, '<caption style="caption-side:bottom; font-weight:normal"><small><i>Ce tableau est généré automatiquement. Pour que son contenu soit modifié, il faut modifier les pages de lieux. Informations détaillées sur [[Module:Localisations|cette page]].</i></small></caption></tbody></table>')
	
	-- if is_there_full_table
	-- then
		table.insert(result_header, '<table class="tableaustandard centre ' .. pokemon_type .. '"><tbody><tr><th width="150px">Versions</th><th width="600px">Localisations</th><th width="60px">Détails</th>')
		table.insert(result, table.concat(full_table, ""))
	-- else table.insert(result_header, '<table class="tableaustandard centre ' .. pokemon_type .. '"><tbody><tr><th width="150px">Versions</th><th width="600px" colspan="2">Localisations</th>')
	-- end
	
	table.insert(result_header, '</tr>')
	table.insert(result_header, table.concat(result, ""))
	return table.concat(result_header, "")
end



-- Fonction pour recenser les endroits de tous les Pokémon détectés pour un même jeu, donné en argument
function p.pokeliste(frame)
	local result = {}
	local game = frame.args["jeu"]
	if not game then game = frame.args[1] end
	local game_long = game_to_game_long[game]
	if not game_long then return "<i>Erreur : jeu invalide.</i>" end
	
	if game ~= "LPA"
	then game_long = "Pokémon " .. game_to_game_long[game]
	end
	
	local locdata = require("Module:Localisations/Données/" .. game_long)
	local pokemon_global_list = {}
	for place_name, pokemon_list in pairs(locdata) do
		local place_name_stripped = mw.text.split(mw.text.split(place_name, "@")[1], "|")[1]
		local place_name_link = "[[" .. place_name_stripped .. "|" .. mw.ustring.gsub(place_name_stripped, " %(.-%).-", "") .. "]]"
		for pokemon, _ in pairs(pokemon_list) do
			if pokemon_global_list[pokemon]
			then pokemon_global_list[pokemon] = pokemon_global_list[pokemon] .. ", " .. place_name_link
			else pokemon_global_list[pokemon] = place_name_link
			end
		end
	end
	
	table.insert(result, '<table class="tableaustandard sortable entetefixe"><tr><th>infosPokemon</th><th>Pokémon</th><th>Lieux</th></tr>')
	
	for pokemon, places in pairs(pokemon_global_list) do
		table.insert(result, '<tr><td>' .. ressources.infosPokemon(pokemon) .. '</td><td>' .. pokemon .. '</td><td>' .. places .. '</td></tr>')
	end
	
	table.insert(result, '</table>')
	
	return table.concat(result, "")
end

return p