Wiki L'encyclopédie Moga
Wiki L'encyclopédie Moga

La documentation pour ce module peut être créée à Module:Games Database/doc

--[[ 
Ce module a pour but de centraliser, standardiser et faciliter l'accès aux 
informations portant sur les jeux.

Il constitue une base de données avec des fonctions permettant d'accéder aux 
données, et doit donc être tenu à jour.
]]
local p = {}
-- Sert pour le formattage de dates 
local lang = mw.getLanguage( 'fr' )
local mh = "Monster Hunter"
-- Accesseurs de la base de donnée
local accessors = require("Module:Database Accessors")

--[[
Liste des zones géographiques utiles pour les jeux MH, on précise aussi 
laquelle  est inclue dans laquelle
]]
local aliases = {
    an = {n = "Amérique du Nord", sup = "oc"},
    au = {n = "Australie",        sup = "oc"},
    ch = {n = "Chine",            sup = "m" },
    co = {n = "Corée",            sup = "m" },
    en = {n = "Royaume-Uni",      sup = "eu"},
    eu = {n = "Europe",           sup = "oc"},
    fr = {n = "France",           sup = "eu"},
    ja = {n = "Japon",            sup = "m" },
    m  = {n = "Monde"                       },
    oc = {n = "Occident",         sup = "m" },
}

-- Banque de données des jeux 
-- Merci d'ajouter les jeux suivant la génération, puis dans l'ordre 
-- chronologique de première sortie, afin de faciliter l'entretion
--[[ 
Abbréviation : 
    * r : "releases", date de première sortie du jeu dans chaque zone 
    géographique. Format de date "jj-mm-aaaa"
    * s : "short" (nom abbrégé) 
    * seq : "sequel" on indique le nom abrégé ou complet du jeu qui est sa suite
    * gen : "generation", la génération du jeu, 
        * Un chiffre pour les ordinaux (première, deuxième), un chaîne pour les 
        autres (Frontier, Online)
]]
games = {
    -- Série principale
    {name = mh, r = {an = "21-09-2004", eu = "27-05-2005", ja = "11-03-2004"}, s = "MH", seq = "MHG", gen = 1},
    {name = mh .. " G", r = {ja = "20-01-2005"}, s = "MHG", seq = "MHF", gen = 1},
    {name = {oc = mh .. " Freedom", ja = mh .. " Portable"}, r = {an="23-05-2006", au="26-05-2006", co="21-09-2006", eu="12-05-2006", ja="01-12-2005"}, s = "MHF", gen = 1},
    {name = {oc = mh .. " 2", ja = mh .. " Dos"}, r = {ja="16-02-2006"}, s = "MH2", seq = "MHF2", gen = 2},
    {name = {oc = mh .. " Freedom 2", ja = mh .. " Portable 2nd"}, r = {an="29-05-2007", au="12-09-2007", co="28-05-2007", eu="07-09-2007", ja="22-02-2007"}, s = "MHF2" , seq = "MHFU", gen = 2},
    {name = {oc = mh .. " Freedom Unite", ja = mh .. " Portable 2nd G"}, r = {an="22-06-2009", au="23-06-2009", co="29-03-2008", eu="26-06-2009", ja="27-03-2008"}, s = "MHFU", gen = 2 },
    -- Remarque : on ne tient pas compte ici du portage de MHFU sur iOS
    {name = {oc = mh .. " 3", ja = mh .. " Tri"}, r = {an="20-04-2010", au="29-04-2010", eu="23-04-2010", ja="01-08-2009"}, s = "MH3", seq = "MH3U", gen = 3 },
    {name = mh .. " Portable 3rd", r = {co="01-12-2010", ja="01-12-2010"}, s = "MHP3rd", gen = 3 },
    {name = {oc = mh .. " 3 Ultimate", ja = mh .. " 3G"}, r = {an="19-03-2013", au="23-03-2013", eu="22-03-2013", ja="10-11-2011"}, s = {oc="MH3U", ja="MH3G"}, gen = 3 },
    {name = mh .. " 4", r = {co = "14-12-2013", ja = "14-09-2013"}, s = "MH4", seq = "MH4U", gen = 4 },
    {name = {oc = mh .. " 4 Ultimate", ja = mh .. " 4G"}, r = {an="13-02-2015", au="14-02-2015", eu="13-02-2015", ja="11-10-2014"}, s = {oc="MH4U", ja="MH4G"}, gen = 4 },
    {name = {oc = mh .. " Generations", ja = mh .. " X"}, r = {oc="15-07-2016", ja="28-11-2015"}, s = {oc="MHGen", ja="MHX"}, seq = "MHGU", gen = 4 },
    {name = {oc = mh .. " Generations Ultimate", ja = mh .. " XX"}, r = {oc="28-08-2018", ja="25-08-2017"}, s = {oc="MHGU", ja="MHXX"}, gen = 4 },
    {name = mh .. ": World", r = {m="26-01-2018"}, s = "MHW", seq = "MHWI", gen = 5 },
    {name = mh .. " World: Iceborne", r = {m="06-09-2019"}, s = "MHWI", gen = 5 },
    {name = mh .. " Rise", r = {m="26-03-2021"}, s = "MHRise", gen = 5},
    -- Série Frontier
    {name = mh .. " Frontier", r = {ja = "21-06-2007"}, s = "MHFrontier", seq = "MHF-S1", gen = "Frontier" },
    {name = mh .. " Frontier Saison 1.0", r = {ja = "21-07-2007"}, s = "MHF-S1", seq = "MHF-S2", gen = "Frontier" },
    {name = mh .. " Frontier Saison 2.0", r = {ja = "30-01-2008"}, s = "MHF-S2", seq = "MHF-S3", gen = "Frontier" },
    {name = mh .. " Frontier Saison 3.0", r = {ja = "02-07-2008"}, s = "MHF-S3", seq = "MHF-S4", gen = "Frontier" },
    {name = mh .. " Frontier Saison 4.0", r = {ja = "17-12-2008"}, s = "MHF-S4", seq = "MHF-S5", gen = "Frontier" },
    {name = mh .. " Frontier Saison 5.0", r = {ja = "08-04-2009"}, s = "MHF-S5", seq = "MHF-S6", gen = "Frontier" },
    {name = mh .. " Frontier Saison 6.0", r = {ja = "16-09-2009"}, s = "MHF-S6", seq = "MHF-S7", gen = "Frontier" },
    {name = mh .. " Frontier Saison 7.0", r = {ja = "09-12-2009"}, s = "MHF-S7", seq = "MHF-S8", gen = "Frontier" },
    {name = mh .. " Frontier Saison 8.0", r = {ja = "21-04-2010"}, s = "MHF-S8", seq = "MHF-S9", gen = "Frontier" },
    {name = mh .. " Frontier Saison 9.0", r = {ja = "29-09-2010"}, s = "MHF-S9", seq = "MHF-S10", gen = "Frontier" },
    {name = mh .. " Frontier Saison 10", r = {ja = "26-01-2011"}, s = "MHF-S10", seq = "MHF-F.1", gen = "Frontier" },
    {name = mh .. " Frontier Forward.1", r = {ja = "20-04-2011"}, s = "MHF-F.1", seq = "MHF-F.2", gen = "Frontier" },
    {name = mh .. " Frontier Forward.2", r = {ja = "29-09-2011"}, s = "MHF-F.2", seq = "MHF-F.3", gen = "Frontier" },
    {name = mh .. " Frontier Forward.3", r = {ja = "01-02-2012"}, s = "MHF-F.3", seq = "MHF-F.4", gen = "Frontier" },
    {name = mh .. " Frontier Forward.4", r = {ja = "23-05-2012"}, s = "MHF-F.4", seq = "MHF-F.5", gen = "Frontier" },
    {name = mh .. " Frontier Forward.5", r = {ja = "17-10-2012"}, s = "MHF-F.5", seq = "MHF-G1", gen = "Frontier" },
    {name = mh .. " Frontier G", r = {ja = "17-04-2013"}, s = "MHF-G", seq = "MHF-G1", gen = "Frontier" },
    {name = mh .. " Frontier G1", r = {ja = "17-04-2013"}, s = "MHF-G1", seq = "MHF-G2", gen = "Frontier" },
    {name = mh .. " Frontier G2", r = {ja = "10-07-2013"}, s = "MHF-G2", seq = "MHF-G3", gen = "Frontier" },
    {name = mh .. " Frontier G3", r = {ja = "16-10-2013"}, s = "MHF-G3", seq = "MHF-GG", gen = "Frontier" },
    {name = mh .. " Frontier G Genuine", r = {ja = "23-04-2014"}, s = "MHF-GG", seq = "MHF-G5", gen = "Frontier" },
    {name = mh .. " Frontier G5", r = {ja = "23-07-2014"}, s = "MHF-G5", seq = "MHF-G6", gen = "Frontier" },
    {name = mh .. " Frontier G6", r = {ja = "19-11-2014"}, s = "MHF-G6", seq = "MHF-G7", gen = "Frontier" },
    {name = mh .. " Frontier G7", r = {ja = "15-04-2015"}, s = "MHF-G7", seq = "MHF-G8", gen = "Frontier" },
    {name = mh .. " Frontier G8", r = {ja = "22-07-2015"}, s = "MHF-G8", seq = "MHF-G9", gen = "Frontier" },
    {name = mh .. " Frontier G9", r = {ja = "18-11-2015"}, s = "MHF-G9", seq = "MHF-G10", gen = "Frontier" },
    {name = mh .. " Frontier G10", r = {ja = "21-04-2016"}, s = "MHF-G10", seq = "MHF-Z", gen = "Frontier" },
    {name = mh .. " Frontier Z", r = {ja = "09-11-2016"}, s = "MHF-Z", seq = "MHF-ZZ", gen = "Frontier" },
    {name = mh .. " Frontier Z Zenith", r = {ja = "26-09-2018"}, s = "MHF-ZZ", gen = "Frontier" },
    -- Série Online
    {name = mh .. " Online", r = {ch = "28-06-2013"}, s = "MHO", gen = "Online" },
    -- Série Diaries
    {name = "MH Diary: Mobile Felyne Village", r = {ja = "10-08-2010"}, s = "MHD:MFV", gen = "Diary" },
    {name = "MH Diary: Poka Poka Felyne Village", r = {ja = "26-08-2010"}, s = "MHD:PPFV", seq = "MH Diary: Poka Poka Felyne Village G", gen = "Diary" },
    {name = "MH Diary: Poka Poka Felyne Village G", r = {ja = "10-09-2011"}, s = "MHD:PPFVG", gen = "Diary" },
    {name = "Felyne Puzzle", r = {ja = "19-07-2012"}, s = "FP", gen = "Diary" },
    {name = "MH Diary: Poka Poka Felyne Village DX", r = {ja = "10-09-2015"}, s = "MHD:PPFVDX", gen = "Diary" },
    -- Autres hors-série
    {name = mh .. " i", r = {ja = "06-02-2006"}, s = "MHi", gen = "Hors-série" },
    {name = mh .. " Dynamic Hunting", r = {m = "01-06-2011"}, s = "MHDH", gen = "Hors-série" },
    {name = mh .. ": Phantom Island Voyage", r = {ja = "11-11-2011"}, s = "MHPIV", gen = "Hors-série" },
    {name = mh .. " Massive Hunting", r = {ja = "04-02-2013"}, s = "MHMH", gen = "Hors-série" },
    {name = mh .. " Big Game Hunting Quest", r = {ja = "29-10-2013"}, s = "MHBGHQ", gen = "Hors-série" },
    {name = mh .. " Mezeporta Reclamation", r = {ja = "27-11-2014"}, s = "MHMR", gen = "Hors-série" },
    {name = mh .. " Spirits", r = {ja = "25-06-2015"}, s = "MHS", gen = "Hors-série" },
    {name = mh .. " Explore", r = {ja = "29-09-2015"}, s = "MHXR", gen = "Hors-série" },
    {name = mh .. " Stories", r = {ja = "08-10-2016", m = "08-09-2017"}, s = "MHST", gen = "Hors-série" },
    {name = mh .. " Riders", r = {m = "12-02-2020"}, s = "MHRd", gen = "Hors-série" },
    {name = mh .. " Stories 2: Wings of Ruin", s = "MHStories2", gen = "Hors-série"
        },
}

-- Attention ! La fonction load_games (plus bas) modifie la base de données


-- Fonctions "privées", utiles à la manipulation des données

--[[
Prend en entrée une table ou une chaîne correspondant à l'une des propriétés 
d'une ligne de la base de données. 

Si c'est une chaîne on la renvoie, sinon, on essaie de trouver la zone 
géographique correspondant à celle demandé (qui doit être la plus précise 
possible)
]]
local function area_boiling(prop, area)
    if type(prop) == "string" then
        return prop
    end
    -- Pas de zone, on va essayer les zones dans lesquelles on sait qu'il y a 
    -- un jeu
    if area == nil then
        local out, k, v
        for k, v in ipairs({"fr", "ja", "ch"}) do
            out = area_boiling(prop, v)
            if out then
                return out
            end
        end
        return false
    end
    if prop[area] then
        return prop[area]
    end
    -- On est remontés jusqu'à la zone "monde" sans rien trouver, on s'arrête
    if area == "m" then
        return false
    end
    -- On relance la recherche sur la zone supérieure
    return area_boiling(prop, aliases[area].sup)
end

--[[
Renvoie true si le premier argument de date est postérieur au second.

Prend en entrée deux dates au format FRANÇAIS (jj-mm-aaa) et renvoie les dates 
au format "Ymd", permet de comparer deux dates entre elles pour les trier.
]]
function comp_dates(d1, d2)
   mw.log(d1)
   return lang:formatDate("Ymd", d1) < lang:formatDate("Ymd", d2) 
end


--[[
Trouve la ligne de la base de donnée dont le titre du jeu correspond au titre
entré. Si la zone n'est pas spécifiée, effectue la recherche avec des zones
distinctes
]]
local function find_game(name, zone, abbr) 
    for _, game in pairs(games) do
        if (abbr and area_boiling(game.s, zone) == name) or (not abbr and 
        	area_boiling(game.name, zone) == name) then
            return game
        end
    end
end

-- Fonctions modifiant la base de données

--[[ 
Fonction modifiant la base de données. 

On ajoute un argument "pre" ("prequel", soit le jeu précédent), complémentaire 
de "seq" ("sequel") qui donne le jeu précédent un autre
]]
local function load_games()
    local i, game, _, game2
    for i, game in pairs(games) do
        if game.seq then
            for _, game2 in pairs(games) do
                if find_game(area_boiling(game.seq), nil, true) == game2 then
                    game2.pre = game
                    game.seq = game2
                end
            end
        end
    end
end
load_games()

-- Fonctions "publiques", accessibles par l'utilisateur

--[[ 
Renvoie le nom du jeu si le jeu en argument d'entré est référencé et rien sinon. 

Possibilité d'utiliser une langue au choix
]]
function p.existe(a)
    local g = find_game(a.args[1], a.args.zone, a.args.abbr)
    if g then
        return area_boiling(g.name, a.args.zone)
    else
        return ""
    end
end

-- Renvoie la date de parution d'un jeu dans une zone géographique donnée, 
-- format personnalisable
function p.date(a)
    local game = find_game(a.args[1], a.args.zone)
    local date_format = a.args.format or 'd F Y'
    return lang:formatDate(date_format, area_boiling(game.r, a.args.zone))
end


-- Renvoie toutes les dates de parution d'un jeu, dans toutes ses zones, 
-- le format est personnalisable
function p.dates_parution(a)
    assert(p.existe(a) ~= "", error("Le jeu " .. a.args["1"] .. 
    	" ne figure pas dans la base de donneés"))
    local game = find_game(a.args["1"])
    local out = ""
    a.args.format = a.args.format or 'd F Y'
    a.args.sep = a.args.sep or "\n"
    table.sort(game.r, comp_dates)
    for k, v in pairs(game.r) do
        out = out .. aliases[k].n .. " - " 
        .. lang:formatDate(a.args.format, v) .. a.args.sep
    end
    return mw.ustring.sub(out, 1, -mw.ustring.len(a.args.sep) - 1)
end

--[[
Prend une liste de jeux en entrée et la renvoie triée

Arguments:
	* Un argument numéroté par jeu
	* sep  : séparateur de sortie entre les jeux
    * zone : permet d'indiquer une zone géographique pour les dates
    * abbr : pour utiliser les abbréviations
]]
function p.trier_jeux(a)
	local date_games, date_list, i, game_r, game_name, _, v, r_date, out
	-- Pour chaque date, les jeux qui y sortent
	date_games = {}
	-- Liste des dates (utile pour le tri)
	date_list = {}
	-- On récupère les jeux à trier
	for _, v in ipairs(a.args) do
		game_r = find_game(v, a.args.zone, a.args.abbr)
		game_name = area_boiling(game_r.name, a.args.zone)
		r_date = area_boiling(game_r.r, a.args.zone)
		if date_games[r_date] == nil then
			date_games[r_date] = {game_name}
			table.insert(date_list, r_date)
		else
			table.insert(date_games[r_date], game_name)
		end
	end
	-- On trie les jeux
	table.sort(date_list, comp_dates)
	out = ""
	for _, v in ipairs(date_list) do
		out = out .. a.args.sep .. table.concat(date_games[v], a.args.sep)
    end
	return mw.ustring.sub(out, 1, -mw.ustring.len(a.args.sep) - 1)
end

-- Renvoie la suite d'un jeu, en abrégé si demandé, en version longue sinon
function p.suite(a)
    assert(p.existe(a) ~= "", "Le jeu " .. a.args[1] .. 
    	" ne figure pas dans la base de donneés")
   local game = find_game(a.args[1], a.args.zone, a.args.abbr)
   if game.seq == nil then
       return ""
   elseif a.args.abbr then
        return area_boiling(game.seq.s, a.args.zone)
    else
        return area_boiling(game.seq.name, a.args.zone)
    end
end

-- Renvoie le nombre de jeux, compatible avec les filtres
function p.nombre_jeux(a)
    local num, ok, _, game, k, v = 0
    for _, game in pairs(games) do
        ok = true
        for k, v in pairs(a.args) do
            ok = ok and accessors.standard_filter(game, k, v)
        end
        if ok then
            num = num + 1
        end
    end
    return num
end

--[[ 
Renvoie le jeu numéro i, après filtrage. Ne renvoie rien si l'indice est 
supérieur à la valeur. Les arguments sont les suivants :
	* sep  : sert à préciser des séparateurs (jusqu'à trois niveaux, séparés 
	par des "/").
    * zone : permet d'indiquer une zone géographique pour les résultats
    * abbr : dit que l'on ne veut que les abbréviations
    * num  : numéro à atteindre
    * lien : indique que l'on veut les résultats avec lien
]]
function p.jeu_numero(a)
    local num, ok, _, game, k, v = 0
    local zone = a.args.zone or "eu"
    for _, game in pairs(games) do
        ok = true
        for k, v in pairs(a.args) do
            ok = ok and (({sep=true, zone=true, abbr=true, num=true, 
            	lien=true})[k] or accessors.standard_filter(game, k, v))
        end
        if ok then
            num = num + 1
        end
        if num == tonumber(a.args.num) then
            if a.args.abbr then
                if a.args.lien then
                    return "[[" .. area_boiling(game.name, "eu") .. "|" .. 
                    area_boiling(game.s, zone) .. "]]"
                else
                    return area_boiling(game.s, zone)
                end
            else
                local out = ""
                if a.args.lien then
                    out = out .. "[["
                end
                out = out .. area_boiling(game.name, zone)
                if a.args.lien then
                    out = out .. "]]"
                end
                return out
            end
        end
    end
end


--[[ 
Renvoie les noms de tous les jeux, rangés dans le même ordre que dans la base de
données (donc a priori ordre chronologique). Les arguments sont les suivants :
	* sep1, sep2, sep3  : servent à préciser les trois niveaux de séparateurs
    * zone : permet d'indiquer une zone géographique pour les résultats
    * abbr : dit que l'on ne veut que les abbréviations
    * lien : indique que l'on veut les rusltats avec lien
    * Un nombre arbitraire d'argument faisant office de filtres
]]
function p.liste_jeux(a)
    a = a or {args={}}
    local sep, out, zone = {a.args.sep1 or "\n\n", 
    	a.args.sep2 or "\n", a.args.sep3 or " • "}, "", (a.args.zone or "eu")
    local i, j, k, v, game, stop
    for i, game in pairs(games) do
        j = 1
        stop = false
        for k, v in pairs(a.args) do
            if not ({sep=true, sep1=true, sep2=true, sep3=true, zone=true, abbr=true, 
            	lien=true})[k] and 
            not accessors.standard_filter(game, k, v) then
                stop = true
                break
            end
            j = j + 1
        end
        if not stop then
            if a.args.abbr then
                if a.args.lien then
                    out = out .. "[[" .. area_boiling(game.name, "eu") .. "|" ..
                    area_boiling(game.s, zone) .. "]]"
                else
                    out = out .. area_boiling(game.s, zone)
                end
            else
                if a.args.lien then
                    out = out .. "[["
                end
                out = out .. area_boiling(game.name, zone)
                if a.args.lien then
                    out = out .. "]]"
                end
            end
            if game.seq then 
                out = out .. sep[3]
            elseif games[i + 1] and games[i + 1].gen == game.gen then
                out = out .. sep[2]
            else
                out = out .. sep[1]
            end
        end
    end
    return mw.ustring.sub(out, 1, -1 - mw.ustring.len(sep[1]))
end

return p