如果你看到本段文字,说明该页面未正常加载全局JS,部分功能无法使用,请点击 刷新 重新加载页面。
如果打开页面显示缩略图创建出错,请点击刷新或页面右上WIKI功能中的刷新按钮清除页面缓存并刷新,如果还有问题,请多尝试几次。
全站通知:
模块:舰娘台词
刷
历
编
跳到导航
跳到搜索
此模块的文档可以在模块:舰娘台词/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 = '登录界面',
extra5th = '五周年登录',
extra6th = '六周年登录',
drop_descrip = '舰船型号',
profile = '自我介绍',
desc = '皮肤描述',
unlock = '获取台词',
--主界面
login = '登录台词',
detail = '查看详情',
main = '主界面',
touch = '触摸台词',
touch2 = '特殊触摸',
headtouch = '摸头台词',
--场景
mission = '任务提醒',
mission_complete = '任务完成',
mail = '邮件提醒',
home = '回港台词',
--好感度
feeling1 = '好感度-失望',
feeling2 = '好感度-陌生',
feeling2i = '好感度-普通',
feeling3 = '好感度-友好',
feeling4 = '好感度-喜欢',
feeling4i = '好感度-协作',
feeling5 = '好感度-爱',
feeling5i = '好感度-应援',
feeling1m = '好感度-未知',
feeling2m = '好感度-调率',
feeling3m = '好感度-理解',
feeling4m = '好感度-同步',
feeling5m = '好感度-共鸣',
propose = '誓约台词',
--场景
expedition = '委托完成',
upgrade = '强化成功',
--战斗台词
battle = '旗舰开战',
win_mvp = '胜利台词',
lose = '失败台词',
skill = '技能台词',
hp_warning = '血量告急',
couple_encourage = '彩蛋台词',
--莱莎的炼金工房相关
ryza_item = '素材收集',
ryza_shop = '商店',
ryza_atellier = '炼金工房',
--闪乱神乐NL
sknl_pt = '秘传忍法书',
--领航员-TB
tb_shengdan = '圣诞节',
tb_chuxi = '除夕',
tb_xinnian = '新年',
tb_qingrenjie = '情人节',
tb_zhongqiu = '中秋节',
tb_wansheng = '万圣节',
tb_huodong = '活动提醒',
tb_genghuan = '更换外形模块',
tb_chime = '报时'
}
KeyList = {
'extra',
'extra5th',
'extra6th',
'drop_descrip',
'profile',
'desc',
'unlock',
--主界面
'login',
'detail',
'main',
'touch',
'touch2',
'headtouch',
--场景
'mission',
'mission_complete',
'mail',
'home',
--好感度
'feeling1',
'feeling2',
'feeling2i',
'feeling3',
'feeling4',
'feeling4i',
'feeling5',
'feeling5i',
'feeling1m',
'feeling2m',
'feeling3m',
'feeling4m',
'feeling5m',
'propose',
--场景
'expedition',
'upgrade',
--战斗台词
'battle',
'win_mvp',
'lose',
'skill',
'hp_warning',
--彩蛋台词
'couple_encourage',
--莱莎的炼金工房相关
'ryza_item',
'ryza_shop',
'ryza_atellier',
--闪乱神乐NL
'sknl_pt',
--领航员-TB
'tb_shengdan',
'tb_chuxi',
'tb_xinnian',
'tb_qingrenjie',
'tb_zhongqiu',
'tb_wansheng',
'tb_huodong',
'tb_genghuan',
'tb_chime',
}
HideIfNoMediaFile = {
'extra5th',
'extra6th',
}
ShipWordsParameters = {
extra5th = {'五周年登录台词', '五周年登录', mediaFile = '%sextra5th.mp3'};
extra6th = {'六周年登录台词', '六周年登录', mediaFile = '%sextra6th.mp3'};
drop_descrip = '舰船型号台词',
profile = '自我介绍台词',
desc = {'描述台词', '皮肤描述台词', mediaFile = '%sget.mp3'};
unlock = {'获取台词', '获得台词', mediaFile = '%sget.mp3'};
login ={'登录台词', '登陆台词'};
detail = {'查看详情台词', '详情台词'};
--主界面台词序列特殊处理
main = {'主界面台词'};
touch = {'普通触摸台词', '触摸台词', mediaFile = '%stouch_1.mp3'};
touch2 = {'特殊触摸台词', '特殊触摸', mediaFile = '%stouch_2.mp3'};
headtouch = {'摸头台词', mediaFile = '%stouch_head.mp3'};
mission = {'任务提醒台词', '任务台词', mediaFile = '%stask.mp3'};
mission_complete = {'任务完成台词', '任务完成'};
mail = {'邮件提醒台词', '邮件台词'};
home = '回港台词',
feeling1 = '好感度-失望台词',
feeling2 = '好感度-陌生台词',
feeling2i = '好感度-普通台词',
feeling3 = '好感度-友好台词',
feeling4 = '好感度-喜欢台词',
feeling4i = '好感度-协作台词',
feeling5 = '好感度-爱台词',
feeling5i = '好感度-应援台词',
feeling1m = {'好感度-未知台词', mediaFile = '%sfeeling1.mp3'};
feeling2m = {'好感度-调率台词', mediaFile = '%sfeeling2.mp3'};
feeling3m = {'好感度-理解台词', mediaFile = '%sfeeling3.mp3'};
feeling4m = {'好感度-同步台词', mediaFile = '%sfeeling4.mp3'};
feeling5m = {'好感度-共鸣台词', mediaFile = '%sfeeling5.mp3'};
propose = '誓约台词',
expedition = {'委托完成台词', '军事委托完成台词'};
upgrade = {'强化成功台词', '强化成功'};
battle = {'旗舰开战台词', '旗舰开战', mediaFile = '%swarcry.mp3'};
win_mvp = {'胜利台词', '胜利MVP台词', mediaFile = '%smvp.mp3'};
lose = {'失败台词', '战斗失败'};
skill = '技能台词',
hp_warning = {'血量告急台词', 'hp告急台词', mediaFile = '%shp.mp3'};
--彩蛋台词序列特殊处理
couple_encourage = {'彩蛋台词'};
--莱莎的炼金工房相关
ryza_item = {'素材收集'};
ryza_shop = {'商店'};
ryza_atellier = {'炼金工房'};
--闪乱神乐NL
sknl_pt = {'秘传忍法书'};
--领航员-TB
tb_shengdan = {'圣诞节'};
tb_chuxi = {'除夕'};
tb_xinnian = {'新年'};
tb_qingrenjie = {'情人节'};
tb_zhongqiu = {'中秋节'};
tb_wansheng = {'万圣节'};
tb_huodong = {'活动提醒'};
tb_genghuan = {'更换外形模块'};
tb_chime = {'报时'};
}
p.ShipWordsParameters = ShipWordsParameters
CollapsableKeys = {
'hp_warning',
'headtouch',
'touch2'
}
GroupKeys = {
main = true,
couple_encourage = true
}
local frame = mw.getCurrentFrame()
--------------------------------------------------
-- 主要过程
--------------------------------------------------
local sm_html = [[
<div class='sm-bar' style='display: block;'>
<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(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 and not html_sm2 and inTable(HideIfNoMediaFile, k) then
-----------------------------
--单语音文件
elseif 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
--跳过空语音周年项目
if not (not next(buff) and inTable(HideIfNoMediaFile, k)) then
result = result .. ([[
<tr data-key="%s">
<th>%s</th>
<td>%s</td>
</tr>
]]):format( k,
KeyNameDict[k] or k,
table.concat(buff,''))
end
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,
['样式'] = 'shiptable',
['展开'] = value.active
}) .. '\n' .. tostring(value.text) ..parseCollapsePanel({
'内容结束'
}) .. '\n'
end
result = result..parseCollapsePanel({
'结束'
})
return result
end
--解析一个包含全部信息的表,并生成整个选项卡面板
function ParseShipWordsTabPanel(data)
data.label_style = 'padding:0.4em 0.6em;'
return parseTabPanel(data)
end
--解析参数列表
function ParseArguments(frame)
local data = {}
data.theme = 'shiptable'
--默认不应用样式表
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;
local shipName = args["shipName"] or false
for _, k in ipairs(KeyList) do
if k == "shipName" then break end --舰娘名称,用于默认语音
for i = 1, 24 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'])
if not data[k][i].mf and shipName then
local mediaFile = type(ShipWordsParameters[k]) == 'table' and ShipWordsParameters[k].mediaFile
if not GroupKeys[k] then
data[k][i].mf = mediaFile
and mediaFile:format(shipName .. '_')
or shipName .. '_' .. k ..'.mp3';
else
data[k][i].mf = mediaFile
and mediaFile:format(shipName .. '_')
or shipName .. '_' .. k .. '_' .. i ..'.mp3';
end
end
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