Terraria Wiki

Button See Issues.png
Des problèmes sur le wiki ?
  • Fichiers et icônes invisibles : Effacez le cache de la page en la purgeant (via « Purge » dans le menu déroulant « Plus » en haut à droite)
  • Vue étrange sur ordinateur : Vous utilisez probablement la vue mobile; cliquez sur « Voir le site complet » tout en bas pour utiliser de nouveau la vue ordinateur
    • Peut aussi être provoqué par un adblocker, tel que Ghostery, essayez de le désactiver sur le wiki
Si rien n'a fonctionné, n'hésitez pas à nous en faire part sur le portail de la communauté ou sur le serveur discord.

EN SAVOIR PLUS

Terraria Wiki
Terraria Wiki
m
 
(7 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
  +
---Holds the tables with the l10n information for the different languages, taken from the l10n submodule.
-- l10n text, needs to be translated.
 
local l10n = mw.loadData('Module:Exclusive/l10n')
+
local l10n_data = mw.loadData('Module:Exclusive/l10n')
   
  +
---Database with exclusivity info.
-- exclusive info database, please read the documentation of Module:Exclusive/data
 
local exclusive_info = mw.loadData( 'Module:Exclusive/data' )
+
local exclusive_info = mw.loadData('Module:Exclusive/data')
   
  +
local bit32 = require('bit32')
------- The following is not related to l10n. --------------
 
 
local trim = mw.text.trim
 
local trim = mw.text.trim
   
  +
---Default content language of the wiki (i.e. `$wgLanguageCode`, not the value of the
local args_table -- cache
 
  +
---`uselang` URL parameter, and not the user's language preference setting).
-- helper function
 
local getArg = function(key)
+
local contentLanguage = mw.getContentLanguage()
  +
  +
---Holds the arguments from the template call.
  +
local args_table
  +
  +
---The current language. Determines which l10n table to use.
  +
local lang
  +
  +
---Return the l10n string associated with the `key`.
  +
---@param key string
  +
---@return string
  +
local function l10n(key)
  +
if l10n_data[lang] then
  +
return l10n_data[lang][key] or l10n_data['en'][key]
  +
else
  +
return l10n_data['en'][key]
  +
end
  +
end
  +
  +
---Return a trimmed version of the value of the template parameter with the specified `key`.
  +
---Return `nil` if the parameter is empty or unset.
  +
---@param key string|number
  +
---@return string|nil
  +
local function getArg(key)
 
local value = trim(args_table[key] or '')
 
local value = trim(args_table[key] or '')
 
return (value ~= '') and value or nil
 
return (value ~= '') and value or nil
 
end
 
end
   
  +
---Convert a string of parameters in a `@param1:value^@param2:value^` format to a table.
local function parameter(parameter, base)
 
  +
---@param paramstr string
if parameter then
 
  +
---@return table
if parameter == '1' or parameter == 'y' or parameter == 'yes' then
 
  +
local function parse(paramstr)
return 'y'
 
  +
local args = {}
end
 
  +
for s in string.gmatch(paramstr, '%b@^') do
if parameter == '0' or parameter == 'n' or parameter == 'no' then
 
  +
local k,v = string.match(s, '^@(.-):(.*)^$')
return nil
 
  +
args[k] = v
end
 
 
end
 
end
return base
+
return args
 
end
 
end
   
  +
---Split the `str` on each `div` in it and return the result as a table.
local standAndExtr = function(page)
 
  +
---This is much much faster then `mw.text.split`.
-- standardize pagename (remove section parts ('x#section' -> 'x') and replace underscores with spaces)
 
  +
---Credit: http://richard.warburton.it.
page = mw.getContentLanguage():ucfirst(string.gsub(string.gsub(page or '', '#.*', ''), '_', ' '))
 
  +
---@param div string
 
  +
---@param str string
-- extract info
 
  +
---@return table|boolean
local raw, ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached = exclusive_info[page]
 
  +
local function explode(div,str)
if raw then
 
  +
if (div=='') then return false end
ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached = raw:find('d'), raw:find('c'), raw:find('o'), raw:find('m'), raw:find('3'), raw:find('j'), 'y'
 
  +
local pos,arr = 0,{}
  +
-- for each divider found
  +
for st,sp in function() return string.find(str,div,pos,true) end do
  +
arr[#arr + 1] = string.sub(str,pos,st-1) -- Attach chars left of current divider
  +
pos = sp + 1 -- Jump past current divider
 
end
 
end
  +
arr[#arr + 1] = string.sub(str,pos) -- Attach chars right of last divider
 
  +
return arr
return ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached
 
 
end
 
end
   
  +
---Return the integer defined in the database for the specified `page`.
local getInfo = function(page, invert, pagenot)
 
  +
---Perform some standardization on the `page` for that first.
local ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached = standAndExtr(page)
 
  +
---@param page string
  +
---@return number
  +
local function readFromDb(page)
  +
-- standardize pagename: remove section parts ('x#section' -> 'x') and replace underscores with spaces
  +
page = contentLanguage:ucfirst(string.gsub(string.gsub(page or '', '#.*', ''), '_', ' '))
  +
return exclusive_info[page] or 0
  +
end
   
  +
---Override the exclusivity information in `info`
-- invert?
 
  +
---with the content of `dcom3j`.
if invert then
 
  +
---@param info number
ex_d = not ex_d
 
  +
---@param dcom3j string Expected format: `<d>:<c>:<o>:<m>:<3>:<j>`, with each platform either a Boolean string ("y", "0", etc.) or an empty string
ex_c = not ex_c
 
  +
---@return number
ex_o = not ex_o
 
  +
local function override(info, dcom3j)
ex_m = not ex_m
 
  +
for k, v in pairs(explode(':', dcom3j)) do
ex_3 = not ex_3
 
ex_j = false
+
if v ~= '' then
  +
if v == '1' or v == 'y' or v == 'yes' then
end
 
  +
info = bit32.replace(info, 1, k-1)
 
  +
elseif v == '0' or v == 'n' or v == 'no' then
-- exclude some versions, depending on pagenot
 
  +
info = bit32.replace(info, 0, k-1)
if pagenot then
 
  +
end
local exnot_d, exnot_c, exnot_o, exnot_m, exnot_3, exnot_j = standAndExtr(pagenot)
 
  +
end
ex_d = ex_d and not exnot_d -- ex_d is true only when ex_d is set and exnot_d is not set.
 
ex_c = ex_c and not exnot_c
 
ex_o = ex_o and not exnot_o
 
ex_m = ex_m and not exnot_m
 
ex_3 = ex_3 and not exnot_3
 
 
end
 
end
  +
return info
   
  +
-- Example to demonstrate the behavior of this function:
return ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached
 
  +
-- Goal: Change "dcom" to "dco3".
  +
-- info = 15 ("dcom"), dcom3j = ":::no:yes:"
  +
-- decimal 15 = binary 001111
  +
-- The first "no" is at index 3 in the dcom3j string, so
  +
-- replace the corresponding bit with a 0: 001111 -> 000111.
  +
-- The "yes" is at index 4, so replace the bit at index 4
  +
-- with a 1: 000111 -> 010111.
  +
-- The result is info = 23 ("dco3").
 
end
 
end
   
  +
---Main function to retrieve exclusivity information.
local eicons = function(ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, _small, _link, lang)
 
  +
---@param page string The entity to get the info about.
 
  +
---@param invert boolean Whether to invert the exclusivity info.
local link = ''
 
  +
---@param pagenot string The entity whose exclusivity info to subtract from the main one's.
local space = false
 
  +
---@param dcom3j string Manual exclusivity info to override the fetched one with.
local size
 
  +
---@return number info An integer that holds the exclusivity information.
local result = ''
 
  +
local function getInfo(page, invert, pagenot, dcom3j)
local l10n = l10n[lang] or l10n['en']
 
  +
local info = 0
   
  +
-- A piece of exclusivity information is a set of Boolean values, one
-- compact mode only if nolink.
 
  +
-- for each platform. This is represented as bits of the `info` integer.
if link == '' then
 
  +
-- Each platform (Desktop, Console, Old-gen console, Mobile, 3DS,
if ex_d and ex_c and ex_o and ex_m and not ex_3 and not ex_j then
 
  +
-- and Japanese console – "dcom3j") is assigned one bit, in this order.
result =
 
  +
-- This means that, for instance, an `info` value of 1 would represent
'[[File:DCOM only.png|' .. (_small and 'x12' or 'x16') ..'px|link=|' .. l10n['icon_text_dcom'] .. ']]'
 
  +
-- Desktop-only exclusivity ("d"):
return mw.text.tag('span',{class='eico'}, result)
 
  +
-- decimal 1 = binary 000001
  +
-- j3mocd -> "d"
  +
-- Similarly, an `info` value of 20 would represent Old-gen and 3DS exclusivity ("o3"):
  +
-- decimal 20 = binary 010100
  +
-- j3mocd -> "o3"
  +
-- See Module:Exclusive/data for a quick overview of all values.
  +
  +
-- This system allows using bitwise operations (https://en.wikipedia.org/wiki/Bitwise_operation)
  +
-- instead of the formerly used string processing, resulting in much lower script execution times.
  +
  +
  +
-- get info about page
  +
if page then
  +
info = readFromDb(page)
  +
if invert then
  +
-- invert dcom3 and set j=0 (always force-off Japanese console when inverting)
  +
info = bit32.band(bit32.bnot(info), 31)
 
end
 
end
  +
if pagenot then
if ex_d and ex_c and not ex_o and ex_m and not ex_3 and not ex_j then
 
  +
-- exclude some versions, depending on pagenot
result =
 
  +
local info_not = readFromDb(pagenot)
'[[File:DCM only.png|' .. (_small and 'x12' or 'x16') ..'px|link=|' .. l10n['icon_text_dcm'] .. ']]'
 
  +
info = bit32.band(info, bit32.bnot(info_not))
return mw.text.tag('span',{class='eico'}, result)
 
end
 
if ex_d and ex_c and not ex_o and not ex_m and not ex_3 and not ex_j then
 
result =
 
'[[File:DC only.png|' .. (_small and 'x12' or 'x16') ..'px|link=|' .. l10n['icon_text_dc'] .. ']]'
 
return mw.text.tag('span',{class='eico'}, result)
 
end
 
if ex_d and not ex_c and not ex_o and ex_m and not ex_3 and not ex_j then
 
result =
 
'[[File:DM only.png|' .. (_small and 'x12' or 'x16') ..'px|link=|' .. l10n['icon_text_dm'] .. ']]'
 
return mw.text.tag('span',{class='eico'}, result)
 
 
end
 
end
  +
  +
-- The "invert" and "pagenot" functionalities above utilize
  +
-- bit masking (https://en.wikipedia.org/wiki/Mask_(computing)).
  +
-- The following example demonstrates the operations:
  +
-- 1. assume info=11 ("dcm", binary 001011)
  +
-- 2. invert:
  +
-- 2a. not(001011) = 110100 ("o3j", the inverse of "dcm")
  +
-- 2b. and(110100, 011111) = 010100 ("o3", forced-off "j")
  +
-- 3. assume info_not=4 ("o", binary 000100)
  +
-- 3a. not(000100) = 111011
  +
-- 3b. and(010100, 111011) = 010000 ("3")
  +
-- An initial exclusivity info of "dcm" was inverted to "o3",
  +
-- then "o" was subtracted from it, resulting in the final
  +
-- exclusivity information of "3".
 
end
 
end
   
  +
-- override if needed
if ex_d then
 
  +
if dcom3j == nil or dcom3j == ':::::' then
result =
 
  +
return info
'[[File:Desktop only.png|' .. (_small and '12' or '16') ..'px|link='
 
  +
else
.. (_link and l10n['icon_link_d'] or '') .. '|' .. l10n['icon_text_d'] .. ']]'
 
  +
return override(info, dcom3j)
space = true
 
 
end
 
end
if ex_c then
 
result = result .. (space and '&thinsp;' or '') ..
 
'[[File:Console only.png|' .. (_small and '13' or '17') ..'px|link='
 
.. (_link and l10n['icon_link_c'] or '') .. '|' .. l10n['icon_text_c'] .. ']]'
 
space = true
 
end
 
if ex_o then
 
result = result .. (space and '&thinsp;' or '') ..
 
'[[File:Old-Gen Console only.png|' .. (_small and 'x12' or 'x16') ..'px|link='
 
.. (_link and l10n['icon_link_o'] or '') .. '|' .. l10n['icon_text_o'] .. ']]'
 
space = true
 
end
 
if ex_m then
 
result = result .. (space and '&thinsp;' or '') ..
 
'[[File:Mobile only.png|' .. (_small and 'x12' or 'x16') ..'px|link='
 
.. (_link and l10n['icon_link_m'] or '') .. '|' .. l10n['icon_text_m'] .. ']]'
 
space = true
 
end
 
if ex_3 then
 
result = result .. (space and '&thinsp;' or '') ..
 
'[[File:3DS.svg|' .. (_small and '24' or '32') ..'px|link='
 
.. (_link and l10n['icon_link_3'] or '') .. '|' .. l10n['icon_text_3'] .. ']]'
 
space = true
 
end
 
if ex_j then
 
result = result .. (space and '&thinsp;' or '') ..
 
'[[File:Flag jp.svg|' .. (_small and '12' or '16') ..'px|link='
 
.. (_link and l10n['icon_link_j'] or '') .. '|' .. l10n['icon_text_j'] .. ']]'
 
end
 
return mw.text.tag('span',{class='eico'}, result)
 
 
end
 
end
   
  +
---Return an HTML span tag whose `class` attribute is set
local getExclusiveInfo = function(page, invert, pagenot)
 
  +
---according to the exclusivity `info`.
local ex_d, ex_c, ex_o, ex_m, ex_3, ex_j
 
  +
---@param info number
if page then
 
  +
---@param _small boolean Whether to add the "s" class, for small icons
ex_d, ex_c, ex_o, ex_m, ex_3, ex_j = getInfo(page, invert, pagenot)
 
  +
---@return string
  +
local function eicons(info, _small)
  +
local class = 'eico' .. (_small and ' s' or '')
  +
  +
if bit32.btest(info, 32) then
  +
-- Japanese console is set, so simply display that
  +
-- ("j" is always alone or not set at all – "dcj", for instance, doesn't exist)
  +
class = class .. ' j'
  +
local hovertext = l10n('text_j')
  +
return mw.text.tag('span', {class=class}, mw.text.tag('span', {title=hovertext}, ''))
 
end
 
end
 
-- override
 
ex_d = parameter(getArg('dsk'), ex_d)
 
ex_c = parameter(getArg('cns'), ex_c)
 
ex_o = parameter(getArg('old'), ex_o)
 
ex_m = parameter(getArg('mbl'), ex_m)
 
ex_3 = parameter(getArg('3ds'), ex_3)
 
ex_j = parameter(getArg('jas'), ex_j)
 
   
  +
-- for each platform of dcom3, add the class and load the hovertext if the platform if set
return ex_d, ex_c, ex_o, ex_m, ex_3, ex_j
 
  +
-- (e.g. for info=25 ("dm3"), append "i0 i3 i4" to the class and load the
  +
-- "text_0", "text_3", and "text_4" l10n strings)
  +
local v = {}
  +
for i = 0, 4 do
  +
if bit32.btest(info, 2^i) then
  +
class = class .. ' i' .. i
  +
v[#v+1] = l10n('text_' .. i)
  +
end
  +
end
  +
local hovertext = mw.text.listToText(v, l10n('list_separator'), l10n('list_conjunction'))
  +
hovertext = hovertext .. contentLanguage:convertPlural(#v, l10n('version_plural_forms'))
  +
return mw.text.tag('span', {class=class}, mw.text.tag('span', {title=hovertext}, ''))
 
end
 
end
   
  +
---Check if the `infoToCheck` integer is a valid number for output.
  +
---It is considered invalid if it represents an empty exclusivity ("")
  +
---or a "full" exclusivity, i.e. all platforms being set ("dcom3" or "dcom3j").
  +
---@param infoToCheck number
  +
---@return boolean
  +
local function infoIsInvalid(infoToCheck)
  +
return infoToCheck == 0 or infoToCheck == 31 or infoToCheck == 63
  +
end
   
  +
-----------------------------------------------------------------
  +
-- main return object
  +
return {
   
  +
-- for templates; get all exclusive info and set it in dplvars.
---------------------------------------------------------------------------------
 
  +
-- parameters: $1 = pagename
  +
getInfo = function(frame)
  +
args_table = frame.args -- cache
   
  +
local info = getInfo(getArg(1), getArg('invert'), getArg('pagenot'))
 
  +
if infoIsInvalid(info) then
 
return {
 
-- for template; get all exclusive info, set it in dplvars.
 
-- parameters: $1 = pagename
 
getInfo = function(frame)
 
args_table = frame.args -- cache
 
local page = getArg(1)
 
if not page then
 
frame:callParserFunction{ name = '#dplvar:set', args = {
 
'ex_d', '', 'ex_c', '', 'ex_o', '', 'ex_m', '', 'ex_3', '', 'ex_j', '', 'ex_cached', 'y'
 
} }
 
return
 
end
 
local ex_d, ex_c, ex_o, ex_m, ex_3, ex_j, cached = getInfo(page, getArg('invert'), getArg('pagenot'))
 
 
frame:callParserFunction{ name = '#dplvar:set', args = {
 
frame:callParserFunction{ name = '#dplvar:set', args = {
'ex_d', ex_d and 'y' or '',
+
'ex_d', '',
'ex_c', ex_c and 'y' or '',
+
'ex_c', '',
'ex_o', ex_o and 'y' or '',
+
'ex_o', '',
'ex_m', ex_m and 'y' or '',
+
'ex_m', '',
'ex_3', ex_3 and 'y' or '',
+
'ex_3', '',
'ex_j', ex_j and 'y' or '',
+
'ex_j', '',
'ex_cached', cached and 'y' or ''
+
'ex_cached', 'y'
 
} }
 
} }
  +
else
end,
 
  +
frame:callParserFunction{ name = '#dplvar:set', args = {
  +
'ex_d', bit32.btest(info, 2^0) and 'y' or '',
  +
'ex_c', bit32.btest(info, 2^1) and 'y' or '',
  +
'ex_o', bit32.btest(info, 2^2) and 'y' or '',
  +
'ex_m', bit32.btest(info, 2^3) and 'y' or '',
  +
'ex_3', bit32.btest(info, 2^4) and 'y' or '',
  +
'ex_j', bit32.btest(info, 2^5) and 'y' or '',
  +
'ex_cached', 'y'
  +
} }
  +
end
  +
end,
   
-- for {{eicons}}
+
-- for {{eicons}}
eicons = function(frame)
+
eicons = function(frame)
args_table = frame.args -- cache
+
args_table = parse(frame.args[1])-- cache
  +
local ex_d, ex_c, ex_o, ex_m, ex_3, ex_j = getExclusiveInfo(getArg(1), getArg('invert'), getArg('pagenot'))
 
  +
local info = getInfo(getArg('page'), getArg('invert'), getArg('pagenot'), getArg('dcom3j'))
if not(ex_d or ex_c or ex_o or ex_m or ex_3 or ex_j) then
 
  +
if infoIsInvalid(info) then
return ''
 
  +
return frame:expandTemplate{ title = 'error', args = { l10n('eicons_error_text'), l10n('eicons_error_cate'), from = 'Eicons' } }
end
 
  +
end
local small = getArg('small')
 
  +
lang = getArg('lang') -- set lang for l10n
if small == 'n' or small == '0' or small == 'no' then
 
  +
return eicons(info, getArg('small'))
small = false
 
end
+
end,
  +
return eicons(
 
  +
-- simplified version of the eicons function above, for other modules such as Module:Item
ex_d, ex_c, ex_o, ex_m, ex_3, ex_j,
 
  +
simpleEicons = function(page, language, small)
small, getArg('link'), getArg('lang')
 
  +
local info = getInfo(page)
)
 
  +
if infoIsInvalid(info) then
end,
 
  +
return ''
  +
end
  +
lang = language -- set lang for l10n
  +
return eicons(info, small)
  +
end,
   
-- for other modules such as Module:item; simple eicons:
 
simpleEicons = function(page, lang, small, link)
 
local ex_d, ex_c, ex_o, ex_m, ex_3, ex_j = getInfo(page)
 
if not(ex_d or ex_c or ex_o or ex_m or ex_3 or ex_j) then
 
return ''
 
end
 
return eicons(
 
ex_d, ex_c, ex_o, ex_m, ex_3, ex_j,
 
small, link, lang
 
)
 
end,
 
 
--purge luacached cache data.
 
purge = function(frame)
 
local cache = require 'mw.ext.LuaCache'
 
cache.delete('exclusive-database')
 
end,
 
 
 
}
 
}

Version actuelle datée du 9 septembre 2021 à 12:21

Voir aussi la page anglaise du module : Module:Exclusive. 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.


---Holds the tables with the l10n information for the different languages, taken from the l10n submodule.
local l10n_data = mw.loadData('Module:Exclusive/l10n')

---Database with exclusivity info.
local exclusive_info = mw.loadData('Module:Exclusive/data')

local bit32 = require('bit32')
local trim = mw.text.trim

---Default content language of the wiki (i.e. `$wgLanguageCode`, not the value of the
---`uselang` URL parameter, and not the user's language preference setting).
local contentLanguage = mw.getContentLanguage()

---Holds the arguments from the template call.
local args_table

---The current language. Determines which l10n table to use.
local lang

---Return the l10n string associated with the `key`.
---@param key string
---@return string
local function l10n(key)
	if l10n_data[lang] then
		return l10n_data[lang][key] or l10n_data['en'][key]
	else
		return l10n_data['en'][key]
	end
end

---Return a trimmed version of the value of the template parameter with the specified `key`.
---Return `nil` if the parameter is empty or unset.
---@param key string|number
---@return string|nil
local function getArg(key)
	local value = trim(args_table[key] or '')
	return (value ~= '') and value or nil
end

---Convert a string of parameters in a `@param1:value^@param2:value^` format to a table.
---@param paramstr string
---@return table
local function parse(paramstr)
	local args = {}
	for s in string.gmatch(paramstr, '%b@^') do
		local k,v = string.match(s, '^@(.-):(.*)^$')
		args[k] = v
	end
	return args
end

---Split the `str` on each `div` in it and return the result as a table.
---This is much much faster then `mw.text.split`.
---Credit: http://richard.warburton.it.
---@param div string
---@param str string
---@return table|boolean
local function explode(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
		arr[#arr + 1] = string.sub(str,pos,st-1) -- Attach chars left of current divider
		pos = sp + 1 -- Jump past current divider
	end
	arr[#arr + 1] = string.sub(str,pos) -- Attach chars right of last divider
	return arr
end

---Return the integer defined in the database for the specified `page`.
---Perform some standardization on the `page` for that first.
---@param page string
---@return number
local function readFromDb(page)
	-- standardize pagename: remove section parts ('x#section' -> 'x') and replace underscores with spaces
	page = contentLanguage:ucfirst(string.gsub(string.gsub(page or '', '#.*', ''), '_', ' '))
	return exclusive_info[page] or 0
end

---Override the exclusivity information in `info`
---with the content of `dcom3j`.
---@param info number
---@param dcom3j string Expected format: `<d>:<c>:<o>:<m>:<3>:<j>`, with each platform either a Boolean string ("y", "0", etc.) or an empty string
---@return number
local function override(info, dcom3j)
	for k, v in pairs(explode(':', dcom3j)) do
		if v ~= '' then
			if v == '1' or v == 'y' or v == 'yes' then
				info = bit32.replace(info, 1, k-1)
			elseif v == '0' or v == 'n' or v == 'no' then
				info = bit32.replace(info, 0, k-1)
			end
		end
	end
	return info

	-- Example to demonstrate the behavior of this function:
	-- Goal: Change "dcom" to "dco3".
	-- info = 15 ("dcom"), dcom3j = ":::no:yes:"
	-- decimal 15 = binary 001111
	-- The first "no" is at index 3 in the dcom3j string, so
	-- replace the corresponding bit with a 0: 001111 -> 000111.
	-- The "yes" is at index 4, so replace the bit at index 4
	-- with a 1: 000111 -> 010111.
	-- The result is info = 23 ("dco3").
end

---Main function to retrieve exclusivity information.
---@param page string The entity to get the info about.
---@param invert boolean Whether to invert the exclusivity info.
---@param pagenot string The entity whose exclusivity info to subtract from the main one's.
---@param dcom3j string Manual exclusivity info to override the fetched one with.
---@return number info An integer that holds the exclusivity information.
local function getInfo(page, invert, pagenot, dcom3j)
	local info = 0

	-- A piece of exclusivity information is a set of Boolean values, one
	-- for each platform. This is represented as bits of the `info` integer.
	-- Each platform (Desktop, Console, Old-gen console, Mobile, 3DS,
	-- and Japanese console – "dcom3j") is assigned one bit, in this order.
	-- This means that, for instance, an `info` value of 1 would represent
	-- Desktop-only exclusivity ("d"):
	-- decimal  1 = binary 000001
	--                     j3mocd  -> "d"
	-- Similarly, an `info` value of 20 would represent Old-gen and 3DS exclusivity ("o3"):
	-- decimal 20 = binary 010100
	--                     j3mocd  -> "o3"
	-- See Module:Exclusive/data for a quick overview of all values.

	-- This system allows using bitwise operations (https://en.wikipedia.org/wiki/Bitwise_operation)
	-- instead of the formerly used string processing, resulting in much lower script execution times.


	-- get info about page
	if page then
		info = readFromDb(page)
		if invert then
			-- invert dcom3 and set j=0 (always force-off Japanese console when inverting)
			info = bit32.band(bit32.bnot(info), 31)
		end
		if pagenot then
			-- exclude some versions, depending on pagenot
			local info_not = readFromDb(pagenot)
			info = bit32.band(info, bit32.bnot(info_not))
		end

		-- The "invert" and "pagenot" functionalities above utilize
		-- bit masking (https://en.wikipedia.org/wiki/Mask_(computing)).
		-- The following example demonstrates the operations:
		-- 1. assume info=11 ("dcm", binary 001011)
		-- 2. invert:
		--    2a. not(001011) = 110100 ("o3j", the inverse of "dcm")
		--    2b. and(110100, 011111) = 010100 ("o3", forced-off "j")
		-- 3. assume info_not=4 ("o", binary 000100)
		--    3a. not(000100) = 111011
		--    3b. and(010100, 111011) = 010000 ("3")
		-- An initial exclusivity info of "dcm" was inverted to "o3",
		-- then "o" was subtracted from it, resulting in the final
		-- exclusivity information of "3".
	end

	-- override if needed
	if dcom3j == nil or dcom3j == ':::::' then
		return info
	else
		return override(info, dcom3j)
	end
end

---Return an HTML span tag whose `class` attribute is set
---according to the exclusivity `info`.
---@param info number
---@param _small boolean Whether to add the "s" class, for small icons
---@return string
local function eicons(info, _small)
	local class = 'eico' .. (_small and ' s' or '')

	if bit32.btest(info, 32) then
		-- Japanese console is set, so simply display that
		-- ("j" is always alone or not set at all – "dcj", for instance, doesn't exist)
		class = class .. ' j'
		local hovertext = l10n('text_j')
		return mw.text.tag('span', {class=class}, mw.text.tag('span', {title=hovertext}, ''))
	end

	-- for each platform of dcom3, add the class and load the hovertext if the platform if set
	-- (e.g. for info=25 ("dm3"), append "i0 i3 i4" to the class and load the
	-- "text_0", "text_3", and "text_4" l10n strings)
	local v = {}
	for i = 0, 4 do
		if bit32.btest(info, 2^i) then
			class = class .. ' i' .. i
			v[#v+1] = l10n('text_' .. i)
		end
	end
	local hovertext = mw.text.listToText(v, l10n('list_separator'), l10n('list_conjunction'))
	hovertext = hovertext .. contentLanguage:convertPlural(#v, l10n('version_plural_forms'))
	return mw.text.tag('span', {class=class}, mw.text.tag('span', {title=hovertext}, ''))
end

---Check if the `infoToCheck` integer is a valid number for output.
---It is considered invalid if it represents an empty exclusivity ("")
---or a "full" exclusivity, i.e. all platforms being set ("dcom3" or "dcom3j").
---@param infoToCheck number
---@return boolean
local function infoIsInvalid(infoToCheck)
	return infoToCheck == 0 or infoToCheck == 31 or infoToCheck == 63
end

-----------------------------------------------------------------
-- main return object
return {

-- for templates; get all exclusive info and set it in dplvars.
-- parameters: $1 = pagename
getInfo = function(frame)
	args_table = frame.args -- cache

	local info = getInfo(getArg(1), getArg('invert'), getArg('pagenot'))
	if infoIsInvalid(info) then
		frame:callParserFunction{ name = '#dplvar:set', args = {
			'ex_d', '',
			'ex_c', '',
			'ex_o', '',
			'ex_m', '',
			'ex_3', '',
			'ex_j', '',
			'ex_cached', 'y'
		} }
	else
		frame:callParserFunction{ name = '#dplvar:set', args = {
			'ex_d', bit32.btest(info, 2^0) and 'y' or '',
			'ex_c', bit32.btest(info, 2^1) and 'y' or '',
			'ex_o', bit32.btest(info, 2^2) and 'y' or '',
			'ex_m', bit32.btest(info, 2^3) and 'y' or '',
			'ex_3', bit32.btest(info, 2^4) and 'y' or '',
			'ex_j', bit32.btest(info, 2^5) and 'y' or '',
			'ex_cached', 'y'
		} }
	end
end,

-- for {{eicons}}
eicons = function(frame)
	args_table = parse(frame.args[1])-- cache

	local info = getInfo(getArg('page'), getArg('invert'), getArg('pagenot'), getArg('dcom3j'))
	if infoIsInvalid(info) then
		return frame:expandTemplate{ title = 'error', args = { l10n('eicons_error_text'), l10n('eicons_error_cate'), from = 'Eicons' } }
	end
	lang = getArg('lang') -- set lang for l10n
	return eicons(info, getArg('small'))
end,

-- simplified version of the eicons function above, for other modules such as Module:Item
simpleEicons = function(page, language, small)
	local info = getInfo(page)
	if infoIsInvalid(info) then
		return ''
	end
	lang = language -- set lang for l10n
	return eicons(info, small)
end,

}