Module:ScenarioArchiveToWiki

From Fire Emblem Heroes Wiki
Jump to: navigation, search
Template-info.svg Documentation

This module has two functions.

convert[edit source]

This function converts raw decompressed message archives processed by FEAT (this expects and only works with FEAT's specific brand of formatting, it may not work if you use any other tool or process the archives manually) into wikitext for story pages.

Edit the module page and paste this in the console:

p.convert({ args = { [==[PasteEnglishHere]==], [==[PasteJapaneseHere]==]} })

convertJSON[edit source]

This function converts HertzDevil's JSON-formatted dumps into wikitext.

Paste this in the console:
p.convertJSON({args={[==[
PasteEnglishJSONHere
]==], 
[==[
PasteJapaneseJSONHere
]==]}})

Adding to the template[edit source]

These templates store the conversion for nameplates and heroes, if the output is wrong it is most likely because Module:ScenarioArchiveToWiki/data has not been updated. There are three data tables:

  • imgToHero
  • npidToNameplateJP
  • npidToNameplateEN

These are ordered from most important to least important. The module does not check npidToNameplateEN for example if the Japanese nameplate matches the Japanese name.

Misc[edit source]

There are a couple of parts to dialogue:

 $WmMEID_ブルーノ,ch04_23_Marth_F_Mask,Face|$w0|…………$k$p世界は、絶望に\n覆われようとしている…$k$p行かなければ。\n取り戻さなければ、未来を…$k$p$Sbs150|
  • Red is the internal ID of the nameplate the game uses. Here it is ブルーノ, which turns into ??? when displayed in-game. Technically the full ID also includes the MEID_ but that is dropped for the purposes of this template (It's highly unlikely it would matter, and if it does, just convert to wikitext manually).
  • Blue is the internal ID for the image that is used. It does not always match the nameplate, here Marth: Enigmatic Blade is shown as ??? despite the Hero's name being "Marth".
  • Green is the expression.
  • Purple is the dialogue.
  • Gray is the other stuff the template removes.
  • $k: Tap to advance
    • Almost always succeeded by $p.
  • $p: Scroll up text
    • Always preceded by $k.
  • $Nu: [Summoner]
  • $Nf: [Friend]
  • $Sbs{number}|: Unknown. Possibly delay in ms.
  • $E{expression}|: Expression
  • $Sbv{unknown},{unknown2}|: Unknown. Only appears in XX002. Appears to have no visible effect.
  • $Sbp{BGM ID}|: BGM
  • $Ssp{SE ID}|: Sound effect
  • $Fo{number1},{R},{G},{B},{Unknown2}|: Fade out the screen to a specified background color. Unknown1 is possibly the time in ms to complete this fade. Unknown2 is probably alpha. R,G,B,A go from 0 to 255.
  • $Fi{number}|: Unknown. Always seen paired after $Fo, so most likely time in ms to fade back in the normal screen.
  • $Sbs{unknown}|: Unknown
  • $w{unknown}|: Unknown


local scenarioData = mw.loadData 'Module:ScenarioArchiveToWiki/data'

local imgToHero = function (hero)
	return scenarioData.imgToHero[hero] or hero
end

local npidToNameplateJP = function (pid)
	return mw.ustring.gsub(mw.ustring.gsub(scenarioData.npidToNameplateJP[pid] or pid, '愛の祭', ''), '[年明水着幼少女男夢伝承総選挙夏祭総選挙味方神階%d]', '')
end

local npidToNameplateEN = function (pid)
	return scenarioData.npidToNameplateEN[pid] or pid
end

local p = {}
local List = require 'Module:ListUtil'
local cargo = mw.ext.cargo
--[======[
	convert JSON use:
p.convertJSON({args={[==[
EnglishTextHere
]==], 
[==[
JapaneseTextHere
]==]}})
	
	]======]
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 parseScenario = function (s, lang)
	local frame = mw.getCurrentFrame()
	local wikitext = {}
	local parsed = ""
	local sections = {""}
	local mwgsub = mw.ustring.gsub
	local mwtrim = mw.text.trim
	local mwsplit = mw.text.split
	local mwsub = mw.ustring.sub
	s = mwgsub( s, "$k" , "" )
	s = mwgsub( s, "$p" , "\t" )
	s = mwgsub( s, "$Nu", "{{Summoner}}" )
	s = mwgsub( s, "$Nf", "{{Friend}}" )
	for section in mw.ustring.gmatch(s, "$[^$]*") do
		local parts = mwsplit(section, "|")
		for _,v in ipairs(parts) do
			if v ~= "" then
				sections[#sections + 1] = mwgsub( mwgsub( mwtrim(v), "%s*\t%s*" , "<br />" ), "\n" , "<br />" )
			end
		end
	end
	local name
	local heroMatchesName
	local img
	local expression
	for _, section in ipairs(sections) do
		if mwsub(section, 1, 1) ~= "$" then
			local dialogue = section
			if dialogue ~= "" then
				local STT = "{{StoryTextTable"
				if not heroMatchesName then
					STT = STT .. "|nameplate=" .. name
				end
				STT = STT .. "|" .. img
				if expression ~= "Face" then
					STT = STT .. "|expression=" .. (mw.ustring.match( expression, "Face_(.*)" ) or "")
				end
				STT = STT .. "|" .. dialogue
				if lang == "ja" then
					STT = STT .. "|ja}}"
				else
					STT = STT .. "}}"
				end
				wikitext[#wikitext + 1] = STT
			end
		elseif mwsub(section, 2, 3) == "Wm" then
			local speakerInfo = mwsplit(mwsub(section, 4), ",")
			local npid = mw.ustring.match( speakerInfo[1], "M[EP]ID_(.*)" )
			local nameJPJA = npidToNameplateJP(npid) --frame:expandTemplate{ title = "npidToNameplateJP", args = { npid } }
			img = imgToHero(speakerInfo[2]) --frame:expandTemplate{ title = 'imgToHero', args = { speakerInfo[2] } }
			heroMatchesName = nameJPJA == frame:expandTemplate{ title = "GetHeroJPName", args = { img } }
			if lang == "ja" then
				name = nameJPJA
			else
				name = npidToNameplateEN(npid) --frame:expandTemplate{ title = "npidToNameplateEN", args = { npid } }
			end
			expression = speakerInfo[3]
		elseif mwsub(section, 2, 2) == "E" then
			expression = mwsub(section, 3)
		elseif mwsub(section, 2, 4) == "Sbp" then
			wikitext[#wikitext + 1] = "{{StoryBGM|" .. mwsub(mw.text.split(section, ",")[1], 5) .. "}}"
		elseif mwsub(section, 2, 4) == "Ssp" then
			wikitext[#wikitext + 1] = "{{StorySE|" .. mwsub(mw.text.split(section, ",")[1], 5) .. "}}"
		elseif mwsub(section, 2, 3) == "Fo" then
			local params = mwsplit(mwsub(section, 4), ",")
			wikitext[#wikitext + 1] = "{{StoryFo|" .. table.concat(params,"|") .. "}}"
		end
	end
	return wikitext
end

local parseStructure = function (obj, lang)
	local opening = {}
	local mapBegin = {}
	local mapEnd = {}
	local ending = {}

	for _, t in ipairs(obj) do
		if (t["key"] == "MID_SCENARIO_OPENING_BGM") then
			opening[#opening + 1] = "{{StoryBGM|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_OPENING_IMAGE") then
			opening[#opening + 1] = "{{StoryImage|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_OPENING") then
			List.concat_self(opening, parseScenario(t["value"], lang))
		elseif (t["key"] == "MID_SCENARIO_MAP_BEGIN_BGM") then
			mapBegin[#mapBegin + 1] = "{{StoryBGM|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_MAP_BEGIN_IMAGE") then
			mapBegin[#mapBegin + 1] = "{{StoryImage|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_MAP_BEGIN") then
			List.concat_self(mapBegin, parseScenario(t["value"], lang))
		elseif (t["key"] == "MID_SCENARIO_MAP_END_BGM") then
			mapEnd[#mapEnd + 1] = "{{StoryBGM|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_MAP_END_IMAGE") then
			mapEnd[#mapEnd + 1] = "{{StoryImage|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_MAP_END") then
			List.concat_self(mapEnd, parseScenario(t["value"], lang))
		elseif (t["key"] == "MID_SCENARIO_ENDING_BGM") then
			ending[#ending + 1] = "{{StoryBGM|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_ENDING_IMAGE") then
			ending[#ending + 1] = "{{StoryImage|" .. t["value"] .. "}}"
		elseif (t["key"] == "MID_SCENARIO_ENDING") then
			List.concat_self(ending, parseScenario(t["value"], lang))
		end
	end

	local wikitext = {}
	local sectionCount = 0

	if #opening > 0 then
		sectionCount = sectionCount + 1
		wikitext[#wikitext + 1] = "===Opening==="
		wikitext[#wikitext + 1] = "{{StoryTextTableHeader}}"
		List.concat_self(wikitext, opening)
		wikitext[#wikitext + 1] = "{{StoryTextTableEnd}}"
	end
	if #mapBegin > 0 then
		sectionCount = sectionCount + 1
		wikitext[#wikitext + 1] = "===Beginning of the battle==="
		wikitext[#wikitext + 1] = "{{StoryTextTableHeader}}"
		List.concat_self(wikitext, mapBegin)
		wikitext[#wikitext + 1] = "{{StoryTextTableEnd}}"
	end
	if #mapEnd > 0 then
		sectionCount = sectionCount + 1
		wikitext[#wikitext + 1] = "====Stage Clear===="
		wikitext[#wikitext + 1] = "{{StoryTextTableHeader}}"
		List.concat_self(wikitext, mapEnd)
		wikitext[#wikitext + 1] = "{{StoryTextTableEnd}}"
	end
	if #ending > 0 then
		sectionCount = sectionCount + 1
		wikitext[#wikitext + 1] = "===Ending==="
		wikitext[#wikitext + 1] = "{{StoryTextTableHeader}}"
		List.concat_self(wikitext, ending)
		wikitext[#wikitext + 1] = "{{StoryTextTableEnd}}"
	end

	return wikitext, sectionCount
end

function p.convertJSON(frame)
	local wikiTextUSEN, sectionCountUSEN = parseStructure(mw.text.jsonDecode(frame.args[1] or "[]"), "en")
	local wikiTextJPJA, sectionCountJPJA = parseStructure(mw.text.jsonDecode(frame.args[2] or "[]"), "ja")

	local outputWikitext = {'==Story=='}
	if sectionCountUSEN == 1 and sectionCountJPJA == 1 and wikiTextUSEN[1] == wikiTextJPJA[1] then
		outputWikitext[#outputWikitext + 1] = table.remove(wikiTextUSEN, 1)
		table.remove(wikiTextJPJA, 1)
	end
	outputWikitext[#outputWikitext + 1] = '<tabber>English='
	List.concat_self(outputWikitext, wikiTextUSEN)
	outputWikitext[#outputWikitext + 1] = '|-|Japanese='
	List.concat_self(outputWikitext, wikiTextJPJA)
	outputWikitext[#outputWikitext + 1] = '</tabber>'
	outputWikitext[#outputWikitext + 1] = '{{StoryNav||}}'
	
	outputWikitext = table.concat(outputWikitext, '\n')
	mw.log(mw.text.trim(outputWikitext))
	return mw.getCurrentFrame():callParserFunction{ name = '#tag', args = { 'pre', outputWikitext } }
end

return p