Module:Luacard
From Archon Arcana - The KeyForge Wiki
--Module:Luacard --canstage --Usage: english - {{#invoke luacard | viewcard | cardname=Angry Mob}} -- other language {{#invoke luacard | viewcard | cardname=Angry Mob | locale=fr-fr}} (language codes are all 2 part) --Debug: print(p.viewcard({args={cardname='Angry Mob', debug=true}})) local p = {} local cargo = mw.ext.cargo function combine(tableto, tablefrom) for k,v in pairs(tablefrom) do tableto[k] = v end end function map(table, func) if table==nil then return table end for k,v in pairs(table) do table[k] = func(v) end return table end function filter(table, func) if table==nil then return table end local new = {} for k,v in pairs(table) do if func(v) then new[k] = v end end return new end function append(table, value) table[#table+1] = value return table end function extend(table1, table2) for k,v in pairs(table2) do append(table1, v) end end local templates = require('Module:LuacardTemplates') local cardstyle = require('Module:LuacardStyle') local translations = require("Module:LocaleTable") -- double quotes to not stage local luastache = require("Module:luastache") -- double quotes to not stage local translate_table = {} local translate = function(word) if(translate_table[word]~=nil) then return translate_table[word] else return word end end function insert_translated(tab) local trans_tab = {} for k,v in pairs(tab) do trans_tab[k..'_t'] = translate(v) end combine(tab, trans_tab) end function stachify(table) local under_tab = {} for k,v in pairs(table) do if v==nil then table[k] = '' v = '' end if string.find(k, '[.]') then local parts = mw.text.split(k, '[.]') if not under_tab[parts[1]] then under_tab[parts[1]] = {} end under_tab[parts[1]][parts[2]] = v end end combine(table, under_tab) end function cargo_results(ctable, cfields, cargs) local table = cargo.query(ctable, cfields, cargs) for i,r in ipairs(table) do stachify(r) if i<#table then r['delim'] = true end end return table end function stache(s, tab) stachify(tab) insert_translated(tab) s = '{{=${ }=}}'..s return luastache:render(s, tab) end function wikitext(s) if s==nil then return '' else return s:gsub('\n', ''):gsub('<p>','__PARA__') end end function dewikitext(s) if s==nil then return '' end return s:gsub('__PARA__', '<p>') end local translate_trait = function(frame, type, word) if(frame.args.locale) then if(not translations[type][frame.args.locale]) then return word end if(not translations[type][frame.args.locale][mw.ustring.lower(word)]) then return word end return mw.ustring.upper(translations[type][frame.args.locale][mw.ustring.lower(word)]) else return word end end local load_translation_table = function(locale) local translate_table_results = cargo_results( 'TranslationTable', 'EnglishText,Type,TranslatedText', { where='Locale="'..locale..'"' }) for r=1, #translate_table_results do local result = translate_table_results[r] translate_table[result.EnglishText] = result.TranslatedText end end local apply_altart = function(frame, vars) if frame.args.locale then vars.art_default = true return end vars.is_amber_vault = vars.cardname_e == 'Dark Æmber Vault' vars.is_its_coming = vars.cardname_e == 'It’s Coming...' vars.altart = cargo_results( 'AltArt,CardData', 'AltArt.File,CardData.Image,CardData.Name', { join='AltArt._pageTitle=CardData.Name', where='CardData.Name="'..vars.cardname_e..'"' } ) vars.art_default = not (vars.is_amber_vault or vars.is_its_coming or #vars.altart>0) end function apply_house(frame, vars) if vars.cardhouse ~= nil then vars.is_multi = string.find(vars.cardhouse, '•', 1, true) vars.is_anomaly = string.find(vars.cardhouse, 'Anomaly') vars.is_starAlliance = string.find(vars.cardhouse, 'Star Alliance') end if(vars.is_multi) then vars.cardhouse_color = '' append(vars.categories, 'Multi') else vars.cardhouse_color = mw.ustring.gsub(vars.cardhouse, '%s', '') vars.cardhouse_color = mw.ustring.sub(vars.cardhouse_color, 1, 1):lower() .. mw.ustring.sub(vars.cardhouse_color, 2) append(vars.categories, vars.cardhouse) end end function minmax_arg(value, max) value = tonumber(value) if(value > max-1) then return {min=tostring(max)..'+', max=tostring(max)..'+', value=value} else return {min=tostring(value), max=tostring(value), value=value} end end function apply_stats(frame, vars) vars.cardstatamber = {} vars.cardstatpower = {} vars.cardstatarmor = {} if(vars.cardtype == 'Creature' and string.len(vars.cardpower)>0 and tonumber(vars.cardpower) >= 0) then vars.cardstatpower = minmax_arg(vars.cardpower, 10) end if(vars.cardtype == 'Token Creature' and string.len(vars.cardpower)>0 and tonumber(vars.cardpower) >= 0) then vars.cardstatpower = minmax_arg(vars.cardpower, 10) end if(vars.cardtype == 'Creature' and string.len(vars.cardarmor)>0 and tonumber(vars.cardarmor) >= 0) then vars.cardstatarmor = minmax_arg(vars.cardarmor, 5) end if(vars.cardtype == 'Token Creature' and string.len(vars.cardarmor)>0 and tonumber(vars.cardarmor) >= 0) then vars.cardstatarmor = minmax_arg(vars.cardarmor, 5) end if(string.len(vars.cardamber)>0 and tonumber(vars.cardamber) >= 1) then vars.cardstatamber = minmax_arg(vars.cardamber, 4) end vars.cardstats = vars.cardstatamber.len==0 and vars.cardstatpower==0 and vars.cardstatarmor==0 end function apply_traits(frame, vars) if vars.cardtraits==nil then return end if(string.len(mw.text.trim(vars.cardtraits))==0) then return end local split = mw.text.split(vars.cardtraits, ' • ') vars.cardtraits = {} vars.translate_trait = function(self) return translate_trait(frame, 'traits', self.trait) end for i = 1, #split do append(vars.categories, split[i]) local ob = {} ob.trait = split[i] if i<#split then ob.delim = true end append(vars.cardtraits, ob) end end function apply_errata(frame, vars) --Use cardname and not cardname_e, because localized errata doesn't exist, we just use the master vault text local errata_results = cargo_results( 'CardData, ErrataData', 'ErrataData.Text,ErrataData.Version', { join='CardData._pageName=ErrataData._pageName', where='ErrataData._ID is not null AND CardData.Name="'..vars.cardname..'"', orderBy='ErrataData._ID ASC' } ) if(#errata_results>0) then vars.has_carderrata = true vars.original_text=errata_results[1]['ErrataData.Text'] vars.errata_text=errata_results[#errata_results]['ErrataData.Text'] vars.errata_version = errata_results[#errata_results]['ErrataData.Version'] if(string.find(vars.errata_version, 'Rulebook')) then append(vars.categories, 'Errata') else append(vars.categories, 'Revised Cards') end end end function apply_categories(frame, vars) mw.log(vars.category_prefix) for c=1, #vars.categories do if(string.len(mw.text.trim(vars.categories[c]))>0) then vars.categories[c] = vars.category_prefix .. vars.categories[c] vars.categories[c] = stache('[[Category:${c}]]', {c=vars.categories[c]}) end end mw.logObject(vars.categories) vars.categories = '<includeonly>'..table.concat(vars.categories,'')..'</includeonly>' end function rulequery(type, cardname) return cargo_results( 'RuleData', 'RulesText, RulesType, RulesSource, RulesPages, RulesDate', { groupBy='RulesText, RulesType, RulesSource, RulesPages, RulesDate', where="((RulesText like '%"..cardname.."%' AND RulesPages IS NULL) OR (RulesPages like '%•"..cardname.."•%')) AND RulesType='"..type.."'", orderBy='RulesDate ASC' }) end function apply_rulings(frame, vars) -- we use cardname_e and just show english rulings local official_results = rulequery('FAQ', vars.cardname_e) if(#official_results>0) then append(vars.categories, 'FAQ') end local ruling_results = rulequery('FFGRuling', vars.cardname_e) if(#ruling_results>0) then append(vars.categories, 'Rulings') end extend(official_results, ruling_results) local commentary_results = rulequery('Commentary', vars.cardname_e) local outstanding_results = rulequery('OutstandingIssues', vars.cardname_e) vars.ruleofficial = official_results mw.logObject(ruleofficial) vars.has_ruleofficial = #vars.ruleofficial > 0 vars.rulecommentary = commentary_results vars.has_rulecommentary = #vars.rulecommentary > 0 vars.ruleoutstanding = filter(outstanding_results, function(ruling) if string.find(ruling['RulesText'], '//') then return true else return false end end) vars.has_ruleoutstanding = #vars.ruleoutstanding > 0 if(has_ruleoutstanding or has_rulecommentary) then append(vars.categories, 'Commentary') end vars.filter_rules_text = function(self) return self['RulesText']:gsub('this card', "'''"..vars.cardname_e.."'''") end end function relatedquery(cardname, type_query) return cargo_results( 'CardRelatedData', 'Pages, Text, Cards, Type', { groupBy='Pages, Text, Cards, Type', where="(Pages like '%•"..cardname.."•%' OR (pages IS null AND Cards like '%•"..cardname.."•%')) AND Type!='twin' "..type_query, orderBy='Text ASC' }) end function relatedflavorquery(cardname) return cargo_results( 'CardData', 'Name, FlavorText', { where="(BINARY CardData.FlavorText LIKE '%"..cardname.."%') AND (CardData.Name NOT LIKE '%"..cardname.."%')", orderBy='CardData.Name ASC' }) end function twinquery(cardname) local searchname = cardname if string.find(cardname, 'Evil Twin') ~= nil then searchname = cardname:gsub(' %(Evil Twin%)', ' ') mw.log('search for not evil twin '..searchname) else searchname = cardname..' (Evil Twin)' mw.log('search for the evil twin '..searchname) end return cargo_results( 'CardData', 'Name', { groupBy='Name', where='Name="'..searchname..'"' }) end function get_related_cards(cardname, related_row) local cards = {} local card_names = related_row['Cards'] if card_names==nil then return cards end for name, _ in mw.ustring.gmatch(card_names, '[^•]+') do mw.log(name..', '..cardname) if name~=cardname then local card_results = cargo_results( 'CardData', 'Name,Image,Artist,Text,FlavorText,Type,Rarity,House,Traits,Power,Armor,Amber', { where='CardData.Name="'..name..'"' }) if card_results[1] ~= nil then card_results[1]["Name_br"] = mw.ustring.gsub(card_results[1]["Name"], "%(", "<br>(") end append(cards, card_results[1]) end end return cards end function apply_related(frame, vars) -- we use cardname_e and just show english related local related_set = {} local ignore_cards_set = relatedquery(vars.cardname_e,"AND Type='ignore'") local ignore_card_table = {} for i=1, #ignore_cards_set do if ignore_cards_set[i]["Cards"] then for name, _ in mw.ustring.gmatch(ignore_cards_set[i]["Cards"], '[^•]+') do ignore_card_table[name] = true end end end local related_cards_set = relatedquery(vars.cardname_e,"AND Type!='ignore'") local related_flavor_set = relatedflavorquery(vars.cardname_e) local related_twin_set = twinquery(vars.cardname_e) mw.logObject(related_twin_set) map(related_twin_set, function(item) local twin_name = 'an Evil Twin' if item["Name"]:find('Evil Twin')==nil then twin_name = 'a non-Evil Twin' end append(related_set, { Pages = "•"..vars.cardname_e.."•", Text = "this card has "..twin_name.." version:", Cards = "•"..item["Name"].."•" }) end) if #related_flavor_set > 0 then local flavor_card_names = "" for i=1, #related_flavor_set do if not ignore_card_table[related_flavor_set[i]["Name"]] then flavor_card_names = flavor_card_names .. "•"..related_flavor_set[i]["Name"].."•" end end if flavor_card_names:len() > 0 then append(related_set, { Pages = "•"..vars.cardname_e.."•", Text = "this card is featured in the flavor text of the following cards:", Cards = flavor_card_names }) append(vars.categories, "Appears in Flavor Text") end end extend(related_set, related_cards_set) map(related_set, function(item) item['Text'] = item['Text']:gsub('this card', "'''"..vars.cardname_e.."'''") item['Cards'] = get_related_cards(frame.args.cardname, item) return item end) vars.related = {} vars.cardnotes = {} for _,row in pairs(related_set) do mw.log(row) if #row['Cards']>0 then append(vars.related, row) mw.log('have related') else append(vars.cardnotes, row) mw.log('have notes') end end if(#vars.related>0) then vars.has_related = true end if(#vars.cardnotes>0) then vars.has_notes = true end end function apply_sets(frame, vars) vars.cardsets = cargo_results( 'SetData,CardData,SetInfo', 'SetData.SetName, SetData.CardNumber, SetInfo.ReleaseYear, SetInfo.ReleaseMonth, SetInfo.ShortName, SetInfo.SetNumber', { join='SetData._pageTitle=CardData.Name,SetData.SetName=SetInfo.SetName', where='CardData.Name="'..frame.args.cardname..'" AND (SetData.Meta IS NULL OR SetData.Meta!="SpoilerReprint")', orderBy='SetInfo.ReleaseYear, SetInfo.ReleaseMonth' }) for r = 1, #vars.cardsets do local result = vars.cardsets[r] mw.log(result['SetInfo.SetNumber']) if mw.ustring.find(result['SetInfo.SetNumber'], 'KFA.*') ~= nil then vars.category_prefix = 'KFA ' -- We use a different gallery link for each KFA set vars.is_kfa = true vars.root_gallery = result['SetData.SetName'] end mw.log(vars.category_prefix) append(vars.categories, result['SetInfo.ShortName']) end vars.shortset_from_name = function(self) local args = {longset = self['SetData.SetName'], shortset=self['SetInfo.ShortName']} return stache('[[${longset}|${shortset}]]', args) end end function p.viewcard(frame) vars = { cardname = frame.args.cardname, cardhouse = '', cardrarity = 'Rare', cardtext = 'Some text', cardartist = 'Some artist', cardstyle = cardstyle.cardstyle, multihouse_style = cardstyle.multihouse_style } local card_results = cargo_results( 'CardData', 'Name,Image,Artist,Text,FlavorText,Type,Rarity,House,Traits,Power,Armor,Amber', { where='CardData.Name="'..frame.args.cardname..'"' }) if(frame.args.locale) then load_translation_table(frame.args.locale) end vars.root_gallery = 'Card_Gallery' vars.cardname_e = vars.cardname vars.cardname_stripped = mw.ustring.gsub(vars.cardname_e, " %(Evil Twin%)", "") vars.cardname_stripped = mw.ustring.gsub(vars.cardname_stripped, " %(Anomaly%)", "") vars.word_power = 'Power' vars.word_armor = 'Armor' vars.word_artist = 'Artist' vars.cardimage = card_results[1]['Image'] vars.cardhouse = card_results[1]['House'] vars.cardrarity = card_results[1]['Rarity'] vars.cardtext = wikitext(card_results[1]['Text']) vars.cardflavortext = wikitext(card_results[1]['FlavorText']) vars.cardartist = card_results[1]['Artist'] or '' vars.cardtype = card_results[1]['Type'] vars.cardpower = card_results[1]['Power'] or '0' vars.cardarmor = card_results[1]['Armor'] or '0' vars.cardamber = card_results[1]['Amber'] or '0' vars.cardtraits = card_results[1]['Traits'] or '' vars.category_prefix = '' if vars.cardhouse == nil then vars.cardhouse = '' vars.has_no_house = true end --This just sets a card in Elders or Ironyx Rebels to display as a Mars card if vars.cardhouse == 'Elders' then vars.cardhouse = 'Mars' end if vars.cardhouse == 'Ironyx Rebels' then vars.cardhouse = 'Mars' end if vars.cardtype == nil then vars.cardtype = '' end if vars.cardrarity == nil then vars.cardrarity = '' vars.has_no_rarity = true end vars.categories = {vars.cardtype, vars.cardrarity, 'Card'} if(string.find(vars.cardtext,vars.cardname_stripped)) then append(vars.categories, 'Self-referential') end if frame.args.locale then vars.locale = frame.args.locale vars.locales = {} vars.locales[1] = {keyforge="pt-pt", locale="/locale/pt-br", locale_name="português do Brasil"} vars.locales[2] = {keyforge="it-it", locale="/locale/it", locale_name="italiano"} vars.locales[3] = {keyforge="zh-hant", locale="/locale/zh-hant", locale_name="中文(繁體)"} vars.locales[4] = {keyforge="de-de", locale="/locale/de", locale_name="Deutsch"} vars.locales[5] = {keyforge="zh-hans", locale="/locale/zh", locale_name="中文"} vars.locales[6] = {keyforge="th-th", locale="/locale/th", locale_name="ไทย"} vars.locales[7] = {keyforge="ko-ko", locale="/locale/ko", locale_name="한국어"} vars.locales[8] = {keyforge="pl-pl", locale="/locale/pl", locale_name="polski"} vars.locales[9] = {keyforge="fr-fr", locale="/locale/fr", locale_name="français"} vars.locales[10] = {keyforge="es-es", locale="/locale/es", locale_name="español"} vars.locales[11] = {keyforge="en-en", locale="", locale_name="english"} vars.locales[12] = {keyforge="ru-ru", locale="/locale/ru", locale_name="Pусский"} local locale_table_results = cargo_results( 'CardLocaleData', 'Name,EnglishName,Text,FlavorText,Locale,Image', { where='CardLocaleData.EnglishName="'..frame.args.cardname..'" and CardLocaleData.Locale="'..frame.args.locale..'"' } ) for c = 1, #locale_table_results do local cardlocale = locale_table_results[c] vars.cardtext = wikitext(cardlocale['Text']) vars.cardname = cardlocale['Name'] vars.cardflavortext = wikitext(cardlocale['FlavorText']) vars.cardimage = cardlocale['Image'] end end apply_sets(frame, vars) apply_altart(frame, vars) apply_house(frame, vars) apply_stats(frame, vars) apply_traits(frame, vars) apply_errata(frame, vars) apply_rulings(frame, vars) apply_related(frame, vars) if not frame.args.locale then apply_categories(frame, vars) else vars.categories = '' end text = stache(templates.template_base:gsub('\n',''), vars) if(frame.args.debug==nil) then text = frame:preprocess(text) end text = dewikitext(text) return text end return p