Terraria Wiki
Terraria Wiki
(more test)
Aucun résumé des modifications
Ligne 115 : Ligne 115 :
 
if item == 'Bois' or item == 'Ébène' or item == 'Acajou riche' or item == 'Bois perlé' or item == 'Bois d\'ombre'
 
if item == 'Bois' or item == 'Ébène' or item == 'Acajou riche' or item == 'Bois perlé' or item == 'Bois d\'ombre'
 
or item == 'Bois sinistre' or item == 'Bois boréal' or item == 'Palmier' then
 
or item == 'Bois sinistre' or item == 'Bois boréal' or item == 'Palmier' then
return 'N\'importe quel Bois'
+
return 'Any Bois'
 
elseif item == 'Lingot de fer' or item == 'Lingot de plomb' then
 
elseif item == 'Lingot de fer' or item == 'Lingot de plomb' then
return 'N\'importe quel Lingot de fer'
+
return 'Any Lingot de fer'
 
elseif item == 'Bloc de sable' or item == 'Bloc de sable perlé' or item == 'Bloc de sable carmin' or item == 'Bloc de sable d\'ébène' or item == 'Bloc de sable durci' then
 
elseif item == 'Bloc de sable' or item == 'Bloc de sable perlé' or item == 'Bloc de sable carmin' or item == 'Bloc de sable d\'ébène' or item == 'Bloc de sable durci' then
return 'N\'importe quel Sable'
+
return 'Any Sable'
 
elseif item == 'Plaque de pression rouge' or item == 'Plaque de pression verte' or item == 'Plaque de pression grise' or item == 'Plaque de pression marron'
 
elseif item == 'Plaque de pression rouge' or item == 'Plaque de pression verte' or item == 'Plaque de pression grise' or item == 'Plaque de pression marron'
 
or item == 'Plaque de pression bleue' or item == 'Plaque de pression jaune' or item == 'Plaque de pression en lihzahrd' then
 
or item == 'Plaque de pression bleue' or item == 'Plaque de pression jaune' or item == 'Plaque de pression en lihzahrd' then
return 'N\'importe quelle Plaque de pression'
+
return 'Any Plaque de pression'
 
elseif item == 'Oiseau' or item == 'Geai bleu' or item == 'Cardinal' then
 
elseif item == 'Oiseau' or item == 'Geai bleu' or item == 'Cardinal' then
return 'N\'importe quel Oiseau'
+
return 'Any Oiseau'
 
elseif item == 'Scorpion noir' or item == 'Scorpion' then
 
elseif item == 'Scorpion noir' or item == 'Scorpion' then
return 'N\'importe quel Scorpion'
+
return 'Any Scorpion'
 
elseif item == 'Écureuil' or item == 'Écureuil roux' then
 
elseif item == 'Écureuil' or item == 'Écureuil roux' then
return 'N\'importe quel Écureuil'
+
return 'Any Écureuil'
 
elseif item == 'Grimace' or item == 'Coriace' or item == 'Limace' then
 
elseif item == 'Grimace' or item == 'Coriace' or item == 'Limace' then
return 'N\'importe quel Insecte'
+
return 'Any Insecte'
 
elseif item == 'Canard colvert' or item == 'Canard' then
 
elseif item == 'Canard colvert' or item == 'Canard' then
return 'N\'importe quel Canard'
+
return 'Any Canard'
 
elseif item == 'Piéride des jardins' or item == 'Papillon Julia' or item == 'Monarque' or item == 'Grand Mars changeant'
 
elseif item == 'Piéride des jardins' or item == 'Papillon Julia' or item == 'Monarque' or item == 'Grand Mars changeant'
 
or item == 'Vulcain' or item == 'Idea malabarica' or item == 'Papilio ulysses' or item == 'Eurytides marcellus' then
 
or item == 'Vulcain' or item == 'Idea malabarica' or item == 'Papilio ulysses' or item == 'Eurytides marcellus' then
return 'N\'importe quel Papillon'
+
return 'Any Papillon'
 
elseif item == 'Luciole' or item == 'Ver luisant' then
 
elseif item == 'Luciole' or item == 'Ver luisant' then
return 'N\'importe quelle Luciole'
+
return 'Any Luciole'
 
elseif item == 'Escargot' or item == 'Escargot luisant' then
 
elseif item == 'Escargot' or item == 'Escargot luisant' then
return 'N\'importe quel Escargot'
+
return 'Any Escargot'
 
end
 
end
 
end
 
end

Version du 16 janvier 2019 à 04:05

Voir aussi la page anglaise du module : Module:Recipes. Elle pourra contenir des informations plus complètes et actuelles.

Aucune sous-page de documentation n'existe déjà pour ce module. En créer une maintenant.


local item_link = require('Module:Item').go
local trim = mw.text.trim
local cargo = mw.ext.cargo

local currentFrame -- global cache for current frame object.
local inputArgs -- global args cache.

local extCols_stationBefore = nil
local extCols_stationAfter = nil

local extCols_A = nil
local extCols_B = nil
local extCols_C = nil
local extCols_D = nil

function getArg(key)
	local v = trim(inputArgs[key] or '')
	if v=='' then
		return nil
	else
		return v
	end
end

local itemLink = function(name, args)
	local args = args or {}
	args[1] = name
	args['small'] = 'y'
	return item_link(currentFrame, args)
end

-- credit: http://richard.warburton.it
-- this version is with trim.
local explode = function(div,str) 
	if (div=='') then return false end
	local pos,arr = 0,{}
	-- for each divider found
	for st,sp in function() return string.find(str,div,pos,true) end do
		table.insert(arr, trim(string.sub(str,pos,st-1))) -- Attach chars left of current divider
		pos = sp + 1 -- Jump past current divider
	end
	table.insert(arr, trim(string.sub(str,pos))) -- Attach chars right of last divider
	return arr
end

-- retuan a array of itemname, split xxx/yyy to item1=xxx, item2=yyy. If it's something like "Lead/Iron Bar", it will normalize as item1 = Iron Bar, item2 = Lead Bar.
local split = (function()
	local metals = {
		['cuivre/étain'] = 1,
		['argent/tungstène'] = 1,
		['or/platine'] = 1,
		['fer/plomb'] = 1,
		['cobalt/palladium'] = 1,
		['mithril/orichalque'] = 1,
		['adamantite/titane'] = 1,
		['étain/cuivre'] = 2,
		['tungstène/argent'] = 2,
		['platine/or'] = 2,
		['plomb/argent'] = 2,
		['palladium/cobalt'] = 2,
		['orichalque/mithril'] = 2,
		['titane/adamantite'] = 2,
	}
	return function(name)
		local count = select(2, name:gsub("/", "/", 2))
		if count == 0 then
			-- only 1 item
			return { trim(name) }
		elseif count == 1 then
			-- 2 items
			local item1a, item1b, item2a, item2b = name:match("^%s*(%S+)%s*(.-)/%s*(%S+)%s*(.-)$")
			local x = metals[item1a..'/'..item2a]
			if tostring(item1b) == '' and x then
				item1b = item2b
			end
			if x == 2 then
				return {trim(item2a..' '..item2b), trim(item1a..' '..item1b)}
			else
				return {trim(item1a..' '..item1b), trim(item2a..' '..item2b)}
			end
		else
			-- 3 or more items
			return explode('/', name)
		end
	end
end)()

-- return 1 or 2 value(s), when input is name[note], return item, note.
local itemname = function(str)
		local item, note = str:match("^(.-)(%b[])$")
		if item then
			return item, note
		else
			return str
		end
end

-- normalize ingredient name input, Lead Bar=>¦Lead Bar¦, Iron/Lead Bar => ¦Iron Bar¦Lead Bar¦, Lead/Iron Bar => ¦Iron Bar¦Lead Bar¦ ....
local normalize = function(name)
	local result = '¦'
	for k, v in ipairs(split(name)) do
		result = result .. itemname(v) .. '¦'
	end
	return result
end

local escape = function(str)
	return str:gsub("'", "\\'"):gsub("'", "\\'")
end
local enclose = function(str)
	return "'" .. escape(str) .. "'"
end

local getItemGroupName = function(item)
	if item == 'Bois' or item == 'Ébène' or item == 'Acajou riche' or item == 'Bois perlé' or item == 'Bois d\'ombre'
	or item == 'Bois sinistre' or item == 'Bois boréal' or item == 'Palmier' then
		return 'Any Bois'
	elseif item == 'Lingot de fer' or item == 'Lingot de plomb' then
		return 'Any Lingot de fer'
	elseif item == 'Bloc de sable' or item == 'Bloc de sable perlé' or item == 'Bloc de sable carmin' or item == 'Bloc de sable d\'ébène' or item == 'Bloc de sable durci' then
		return 'Any Sable'
	elseif item == 'Plaque de pression rouge' or item == 'Plaque de pression verte' or item == 'Plaque de pression grise' or item == 'Plaque de pression marron'
	    or item == 'Plaque de pression bleue' or item == 'Plaque de pression jaune' or item == 'Plaque de pression en lihzahrd' then
		return 'Any Plaque de pression'
	elseif item == 'Oiseau' or item == 'Geai bleu' or item == 'Cardinal' then
		return 'Any Oiseau'
	elseif item == 'Scorpion noir' or item == 'Scorpion' then
		return 'Any Scorpion'
	elseif item == 'Écureuil' or item == 'Écureuil roux' then
		return 'Any Écureuil'
	elseif item == 'Grimace' or item == 'Coriace' or item == 'Limace' then
		return 'Any Insecte'
	elseif item == 'Canard colvert' or item == 'Canard' then
		return 'Any Canard'
	elseif item == 'Piéride des jardins' or item == 'Papillon Julia' or item == 'Monarque' or item == 'Grand Mars changeant' 
	    or item == 'Vulcain' or item == 'Idea malabarica' or item == 'Papilio ulysses' or item == 'Eurytides marcellus' then
		return 'Any Papillon'
	elseif item == 'Luciole' or item == 'Ver luisant' then
		return 'Any Luciole'
	elseif item == 'Escargot' or item == 'Escargot luisant' then
		return 'Any Escargot'
	end
end

local normalizeStation = function(station)
	if station == 'Autel' then
		station = 'Autel démoniaque'
	end
	return station
end

local normalizeVersion = function(_version)
	local _version = trim(_version):lower()
	local version = ''
	if _version:find('desktop', 1, true) then
		version = version .. ' desktop'
	end
	if _version:find('console', 1, true) then
		version = version .. ' console'
	end
	if _version:find('old-gen', 1, true) then
		version = version .. ' old-gen'
	end
	if _version:find('japan', 1, true) then
		version = version .. ' japan'
	end
	if _version:find('mobile', 1, true) then
		version = version .. ' mobile'
	end
	if _version:find('3ds', 1, true) then
		version = version .. ' 3ds'
	end
	if version == ' desktop console old-gen mobile 3ds' then
		version = ''
	end
	return trim(version)
end

local criStr = function(args)
	local constraints = {}
	-- station = ? and station != ?
	local _station = trim(args['station'] or '')
	local _stationnot = trim(args['stationnot'] or '')
	local str = ''
	if _station ~= '' then
		for _, v in ipairs(explode('/', _station)) do
			if str ~= '' then
				str = str .. ' OR '
			end
			str = str .. "station = " .. enclose(normalizeStation(v))
		end
	end
	if _stationnot ~= '' then
		if str ~= '' then
			str = '(' .. str .. ')'
		end
		for _, v in ipairs(explode('/', _stationnot)) do
			if str ~= '' then
				str = str .. ' AND '
			end
			str = str .. 'station <> ' .. enclose(normalizeStation(v))
		end
	end
	constraints['station'] = str
	-- result = ? and result != ?
	local _result = trim(args['result'] or '')
	local _resultnot = trim(args['resultnot'] or '')
	local str = ''
	if _result ~= '' then
		for _, v in ipairs(explode('/', _result)) do
			if str ~= '' then
				str = str .. ' OR '
			end
			if mw.ustring.sub(v, 1, 5) == 'LIKE ' then
				str = str .. "result LIKE " .. enclose(trim(mw.ustring.sub(v, 6)))
			else
				str = str .. 'result=' .. enclose(v)
			end
		end
	end
	if _resultnot ~= '' then
		if str ~= '' then
			str = '(' .. str .. ')'
		end
		for _, v in ipairs(explode('/', _resultnot)) do
			if str ~= '' then
				str = str .. ' AND '
			end
			if mw.ustring.sub(v, 1, 5) == 'LIKE ' then
				str = str .. "result NOT LIKE " .. enclose(trim(mw.ustring.sub(v, 6)))
			else
				str = str .. 'result <> ' .. enclose(v)
			end
		end
	end
	if str ~= '' then
		constraints['result'] = str
	end
	-- ingredient = ?
	local _ingredient = trim(args['ingredient'] or '')
	if _ingredient ~= '' then
		local str = ''
		for _, v in ipairs(explode('/', _ingredient)) do
			if str ~= '' then
				str = str .. ' OR '
			end
			if mw.ustring.sub(v, 1, 1) == '#' then
				str = str .. "ingredients HOLDS LIKE '%¦" .. escape(mw.ustring.sub(v, 2)) .. "¦%'"
			elseif mw.ustring.sub(v, 1, 5) == 'LIKE ' then
				str = str .. "ingredients HOLDS LIKE '%¦" .. escape(trim(mw.ustring.sub(v, 6))) .. "¦%'"
			else
				str = str .. "ingredients HOLDS LIKE '%¦" .. escape(v) .. "¦%'"
				-- any xxx
				local group = getItemGroupName(v)
				if group then
					str = str .. " OR ingredients HOLDS LIKE '%¦" .. escape(group) .. "¦%'"
				end
			end
		end
		constraints['ingredient'] = str
	end

	--versions
	local _version = normalizeVersion(args['version'] or args['versions'] or '')
	if _version ~= '' then
		constraints['version'] = 'version = '..enclose(_version)
	end

	local where = ''
	if constraints['station'] then
		where = constraints['station']
	end
	if constraints['result'] then
		if where ~= '' then
			where = where .. ' AND '
		end
		where = where .. '(' .. constraints['result'] .. ')'
	end
	if constraints['ingredient'] then
		if where ~= '' then
			where = where .. ' AND '
		end
		where = where .. '(' .. constraints['ingredient'] .. ')'
	end
	if constraints['version'] then
		if where ~= '' then
			where = where .. ' AND '
		end
		where = where .. '(' .. constraints['version'] .. ')'
	end
	return where
end

local resultCell = function(row, showResultId, needLink, noVersion)
	local result, resultid, resultimage, resulttext, amount, version = row['result'], row['resultid'], row['resultimage'], row['resulttext'], row['amount'], row['version']
	local str = ''
	local args = {nolink = not needLink, class='multi-line'}
	if showResultId then
		args['id'] = resultid
	end
	if resultimage then
		args['image'] = resultimage
	end
	if resulttext then
		args[2] = resulttext
	end
	str = str .. itemLink(result, args)
	if amount ~= '1' then
		str = str .. ' <span class="note-text">('..amount..')</span>'
	end
	if not noVersion then
		if version ~= '' then
			str = str .. ' (' ..currentFrame:expandTemplate{ title = 'version icons', args = {version} }..')'
		end
	end
	return str
end

local ingredientsCell = function(args)
	local str = '<ul>'
	for _, v in ipairs(explode('^', args)) do
		str = str .. '<li>'
		local item, amount = v:match('^(.-)¦(.-)$')
		local s
		for _, itemname in ipairs(split(item)) do
			if s then
				s = s .. " ''or'' " .. itemLink(itemname)
			else
				s = itemLink(itemname)
			end
		end
		str = str .. s
		if amount ~= '1' then
			str = str .. ' <span class="note-text">('..amount..')</span>'
		end
		str = str .. '</li>'
	end
	str = str .. '</ul>'
	return str
end

local stationCell = function(station)
	if station == 'À la main' then
		return '[[À la main]]'
	elseif station == 'Four' or station == 'Établi' or station == 'Scierie' or station == "Atelier de bricolage" or station == 'Bac à teinture'
	  or station == 'Métier' or station == 'Fût' or station == 'Forge d\'enfer' or station == 'Bibliothèque' or station == 'Station d\'infusion' or station == 'Lave'
	  or station == 'Miel' or station == 'Four à verre' or station == 'Cuve à clonage de chair' or station == 'Marteau automatique' or station == 'Boule de cristal'
	  or station == 'Machine à glace' or station == 'Hachoir à viande' or station == 'Métier à bois vivant' or station == 'Établi lourd' or station == 'Moulin céleste'
	  or station == 'Solidificateur' or station == 'Distributeur de miel' or station == 'Soudeuse d\'os' or station == 'Mixomatique' or station == 'Chaudière steampunk'
	  or station == 'Manipulateur antique' or station == 'Lihzahrd Furnace' or station == 'Bois vivant' then
		return itemLink(station, {wrap = 'y'})
	elseif station == 'Enclume en fer' then
		return itemLink('Enclume en fer') .. "<br/>'''''ou'''''<br/>" .. itemLink('Enclume en plomb')
	elseif station == 'Forge en adamantite' then
		return itemLink('Forge en adamantite') .. "<br/>'''''ou'''''<br/>" .. itemLink('Forge en titane')
	elseif station == 'Enclume en mithril' then
		return itemLink('Enclume en mithril') .. "<br/>'''''ou'''''<br/>" .. itemLink('Enclume en orichalque')
	elseif station == 'Autel démoniaque' then
		return itemLink('Autel démoniaque') .. "<br/>'''''ou'''''<br/>" .. itemLink('Autel carmin')
	elseif station == 'Marmite' then
		return itemLink('Marmite') .. "<br/>'''''ou'''''<br/>" .. itemLink('Chaudron')
	elseif station == 'Bouteille placée' then
		return itemLink('Bouteille placée') .. "<br/>'''''ou'''''<br/>" .. itemLink('Table d\'alchimie', {wrap = 'y'})
	elseif station == 'Eau' then
		return itemLink('Eau') .. "<br/>'''''ou'''''<br/>" .. itemLink('Évier', {wrap = 'y'})
	elseif station == 'Table et Chaise' then
		return itemLink('Table') .. " '''et''' " .. itemLink('Chaise')
	elseif station == 'Établi et Chaise' then
		return itemLink('Établi') .. " '''et''' " .. itemLink('Chaise')
	elseif station == 'Boule de cristal et Lave' then
		return itemLink('Boule de cristal') .. " '''et''' " .. itemLink('Lave')
	elseif station == 'Boule de cristal et Miel' then
		return itemLink('Boule de cristal') .. " '''et''' " .. itemLink('Miel')
	elseif station == 'Boule de cristal et Eau' then
		return itemLink('Boule de cristal') .. " '''et''' ".. '<span class="water">' .. itemLink('Eau') .. "<br/>'''''ou'''''<br/>" .. itemLink('Évier', {wrap = 'y'}) .. '</span>'
	elseif station == 'Moulin céleste et Eau' then
		return itemLink('Moulin céleste', {wrap = 'y'}) .. " '''et''' ".. '<span  class="water">' .. itemLink('Eau') .. "<br/>'''''ou'''''<br/>" .. itemLink('Évier', {wrap = 'y'}) .. '</span>'
	elseif station == 'Moulin céleste et Toundra' then
		return itemLink('Moulin céleste', {wrap = 'y'}) .. " '''et''' ".. '[[Toundra]]'
	elseif station == 'Bouteille placée seulement' then
		return itemLink('Bouteille placée')
	else
		return station
	end
end
-- for extract.
local compactStation = function(station)
	if station == 'À la main' then
		return ''
	elseif station == 'Four' or station == 'Établi' or station == 'Scierie' or station == "Atelier de bricoleur" or station == 'Bac à teinture'
	  or station == 'Métier' or station == 'Fût' or station == 'Forge d\'enfer' or station == 'Bibliothèque' or station == 'Station d\'infusion' or station == 'Lave'
	  or station == 'Miel' or station == 'Four à verre' or station == 'Cuve à clonage de chair' or station == 'Marteau automatique' or station == 'Boule de cristal'
	  or station == 'Machine à glace' or station == 'Hachoir à viande' or station == 'Métier à bois vivant' or station == 'Établi lourd' or station == 'Moulin céleste'
	  or station == 'Solidificateur' or station == 'Distributeur de miel' or station == 'Soudeuse d\'os' or station == 'Mixomatique' or station == 'Chaudière steampunk'
	  or station == 'Manipulateur antique' or station == 'Four de lihzahrd' or station == 'Bois vivant' then
		return ' @&thinsp;' .. itemLink(station, {mode = 'image'})
	elseif station == 'Enclume en fer' then
		return ' @&thinsp;' .. itemLink('Enclume en fer', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Enclume en plomb', {mode = 'image'})
	elseif station == 'Forge en adamantite' then
		return ' @&thinsp;' .. itemLink('Forge en adamantite', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Forge en titane', {mode = 'image'})
	elseif station == 'Enclume en mithril' then
		return ' @&thinsp;' .. itemLink('Enclume en mithril', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Enclume en orichalque', {mode = 'image'})
	elseif station == 'Autel démoniaque' then
		return ' @&thinsp;' .. itemLink('Autel démoniaque', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Autel carmin', {mode = 'image'})
	elseif station == 'Marmite' then
		return ' @&thinsp;' .. itemLink('Marmite', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Chaudron', {mode = 'image'})
	elseif station == 'Bouteille placée' then
		return ' @&thinsp;' .. itemLink('Bouteille placée', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Table d\'alchimie', {mode = 'image'})
	elseif station == 'Eau' then
		return ' @&thinsp;' .. itemLink('Eau', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Évier', {mode = 'image'})
	elseif station == 'Table and Chair' then
		return ' @&thinsp;' .. itemLink('Table', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;" .. itemLink('Chair', {mode = 'image'})
	elseif station == 'Établi and Chair' then
		return ' @&thinsp;' .. itemLink('Établi', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;" .. itemLink('Chair', {mode = 'image'})
	elseif station == 'Boule de cristal et Lave' then
		return ' @&thinsp;' .. itemLink('Boule de cristal', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;" .. itemLink('Lave', {mode = 'image'})
	elseif station == 'Boule de cristal et Miel' then
		return ' @&thinsp;' .. itemLink('Boule de cristal', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;" .. itemLink('Miel', {mode = 'image'})
	elseif station == 'Boule de cristal et Eau' then
		return ' @&thinsp;' .. itemLink('Boule de cristal', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;".. '(&thinsp;' .. itemLink('Eau', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Évier', {mode = 'image'}) .. '&thinsp;)'
	elseif station == 'Moulin céleste et Eau' then
		return ' @&thinsp;' .. itemLink('Moulin céleste', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;".. '(&thinsp;' .. itemLink('Eau', {mode = 'image'}) .. "&thinsp;/&thinsp;" .. itemLink('Évier', {mode = 'image'}) .. '&thinsp;)'
	elseif station == 'Moulin céleste et Toundra' then
		return ' @&thinsp;' .. itemLink('Moulin céleste', {mode = 'image'}) .. "&thinsp;&amp;&thinsp;".. '[[Toundra]]'
	elseif station == 'Bouteille placée seulement' then
		return ' @&thinsp;' .. itemLink('Bouteille placée', {mode = 'image'})
	else
		return ' @&thinsp;' .. station
	end
end

local getFlags = function(args)
	local needCate = 1
	local needLink = true
	local _cate = trim(args['cate'] or '')
	if _cate == 'force' or _cate == 'all' then
		needCate = 2
	elseif _cate == 'n' or _cate == 'no' then
		needCate = nil
	end
	local _link = trim(args['link'] or '')
	if _link == 'y' or _link == 'yes' or _link == 'force' then
		needLink = true
	elseif _link == 'n' or _link == 'no' then
		needLink = false
	end
	return needCate, needLink
end


local addCate, cateStr = (function() 
	local cate = {
		['Enclume en plomb'] = 'Enclume en fer ou en plomb',
		['Enclume en fer'] = 'Enclume en fer ou en plomb',
		['Enclume en orichalque'] = 'Enclume en mithril ou en orichalque',
		['Enclume en mithril'] = 'Enclume en mithril ou en orichalque',
		['Autel démoniaque'] =  'Autel démoniaque ou carmin',
		['Autel carmin'] = 'Autel démoniaque ou carmin',
		['Autel'] = 'Autel démoniaque ou carmin',
		['Forge en titane'] = 'Forge en adamantite ou en titane',
		['Forge en adamantite'] = 'Forge en adamantite ou en titane',
		['Chaudron'] = 'Marmite ou Chaudron',
		['Marmite'] = 'Marmite ou Chaudron',
		['Bouteille seulement'] = 'Bouteille placée',
		['Bouteille placée seulement'] = 'Bouteille placée',
		['Bottle'] = 'Bouteille placée ou Table d\'alchimie',
		['Bouteille placée'] = 'Bouteille placée ou Table d\'alchimie',
		['Table d\'alchimie'] = 'Bouteille placée ou Table d\'alchimie',
		['Eau'] = 'Eau ou Évier',
		['Évier'] = 'Eau ou Évier',
		['Boule de cristal et Eau'] = 'Boule de cristal et Eau ou Évier',
		['Moulin céleste et Eau'] = 'Moulin céleste et Eau ou Évier',
	}
	local cateCache = {}
	local addCate = function(station)
		cateCache[station] = true
	end
	local cateStr = function()
		local str = ''
		for station, _ in pairs(cateCache) do
			str = str .. '[[Catégorie:'..(cate[station] or station)..']]'
		end
		if str ~= '' then
			str = '[[Catégorie:Objets façonnables]]' .. str
		end
		return str
	end
	return addCate, cateStr
end)()

local tableStart = function(title, withStation)
	local header_
	local str = '<div class="crafts '.. (getArg('class') or '')
	local _id = (getArg('id') or '')
	if _id ~= '' then
		str = str .. '" id="'.. _id
	end
	local _css = (getArg('css') or getArg('style') or '')
	if _css ~= '' then
		str = str .. '" style="'.. _css
	end
	str = str .. '"><div class="wrap"><table '
	if (getArg('sortable') or 'y'):sub(1,1) ~= 'n' then
		str = str .. 'class="sortable" '
	end
	str = str .. 'cellpadding="0" cellspacing="0">'
	if title ~= '' then
		str = str .. '<caption>' .. title .. '</caption>'
	end

	local _i, _field
	str = str .. '<tr>'
	_i = 1
	_field = 'col-A-1'
	while getArg(_field) do
		if not extCols_A then
			extCols_A = {}
		end
		table.insert(extCols_A, _field)
		str = str .. '<th>'.. getArg(_field) ..'</th>'
		_i = _i + 1
		_field = 'col-A-' .. _i
	end
	str = str .. '<th class="result">' .. (getArg('header-result') or 'Résultat') .. '</th>'
	_i = 1
	_field = 'col-B-1'
	while getArg(_field) do
		if not extCols_B then
			extCols_B = {}
		end
		table.insert(extCols_B, _field)
		str = str .. '<th>'.. getArg(_field) ..'</th>'
		_i = _i + 1
		_field = 'col-B-' .. _i
	end
	str = str .. '<th class="ingredients">' .. (getArg('header-ingredients') or 'Ingrédients') .. '</th>'
	_i = 1
	_field = 'col-C-1'
	while getArg(_field) do
		if not extCols_C then
			extCols_C = {}
		end
		table.insert(extCols_C, _field)
		str = str .. '<th>'.. getArg(_field) ..'</th>'
		_i = _i + 1
		_field = 'col-C-' .. _i
	end
	if withStation then
		_i = 1
		_field = 'station-col-before-1'
		while getArg(_field) do
			if not extCols_stationBefore then
				extCols_stationBefore = {}
			end
			table.insert(extCols_stationBefore, _field)
			str = str .. '<th class="station">'.. getArg(_field) ..'</th>'
			_i = _i + 1
			_field = 'station-col-before-' .. _i
		end
		str = str .. '<th class="station">' .. (getArg('header-station') or '[[Station de fabrication]]') .. '</th>'
		_i = 1
		_field = 'station-col-after-1'
		while getArg(_field) do
			if not extCols_stationAfter then
				extCols_stationAfter = {}
			end
			table.insert(extCols_stationAfter, _field)
			str = str .. '<th class="station">'.. getArg(_field) ..'</th>'
			_i = _i + 1
			_field = 'station-col-after-' .. _i
		end
	end
	_i = 1
	_field = 'col-D-1'
	while getArg(_field) do
		if not extCols_D then
			extCols_D = {}
		end
		table.insert(extCols_D, _field)
		str = str .. '<th>'.. getArg(_field) ..'</th>'
		_i = _i + 1
		_field = 'col-D-' .. _i
	end
	str = str .. '</tr>'
	return str
end

local tableEnd = function(rows_count, expectedrows)
	local str = '</table><div style="display: none">total: '..rows_count..' row(s)</div></div></div>'
	if expectedrows and rows_count ~= expectedrows then
		str = str .. '[[Category:Recipes table with unexcepted total number of rows]]'
	end
	if not expectedrows and rows_count == 0 then
		str = str .. '[[Category:Recipes table with no row]]'
	end
	return str
end

local tableRow = function(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, needLink, needGroup, current_result, result_count, current_result_ext, result_ext_count)
	local str_w = '' -- before result col
	local str_x = '' -- between result and ingredients cols
	local str_y = '' -- between ingredients and station cols
	local str_z = '' -- after station
	local str_resultCell = ''

	local result_index = getArg('result-index-#'..rows_count) or getArg('result-index-'..row['result']..'-'..row['version']) or getArg('result-index-'..row['result'])

	str = str .. '<tr data-rowid="'..tostring(rows_count)..'">'

	if needGroup then
		local result = row['result']..'|'..row['resultid']..'|'..row['resultimage']..'|'..row['resulttext']..'|'..row['amount']..'|'..row['version']
		-- grouping result col
		if current_result == result then -- is same group ??
			result_count = result_count + 1
		else
			--new group:
			-- rowspan value for prev group, if needed.
			if result_count then
				str = str:gsub("yyyrowspanyyy", tostring(result_count))
			end
			-- begin this group
			current_result = result
			result_count = 1
			str_resultCell = '<td class="result" rowspan="yyyrowspanyyy">'.. resultCell(row, showResultId, needLink).. '</td>'
		end
		-- grouping ext cols
		if result_index and (current_result_ext == result_index) then -- is same group ??
			result_ext_count = result_ext_count + 1
		else
			--new group:
			-- rowspan value for prev group, if needed.
			if result_ext_count then
				str = str:gsub("zzzrowspanzzz", tostring(result_ext_count))
			end
			-- begin this group
			current_result_ext = result_index
			result_ext_count = 1
			if extCols_A then
				for _, v in ipairs(extCols_A) do
					if result_index then
						str_w = str_w .. '<td rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
					else
						str_w = str_w .. '<td rowspan="zzzrowspanzzz"></td>'
					end
				end
			end
			if extCols_B then
				for _, v in ipairs(extCols_B) do
					if result_index then
						str_x = str_x .. '<td rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
					else
						str_x = str_x .. '<td rowspan="zzzrowspanzzz"></td>'
					end
				end
			end
			if extCols_C then
				for _, v in ipairs(extCols_C) do
					if result_index then
						str_y = str_y .. '<td rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
					else
						str_y = str_y .. '<td rowspan="zzzrowspanzzz"></td>'
					end
				end
			end
			if extCols_D then
				for _, v in ipairs(extCols_D) do
					if result_index then
						str_z = str_z .. '<td rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
					else
						str_z = str_z .. '<td rowspan="zzzrowspanzzz"></td>'
					end
				end
			end
		end
	else
		if extCols_A then
			for _, v in ipairs(extCols_A) do
				if result_index then
					str_w = str_w .. '<td>' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
				else
					str_w = str_w .. '<td></td>'
				end
			end
		end
		if extCols_B then
			for _, v in ipairs(extCols_B) do
				if result_index then
					str_x = str_x .. '<td>' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
				else
					str_x = str_x .. '<td></td>'
				end
			end
		end
		if extCols_C then
			for _, v in ipairs(extCols_C) do
				if result_index then
					str_y = str_y .. '<td>' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
				else
					str_y = str_y .. '<td></td>'
				end
			end
		end
		if extCols_D then
			for _, v in ipairs(extCols_D) do
				if result_index then
					str_z = str_z .. '<td>' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
				else
					str_z = str_z .. '<td></td>'
				end
			end
		end
		str_resultCell = '<td class="result">'.. resultCell(row, showResultId, needLink).. '</td>'
	end

	str = str .. str_w .. str_resultCell .. str_x .. '<td class="ingredients">' .. ingredientsCell(row['args']).. '</td>' .. str_y

	if withStation then
		local station = row['station']
		if current_station == station then -- is same group ??
			station_count = station_count + 1
		else
			--new group:
			-- rowspan value for prev group, if needed.
			if station_count then
				str = str:gsub("xxxrowspanxxx", tostring(station_count))
			end
			-- begin this group
			current_station = station
			station_count = 1
			local station_index = getArg('station-index-'..station)
			-- station before:
			if extCols_stationBefore then
				for _, v in ipairs(extCols_stationBefore) do
					if station_index then
						str = str .. '<td class="station" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
					else
						str = str .. '<td class="station" rowspan="xxxrowspanxxx"></td>'
					end
				end
			end
			str = str .. '<td class="station" rowspan="xxxrowspanxxx">'.. stationCell(station) ..'</td>'
			-- station after:
			if extCols_stationAfter then
				for _, v in ipairs(extCols_stationAfter) do
					if station_index then
						str = str .. '<td class="station" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
					else
						str = str .. '<td class="station" rowspan="xxxrowspanxxx"></td>'
					end
				end
			end
		end
	end

	str = str .. str_z ..'</tr>'
	return str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count
end

local extRows = function(withStation, isTop)
	local prefix
	if isTop then
		prefix = 'topextrow-'
	else
		prefix = 'extrow-'
	end
	local returnstr = ''
	local valid = true
	local p
	local str
	local _i = 1
	local temp
	while valid do
		local i = tostring(_i) .. '-'
		p = prefix .. i
		valid = false
		str = '<tr data-'..prefix..'id="'..tostring(_i)..'">'
		if extCols_A then
			for _, v in ipairs(extCols_A) do
				temp = getArg(p..v)
				if temp then
					valid = true
					str = str .. '<td>' .. temp .. '</td>'
				else
					str = str .. '<td></td>'
				end
			end
		end
		temp = getArg(p..'col-result')
		if temp then
			valid = true
			str = str .. '<td class="result">' .. temp .. '</td>'
		else
			str = str .. '<td class="result"></td>'
		end
		if extCols_B then
			for _, v in ipairs(extCols_B) do
				temp = getArg(p..v)
				if temp then
					valid = true
					str = str .. '<td>' .. temp .. '</td>'
				else
					str = str .. '<td></td>'
				end
			end
		end
		temp = getArg(p..'col-ingredients')
		if temp then
			valid = true
			str = str .. '<td class="ingredients">' .. temp .. '</td>'
		else
			str = str .. '<td class="ingredients"></td>'
		end
		if extCols_C then
			for _, v in ipairs(extCols_C) do
				temp = getArg(p..v)
				if temp then
					valid = true
					str = str .. '<td>' .. temp .. '</td>'
				else
					str = str .. '<td></td>'
				end
			end
		end
		if withStation then
			-- station before:
			if extCols_stationBefore then
				for _, v in ipairs(extCols_stationBefore) do
					temp = getArg(p..v)
					if temp then
						valid = true
						str = str .. '<td class="station">' .. temp .. '</td>'
					else
						str = str .. '<td class="station"></td>'
					end
				end
			end
			temp = getArg(p..'col-station')
			if temp then
				valid = true
				str = str .. '<td class="station">' .. temp .. '</td>'
			else
				str = str .. '<td class="station"></td>'
			end
			-- station after:
			if extCols_stationAfter then
				for _, v in ipairs(extCols_stationAfter) do
					temp = getArg(p..v)
					if temp then
						valid = true
						str = str .. '<td class="station">' .. temp .. '</td>'
					else
						str = str .. '<td class="station"></td>'
					end
				end
			end
		end
		if extCols_D then
			for _, v in ipairs(extCols_D) do
				temp = getArg(p..v)
				if temp then
					valid = true
					str = str .. '<td>' .. temp .. '</td>'
				else
					str = str .. '<td></td>'
				end
			end
		end
		str = str .. '</tr>'

		if valid then
			_i = _i + 1
			returnstr = returnstr .. str
		end
	end
	return returnstr
end


local tableBody = function(result, showResultId, withStation, needGroup, needCate, needLink, rootpagename, title, expectedrows)
		local str = tableStart(title, withStation)
		-- top ext rows:
		str = str .. extRows(withStation, true)
		-- main rows:
		local current_station
		local station_count
		local rows_count = 0
		local current_result
		local result_count
		local current_result_ext
		local result_ext_count
		for _, row in ipairs(result) do
			rows_count = rows_count + 1
			-- table row:
			str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count = tableRow(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, needLink, needGroup, current_result, result_count, current_result_ext, result_ext_count)
			-- cate:
			if needCate then
				if needCate == 2 or rootpagename == row['result'] then
					addCate(row['station'])
				end
			end
		end
		-- rowspan value for last station group and result group
		if station_count then
			str = str:gsub("xxxrowspanxxx", tostring(station_count))
		end
		if needGroup then
			str = str:gsub("yyyrowspanyyy", tostring(result_count))
			str = str:gsub("zzzrowspanzzz", tostring(result_ext_count))
		end
		-- ext rows:
		str = str .. extRows(withStation)
		-- table end
		str = str .. tableEnd(rows_count, expectedrows)

		-- cate
		if needCate then
			str = str .. cateStr()
		end

		return str
end
-----------------------------------------------------------------

local p = {}

-- for {{recipes/register}}
p.register = function(frame)
	local args = frame:getParent().args

	-- {{{ingredients}}}
	local ingredients = {} -- list of {index, itemname, amount}
	for k, v in pairs(args) do
		if(type(k) == 'number') then
			if k % 2 == 1 then  -- 2n-1, nth item
				local index, item, amount = (k+1)/2, trim(v), trim(args[k+1])
				ingredients[index] = {item, amount}
			end
		end
	end

	local serialized = '' -- serialized ingredients list
	for _, v in ipairs(ingredients) do
		serialized = serialized .. '^' .. v[1] .. '¦' .. v[2]
	end
	serialized = mw.ustring.sub(serialized, 2)

	table.sort(ingredients, function(a , b) return a[1] < b[1] end) -- sort by ingredient item name
	local ingredients_string = ''
	local ingredients_string_full = ''
	for _, v in ipairs(ingredients) do
		local name, amount = unpack(v)
		local ingstr = normalize(name)
		ingredients_string = ingredients_string .. '^' .. ingstr
		ingredients_string_full = ingredients_string_full .. '^' .. ingstr .. amount
	end

	--{{{version}}}, normalize
	version = normalizeVersion(args['version'] or '')

	--store
	frame:callParserFunction('#cargo_store:_table=Recipes',{
		result = trim(args['result'] or ''),
		resultid = trim(args['resultid'] or ''),
		resultimage = trim(args['image'] or ''),
		resulttext = trim(args['text'] or ''),
		amount = trim(args['amount'] or ''),
		version = version,
		station = normalizeStation(trim(args['station'] or '')), 
		ingredients = mw.ustring.sub(ingredients_string, 2),
		ings = mw.ustring.sub(ingredients_string_full, 2),
		args = serialized,
	})
end -- p.register

-- for {{recipes}}
p.query = function(frame)
	currentFrame = frame -- global frame cache
	local args = frame:getParent().args
	inputArgs = args

	local where = trim(args['where'] or '')
	if where == '' then
		where = criStr(args)
	end

	-- no constraint no result.
	if where == '' then
		return '<span style="color:red;font-weight:bold;">Recettes : Aucune contrainte</span>'
	end

	-- format:
	local needCate, needLink = getFlags(args)
	local needGroup = true
	if (getArg('grouping') or 'y'):sub(1,1) == 'n' then
		needGroup = false
	end
	local showResultId = false
	if trim(args['showresultid'] or '') ~= '' then
		showResultId = true
	end
	local _title = trim(args['title'] or '')
	local _expectedrows = trim(args['expectedrows'] or '')
	if _expectedrows ~= '' then
		_expectedrows = tonumber(_expectedrows)
	else
		_expectedrows = nil
	end
	local rootpagename = mw.title.getCurrentTitle().rootText

	if trim(args['nostation'] or '') ~= '' then
		-- no station
		-- query, still need contain station field for cate.
		local result = mw.ext.cargo.query('Recipes', 'result, resultid, resultimage, resulttext, amount, version, station, args', {
			where = where,
			groupBy = "resultid, result, amount, version, ings",
			orderBy = "result, amount DESC, version", -- Don't order by station
			limit = 2000,
		})
		return tableBody(result, showResultId, false, needGroup, needCate, needLink, rootpagename, _title, _expectedrows)
	else
		-- with station
		-- query
		local result = mw.ext.cargo.query('Recipes', 'result, resultid, resultimage, resulttext, amount, version, station, args', {
			where = where,
			groupBy = "resultid, result, amount, ings, version",
			orderBy = "station, result, amount DESC, version, ings", -- order by station first for station grouping.
			limit = 2000,
		})
		return tableBody(result, showResultId, true, needGroup, needCate, needLink, rootpagename, _title, _expectedrows)
	end
end -- p.query

-- for {{recipes/extract}}
p.extract = function(frame)
	currentFrame = frame -- global frame cache
	local args = frame:getParent().args
	inputArgs = args

	local where = trim(args['where'] or '')
	if where == '' then
		where = criStr(args)
	end

	-- no constraint no result.
	if where == '' then
		return '<span style="color:red;font-weight:bold;">Recipes/extract: No constraint</span>'
	end

	-- query:
	local result = mw.ext.cargo.query('Recipes', 'result, resultid, resultimage, resulttext, amount, version, station, args', {
		where = where,
		groupBy = "resultid, result, amount, version, ings",
		orderBy = "result, amount DESC, version", -- Don't order by station
		limit = 20, -- enough.
	})

	-- output
	local mode = getArg('mode')
	local sep = getArg('sep') or getArg('seperator')
	if not mode or mode =='compact' or mode == '' then
		--default mode = ingredients
		local sep = sep or "<br/>'''ou'''<br/>"
		local withResult = getArg('withresult')
		local withStation = not getArg('nostation')
		local str = nil
		for _, row in ipairs(result) do
			if str then
				str = str .. sep
			else
				str = ''
			end
			str = str .. '<span class="recipe compact">'
			local ingFlag = nil
			for _, v in ipairs(explode('^', row['args'])) do
				if ingFlag then
					str = str .. ' + '
				else
					ingFlag = true
				end
				local item, amount = v:match('^(.-)¦(.-)$')
				if amount ~= '1' then
					str = str .. amount .. ' '
				end				
				local s
				for _, itemname in ipairs(split(item)) do
					if s then
						s = s .. "&thinsp;/&thinsp;" .. itemLink(itemname, {mode='image'})
					else
						s = itemLink(itemname, {mode='image'})
					end
				end
				str = str .. s
			end
			if withStation then
				str = str .. compactStation(row['station'])
			end
			if withResult then
				str = str .. ' = '				
				if row['amount'] ~= '1' then
					str = str .. row['amount'] .. ' '
				end
				local args = {mode='image'}
				if row['resultimage'] then
					args['image'] = row['resultimage']
				end
				str = str .. itemLink(row['result'], args)
			end			
			str = str..'</span>'
		end
		return str
	elseif mode == 'ingredients' then
		local sep = sep or "'''or'''"
		local str = nil
		for _, row in ipairs(result) do
			if str then
				str = str .. sep
			else
				str = ''
			end
			str = str .. ingredientsCell(row['args'])
		end
		return '<div class="crafting-ingredients">'..str..'</div>'
	elseif mode == 'station' then
		-- only return first row.
		for _, row in ipairs(result) do
			return stationCell(row['station'])
		end
	elseif mode == 'result' then
		-- only return first row.
		local needCate, needLink = getFlags(args)
		for _, row in ipairs(result) do
			return resultCell(row, getArg('showresultid'), needLink, true)
		end
	else
		return '<span style="color:red;font-weight:bold;">Recipes/extract : Mode invalide</span>'
	end
end -- p.extract

return p