全站通知:
模块:舰娘台词
刷
历
编
跳到导航
跳到搜索
此模块的文档可以在模块:舰娘台词/doc创建
--[[
{{#invoke: 舰娘台词 | 台词表格
| name = 胡德
| touch = 我随时能够行动
| home = 漂亮的战斗,指挥官
| main_1 = 一名优秀的指挥官对于红茶应该有深入的了解
| main_2 = 这个字是……啊,原来刚才看岔了,抱歉,我的视力不太好呢
| main_3 = 多听,少说,您应当多听取他人的意见,但保留自己的判断
| feeling1 = …………我会听从你的命令
| feeling1_jp = 私はあなたの命令に従います。
| feeling1_mediaFile = 胡德feeling1.mp3
}} ]]
--[[
{{#invoke: 舰娘台词 | 台词面板
| 标题1 = 其他台词
| 内容1 = {{#invoke: 舰娘台词 | 台词表格
| profile = 汝想知道些什么?
| drop_descrip = 旧V级驱逐舰—吸血鬼,舷号D68
}}
| 标题2 = 吸血鬼·婚纱
| 内容2 = {{#invoke: 舰娘台词 | 台词表格
| profile = 汝想知道些什么?
| drop_descrip = 旧V级驱逐舰—吸血鬼,舷号D68
}}
}} ]]
local p = {}
KeyNameDict = {
extra = '登陆界面',
drop_descrip = '舰船型号',
profile = '自我介绍',
desc = '皮肤描述',
unlock = '获取台词',
--主界面
login = '登录台词',
detail = '查看详情',
main = '主界面',
touch = '触摸台词',
touch2 = '特殊触摸',
headtouch = '摸头台词',
--场景
mission = '任务提醒',
mission_complete = '任务完成',
mail = '邮件提醒',
home = '回港台词',
--好感度
feeling1 = '好感度-失望',
feeling2 = '好感度-陌生',
feeling3 = '好感度-友好',
feeling4 = '好感度-喜欢',
feeling5 = '好感度-爱',
propose = '誓约台词',
--场景
expedition = '委托完成',
upgrade = '强化成功',
--战斗台词
battle = '旗舰开战',
win_mvp = '胜利台词',
lose = '失败台词',
skill = '技能台词',
hp_warning = '血量告急',
couple_encourage = '彩蛋台词'
}
KeyList = {
'extra',
'drop_descrip',
'profile',
'desc',
'unlock',
--主界面
'login',
'detail',
'main',
'touch',
'touch2',
'headtouch',
--场景
'mission',
'mission_complete',
'mail',
'home',
--好感度
'feeling1',
'feeling2',
'feeling3',
'feeling4',
'feeling5',
'propose',
--场景
'expedition',
'upgrade',
--战斗台词
'battle',
'win_mvp',
'lose',
'skill',
'hp_warning',
'couple_encourage'
}
CollapsableKeys = {
'hp_warning',
'headtouch',
'touch2'
}
local frame = mw.getCurrentFrame()
--------------------------------------------------
-- 主要过程
--------------------------------------------------
local sm_html = [[
<div class='sm-bar'><a title="%s" class="sm-button sm-play-pause"></a>
<div class='sm-audio-src'>%s</div>
</div>]]
--生成语音的HTML并剔除台词文本中的<div>
function ParseMediaFileToHTML(mediaFile, wordLine, tooltip)
local text = wordLine:gsub('<div.+</div>', '')
local html = wordLine:match('<div.+</div>')
if not mediaFile then
--兼容 直接在嵌套{{Player|xx.mp3}}
if html and not html:match('//%S+%.mp3') then
mw.log('[舰娘台词]: 参数的<div>中没有包含mp3文件')
mw.log(wordLine)
return nil, text
end
return html, text
end
if html then
mw.log('[舰娘台词]: 参数中不应当包含<div>')
mw.log(wordLine)
end
--将文件名转换为URL
if not mediaFile:match('^https?://') then
local file = frame:callParserFunction('filepath', mediaFile) or ''
if file == '' then
mw.log('[舰娘台词]: 媒体文件不存在'..mediaFile)
return nil, text
end
mediaFile = file
end
html = sm_html:format(tooltip or '播放/停止', mediaFile)
return html, text
end
-- 根据包含台词信息的数据包解析为表格(面板的一个页面)
function ShowShipWordsTable(data)
local result = [[
<table class="table-ShipWordsTable">
]]
for _, k in ipairs(KeyList) do
if not data[k] then
--跳过空项目
elseif table.maxn(data[k]) < 1 and inTable(CollapsableKeys, k) then
--跳过空项目
else
local buff = {}
for i, dd in pairs(data[k]) do
--[[
td
.ship_word_block .ship_word_media_wrap
p.ship_word_line //日文台词
[p.ship_word_line //中文台词]
.sm //语音
.ship_word_block
.ship_word_media_wrap
p.ship_word_line //日文台词
.sm //日文语音
.ship_word_media_wrap
p.ship_word_line //中文台词
.sm //中文台词
]]
--根据mf参数和text参数获取语音和剔除div后的台词文本
local html_sm, text = ParseMediaFileToHTML(dd.mf, dd.text or '', KeyNameDict[k])
local html_sm2, text2 = ParseMediaFileToHTML(dd.jp_mf, dd.jp or '', KeyNameDict[k])
-----------------------------
--单语音文件
if not html_sm or not html_sm2 then
table.insert(buff,([[
<div class="ship_word_block ship_word_media_wrap" data-key="%s" data-key-i="%s">
]]):format(k, i))
--插入【日语台词】
if dd.jp and text2 ~= '' then
table.insert(buff, ([[
<p class="ship_word_line" data-lang="jp" data-key="%s" data-key-i="%s">
]]):format(k, i))
--TODO 修改Qchar.js后移除冗余的data-key
table.insert(buff, text2)
table.insert(buff, '</p>\n')
end
--插入【中文台词】
if dd.text and text ~= '' then
table.insert(buff, ([[
<p class="ship_word_line" data-lang="zh" data-key="%s" data-key-i="%s">
]]):format(k, i))
--TODO 修改Qchar.js后移除冗余的data-key
table.insert(buff, text)
table.insert(buff, '</p>\n')
end
--插入【语音】
table.insert(buff, html_sm or html_sm2 or '')
table.insert(buff, '</div>')
----------------------------
-- 双语音文件
else
table.insert(buff, ([[
<div class="ship_word_block" data-key="%s" data-key-i="%s">
]]):format(k, i))
--插入【日语台词】
table.insert(buff, [[
<div class="ship_word_media_wrap">
<p class="ship_word_line" data-lang="jp">
]])
table.insert(buff, text2)
table.insert(buff, '</p>\n')
--插入【日语语音】
table.insert(buff, html_sm2)
table.insert(buff, '\n</div>')
--插入【中文台词】
table.insert(buff, [[
<div class="ship_word_media_wrap">
<p class="ship_word_line" data-lang="zh">
]])
table.insert(buff, text)
table.insert(buff, '</p>\n')
--插入【中文语音】
table.insert(buff, html_sm)
table.insert(buff, '\n</div></div>')
end
end
result = result .. ([[
<tr data-key="%s">
<th>%s</th>
<td>%s</td>
</tr>
]]):format( k,
KeyNameDict[k] or k,
table.concat(buff,''))
end
end
return result..'</table>'
end
p.ShowShipWordsTable = ShowShipWordsTable
--解析一个包含全部信息的表,并生成整个折叠面板
function ParseShipWordsPanel(data)
local result = ''
result = result..parseCollapsePanel({
'开始',
['主框'] = 1
})
for i, value in ipairs(data) do
result = result..parseCollapsePanel({
['标题'] = value.title,
['选项'] = 'ShipWords-'..i,
['主框'] = 1,
['样式'] = data.theme or 'primary',
['展开'] = value.active
}) .. '\n' .. tostring(value.text) ..parseCollapsePanel({
'内容结束'
}) .. '\n'
end
result = result..parseCollapsePanel({
'结束'
})
return result
end
--解析一个包含全部信息的表,并生成整个选项卡面板
function ParseShipWordsTabPanel(data)
data.label_style = 'font-weight:bolder; padding:0.5em 1.2em;'
return parseTabPanel(data)
end
--解析参数列表
function ParseArguments(frame)
local data = {}
data.theme = frame.args['样式'] or frame.args['主题']
--默认不应用样式表
data.no_stylesheet = not frame.args['应用样式表']
or mw.text.trim(frame.args['应用样式表']) == '否'
--默认展开第一个子面板
local selected = tonumber(frame.args['选中'] or 1) or 1
--生成随机种子,为生成ID做准备
math.randomseed(os.time())
local i = 1
local labelN = '标题'..i
while frame.args[labelN] do
local title = mw.text.encode(frame.args[labelN])
local text = frame.args['内容'..i]
--将标题记录到table中,以方便js获取
text = text:gsub('<table class=\"table%-ShipWordsTable\">',
'<table class=\"table-ShipWordsTable\" data-title=\"'..title..'\">')
data[i] = {
title = title,
text = text,
id = generateId(frame.args['Id'..i] or frame.args['ID'..i]),
active = i == selected
}
i = i + 1
labelN = '标题'..i
end
return data
end
--解析台词表格的Key=Value参数列表
function ParseKeyWordArguments(frame)
local data = {};
local args = frame.args;
for _, k in ipairs(KeyList) do
for i = 1, 15 do
local key = i == 1 and args[k] and k or k..'_'..i
local text = trimNullOrEmpty(args[key])
--main_N 支持间断的N
if not text and k ~= 'main' then break end
--[[
data[k] = {
[1] = {
text = '中文文本'
jp = '日文文本'
mf = 'xxx.mp3'
jp_mf = 'xxx2.mp3'
}
} ]]
if text then
data[k] = data[k] or {}
data[k][i] = data[k][i] or {}
data[k][i].text = text
data[k][i].jp = trimNullOrEmpty(args[key..'_jp'])
data[k][i].mf = trimNullOrEmpty(args[key..'_mediaFile'])
data[k][i].jp_mf = trimNullOrEmpty(args[key..'_jp_mediaFile'])
end
end
end
--兼容旧的写法
if data['main'] and table.maxn(data['main']) == 1 then
local spl = mw.text.split(data['main'][1].text, '<br ?/?>')
if #spl > 1 then
for i = 1, #spl do
data['main'][i] = data['main'][i] or {}
data['main'][i].text = trimNullOrEmpty(spl[i])
end
end
end
if data['couple_encourage'] and #data['couple_encourage'] == 1 then
local spl = mw.text.split(data['couple_encourage'][1].text, '<br ?/?>')
if #spl > 1 then
for i = 1, #spl do
data['couple_encourage'][i] = data['couple_encourage'][i] or {}
data['couple_encourage'][i].text = trimNullOrEmpty(spl[i])
end
end
end
return data
end
--------------------------------------------------
-- 公开函数
--------------------------------------------------
p['台词表格'] = function(frame)
local data = ParseKeyWordArguments(frame)
return ShowShipWordsTable(data)
end
p['台词面板'] = function(frame)
local data = ParseArguments(frame)
return ParseShipWordsTabPanel(data)
end
p['台词折叠面板'] = function(frame)
local data = ParseArguments(frame)
--data[1].active = false
return ParseShipWordsPanel(data)
end
p['测试'] = function(frame)
frame = frame or {
args = {
home = '漂亮的战斗,指挥官<div cc>aa</div>';
feeling1_jp = ' 私はあなたの命令に従います。<div cc>aa</div>';
main_1 = 'main_1文字';
main_1_jp = 'main_1JP';
main_1_mediaFile = '平海换装2_main_1.mp3';
main_2 = 'main_2文字';
main_2_jp = '身份确认——欢迎回来,主人';
main_2_mediaFile = '平海换装2_main_1.mp3';
main_2_jp_mediaFile = '加斯科涅login_ex100.mp3';
}
}
local data = ParseKeyWordArguments(frame)
local text = ShowShipWordsTable(data)
mw.log(text)
return text
end
p.RunTest = function()
end
--------------------------------------------------
-- 工具函数
--------------------------------------------------
function parseCollapsePanel(arg_list)
return mw.getCurrentFrame():expandTemplate({
title = '折叠面板',
args = arg_list
})
end
function parseTabPanel(data)
local mTbPn = require('模块:选项卡面板')
return mTbPn.GenerateWholePanel(data)
end
function generateId(text)
text = text and text ~= '' and text:lower()
or ('%X'):format(math.random(1677215))
return 'ShWrPn-'..text;
end
function inTable(tab, val)
for k, v in pairs(tab) do
if v == val then return true end
end
return false
end
function trimNullOrEmpty(s)
if not s then return false end
s = mw.text.trim(s)
return s ~= '' and s
end
return p