Module:QuoteArchiveToWiki

local p = {} local cargo = mw.ext.cargo local scenarioData = mw.loadData 'Module:ScenarioArchiveToWiki/data' local lang_USEN = mw.loadData("Module:FEH lang/USEN/data") local lang_JPJA = mw.loadData("Module:FEH lang/JPJA/data")

function p.convert(frame) -- Console use: p.convert({ args = { [==[EnglishTextHere]==], [==[JapaneseTextHere]==]} }) local jsonTable1 = {} for key,val in mw.ustring.gmatch(frame.args[1] or "", "%s*(.-): ([^\n]*)" ) do		jsonTable1[#jsonTable1 + 1] = {["key"] = key, ["value"] = val} end local jsonTable2 = {} for key,val in mw.ustring.gmatch(frame.args[2] or "", "%s*(.-): ([^\n]*)" ) do		jsonTable2[#jsonTable2 + 1] = {["key"] = key, ["value"] = val} end frame.args[1] = mw.text.jsonEncode(jsonTable1) frame.args[2] = mw.text.jsonEncode(jsonTable2) return p.convertJSON(frame) end

local function addToWarnings(warningsTable, warning) if not warningsTable[warning] then warningsTable[warning] = 1 end warningsTable[warning] = warningsTable[warning] + 1 end

local function processScenario(input_text, lang, warnings_table) local result = mw.ustring.gsub( input_text, "$Nu", "" ) result = mw.ustring.gsub( result, "$Nf", "" ) result = mw.ustring.gsub( result, "$k$p", " " ) for npid in mw.ustring.gmatch( result, "%$nM[EP]ID_([^|]*)|" ) do		local name if lang == "USEN" then name = lang_USEN['MPID_' .. npid] or scenarioData.npidToNameplateEN[npid] if not name then addToWarnings(warnings_table, "Could not find ID for USEN: " .. npid) end name = name or ("") elseif lang == "JPJA" then name = lang_JPJA['MPID_' .. npid] or scenarioData.npidToNameplateJP[npid] if not name then addToWarnings(warnings_table, "Could not find ID for JPJA: " .. npid) end name = name or ("") end result = mw.ustring.gsub( result, "%$nM[EP]ID_[^|]*|", "" .. name .. ": ", 1) end if mw.ustring.find( result, "•" ) then result = mw.ustring.gsub( result, "\n", " " ) else result = mw.ustring.gsub( result, "\n", " " ) end

return result end

function p.convertJSON(frame) -- Console use: p.convertJSON({ args = { [==[PasteEnglishJSONHere]==], [==[PasteJapaneseJSONHere]==]} }) local frameEX = mw.getCurrentFrame local warnings_table = {} local mess_archive_inputs = { USEN = mw.text.jsonDecode(frame.args[1] or "[]"), JPJA = mw.text.jsonDecode(frame.args[2] or "[]") }	local archive_size = math.max(#mess_archive_inputs.USEN, #mess_archive_inputs.JPJA)

--If the third parameter quotesType is not provided, search the archives to see if this is a duo/resplendent hero local quotesType = frame.args[3] if quotesType == nil then for lang, lang_archive in pairs(mess_archive_inputs) do			for i=1,archive_size do				if mw.ustring.find( lang_archive[i]["value"], "PID_二人" ) then quotesType = 'duo' break elseif mw.ustring.find( lang_archive[i]["value"], "PID_三人" ) then quotesType = 'trio' break elseif mw.ustring.find(lang_archive[i]["key"], '_EX01_') then quotesType = 'resplendent' break end end end end for lang, lang_archive in pairs(mess_archive_inputs) do		for i=1,archive_size do			mess_archive_inputs[lang][i]["value"] = processScenario(mess_archive_inputs[lang][i]["value"], lang, warnings_table) end end

local mess_archive_outputs = {quotesType == 'resplendent' and '==Resplendent Hero==' or ""}

local add_line = function (str) if mw.ustring.find(str, "%S") then table.insert(mess_archive_outputs, str) end end

local add_heading = function (str, level) add_line(('%s%s%s'):format(('='):rep(level), str, ('='):rep(level))) end

local home_quotes = {USEN = {}, JPJA = {}} local friend_quotes = {USEN = {}, JPJA = {}} local level_quotes = {USEN = {}, JPJA = {}} local skill_quotes = {USEN = {}, JPJA = {}} local join_quotes = {USEN = {}, JPJA = {}} local strongest_quotes = {USEN = {}, JPJA = {}}

for lang in pairs(mess_archive_inputs) do		local add_quotes = function (quotes, ident) for i=1,archive_size do				local obj = mess_archive_inputs[lang][i] if obj and mw.ustring.find( obj["key"], ident, 1, false ) then table.insert(quotes[lang], obj["value"] ) mess_archive_inputs[lang][i] = nil end end end

add_quotes(home_quotes, "HOME") add_quotes(friend_quotes, "FRIEND") add_quotes(level_quotes, "LEVEL") add_quotes(skill_quotes, "SKILL") add_quotes(join_quotes, "JOIN") add_quotes(strongest_quotes, "STRONGEST") end

local fill_quote = function (quotes, index) add_line("") add_line("") add_line "

"	end

local fill_quotes = function (quotes) local index = 1 while quotes.USEN[index] or quotes.JPJA[index] do			fill_quote(quotes, index) index = index + 1 end end

if quotesType ~= 'resplendent' then add_heading('Summoning', 2) fill_quotes(join_quotes)

add_heading('Castle', 2) fill_quotes(home_quotes)

add_heading('Friend greeting', 2) fill_quotes(friend_quotes)

add_heading('Leveling up', 2) add_heading('+[4,5] points', 3) fill_quote(level_quotes, 1) add_heading('+[2,3] points', 3) fill_quote(level_quotes, 2) add_heading('+[0,1] points', 3) fill_quote(level_quotes, 3)

add_heading('Ally Growth', 2) fill_quotes(skill_quotes)

add_heading('5★ LV. 40 conversation', 2) fill_quotes(strongest_quotes) end

local get_voice_quote = function (archive, ident, is_jpja) -- Finds the next voice quote, removes Japanese text from English text local text for i=1,archive_size do			if archive[i] and mw.ustring.find( archive[i]["key"], ident, 1, false ) then text = archive[i]["value"] archive[i] = nil break end end if not text then return "" elseif is_jpja or (not mw.ustring.find( text, "[！あいうえおかきくけこゃょさしすせそたちつてとなにぬねのひふへはほまみむめもやゆよらりるれろわゐをがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽっ]", 1, false )) then return text or "" else return "" end end

local fill_voice_quote = function (lang, fname, ident, rarity, is_resplendent) local line = "" add_line(line) end

local fill_voice_section = function (title, voices, opts) opts = opts or {} add_heading(title, opts.resplendent and 3 or 2) add_line(opts.has_rarities and "" or "") for _, v in ipairs(voices) do			fill_voice_quote("USEN", v[1], v[2], v[3], opts.resplendent) end add_line "|}" add_line(opts.has_rarities and "" or "") for _, v in ipairs(voices) do			fill_voice_quote("JPJA", v[1], v[2], v[3], opts.resplendent) end add_line "|}" add_line "

"	end

if quotesType == 'duo' then fill_voice_section("Attack", {			{"ATTACK_1", "VOICE01"},			{"ATTACK_2", "VOICE02"},		}) fill_voice_section("Damage", {			{{"DAMAGE_1A","DAMAGE_1B"}, nil},			{"DAMAGE_2", "VOICE03"},			{"DAMAGE_3", "VOICE04"},		}) fill_voice_section("Special trigger", {			{{"SKILL_1A","SKILL_1B"}, "VOICE05"},			{"SKILL_2", "VOICE06"},			{"SKILL_3", "VOICE07"},			{"SKILL_4", "VOICE08"},		}) fill_voice_section("Defeat", {			{"DEAD_1","VOICE10"}		}) fill_voice_section("Status page", {			{"STATUS_1", "VOICE15", ""},			{"STATUS_2", "VOICE16", ""},		}, {has_rarities = true}) fill_voice_section("Turn action", {			{"MAP_1", "VOICE17"},			{"MAP_2", "VOICE18"},			{"MAP_3", "VOICE19"},		}) fill_voice_section("Cohort supporting", {			{"SUPPORT_1","VOICE11"},			{"SUPPORT_2","VOICE12"},		}) fill_voice_section("Duo Skill", {			{"SPECIAL_1","VOICE13"},			{"SPECIAL_2","VOICE14"},		})

local voices = {} local relianceCounter = 1 for i=1,archive_size do			local vmatch if mess_archive_inputs.JPJA[i] then vmatch = mw.ustring.match(mess_archive_inputs.JPJA[i]["key"], "(VOICE%d+)") elseif mess_archive_inputs.USEN[i] then vmatch = mw.ustring.match(mess_archive_inputs.USEN[i]["key"], "(VOICE%d+)") end if vmatch then if tonumber(mw.ustring.match(vmatch, "VOICE(%d+)")) >= 20 then table.insert(voices, {"RELIANCE_" .. relianceCounter, vmatch}) relianceCounter = relianceCounter + 1 end end end fill_voice_section("Duo conversation", voices)

elseif quotesType == 'trio' then -- Palla: Sisterly Trio fill_voice_section("Attack", {			{"ATTACK_1", "VOICE01"},			{"ATTACK_2", "VOICE02"},		}) fill_voice_section("Damage", {			{{"DAMAGE_1A","DAMAGE_1B","DAMAGE_1C"}, 'VOICE03'},			{"DAMAGE_2", "VOICE04"},			{"DAMAGE_3", "VOICE09"},		}) fill_voice_section("Special trigger", {			{{"SKILL_1A","SKILL_1B", 'SKILL_1C'}, "VOICE05"},			{{"SKILL_2A",'SKILL_2B','SKILL_2C'}, "VOICE06"},			{"SKILL_3", "VOICE07"},			{"SKILL_4", "VOICE08"},		}) fill_voice_section("Defeat", {			{"DEAD_1","VOICE10"}		}) fill_voice_section("Status page", {			{"STATUS_1", "VOICE15", ""},			{"STATUS_2", "VOICE16", ""},		}, {has_rarities = true}) fill_voice_section("Turn action", {			{"MAP_1", "VOICE17"},			{"MAP_2", "VOICE18"},			{"MAP_3", "VOICE19"},			{"MAP_4", "VOICE19_2"},		}) fill_voice_section("Cohort supporting", {			{"SUPPORT_1","VOICE11"},			{"SUPPORT_2","VOICE12"},			{"SUPPORT_3","VOICE12_2"},		}) fill_voice_section("Duo Skill", {			{"SPECIAL_1","VOICE13"},			{"SPECIAL_2","VOICE14"},		})

local voices = {} local relianceCounter = 1 for i=1,archive_size do			local vmatch if mess_archive_inputs.JPJA[i] then vmatch = mw.ustring.match(mess_archive_inputs.JPJA[i]["key"], "(VOICE%d+)") elseif mess_archive_inputs.USEN[i] then vmatch = mw.ustring.match(mess_archive_inputs.USEN[i]["key"], "(VOICE%d+)") end if vmatch then if tonumber(mw.ustring.match(vmatch, "VOICE(%d+)")) >= 20 then table.insert(voices, {"RELIANCE_" .. relianceCounter, vmatch}) relianceCounter = relianceCounter + 1 end end end fill_voice_section("Duo conversation", voices)

elseif quotesType == 'tms' then fill_voice_section("Attack", {			{"ATTACK_1", "VOICE01"},			{"ATTACK_2", "VOICE02"},		}) fill_voice_section("Damage", {			{"DAMAGE_1", "VOICE03"},			{"DAMAGE_2", "VOICE04"},		}) fill_voice_section("Special trigger", {			{"SKILL_1", "VOICE05"},			{"SKILL_2", "VOICE06"},			{"SKILL_3", "VOICE07"},			{"SKILL_4", "VOICE08"},			{"SKILL_5", "VOICE09"},			{"SKILL_6", "VOICE10"},		}) fill_voice_section("Defeat", {			{"DEAD_1", "VOICE11"},		}) fill_voice_section("Status page", {			{"STATUS_1", "VOICE12", 1},			{"STATUS_2", "VOICE13", 1},			{"STATUS_3", "VOICE14", 1},			{"STATUS_4", "VOICE15", 1},			{"STATUS_5", "VOICE16", 4}, -- inferred from Common/Sound/arc/*.bin			{"STATUS_6", "VOICE17", 4},			{"STATUS_7", "VOICE18", 1},			{"STATUS_8", "VOICE19", 4},			{"STATUS_9", "VOICE20", 5},			{"STATUS_10", "VOICE21", 5},			{"STATUS_11", "VOICE22", 5},		}, {has_rarities = true}) fill_voice_section("Turn action", {			{"MAP_1", "VOICE23"},			{"MAP_2", "VOICE24"},			{"MAP_3", "VOICE25"},			{"MAP_4", "VOICE26"},		})

elseif quotesType == 'resplendent' then fill_voice_section("Attack", {			{"ATTACK_1", "VOICE01"},			{"ATTACK_2", "VOICE02"},		}, {resplendent = true}) fill_voice_section("Damage", {			{"DAMAGE_1", "VOICE03"},			{"DAMAGE_2", "VOICE04"},		}, {resplendent = true}) fill_voice_section("Special trigger", {			{"SKILL_1", "VOICE05"},			{"SKILL_2", "VOICE06"},			{"SKILL_3", "VOICE07"},			{"SKILL_4", "VOICE08"},		}, {resplendent = true}) fill_voice_section("Defeat", {			{"DEAD_1", "VOICE09"},		}, {resplendent = true}) fill_voice_section("Status page", {			{"STATUS_1", "VOICE10", 1},			{"STATUS_2", "VOICE11", 1},			{"STATUS_3", "VOICE12", 1},			{"STATUS_4", "VOICE13", 1},			{"STATUS_5", "VOICE14", 4},			{"STATUS_6", "VOICE15", 4},			{"STATUS_7", "VOICE16", 5},			{"STATUS_8", "VOICE17", 5},		}, {resplendent = true, has_rarities = true}) fill_voice_section("Turn action", {			{"MAP_1", "VOICE18"},			{"MAP_2", "VOICE19"},			{"MAP_3", "VOICE20"},		}, {resplendent = true})

else fill_voice_section("Attack", {			{"ATTACK_1", "VOICE01"},			{"ATTACK_2", "VOICE02"},		}) fill_voice_section("Damage", {			{"DAMAGE_1", "VOICE03"},			{"DAMAGE_2", "VOICE04"},		}) fill_voice_section("Special trigger", {			{"SKILL_1", "VOICE05"},			{"SKILL_2", "VOICE06"},			{"SKILL_3", "VOICE07"},			{"SKILL_4", "VOICE08"},		}) fill_voice_section("Defeat", {			{"DEAD_1", "VOICE09"},		}) fill_voice_section("Status page", {			{"STATUS_1", "VOICE10", 1},			{"STATUS_2", "VOICE11", 1},			{"STATUS_3", "VOICE12", 1},			{"STATUS_4", "VOICE13", 1},			{"STATUS_5", "VOICE14", 4},			{"STATUS_6", "VOICE15", 4},			{"STATUS_7", "VOICE16", 5},			{"STATUS_8", "VOICE17", 5},		}, {has_rarities = true}) fill_voice_section("Turn action", {			{"MAP_1", "VOICE18"},			{"MAP_2", "VOICE19"},			{"MAP_3", "VOICE20"},		})

local misc_quotes = {USEN = {}, JPJA = {}} for lang, archive in pairs(mess_archive_inputs) do			for i=1,archive_size do				if archive[i] then local voiceNum = mw.ustring.match(archive[i]["key"], "VOICE(%d+)") if voiceNum and (voiceNum > 20) then table.insert(misc_quotes[lang], archive[i]["value"] ) archive[i] = nil end end end end

local max_quotes_count = math.max(0, #misc_quotes.USEN, #misc_quotes.JPJA) if max_quotes_count > 0 then local voices = {} for i = 1, max_quotes_count do table.insert(voices, {"VOICE" .. (i + 20), "VOICE" .. (i + 20)}) end fill_voice_section("Miscellaneous", voices) end end

if quotesType ~= 'resplendent' then add_line "" end

local mess_archive_output = table.concat(mess_archive_outputs, "\n") mess_archive_output = mw.ustring.gsub( mess_archive_output, "|%*", "| *" ) mw.log(mess_archive_output) mw.log("Warnings/etc.:") for warning,times in pairs(warnings_table) do		if times > 1 then mw.log(warning, " (×"..times..")") else mw.log(warning) end end

for lang, archive in pairs(mess_archive_inputs) do		for i=1,archive_size do			if archive[i] then mw.log("-\nNot added from " .. lang .. " archive:\n") break end end for i=1,archive_size do			if archive[i] then mw.log( archive[i]["key"] .. ": " .. archive[i]["value"]) end end end

return mess_archive_output end

return p