提供一个语音台词写法的范例

This commit is contained in:
Spmario233 2024-04-28 21:02:20 +08:00
parent d9532d354d
commit 1f67b90fec
4 changed files with 79 additions and 11 deletions

View File

@ -4,6 +4,7 @@ import cards from "./card.js";
import pinyins from "./pinyin.js"; import pinyins from "./pinyin.js";
import skills from "./skill.js"; import skills from "./skill.js";
import translates from "./translate.js"; import translates from "./translate.js";
import voices from "./voices.json";
game.import("character", function () { game.import("character", function () {
return { return {
@ -98,7 +99,7 @@ game.import("character", function () {
}, },
card: { ...cards }, card: { ...cards },
skill: { ...skills }, skill: { ...skills },
translate: { ...translates }, translate: { ...translates, ...voices },
pinyins: { ...pinyins }, pinyins: { ...pinyins },
}; };
}); });

10
character/key/voices.json Normal file
View File

@ -0,0 +1,10 @@
{
"#yuri_xingdong1": "では、オペレーション・スターーート!!",
"#yuri_xingdong2": "では、オペレーション・スタート!",
"#yuri_xingdong3": "では、オペレーションスタート!",
"#yuri_xingdong_gain1": "…さすがね、あたしの勘。",
"#yuri_xingdong_gain2": "あたしの予想ではね。",
"#yuri_wangxi1": "賢明ね。これでようやくあなたにも戦線で戦う目的が生まれたってわけね。",
"#yuri_wangxi2": "落ち着いて…ここは地獄なんかじゃないわ。",
"#key_yuri:die": "ひどい…リーダーね。"
}

View File

@ -1482,8 +1482,9 @@ export class Game {
* @typedef {[string,number]|string|number|boolean} audioInfo * @typedef {[string,number]|string|number|boolean} audioInfo
* @typedef {{audio: audioInfo, audioname?:string[], audioname2?:{[playerName: string]: audioInfo}}} skillInfo * @typedef {{audio: audioInfo, audioname?:string[], audioname2?:{[playerName: string]: audioInfo}}} skillInfo
* @param { string } skill 技能名 * @param { string } skill 技能名
* @param { Player | string } [player] 角色/角色名 * @param { Player | Object | string } [player] 角色/角色名
* @param { skillInfo | audioInfo } [skillInfo] 预设的skillInfo/audioInfo(转为skillInfo)覆盖lib.skill[skill] * @param { skillInfo | audioInfo } [skillInfo] 预设的skillInfo/audioInfo(转为skillInfo)覆盖lib.skill[skill]
* @param { boolean | undefined } [useRawAudio]
* @returns { string[] } 语音地址列表 * @returns { string[] } 语音地址列表
* @example * @example
* ```js * ```js
@ -1515,7 +1516,7 @@ export class Game {
* //如果key中包含发动技能的角色名player则直接改用info.audioname2[player]来播放语音 * //如果key中包含发动技能的角色名player则直接改用info.audioname2[player]来播放语音
* ``` * ```
*/ */
parseSkillAudio(skill, player, skillInfo) { parseSkillAudio(skill, player, skillInfo, useRawAudio) {
if (typeof player === "string") player = { name: player }; if (typeof player === "string") player = { name: player };
else if (typeof player !== "object" || player === null) player = {}; else if (typeof player !== "object" || player === null) player = {};
@ -1527,7 +1528,7 @@ export class Game {
if (!history.includes(skill)) return true; if (!history.includes(skill)) return true;
if (history[0] === skill) return false; if (history[0] === skill) return false;
//deadlock //deadlock
throw new RangeError(`parseSkillAudio: ${skill} in `, history, ` forms a deadlock`); throw new RangeError(`parseSkillAudio: ${skill} in ${ history }forms a deadlock`);
}; };
const getName = (filter) => { const getName = (filter) => {
@ -1538,7 +1539,7 @@ export class Game {
if (result) return result; if (result) return result;
if (!name) return result; if (!name) return result;
if (filter(name)) return name; if (filter(name)) return name;
let tempname = get.character(name, 4).find((tag) => tag.startsWith("tempname:")); let tempname = get.character(name).trashBin.find((tag) => tag.startsWith("tempname:"));
if (!tempname) return result; if (!tempname) return result;
tempname = tempname tempname = tempname
.split(":") .split(":")
@ -1555,7 +1556,7 @@ export class Game {
* @param {skillInfo} [skillInfo] * @param {skillInfo} [skillInfo]
* @returns {string[]} * @returns {string[]}
*/ */
function getAudioList(skill, options, skillInfo) { function getAudioList(skill, options, skillInfo, useRawAudio) {
const info = skillInfo || lib.skill[skill]; const info = skillInfo || lib.skill[skill];
if (!info) { if (!info) {
console.error(new ReferenceError(`parseSkillAudio: Cannot find ${skill} in lib.skill`)); console.error(new ReferenceError(`parseSkillAudio: Cannot find ${skill} in lib.skill`));
@ -1610,7 +1611,7 @@ export class Game {
) )
format = ".mp3"; format = ".mp3";
if (path && format) return parseAudio(audioInfo, options, [true, 2]); if (path && format) return parseAudio(audioInfo, options, [true, 2]);
return [`${path}${audioInfo}${format}`]; return [useRawAudio ? audioInfo : `${path}${audioInfo}${format}`];
} }
let _audioname = getName((i) => audioname.includes(i)); let _audioname = getName((i) => audioname.includes(i));
@ -1622,13 +1623,32 @@ export class Game {
const audioList = []; const audioList = [];
list[2] = parseInt(list[2]); list[2] = parseInt(list[2]);
for (let i = 1; i <= list[2]; i++) { for (let i = 1; i <= list[2]; i++) {
audioList.push(`${list[1] || "skill"}/${skill}${_audioname}${i}.${list[3] || "mp3"}`); if(useRawAudio) audioList.push(`${skill}${_audioname}${i}`);
else audioList.push(`${list[1] || "skill"}/${skill}${_audioname}${i}.${list[3] || "mp3"}`);
} }
return audioList; return audioList;
} }
return getAudioList(skill, { audioname: [], history: [] }, skillInfo); return getAudioList(skill, { audioname: [], history: [] }, skillInfo);
} }
/**
* 根据skill中的audio,audioname,audioname2和player来获取技能台词列表
* @typedef {[string,number]|string|number|boolean} audioInfo
* @typedef {{audio: audioInfo, audioname?:string[], audioname2?:{[playerName: string]: audioInfo}}} skillInfo
* @param { string } skill 技能名
* @param { Player | Object | string } [player] 角色/角色名
* @param { skillInfo | audioInfo } [skillInfo] 预设的skillInfo/audioInfo(转为skillInfo)覆盖lib.skill[skill]
* @returns { string[] } 语音地址列表
*/
parseSkillText(skill, player, skillInfo){
const audios = game.parseSkillAudio(skill, player, skillInfo, true);
const voiceMap = [];
audios.forEach(audioname => {
const voiceText = lib.translate[`#${audioname}`];
if(voiceText) voiceMap.push(voiceText);
});
return voiceMap;
}
/** /**
* *
* @param { string } skill * @param { string } skill

View File

@ -3494,14 +3494,14 @@ export class Click {
} else { } else {
// 样式一 // 样式一
//TODO: 这里的数据也暂时没有改成新格式,需要后续的修改 //TODO: 这里的数据也暂时没有改成新格式,需要后续的修改
const nameInfo = get.character(name);
const introduction = ui.create.div(".characterintro", uiintro), const introduction = ui.create.div(".characterintro", uiintro),
showCharacterNamePinyin = lib.config.show_characternamepinyin; showCharacterNamePinyin = lib.config.show_characternamepinyin;
if (showCharacterNamePinyin != "doNotShow") { if (showCharacterNamePinyin != "doNotShow") {
const characterIntroTable = ui.create.div(".character-intro-table", introduction), const characterIntroTable = ui.create.div(".character-intro-table", introduction),
span = document.createElement("span"); span = document.createElement("span");
span.style.fontWeight = "bold"; span.style.fontWeight = "bold";
const nameInfo = get.character(name), const exInfo = nameInfo.trashBin,
exInfo = nameInfo.trashBin,
characterName = characterName =
exInfo && exInfo.includes("ruby") ? lib.translate[name] : get.rawName2(name); exInfo && exInfo.includes("ruby") ? lib.translate[name] : get.rawName2(name);
span.innerHTML = characterName; span.innerHTML = characterName;
@ -3632,8 +3632,45 @@ export class Click {
const htmlParser = document.createElement("body"); const htmlParser = document.createElement("body");
htmlParser.innerHTML = get.characterIntro(name); htmlParser.innerHTML = get.characterIntro(name);
Array.from(htmlParser.childNodes).forEach((value) => introduction.appendChild(value)); Array.from(htmlParser.childNodes).forEach((value) => introduction.appendChild(value));
//添加技能语音部分
const dieAudio = lib.translate[`#${name}:die`];
const skillAudioMap = new Map();
nameInfo.skills.forEach(skill => {
const voiceMap = game.parseSkillText(skill, name, null, true);
if(voiceMap.length) skillAudioMap.set(skill, voiceMap);
});
if (dieAudio || skillAudioMap.size > 0){
introduction.appendChild(document.createElement("hr"));
const skillNameSpan = document.createElement("span");
skillNameSpan.innerHTML = `技能台词<br>`;
introduction.appendChild(skillNameSpan);
if(skillAudioMap.size > 0){
skillAudioMap.forEach((texts, skill) => {
const skillNameSpan = document.createElement("span"), skillNameSpanStyle = skillNameSpan.style;
skillNameSpanStyle.fontWeight = "bold";
skillNameSpan.innerHTML = `<br>${get.translation(skill)}<br>`;
introduction.appendChild(skillNameSpan);
texts.forEach((text, index) => {
const skillTextSpan = document.createElement("span");
skillTextSpan.innerHTML = `${index + 1}. ${text}<br>`;
introduction.appendChild(skillTextSpan);
})
});
}
if(dieAudio){
const skillNameSpan = document.createElement("span"), skillNameSpanStyle = skillNameSpan.style;
skillNameSpanStyle.fontWeight = "bold";
skillNameSpan.innerHTML = `<br>阵亡台词<br>`;
introduction.appendChild(skillNameSpan);
const skillTextSpan = document.createElement("span");
skillTextSpan.innerHTML = `${dieAudio}`;
introduction.appendChild(skillTextSpan);
}
}
const introduction2 = ui.create.div(".characterintro.intro2", uiintro); const introduction2 = ui.create.div(".characterintro.intro2", uiintro);
var list = get.character(name, 3) || []; var list = get.character(name).skills;
var skills = ui.create.div(".characterskill", uiintro); var skills = ui.create.div(".characterskill", uiintro);
if (lib.config.touchscreen) { if (lib.config.touchscreen) {
lib.setScroll(introduction); lib.setScroll(introduction);