武将:职业天赋接口

This commit is contained in:
陆莹
2022-03-22 20:46:17 +08:00
parent 3c24e54350
commit 5d0040b8a8
20 changed files with 2811 additions and 1199 deletions

View File

@@ -30,7 +30,8 @@ export enum HERO_SYSTEM_TYPE {
JEWEL_RESET_RANDSE = 27, // 天晶石洗练
JEWEL_QUENCH = 28, // 天晶石淬炼
REBIRTH = 29, // 武将重生
};
TALENT = 30, // 天赋
};
// 武将上限
export const HERO_GROW_MAX = {

View File

@@ -433,6 +433,7 @@ export const FILENAME = {
DIC_HERO_QUALITY_UP: 'dic_zyz_hero_quality_up',
DIC_HERO_STAR: 'dic_zyz_hero_star',
DIC_HERO_WAKE: 'dic_zyz_hero_wake',
DIC_HERO_TALENT: 'dic_zyz_hero_talent',
DIC_HERO_SKILL: 'dic_zyz_heroskill',
DIC_JOB: 'dic_zyz_job',
DIC_KING_EXP: 'dic_zyz_kingexp',
@@ -1011,6 +1012,7 @@ export enum ITEM_CHANGE_REASON {
ACT_GUILD_PAY_REWARD = 144, // 活动-军团人数奖励
RECEIVE_CHAPTER_BOX = 145, // 领取主线章节宝箱
JEWEL_INHERIT = 146, // 天晶继承
RESET_TALENT = 147, // 洗点
}
export enum TA_EVENT {
@@ -1090,4 +1092,10 @@ export enum LOG_TYPE {
export enum CE_CHANGE_REASON {
HERO = 'hero', // 武将
}
export enum TALENT_RELATION_TYPE {
NORMAL = 1, // 正常
CONFLICT = 2, // 冲突
REPLACE = 3, // 替换
}

View File

@@ -288,6 +288,11 @@ export const STATUS = {
ROLE_SHORT_HERO_CONECTION: { code: 30308, simStr: '未拥有羁绊武将' },
HERO_FAVOUR_LEVEL_REACH_MAXT: { code: 30309, simStr: '武将好感等级以达到最大' },
HERO_JOB_REACH_MAX_STAGE: { code: 30310, simStr: '武将已达到最大的职业阶级' },
TALENT_HAS_UNLOCKED: { code: 30311, simStr: '该天赋已经解锁' },
TALENT_CONDITION_NOT_FIT: { code: 30312, simStr: '天赋解锁条件未达成' },
TALENT_POINT_NOT_ENOUGH: { code: 30313, simStr: '天赋点不足' },
TALENT_NOT_UNLOCKED: { code: 30314, simStr: '该天赋未解锁' },
TALENT_LEVEL_MAX: { code: 30315, simStr: '该天赋等级已达最高' },
// 装备养成 30400-30499
ROLE_EQUIP_PLACE_NOT_ENOUGH: { code: 30400, simStr: '装备栏未装备或无可强化' },

View File

@@ -7,6 +7,7 @@ import { reduceCe } from '../pubUtils/util';
import Skin from './Skin';
import { SearchHeroParam } from '../domain/backEndField/search';
import { Reward } from '../domain/battleField/pvp';
import { getHeroInitTalent } from '../pubUtils/data';
type CeAttrUpdate = Partial<CeAttrData>;
export class CeAttrData {
@@ -61,6 +62,18 @@ export class Connect {
level: number;
}
export class Talent {
@prop({ required: true })
id: number; // 天赋表id
@prop({ required: true })
level: number; // 激活等级
constructor(id: number, level = 1) {
this.id = id;
this.level = level;
}
}
export class HeroSkin {
@prop({ required: true })
id: number;
@@ -70,6 +83,19 @@ export class HeroSkin {
skin: Ref<Skin>;
@prop({ required: true })
enable: boolean;
@prop({ required: true, type: Talent, _id: false })
talent: Talent[]; // 天赋树
@prop({ required: true })
usedTalentPoint: number; // 已使用的天赋点数
constructor(id: number, skinId: number, skin: string, enable: boolean) {
this.id = id;
this.skinId = skinId;
this.skin = skin;
this.enable = enable;
this.talent = getHeroInitTalent(skinId);
this.usedTalentPoint = 0;
}
}
export class Stone {

File diff suppressed because one or more lines are too long

View File

@@ -140,7 +140,6 @@ export class CalHeroCe {
this.getSingleAttrObj(id).updateAttr({ inc: { fixUp: attr } });
}
}
addSeidEffect.bind(this, dicJob.seid);
}

View File

@@ -5,7 +5,7 @@ import { dicEvent, dicEventList, loadEvent } from "./dictionary/DicEvent";
import { dicExpedition, DicExpedition, loadExpedition } from "./dictionary/DicExpedition";
import { dicExpeditionPoint, loadExpeditionPoint } from "./dictionary/DicExpeditionPoint";
import { dicHeroSkill, loadHeroSkill } from "./dictionary/DicHeroSkill";
import { dicJob, jobClassAndgrades, jobClassMaxGrades, loadJob } from "./dictionary/DicJob";
import { dicJob, jobClassAndgrades, jobClassMaxGrades, loadJob, talentPointOfJob } from "./dictionary/DicJob";
import { dicKingExp, maxPlayerLv, loadKingExp } from "./dictionary/DicKingExp";
import { dicCharExp, loadCharExp } from "./dictionary/DicCharExp";
import { dicQuestion, loadQuestion } from "./dictionary/DicQuestion";
@@ -101,6 +101,8 @@ import { dicEquipQualityExtra, loadEquipQualityExtra } from './dictionary/DicEqu
import { dicEquipSuit, dicEquipSuitByJobClass, loadEquipSuit } from "./dictionary/DicEquipSuit";
import { dicJewelCondition, loadJewelCondition } from './dictionary/DicJewelCondition';
import { dicMainStarBox, dicMainStarBoxByChapter, loadMainStarBox } from './dictionary/DicMainStarBox';
import { dicHeroTalent, initTalents, loadHeroTalent } from './dictionary/DicHeroTalent';
import { Talent } from "../db/Hero";
export const gameData = {
daily: dicDaily,
@@ -252,6 +254,9 @@ export const gameData = {
heroIdByWar: dicHeroIdByWar,
mainBox: dicMainStarBox,
mainBoxByChapter: dicMainStarBoxByChapter,
heroTalent: dicHeroTalent,
initTalents: initTalents,
talentPointOfJob: talentPointOfJob,
};
// 在此提供一些原先在gamedata中提供的方法以便更方便获取gameData数据
@@ -869,6 +874,14 @@ export function getRandEffectByGroupAndLevel(group: number, level: number) {
return gameData.randomEffectPool.get(id);
}
// 根据皮肤获得他的初始天赋id
export function getHeroInitTalent(skinId: number) {
let dicHero = gameData.hero.get(skinId);
if(!dicHero) return [];
let ids = gameData.initTalents.get(dicHero.talentId)||[];
return ids.map(id => (new Talent(id)));
}
// 初始加载
function initDatas() {
parseDicParam();
@@ -1035,6 +1048,7 @@ function loadDatas() {
loadStone();
loadJewelCondition();
loadMainStarBox();
loadHeroTalent();
}
// 重载dicParam

View File

@@ -86,8 +86,8 @@ export const EXTERIOR = {
EXTERIOR_APPEARANCE: 11419, // 默认形象id
};
export const HTTPMANAGE = {
ADDRESSTYPE: 1, // 1开发服(dev)2正式服(official)3测试服(alpha)4版号服(isbn) 5: 37测试服(sq1)
SERVERTYPE: 2, // ADDRESSTYPE下服务器的筛选1正式服(official)2开发服(develop) 3. 测试服(alpha)
ADDRESSTYPE: 3, // 1开发服(dev)2正式服(official)3测试服(alpha)4版号服(isbn) 5: 37测试服(sq1)
SERVERTYPE: 3, // ADDRESSTYPE下服务器的筛选1正式服(official)2开发服(develop) 3. 测试服(alpha)
};
export const CHAT_SYSTEM = {
RECENT_GROUP_MSGS_CNT: 10, // 群消息获取条数
@@ -262,9 +262,15 @@ export const VIP = {
VIP_TOWER_TASK_CAN_SEND_AT_ONCE_WITHOUT_VIP: 0, // 镇念没有月卡是否可以被一键悬赏
VIP_TOWER_TASK_CAN_SEND_AT_ONCE_WITH_VIP: 1, // 镇念塔有月卡是否可以被一键悬赏
VIP_TOWER_HUNG_UP_RATIO: 1.2, // 镇念塔挂机奖励加成倍率在dic_zyz_tower的rewardOfcollect基础上直接乘以这个倍数
VIP_REGRET_CNT_WITHOUT_VIP: 10, // 没有月卡时候的悔棋次数
VIP_REGRET_CNT_WITH_VIP: 11, // 有月卡时候的悔棋次数
VIP_REGRET_CNT_WITHOUT_VIP: 0, // 没有月卡时候的悔棋次数
VIP_REGRET_CNT_WITH_VIP: 1, // 有月卡时候的悔棋次数
VIP_PVP_CHALLENGE_COUNTS_ADD: 2, // pvp上限增加如果有月卡在PVP.PVP_CHALLENGE_COUNTS的基础上增加X次
VIP_DAILY_TIMERS_PER_DAY_ADD: 2, // 每日任务免费次数增加如果有月卡在dic_daily的timesPerDay的基础上增加多少次
VIP_DUNGEON_CONST_FREE_ADD: 2, // 秘境免费次数增加如果有月卡在DUNGEON_CONST.DUNGEON_CONST_FREE的基础上加多少次
};
export const PUBLIC_NOTICE_PERIOD = {
PUBLIC_NOTICE_PERIOD_TIME: 24, // 活动公示期时间
};
export const HERO = {
HERO_TALENTPOINT_RESET: '31002&100', // 天赋点重置花费
};

View File

@@ -33,10 +33,12 @@ export interface DicHero {
readonly recruit: boolean;
// 武将图标id
readonly face_id: string;
// 天赋树id
readonly talentId: number;
}
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const DicHeroKeys: KeysEnum<DicHero> = {heroId: true, name: true, quality: true, camp: true, jobClass: true, jobid: true, skill: true, pieceId: true, initialStars: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true};
const DicHeroKeys: KeysEnum<DicHero> = {heroId: true, name: true, quality: true, camp: true, jobClass: true, jobid: true, skill: true, pieceId: true, initialStars: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true, talentId: true};
export const dicHero = new Map<number, DicHero>();
export function loadHero() {
dicHero.clear();

View File

@@ -0,0 +1,81 @@
// 武将升星表
import { decodeArrayListStr, parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts';
const _ = require('lodash');
export interface DicHeroTalent {
// 唯一id
readonly id: number;
// 天赋组id
readonly talentId: number;
// 节点层数
readonly nodeSort: number;
// 和其他节点关系
readonly relation: [{ type: number, ids?: number[] }];
// 节点等级数
readonly level: [{ lv: number, seid: number, cost: number }];
// 前置节点
readonly prepositionId: number[][];
// 需要满足在天赋树中累计消耗n点天赋点
readonly preTotalPoint: number;
// 在前置节点中消耗至少n点天赋点在有多个前置节点时取最高的1个
readonly preSinglePoint: number;
}
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const DicHeroTalentKeys: KeysEnum<DicHeroTalent> = {id: true, talentId: true, nodeSort: true, relation: true, level: true, prepositionId: true, preTotalPoint: true, preSinglePoint: true};
export const dicHeroTalent = new Map<number, DicHeroTalent>();
export const initTalents = new Map<number, number[]>();
export function loadHeroTalent() {
dicHeroTalent.clear();
let arr = readFileAndParse(FILENAME.DIC_HERO_TALENT);
arr.forEach(o => {
o.relation = parseRelation(o.type, o.relationId);
o.level = parseLevel(o.levelCount, o.levelSeid, o.levelConsume);
o.prepositionId = parsePrePositionId(o.prepositionId);
dicHeroTalent.set(o.id, _.pick(o, Object.keys(DicHeroTalentKeys)));
if(o.prepositionId.length == 0 && o.levelConsume == '&') {
if(!initTalents.has(o.talentId)) {
initTalents.set(o.talentId, []);
}
initTalents.get(o.talentId).push(o.id);
}
});
arr = undefined;
}
function parseRelation(type: string, relationId: string) {
let relation: {type: number, ids?: number[]}[] = [];
let types = parseNumberList(type);
let relations = decodeArrayListStr(relationId);
for(let i = 0; i < types.length; i++) {
if(relations[i]) {
relation.push({
type: types[i],
ids: relations[i].map(id => parseInt(id))
});
}
}
return relation;
}
function parseLevel(levelCount: number, levelSeid: string, levelConsume: string) {
let levelSeids = parseNumberList(levelSeid);
let levelConsumes = parseNumberList(levelConsume);
let level: { lv: number, seid: number, cost: number }[] = [];
for(let i = 0; i < levelCount; i++) {
level.push({ lv: i + 1, seid: levelSeids[i]||0, cost: levelConsumes[i]||0});
}
return level;
}
function parsePrePositionId(str: string) {
let arr = decodeArrayListStr(str);
return arr.map(arr1 => {
return arr1.map(str => parseInt(str));
});
}

View File

@@ -17,8 +17,8 @@ export interface DicJob {
readonly job_class: number;
// 职业类别
readonly type: number;
// 特性
readonly seid: Array<number>;
// // 特性
// readonly seid: Array<number>;
// 训练消耗
readonly trainingConsume: Array<RewardInter>;
// 升阶消耗
@@ -27,15 +27,17 @@ export interface DicJob {
readonly ceAttr: Map<number, {id: number, attr: number}>;
// 一共有多少阶升级
readonly maxStage: number;
// 到这一阶能获得多少天赋点
readonly talentPoint: number;
}
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const DicJobKeys: KeysEnum<DicJob> = {jobid: true, name: true, grade: true, unlockLevel: true, job_class: true, type: true, seid: true,trainingConsume: true, upGradeConsume: true, ceAttr: true, maxStage: true};
const DicJobKeys: KeysEnum<DicJob> = {jobid: true, name: true, grade: true, unlockLevel: true, job_class: true, type: true, trainingConsume: true, upGradeConsume: true, ceAttr: true, maxStage: true, talentPoint: true};
export const dicJob = new Map<number, DicJob>();
export const jobClassMaxGrades = new Map<number, {grade:number, jobid:number}>();
export const jobClassAndgrades = new Map<string, {jobid:number, unlockLevel:number}>();
export const talentPointOfJob = new Map<number, number>();
export function loadJob() {
dicJob.clear();
@@ -43,6 +45,7 @@ export function loadJob() {
jobClassAndgrades.clear();
let arr = readFileAndParse(FILENAME.DIC_JOB);
let jobByJobClass = new Map<number, number[]>(); // jobClass => jobid[]
arr.forEach(o => {
if(o.isPlayer) {
@@ -56,9 +59,25 @@ export function loadJob() {
if (!jobClass || jobClass.grade < o.grade) {
jobClassMaxGrades.set(o.job_class, {grade: o.grade,jobid: o.jobid});
}
jobClassAndgrades.set(o.job_class+'_'+o.grade,{unlockLevel:o.unlockLevel, jobid:o.jobid});
jobClassAndgrades.set(o.job_class+'_'+o.grade,{unlockLevel:o.unlockLevel, jobid:o.jobid});
if(!jobByJobClass.has(o.job_class)) {
jobByJobClass.set(o.job_class, []);
}
jobByJobClass.get(o.job_class).push(o.jobid);
}
});
for(let [_, { job_class, talentPoint }] of dicJob) {
let jobs = jobByJobClass.get(job_class)||[];
for(let jobid of jobs) {
if(!talentPointOfJob.has(jobid)) {
talentPointOfJob.set(jobid, talentPoint);
} else {
talentPointOfJob.set(jobid, talentPointOfJob.get(jobid) + talentPoint);
}
}
}
jobByJobClass = undefined;
arr = undefined;
}

View File

@@ -2,10 +2,10 @@
* 体力系统
*/
import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, LINEUP_NUM } from '../consts';
import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, LINEUP_NUM, TALENT_RELATION_TYPE } from '../consts';
import { cal, deepCopy, getAllAttrStage, reduceCe } from './util';
import { HeroModel, HeroType, HeroUpdate, CeAttrData, EPlace, Stone } from '../db/Hero';
import { HeroModel, HeroType, HeroUpdate, CeAttrData, EPlace, Stone, Talent } from '../db/Hero';
import { RoleModel, RoleType, RoleUpdate, CeAttrDataRole } from '../db/Role';
import { AttributeCal } from '../domain/roleField/attribute';
import { ABI_STAGE, SEID_TYPE } from '../consts';
@@ -20,6 +20,7 @@ import { GuildModel } from '../db/Guild';
import { DicJob } from './dictionary/DicJob';
import { saveCeChangeLog } from './logUtil';
import { JewelType } from '../db/Jewel';
import { type } from 'os';
// 修改并下发战力
export async function calPlayerCeAndSave(type: number, roleId: string, originHero: HeroType, update: HeroUpdate, args?: Array<number>, params?: any) {
@@ -161,7 +162,7 @@ export async function calPlayerCe(hero: HeroType, update: HeroUpdate, type: numb
heroAttrs = calHeroTrainIncAttr(hero, update);
break;
case HERO_SYSTEM_TYPE.STAGEUP:
heroAttrs = calHeroJobStageUpIncAttr(hero, update, addSeidList, removeSeidList);
// heroAttrs = calHeroJobStageUpIncAttr(hero, update, addSeidList, removeSeidList);
break;
case HERO_SYSTEM_TYPE.SKIN:
heroAttrs = calHeroWearSkinIncAttr(hero, update, addSeidList, removeSeidList);
@@ -197,6 +198,9 @@ export async function calPlayerCe(hero: HeroType, update: HeroUpdate, type: numb
case HERO_SYSTEM_TYPE.SCROLL:
heroAttrs = calHeroCeScrollIncAttr(hero, update);
break;
case HERO_SYSTEM_TYPE.TALENT:
heroAttrs = calHeroTalent(hero, update, addSeidList, removeSeidList);
break;
default:
break;
}
@@ -460,29 +464,29 @@ export function calHeroTrainIncAttr(originHero: HeroType, update: HeroUpdate) {
* @param {number[]} addSeidList 用于更新被动
* @param {number[]} removeSeidList 用于更新被动
*/
export function calHeroJobStageUpIncAttr(originHero: HeroType, update: HeroUpdate, addSeidList: Array<number>, removeSeidList: Array<number>) {
let { job: oldJob, attr: heroAttrs } = originHero;
let { job = oldJob } = update;
// export function calHeroJobStageUpIncAttr(originHero: HeroType, update: HeroUpdate, addSeidList: Array<number>, removeSeidList: Array<number>) {
// let { job: oldJob, attr: heroAttrs } = originHero;
// let { job = oldJob } = update;
let lastJob = gameData.job.get(oldJob);
let currentJob = gameData.job.get(job);
let lastSeids = lastJob?.seid||new Array<number>();
let curSeids = currentJob?.seid||new Array<number>();
// let lastJob = gameData.job.get(oldJob);
// let currentJob = gameData.job.get(job);
// let lastSeids = lastJob?.seid||new Array<number>();
// let curSeids = currentJob?.seid||new Array<number>();
for (let seid of curSeids) {
let index = findIndex(lastSeids, seid);
if (index < 0) {
addSeidList.push(seid, 0);
}
}
for (let seid of lastSeids) {
let index = findIndex(curSeids, seid);
if (index < 0) {
removeSeidList.push(seid, 0);
}
}
return heroAttrs;
}
// for (let seid of curSeids) {
// let index = findIndex(lastSeids, seid);
// if (index < 0) {
// addSeidList.push(seid, 0);
// }
// }
// for (let seid of lastSeids) {
// let index = findIndex(curSeids, seid);
// if (index < 0) {
// removeSeidList.push(seid, 0);
// }
// }
// return heroAttrs;
// }
/**
* 初始计算兵种属性
@@ -515,7 +519,7 @@ export function calHeroJobAttr(originHero: HeroType, hero: HeroUpdate, addSeidLi
};
originHero.attr = heroAttrs;
heroAttrs = calHeroJobStageUpIncAttr(originHero, hero, addSeidList, removeSeidList);
// heroAttrs = calHeroJobStageUpIncAttr(originHero, hero, addSeidList, removeSeidList);
return heroAttrs;
}
@@ -552,6 +556,8 @@ export function calHeroWearSkinIncAttr(originHero: HeroType, update: HeroUpdate,
calEquipStrengthIncAttr(originHero, update, eplaceIds);
calEquipQualityIncAttr(originHero, update, eplaceIds);
calEquipStarIncAttr(originHero, update, eplaceIds, addSeidList, removeSeidList);
// 天赋点
calHeroTalent(originHero, update, addSeidList, removeSeidList);
return heroAttrs;
}
@@ -990,6 +996,43 @@ function calHeroCeScrollIncAttr(originHero: HeroType, update: HeroUpdate) {
return heroAttrs;
}
function calHeroTalent(originHero: HeroType, update: HeroUpdate, addSeidList: number[], removeSeidList: number[]) {
let { attr: heroAttrs, skins: oldSkins } = originHero;
let { skins } = update;
let oldSkin = oldSkins.find(cur => cur.enable);
let newSkin = skins.find(cur => cur.enable);
let oldSeids = getTalentSeid(oldSkin.talent);
let newSeids = getTalentSeid(newSkin.talent);
for(let seid of newSeids) addSeidList.push(seid);
for(let seid of oldSeids) removeSeidList.push(seid);
return heroAttrs
}
function getTalentSeid(talent: Talent[]) {
let seids = new Map<number, number[]>(); // id, seids
for(let { id, level } of talent) {
let dicHeroTalent = gameData.heroTalent.get(id);
for(let { type, ids} of dicHeroTalent.relation) {
if(type == TALENT_RELATION_TYPE.REPLACE) {
for(let id of ids) {
seids.delete(id);
}
}
}
for(let { lv, seid } of dicHeroTalent.level) {
if(level >= lv) {
if(!seids.has(id)) seids.set(id, []);
seids.get(id).push(seid);
}
}
}
let result: number[] = [];
for(let [_, ids] of seids) {
result.push(...ids);
}
return result;
}
/**
* 升爵位
* @param role 角色数据

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,394 @@
[
{
"id": 1,
"talentId": 1,
"nodeSort": 1,
"type": "1&",
"relationId": "&",
"name": "援护初始",
"levelCount": 1,
"levelSeid": "31&",
"levelConsume": "&",
"prepositionId": "&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 2,
"talentId": 1,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "攻击初始",
"levelCount": 5,
"levelSeid": "50201&50301&50211&50311&50221&50321",
"levelConsume": "1&2&3&4&5",
"prepositionId": "1&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 3,
"talentId": 1,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "物防初始",
"levelCount": 5,
"levelSeid": "401&402&501&502&402",
"levelConsume": "1&2&3&4&5",
"prepositionId": "1&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 4,
"talentId": 1,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "策防初始",
"levelCount": 5,
"levelSeid": "401&402&501&502&402",
"levelConsume": "1&2&3&4&5",
"prepositionId": "1&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 5,
"talentId": 1,
"nodeSort": 3,
"type": "2&3",
"relationId": "6&7&13&14|1&",
"name": "高级援护",
"levelCount": 3,
"levelSeid": "1001&1002&1011",
"levelConsume": "5&5&5",
"prepositionId": "2&",
"preTotalPoint": 40,
"preSinglePoint": 10
},
{
"id": 6,
"talentId": 1,
"nodeSort": 3,
"type": "2&3",
"relationId": "5&7&12&14|1&",
"name": "减伤光环",
"levelCount": 3,
"levelSeid": "11001&11002&11003",
"levelConsume": "5&5&5",
"prepositionId": "3&",
"preTotalPoint": 40,
"preSinglePoint": 10
},
{
"id": 7,
"talentId": 1,
"nodeSort": 3,
"type": "2&3",
"relationId": "5&6&12&13|1&",
"name": "抗伤光环",
"levelCount": 3,
"levelSeid": "16001&16002&16003",
"levelConsume": "5&5&5",
"prepositionId": "4&",
"preTotalPoint": 40,
"preSinglePoint": 10
},
{
"id": 8,
"talentId": 1,
"nodeSort": 4,
"type": "1&",
"relationId": "&",
"name": "格挡",
"levelCount": 5,
"levelSeid": "1101&1102&1201&1202&1301",
"levelConsume": "1&2&3&4&5",
"prepositionId": "5|6|7",
"preTotalPoint": 50,
"preSinglePoint": 10
},
{
"id": 9,
"talentId": 1,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "反击伤害",
"levelCount": 5,
"levelSeid": "23611&23621&23631&23641&23651",
"levelConsume": "1&2&3&4&5",
"prepositionId": "8&",
"preTotalPoint": 60,
"preSinglePoint": 10
},
{
"id": 10,
"talentId": 1,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "物理减伤",
"levelCount": 5,
"levelSeid": "11006&11007&11008&11009&11010",
"levelConsume": "1&2&3&4&5",
"prepositionId": "8&",
"preTotalPoint": 60,
"preSinglePoint": 10
},
{
"id": 11,
"talentId": 1,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "策略减伤",
"levelCount": 5,
"levelSeid": "16006&16007&16008&16009&16010",
"levelConsume": "1&2&3&4&5",
"prepositionId": "8&",
"preTotalPoint": 60,
"preSinglePoint": 10
},
{
"id": 12,
"talentId": 1,
"nodeSort": 6,
"type": "2&3",
"relationId": "6&7&13&14|5&",
"name": "援护强化",
"levelCount": 5,
"levelSeid": "1201&1202&1301&1302&1402",
"levelConsume": "1&2&3&4&5",
"prepositionId": "9&",
"preTotalPoint": 70,
"preSinglePoint": 10
},
{
"id": 13,
"talentId": 1,
"nodeSort": 6,
"type": "2&3",
"relationId": "5&7&12&14|6&",
"name": "减伤强化",
"levelCount": 5,
"levelSeid": "2800&2801&2802&2803&2804",
"levelConsume": "1&2&3&4&5",
"prepositionId": "10&",
"preTotalPoint": 70,
"preSinglePoint": 10
},
{
"id": 14,
"talentId": 1,
"nodeSort": 6,
"type": "2&3",
"relationId": "5&6&12&13|7&",
"name": "抗伤强化",
"levelCount": 5,
"levelSeid": "2805&2806&2807&2808&2809",
"levelConsume": "1&2&3&4&5",
"prepositionId": "11&",
"preTotalPoint": 70,
"preSinglePoint": 10
},
{
"id": 15,
"talentId": 2,
"nodeSort": 1,
"type": "1&",
"relationId": "&",
"name": "援护初始",
"levelCount": 1,
"levelSeid": "31&",
"levelConsume": "&",
"prepositionId": "&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 16,
"talentId": 2,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "攻击初始",
"levelCount": 4,
"levelSeid": "50201&50301&50211&50311&50221",
"levelConsume": "1&2&3&4",
"prepositionId": "15&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 17,
"talentId": 2,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "物防初始",
"levelCount": 4,
"levelSeid": "401&402&501&502",
"levelConsume": "1&2&3&4",
"prepositionId": "15&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 18,
"talentId": 2,
"nodeSort": 2,
"type": "1&",
"relationId": "&",
"name": "策防初始",
"levelCount": 4,
"levelSeid": "401&402&501&402",
"levelConsume": "1&2&3&4",
"prepositionId": "15&",
"preTotalPoint": 0,
"preSinglePoint": 0
},
{
"id": 19,
"talentId": 2,
"nodeSort": 3,
"type": "2&3",
"relationId": "20&21&27&28|15&",
"name": "高级援护",
"levelCount": 3,
"levelSeid": "1001&1002&1011",
"levelConsume": "5&5&5",
"prepositionId": "16&",
"preTotalPoint": 30,
"preSinglePoint": 10
},
{
"id": 20,
"talentId": 2,
"nodeSort": 3,
"type": "2&3",
"relationId": "19&21&26&28|15&",
"name": "减伤光环",
"levelCount": 3,
"levelSeid": "11001&11002&11003",
"levelConsume": "5&5&5",
"prepositionId": "17&",
"preTotalPoint": 30,
"preSinglePoint": 10
},
{
"id": 21,
"talentId": 2,
"nodeSort": 3,
"type": "2&3",
"relationId": "19&20&26&27|15&",
"name": "抗伤光环",
"levelCount": 3,
"levelSeid": "16001&16002&16003",
"levelConsume": "5&5&5",
"prepositionId": "18&",
"preTotalPoint": 30,
"preSinglePoint": 10
},
{
"id": 22,
"talentId": 2,
"nodeSort": 4,
"type": "1&",
"relationId": "&",
"name": "格挡",
"levelCount": 5,
"levelSeid": "1101&1102&1201&1202&1301",
"levelConsume": "1&2&3&4&5",
"prepositionId": "19|20|21",
"preTotalPoint": 40,
"preSinglePoint": 10
},
{
"id": 23,
"talentId": 2,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "反击伤害",
"levelCount": 5,
"levelSeid": "23611&23621&23631&23641&23651",
"levelConsume": "1&2&3&4&5",
"prepositionId": "22&",
"preTotalPoint": 50,
"preSinglePoint": 10
},
{
"id": 24,
"talentId": 2,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "物理减伤",
"levelCount": 5,
"levelSeid": "11006&11007&11008&11009&11010",
"levelConsume": "1&2&3&4&5",
"prepositionId": "22&",
"preTotalPoint": 50,
"preSinglePoint": 10
},
{
"id": 25,
"talentId": 2,
"nodeSort": 5,
"type": "1&",
"relationId": "&",
"name": "策略减伤",
"levelCount": 5,
"levelSeid": "16006&16007&16008&16009&16010",
"levelConsume": "1&2&3&4&5",
"prepositionId": "22&",
"preTotalPoint": 50,
"preSinglePoint": 10
},
{
"id": 26,
"talentId": 2,
"nodeSort": 6,
"type": "2&3",
"relationId": "20&21&27&28|23&",
"name": "援护强化",
"levelCount": 5,
"levelSeid": "1201&1202&1301&1302&1402",
"levelConsume": "1&2&3&4&5",
"prepositionId": "23&",
"preTotalPoint": 60,
"preSinglePoint": 10
},
{
"id": 27,
"talentId": 2,
"nodeSort": 6,
"type": "2&3",
"relationId": "19&21&26&28|24&",
"name": "减伤强化",
"levelCount": 5,
"levelSeid": "2800&2801&2802&2803&2804",
"levelConsume": "1&2&3&4&5",
"prepositionId": "24&",
"preTotalPoint": 60,
"preSinglePoint": 10
},
{
"id": 28,
"talentId": 2,
"nodeSort": 6,
"type": "2&3",
"relationId": "19&20&26&27|25&",
"name": "抗伤强化",
"levelCount": 5,
"levelSeid": "2805&2806&2807&2808&2809",
"levelConsume": "1&2&3&4&5",
"prepositionId": "25&",
"preTotalPoint": 60,
"preSinglePoint": 10
}
]

File diff suppressed because it is too large Load Diff