Merge pull request #1349 from kuangshen04/PR-Branch

parseDieTextMap功能升级
This commit is contained in:
Spmario233 2024-05-13 14:35:33 +08:00 committed by GitHub
commit 467f9401ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 189 additions and 111 deletions

View File

@ -1471,13 +1471,15 @@ export class Game {
* @returns { any[] } 语音地址列表 * @returns { any[] } 语音地址列表
*/ */
parseSkillTextMap(skill, player, skillInfo) { parseSkillTextMap(skill, player, skillInfo) {
if (typeof player === "string") player = { name: player }; if (typeof player === "string") player = get.convertedCharacter({ name: player });
else if (typeof player !== "object" || player === null) player = {}; else if (typeof player !== "object" || player === null) player = get.convertedCharacter({ isNull: true });
if (skillInfo && (typeof skillInfo !== "object" || Array.isArray(skillInfo))) skillInfo = { audio: skillInfo }; if (skillInfo && (typeof skillInfo !== "object" || Array.isArray(skillInfo))) skillInfo = { audio: skillInfo };
const checkSkill = (skill, history) => { const defaultInfo = [true, 2];
if (!lib.skill[skill]) return false;
const check = (skill, history) => {
if (!get.info(skill)) return false;
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
@ -1495,17 +1497,18 @@ export class Game {
}, void 0); }, void 0);
}; };
const getTextMap = (path, name, ext) => ({ const getTextMap = (path, name, ext, isDefault) => ({
name, name,
file: `${path}${name}${ext}`, file: `${path}${name}${ext}`,
text: lib.translate[`#${name}`], text: lib.translate[`#${name}`],
isDefault
}); });
function getAudioList(skill, options, skillInfo) { const getAudioList = (skill, options, skillInfo) => {
const info = skillInfo || lib.skill[skill]; const info = skillInfo || get.info(skill);
if (!info) { if (!info) {
console.error(new ReferenceError(`parseSkillAudio: Cannot find ${skill} in lib.skill`)); console.error(new ReferenceError(`parseSkillTextMap: Cannot find ${skill} in lib.skill`));
return parseAudio(skill, options, [true, 2]); return parseAudio(skill, Object.assign(options, { isDefault: true }), defaultInfo);
} }
const { audioname, history } = options; const { audioname, history } = options;
@ -1517,14 +1520,15 @@ export class Game {
return parseAudio(skill, options, audioInfo); return parseAudio(skill, options, audioInfo);
} }
function parseAudio(skill, options, audioInfo) { const parseAudio = (skill, options, audioInfo) => {
const audioname = options.audioname.slice(); const audioname = options.audioname.slice();
const history = options.history.slice(); const history = options.history.slice();
options = { audioname, history }; const isDefault = options.isDefault;
options = { audioname, history, isDefault };
if (Array.isArray(audioInfo)) { if (Array.isArray(audioInfo)) {
if (audioInfo.length === 2 && typeof audioInfo[0] === "string" && typeof audioInfo[1] === "number") { if (audioInfo.length === 2 && typeof audioInfo[0] === "string" && typeof audioInfo[1] === "number") {
const [name, number] = audioInfo; const [name, number] = audioInfo;
if (checkSkill(name, history)) return getAudioList(name, options).slice(0, number); if (check(name, history)) return getAudioList(name, options).slice(0, number);
return parseAudio(name, options, number); return parseAudio(name, options, number);
} }
@ -1535,93 +1539,145 @@ export class Game {
return Object.values(map); return Object.values(map);
} }
if (!["string", "number", "boolean"].includes(typeof audioInfo)) return parseAudio(skill, options, [true, 2]); if (!["string", "number", "boolean"].includes(typeof audioInfo)) return parseAudio(skill, Object.assign(options, { isDefault: true }), defaultInfo);
if (audioInfo === false) return []; if (audioInfo === false) return [];
if (typeof audioInfo === "string") { if (typeof audioInfo === "string") {
if (["data:", "blob:"].some(prefix => audioInfo.startsWith(prefix))) return [getTextMap("", audioInfo, "")]; if (["data:", "blob:"].some(prefix => audioInfo.startsWith(prefix))) return [getTextMap("", audioInfo, "", isDefault)];
if(checkSkill(audioInfo, history)) return getAudioList(audioInfo, options); if (check(audioInfo, history)) return getAudioList(audioInfo, options);
} }
audioInfo = String(audioInfo); audioInfo = String(audioInfo);
const list = audioInfo.match(/(?:(.*):|^)(true|\d+)(?::(.*)|$)/); // [path, number|true, ext] const list = audioInfo.match(/(?:(.*):|^)(true|\d+)(?::(.*)|$)/); // [path, number|true, ext]
if (!list) { if (list) {
let path = "", ext = ""; let [, path = "skill", audioNum, ext = "mp3"] = list;
if (!/^db:|^ext:|\//.test(audioInfo)) path = "skill/"; let _audioname = getName(i => audioname.includes(i));
if (!/\.\w+$/.test(audioInfo)) ext = ".mp3"; _audioname = _audioname ? `_${_audioname}` : "";
if (path && ext) return parseAudio(audioInfo, options, [true, 2]);
//@TODO if (audioNum === "true") return [getTextMap(`${path}/`, `${skill}${_audioname}`, `.${ext}`, isDefault)];
console.warn(`${skill}中“${audioInfo}”的地址写法暂时没有完全支持台词系统。`);
return [getTextMap(path, audioInfo, ext)]; const audioList = [];
audioNum = parseInt(audioNum);
for (let i = 1; i <= audioNum; i++) {
audioList.push(getTextMap(`${path}/`, `${skill}${_audioname}${i}`, `.${ext}`, isDefault));
}
return audioList;
} }
let [, path = "skill", audioNum, ext = "mp3"] = list; let path = "", ext = "";
let _audioname = getName(i => audioname.includes(i)); if (!/^db:|^ext:|\//.test(audioInfo)) path = "skill/";
_audioname = _audioname ? `_${_audioname}` : ""; if (!/\.\w+$/.test(audioInfo)) ext = ".mp3";
if (path && ext) return parseAudio(audioInfo, Object.assign(options, { isDefault: true }), defaultInfo);
if (audioNum === "true") return [getTextMap(`${path}/`, `${skill}${_audioname}`, `.${ext}`)]; //@TODO
console.warn(`${skill}中的地址写法(${audioInfo})暂时没有完全支持台词系统。`);
const audioList = []; return [getTextMap(path, audioInfo, ext, isDefault)];
audioNum = parseInt(audioNum);
for (let i = 1; i <= audioNum; i++) {
audioList.push(getTextMap(`${path}/`, `${skill}${_audioname}${i}`, `.${ext}`));
}
return audioList;
} }
return getAudioList(skill, { audioname: [], history: [] }, skillInfo); return getAudioList(skill, { audioname: [], history: [], isDefault: false }, skillInfo);
} }
/** /**
* 获取角色死亡时能播放的所有阵亡语音 * 获取角色死亡时能播放的所有阵亡语音
* @param { string | Player } player 角色名 * @param { string | Player } player 角色名
* @returns { any[] } 语音地址列表 * @returns { any[] } 语音地址列表
*/ */
parseDieTextMap(player){ parseDieTextMap(player) {
let name, rawName; let name = typeof player === "string" ? player : player.name;
if (typeof player === "string") { let audioInfo;
name = player; if (typeof player !== "string" && player.skin && player.skin.name) {
rawName = name; const skinName = player.skin.name;
} if (skinName !== name && lib.characterSubstitute[name]) {
else if (get.itemtype(player) === "player") { const skin = lib.characterSubstitute[name].find((i) => i[0] === skinName);
// @ts-ignore if (skin) {
name = player.skin.name || player.name; const newCharacter = get.convertedCharacter(['', '', 0, [], skin[1]]);
rawName = player.name; name = skinName;
} audioInfo = newCharacter.dieAudios;
const info = get.character(name), datas = [];
let dieAudios;
if(info && info.dieAudios.length > 0){
dieAudios = info.dieAudios;
}
//@mengxinzxz写的屎山
else if(rawName !== name && lib.characterSubstitute[rawName] && lib.characterSubstitute[rawName].some((i) => i[0] == name)){
const trashes = lib.characterSubstitute[rawName].find((i) => i[0] == name)[1];
const newCharacter = get.convertedCharacter(['','',0,[],trashes]);
dieAudios = newCharacter.dieAudios;
}
if(dieAudios && dieAudios.length > 0){
dieAudios.forEach(item => {
let key, file;
if(item.startsWith("ext:")){
key = item.slice(4).split("/")[1];
file = item;
} }
else {
key = item;
file = `die/${item}.mp3`;
}
const data = {key, file}
if(lib.translate[`#${key}:die`]) data.text = lib.translate[`#${key}:die`];
datas.push(data);
});
}
else {
const data = {
key: name,
file: `die/${name}.mp3`,
isDefault: true,
} }
if(lib.translate[`#${name}:die`]) data.text = lib.translate[`#${name}:die`];
datas.push(data);
} }
return datas;
const defaultInfo = true;
const check = (name, history) => {
if (get.character(name).isNull) return false;
if (!history.includes(name)) return true;
if (history[0] === name) return false;
//deadlock
throw new RangeError(`parseDieTextMap: ${name} in ${history} forms a deadlock`);
};
const getTextMap = (path, name, ext, isDefault) => ({
name,
file: `${path}${name}${ext}`,
text: lib.translate[`#${name}:die`],
isDefault
});
const getAudioList = (name, options, audioInfo) => {
if (!audioInfo) {
const info = get.character(name);
if (info.isNull) {
// console.error(new ReferenceError(`parseDieTextMap: Cannot find ${name} in lib.character`));
return parseAudio(name, Object.assign(options, { isDefault: true }), defaultInfo);
}
audioInfo = info.dieAudios;
}
if (audioInfo.length === 0) audioInfo = void 0;
const { history } = options;
history.unshift(name);
return parseAudio(name, options, audioInfo);
}
const parseAudio = (name, options, audioInfo) => {
const history = options.history.slice();
const isDefault = options.isDefault;
options = { history, isDefault };
if (Array.isArray(audioInfo)) {
// if (audioInfo.length === 2 && typeof audioInfo[0] === "string" && typeof audioInfo[1] === "number") {
// const [name, number] = audioInfo;
// if (check(name, history)) return getAudioList(name, options).slice(0, number);
// return parseAudio(name, options, number);
// }
const map = {};
audioInfo.forEach((i) => {
parseAudio(name, options, i).forEach(data => map[data.name] = data);
});
return Object.values(map);
}
if (!["string", "number", "boolean"].includes(typeof audioInfo)) return parseAudio(name, Object.assign(options, { isDefault: true }), defaultInfo);
if (audioInfo === false) return [];
if (typeof audioInfo === "string") {
if (["data:", "blob:"].some(prefix => audioInfo.startsWith(prefix))) return [getTextMap("", audioInfo, "", isDefault)];
if (check(audioInfo, history)) return getAudioList(audioInfo, options);
}
audioInfo = String(audioInfo);
const list = audioInfo.match(/(?:(.*):|^)(true|\d+)(?::(.*)|$)/); // [path, number|true, ext]
if (list) {
let [, path = "die", audioNum, ext = "mp3"] = list;
if (audioNum === "true") return [getTextMap(`${path}/`, `${name}`, `.${ext}`, isDefault)];
const audioList = [];
audioNum = parseInt(audioNum);
for (let i = 1; i <= audioNum; i++) {
audioList.push(getTextMap(`${path}/`, `${name}${i}`, `.${ext}`, isDefault));
}
return audioList;
}
let path = "", ext = "";
if (!/^db:|^ext:|\//.test(audioInfo)) path = "die/";
if (!/\.\w+$/.test(audioInfo)) ext = ".mp3";
if (path && ext) return parseAudio(audioInfo, Object.assign(options, { isDefault: true }), defaultInfo);
//@TODO
console.warn(`${name}中的地址写法(${audioInfo})暂时没有完全支持台词系统。`);
return [getTextMap(path, audioInfo, ext, isDefault)];
}
return getAudioList(name, { history: [], isDefault: false }, audioInfo);
} }
/** /**
* *
@ -1640,12 +1696,40 @@ export class Game {
if (info.direct && !directaudio) return; if (info.direct && !directaudio) return;
if (lib.skill.global.includes(skill) && !info.forceaudio) return; if (lib.skill.global.includes(skill) && !info.forceaudio) return;
let audio, let audio, list = game.parseSkillTextMap(skill, player, skillInfo).randomSort();
list = game.parseSkillAudio(skill, player, skillInfo).randomSort();
return (function play() { return (function play() {
if (!list.length) return; if (!list.length) return;
audio = list.shift(); audio = list.shift();
return game.playAudio(audio, play); return game.playAudio(audio.file, play);
})();
}
/**
* @param { Player | string } player
* @returns
*/
tryDieAudio(player) {
game.broadcast(game.tryDieAudio, player);
if (!lib.config.background_speak) return;
let playerName;
if (typeof player === "string") playerName = player;
else if (player.skin && player.skin.name) playerName = player.skin.name;
else playerName = player.name;
let audio, isDefault, list = game.parseDieTextMap(player).randomSort();
const check = () => {
if (list.length) return true;
if (!audio) return false;
if (!audio.isDefault) return false;
if (!playerName.includes("_")) return false;
playerName = playerName.slice(playerName.indexOf("_") + 1);
list = game.parseDieTextMap(playerName).randomSort();
return check();
}
return (function play() {
if (!check()) return;
audio = list.shift();
return game.playAudio(audio.file, play);
})(); })();
} }
/** /**

View File

@ -619,7 +619,7 @@ export class Get {
if (num === 3 || num === 4) return []; if (num === 3 || num === 4) return [];
return; return;
} }
return info || get.convertedCharacter({}); return info || get.convertedCharacter({ isNull: true });
} }
characterInitFilter(name) { characterInitFilter(name) {
const info = get.character(name); const info = get.character(name);

View File

@ -160,6 +160,11 @@ export class Character {
* @type { string[] } * @type { string[] }
*/ */
tempname = []; tempname = [];
/**
* 武将牌是否存在(get.character未找到武将使用)
* @type { boolean }
*/
isNull = false;
/** /**
* @param { Object|[string, string, string|number, string[], any[]|undefined, any[]|undefined] } [data] * @param { Object|[string, string, string|number, string[], any[]|undefined, any[]|undefined] } [data]
*/ */
@ -208,8 +213,7 @@ export class Character {
* @param { any[] } trash * @param { any[] } trash
*/ */
setPropertiesFromTrash(trash) { setPropertiesFromTrash(trash) {
const keptTrashes = [], const keptTrashes = [], clans = [], dieAudios=[];
clans = [];
for (let i = 0; i < trash.length; i++) { for (let i = 0; i < trash.length; i++) {
const item = trash[i]; const item = trash[i];
if (typeof item !== "string") { if (typeof item !== "string") {
@ -260,10 +264,11 @@ export class Character {
clans.push(item.slice(5)); clans.push(item.slice(5));
} else if (item.startsWith("InitFilter:")) { } else if (item.startsWith("InitFilter:")) {
this.initFilters = item.slice(11).split(":"); this.initFilters = item.slice(11).split(":");
} else if (item.startsWith("die:")){ } else if (item.startsWith("die:")) {
this.dieAudios.push(item.slice(4)); dieAudios.add(item.slice(4));
} else if (item.startsWith("die_audio:")){ } else if (item.startsWith("die_audio:")) {
this.dieAudios = item.slice(10).split(":"); console.warn(`die_audio参数已废弃请使用多个die参数。`);
dieAudios.addArray(item.slice(10).split(":"));
} else if (item.startsWith("tempname:")) { } else if (item.startsWith("tempname:")) {
this.tempname = item.slice(9).split(":"); this.tempname = item.slice(9).split(":");
} else { } else {
@ -271,6 +276,7 @@ export class Character {
} }
} }
this.clans = clans; this.clans = clans;
this.dieAudios = dieAudios;
this.trashBin = keptTrashes; this.trashBin = keptTrashes;
} }
/** /**
@ -388,8 +394,7 @@ export class Character {
trashes.push(`InitFilters:${character.initFilters.join(":")}`); trashes.push(`InitFilters:${character.initFilters.join(":")}`);
} }
if (character.dieAudios.length > 0) { if (character.dieAudios.length > 0) {
if (character.dieAudios.length === 1) trashes.push(`die:${character.dieAudios[0]}`) character.dieAudios.forEach((item) => trashes.push(`die:${item}`));
else trashes.push(`die_audio:${character.dieAudios.join(":")}`);
} }
if (character.tempname.length > 0) { if (character.tempname.length > 0) {
trashes.push(`tempname:${character.tempname.join(":")}`); trashes.push(`tempname:${character.tempname.join(":")}`);

View File

@ -8776,20 +8776,9 @@ export const Content = {
game.dead.push(player); game.dead.push(player);
_status.dying.remove(player); _status.dying.remove(player);
if (lib.config.background_speak) {
const audios = game.parseDieTextMap(player).randomGet();
if (audios.isDefault) {
const name = audios.key;
game.playAudio("die", name, function () {
game.playAudio("die", name.slice(name.indexOf("_") + 1));
});
}
else{
game.playAudio(audios.file);
}
}
}, player); }, player);
game.tryDieAudio(player);
game.addVideo("diex", player); game.addVideo("diex", player);
if (event.animate !== false) { if (event.animate !== false) {
player.$die(source); player.$die(source);

View File

@ -3360,7 +3360,7 @@ export class Click {
} }
// 添加台词部分 // 添加台词部分
const dieAudios = game.parseDieTextMap(name).filter(i => "text" in i); const dieAudios = game.parseDieTextMap(name).map(i => i.text).filter(Boolean);
const skillAudioMap = new Map(); const skillAudioMap = new Map();
nameinfo.skills.forEach(skill => { nameinfo.skills.forEach(skill => {
const voiceMap = game.parseSkillText(skill, name, null, true); const voiceMap = game.parseSkillText(skill, name, null, true);
@ -3397,10 +3397,10 @@ export class Click {
skillNameSpanStyle2.lineHeight = "1.9"; skillNameSpanStyle2.lineHeight = "1.9";
skillNameSpan2.innerHTML = `• 阵亡台词`; skillNameSpan2.innerHTML = `• 阵亡台词`;
intro.appendChild(skillNameSpan2); intro.appendChild(skillNameSpan2);
dieAudios.forEach((item, index) => { dieAudios.forEach((text, index) => {
const dieTextSpan = document.createElement("span"); const dieTextSpan = document.createElement("span");
dieTextSpan.style.fontSize = "15.2px"; dieTextSpan.style.fontSize = "15.2px";
dieTextSpan.innerHTML = `<br>${dieAudios.length > 1 ? `${index + 1}. ` : ""}${item.text}`; dieTextSpan.innerHTML = `<br>${dieAudios.length > 1 ? `${index + 1}. ` : ""}${text}`;
intro.appendChild(dieTextSpan); intro.appendChild(dieTextSpan);
}); });
} }
@ -3677,7 +3677,7 @@ export class Click {
Array.from(htmlParser.childNodes).forEach((value) => introduction.appendChild(value)); Array.from(htmlParser.childNodes).forEach((value) => introduction.appendChild(value));
// 添加台词部分 // 添加台词部分
const dieAudios = game.parseDieTextMap(name).filter(i => "text" in i); const dieAudios = game.parseDieTextMap(name).map(i => i.text).filter(Boolean);
const skillAudioMap = new Map(); const skillAudioMap = new Map();
nameInfo.skills.forEach(skill => { nameInfo.skills.forEach(skill => {
const voiceMap = game.parseSkillText(skill, name, null, true); const voiceMap = game.parseSkillText(skill, name, null, true);
@ -3712,9 +3712,9 @@ export class Click {
skillNameSpan.innerHTML = `<br>阵亡台词`; skillNameSpan.innerHTML = `<br>阵亡台词`;
introduction.appendChild(skillNameSpan); introduction.appendChild(skillNameSpan);
dieAudios.forEach((item, index) => { dieAudios.forEach((text, index) => {
const dieTextSpan = document.createElement("span"); const dieTextSpan = document.createElement("span");
dieTextSpan.innerHTML = `<br>${dieAudios.length > 1 ? `${index + 1}. ` : ""}${item.text}`; dieTextSpan.innerHTML = `<br>${dieAudios.length > 1 ? `${index + 1}. ` : ""}${text}`;
introduction.appendChild(dieTextSpan); introduction.appendChild(dieTextSpan);
}); });
} }