Modulo:Learnlist
Vai alla navigazione
Vai alla ricerca
Questo modulo non ha ancora un manuale. Creane uno!
--[[
Creates the list of moves learned by a certain Pokémon.
Its main WikiCode interface are "level", "tm", "breed", "tutor", "preevo" and
"event", used as
{{#invoke: learnlist | level | <pokemon name> | gen = <gen> | form = <abbr> }}
where "gen" is optional and defaults to the latest generation, and "form" is
optional and defaults to base form.
Also the Pokémon name is optional and defaults to the page's name.
A typical usage is
{{#invoke: learnlist | level }}
in a Pokémon's page in order to build the list of moves it learns in the latest
generation.
-- ============================================================================
Some useful informations for developers:
- notes are needed only for breed and preevo
- except for level and tm, other methods has exactly one line per move.
A move can be learned at multiple levels, and a tm or hm with a move can
change within a generation (es: spaccaroccia)
--]]
local l = {}
local txt = require('Modulo:Wikilib/strings') -- luacheck: no unused
local tab = require('Modulo:Wikilib/tables') -- luacheck: no unused
local lib = require('Modulo:Wikilib/learnlists')
local genlib = require('Modulo:Wikilib/gens')
local multigen = require('Modulo:Wikilib/multigen')
local wlib = require('Modulo:Wikilib')
local links = require('Modulo:Links')
local ms = require('Modulo:MiniSprite')
local hf = require('Modulo:Learnlist/hf')
local sup = mw.loadData('Modulo:Sup/data')
local pokes = mw.loadData('Modulo:Poké/data')
local moves = mw.loadData('Modulo:Move/data')
local gendata = mw.loadData('Modulo:Gens/data')
local mtdata = mw.loadData('Modulo:Machines/data')
-- ============================ Wikilib-learnlists ============================
-- Here are functions previously in Wikilib-learnlists that uses PokéMoves-data
-- Moved here to remove dependency on the data module of pages that doesn't use
-- it specifically
local pokemoves = mw.loadData('Modulo:PokéMoves/data')
--[[
Given something, compute breed notes, ie. "breed chain", "the parent should
have learned the move in a previous gen" or "no parent can learn the move".
Arguments:
- gen: the generation of this entry
- move: the name of the move
- parent: any parent listed in the data module
- basenotes (optional): notes from the data module
(ie. pokemoves[poke][kind][gen][move].notes)
--]]
l.breednotes = function(gen, move, parent, basenotes)
local notes = { basenotes }
-- To compute notes it checks only one parent because they should all be
-- the same for this. Otherwise the different one would be the only one
-- (for instance: parents that need a chain aren't listed if there are
-- some that doesn't)
if parent and not l.canLearn(move, parent, gen, {"breed"}) then
if l.learnKind(move, parent, gen, "breed") then
-- Parent can learn by breed but not in any other way: chain
table.insert(notes, 1, "catena di accoppiamenti")
-- In theory this second check is useless because a parent wouldn't
-- be listed if it doesn't learn the move, so if it doesn't in this
-- gen it should in a past one
-- elseif l.learnPreviousGen(move, parent1, gen) then
else
table.insert(notes, 1, "il padre deve aver imparato la mossa in una generazione precedente")
end
elseif not parent then
table.insert(notes, 1, "nessun genitore può apprendere la mossa")
end
return table.concat(notes, ", ")
end
-- ====================== "Decompress" PokéMoves entries ======================
-- Decompress a level entry. A level entry is the "table" obtained picking a
-- pokemon, generation and move from pokemoves-data
-- (ie: pokemoves[poke].level[gen][move])
l.decompressLevelEntry = function(entry, gen)
local res
if type(entry) == 'table' then
res = table.copy(entry)
else
res = { { entry } }
end
-- if type(res[1]) ~= 'table' then
-- res[1] = {res[1]}
-- end
if #res == 1 then
res = table.map(lib.games.level[gen], function()
return table.copy(res[1])
end)
end
return res
end
-- Get a decompressed level entry
l.getLevelEntry = function(move, ndex, gen)
local pmkind = pokemoves[ndex].level
if not pmkind or not pmkind[gen] or not pmkind[gen][move] then
return nil
end
return l.decompressLevelEntry(pmkind[gen][move], gen)
end
-- ========================== Check learn functions ==========================
--[[
Given a move, an ndex, a gen and a kind check whether that Pokémon can learn
that move in that generation in that kind. Return a true value if it can, a
false otherwise.
Arguments:
- move: name of the move
- ndex: name or ndex of the Pokémon
- gen: generation (a string)
- kind: kind of learnlist ("level", "tm", ...)
--]]
l.learnKind = function(move, ndex, gen, kind)
local pmkind = pokemoves[ndex][kind]
if not pmkind or not pmkind[gen] then
return false
end
local mdata = pmkind[gen]
if kind == "tm" then
local mlist = mdata.all and tmdata[gen] or mdata
-- Extra parentheses to force a single return value
return (table.deepSearch(mlist, move))
else
return mdata[move]
end
end
--[[
Given a move and an ndex check whether that Pokémon can learn the given move
in a given generation. Return a true value if it can, a false otherwise. It is
also possible to give an array of kind that aren't considered when determining
whether it can learn the move or not.
Arguments:
- move: name of the move
- ndex: name or ndex of the Pokémon
- gen: generation
- excludekinds: (optional) array of kinds to exclude
--]]
l.canLearn = function(move, ndex, gen, excludekinds)
excludekinds = excludekinds or {}
return table.any(pokemoves[ndex], function(_, kind)
if table.search(excludekinds, kind) then
return false
end
return l.learnKind(move, ndex, gen, kind)
end)
end
--[[
Check whether a a Pokémon can learn a move in a generation previous than the
given one. If it can't returns false, otherwise the highest generation in which
it can learn it.
Arguments:
- move: name of the move
- ndex: name or ndex of the Pokémon
- gen: the gen considered: the function controls any generation strictly
lower than this.
- firstgen: (optional) the lowest gen to check. Defaults to 1
--]]
l.learnPreviousGen = function(move, ndex, gen, firstgen)
for g = gen - 1, firstgen or 1, -1 do
if table.any(pokemoves[ndex], function(_, kind)
return l.learnKind(move, ndex, g, kind)
end) then
return g
end
end
return false
end
-- ========================== End Wikilib-learnlists ==========================
local STRINGS = {
evolevelstr = 'Evo<span class="hidden-xs">luzione</span>',
tmcell = [=[
| class="black-text" style="padding: 0.1em 0.3em;" | <span class="hidden-xs">[[File:${img} ${tipo} VIII Sprite Zaino.png]]</span>[[${p1}]]]=],
breedcell = [=[
| style="padding: 0.1em 0.3em;" | ${p}]=],
}
--[[
TODO: select entry building function depending on gen (eg: gen 1 -> no category,
gen 4 -> contest entry)
Build the string corresponding to the last part of an entry, that is the part
without the learning method (levels for level entry, parents for breed entry,
etc.).
Arguments:
- poke: Pokémon name or ndex
- mossa: move name
- notes: any note that should be added to this entry
- gen: (optional) gen of the entry. Defaults to latest
--]]
l.entrytail = function(poke, mossa, notes, gen)
local data = multigen.getgen(moves[mossa], gen)
local stab = lib.computeSTAB(poke, mossa, nil, gen)
return lib.categoryentry(stab, data.name, notes, string.fu(data.type),
string.fu(data.category), data.power,
data.accuracy, data.pp)
end
--[[
Add header and footer for a learnlist table.
Arguments:
- str: body of the learnlist, to enclose between header and footer
- poke: Pokémon name or ndex
- gen: the generation of this entry
- kind: kind of entry. Either "level", "tm", "breed", "tutor", "preevo" and
"event".
--]]
l.addhf = function(str, poke, gen, kind)
local pokedata = multigen.getGen(pokes[poke], gen)
local hfargs = { pokedata.name, pokedata.type1, pokedata.type2, gen,
genlib.getGen.ndex(pokedata.ndex) }
return table.concat({
hf[kind .. "h"]{ args = hfargs },
str,
hf[kind .. "f"]{ args = hfargs },
}, "\n")
end
--[[
General function to build an entry. Requires some functions in funcDict to
determine details of the entry.
Oop isn't used because there's no inheritance.
Arguments:
- poke: Pokémon name or ndex
- gen: the generation of this entry
- kind: kind of entry. Either "level", "tm", "breed", "tutor", "preevo" and
"event". Also used to select functions (picks the funcDict)
This function makes use of a dictionary of function, retrieved using "kind", to
implement details of the entry. It should contain the following functions:
- processData: given a single value of pokemoves[poke][kind][gen]
transform it in a format more suitable for sorting and
printing. It is mapped over that table with dataMap.
Takes four arguments:
- poke: Pokémon name or ndex
- gen: the generation of this entry
- value: the value of pokemoves[poke][kind][gen][key]
- key: the key of that value
It should return an array of elements that will be sorted
and printed using other functions in the dict.
- dataMap: the kind of map used to map processData over the collection.
Often table.flatMapToNum or table.mapToNum
- lt: given two elements produced by processData, compares them
Takes two arguments, the two elements to compare.
- makeEntry: create the string of an entry from an element produced by
processData.
Takes three arguments:
- poke: Pokémon name or ndex
- gen: the generation of this entry
- entry: the element produced by processData
--]]
l.entryLua = function(poke, gen, kind)
local funcDict = l.dicts[kind]
local res = {}
local pmkind = pokemoves[poke][kind]
if pmkind and pmkind[gen] then
res = funcDict.dataMap(pmkind[gen],
function(v, k) return funcDict.processData(poke, gen, v, k) end)
end
local resstr
if #res == 0 then
resstr = lib.entrynull(kind, "100")
else
table.sort(res, funcDict.lt)
resstr = wlib.mapAndConcat(res, "\n", function(val)
return funcDict.makeEntry(poke, gen, val)
end)
end
return l.addhf(resstr, poke, gen, kind)
end
l.dicts = {}
--[[
Given a frame for learnlist returns the two parameters poke and gen, in this
order.
--]]
l.getParams = function(frame)
local p = lib.sanitize(mw.clone(frame.args))
local gen = tonumber(p.gen) or gendata.latest
local form = p.form or ""
local poke = mw.text.decode(p[1] or mw.title.getCurrentTitle().baseText):lower()
return poke .. form, gen
end
--[[
Adds main lua and WikiCode interfaces for a kind of entries.
Arguments:
- kind: the kind of entry
Lua interfaces take two arguments, poke and gen.
WikiCode interfaces are described in the initial comment.
--]]
local addInterfaces = function(kind)
l[kind .. "Lua"] = function(poke, gen)
return l.entryLua(poke, gen, kind)
end
l[kind] = function(frame)
local poke, gen = l.getParams(frame)
return l.entryLua(poke, gen, kind)
end
l[string.fu(kind)] = l[kind]
end
-- ================================== Level ==================================
--[[
This table hold texts used when a Pokémon can't learn a move in a game. It is
guaranteed to have the very same structure as pokemoves.games.level
--]]
l.nogameText = {
[1] = {
"Disponibile solo in Giallo",
"Disponibile solo in Rosso e Blu"
},
[2] = {
"Disponibile solo in Cristallo",
"Disponibile solo in Oro e Argento"
},
[3] = {
"Non disponibile in Rubino e Zaffiro",
"Non disponibile in Rosso Fuoco e Verde Foglia",
"Non disponibile in Smeraldo"
},
[4] = {
"Non disponibile in Diamante e Perla",
"Non disponibile in Platino",
"Non disponibile in Oro HeartGold e Argento SoulSilver"
},
[5] = {
"Disponibile solo in Nero 2 e Bianco 2",
"Disponibile solo in Nero e Bianco"
},
[6] = {
"Disponibile solo in Rubino Omega e Zaffiro Alpha",
"Disponibile solo in X e Y"
},
[7] = {
"Disponibile solo in Ultrasole e Ultraluna",
"Disponibile solo in Sole e Luna"
},
[8] = {
"",
}
}
--[[
Creates and entry of a level learnlist.
Arguments:
- poke: Pokémon name or ndex
- gen: set of game for this entry. Should be an index of
pokemoves.games.level
- move: move name
- levels: the set of levels to print. It should be in the following format:
an array, of the same length ad pokemoves.games.level[gen], with each
element being either a level (a number, "inizio" or "evo") or false,
meaning that the Pokémon can't learn the move in that game
--]]
l.levelEntry = function(poke, gen, move, levels)
levels = table.map(l.nogameText[gen], function(text, idx)
local lvl = levels[idx]
if not lvl then
return links.tt('—', text)
elseif lvl == "evo" then
return STRINGS.evolevelstr
else
return string.fu(lvl)
end
end)
return table.concat{
'|-\n',
lib.gameslevel(unpack(levels)),
l.entrytail(poke, move, '', gen),
}
end
-- Compares two levels (a number, "inizio", "evo" or nil). The order is
-- "inizio" < "evo" < numbers < nil
l.ltLevel = function(a, b)
if b == "inizio" then
return false
elseif b == "evo" and a ~= "inizio" then
return false
elseif b == nil then
return a ~= nil
elseif (type(a) == "number" and a >= b) or a == nil then -- b is a number
return false
end
return true
end
--[[
Comparator for levels. Given two levels tables, that are two arrays of the same
length with each element being either a level (a number, "inizio" or "evo") or
false, it returns true iff a <= b.
Sorting is lexicographic on levels, replacing false with the first subsequent
non-false value.
TODO: make this function more efficient
--]]
l.ltLevelarr = function(a, b)
for k, v in ipairs(a[2]) do
local aval, k1 = v, k
-- Can't use (not aval) because that is true also for nil
while aval == false do
k1 = k1 + 1
aval = a[2][k1]
end
local bval, k2 = b[2][k], k
while bval == false do
k2 = k2 + 1
bval = b[2][k2]
end
if l.ltLevel(aval, bval) then
return true
elseif aval ~= bval then -- if they aren't equale then bval > aval
return false
end
end
-- here aval == bval at any iteration => equality => check name
return a[1] < b[1]
end
l.dicts.level = {
processData = function(_, gen, levels, move)
levels = l.decompressLevelEntry(levels, gen)
-- levels = { {"inizio"}, {"inizio", "evo"} },
local alllevels = table.unique(table.flatten(levels))
return table.map(alllevels, function(lvl)
return { move, table.map(levels, function(t)
return table.search(t, lvl) and lvl or false
end) }
end)
end,
dataMap = table.flatMapToNum,
-- elements of res are like
-- {
-- <movename>,
-- { <level of first game or false>, <level of second game or false>, ... },
-- }
lt = l.ltLevelarr,
makeEntry = function(poke, gen, val)
return l.levelEntry(poke, gen, unpack(val))
end,
}
addInterfaces("level")
-- ==================================== Tm ====================================
--[[
Creates an entries of a tm learnlist.
Arguments:
- poke: Pokémon name or ndex
- gen: generation for this entry
- move: move name, all lowercase
- tmnum: tm or hm number. Is a pair { "M[TN]", "<number>" }
- games: (optional) the abbr of a game, that is put as a note in sup
--]]
l.tmEntry = function(poke, gen, move, tmnum, games)
local tmcell = string.interp(STRINGS.tmcell, {
img = tmnum[1],
p1 = table.concat(tmnum),
tipo = string.fu(multigen.getGenValue(moves[move].type, gen))
or 'Sconosciuto'
})
return table.concat{
'|-\n',
tmcell,
l.entrytail(poke, move, sup[games:upper()] or "", gen),
}
end
--[[
Comparator for two tm/hm pairs.
--]]
l.ltTm = function(a, b)
return a[1] > b[1] or (a[1] == b[1] and tonumber(a[2]) < tonumber(b[2]))
end
l.dicts.tm = {
processData = function(_, gen, move)
return table.mapToNum(mtdata[gen], function(tmdata, tmkind)
local tmnum, i = table.deepSearch(tmdata, move)
if tmnum then
local tmnums = string.nFigures(tmnum, 2)
if i then
return { move, { tmkind, tmnums }, tmdata[tmnum][i][1] }
else
return { move, { tmkind, tmnums }, "" }
end
end
-- Needed because otherwise the function returns 0 values and
-- table.insert complains (there's no automatic addition of nils)
return nil
end)
end,
dataMap = table.flatMapToNum,
-- elements of res are like
-- { <movename>, { "M[TN]", "12"}, <games abbr> }
lt = function(a, b)
return l.ltTm(a[2], b[2])
end,
makeEntry = function(poke, gen, val)
return l.tmEntry(poke, gen, unpack(val))
end,
}
-- Added by hand to handle the special case with all tms
l.tmLua = function(poke, gen)
if pokemoves[poke].tm[gen].all then
return l.addhf(hf.alltm{args={poke, gen, "tm"}}, poke, gen, "tm")
end
return l.entryLua(poke, gen, "tm")
end
l.tm = function(frame)
return l.tmLua(l.getParams(frame))
end
l.Tm = l.tm
-- addInterfaces("tm")
-- ================================== Breed ==================================
l.dicts.breed = {
processData = function(_, gen, movedata, move)
--Bulba style: in a Pokémon page it prints parents for the latest game
local parents = lib.moveParentsGame(movedata,
lib.games.breed[gen][#lib.games.breed[gen]])
local notes = movedata.notes or l.breednotes(gen, move, parents[1])
local res = { move, parents[1] and parents or { 000 },
notes == "" and "" or links.tt("*", string.fu(notes))
}
if movedata.games then
res[3] = wlib.mapAndConcat(movedata.games,
function(s) return sup[s] end)
.. res[3]
end
return res
end,
dataMap = table.mapToNum,
-- elements of res are like
-- { <movename>, { <array of parents> }, <notes> }
lt = function(a, b)
return a[1] < b[1]
end,
makeEntry = function(poke, gen, val)
local firstcell = string.interp(STRINGS.breedcell, {
p = lib.msarrayToModal(val[2], gen, nil, 6),
})
return table.concat{
'|-\n',
firstcell,
l.entrytail(poke, val[1], val[3], gen),
}
end,
}
addInterfaces("breed")
-- ================================== Tutor ==================================
l.dicts.tutor = {
processData = function(_, gen, games, move)
return {
move,
table.zip(lib.games.tutor[gen], games, function(a, b)
return { a, b and "Yes" or "No" }
end)
}
end,
dataMap = table.mapToNum,
-- elements of res are like
-- { <movename>, { <array of games pairs { <abbr>, "Yes"/"No" }> } }
lt = function(a, b)
for k, v in ipairs(a[2]) do
if v[2] ~= b[2][k][2] then
-- Equivalent to v[2] < b[2][k][2]
return v[2] == "Yes"
end
end
return a[1] < b[1]
end,
makeEntry = function(poke, _, val)
return table.concat{
'|-\n',
lib.tutorgames(val[2]),
l.entrytail(poke, val[1], "", gen),
}
end,
}
addInterfaces("tutor")
-- ================================== Preevo ==================================
l.dicts.preevo = {
processData = function(_, _, preevos, move)
return { move, table.map(preevos, function(ndex)
return { ndex, "" }
end, ipairs), games = preevos.games }
end,
dataMap = table.mapToNum,
-- elements of res are like
-- { <movename>, { <array of preevo pairs: { ndex, notes }> } }
lt = function(a, b)
return a[1] < b[1]
end,
makeEntry = function(poke, gen, val)
local firstcell = wlib.mapAndConcat(val[2], function(pair)
return ms.staticLua(string.tf(pair[1] or "000"), gen or "")
.. (lib.preevott[pair[2]] or "")
end)
local notes = val.games
and wlib.mapAndConcat(val.games, function(s) return sup[s] end)
or ""
return table.concat{
"|-\n| ",
firstcell,
l.entrytail(poke, val[1], notes, gen),
}
end,
}
addInterfaces("preevo")
-- ================================== Event ==================================
l.dicts.event = {
processData = function(_, _, occasion, move)
return { move, occasion }
end,
dataMap = table.mapToNum,
-- elements of res are like
-- { <movename>, <occasion> }
lt = function(a, b)
return a[1] < b[1]
end,
makeEntry = function(poke, gen, val)
local firstcell = string.interp(STRINGS.breedcell, {
p = val[2],
})
return table.concat{
'|-\n',
firstcell,
l.entrytail(poke, val[1], "", gen),
}
end,
}
addInterfaces("event")
-- ============================================================================
return l