PADDashFormation/monsters-info/extractByNode.js

312 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs');
const crypto = require('crypto');
const Card = require('./official-API/parseCard');
const Skill = require('./official-API/parseSkill');
const runDate = new Date();
const officialAPI = [ //来源于官方API
{
code: "ja",
customName: ["cht", "chs"]
},
{
code: "en",
customName: []
},
{
code: "ko",
customName: []
}
];
//数组去重
Array.prototype.distinct = function () {
let _set = new Set(this);
return Array.from(_set)
}
//比较两只怪物是否是同一只(在不同语言服务器)
function sameCard(m1, m2) {
//不管那么多了,懒得判断了
return true;
if (m1 == undefined || m2 == undefined) return false; //是否存在
if (m1.attrs[0] != m2.attrs[0]) return false; //主属性
//if (m1.attrs[1] != m2.attrs[1]) return false; //副属性
//全部类型有任意不同的时候也返回false但是考虑到上修不要求总数一致
for (let i = 0; i < Math.min(m1.types.length, m2.types.length); i++) {
if (m1.types[i] != m2.types[i]) return false;
}
if (m1.maxLevel != m2.maxLevel) return false; //最大等级
if (m1.seriesId != m2.seriesId) return false; //系列ID
return true;
}
//查找到真正起作用的那一个技能
function getActuallySkills(skillsDataset, skillid, skillTypes, searchRandom = true) {
const skill = skillsDataset[skillid];
if (skill) {
if (skillTypes.includes(skill.type)) {
return [skill];
} else if (skill.type == 116 || //主动技
(searchRandom && skill.type == 118) || //随机主动技
skill.type == 138 || //队长技
skill.type == 232 || //进化技能1不循环
skill.type == 233) { //进化技能2循环
//因为可能有多层调用特别是随机118再调用组合116的所以需要递归
let subSkills = skill.params.flatMap(id => getActuallySkills(skillsDataset, id, skillTypes, searchRandom));
subSkills = subSkills.filter(s => s);
return subSkills;
} else {
return [];
}
} else {
return [];
}
}
/*
* 正式流程
*/
officialAPI.forEach(function (lang) {
console.log("正在读取官方 %s 信息", lang.code);
const cardJson = fs.readFileSync("official-API/" + lang.code + "-card.json", 'utf-8'); //使用同步读取怪物
const cardJsonObj = JSON.parse(cardJson);
const oCards = lang.cardOriginal = cardJsonObj.card;//将字符串转换为json对象
const monCards = lang.cards = [];
//const monCards = lang.cards = oCards.map(ocard=>new Card(ocard));
/*oCards.forEach((oCard, idx)=>{
let mid = oCard[0];
if (mid === idx) //原始怪物
{
monCards.push(new Card(oCard));
}else
{
const nCard = monCards[mid % 100000];
if (!nCard.specialVersion) nCard.specialVersion = {};
nCard.specialVersion[Math.floor(mid / 100000)] = new Card(oCard);
}
});*/
//为了减小数据文件容量,删掉一些用不上的,有的可以后面游戏内再重新加上
for (let cardIndex = 0; oCards[cardIndex][0] < 1e5; cardIndex++) {
const card = new Card(oCards[cardIndex]);
delete card.enemy; //不做地下城解析,用不上
delete card.onlyAssist; //数量太少了,游戏内再加
delete card.unk01;
delete card.unk02;
delete card.unk03;
delete card.unk04;
delete card.unk05;
delete card.unk06;
delete card.unk07;
delete card.unk08;
if (card.searchFlags.every(num => isNaN(num)))
delete card.searchFlags; //没有队长技能的,用不上
if (!card.syncAwakening)
delete card.syncAwakeningConditions; //没有同步觉醒
monCards.push(card);
}
//加入自定义的语言
lang.customName.forEach(function (lcode) {
console.log("正在读取自定义 " + lcode + " 信息");
const ljson = fs.readFileSync("custom/" + lcode + ".json", 'utf-8'); //使用同步读取
const ccard = JSON.parse(ljson);//将字符串转换为json对象
ccard.forEach(function (cm) { //每个文件内的名字循环
let m = monCards[cm.id];
if (m) {
if (!m.otLangName) //如果没有其他语言名称属性,则添加一个对象属性
m.otLangName = {};
m.otLangName[lcode] = cm.name;
if (!m.otTags) //如果没有其他语言名称属性,则添加一个对象属性
m.otTags = [];
let newTags = Array.from(new Set(cm.tags));
newTags = newTags.filter(tag => !m.altName.includes(tag) && !m.otTags.includes(tag));
m.otTags.push(...newTags);
}
});
});
const skillJson = fs.readFileSync("official-API/" + lang.code + "-skill.json", 'utf-8'); //使用同步读取技能
const skillJsonObj = JSON.parse(skillJson);
const oSkills = lang.skillOriginal = skillJsonObj.skill;//将字符串转换为json对象
lang.skills = oSkills.map((oc, idx) => new Skill(idx, oc)); //每一项生成分析对象
lang.cards.forEach((m, cardId, cardArr) => {
let henshinTo = null;
const henshinSkill = getActuallySkills(lang.skills, m.activeSkillId, [202, 236]);
if (henshinSkill.length) {
const skill = henshinSkill[0];
henshinTo = skill.params.distinct();
if (Array.isArray(henshinTo)) {
m.henshinTo = henshinTo;
//变身来源可能有多个,因此将变身来源修改为数组
for (let toId of henshinTo) {
let henshinFrom = cardArr[toId].henshinFrom;
if (Array.isArray(henshinFrom)) {
henshinFrom.push(cardId);
} else {
cardArr[toId].henshinFrom = [cardId];
}
}
}
}
});
//const eskillJson = fs.readFileSync("official-API/" + lang.code +"-enemy_skill.json", 'utf-8'); //使用同步读取技能
//const eskillJsonObj = JSON.parse(eskillJson);
//lang.enemy_skills = eskillJsonObj.enemy_skills;
});
//加入其他服务器相同角色的名字
for (let li = 0; li < officialAPI.length; li++) {
const otherLangs = officialAPI.concat(); //复制一份原始数组,储存其他语言
const lang = otherLangs.splice(li, 1)[0]; //删掉并取得当前的语言
const langCard = lang.cards;
const langCardCount = langCard.length;
for (let mi = 0; mi < langCardCount; mi++) {
const m = langCard[mi];
const name = m.name; //当前语言的名字
//名字对象
otherLangs.forEach((otLang) => {
let _m = otLang.cards[mi]; //获得这种其他语言的当前这个怪物数据
let isSame = false; //与原语言怪物是否是同一只
const l1 = lang.code, l2 = otLang.code;
if (
l1 == 'ja' && (l2 == 'en' || l2 == 'ko') ||
l2 == 'ja' && (l1 == 'en' || l1 == 'ko')
) { //当同id两者不同日服和英韩服比较时的一些人工确认相同的特殊id差异卡片
const langIsJa = l1 == 'ja' ? true : false; //原始语言是否是日语
let diff = 0; //日语和其它语言的id差异
switch (true) {
case (langIsJa && mi >= 671 && mi <= 680) ||
(!langIsJa && mi >= 1049 && mi <= 1058):
//神罗 日服 671-680 等于英韩服 1049-1058
diff = 378;
break;
case (langIsJa && mi >= 669 && mi <= 670) ||
(!langIsJa && mi >= 934 && mi <= 935):
//神罗 日服 669-670 等于英韩服 934-935
diff = 265;
break;
case (langIsJa && mi >= 924 && mi <= 935) ||
(!langIsJa && mi >= 669 && mi <= 680):
//蝙蝠侠 日服 924-935 等于英韩服 669-680
diff = -255;
break;
case (langIsJa && mi >= 1049 && mi <= 1058) ||
(!langIsJa && mi >= 924 && mi <= 933):
//蝙蝠侠 日服 1049-1058 等于英韩服 924-933
diff = -125;
break;
}
if (diff != 0) {
_m = langIsJa ? otLang.cards[mi + diff] : otLang.cards[mi - diff];
isSame = true;
}
}
if (!isSame) isSame = sameCard(m, _m); //不属于特殊指定区间的情况下,判断与原语言怪物是否是同一只
if (_m && isSame) //如果有这个怪物,且与原语言怪物是同一只
{
const otName = _m.name;
if (/^(?:\?+|\*+|초월\s*\?+)/i.test(otName)) //名字以问号、星号、韩文的问号开头
{
return; //跳过
} else {
if (!m.otLangName) //如果没有其他语言名称属性,则添加一个对象属性
m.otLangName = {};
m.otLangName[otLang.code] = otName;
if (_m.otLangName) { //增加储存当前语言的全部其他语言
Object.entries(_m.otLangName).forEach(entry => {
const lcode = entry[0];
if (lcode != l1 && !Object.keys(m.otLangName).includes(lcode)) //如果不是本来的的语言
m.otLangName[lcode] = entry[1];
});
}
}
if (!m.otTags) //如果没有其他语言标签属性,则添加一个数组属性
m.otTags = [];
let otTags = Array.from(new Set(_m.otTags ? _m.altName.concat(_m.otTags) : _m.altName));
otTags = otTags.filter(tag => !m.altName.includes(tag) && !m.otTags.includes(tag));
m.otTags.push(...otTags);
}
});
}
}
var newCkeyObjs = officialAPI.map(lang => {
const lcode = lang.code;
const cardStr = JSON.stringify(lang.cards);
const skillStr = JSON.stringify(lang.skills);
//写入Cards
fs.writeFile(`./mon_${lcode}.json`, cardStr, function (err) {
if (err) {
console.error(err);
}
console.log(`mon_${lcode}.json 导出成功`);
});
//写入Skills
fs.writeFile(`./skill_${lcode}.json`, skillStr, function (err) {
if (err) {
console.error(err);
}
console.log(`skill_${lcode}.json 导出成功`);
});
//const enemy_skillsStr = lang.enemy_skills;
//写入enemy_skills
//fs.writeFile(`./enemy_skills_${lcode}.json`,enemy_skillsStr,function(err){
// if(err){
// console.error(err);
// }
// console.log(`enemy_skills_${lcode}.json 导出成功`);
//});
const cardHash = crypto.createHash('md5');
const skillHash = crypto.createHash('md5');
cardHash.update(cardStr, 'utf8');
skillHash.update(skillStr, 'utf8');
const ckeyOutObj = {
code: lcode,
ckey: {
card: cardHash.digest('hex'),
skill: skillHash.digest('hex'),
},
updateTime: runDate.getTime(),
};
return ckeyOutObj;
});
//读取旧的ckeyObj
var ckeyObjs;
fs.readFile('./ckey.json', 'utf-8', function (err, data) {
if (err) { //如果读取错误直接使用全新ckey
ckeyObjs = newCkeyObjs;
} else { //如果读取正确则读入JSON并判断是否和旧有的一致
ckeyObjs = JSON.parse(data);
for (let ci = 0; ci < ckeyObjs.length; ci++) {
const oldCkey = ckeyObjs[ci];
const newCkey = newCkeyObjs.find(nckey => nckey.code === oldCkey.code);
if (newCkey && (oldCkey.ckey.card != newCkey.ckey.card || oldCkey.ckey.skill != newCkey.ckey.skill)) {
ckeyObjs[ci] = newCkey;
}
}
}
fs.writeFile('./ckey.json', JSON.stringify(ckeyObjs, null, '\t'), function (err) {
if (err) {
console.error(err);
}
console.log('ckey.json 导出成功');
});
});