feat(稷下学宫): ff931afe4到7421822f6

This commit is contained in:
luying
2023-08-30 11:02:52 +08:00
parent 59a334d673
commit 05cbe318e9
102 changed files with 147876 additions and 715 deletions

5
.gitignore vendored
View File

@@ -5,3 +5,8 @@ game-server/logs
.vscode/*
shared/**/*.js
shared/resource/privateKey
/.idea/.gitignore
/.idea/modules.xml
/.idea/inspectionProfiles/Project_Default.xml
/.idea/vcs.xml
/.idea/zyz_server.iml

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
import { RougelikeRecordDetailType } from '../../db/RougelikeRecordDetail';
import { COLLECTION_TYPE, PUSH_ROUTE, ROUGE_LIKE_CARD_TYPE } from '../../consts';
import { genCode } from '../../pubUtils/util';
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from '../../db/RougelikeChara';
import { RougelikeCardPara, RougelikeCardModel } from '../../db/RougelikeCard';
import { CommonCard, CommonChara } from '../../pubUtils/interface';
import { RougelikeCollectionModel } from '../../db/RougelikeCollection';
import { sendMessageToUserWithSuc } from '../pushService';
import { gameData } from '../../pubUtils/data';
import { clone } from 'underscore';
import { RougeEffect, getSlotUnlockPoint } from './rougeEffectService';
export class HandleAddCard {
roleId: string;
sid: string;
gameCode: string;
getLayer: number = 0;
getWay: number = 0;
addCharas: RougelikeCharaPara[] = []; // 需要更新的角色
addPassiveCards: RougelikeCardPara[] = []; // 需要更新的特性卡
addHolyCards: RougelikeCardPara[] = []; // 需要更新的圣物
addCoin: number = 0; // 需要增加的试炼币
constructor(roleId: string, sid: string, gameCode: string, recordDetail?: RougelikeRecordDetailType) {
this.roleId = roleId;
this.sid = sid;
this.gameCode = gameCode;
if (recordDetail) {
this.getLayer = recordDetail.layer;
this.getWay = recordDetail.nodeType;
}
}
private getCommonParam() {
let { roleId, gameCode, getLayer, getWay } = this;
return { roleId, gameCode, getLayer, getWay };
}
public pushChara(id: number, maxHp: number, passiveCardIds: number[]) {
let cards: Card[] = [];
for (let index = 0; index < passiveCardIds.length; index++) {
let cardId = passiveCardIds[index];
let cardCode = this.pushPassiveCard(cardId, id);
cards.push({ index, cardCode, cardId });
}
let charaCode = genCode(8);
this.addCharas.push({ ...this.getCommonParam(), cards, charaCode, charaId: id, maxHp, hp: maxHp, ap: 0, shield: 0, roundSkill: 0, apSkill: 0 });
return charaCode;
}
public pushCard(id: number, rewardType: ROUGE_LIKE_CARD_TYPE, charaId: number = 0) {
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE) {
return this.pushPassiveCard(id, charaId);
} else if (rewardType == ROUGE_LIKE_CARD_TYPE.HOLY) {
return this.pushHolyCard(id);
}
}
public pushPassiveCard(id: number, charaId: number = 0) {
let cardCode = genCode(8);
this.addPassiveCards.push({
...this.getCommonParam(), cardCode, cardId: id, type: ROUGE_LIKE_CARD_TYPE.PASSIVE, lv: gameData.rougePassiveCard.get(id)?.lv || 0, charaId
});
return cardCode
}
public pushHolyCards(ids: number[]) {
for (let id of ids) this.pushHolyCard(id);
}
public pushHolyCard(id: number) {
let cardCode = genCode(8);
this.addHolyCards.push({
...this.getCommonParam(), cardCode, cardId: id, type: ROUGE_LIKE_CARD_TYPE.HOLY, useCount: this.getHolyUseCount(id)
});
return cardCode
}
private getHolyUseCount(holyId: number) {
const holyCardData = gameData.rougeHolyCard.get(holyId);
return holyCardData?.useCount || 0;
}
public async save() {
let result: { addCharas?: CommonChara[], addCards?: CommonCard[] } = {};
if (this.addCharas.length > 0) {
let updateParams = this.addCharas || [];
let resultArrs = await RougelikeCharaModel.createCharas(updateParams);
this.addCharas = resultArrs;
result.addCharas = resultArrs.map(param => new CommonChara(param));
}
if (this.addPassiveCards.length > 0 || this.addHolyCards.length > 0) {
let updateParams = [...(this.addPassiveCards || []), ...(this.addHolyCards || [])];
// await RougelikeCardModel.bulkWriteUpdate(updateParams);
updateParams.map(async param => {
const { gameCode, cardCode } = param;
await RougelikeCardModel.updateByCode(gameCode, cardCode, { $set: param })
});
result.addCards = updateParams.map(param => new CommonCard(param));
}
let collections: { type: number, id: number, addNum?: number }[] = [];
for (let { cardId, type } of result.addCards || []) {
if (type == ROUGE_LIKE_CARD_TYPE.PASSIVE) {
collections.push({ type: COLLECTION_TYPE.PASSIVE_CARD, id: cardId });
}
if (type == ROUGE_LIKE_CARD_TYPE.HOLY) collections.push({ type: COLLECTION_TYPE.HOLY_CARD, id: cardId });
}
if (collections.length > 0) await addCollection(this.roleId, this.sid, this.gameCode, collections);
if (this.addCharas.length > 0) {
result.addCharas = await this.getCharasByHolyEffect();
}
return result;
}
// 处理获得角色卡时拥有圣物效果
public async getCharasByHolyEffect() {
let result = await getSlotUnlockPoint(this.roleId, this.gameCode, this.addCharas || []);
this.addCharas = result.dbCharas;
if (result.isUpdate) {
await RougelikeCharaModel.bulkWriteUpdate(this.addCharas || []);
}
return this.addCharas.map(param => new CommonChara(param));
}
// 处理圣物效果
public async getHolyEffect() {
let result: { addCharas?: CommonChara[], addCards?: CommonCard[] } = {};
let charasMap = (this.addCharas || []).reduce((result, cur) => { result.set(cur.charaCode, cur); return result; }, new Map<string, RougelikeCharaPara>());
let cardsMap = [...(this.addPassiveCards || []), ...(this.addHolyCards || [])].reduce((result, cur) => { result.set(cur.cardCode, cur); return result; }, new Map<string, RougelikeCardPara>());
if ((this.addHolyCards || []).length > 0) {
let rougeEffect = new RougeEffect(this.roleId, this.gameCode);
let holyIds = clone(this.addHolyCards.map(cur => { return { cardCode: cur.cardCode, cardId: cur.cardId, useCount: cur.useCount } }));
let { charas, cards } = await rougeEffect.getEffectImmediate(holyIds);
if (charas && charas.size > 0) {
await RougelikeCharaModel.bulkWriteUpdate([...charas.values()]);
charasMap = new Map([...charasMap, ...charas])
}
if (cards && Object.entries(cards).length > 0) {
cardsMap = new Map([...cardsMap, ...cards])
}
}
result.addCharas = [...charasMap.values()].map(param => new CommonChara(param));
result.addCards = [...cardsMap.values()].map(param => new CommonCard(param));
return result;
}
}
export function formateCharasOrCards(params: RougelikeCharaPara[] | RougelikeCardPara[], type: number) {
let result: { charas?: CommonChara[], cards?: CommonCard[] } = {};
if (!params || params.length == 0) return result;
const updateParams = params || [];
if (type == ROUGE_LIKE_CARD_TYPE.CHARA) result.charas = updateParams.map(param => new CommonChara(param));
else result.cards = updateParams.map(param => new CommonCard(param));
return result;
}
export async function addCollection(roleId: string, sid: string, gameCode: string, arr: { type: number, id: number, addNum?: number }[]) {
let collections: { type: number, id: number, num: number }[] = [], passiveCnt = 0;
for (let { type, id, addNum = 1 } of arr) {
if (type == COLLECTION_TYPE.PASSIVE_CARD_SUM) continue;
let collection = await RougelikeCollectionModel.addRec(roleId, type, id, gameCode, addNum);
if (!collection || collection.num > 1) continue;
if (collection.num == 1) passiveCnt++;
collections.push({ type, id, num: collection.num });
}
if (passiveCnt > 0) {
let collection = await RougelikeCollectionModel.addRec(roleId, COLLECTION_TYPE.PASSIVE_CARD_SUM, 0, gameCode, passiveCnt);
collections.push({ type: COLLECTION_TYPE.PASSIVE_CARD, id: 0, num: collection.num });
}
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.ROUGE_COLLECT_UPDATE, { collections }, sid);
return collections;
}
export async function addSingleCollect(roleId: string, sid: string, gameCode: string, type: number, id: number) {
return await addCollection(roleId, sid, gameCode, [{ type, id }]);
}
export async function addSameTypeCollect(roleId: string, sid: string, gameCode: string, type: number, ids: number[]) {
return await addCollection(roleId, sid, gameCode, ids.map(id => ({ type, id })));
}

View File

@@ -0,0 +1,536 @@
import { ABI_TYPE } from "../../consts/constModules/abilityConst";
import { ROUGELIKE_SKILLTYPE, ROUGE_EFFECT_TYPE, ROUGE_EFFECT_TYPE_KIND, ROUGE_LIKE_CARD_TYPE, ROUGE_SLOT_LIMIT } from "../../consts";
import { RougelikeCardModel, RougelikeCardPara, RougelikeCardType } from "../../db/RougelikeCard";
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from "../../db/RougelikeChara";
import { RougelikeRecordModel } from "../../db/RougelikeRecord";
import { gameData, getRougeEffectTypeKind } from "../../pubUtils/data";
import { DicRougePassiveCardPlan } from "../../pubUtils/dictionary/DicRougePassiveCardPlan";
import { getRandEelm } from "../../pubUtils/util";
import { RougelikeTechModel } from "../../db/RougelikeTech";
import { getAuthorTypeCardNum } from "./rougeService";
import * as util from 'util';
export class holyId {
cardCode: string;
cardId: number;
useCount: number;
}
export class RougeEffect {
roleId: string;
gameCode: string;
newEffect: { effectType: number, effectParam: number[], cardCode?: string }[] = [];
holyMap = new Map<string, { cardCode: string, cardId: number, useCount: number }>();
updateHolyMap = new Map<string, RougelikeCardType>();
updateCharaMap = new Map<string, RougelikeCharaType>();
updateCardMap = new Map<string, RougelikeCardType>();
dbCharas: RougelikeCharaType[] = [];
dbCards: RougelikeCardType[] = [];
constructor(roleId: string, gameCode: string) {
this.roleId = roleId || '';
this.gameCode = gameCode || '';
}
/**
* 根据类型获取effectId
* @param effectTypes
* @param holyIds
* @returns
*/
public async getEffectData(effectTypes: number[], holyIds?: holyId[]) {
let kinds = getRougeEffectTypeKind(effectTypes);
if (kinds.includes(ROUGE_EFFECT_TYPE_KIND.HOLY)) {
if (!holyIds || holyIds.length == 0) {
const dbCards = await RougelikeCardModel.findByGameCodeAndType(this.gameCode, ROUGE_LIKE_CARD_TYPE.HOLY);
holyIds = dbCards.map((cur) => { return { cardCode: cur.cardCode, cardId: cur.cardId, useCount: cur.useCount || 0 } });
}
if (!holyIds || holyIds.length == 0) return { newEffect: this.newEffect, holyMap: this.holyMap };
for (const { cardCode, cardId, useCount } of holyIds) {
let effectIds = gameData.rougeHolyCard.get(cardId)?.effectId || [];
if (effectIds.length == 0) continue;
for (const effectId of effectIds) {
const effectDataOne = gameData.rougeEffect.get(effectId);
if (!effectDataOne) continue;
const effectParam = effectDataOne.effectParam || [];
for (let effectType of effectTypes) {
if (effectType != effectDataOne.effectType || 0) continue;
this.newEffect.push({ effectType, effectParam, cardCode });
this.holyMap.set(cardCode, { cardCode, cardId, useCount })
}
}
}
}
if (kinds.includes(ROUGE_EFFECT_TYPE_KIND.TECH)) {
let tech = await RougelikeTechModel.findByRoleId(this.roleId, 'effectIds');
for (let effectId of (tech?.effectIds || [])) {
const effectDataOne = gameData.rougeEffect.get(effectId);
if (!effectDataOne) continue;
for (let effectType of effectTypes) {
if (effectType != effectDataOne.effectType || 0) continue;
this.newEffect.push({ effectType, effectParam: effectDataOne.effectParam || [] });
}
}
}
return { newEffect: this.newEffect, holyMap: this.holyMap }
}
/* **
* 获取圣物时生效
* @param gameCode
*/
public async getEffectImmediate(holyIds?: holyId[]) {
let result: { charas?: Map<string, RougelikeCharaType>, cards?: Map<string, RougelikeCardType> } = {};
this.dbCharas = await RougelikeCharaModel.findByGameCode(this.gameCode);
this.dbCards = await RougelikeCardModel.findByGameCode(this.gameCode);
await this.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_ALL, //2002
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_RAND, //2003
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_UPDATE_RAND, //2006
ROUGE_EFFECT_TYPE.HOLY_UPDATE_PASSIVE_BY_LV, //2012
ROUGE_EFFECT_TYPE.HOLY_REPAIRE_HOLY, //2015
], holyIds)
await this.getCharaSlot();
await this.getRandCharaSlot();
await this.getRandomCardLv()
await this.getPassiveLv();
await this.getRecoveryHoly();
result = { charas: this.updateCharaMap, cards: this.updateCardMap };
return result;
}
// 获得该圣物时所有学员立刻解锁X个特性槽 2002
private async getCharaSlot() {
if (this.newEffect.length == 0 || this.dbCharas.length == 0) return;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_ALL) continue;
if (effectParam.length == 0) continue;
for (let val of this.dbCharas) {
let { charaCode, cards = [] } = val;
let unlockNum = effectParam[0] || 0;
for (let i = 0; i < unlockNum; i++) {
unlockNum = effectParam[0] || 0;
if (cards.length >= ROUGE_SLOT_LIMIT) continue;
for (let index = 0; index < ROUGE_SLOT_LIMIT; index++) {
if (cards.find(cur => cur.index == index) != undefined || unlockNum == 0) continue;
cards.push({ index, cardCode: '', cardId: 0 });
this.updateCharaMap.set(charaCode, val);
unlockNum--;
}
}
}
}
}
// 获得该圣物时随机解锁X个学员的Y个特性槽 2003
private async getRandCharaSlot() {
if (this.newEffect.length == 0 || this.dbCharas.length == 0) return;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_RAND) continue;
if (effectParam.length == 0) continue;
const randomNum = effectParam[0] || 0;
let unlockNum = effectParam[1] || 0;
let charas = getRandEelm(this.dbCharas.filter(cur => cur.cards.length < ROUGE_SLOT_LIMIT), randomNum);
for (let val of charas) {
unlockNum = effectParam[1] || 0;
let { charaCode, cards = [] } = val;
for (let index = 0; index < ROUGE_SLOT_LIMIT; index++) {
if (cards.find(cur => cur.index == index) != undefined || unlockNum == 0) continue;
cards.push({ index, cardCode: '', cardId: 0 });
this.updateCharaMap.set(charaCode, val);
unlockNum--;
}
}
}
}
// 随机升级X个已装备的特性 2006
private async getRandomCardLv() {
let cards: RougelikeCardType[] = [];
if (this.newEffect.length == 0 || this.dbCards.length == 0) return cards;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_PASSIVE_UPDATE_RAND) continue;
if (effectParam.length == 0) continue;
const randomNum = effectParam[0] || 0;
let random = this.dbCards.filter(cur => cur.type == ROUGE_LIKE_CARD_TYPE.PASSIVE && cur.charaId != 0 && cur.lv < (gameData.rougePassiveCard.get(cur.cardId)?.lv || 0))
let cards = getRandEelm(random, randomNum);
cards.forEach(cur => {
cur.lv += 1;
this.updateCardMap.set(cur.cardCode, cur);
});
}
}
// 获得该圣物时立即升级所有X星特性卡 2012
private async getPassiveLv() {
if (this.newEffect.length == 0) return;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_UPDATE_PASSIVE_BY_LV) continue;
if (effectParam.length == 0) continue;
const level = effectParam[0] || 0;
for (let val of this.dbCards) {
let { lv, cardId, cardCode } = val;
const passiveCardData = gameData.rougePassiveCard.get(cardId);
if (level != passiveCardData?.quality || 0 || lv >= passiveCardData?.lv || 0) continue;
lv += 1;
this.updateCardMap.set(cardCode, val);
}
}
}
// 获得该圣物时随机修复X个已损毁的圣物 2015
private async getRecoveryHoly() {
if (this.newEffect.length == 0) return;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_REPAIRE_HOLY) continue;
if (effectParam.length == 0) continue;
const num = effectParam[0] || 0;
let canRandomCards: RougelikeCardType[] = []
this.dbCards.forEach(cur => {
const { cardCode, cardId, useCount = 0, type } = cur;
const holyCardData = gameData.rougeHolyCard.get(cardId);
let tempUseCount = holyCardData?.useCount || 0;
if (tempUseCount > 0 && useCount < tempUseCount && type == ROUGE_LIKE_CARD_TYPE.HOLY) canRandomCards.push(cur);
})
let randomCards = getRandEelm(canRandomCards, num);
for (let val of randomCards) {
let { cardCode, cardId } = val;
val.useCount += 1;
// if (this.holyMap.has(cardCode)) this.holyMap.set(cardCode, { cardCode, cardId, useCount });
this.updateCardMap.set(cardCode, val)
}
}
}
// 和圣物相关maxhp
public async getEffectMaxHp() {
let addRatio = 0;
await this.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP_BY_COIN, // 2005
ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP, // 2020
ROUGE_EFFECT_TYPE.TECH_CHARA_MAIN_ATTR_UP, // 3001
])
addRatio = await this.getMaxHpByCoin();
addRatio += await this.getMaxHpByBase();
return addRatio;
}
// 每有X个试炼币全员基础属性id提高Y 2005
private async getMaxHpByCoin() {
let addRatio = 0;
const dbRecord = await RougelikeRecordModel.findByGameCode(this.gameCode);
let coinTotal = dbRecord?.coin || 0;
if (this.newEffect.length == 0) return addRatio;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP_BY_COIN) continue;
if (effectParam.length == 0) continue;
const count = effectParam[0] || 0;
const id = effectParam[1] || 0;
const value = effectParam[2] || 0;
if (count == 0 || id != ABI_TYPE.ABI_HP || value == 0) continue;
addRatio += Math.floor(coinTotal / count * value)
}
return addRatio;
}
// 基础属性Id&num 2020
private async getMaxHpByBase() {
let addRatio = 0;
if (this.newEffect.length == 0) return addRatio;
for (const { effectParam, effectType } of this.newEffect) {
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP && effectType != ROUGE_EFFECT_TYPE.TECH_CHARA_MAIN_ATTR_UP) continue;
if (effectParam.length == 0) continue;
const id = effectParam[0] || 0;
const value = effectParam[1] || 0;
if (id != ABI_TYPE.ABI_HP || value == 0) continue;
addRatio += value;
}
return addRatio;
}
}
// 每场战斗结束后学员恢复血量上限X%的生命 2001
export async function getCharaHp(roleId: string, gameCode: string) {
let hpRatio = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_CHARA_HP_RECOVERY_UP,// 2001
]);
if (newEffect.length == 0) return hpRatio;
for (const { effectType, effectParam } of newEffect) {
if (effectParam.length == 0) continue;
hpRatio += (effectParam[0] || 0);
}
return hpRatio;
}
// 战斗胜利后获得的试炼币增加X 2004
export async function getAddCoin(roleId: string, gameCode: string, nodeType: number) {
let coinRatio = 0, coinAdd = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_COIN_UP, //2004
ROUGE_EFFECT_TYPE.TECH_COIN_UP_BY_NODE_TYPE, //3007
]);
if (newEffect.length == 0) return { coinRatio, coinAdd };
for (const { effectType, effectParam } of newEffect) {
if (effectParam.length == 0) continue;
if (effectType == ROUGE_EFFECT_TYPE.HOLY_COIN_UP) {
const type = effectParam[0] || 0;
const value = effectParam[1] || 0;
if (type == 1) coinAdd += value;
else if (type == 2) coinRatio += value;
}
if (effectType == ROUGE_EFFECT_TYPE.TECH_COIN_UP_BY_NODE_TYPE) {
let [targetNodeType = 0, value = 0] = effectParam;
if (targetNodeType == nodeType) coinRatio += value;
}
}
return { coinRatio, coinAdd };
}
// 获得圣物后X流派特性卡的权重增加Y 2007
export async function getAddPassiveWeight(roleId: string, gameCode: string, authorType: number) {
let addPassiveWeight = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_WEIGHT_UP_BY_AUTHOR,//2007
]);
if (newEffect.length == 0) return addPassiveWeight;
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const type = effectParam[0] || 0;
const value = effectParam[1] || 0;
if (type != authorType) continue;
addPassiveWeight += value;
}
return addPassiveWeight;
}
// 非boss战斗失败视为胜利并且满血复活 2009
export async function getNoBossRecoveryHp(roleId: string, gameCode: string) {
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_REVIVE_ALL,//2009
]);
if (newEffect.length == 0) return false;
return true; // 拿到true 将所有学员更新和hp=maxHp
}
// 战斗胜利后若有学员死亡则满血复活X名死亡学员 2010
export async function getBattleRecoveryNum(roleId: string, gameCode: string) {
let recoveryNum = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_REVIVE_CHARA_RAND,//2010
]);
if (newEffect.length == 0) return recoveryNum;
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
recoveryNum += (effectParam[0] || 0)
}
return recoveryNum;
}
// 试炼商店中所有商品X折出售 2011
export async function getShopDiscount(roleId: string, gameCode: string) {
let discount = 100;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_SHOP_DISCOUNT,//2011
]);
if (newEffect.length == 0) return discount;
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const tempDiscount = effectParam[0] || 0;
discount *= (tempDiscount / 100);
}
return Math.floor(discount);
}
// 下次选择特性卡时必定出现X星特性卡 2013
export async function getChooseQualityPassives(roleId: string, gameCode: string, passiveCards: DicRougePassiveCardPlan[]) {
let targetPassives: DicRougePassiveCardPlan[] = [];
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_CHOOSE_FIX,//2013
]);
if (newEffect.length == 0) return targetPassives;
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const level = effectParam[0] || 0;
for (let val of passiveCards) {
const { cardId } = val;
const passiveCardData = gameData.rougePassiveCard.get(cardId);
if (level != passiveCardData?.lv || 0) continue;
targetPassives.push(val);
}
}
return targetPassives;
}
// 下次选择特性卡时可多选X张特性卡 2014
export async function getAddChoosePassive(roleId: string, gameCode: string) {
let addChooseNum = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_CHOOSE_NUM_UP,//2014
]);
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const num = effectParam[0] || 0;
addChooseNum += num;
}
return addChooseNum
}
// 获得该圣物后所有角色解锁X号位置的特性槽 2023
export async function getSlotUnlockPoint(roleId: string, gameCode: string, dbCharas: RougelikeCharaPara[]) {
let isUpdate = false;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_POINT,//2023
]);
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const index = effectParam[0] || 0;
for (let { cards = [] } of dbCharas) {
if (cards.length == 0) {
cards.push({ index, cardCode: '', cardId: 0 });
isUpdate = true;
continue;
}
if (cards.find(cur => cur.index == index) == undefined) {
isUpdate = true
cards.push({ index, cardCode: '', cardId: 0 });
}
}
}
return { isUpdate, dbCharas };
}
// 休整点额外恢复X%的生命 2017 3006
export async function getRecoveryExtendHp(roleId: string, gameCode: string) {
let hpRatio = 0;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_RECOVERY_POINT_UP, // 2017
ROUGE_EFFECT_TYPE.TECH_RECOVERY_POINT_UP, // 3006
]);
if (newEffect.length == 0) return hpRatio;
for (const { effectType, effectParam } of newEffect) {
if (effectParam.length == 0) continue;
hpRatio += (effectParam[0] || 0);
}
return hpRatio;
}
// 休整点特训价格X折 2018 3009
export async function getTrainCardDiscount(roleId: string, gameCode: string) {
let discount = 100;
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect, holyMap } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.HOLY_TRAIN_POINT_DISCOUNT, // 2018
ROUGE_EFFECT_TYPE.TECH_TRAIN_POINT_DISCOUNT, // 3009
]);
if (newEffect.length == 0) return discount;
for (const { effectParam } of newEffect) {
if (effectParam.length == 0) continue;
const tempDiscount = effectParam[0] || 0;
discount *= (tempDiscount / 100);
}
return Math.floor(discount);
}
// 初始获得试炼币&圣物 3003 3005
export async function getEffectWhenGameStart(roleId: string, gameCode: string, authorType: number) {
let rougeEffect = new RougeEffect(roleId, gameCode);
let addCoin = 0, cardIds: number[] = [];
let { newEffect } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.TECH_INIT_HOLY_BY_AUTHOR,
ROUGE_EFFECT_TYPE.TECH_INIT_COIN,
]);
if (newEffect.length == 0) return { addCoin, cardIds };
for (const { effectType, effectParam } of newEffect) {
if (effectParam.length == 0) continue;
if (effectType == ROUGE_EFFECT_TYPE.TECH_INIT_HOLY_BY_AUTHOR) {
for (let cardId of effectParam) {
let dicCard = gameData.rougeHolyCard.get(cardId);
if (!dicCard || dicCard.authorType != authorType) continue;
cardIds.push(cardId);
}
}
if (effectType == ROUGE_EFFECT_TYPE.TECH_INIT_COIN) addCoin += effectParam[0];
}
return { addCoin, cardIds };
}
// 是否可以选择技能卡 3004
export async function checkCanChooseSkillCard(roleId: string, gameCode: string, skillId: number, cards: Card[]) {
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.TECH_CAN_CHOOSE_SKILL_CARD, // 3004
]);
let dicSkillCard = gameData.rougeSkillCard.get(skillId);
if (!dicSkillCard) return false;
let { authorType, skillType } = dicSkillCard;
let num = getAuthorTypeCardNum(authorType, cards);
let curParam = newEffect.find(({ effectParam }) => {
return effectParam[1] == skillType;
});
if (!curParam || num < curParam.effectParam[0]) return false;
return true;
}
// 是否可以重置
export async function checkCanReRandomReward(roleId: string, gameCode: string, rewardType: number) {
let rougeEffect = new RougeEffect(roleId, gameCode);
let { newEffect } = await rougeEffect.getEffectData([
ROUGE_EFFECT_TYPE.TECH_PASSIVE_RANDOM_AGAIN, // 3008
]);
let curParam = newEffect.find(({ effectParam }) => {
return effectParam[0] == rewardType;
});
if (!curParam) return { canReRandom: false, costCoin: 0 }
return { canReRandom: true, costCoin: curParam.effectParam[1] || 0 };
}

View File

@@ -0,0 +1,958 @@
import { clone, result } from "underscore";
import { ROUGE_CHARA_INITIAL, ROUGE_CHARA_TYPE, ROUGE_EFFECT_TYPE, ROUGE_LIKE_CARD_TYPE, ROUGE_LIKE_CHOOSE_REWARD, ROUGE_LIKE_NODE_TYPE, ROUGE_LIKE_STATUS, SHOP_REFRESH_TYPE } from "../../consts";
import { Card, RougelikeCharaModel, RougelikeCharaType } from "../../db/RougelikeChara";
import { RougelikeLayerModel, RougelikeLayerType } from "../../db/RougelikeLayer";
import { RougelikeRecordModel, RougelikeRecordType } from "../../db/RougelikeRecord";
import { gameData } from "../../pubUtils/data";
import { ROUGELIKE } from "../../pubUtils/dicParam";
import { genCode, getRandEelm, getRandEelmWithWeight, getRandEelmWithWeightAndNum, getRandValueByMinMax } from "../../pubUtils/util";
import { RougelikeCardModel, RougelikeCardType } from "../../db/RougelikeCard";
import RougelikeRecordDetail, { RougelikeRecordDetailModel, RougelikeRecordDetailPara, RougelikeRecordDetailType } from "../../db/RougelikeRecordDetail";
import { CollectionReturnParam, CommonCard, CommonChara, CommonNode, CommonReward, RewardInter, layerNode } from "../../pubUtils/interface";
import { DicRougeQuestionMarkPlan } from "../../pubUtils/dictionary/DicRougeQuestionMarkPlan";
import { DicRougeRandomEventPlan } from "../../pubUtils/dictionary/DicRougeRandomEventPlan";
import * as util from 'util';
import { RougelikeCollectionModel, } from "../../db/RougelikeCollection";
import { RougelikeScoreModel } from "../../db/RougelikeScore";
import { getTechData } from "./rougeTechService";
import { getZeroPointOfTimeD } from "../../pubUtils/timeUtil";
import { sendMailByContent } from "../mailService";
import { DicRougeCharaCardPlan } from "../../pubUtils/DicRougeCharaCardPlan";
import { MAIL_TYPE, PUSH_ROUTE } from "../../consts";
import { sendMessageToUserWithSuc } from "../pushService";
import { RougeEffect, getAddChoosePassive, getAddPassiveWeight, getChooseQualityPassives, getShopDiscount } from "./rougeEffectService";
import { formateCharasOrCards } from "./rougeCollectService";
import { errlogger } from "../../util/logger";
import { RougelikeExtendModel } from "../../db/RougelikeExtend";
export async function getRougeData(roleId: string) {
let isPlaying = true, gameCode = '';
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
if (!dbRecord) isPlaying = false;
else gameCode = dbRecord.gameCode;
let dbScore = await RougelikeScoreModel.findByRoleId(roleId);
let techData = await getTechData(roleId);
let dbCollections = await RougelikeCollectionModel.findByRoleId(roleId);
let collections = dbCollections.map((obj) => new CollectionReturnParam(obj));
const dbExtends = await RougelikeExtendModel.findByRoleId(roleId);
const limitIds = dbExtends.map(cur => cur.limitId);
return { isPlaying, gameCode, weeklyScore: dbScore?.score || 0, receivedScore: dbScore?.received || [], ...techData, collections, limitIds }
}
/*
/**
* 获取初始三名角色卡
* @param
* @returns
*/
export function getInitCharaCard() {
let canRandomCharas = gameData.rougeCharaByInitial.get(ROUGE_CHARA_INITIAL.CAN);
if (!canRandomCharas || canRandomCharas.length < ROUGELIKE.INIT_RANDOM_CHARA_COUNT) {
console.error("getInitChara--配置表中能初始随机的角色卡不足, canRandomCharas=%s", canRandomCharas);
return;
}
let randomData = getRandEelm(canRandomCharas, ROUGELIKE.INIT_RANDOM_CHARA_COUNT)
return randomData;
}
/**
* 获取大地图生成数据
* @param layerPlan
* @param layerCount
*/
export function getMap(layerPlan: number, layerCount: number) {
let retLayer = getLayerNodeRandom(layerPlan, layerCount);
if (!retLayer) return [];
return getLayerNodeLineRandom(retLayer) || [];
}
export function getLayerNodeRandom(layerPlan: number, layerCount: number) {
if (!layerPlan || !layerCount) return;
const layerPlanDatas = gameData.rougeLayerPlanByPlanId.get(layerPlan);
if (!layerPlanDatas || layerPlanDatas.length != layerCount) return console.error("getMap--获取配置层数不一致, layerPlan=%s, layerCount=%s", layerPlan, layerCount);
let retLayer = new Map<number, CommonNode>();
//获取可随机到的节点
for (let data of layerPlanDatas) {
let layerNodeNumPlanDatas = gameData.rougeLayerNodeNumPlan.get(data.nodeNumPlan);
if (!layerNodeNumPlanDatas) return console.error("getMap--rougeLayerNodeNumPlan配置错误, planId=%s", data.nodeNumPlan);
let nodeNum = 0;
if (layerNodeNumPlanDatas.length == 1) nodeNum = 1;
else nodeNum = getRandEelmWithWeight(layerNodeNumPlanDatas).dic.nodeNum;
let layerNodePlans = gameData.rougeLayerNodePlan.get(data.nodePlan);
if (!layerNodePlans || layerNodePlans.length == 0) return console.error("getMap--rougeLayerNodePlan配置错误, planId=%s", data.nodePlan);
let randomNodes: CommonNode['layerNodes'] = [], tempIndex = 0;
if (layerNodePlans.length > nodeNum) {
randomNodes = getRandEelmWithWeightAndNum(layerNodePlans, nodeNum).map((cur) => {
let nodeId = cur.dic.nodeId;
let nodeData = gameData.rougeNode.get(nodeId);
if (!nodeData) errlogger.error(`nodePlane ${data.nodePlan} 's nodeId ${nodeId} not found`);
return { detailCode: genCode(8), index: tempIndex++, nodeId, preNodeIndexs: [], type: nodeData.nodeType, isChoose: 0 };
});
} else {
randomNodes = layerNodePlans.map((cur) => {
let nodeId = cur.nodeId;
let nodeData = gameData.rougeNode.get(nodeId);
return { detailCode: genCode(8), index: tempIndex++, nodeId: cur.nodeId, preNodeIndexs: [] as number[], type: nodeData.nodeType, isChoose: 0 };
});
}
retLayer.set(data.layerIndex, { layer: data.layerIndex, layerNodes: randomNodes });
}
// console.log('-x-x--x-x-x-x-x-x-x-x-x- retLayer', util.inspect(retLayer, { depth: null }));
return retLayer;
}
/**
* 随机节点连线
* @param retLayer
* @returns
*/
export function getLayerNodeLineRandom(retLayer: Map<number, CommonNode>) {
for (let [key, value] of retLayer) {
let preLayer = retLayer.get(key - 1);
let curLayer = retLayer.get(key);
if (!preLayer || !curLayer) continue;
let tempPreNodes = preLayer.layerNodes; // 前一层节点数据
let tempCurNodes = curLayer.layerNodes; // 当前层节点数据
let indexMap = new Map<number, { dx: number, index: number }>(); //记录下前一层有那些节点与当前层是否连线
//当前层首节点
tempCurNodes[0].preNodeIndexs.push(tempPreNodes[0].index);
indexMap.set(tempPreNodes[0].index, { dx: 0, index: tempCurNodes[0].index });
//当前层尾节点
if (!(tempCurNodes.length == 1 && tempPreNodes.length == 1)) {
tempCurNodes[tempCurNodes.length - 1].preNodeIndexs.push(tempPreNodes[tempPreNodes.length - 1].index);
indexMap.set(tempPreNodes[tempPreNodes.length - 1].index, { dx: tempCurNodes.length - 1, index: tempCurNodes[tempCurNodes.length - 1].index });
}
for (let i = 0; i < tempCurNodes.length - 1; i++) {
let minIndex = 0, maxIndex = 0, start = 0;
if (i != 0) start = minIndex = maxIndex = Math.max(...tempCurNodes[i - 1].preNodeIndexs);
if (tempPreNodes[start + 1]) maxIndex = tempPreNodes[start + 1].index;
if (tempPreNodes[start + 2]) maxIndex = tempPreNodes[start + 2].index;
let randomIndex = minIndex;
if (minIndex < maxIndex) randomIndex = getRandValueByMinMax(minIndex, maxIndex + 1, 0);
if (tempCurNodes[i].preNodeIndexs.indexOf(randomIndex) != -1) continue;
tempCurNodes[i].preNodeIndexs.push(randomIndex);
if (indexMap.get(randomIndex) && indexMap.get(randomIndex).dx < i) continue;
indexMap.set(randomIndex, { dx: i, index: tempCurNodes[i].index });
}
//处理前一层有节点未连接情况
for (let i = 1; i < tempPreNodes.length - 1; i++) {
if (indexMap.get(tempPreNodes[i].index)) continue;
let minDx = 0, maxDx = 0;
let tempMap = new Map<number, number>();
if (tempPreNodes[i - 1] && indexMap.get(tempPreNodes[i - 1].index)) {
minDx = maxDx = indexMap.get(tempPreNodes[i - 1].index).dx
tempMap.set(minDx, indexMap.get(tempPreNodes[i - 1].index).index);
}
if (tempPreNodes[i + 1] && indexMap.get(tempPreNodes[i + 1].index)) {
maxDx = indexMap.get(tempPreNodes[i + 1].index).dx
tempMap.set(maxDx, indexMap.get(tempPreNodes[i + 1].index).index);
}
let randomDx = minDx;
if (minDx < maxDx) randomDx = getRandValueByMinMax(minDx, maxDx + 1, 0);
tempCurNodes[randomDx].preNodeIndexs.push(tempPreNodes[i].index);
if (indexMap.get(tempPreNodes[i].index) && indexMap.get(tempPreNodes[i].index).dx < randomDx) continue;
indexMap.set(tempPreNodes[i].index, { dx: randomDx, index: tempMap.get(randomDx) });
}
}
// console.log('-x-x--x-x-x-x-x-x-x-x-x- [...retLayer.values()]', util.inspect([...retLayer.values()], { depth: null }));
return [...retLayer.values()];
}
/**
* 选择节点
* @param dbRecord
* @param layerChooseNode
* @returns
*/
export async function chooseNode(dbRecord: RougelikeRecordType, layerChooseNode: layerNode, layer: number) {
const { roleId, gameCode, type, grade, curLayer, authorType } = dbRecord;
const { detailCode, nodeId, } = layerChooseNode
let nodeType = layerChooseNode.type;
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
const nodeData = gameData.rougeNode.get(nodeId);
if (!typeGradeData || !nodeData) return;
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
// console.log("-x--x-x-x-x- nodeData", nodeData)
// console.log("-x--x-x-x-x- typeGradeData", typeGradeData)
// console.log("-x--x-x-x-x- layerPlanData", layerPlanData)
if (!layerPlanData) return;
let isReward = false, isShop = false;
let warId, reward = {} as CommonReward, shops: RougelikeRecordDetailType['shops'] = [],
challenge = {} as RougelikeRecordDetailType['challenge'], question = {} as RougelikeRecordDetail['question'], restPoints: RougelikeRecordDetail['restPoints'] = [];
const dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
let status = 0;
if (dbDetail) status = dbDetail.status || 0;
let dbPara = { roleId, layer, nodeId, nodeType, status } as RougelikeRecordDetailPara;
//普通关、精英关、boss关
if (nodeType == ROUGE_LIKE_NODE_TYPE.ORDINARY || nodeType == ROUGE_LIKE_NODE_TYPE.ELITE || nodeType == ROUGE_LIKE_NODE_TYPE.BOSS) {
isReward = true;
warId = dbPara.warId = nodeData.param;
}
//挑战关
else if (nodeType == ROUGE_LIKE_NODE_TYPE.CHALLENGE) {
let getChallengeData = getChallenge(typeGradeData.challengePlan);
if (getChallengeData) {
challenge = { challengeId: getChallengeData.challengeId, status: 1, progress: 0 } as RougelikeRecordDetailType['challenge'];
dbPara.challenge = challenge;
}
// isReward = true;
}
//商店
else if (nodeType == ROUGE_LIKE_NODE_TYPE.SHOP) {
isShop = true;
}
//休整点
else if (nodeType == ROUGE_LIKE_NODE_TYPE.REST_POINT) {
isReward = true;
if (dbDetail && dbDetail.restPoints) restPoints = dbDetail.restPoints || restPoints;
else dbPara.restPoints = restPoints;
}
//问号点
else if (nodeType == ROUGE_LIKE_NODE_TYPE.QUEST_POINT) {
if (dbDetail) {
question = dbDetail.question || {} as RougelikeRecordDetail['question'];
warId = dbDetail.warId;
}
else {
const questionMarkPLanData = gameData.rougeQuestionMarkPlan.get(nodeData.param);
if (!questionMarkPLanData) return;
let randomData = {} as DicRougeQuestionMarkPlan;
if (questionMarkPLanData.length == 1) randomData = questionMarkPLanData[0];
else randomData = getRandEelmWithWeight(questionMarkPLanData).dic;
dbPara.questType = randomData.nodeType;
if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.ORDINARY || randomData.nodeType == ROUGE_LIKE_NODE_TYPE.ELITE) {
isReward = true;
warId = dbPara.warId = 101110101//randomData.param;
}
else if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.SHOP) {
isShop = true
}
else if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.EVENT) {
let random = {} as DicRougeRandomEventPlan;
const randomEventPlanData = gameData.rougeRandomEventPlan.get(typeGradeData.randomEventPlan);
if (!randomEventPlanData) return;
if (randomEventPlanData.length == 1) random = randomEventPlanData[0];
else random = getRandEelmWithWeight(randomEventPlanData).dic;
question.randomEventId = random.randomEventId;
question.EventOptions = [];
dbPara.question = question;
}
}
}
if ((!dbDetail || !dbDetail.shops || dbDetail.shops.length == 0) && isShop) {
shops = await getLayerShopReward(roleId, gameCode, authorType, nodeId, layerPlanData.shopPlan);
dbPara.shops = shops;
}
if (dbDetail && dbDetail.shops) shops = dbDetail.shops || shops;
if ((!dbDetail || !dbDetail.rewards || dbDetail.rewards.length == 0) && isReward) {
let result = await getLayerNodeReward(roleId, gameCode, authorType, nodeId, layerPlanData.rewardPlan, layer, dbPara.questType);
if (result) {
reward = result;
dbPara.rewards = result.rewards;
}
}
if (dbDetail && dbDetail.rewards) {
let tempType = (dbDetail?.questType || 0) > 0 ? dbDetail?.questType : nodeType
const layerRewardData = gameData.rougeLayerRewardPlan.get(layerPlanData.rewardPlan + '_' + tempType);
if (!layerRewardData) return;
let { coin, score, tech } = layerRewardData;
reward = { rewards: dbDetail.rewards || [], score: score || 0, techScore: tech || 0, takeoutReward: layerPlanData.takeoutReward || [] };
}
if (!dbDetail) {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- dbPara', util.inspect(dbPara, { depth: null }));
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: dbPara });
await RougelikeRecordModel.updateByGameCode(gameCode, { $set: { curLayer: layer } })
await RougelikeLayerModel.updateByGameCodeAndLayer(gameCode, layer, detailCode, ROUGE_LIKE_CHOOSE_REWARD.CHOOSE)
}
let curNode = { detailCode, nodeId, nodeType, status, warId, reward, shops, challenge, question, restPoints, }
// console.log('-x-x--x-x-x-x-x-x-x-x-x- curNode', util.inspect(curNode, { depth: null }));
return curNode;
}
/**
* 获取当前层当前节点奖励
* @param gameCode
* @param detailCode
* @param nodeId 关卡id
* @param rewardPlan 赠送奖励id
* @returns
*/
export async function getLayerNodeReward(roleId: string, gameCode: string, type: number, nodeId: number, rewardPlan: number, layer: number, nodeType?: number) {
const nodeData = gameData.rougeNode.get(nodeId);
if (!nodeData) return;
if (!nodeType) nodeType = nodeData?.nodeType || 0;
const layerRewardData = gameData.rougeLayerRewardPlan.get(rewardPlan + '_' + nodeType);
if (!layerRewardData) return;
let { charaPlan, charaRandomNum, charaChooseNum,
passiveCardPlan, charaPassivePlan, passiveCardRandomNum, passiveCardChooseNum,
holyCardPlan, holyCardRandomNum, holyCardChooseNum,
coin, score, tech } = layerRewardData;
let dbRougelikeCards = await RougelikeCardModel.findByGameCodeAndType(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
let rewards: RougelikeRecordDetailType['rewards'] = [];
let charaCards = getCharaCardPlan(charaPlan, charaRandomNum);
if (charaCards && charaCards.length > 0) {
let tempOptions = [], index = 0;
for (let ele of charaCards) {
tempOptions.push({
optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
passiveCardIds: await getSelfPassiveCards(ele.cardId, charaPassivePlan, type, dbRougelikeCards, gameCode, roleId)
})
}
rewards.push({
groupIndex: rewards.length + 1,
rewardType: ROUGE_LIKE_CARD_TYPE.CHARA,
options: tempOptions,
groupStatus: charaChooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
chooseNum: charaChooseNum,
});
}
let passiveCards = await getPassiveCardPlan(passiveCardPlan, passiveCardRandomNum, type, dbRougelikeCards, gameCode, roleId);
if (passiveCards && passiveCards.length > 0) {
let chooseNum = await getPassiveCardChooseNum(passiveCardChooseNum, passiveCardRandomNum, gameCode, layer, roleId);
rewards.push({
groupIndex: rewards.length + 1,
rewardType: ROUGE_LIKE_CARD_TYPE.PASSIVE,
options: passiveCards.map((ele, index) => { return { optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE, weightRecord: ele.weightRecord } }),
groupStatus: chooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
chooseNum
});
}
let holyCards = await getHolyCardPlan(holyCardPlan, holyCardRandomNum, dbRougelikeCards, gameCode, roleId);
if (holyCards && holyCards.length > 0) {
rewards.push({
groupIndex: rewards.length + 1,
rewardType: ROUGE_LIKE_CARD_TYPE.HOLY,
options: holyCards.map((ele, index) => { return { optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE, weightRecord: ele.weightRecord } }),
groupStatus: holyCardChooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
chooseNum: holyCardChooseNum,
});
}
// rewards.push({ groupIndex: rewards.length + 1, rewardType: 0, groupStatus: (coin || 0) > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE, chooseNum: coin || 0 })
return { rewards, score, techScore: tech };
}
// 处理挑战类型中 接下来X次选择特性卡时可选择的卡片数量少1
export async function getPassiveCardChooseNum(passiveCardChooseNum: number, passiveCardRandomNum: number, gameCode: string, layer: number, roleId: string) {
let chooseNum = passiveCardChooseNum;
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, layer);
if (dbDetails.length == 0) return chooseNum;
for (let { challenge } of dbDetails) {
if (challenge && Object.entries(challenge).length != 0 && challenge.status == 1) {
let { challengeId } = challenge;
const rougeChallengeData = gameData.rougeChallenge.get(challengeId);
if (!rougeChallengeData) return chooseNum;
for (let effectId of (rougeChallengeData.effectId || [])) {
const rougeEffectTypeData = gameData.rougeEffect.get(effectId);
if (rougeEffectTypeData.effectType != ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
chooseNum -= (rougeEffectTypeData.effectParam[1] || 0);
}
}
}
chooseNum += await getAddChoosePassive(roleId, gameCode);
if (chooseNum < 0) chooseNum = 0;
if (chooseNum > passiveCardRandomNum) chooseNum = passiveCardRandomNum;
return chooseNum;
}
/**
* 获取高级角色卡自带特性
* @param charaId
* @param passiveCardPlan
* @param passiveCardRandomNum
* @param type
* @param dbRougelikeCards
* @returns
*/
export async function getSelfPassiveCards(charaId: number, passiveCardPlan: number, type: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
let result: number[] = [];
let charaData = gameData.rougeChara.get(charaId);
if (!charaData) return result;
if (charaData.charaType != ROUGE_CHARA_TYPE.HIGH) return result;
let passiveCards = await getPassiveCardPlan(passiveCardPlan, charaData.initCardCnt, type, dbRougelikeCards, gameCode, roleId);
if (passiveCards && passiveCards.length > 0) result.push(...passiveCards.map((ele) => { return ele.cardId }),);
return result;
}
/**
* 获取当前层当前节点商店数据
* @param gameCode
* @param detailCode
* @param nodeId
* @param shopPlan
* @returns
*/
export async function getLayerShopReward(roleId: string, gameCode: string, type: number, nodeId: number, shopPlan: number) {
let shops: RougelikeRecordDetailType['shops'] = [];
let shopPlanData = gameData.rougeShopPlan.get(shopPlan);
// let nodeData = gameData.rougeNode.get(nodeId);
if (!shopPlanData) return shops;
let dbRougelikeCards = await RougelikeCardModel.findByGameCodeAndType(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
let passiveCards = await getPassiveCardPlan(shopPlanData.passivecardPlanId, shopPlanData.passiveCardRandomNum, type || 0, dbRougelikeCards, gameCode, roleId);
let index = 0, discount = await getShopDiscount(roleId, gameCode);
if (passiveCards && passiveCards.length > 0) {
for (let ele of passiveCards) {
let price = gameData.rougePassiveCard.get(ele.cardId)?.price || 0
shops.push({
optionIndex: shops.length + index,
rewardType: ROUGE_LIKE_CARD_TYPE.PASSIVE,
rewardId: ele.cardId,
optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
price,
discountPrice: Math.floor(price * discount / 100),
})
index++;
}
}
let holyCards = await getHolyCardPlan(shopPlanData?.holyCardPlanId, shopPlanData?.holyCardRandomNum, dbRougelikeCards, gameCode, roleId);
if (holyCards && holyCards.length > 0) {
for (let ele of holyCards) {
let price = gameData.rougeHolyCard.get(ele.cardId)?.purchasePrice || 0;
shops.push({
optionIndex: shops.length + index,
rewardType: ROUGE_LIKE_CARD_TYPE.HOLY,
rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
price,
discountPrice: Math.floor(price * discount / 100),
})
index++;
}
}
return shops;
}
/**
* 检测配置数据是否满足随机数量
* @param planId
* @param randomNum
* @returns
*/
export function checkRandomLimit(planId: number, randomNum: number, rewardType: number) {
let cards: DicRougeCharaCardPlan[] = [];
if (!planId || planId == 0 || !randomNum || randomNum == 0) return cards;
let cardPlanDatas = gameData.rougeCharaCardPlan.get(planId);
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE) cardPlanDatas = gameData.rougePassiveCardPlan.get(planId);
else if (rewardType == ROUGE_LIKE_CARD_TYPE.HOLY) cardPlanDatas = gameData.rougeHolyCardPlan.get(planId);
if (!cardPlanDatas) return cards;
else if (cardPlanDatas.length < randomNum) {
console.error("checkRandomLimit可随机的角色卡数量少于需要数量, planId=%s, randomNum=%s", planId, randomNum);
return cardPlanDatas;
}
else if (cardPlanDatas.length >= randomNum) return cardPlanDatas;
return cards;
}
/**
* 获取角色卡随机
* @param planId
* @param charaRandomNum
* @returns
*/
export function getCharaCardPlan(planId: number, charaRandomNum: number) {
let cards = checkRandomLimit(planId, charaRandomNum, ROUGE_LIKE_CARD_TYPE.CHARA);
if (cards.length <= charaRandomNum) return cards;
let randResult = getRandEelmWithWeightAndNum(cards, charaRandomNum);
return randResult.map(cur => cur.dic);
}
/**
* 获取特性卡随机
* @param passiveCardPlan
* @param passiveCardRandomNum
*/
export async function getPassiveCardPlan(passiveCardPlan: number, passiveCardRandomNum: number, type: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
let cards = checkRandomLimit(passiveCardPlan, passiveCardRandomNum, ROUGE_LIKE_CARD_TYPE.PASSIVE);
if (cards.length <= passiveCardRandomNum) return cards;
// 计算变化权重
let lableMap = new Map<number, number>(); //统计lable数量
if (dbRougelikeCards && dbRougelikeCards.length > ROUGELIKE.PASSIVE_LABLE_NUM) {
for (let { cardId } of dbRougelikeCards) {
if (!cardId) continue;
let passiveCardData = gameData.rougePassiveCard.get(cardId);
if (!passiveCardData || !passiveCardData.passiveLabel || passiveCardData.passiveLabel.length == 0) continue;
for (let val of passiveCardData.passiveLabel) {
if (!lableMap.get(val)) {
lableMap.set(val, 1);
continue;
}
lableMap.set(val, lableMap.get(val) + 1);
}
}
}
let newCards = [];
let cardsMap = await getCardCount(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
const { chooseCardsMap, noChooseCardsMap } = await getIsChooseCard(gameCode);
for (let obj of cards) {
let weightRecord: { originalWight?: number, passiveRedWight?: number, passiveLableNum?: number, authorAddWeight?: number, passiveLableNumAddWeight?: number, finalWeight?: number } = {};
if (!obj) continue;
let { cardId, weight } = obj;
if (!cardId || !weight) continue;
let passiveCardData = gameData.rougePassiveCard.get(cardId);
if (!passiveCardData) continue;
const getLimit = cardsMap.get(cardId) || 0;
if (getLimit >= (passiveCardData?.getLimit || 0)) continue; //处理限制获取数量
weightRecord.originalWight = weight;
if (chooseCardsMap.has(cardId)) {
weight = Math.floor(weight * (1 - ROUGELIKE.SELECT_PASSIVECARD_WEIGHT / 100));
weightRecord.passiveRedWight = Math.floor(weight * ROUGELIKE.SELECT_PASSIVECARD_WEIGHT / 100);
}
else if (noChooseCardsMap.has(cardId)) {
weight = Math.floor(weight * (1 - ROUGELIKE.RANDOM_PASSIVECARD_WEIGHT / 100));
weightRecord.passiveRedWight = Math.floor(weight * ROUGELIKE.RANDOM_PASSIVECARD_WEIGHT / 100);
}
weight += await getAddPassiveWeight(roleId, gameCode, type);
if ((passiveCardData?.authorType || 0) == type) weight += ROUGELIKE.AUTHOR_ADD_RANDOM;
weightRecord.authorAddWeight = ROUGELIKE.AUTHOR_ADD_RANDOM;
let labelNum = lableMap.get(cardId) || 0;
if (labelNum >= ROUGELIKE.PASSIVE_LABLE_NUM) {
weight += ROUGELIKE.PASSIVE_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.PASSIVE_LABLE_NUM));
weightRecord.passiveLableNum = labelNum;
weightRecord.passiveLableNumAddWeight = ROUGELIKE.PASSIVE_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.PASSIVE_LABLE_NUM));
}
// if (!passiveCardData.passiveLabel || passiveCardData.passiveLabel.length == 0) continue;
// for (let val of passiveCardData.passiveLabel) {
// let labelNum = lableMap.get(val) || 0;
// if (labelNum < ROUGELIKE.PASSIVE_LABLE_NUM || ROUGELIKE.PASSIVE_LABLE_NUM == 0) continue;
// weight += ROUGELIKE.PASSIVE_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.PASSIVE_LABLE_NUM));
// }
weightRecord.finalWeight = weight;
newCards.push({ ...obj, weight, weightRecord });
}
let targetPassives = await getChooseQualityPassives(roleId, gameCode, newCards);
let result = [];
if (passiveCardRandomNum >= 1 && targetPassives.length > 0) result.push(getRandEelmWithWeight(targetPassives).dic);
let randResult = getRandEelmWithWeightAndNum(newCards, passiveCardRandomNum - result.length);
return [...result, ...randResult.map(cur => cur.dic)]
}
export async function getIsChooseCard(gameCode: string) {
const dbDetails = await RougelikeRecordDetailModel.findByGameCode(gameCode);
let chooseCardsMap = new Map<number, number>();
let noChooseCardsMap = new Map<number, number>();
for (const { rewards } of dbDetails) {
if (!rewards || rewards.length == 0) continue;
for (const { options } of rewards) {
if (!options || options.length == 0) continue;
for (const { rewardId, optionStatus } of options) {
if (optionStatus != 0) {
chooseCardsMap.set(rewardId, rewardId);
continue;
}
noChooseCardsMap.set(rewardId, rewardId);
}
}
}
return { chooseCardsMap, noChooseCardsMap };
}
export async function getCardCount(gameCode: string, type: number) {
const dbCards: RougelikeCardType[] = await RougelikeCardModel.findByGameCodeAndType(gameCode, type);
let cardsMap = new Map<number, number>();
dbCards.forEach((cur) => { cardsMap.set(cur.cardId, (cardsMap.get(cur.cardId) || 0) + 1); })
return cardsMap;
}
/**
* 获取圣物随机
* @param planId
* @param holyCardPlan
*/
export async function getHolyCardPlan(holyCardPlan: number, holyCardRandomNum: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
let cards = checkRandomLimit(holyCardPlan, holyCardRandomNum, ROUGE_LIKE_CARD_TYPE.HOLY);
if (cards.length <= holyCardRandomNum) return cards;
let lableMap = new Map<number, number>();//统计lable数量
if (dbRougelikeCards && dbRougelikeCards.length > ROUGELIKE.HOLY_LABLE_NUM) {
for (let { cardId } of dbRougelikeCards) {
if (!cardId) continue;
let passiveCardData = gameData.rougePassiveCard.get(cardId);
if (!passiveCardData || !passiveCardData.holyLabel || passiveCardData.holyLabel.length == 0) continue;
for (let val of passiveCardData.holyLabel) {
if (!lableMap.get(val)) {
lableMap.set(val, 1);
continue;
}
lableMap.set(val, lableMap.get(val) + 1);
}
}
}
// 计算变化权重
let newCards = [];
let cardsMap = await getCardCount(gameCode, ROUGE_LIKE_CARD_TYPE.HOLY);
const { chooseCardsMap, noChooseCardsMap } = await getIsChooseCard(gameCode);
for (let obj of cards) {
let weightRecord: {
originalWight?: number, passiveRedWight?: number, holyRedWight?: number, authorAddWeight?: number,
passiveLableNum?: number, passiveLableNumAddWeight?: number, holyLableNum?: number, holyLableNumAddWeight?: number,
finalWeight?: number
} = {};
if (!obj) continue;
let { cardId, weight } = obj;
if (!cardId || !weight) continue;
let holyCardData = gameData.rougeHolyCard.get(cardId);
if (!holyCardData) continue;
const getLimit = cardsMap.get(cardId) || 0;
if (getLimit >= (holyCardData?.getLimit || 0)) continue; //处理限制获取数量
weightRecord.originalWight = weight;
if (chooseCardsMap.has(cardId)) {
weight = Math.floor(weight * (1 - ROUGELIKE.SELECT_HOLLYCARD_WEIGHT / 100));
weightRecord.holyRedWight = Math.floor(weight * ROUGELIKE.SELECT_HOLLYCARD_WEIGHT / 100);
}
else if (noChooseCardsMap.has(cardId)) {
weight = Math.floor(weight * (1 - ROUGELIKE.RANDOM_HOLLYCARD_WEIGHT / 100));
weightRecord.holyRedWight = Math.floor(weight * ROUGELIKE.RANDOM_HOLLYCARD_WEIGHT / 100);
}
if (!holyCardData.label) {
newCards.push({ ...obj });
continue;
};
let labelNum = lableMap.get(holyCardData.label) || 0;
if (labelNum < ROUGELIKE.HOLY_LABLE_NUM || ROUGELIKE.HOLY_LABLE_NUM == 0) {
newCards.push({ ...obj });
continue;
};
weight += ROUGELIKE.HOLY_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.HOLY_LABLE_NUM));
weightRecord.holyLableNum = labelNum;
weightRecord.holyLableNumAddWeight = ROUGELIKE.HOLY_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.HOLY_LABLE_NUM));
weightRecord.finalWeight = weight;
newCards.push({ ...obj, weight, weightRecord });
}
let randResult = getRandEelmWithWeightAndNum(newCards, holyCardRandomNum);
return randResult.map(cur => cur.dic);
}
/**
* 获取挑战关卡数据
* @param planId
* @returns
*/
export function getChallenge(planId: number) {
const randomChallenge = getChallengePlan(planId);
if (!randomChallenge) return;
const rougeChallengeData = gameData.rougeChallenge.get(randomChallenge.challengeId);
if (!rougeChallengeData) return;
return rougeChallengeData;
}
/**
* 获取挑战关随机
* @param planId
* @returns
*/
export function getChallengePlan(planId: number) {
const challengePlanData = gameData.rougeChallengePlan.get(planId);
if (!challengePlanData) return;
if (challengePlanData.length == 1) return challengePlanData[0];
return getRandEelmWithWeight(challengePlanData).dic;
}
export async function updateChalleng(dbRecord: RougelikeRecordType, roleId: string, sid: string, gameCode: string, curLayer: number, rougeDamage, isAp?: boolean, isRound?: boolean) {
let len = rougeDamage.length;
const minHp = rougeDamage.reduce((min, cur) => { return Math.min(min, cur.hp); }, Infinity);
let challenges: { challengeId: number, status: number, progress: number, detailCode: string }[] = [];
const { authorType, type, grade } = dbRecord;
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, curLayer);
if (dbDetails.length == 0) return true;
let updateChallengs: RougelikeRecordDetailPara[] = [];
for (let { detailCode, challenge, rewards = [], nodeId, layer } of dbDetails) {
if (challenge && Object.entries(challenge).length != 0 && challenge.status == 1) {
let { challengeId } = challenge;
const rougeChallengeData = gameData.rougeChallenge.get(challengeId);
if (!rougeChallengeData) return true;
for (let effectId of (rougeChallengeData.effectId || [])) {
const rougeEffectTypeData = gameData.rougeEffect.get(effectId);
if (len == 0) {
//接下来X次选择特性卡时可选择的卡片数量少1
if (rougeEffectTypeData.effectType != ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
} else {
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NO_AP_SKILL && isAp) continue;
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NO_ROUND_SKILL && isRound) continue;
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_HP_LIMIT && (rougeEffectTypeData.effectParam[1] || 0) > minHp) continue;
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NUM_LIMIT && (rougeEffectTypeData.effectParam[1] || 0) != len) continue;//接下来X场战斗每场战斗只能上阵2名学员
}
challenge.progress += 1;
if (challenge.progress == rougeChallengeData.condition) {
challenge.status = 2;
//处理在挑战进度完成时再随机奖励
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
if (!typeGradeData) continue;
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
if (!layerPlanData) continue;
let result = await getLayerNodeReward(roleId, gameCode, authorType, nodeId, layerPlanData.rewardPlan, layer);
rewards = result.rewards;
};
}
challenges.push({ challengeId, status: challenge.status, progress: challenge.progress, detailCode });
updateChallengs.push({ gameCode, detailCode, challenge, status: 1, rewards });
}
}
await RougelikeRecordDetailModel.bulkWriteUpdate(updateChallengs);
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.ROUGE_CHALLENGE_UPDATE, { challenges }, sid);
return true;
}
export function getLayerRewardOneData(type: number, grade: number, layer: number, nodeType: number) {
let result: { takeoutReward?: RewardInter[], coin?: number, score?: number, tech?: number, spiritPlan?: number } = {};
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
if (!typeGradeData) return result;
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
if (!layerPlanData) return result;
const layerRewardData = gameData.rougeLayerRewardPlan.get(layerPlanData.rewardPlan + '_' + nodeType);
if (!layerRewardData) return result;
return { ...layerRewardData, takeoutReward: layerPlanData.takeoutReward, spiritPlan: layerPlanData.spiritPlan };
}
export function getRandomSpirit(spiritPlan: number) {
let spiritId: number[] = [];
const spiritPlanData = gameData.spiritPlan.get(spiritPlan);
if (ROUGELIKE.SPIRIT_RANDOM_NUM == 0 || !spiritPlanData || spiritPlanData.length == 0) return spiritId;
let random = getRandEelmWithWeightAndNum(spiritPlanData, ROUGELIKE.SPIRIT_RANDOM_NUM);
spiritId = random.map(cur => { return cur.dic.spiritId });
return spiritId;
}
/**
* 获取
* @param authorType
* @param cards
* @returns
*/
export function getAuthorTypeCardNum(authorType: number, cards: Card[]) {
return cards.filter(card => {
let dicCard = card.cardId == 0 ? null : gameData.rougePassiveCard.get(card.cardId);
if (!dicCard) return false;
return dicCard.authorType == authorType;
}).length;
}
export async function repaireSendScoreReward() {
let maxNum = gameData.rougeScoreNum.num || 0;
let refTime = getZeroPointOfTimeD(Date.now() - 86400000, SHOP_REFRESH_TYPE.WEEKLY);
let allRewards = await RougelikeScoreModel.findByReceiveNum(refTime, maxNum);
let _ids: string[] = [];
for (let { roleId, received, _id, score } of allRewards) {
let goods: RewardInter[] = [];
for (let [index, { reward, score: targetScore }] of gameData.rougeScoreReward) {
if (score >= targetScore && !received.includes(index)) goods.push(...reward);
}
await sendMailByContent(MAIL_TYPE.ROUGE_SCORE_REPAIRE, roleId, { goods });
_ids.push(_id);
}
await RougelikeScoreModel.receiveAll(_ids, maxNum + 1);
}
/**
* 获取最大血量
* @param charaId
* @param type
* @param grade
* @returns
*/
export async function getMaxHp(roleId: string, gameCode: string, charaId: number, type: number, grade: number,) {
let maxHp = 0;
const charaData = gameData.rougeChara.get(charaId);
if (!charaData || !charaData.heroId) return maxHp;
const heroData = gameData.hero.get(charaData.heroId);
// console.log("x-x-x-x--x-xx- heroData", heroData);
if (!heroData || !heroData.hp) return maxHp;
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
// console.log("x-x-x-x--x-xx- typeGradeData", typeGradeData);
if (!typeGradeData || !typeGradeData.heroValue) return maxHp;
let rougeEffect = new RougeEffect(roleId, gameCode);
const holyMaxHp = await rougeEffect.getEffectMaxHp();
maxHp = heroData.hp * typeGradeData.heroValue / 10000 * (1 + holyMaxHp / 100);
return Math.floor(maxHp);
}
export async function updateMaxHp(roleId: string, gameCode: string, type: number, grade: number) {
let dbCharas = await RougelikeCharaModel.findByGameCode(gameCode);
if (dbCharas.length == 0) return [];
let result: RougelikeCharaType[] = [];
for (let val of dbCharas) {
let tempMaxHp = await getMaxHp(roleId, gameCode, val.charaId, type, grade);
if (tempMaxHp == val.maxHp) continue;
val.maxHp = tempMaxHp;
result.push(val);
}
await RougelikeCharaModel.bulkWriteUpdate(result);
let { charas } = formateCharasOrCards(result, ROUGE_LIKE_CARD_TYPE.CHARA)
return charas || [];
}
// 获取当前层之前所有未完成挑战关
export async function getPreCurLayerChallengs(gameCode: string, layer: number) {
let challenges: { challengeId: number, status: number, progress: number, detailCode: string, reward: CommonReward }[] = [];
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, layer);
if (dbDetails.length == 0) return challenges;
for (let { detailCode, challenge, rewards } of dbDetails) {
if (!challenge) continue;
const { challengeId, status, progress } = challenge;
if (status == 3) continue;
challenges.push({ challengeId, status, progress, detailCode, reward: { rewards } });
}
return challenges;
}
export async function getGame(roleId: string) {
let isPlaying = true, nodes: RougelikeLayerType[] = [], hasPass = false, curNode = {};
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
if (!dbRecord) {
isPlaying = false;
return { isPlaying };
}
const { gameCode, grade, type, authorType = 0, curLayer = 0, maxLayer = 0, coin = 0, score = 0, techScore = 0, coinTotal = 0 } = dbRecord;
const dbNodes = await RougelikeLayerModel.findByGameCode(gameCode);
let dbCurLayerChooseNode = {} as layerNode;
if (dbNodes) nodes = dbNodes.map((obj) => {
const { layer, layerNodes, hasPass: dbHasPass = false } = obj;
if (layer == curLayer) {
hasPass = dbHasPass;
dbCurLayerChooseNode = layerNodes.find(cur => cur.isChoose == ROUGE_LIKE_CHOOSE_REWARD.CHOOSE);
}
return { layer, layerNodes } as RougelikeLayerType
})
const charas: CommonChara[] = formateCharasOrCards(await RougelikeCharaModel.findByGameCode(gameCode), ROUGE_LIKE_CARD_TYPE.CHARA)?.charas || [];
const cards: CommonCard[] = formateCharasOrCards(await RougelikeCardModel.findByGameCode(gameCode), ROUGE_LIKE_CARD_TYPE.PASSIVE | ROUGE_LIKE_CARD_TYPE.HOLY)?.cards || [];
console.log("x-x-x-x-x-x-x-x- dbCurLayerChooseNode", dbCurLayerChooseNode)
if (Object.entries(dbCurLayerChooseNode).length != 0) curNode = await chooseNode(dbRecord, dbCurLayerChooseNode, curLayer)
return {
isPlaying, gameCode, grade, type, authorType,
curLayer, hasPass, maxLayer, coin, coinTotal, score, techScore, nodes: nodes || [], charas, cards, curNode,
preChallengs: await getPreCurLayerChallengs(gameCode, curLayer)
};
}

View File

@@ -0,0 +1,121 @@
import { Circle, RougelikeTechModel, RougelikeTechType } from '../../db/RougelikeTech';
import { gameData } from '../../pubUtils/data';
import { HeroModel } from '../../db/Hero';
import { compareNumberArray } from '../../pubUtils/util';
/**
* 首页获得的科技树数据
* @param techData
* @returns
*/
export async function getTechData(roleId: string) {
let techData = await RougelikeTechModel.findByRoleId(roleId);
if(!techData) return { techTrees: [], sumTechScore: 0 };
let { unlockedTech = [], circles = [] } = techData;
circles = await calCircleCe(roleId, unlockedTech, circles);
let techTrees = unlockedTech.map(techId => getSingleTechData(techId, circles));
return {
techTrees
}
}
/**
* 从首页重新进入,重新计算他的战力
* @param roleId
* @param circles
* @returns
*/
async function calCircleCe(roleId: string, unlockedTech: number[], circles: Circle[]) {
let hids: number[] = circles.map(circle => circle.hid).filter(hid => hid > 0);
if(hids.length <= 0) return circles
let heroes = await HeroModel.findByHidRange(hids, roleId);
let newCircle = circles.map(circle => {
if(circle.hid == 0) return circle;
let hero = heroes.find(cur => cur.hid == circle.hid);
return { ...circle, ce: hero?.ce||0 }
});
let effectIds = getTechEffectIds(unlockedTech, circles)
await RougelikeTechModel.updateCircle(roleId, newCircle, effectIds);
return newCircle;
}
export async function updateEffectId(techData: RougelikeTechType) {
let effectIds = getTechEffectIdsByData(techData);
if(!compareNumberArray(effectIds, techData.effectIds||[])) {
await RougelikeTechModel.updateEffectId(techData.roleId, effectIds);
}
}
/**
* 处理后单个科技点的数据
* @param techData
* @param techId
* @returns
*/
export function getCurTechData(techData: RougelikeTechType, techId: number) {
if(!techData || !techId) return { curTechTree: { techId, circles: [] } }
let { circles = [] } = techData;
return {
curTechTree: getSingleTechData(techId, circles)
}
}
/**
* 获取单片科技树数据
* @param techId
* @param circles
* @returns
*/
function getSingleTechData(techId: number, circles: Circle[]) {
let result: { circleId: number, hid: number, ce: number }[] = [];
for(let { techId: curTechId, hid, circleId, ce } of circles) {
if(curTechId == techId) result.push({ hid, circleId, ce });
}
return { techId, circles: result };
}
/**
* 检查前置科技点是否解锁
* @param techId
* @param unlockedTech
* @returns
*/
export function checkPreRougeTech(techId: number, unlockedTech: number[]) {
let dicTech = gameData.rougeTech.get(techId);
let preTechId = dicTech?.preTechId||[];
for(let techId of preTechId) {
if(!unlockedTech.includes(techId)) return false;
}
return true;
}
/**
* 获取科技树带来的type加成
* @param roleId
* @returns [{ type: number, param: number[] }]
*/
export function getTechEffectIdsByData(techData: RougelikeTechType) {
if(!techData) return [];
return getTechEffectIds(techData.unlockedTech, techData.circles);
}
export function getTechEffectIds(unlockedTech: number[], circles: Circle[]) {
let result: number[] = [];
let techMap = new Map<number, number>();
for(let techId of unlockedTech) {
techMap.set(techId, 0);
}
for(let { techId, ce } of circles) {
let oldCe = techMap.get(techId)||0;
techMap.set(techId, oldCe + ce);
}
for(let [techId, ce] of techMap) {
let levelDatas = gameData.rougeTechLevel.get(techId)||[];
let effectIds: number[] = [];
for(let { techEffectIds, ce: targetCe } of levelDatas) {
if(ce >= targetCe) effectIds = techEffectIds;
}
result.push(...effectIds);
}
return result;
}

View File

@@ -866,6 +866,167 @@ export function checkRouteParam(route: string, msg: any) {
if (!checkNaturalNumbers(msg.id)) return false;
break;
}
case "battle.rougeHandler.getData":
break;
case "battle.rougeHandler.getGame":
break;
case "battle.rougeHandler.getInitCharaCard":
{
let { type, grade } = msg
if (!checkNaturalNumbers(type, grade)) return false;
break;
}
case "battle.rougeHandler.startGame":
{
let { gameCode, authorType } = msg;
if (!checkNaturalStrings(gameCode)) return false;
if (!checkNaturalNumbers(authorType)) return false;
break;
}
case "battle.rougeHandler.gameEnd":
{
let { gameCode } = msg;
if (!checkNaturalStrings(gameCode)) return false;
break;
}
case "battle.rougeHandler.chooseNode":
{
let { gameCode, layer, detailCode } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkNaturalNumbers(layer)) return false;
break;
}
case "battle.rougeHandler.checkBattle":
{
let { gameCode, detailCode, warId, charaCodes } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkNaturalNumbers(warId)) return false;
if (!checkIsDuplicateStrings(charaCodes)) return false;
break;
}
case "battle.rougeHandler.battleEnd":
{
let { gameCode, detailCode, battleCode, warId, status, round, rougeDamage, isAp, isRound } = msg;
if (!checkNaturalStrings(gameCode, detailCode, battleCode)) return false;
if (!checkNaturalNumbers(warId, round, status)) return false;
if (!checkBooleanIfExist(isAp, isRound)) return false;
if (!isArray(rougeDamage) || rougeDamage.length == 0) return false;
let charaCodes: string[] = [];
for (let { charaCode } of rougeDamage) {
if (!charaCode) return false;
charaCodes.push(charaCode);
}
if (!checkIsDuplicateStrings(charaCodes)) return false;
break;
}
case "battle.rougeHandler.chooseReward":
{
let { gameCode, detailCode, groupIndex, optionIndexs } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkNaturalNumbers(groupIndex)) return false;
if (!checkIsDuplicateNumbers(optionIndexs)) return false;
break;
}
case "battle.rougeHandler.reRandomReward":
{
let { gameCode, detailCode, rewardType } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkNaturalNumbers(rewardType)) return false;
break;
}
case "battle.rougeHandler.shopBuy":
{
let { gameCode, detailCode, optionIndex } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkNaturalNumbers(optionIndex)) return false;
break;
}
case "battle.rougeHandler.chooseOption":
{
let { gameCode, detailCode, eventOptions } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
if (!checkIsDuplicateNumbers(eventOptions)) return false;
break;
}
case "battle.rougeHandler.recovery":
{
let { gameCode, detailCode } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
break;
}
case "battle.rougeHandler.trainCard":
{
let { gameCode, detailCode, cardCode } = msg;
if (!checkNaturalStrings(gameCode, detailCode, cardCode)) return false;
break;
}
case "battle.rougeHandler.nodeEnd":
{
let { gameCode, detailCode, } = msg;
if (!checkNaturalStrings(gameCode, detailCode)) return false;
break;
}
case "battle.rougeHandler.putOnOrOffCard":
{
let { gameCode, charaCode, cards } = msg;
if (!checkNaturalStrings(gameCode, charaCode)) return false;
let cardCodes: string[] = [], indexs: number[] = [];
for (let { index, cardCode } of cards) {
indexs.push(index);
if (cardCode) cardCodes.push(cardCode);
}
if (!checkIsDuplicateNumbers(indexs)) return false;
if (!checkIsDuplicateStrings(cardCodes)) return false;
break;
}
case "battle.rougeHandler.exchangeChara":
{
let { gameCode, oldCharaCode, newCharaCode } = msg;
if (!checkNaturalStrings(gameCode, oldCharaCode, newCharaCode)) return false;
break;
}
case "battle.rougeHandler.unlockTech":
{
if (!checkNaturalNumbers(msg.techId)) return false;
break;
}
case "battle.rougeHandler.putOnCircle":
{
if (!checkNaturalNumbers(msg.circleId, msg.hid)) return false;
break;
}
case "battle.rougeHandler.chooseSkillCard":
{
if (!checkNaturalStrings(msg.gameCode, msg.charaCode)) return false;
if (!checkNaturalNumbers(msg.skillType, msg.id)) return false;
break;
}
case "battle.rougeHandler.receiveCollectionReward":
{
if (!checkNaturalNumbers(msg.type, msg.id)) return false;
break;
}
case "battle.rougeHandler.receiveScore":
{
if (!checkNaturalNumbers(msg.index)) return false;
break;
}
case "chat.chatHandler.sendGroupMessage":
{
let { channel, type, content, targetRoleId, targetMsgCode } = msg;
@@ -2223,11 +2384,17 @@ export function checkRouteParam(route: string, msg: any) {
case "activity.bindPhoneHandler.debugSetGiftCodeStatus":
case 'activity.rebateHandler.debugSetRebate':
case 'activity.newHeroGKHandler.debugResetGK':
case 'battle.rougeHandler.debugClearTech':
case "battle.rougeHandler.debugAddCard":
case "battle.rougeHandler.debugAddScore":
case "battle.rougeHandler.debugRepaireScoreReward":
case "battle.rougeHandler.debugAddCollection":
{
if (msg.magicWord !== DEBUG_MAGIC_WORD || !isDevelopEnv()) return false;
break;
}
case "battle.rougeHandler.debugAddLimitId":
case "comBattle.comBattleHandler.getTeams":
case "comBattle.comBattleHandler.teammateReady":
case "comBattle.comBattleHandler.battleEnd":
@@ -2364,3 +2531,27 @@ function checkCombo(combo: { groupId: number, levelList: number[] }[]) {
}
return true;
}
function checkIsDuplicateNumbers(array: number[]) {
const seen = new Set();
for (const item of array) {
if (!isNumber(item)) return false;
if (seen.has(item)) {
return false; // 发现重复元素
}
seen.add(item);
}
return true; // 没有重复元素
}
function checkIsDuplicateStrings(array: string[]) {
const seen = new Set();
for (const item of array) {
if (!isString(item)) return false;
if (seen.has(item)) {
return false; // 发现重复元素
}
seen.add(item);
}
return true; // 没有重复元素
}

View File

@@ -54,6 +54,7 @@ import { LinkModel } from '../db/Link';
import { getHiddenData } from './memoryCache/hiddenData';
import { AuthorBookModel } from '../db/AuthorBook';
import { gameData } from '../pubUtils/data';
import { getRougeData } from './battle/rougeService';
/**
* init: 初始的时候是否推送 true-推 false-不推
@@ -89,6 +90,7 @@ const modules = [
{ id: 26, type: 'survey', init: false, refresh: true, guild: false },
{ id: 27, type: 'ladder', init: false, refresh: true, guild: false },
{ id: 28, type: 'hiddenData', init: true, refresh: true, guild: false },
{ id: 29, type: 'rouge', init: true, refresh: true, guild: false },
]
export async function pushData(hasInit: boolean, role: RoleType, session: FrontendOrBackendSession, pushType: 'entry' | 'refresh' = 'entry') {
@@ -229,6 +231,8 @@ export async function getModuleData(type: string, data: { role: RoleType, sessio
return await getLadderData(role.roleId, false);
case 'hiddenData':
return getHiddenData();
case 'rouge':
return await getRougeData(role.roleId);
default:
return null;
}

View File

@@ -31,6 +31,7 @@ import { pick } from "underscore";
import { memberJoinGuildToLeague } from "./gvg/gvgTeamService";
import { isToday } from '../pubUtils/timeUtil';
import moment = require("moment");
import { repaireSendScoreReward } from "./battle/rougeService";
export async function getMyGuildInfo(roleId: string, sid: string, userGuild: UserGuildType, guild: GuildType, serverId: number, session: FrontendOrBackendSession) {
@@ -433,6 +434,10 @@ export async function settleGuildWeekly() {
await initSingleRank(REDIS_KEY.GUILD_ACTIVE_RANK);
await initSingleRank(REDIS_KEY.GUILD_LV_RANK);
let curSeasonNum = await CounterModel.getCounter(COUNTER.PVP_SEASON_NUM);
// 发送肉鸽奖励
await repaireSendScoreReward();
console.log('————— settleGuildWeekly结束 —————');
}

View File

@@ -622,6 +622,10 @@ export function checkVoucherId(id: number) {
return id == voucher || id == voucherCoin;
}
export function getRougeTechScoreObject(count: number) {
return { id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.ROUGE_TECH)||0, count };
}
/**
* 返回 解锁头像/相框
* @param conditions 解锁条件

View File

@@ -0,0 +1,178 @@
import { Client } from './Client';
import 'mocha';
import { PinusWSClient } from 'pinus-robot-plugin';
import { expect } from 'chai';
import { checkBattleGoods, checkDisplayItems, checkSuccessResponse, checkTimeStamp, checkWarJson } from './CheckPatten';
import { DEBUG_MAGIC_WORD } from '../app/consts';
import { getRandSingleEelm } from './pureUtil';
import * as util from 'util';
const NORMAIL_BATTLEID = 101;
const DUNGEON_BATTLEID = 5001;
describe('稷下学宫测试', function () {
let pinusClient: PinusWSClient;
let roleInfo;
before(function (done) {
const c = new Client();
const timer = setInterval(() => {
if (c.client) {
pinusClient = c.client;
roleInfo = c.roleInfo;
clearInterval(timer);
done();
}
}, 500);
});
after(function (done) {
pinusClient.disconnect();
// disconnect 后等待 500ms供服务器清理环境、退出频道等
setTimeout(() => {
done();
}, 500);
});
// it('getData', function (done) {
// pinusClient.request('battle.rougeHandler.getData', {}, (res) => {
// console.log("res:", res)
// done();
// });
// });
// it('getGame', function (done) {
// pinusClient.request('battle.rougeHandler.getGame', {}, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
it('getInitCharaCard', function (done) {
pinusClient.request('battle.rougeHandler.getInitCharaCard', { type: 2, grade: 1 }, (res) => {
console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
done();
});
});
// it('startGame', function (done) {
// pinusClient.request('battle.rougeHandler.startGame', { gameCode: 'MkSLT1HY', authorType: 1 }, (res) => {
// done();
// });
// });
// it('chooseNode', function (done) {
// pinusClient.request('battle.rougeHandler.chooseNode', { gameCode: '4EPoEyML', layer: 2, detailCode: 'gREeb6Ku' }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('gameEnd', function (done) {
// pinusClient.request('battle.rougeHandler.gameEnd', { gameCode: 'voe64495' }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('shopBuy', function (done) {
// pinusClient.request('battle.rougeHandler.shopBuy', { gameCode: '5b8ioYN3', detailCode: '6ZhZYDXk', optionIndex: 1 }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('chooseReward', function (done) {
// pinusClient.request('battle.rougeHandler.chooseReward', { gameCode: '5b8ioYN3', detailCode: 'Jv5JEneT', groupIndex: 1, optionIndexs: [0] }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('checkBattle', function (done) {
// pinusClient.request('battle.rougeHandler.checkBattle', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku' ,warId:107, charaCodes:['D41jpqe6']}, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('battleEnd', function (done) {
// pinusClient.request('battle.rougeHandler.battleEnd', { gameCode: '5b8ioYN3', detailCode: 'pEu6Wetd', warId: 102, battleCode: 'R3FobvR2', status: 1, round: 5, rougeDamage: [{ charaCode: 'WaAhKQu6',hp:1, ap:1, shield:1 }] }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('nodeEnd', function (done) {
// pinusClient.request('battle.rougeHandler.nodeEnd', { gameCode: 'MkSLT1HY', detailCode: 'fve9s7ej' }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();``
// });
// });
// it('chooseOption', function (done) {
// pinusClient.request('battle.rougeHandler.chooseOption', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku', eventOptions:[1,4,10, 13] }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('trainCard', function (done) {
// pinusClient.request('battle.rougeHandler.trainCard', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku', cardCode:'GB4AtwlA' }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// it('recovery', function (done) {
// pinusClient.request('battle.rougeHandler.recovery', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku' }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// index: NumberInt("0"),
// cardCode: "ShNTcBGa",
// cardId: NumberInt("10003")
// it('putOnOrOffCard', function (done) {
// pinusClient.request('battle.rougeHandler.putOnOrOffCard', { gameCode: '4EPoEyML', charaCode: 'GLYk8Q1C', cards: [{ index: 0, cardCode: "", }] }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// for (let id = 20001; id <= 20034; id++) {
// it('debugAddCard', function (done) {
// pinusClient.request('battle.rougeHandler.debugAddCard', { tye: 3, id }, (res) => {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
// done();
// });
// });
// }
});

View File

@@ -29,8 +29,8 @@ export const CHANNEL_PREFIX = {
LEAGUE: 'league', // 联军
}
export const getChannelType = function(prefix: string) {
switch(prefix) {
export const getChannelType = function (prefix: string) {
switch (prefix) {
case CHANNEL_PREFIX.SYS:
return 1;
case CHANNEL_PREFIX.WORLD:
@@ -48,8 +48,8 @@ export const getChannelType = function(prefix: string) {
}
}
export const getSdkChannelId = function(prefix: string) {
switch(prefix) {
export const getSdkChannelId = function (prefix: string) {
switch (prefix) {
case CHANNEL_PREFIX.WORLD:
return 1;
case CHANNEL_PREFIX.GUILD:
@@ -194,7 +194,7 @@ export const PUSH_ROUTE = {
LEAGUE_DISSMISS: 'onLeagueDismiss', // 当联军解散
LEAGUE_ABDICATE: 'onLeagueAbdicate', // 当被转让盟主
LEAGUE_ITEM_UPDATE: 'onLeagueItemUpdate',
LEAGUE_TECH_CHANGE : 'onGVGTechChange', // 千机阁科技变更
LEAGUE_TECH_CHANGE: 'onGVGTechChange', // 千机阁科技变更
LEAGUE_TECH_UNLOCK: 'onGVGTechUnlock', // 千机阁科技解锁
LEAGUE_TECH_ACITVE: 'onGVGTechActive', // 千机阁科技激活
LEAGUE_TECH_ROLLBACK: 'onGVGTechRollback', // 千机阁科技回退
@@ -212,4 +212,7 @@ export const PUSH_ROUTE = {
GVG_NOTICE_UPDATE: 'onGVGNoticeUpdate', // 管理信息更新
PUBLIC_ACCOUNT_GIFT: 'onPublicAccountGift', // 公众号发送
GVG_REC_ADD: 'onGVGRecAdd', // 动态更新
ROUGE_COLLECT_UPDATE: 'onRougeCollectUpdate', // 更新图鉴
ROUGE_CHALLENGE_UPDATE: 'onRougeChallengeUpdate', //更新学宫挑战进度
}

View File

@@ -180,6 +180,7 @@ export const CURRENCY_TYPE = {
KING_EXP: 'kingExp',
VOUCHER: 'voucher',
VOUCHER_COIN: 'voucherCoin',
ROUGE_TECH: 'rougeTech',
}
const currencyArr = [
@@ -197,7 +198,8 @@ const currencyArr = [
{ "gid": 72021, "name": "天机骰子", "type": CURRENCY_TYPE.SPECIAL_DICE },
{ "gid": 72030, "name": "主公经验", "type": CURRENCY_TYPE.KING_EXP },
{ "gid": 81000, "name": "英杰券", "type": CURRENCY_TYPE.VOUCHER},
{ "gid": 81001, "name": "英杰币", "type": CURRENCY_TYPE.VOUCHER_COIN}
{ "gid": 81001, "name": "英杰币", "type": CURRENCY_TYPE.VOUCHER_COIN},
{ "gid": 40022, "name": "科技点", "type": CURRENCY_TYPE.ROUGE_TECH },
];
export const CURRENCY = new Map<number, { gid: number, name: string, type: string }>();

View File

@@ -76,6 +76,7 @@ export enum MAIL_TYPE {
ARTIFACT_OVER = 46, // 宝物数量超过
GVG_BATTLE_PLAYER_SETTLE_RANK_REWARD = 47, // 激战期个人占领排行榜奖励
REPAIRE_SIGN_IN = 48, // 高级签到补发奖励
ROUGE_SCORE_REPAIRE = 49, // 补发肉鸽每周奖励
};
export const SEND_NAME = '系统';

View File

@@ -0,0 +1,127 @@
// 肉鸽相关
export enum ROUGE_LIKE_STATUS {
CHOOSECHARA = 0,//选角色卡
INPROGRESS = 1, // 进行中
SUCCESS = 2, // 达成
}
export enum ROUGE_CHARA_INITIAL {
NOT = 0, // 不能被随机
CAN = 1, // 能被随机
}
export enum ROUGE_CHARA_TYPE {
ORDINARY = 1, // 普通
HIGH = 2, // 高级
}
export enum ROUGE_LIKE_CARD_TYPE {
CHARA = 1, //角色卡
PASSIVE = 2, //特性卡
HOLY = 3, //圣物
// SKILL = 4, //技能卡
// PASSON = 5, //传人卡
// EVENT = 6, //事件
// // COIN = 4, //试炼币
}
export enum COLLECTION_TYPE {
PASSIVE_CARD_SUM = 0,
PASSIVE_CARD = 1,
HOLY_CARD = 2,
SKILL_CARD = 3,
EVENT = 4,
}
export enum ROUGE_LIKE_DETAIL_STATUS {
CHOOSE = 1, //已选择
GET = 2, //已获得
GET_REWARD = 3, //已领奖
}
export enum ROUGE_LIKE_CHOOSE_REWARD {
NOCHOOSE = 0, //未选择
CHOOSE = 1, //选择
}
export enum ROUGE_LIKE_NODE_STATUS {
FAIL = 0, // 失败
SUCCESS = 1, //成功
}
export enum ROUGE_LIKE_NODE_TYPE {
ORDINARY = 1, // 普通关
ELITE = 2, // 精英关
CHALLENGE = 3, // 挑战关
SHOP = 4, // 试炼商店
REST_POINT = 5, // 休整点
QUEST_POINT = 6, // 问号点
BOSS = 7, // boss关
EVENT = 8, //事件
}
export enum REST_POINT_TYPE {
RECOVERY = 1, //恢复
RECURIT = 2, //招募
TRAIN = 3, //强化
}
export enum ROUGELIKE_SKILLTYPE {
AP = 1, //怒气
ROUND = 2, //回合
}
export enum ROUGE_EFFECT_TYPE {
CHALLENGE_ENEMY_MAIN_ATTR_UP = 1001, // 接下来X场战斗敌军属性id提高num
CHALLENGE_ENEMY_SUB_ATTR_UP = 1002, // 接下来X场战斗敌军属性id提高num
CHALLENGE_CHARA_MAIN_ATTR_DOWN = 1003, // 接下来X场战斗我军学员属性id降低num
CHALLENGE_CHARA_SUB_ATTR_DOWN = 1004, // 接下来X场战斗我军学员属性id降低num
CHALLENGE_CHARA_HP_LIMIT = 1005, // 接下来X场战斗战斗结束后我军学员生命不低于num
CHALLENGE_CHARA_NO_AP_SKILL = 1006, // 接下来X场战斗战斗过程中我军学员无法使用怒气技
CHALLENGE_CHARA_NO_ROUND_SKILL = 1007, // 接下来X场战斗战斗过程中我军学员无法使用回合技
CHALLENGE_PASSIVE_CARD_REDUCE = 1008, // 接下来X次选择特性卡时可选择的卡片数量少1
CHALLENGE_CHARA_NUM_LIMIT = 1009, // 接下来X场战斗每场战斗只能上阵2名学员
HOLY_CHARA_HP_RECOVERY_UP = 2001, // 每场战斗结束后学员恢复血量上限X%的生命
HOLY_CHARA_SLOT_UNLOCK_ALL = 2002, // 获得该圣物时所有学员立刻解锁X个特性槽
HOLY_CHARA_SLOT_UNLOCK_RAND = 2003, // 获得该圣物时随机解锁X个学员的Y个特性槽
HOLY_COIN_UP = 2004, // 战斗胜利后获得的试炼币增加X
HOLY_CHARA_MAIN_ATTR_UP_BY_COIN = 2005, // 每累积X个试炼币全员基础属性id提高Y
HOLY_PASSIVE_UPDATE_RAND = 2006, // 随机升级X个已装备的特性
HOLY_PASSIVE_WEIGHT_UP_BY_AUTHOR = 2007, // 获得圣物时X流派特性卡的权重增加Y
HOLY_ENEMY_MAIN_ATTR_DOWN = 2008, // 进入战斗后所有敌军扣减X的某基础属性id
HOLY_REVIVE_ALL = 2009, // 非首领敌人战斗失败视为胜利,并且满血复活
HOLY_REVIVE_CHARA_RAND = 2010, // 战斗胜利后若有学员死亡则满血复活X名死亡学员
HOLY_SHOP_DISCOUNT = 2011, // 试炼商店中所有商品X折出售
HOLY_UPDATE_PASSIVE_BY_LV = 2012, // 获得该圣物时立即升级所有X星特性卡
HOLY_PASSIVE_CHOOSE_FIX = 2013, // 下次选择特性卡时必定出现X星特性卡
HOLY_PASSIVE_CHOOSE_NUM_UP = 2014, // 下次选择特性卡时可多选X张特性卡
HOLY_REPAIRE_HOLY = 2015, // 获得该圣物后随机修复X个已损毁的圣物
// HOLY_RESET_PASSIVE = 2016, // 获得该圣物后随机重置X个已装配的特性卡
HOLY_RECOVERY_POINT_UP = 2017, // 休整点额外恢复X%的生命
HOLY_TRAIN_POINT_DISCOUNT = 2018, // 休整点特训价格X折
HOLY_CHARA_SUB_ATTR_UP_BY_COIN = 2019, // 每累积X个试炼币全员次级属性id提高Y
HOLY_CHARA_MAIN_ATTR_UP = 2020, // 基础属性提升
HOLY_CHARA_SUB_ATTR_UP = 2021, // 次级属性提升
HOLY_CHARA_ATTR_UP_BY_ROUND = 2022, // 每场战斗第X回合后全员属性id提高Y
HOLY_CHARA_SLOT_UNLOCK_POINT = 2023, // 获得该圣物后所有角色解锁X号位置的特性槽
TECH_CHARA_MAIN_ATTR_UP = 3001, // 基础属性提升
TECH_CHARA_SUB_ATTR_UP = 3002, // 次级属性提升
TECH_INIT_HOLY_BY_AUTHOR = 3003, // 选择百家流派后获得1个流派专属圣物XX圣物池
TECH_CAN_CHOOSE_SKILL_CARD = 3004, // 装备X个同百家流派特性的角色可额外选择流派专属Y技能类型
TECH_INIT_COIN = 3005, // 初始获得X个试炼币
TECH_RECOVERY_POINT_UP = 3006, // 休整点恢复额外恢复血量上限X%的生命
TECH_COIN_UP_BY_NODE_TYPE = 3007, // 某些nodeType后获得的试炼币增加X%
TECH_PASSIVE_RANDOM_AGAIN = 3008, // 选择特性卡时可消耗X试炼币重置Y次
TECH_TRAIN_POINT_DISCOUNT = 3009, // 休整点特训价格降低X%
TECH_BOSS_ANGER_MAX = 3010, // 挑战boss关前所有角色怒气值充满
TECH_BOSS_HP_MAX = 3011, // 挑战boss关前所有角色生命恢复至100%
}
export enum ROUGE_EFFECT_TYPE_KIND {
CHALLENGE = 1, // 挑战
HOLY = 2, // 圣物特效
TECH = 3, // 法阵特性
}

View File

@@ -32,6 +32,8 @@ export const CHECT_BATTLE_TYPE_HIDE = 202; // 隐藏武将
export const ITID_STONE_LIMIT = 6; //玉石一键合成等级限制
export const ROUGE_SLOT_LIMIT = 5;//rouge卡槽数量
export enum TIME_OUTPUT_TYPE {
DATE = 1,
STAMP_10 = 2,
@@ -64,6 +66,7 @@ export const COUNTER = {
HIDDEN_DATA: { name: 'hiddendata', def: 1 },
ARTIFACT_ID: { name: 'artid', def: 1 },
GVG_CONFIG: { name: 'gvg', def: 1 },
ROUGE_CHARA: { name: 'rougeChara', def: 1 },
};
export const DEFAULT_HEROES = [19, 53,];
@@ -654,6 +657,39 @@ export const FILENAME = {
DIC_AUTHORS_BOOK_SUB: 'dic_zyz_authorsBookSub',
DIC_AUTHORS_GOODID: 'dic_zyz_authorsGoodId',
DIC_BOSS_RANK_ACTIVE_POINT: 'dic_zyz_bossRank_activePoint',
// DIC_ROUGE_TYPE: "dic_rougeType", 暂时用不到
DIC_ROUGE_AUTHOR_TYPE: "dic_rougeAuthorType",
DIC_ROUGE_TYPE_GRADE: "dic_rougeType_grade",
DIC_ROUGE_LAYER_PLAN: "dic_rougeLayer_plan",
DIC_SPIRIT_PLAN: "dic_spiritPlan",
DIC_ROUGE_LAYER_NODE_NUM_PLAN: "dic_rougeLayer_nodeNumPlan",
DIC_ROUGE_LAYER_NODE_PLAN: "dic_rougeLayer_nodePlan",
DIC_ROUGE_NODE: "dic_rougeNode",
DIC_ROUGE_LAYER_REWARD_PLAN: "dic_rougeLayer_rewardPlan",
DIC_ROUGE_SHOP_PLAN: "dic_rougeShopPlan",
DIC_ROUGE_CHARA: "dic_rougeChara",
DIC_ROUGE_PASSIVE_CARD: "dic_rougePassiveCard",
DIC_ROUGE_PASSIVE_COLLECT: "dic_rougePassiveCollect",
DIC_ROUGE_SKILL_CARD: "dic_rougeSkillCard",
DIC_ROUGE_HOLY_CARD: "dic_rougeHolyCard",
DIC_ROUGE_CHARA_CARD_PLAN: "dic_rougeChara_cardPlan",
DIC_ROUGE_PASSIVE_CARD_PLAN: "dic_rougePassive_cardPlan",
DIC_ROUGE_HOLY_CARD_PLAN: "dic_rougeHoly_cardPlan",
DIC_ROUGE_CHALLANGE: "dic_rougeChallenge",
DIC_ROUGE_CHALLANGE_PLAN: "dic_rougeChallengePlan",
DIC_ROUGE_QUESTION_MARK_PLAN: "dic_rougeQuestionMarkPlan",
DIC_ROUGE_RANDOM_EVENT_PLAN: "dic_rougeRandomEventPlan",
DIC_ROUGE_EVENT_OPTION: "dic_rougeEventOption",
DIC_ROUGE_OPTION_GROUP: "dic_rougeOptionGroup",
DIC_GK_ROUGE: "dic_zyz_gk_rouge",
DIC_ROUGE_SCORE_REWARD: "dic_rougeScoreReward",
DIC_ROUGE_EFFECT: "dic_rougeEffect",
DIC_ROUGE_EFFECT_TYPE: "dic_rougeEffectType",
DIC_ROUGE_TECH: "dic_rougeTech",
DIC_ROUGE_TECH_CIRCLE: "dic_rougeTechCircle",
DIC_ROUGE_TECH_LEVEL: "dic_rougeTechLevel",
}
export const WAR_RELATE_TABLES = [
@@ -679,6 +715,7 @@ export const WAR_RELATE_TABLES = [
FILENAME.DIC_GK_BRANCH_ELITE,
FILENAME.DIC_GK_GVG_VESTIGE,
FILENAME.DIC_GK_GVGBATTLE,
FILENAME.DIC_GK_ROUGE,
]
// 装备栏强化类型
@@ -1211,6 +1248,12 @@ export enum ITEM_CHANGE_REASON {
QIXI_REWARD = 195, // 七夕活动奖励
MID_AUTUMN_REWARD = 196, // 中秋活动奖励
AUTHOR_GACHA_REWARD = 197, // 百家争鸣祈灵奖励
ROUGE_TAKE_OUT_REWARD = 198, // 肉鸽外带奖励
ROUGE_TECH_SCORE = 199, // 肉鸽科技点结算
ROUGE_UNLOCK_TECH = 200, // 肉鸽解锁科技点
ROUGE_FIRST_REWARD = 201, // 肉鸽首通奖励
RECEIVE_COLLECT_REWARD = 202, // 领取图鉴奖励
RECEIVE_ROUGE_SCORE_REWARD = 203, // 领取积分奖励
}
export enum TA_EVENT {

View File

@@ -11,5 +11,6 @@ export * from './constModules/httpConst';
export * from './constModules/auctionConst';
export * from './constModules/mailConst';
export * from './constModules/gvgConst';
export * from './constModules/rougeConst';
export * from './statusCode';
export * from './dataName';

View File

@@ -21,13 +21,13 @@ export const STATUS = {
DUPLICATE_ACCESS: { code: 16, simStr: '随机请求参数重复' },
ADDRESS_ERR: { code: 17, simStr: '您的版本已停止支持,请前往应用商店下载最新安装包' },
GLOBAL_ERR: { code: 1003, simStr: '刷新服务器数据错误,请尝试重新登录或联系客服' },
UPDATE_INFO_ERR: {code: 1004, simStr: '热更新配置错误'},
DEBUG_FUNCTION_ERR: {code: 1005, simStr: '功能逻辑已改debug接口不再提供'},
DEVELOP_ONLY: {code: 1006, simStr: '只有测试环境才可以使用该接口'},
PACKAGE_NOT_FOUND: {code: 1007, simStr: '您的版本未被支持,请前往应用商店重新下载或联系客服解决'},
REGION_NOT_FOUND: {code: 1008, simStr: '未找到此版本对应区服'},
PACKAGE_CREATE_FAILED: {code: 1009, simStr: '创建子包失败'},
PACKAGE_UPDATE_FAILED: {code: 1010, simStr: '更新子包失败'},
UPDATE_INFO_ERR: { code: 1004, simStr: '热更新配置错误' },
DEBUG_FUNCTION_ERR: { code: 1005, simStr: '功能逻辑已改debug接口不再提供' },
DEVELOP_ONLY: { code: 1006, simStr: '只有测试环境才可以使用该接口' },
PACKAGE_NOT_FOUND: { code: 1007, simStr: '您的版本未被支持,请前往应用商店重新下载或联系客服解决' },
REGION_NOT_FOUND: { code: 1008, simStr: '未找到此版本对应区服' },
PACKAGE_CREATE_FAILED: { code: 1009, simStr: '创建子包失败' },
PACKAGE_UPDATE_FAILED: { code: 1010, simStr: '更新子包失败' },
// http请求
REQUEST_TIME_OUT: { code: 2000, simStr: '请求超时' },
@@ -69,10 +69,10 @@ export const STATUS = {
BATTLE_END_WRONG_TYPE: { code: 20008, simStr: '此类型无法使用通用结算' },
BATTLE_GOLD_NOT_ENOUGH: { code: 20009, simStr: '元宝不足' },
BATTLE_REGRET_MAX: { code: 20010, simStr: '悔棋步数达上限' },
BATTLE_NOT_FOUND: { code: 20011, simStr: '未找到对应关卡'},
BATTLE_RPL_UPDATE_ERR: { code: 20012, simStr: '录像状态更新失败'},
BATTLE_RPL_NOT_SUPPORT: { code: 20013, simStr: '暂不支持保存此类战斗的录像'},
BATTLE_CHECK_REC_SAVE_ERR: { code: 20014, simStr: '战斗检测记录保存错误'},
BATTLE_NOT_FOUND: { code: 20011, simStr: '未找到对应关卡' },
BATTLE_RPL_UPDATE_ERR: { code: 20012, simStr: '录像状态更新失败' },
BATTLE_RPL_NOT_SUPPORT: { code: 20013, simStr: '暂不支持保存此类战斗的录像' },
BATTLE_CHECK_REC_SAVE_ERR: { code: 20014, simStr: '战斗检测记录保存错误' },
// 主线 20100 - 20199
BATTLE_INFO_VALIDATE_ERR: { code: 20101, simStr: '关卡信息不同' },
@@ -165,7 +165,7 @@ export const STATUS = {
COM_BATTLE_HEROES_ERR: { code: 20629, simStr: '阵容异常' },
COM_BATTLE_SET_FRD_ERR: { code: 20630, simStr: '设置情谊助战异常' },
COM_BATTLE_BLACKLIST: { code: 20633, simStr: '队伍中存在黑名单玩家' },
COM_BATTLE_BE_KICKED: { code: 20634, simStr: '您已被队伍踢出,无法加入'},
COM_BATTLE_BE_KICKED: { code: 20634, simStr: '您已被队伍踢出,无法加入' },
COM_BATTLE_CREATE_CE_LIMIT: { code: 20635, simStr: '你的战力不足,不可设置该级别限制' },
COM_BATTLE_TEAM_NOT_DEFAULT: { code: 20636, simStr: '队伍已过期' },
COM_BATTLE_IS_RUNNING: { code: 20637, simStr: '您有队伍正在进行中' },
@@ -610,7 +610,7 @@ export const STATUS = {
GIFT_CODE_CHANNEL_ERR: { code: 31206, simStr: '礼包码在您的渠道不生效' },
GIFT_TYPE_ERR: { code: 31207, simStr: '该礼包码不可在此界面使用' },
// 邮件相关 31301-31400
MAIL_HAS_RECEIVE: { code: 31301, simStr: '邮件已领取'},
MAIL_HAS_RECEIVE: { code: 31301, simStr: '邮件已领取' },
EQUIP_IS_OVER: { code: 31302, simStr: '装备已超过上限,无法领取' },
// 道具相关
ITEM_CANNOT_RECEIVE_NO_GUILD: { code: 31401, simStr: '您没有加入军团,不可使用该道具' },
@@ -660,7 +660,7 @@ export const STATUS = {
ACTIVITY_ITEM_CANNOT_RECEIVE: { code: 50036, simStr: '无可领取物品' },
ACTIVITY_POP_UP_MUST_BUY: { code: 50037, simStr: '该礼包必须购买' },
DAILY_COIN_BOX_NOT_FOUND: { code: 50038, simStr: '未找到该宝箱' },
DAILY_COIN_BOX_CANNOT_RECEIVE: {code: 50013, simStr: '该宝箱不可领取' },
DAILY_COIN_BOX_CANNOT_RECEIVE: { code: 50013, simStr: '该宝箱不可领取' },
ACTIVITY_GROUP_SHOP_BUY_CNT_MAX: { code: 50039, simStr: '购买次数超过最大值' },
ACTIVITY_GROUP_SHOP_ITEM_NOT_FOUND: { code: 50040, simStr: '未找到该商品' },
@@ -763,7 +763,46 @@ export const STATUS = {
ORDER_CANNOT_BUY: { code: 70016, simStr: '该礼包不可购买' },
VOUCHER_NOT_ENOUGH: { code: 70017, simStr: '代金券不足' },
ORDER_STATUS_ERROR: { code: 70018, simStr: '订单状态错误' },
PAY_NOT_OPEN: { code: 70019, simStr: '支付功能暂未开启' }
PAY_NOT_OPEN: { code: 70019, simStr: '支付功能暂未开启' },
// 稷下学宫 相关状态 80000 - 89999
SHOP_NO_BUY: { code: 80001, simStr: '商店不可购买' },
COIN_NOT_ENOUGH: { code: 80002, simStr: '试炼币不足' },
REWARD_NO_CHOOSE: { code: 80003, simStr: '奖励不可选择' },
NO_CARD: { code: 80004, simStr: '卡不存在' },
SLOT_UNLOCK: { code: 80005, simStr: '卡槽未解锁' },
NO_PASSIVE: { code: 80006, simStr: '非特性卡不能安装' },
ROUGELIKE_GAME_PLAYING: { code: 80007, simStr: '有一场试炼正在进行中' },
NO_TYPE_GRADE: { code: 80008, simStr: '不存在这样的试炼' },
LIMIT_LV: { code: 80008, simStr: '未达到等级限制' },
NO_ROUGELIKE_GAME: { code: 80009, simStr: '该场游戏无效' },
ROUGELIKE_GAME_END: { code: 80010, simStr: '该场游戏已结束' },
NODE_NO_CHOOSE: { code: 80011, simStr: '该节点不可选择' },
NO_AUTHOR_TYPE: { code: 80012, simStr: '流派不存在' },
TYPE_UNLOCK: { code: 80013, simStr: '试炼未解锁' },
WAR_NO_CHOOSE: { code: 80014, simStr: '该关卡不可选择' },
NO_EXIT_NODE: { code: 80015, simStr: '该节点不存在' },
NODE_NO_END: { code: 80016, simStr: '该节点不能直接完成' },
HIGH_LV: { code: 80017, simStr: '已达到最高等级, 无法强化等级' },
BATTLE_ABNORMAL: { code: 80018, simStr: '战斗异常' },
NO_TIME_RECOVERY: { code: 80019, simStr: '没有回复次数' },
ROUGE_PASSIVE_CARD_NOT_ENOUGH: { code: 80020, simStr: '装备的特性卡不足' },
ROUGELIKE_TAKEOUT_HAS_RECEIVED: { code: 80021, simStr: '外带奖励已领取' },
ROUGELIKE_TAKEOUT_CNT_NOT_ENOUGH: { code: 80022, simStr: '本周外带次数不足' },
BATTLE_ABNORMAL_CHARA: { code: 80023, simStr: '上阵学员数量异常' },
ROUGE_RE_RANDOM_CNT_OVER: { code: 80024, simStr: '已重新随机过' },
ROUGE_TECH_SCORE_NOT_ENOUGH: { code: 80101, simStr: '科技点不足' },
ROUGE_TECH_HAS_UNLOCKED: { code: 80102, simStr: '科技点已解锁' },
ROUGE_TECH_PRE_NOT_UNLOCKED: { code: 80103, simStr: '前置节点未解锁' },
ROUGE_CIRCLE_NOT_UNLOCK: { code: 80104, simStr: '对应科技点未解锁' },
ROUGE_COLLECT_HAS_RECEIVED: { code: 80105, simStr: '该图鉴奖励已领取' },
ROUGE_SCORE_NOT_ENOUGH: { code: 80106, simStr: '积分不足' },
ROUGE_SCORE_HAS_RECEIVED: { code: 80107, simStr: '已领取' },
ROUGE_COLLECT_NOT_ENOUGH: { code: 80108, simStr: '该图鉴条件未达成' },
ROUGE_TECH_NOT_UNLOCKED: { code: 80109, simStr: '对应科技点未解锁' },
}
export const PAY_37_CALLBACK_CODE = {

View File

@@ -1,6 +1,7 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { LineupParam } from '../domain/rank';
import { Card } from './RougelikeChara';
/**
* 战斗记录接口
@@ -17,6 +18,31 @@ class DamageRecord {
underDamage: number;
}
class RougeCharaRecord {
@prop({ required: false, default: '' })
charaCode?: string; // 角色卡id
@prop({ required: false, default: 0 })
charaId?: number; // 角色卡id
@prop({ required: false, type: Card, default: [] })
cards?: Card[];
@prop({ required: false, default: 0 })
hp?: number; // 当前hp
@prop({ required: false, default: 0 })
ap?: number; // 当前怒气
@prop({ required: false, default: 0 })
roundSkill?: number; // 玩家选择的回合技能卡
@prop({ required: false, default: 0 })
apSkill?: number; // 玩家选择的怒气技能卡
@prop({ required: false, default: 0 })
shield?: number
@prop({ required: false })
damage?: number;
@prop({ required: false })
heal?: number;
@prop({ required: false })
underDamage?: number;
}
class Record {
@prop({ required: true, type: Number })
heroes?: Array<number>; // 武将id
@@ -29,11 +55,11 @@ class Record {
@prop({ required: false })
pos?: number; // pvp位置
@prop({ required: false })
trainId?:number;
trainId?: number;
@prop({ required: false })
trainLv?:number;
trainLv?: number;
@prop({ required: false })
hid?:number;
hid?: number;
@prop({ required: false })
guildCode?: string;
@prop({ required: false })
@@ -53,6 +79,11 @@ class Record {
damageRecord?: DamageRecord[];
@prop({ required: false })
round?: number;
@prop({ required: false, type: RougeCharaRecord })
rougeOriginal?: RougeCharaRecord[];
@prop({ required: false, type: RougeCharaRecord })
rougeDamage?: RougeCharaRecord[];
}
@index({ roleId: 1, battleId: 1 })
@@ -107,13 +138,14 @@ export default class BattleRecord extends BaseModel {
return result;
}
public static async deleteAccount(roleId: string) {
let result = await BattleRecordModel.deleteMany({ roleId });
return result || {};
}
public static async incBossDamage(battleCode: string, damage: number, bossHp: number) {
if(bossHp < 0) { // 最后一击,被扣到负了
if (bossHp < 0) { // 最后一击,被扣到负了
damage += bossHp;
}
let result: BattleRecordType = await BattleRecordModel.findOneAndUpdate({ battleCode }, { $inc: { 'record.bossDamage': damage } }, { new: true }).lean();

View File

@@ -22,6 +22,15 @@ export default class Counter extends BaseModel {
return counter?.seq;
}
public static async getNewCounterNum(param:{name: string, def: number}, inc = 1) {
let {name, def:defaultVal} = param;
let counter: CounterType = await CounterModel.findOneAndUpdate({ name }, { $inc: { seq: inc } }, { new: true, upsert: true }).lean();
if(!counter || (counter&&counter.seq == 1) && defaultVal != 1) {
counter = await CounterModel.findOneAndUpdate({ name }, { $set: { seq: defaultVal } }, { new: true, upsert: true }).lean();
}
return counter?.seq;
}
public static async getCounter(param:{name: string, def: number}, lean = true) {
let {name} = param;
let counter: CounterType = await CounterModel.findOne({ name }).lean(lean);

View File

@@ -0,0 +1,89 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
/**
* 每场获得的圣物&特性卡
*/
@index({ roleId: 1 })
@index({ gameCode: 1 })
@index({ gameCode: 1, cardCode: 1 })
@index({ gameCode: 1, type: 1 })
export default class RougelikeCard extends BaseModel {
@prop({ required: true })
roleId: string; // 角色id
@prop({ required: true, default: '' })
gameCode: string; // 场次唯一code
@prop({ required: true, default: '' })
cardCode: string; // 卡唯一code
@prop({ required: true, default: 0 })
cardId: number; // 卡id
@prop({ required: true, default: 0 })
type: number; // 卡类型
@prop({ required: true, default: 0 })
charaId: number; // 装备在哪个角色上没有装备为0
@prop({ required: true, default: 0 })
lv: number; // 特性卡的等级
@prop({ required: true, default: 0 })
getLayer: number; // 在哪一层获得的
@prop({ required: true, default: 0 })
getWay: number; // 在做什么的时候获得的
@prop({ required: true, default: 0 })
useCount?: number // 可使用次数
public static async updateByCode(gameCode: string, cardCode: string, params: { $set?: RougelikeCardPara, $inc?: { lv?: number } }, lean = true) {
const result: RougelikeCardType = await RougelikeCardModel.findOneAndUpdate({ gameCode, cardCode }, params, { new: true, upsert: true }).lean(lean);
return result;
}
public static async findByGameCode(gameCode: string, lean = true) {
const result: RougelikeCardType[] = await RougelikeCardModel.find({ gameCode }).lean(lean);
return result;
}
public static async findByCode(gameCode: string, cardCode: string, lean = true) {
const result: RougelikeCardType = await RougelikeCardModel.findOne({ gameCode, cardCode }).lean(lean);
return result;
}
public static async findByGameCodeAndType(gameCode: string, type: number, lean = true) {
const result: RougelikeCardType[] = await RougelikeCardModel.find({ gameCode, type: { $eq: type }, }).lean(lean);
return result;
}
public static async findByGameCodeAndCardCodes(gameCode: string, cardCodes: string[], lean = true) {
const result: RougelikeCardType[] = await RougelikeCardModel.find({ gameCode, cardCode: { $in: cardCodes } }).lean(lean);
return result;
}
// public static async bulkWriteUpdate(updateArr: { gameCode: string, cardCode: string, charaId: number }[]) {
// if (updateArr.length == 0) return;
// await RougelikeCardModel.bulkWrite(updateArr.map(({ gameCode, cardCode, charaId }) => {
// return { updateOne: { filter: { gameCode, cardCode }, update: { $set: { charaId } }, upsert: true } }
// }))
// }
public static async bulkWriteUpdate(updateArr: RougelikeCardPara[]) {
if (updateArr.length == 0) return;
await RougelikeCardModel.bulkWrite(updateArr.map((param) => {
const { gameCode, cardCode } = param
return { updateOne: { filter: { gameCode, cardCode }, update: { $set: { ...param } }, upsert: true } }
}))
}
};
export const RougelikeCardModel = getModelForClass(RougelikeCard);
export interface RougelikeCardType extends Pick<DocumentType<RougelikeCard>, keyof RougelikeCard> { };
export type RougelikeCardPara = Partial<RougelikeCardType>; // 将所有字段变成可选项

126
shared/db/RougelikeChara.ts Normal file
View File

@@ -0,0 +1,126 @@
import { COUNTER, ROUGELIKE_SKILLTYPE } from '../consts';
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
import { CounterModel } from './Counter';
export class Card {
@prop({ required: false })
index: number; // 卡槽没有那个index表示没有解锁
@prop({ required: false })
cardCode: string; //卡唯一code,为空串表示没安装
@prop({ required: false })
cardId: number; // 当为0的时候表示没有装入卡片
}
/**
* 每场获得角色(普通角色和高级角色)
*/
@index({ roleId: 1 })
@index({ gameCode: 1 })
@index({ gameCode: 1, charaCode: 1 })
export default class RougelikeChara extends BaseModel {
@prop({ required: true })
roleId: string; // 角色id
@prop({ required: true, default: '' })
gameCode: string; // 场次唯一code
@prop({ required: true, default: 0 })
seqId: number; // 角色卡排序
@prop({ required: true, default: '' })
charaCode: string; // 角色卡唯一id
@prop({ required: true, default: 0 })
charaId: number; // 角色卡id
@prop({ required: true, type: Card, default: [] })
cards: Card[];
@prop({ required: true, default: 0 })
hp: number; // 当前hp
@prop({ required: true, default: 0 })
maxHp: number; // 最大hp
@prop({ required: true, default: 0 })
ap: number; // 当前怒气
@prop({ required: true, default: 0 })
shield: number; // 盾
@prop({ required: true, default: 0 })
roundSkill: number; // 玩家选择的回合技能卡
@prop({ required: true, default: 0 })
apSkill: number; // 玩家选择的怒气技能卡
@prop({ required: true, default: 0 })
getLayer: number; // 在哪一层获得的
@prop({ required: true, default: 0 })
getWay: number; // 在做什么的时候获得的
public static async createCharas(updateArr: RougelikeCharaPara[]) {
if (updateArr.length == 0) return [];
let num = await CounterModel.getNewCounterNum(COUNTER.ROUGE_CHARA, updateArr.length);
let resultArr: RougelikeCharaType[] = [];
for(let index = 0; index < updateArr.length; index++) {
let param = updateArr[index];
let seqId = num - updateArr.length + index + 1;
const { gameCode, charaCode } = param;
let data = await RougelikeCharaModel.findOneAndUpdate({ gameCode, charaCode }, { $set: { ...param, seqId }}, { new: true, upsert: true }).lean();
if(data) resultArr.push(data)
}
return resultArr
}
public static async updateByCode(gameCode: string, charaCode: string, params: { $set: RougelikeCharaPara }, lean = true) {
const result: RougelikeCharaType = await RougelikeCharaModel.findOneAndUpdate({ gameCode, charaCode }, params, { new: true }).lean(lean);
return result;
}
public static async findByGameCode(gameCode: string, lean = true) {
const result: RougelikeCharaType[] = await RougelikeCharaModel.find({ gameCode }).lean(lean);
return result;
}
public static async findByCode(gameCode: string, charaCode: string, lean = true) {
const result: RougelikeCharaType = await RougelikeCharaModel.findOne({ gameCode, charaCode }).lean(lean);
return result;
}
public static async findByCodes(gameCode: string, charaCodes: string[], lean = true) {
const result: RougelikeCharaType[] = await RougelikeCharaModel.find({ gameCode, charaCode: { $in: charaCodes } }).lean(lean);
return result;
}
public static async putOnOrOffSkillCard(gameCode: string, charaCode: string, skillType: ROUGELIKE_SKILLTYPE, id: number) {
if (skillType == ROUGELIKE_SKILLTYPE.AP) {
const result: RougelikeCharaType = await RougelikeCharaModel.findOneAndUpdate({ gameCode, charaCode }, { $set: { apSkill: id } }, { new: true }).lean();
return result;
} else {
const result: RougelikeCharaType = await RougelikeCharaModel.findOneAndUpdate({ gameCode, charaCode }, { $set: { roundSkill: id } }, { new: true }).lean();
return result;
}
}
public static async bulkWriteUpdate(updateArr: RougelikeCharaPara[]) {
if (updateArr.length == 0) return;
await RougelikeCharaModel.bulkWrite(updateArr.map((param) => {
delete param._id;
const { gameCode, charaCode } = param
return { updateOne: { filter: { gameCode, charaCode }, update: { $set: { ...param } } } }
}))
}
};
export const RougelikeCharaModel = getModelForClass(RougelikeChara);
export interface RougelikeCharaType extends Pick<DocumentType<RougelikeChara>, keyof RougelikeChara> { };
export type RougelikeCharaPara = Partial<RougelikeCharaType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,54 @@
import { COLLECTION_TYPE } from '../consts';
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
@index({ roleId: 1, type: 1, id: 1 })
export default class RougelikeCollection extends BaseModel {
@prop({ required: true })
roleId: string;
@prop({ required: true, default: 0 })
type: number;
@prop({ required: true, default: 0 })
id: number;
@prop({ required: true, default: 0 })
num: number;
@prop({ required: true, default: '' })
gameCode: string;
@prop({ required: true, type: Number, default: false })
received: number[]; // 是否领取奖励
public static async addRec(roleId: string, type: number, id: number, gameCode: string, addNum = 1) {
const result: RougelikeCollectionType = await RougelikeCollectionModel.findOneAndUpdate({ roleId, type, id }, { $setOnInsert: { received: [] }, $inc: { num: addNum }, $set: { gameCode } }, { new: true, upsert: true }).lean();
return result;
}
public static async findByRoleId(roleId: string, lean = true) {
const result: RougelikeCollectionType[] = await RougelikeCollectionModel.find({ roleId }).lean(lean);
return result;
}
public static async findByRoleAndId(roleId: string, type: number, id: number) {
const result: RougelikeCollectionType = await RougelikeCollectionModel.findOne({ roleId, type, id: type == COLLECTION_TYPE.PASSIVE_CARD_SUM? 0: id }).lean();
return result;
}
public static async receive(roleId: string, type: number, id: number, num = 1) {
if(type == COLLECTION_TYPE.PASSIVE_CARD_SUM) {
const result: RougelikeCollectionType = await RougelikeCollectionModel.findOneAndUpdate({ roleId, type, id: 0, num: { $gte: num } }, { $push: { received: id } }, { new: true }).lean();
return result;
} else {
const result: RougelikeCollectionType = await RougelikeCollectionModel.findOneAndUpdate({ roleId, type, id }, { $push: { received: id } }, { new: true }).lean();
return result;
}
}
}
export const RougelikeCollectionModel = getModelForClass(RougelikeCollection);
export interface RougelikeCollectionType extends Pick<DocumentType<RougelikeCollection>, keyof RougelikeCollection> { };
export type RougelikeCollectionPara = Partial<RougelikeCollectionType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,50 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
@index({ roleId: 1, limitId: 1 })
export class RewardInter {
@prop({ required: true })
id: number;
@prop({ required: true })
count: number;
@prop({ required: true })
expireTime?: number;
}
export default class RougelikeExtend extends BaseModel {
@prop({ required: true })
roleId: string;
@prop({ required: true, default: 0 })
limitId: number; // 前置试炼id,只会是已通关
@prop({ required: true, type: RewardInter, default: 0 })
firstReward: RewardInter[]; //首通奖励
@prop({ required: true, default: '' })
gameCode: string;
public static async update(roleId: string, limitId: number, firstReward: RewardInter[], gameCode: string, lean = true) {
const result: RougelikeExtendType = await RougelikeExtendModel.findOneAndUpdate({ roleId, limitId }, { firstReward, gameCode }, { new: true, upsert: true }).lean(lean);
return result;
}
public static async findByRoleId(roleId: string, lean = true) {
const result: RougelikeExtendType[] = await RougelikeExtendModel.find({ roleId }).lean(lean);
return result;
}
public static async findByRoleIdAndLimitId(roleId: string, limitId: number, lean = true) {
const result: RougelikeExtendType = await RougelikeExtendModel.findOne({ roleId, limitId }).lean(lean);
return result;
}
}
export const RougelikeExtendModel = getModelForClass(RougelikeExtend);
export interface RougelikeExtendType extends Pick<DocumentType<RougelikeExtend>, keyof RougelikeExtend> { };
export type RougelikeExtendPara = Partial<RougelikeExtendType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,91 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
export class Node {
@prop({ required: true, default: '' })
detailCode: string;
@prop({ required: true, default: 0 })
index: number; // 索引
@prop({ required: true, default: 0 })
nodeId: number; // 关卡id
@prop({ required: true, type: Number, default: [] })
preNodeIndexs: number[]; // 连线的关卡,填上一层节点的索引
@prop({ required: true, default: 0 })
type: number; // 类型
@prop({ required: true, default: 0 })
isChoose: number; // 玩家选择 0-未选择1-选择
}
/**
* 每场的每层数据
*/
@index({ roleId: 1 })
@index({ gameCode: 1 })
@index({ gameCode: 1, layer: 1 })
@index({ gameCode: 1, hasPass: 1 })
export default class RougelikeLayer extends BaseModel {
@prop({ required: true })
roleId: string;
@prop({ required: true, default: '' })
gameCode: string; // 每场唯一code
@prop({ required: true, default: 0 })
layer: number; // 第几层
@prop({ required: true, type: Node, default: [], _id: false })
layerNodes: Node[]; // 地图随机到的各种关卡,用于画图
@prop({ required: true, default: false })
hasPass: boolean;
public static async updateByGameCode(gameCode: string, layer: number, params: { $set: RougelikeLayerPara }, lean = true) {
const result: RougelikeLayerType[] = await RougelikeLayerModel.findOneAndUpdate({ gameCode, layer }, params, { new: true, upsert: true }).lean(lean);
return result;
}
public static async updateByGameCodeAndLayer(gameCode: string, layer: number, detailCode: string, isChoose: number, params?: { $set?: RougelikeLayerPara }, lean = true) {
const result: RougelikeLayerType[] = await RougelikeLayerModel.findOneAndUpdate({ gameCode, layer, 'layerNodes.detailCode': detailCode }, { ...params, 'layerNodes.$.isChoose': isChoose }, { new: true, upsert: true }).lean(lean);
return result;
}
public static async bulkWriteUpdate(updateArr: { gameCode: string, roleId: string, layer: number, layerNodes: Node[] }[]) {
if (updateArr.length == 0) return;
await RougelikeLayerModel.bulkWrite(updateArr.map(({ gameCode, roleId, layer, layerNodes }) => {
return { updateOne: { filter: { gameCode, roleId, layer }, update: { $set: { layerNodes } }, upsert: true } }
}))
}
public static async findByGameCode(gameCode: string, lean = true) {
const result: RougelikeLayerType[] = await RougelikeLayerModel.find({ gameCode }).lean(lean);
return result;
}
public static async findByGameCodeAndLayer(gameCode: string, layer: number, lean = true) {
const result: RougelikeLayerType = await RougelikeLayerModel.findOne({ gameCode, layer }).lean(lean);
return result;
}
public static async findByGameCodeAndLayers(gameCode: string, layers: number[], lean = true) {
const result: RougelikeLayerType[] = await RougelikeLayerModel.find({ gameCode, layer: { $in: layers } }).lean(lean);
return result;
}
public static async findByGameCodeAndHasPass(gameCode: string, hasPass: boolean, lean = true) {
const result: RougelikeLayerType[] = await RougelikeLayerModel.find({ gameCode, hasPass }).lean(lean);
return result;
}
};
export const RougelikeLayerModel = getModelForClass(RougelikeLayer);
export interface RougelikeLayerType extends Pick<DocumentType<RougelikeLayer>, keyof RougelikeLayer> { };
export type RougelikeLayerPara = Partial<RougelikeLayerType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,109 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
export class RewardInter {
@prop({ required: true })
id: number;
@prop({ required: true })
count: number;
@prop({ required: true })
expireTime?: number;
}
/**
* 每场获得的圣物&特性卡
*/
@index({ roleId: 1 })
@index({ gameCode: 1 })
@index({ roleId: 1, status: 1 })
export default class RougelikeRecord extends BaseModel {
@prop({ required: true })
roleId: string; // 角色id
@prop({ required: true, default: '' })
gameCode: string; // 每场唯一code
@prop({ required: true, default: 0 })
grade: number; // 难度
@prop({ required: true, default: 0 })
type: number; // 试炼类型
@prop({ required: true, default: 0 })
authorType: number; // 流派类型
@prop({ required: true, default: 0 })
maxLayer: number; // 总共多少层
@prop({ required: true, default: 0 })
curLayer: number; // 当前在第几层
@prop({ required: true, default: 0 })
status: number; // 0-选角色卡, 1-进行中 2-已达成
@prop({ required: true, default: 0 })
score: number; // 本场获得的积分
@prop({ required: true, type: RewardInter, default: [] })
takeoutReward: RewardInter[]; // 本场获得了的奖励灵石记录一下id&count
@prop({ required: true, default: false })
hasReceivedTakeout: boolean; // 是否已带出
@prop({ required: true, default: 0 })
coin: number; // 试炼币
@prop({ required: true, default: 0 })
coinTotal: number; // 试炼币累计值
@prop({ required: true, default: 0 })
techScore: number; // 科技分
// public static async updateByGameCode(gameCode: string, params: { $set: RougelikeRecordPara, $inc?: { coin?: number, score?: number, techScore?: number } }, lean = true) {
// let doc = new RougelikeRecordModel();
// let insert = Object.assign(doc);
// for (let key in params.$inc) {
// if (insert[key] != undefined) delete insert[key];
// }
// for (let key in params.$set) {
// if (insert[key] != undefined) delete insert[key];
// }
// const result: RougelikeRecordType = await RougelikeRecordModel.findOneAndUpdate({ gameCode }, { $setOnInsert: insert, ...params }, { new: true, upsert: true }).lean(lean);
// return result;
// }
public static async updateByGameCode(gameCode: string, params: { $set?: RougelikeRecordPara, $inc?: { coin?: number, coinTotal?: number, score?: number, techScore?: number } }, lean = true) {
const result: RougelikeRecordType = await RougelikeRecordModel.findOneAndUpdate({ gameCode }, params, { new: true, upsert: true }).lean(lean);
return result;
}
public static async findByGameCode(gameCode: string, lean = true) {
const result: RougelikeRecordType = await RougelikeRecordModel.findOne({ gameCode }).lean(lean);
return result;
}
public static async findByRoleIdAndStatus(roleId: string, status: number, lean = true) {
const result: RougelikeRecordType = await RougelikeRecordModel.findOne({ roleId, status: { $lt: status } }).lean(lean);
return result;
}
public static async takeout(gameCode: string) {
const result: RougelikeRecordType = await RougelikeRecordModel.findOneAndUpdate({ gameCode }, { $set: { hasReceivedTakeout: true } }, { new: true }).lean();
return result;
}
public static async costCoin(gameCode: string, costCoin: number) {
const result: RougelikeRecordType = await RougelikeRecordModel.findOneAndUpdate({ gameCode, coin: { $gte: costCoin } }, { $inc: { coin: -costCoin } }, { new: true }).lean();
return result;
}
};
export const RougelikeRecordModel = getModelForClass(RougelikeRecord);
export interface RougelikeRecordType extends Pick<DocumentType<RougelikeRecord>, keyof RougelikeRecord> { };
export type RougelikeRecordPara = Partial<RougelikeRecordType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,254 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
export class RewardInter {
@prop({ required: true })
id: number;
@prop({ required: true })
count: number;
@prop({ required: true })
expireTime?: number;
}
export class Quest {
@prop({ required: true, default: 0 })
randomEventId: number; //问号点随机事件id
@prop({ required: true, type: Number, default: [] })
EventOptions: number[]; // 问号点用:随机事件的选项
}
export class RecoveryChara {
@prop({ required: true, default: '' })
charaCode: string
@prop({ required: true, default: 0 })
charaId: number; // 恢复的武将
@prop({ required: true, default: 0 })
beforeHp: number; // 恢复前的hp
@prop({ required: true, default: 0 })
afterHp: number; // 恢复后的hp
}
export class Recruit {
@prop({ required: true, default: 0 })
index: number; // 索引
@prop({ required: true, default: 0 })
charaId: number; // 角色卡id
@prop({ required: true, default: 0 })
status: number; // 0-未领取 1-已领取
};
export class TrainCard {
@prop({ required: true, default: '' })
cardCode: string;
@prop({ required: true, default: 0 })
cardId: number; // 特训的卡牌
@prop({ required: true, default: 0 })
beforeLv: number; // 特训前等级
@prop({ required: true, default: 0 })
afterLv: number; // 特训后等级
};
export class RestPoint {
@prop({ required: true })
restType: number; // 休整点用:玩家选择的类型
@prop({ required: false })
recoveryCnt?: number; // 恢复的次数
@prop({ required: false, type: RecoveryChara })
recoveryCharas?: RecoveryChara[];//恢复的数据
// @prop({ required: false, type: Recruit })
// recruits: Recruit[]; // 休整点:提供的随机可供招募的武将
@prop({ required: false })
trainCardCnt?: number; //休整点:特训 特训次数
@prop({ required: false, type: TrainCard })
trainCards?: TrainCard[]; //特训卡
}
export class Challenge {
@prop({ required: true, default: 0 })
challengeId: number; // 挑战id
@prop({ required: true, default: 0 })
status: number; // 0-未选择 1-已选择 2-已达成 3-已领取
@prop({ required: true, default: 0 })
progress: number; // 挑战进度
};
export class Shop {
@prop({ required: true, default: 0 })
optionIndex: number; //商店物品索引
@prop({ required: true, default: 0 })
rewardType: number; //特性卡、圣物类型
@prop({ required: true, default: 0 })
rewardId: number; // 特性卡、圣物id
@prop({ required: true, default: 0 })
optionStatus: number; // 0-未领取 1-已领取
@prop({ required: true, default: 0 })
price: number; // 原价
@prop({ required: true, default: 0 })
discountPrice: number; //购买时折扣价格
}
export class WeightRecord {
@prop({ required: false, default: 0 })
originalWight?: number;
@prop({ required: false, default: 0 })
passiveRedWight?: number;
@prop({ required: false, default: 0 })
holyRedWight?: number;
@prop({ required: false, default: 0 })
authorAddWeight?: number;
@prop({ required: false, default: 0 })
passiveLableNum?: number;
@prop({ required: false, default: 0 })
passiveLableNumAddWeight?: number;
@prop({ required: false, default: 0 })
holyLableNum?: number;
@prop({ required: false, default: 0 })
holyLableNumAddWeight?: number;
@prop({ required: false, default: 0 })
finalWeight?: number;
}
export class Option {
@prop({ required: true, default: 0 })
optionIndex: number;
@prop({ required: true, default: 0 })
rewardId: number; // 角色卡、特性卡、圣物id
@prop({ required: true, default: 0 })
optionStatus: number; // 0-未领取 1-已领取
@prop({ required: false, type: Number, default: [] })
passiveCardIds?: number[]; //高级学员自带特性卡
@prop({ required: false, type: WeightRecord, default: {} })
weightRecord?: WeightRecord //用于测试权重记录
}
export class RewardIn {
@prop({ required: true, default: 0 })
groupIndex: number; // 组index
@prop({ required: true, default: 0 })
rewardType: number; // 奖励类型
@prop({ required: false, type: Option })
options?: Option[]; // 组内随机的奖励
@prop({ required: true, default: 0 })
groupStatus: number; // 组选择 0-未选择 1-已选择
@prop({ required: true, default: 0 })
chooseNum: number; // 这一组总共能选的数量3选2
}
/**
* 每场的每层选择的关卡的数据
*/
@index({ roleId: 1 })
@index({ gameCode: 1 })
@index({ gameCode: 1, detailCode: 1 })
@index({ gameCode: 1, layer: 1, nodeId: 1 })
export default class RougelikeRecordDetail extends BaseModel {
@prop({ required: true })
roleId: string; //角色id
@prop({ required: true, default: '' })
gameCode: string; // 每场唯一code
@prop({ required: true, default: '' })
detailCode: string; // 层+关卡id唯一code
@prop({ required: true, default: 0 })
layer: number; // 层
@prop({ required: true, default: 0 })
nodeId: number; // 关卡id
@prop({ required: true, default: 0 })
nodeType: number; // 关卡类型 普通关、精英关、挑战关、试炼商店、休整点、问号点、boss
@prop({ required: false })
warId?: number; // 关卡id //【普通关、精英关、boss关】
@prop({ required: false })
battleCode?: string; // battleRecord的code
@prop({ required: true, default: 0 })
status: number; // 关卡状态 0-默认值 1-成功 2-失败
@prop({ required: false, type: Quest, default: [] })
question?: Quest; // 问好点随机事件
@prop({ required: false, default: 0 })
questType?: number; // 问好点随机type
@prop({ required: false, type: RestPoint, default: [] })
restPoints?: RestPoint[];
@prop({ required: false, type: Challenge, default: {} })
challenge?: Challenge; // 【挑战点】
@prop({ required: false, type: Shop, default: [] })
shops?: Shop[]; // 商店内的随机商品
@prop({ required: false, type: RewardIn, default: [] })
rewards?: RewardIn[]; // 通用过关后的奖励,挑战后的奖励
@prop({ required: false, default: 0 })
reRandRewardCnt: number; // 重新随机奖励
public static async updateByCode(gameCode: string, detailCode: string, params: { $set: RougelikeRecordDetailPara, $inc?: { reRandRewardCnt: 1 } }, lean = true) {
const result: RougelikeRecordDetailType = await RougelikeRecordDetailModel.findOneAndUpdate({ gameCode, detailCode }, params, { new: true, upsert: true }).lean(lean);
return result;
}
public static async updateRewardByGroupIndex(gameCode: string, detailCode: string, groupIndex: number, groupStatus: number, options: Option[], params?: { $set: RougelikeRecordDetailPara }, lean = true) {
const result: RougelikeRecordDetailType = await RougelikeRecordDetailModel.findOneAndUpdate({ gameCode, detailCode, 'rewards.groupIndex': groupIndex }, { ...params, 'rewards.$.options': options, 'rewards.$.groupStatus': groupStatus, }, { new: true, upsert: true }).lean(lean);
return result;
}
public static async updateShopByCode(gameCode: string, detailCode: string, optionIndex: number, optionStatus: number, params?: { $set: RougelikeRecordDetailPara }, lean = true) {
const result: RougelikeRecordDetailType = await RougelikeRecordDetailModel.findOneAndUpdate({ gameCode, detailCode, 'shops.optionIndex': optionIndex }, { ...params, 'shops.$.optionStatus': optionStatus }, { new: true, upsert: true }).lean(lean);
return result;
}
public static async findByGameCode(gameCode: string, lean = true) {
const result: RougelikeRecordDetailType[] = await RougelikeRecordDetailModel.find({ gameCode }).lean(lean);
return result;
}
public static async findByCode(gameCode: string, detailCode: string, lean = true) {
const result: RougelikeRecordDetailType = await RougelikeRecordDetailModel.findOne({ gameCode, detailCode }).lean(lean);
return result;
}
public static async findByGameCodeAndLtLayer(gameCode: string, layer: number, lean = true) {
const result: RougelikeRecordDetailType[] = await RougelikeRecordDetailModel.find({ gameCode, layer: { $lt: layer } }).lean(lean);
return result;
}
public static async findByGameCodeAndLayer(gameCode: string, layer: number, lean = true) {
const result: RougelikeRecordDetailType = await RougelikeRecordDetailModel.findOne({ gameCode, layer }).lean(lean);
return result;
}
public static async bulkWriteUpdate(updateArr: RougelikeRecordDetailPara[]) {
if (updateArr.length == 0) return;
await RougelikeRecordDetailModel.bulkWrite(updateArr.map((param) => {
const { gameCode, detailCode } = param
return { updateOne: { filter: { gameCode, detailCode }, update: { $set: { ...param } }, upsert: true } }
}))
}
};
export const RougelikeRecordDetailModel = getModelForClass(RougelikeRecordDetail);
export interface RougelikeRecordDetailType extends Pick<DocumentType<RougelikeRecordDetail>, keyof RougelikeRecordDetail> { };
export type RougelikeRecordDetailPara = Partial<RougelikeRecordDetailType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,66 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
import { getZeroPointD } from '../pubUtils/timeUtil';
import { SHOP_REFRESH_TYPE } from '../consts';
@index({ roleId: 1, refTime: 1 })
@index({ refTime: 1, receiveNum: 1 })
export default class RougelikeScore extends BaseModel {
@prop({ required: true })
roleId: string;
@prop({ required: true, default: new Date() })
refTime: Date; // 每周刷新奖励
@prop({ required: true, default: 0 })
score: number; // 积分
@prop({ required: true, type: Number, default: [] })
received: number[]; // 已领取的id
@prop({ required: true, default: 0 })
receiveNum: number; // 已领取的id
@prop({ required: true, default: 0 })
takeoutRewardCnt: number; // 额外奖励已领取的次数
public static async findByRoleId(roleId: string) {
let refTime = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
let result: RougelikeScoreType = await RougelikeScoreModel.findOne({ roleId, refTime }).lean();
return result;
}
public static async incScore(roleId: string, score: number) {
let refTime = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
let result: RougelikeScoreType = await RougelikeScoreModel.findOneAndUpdate({ roleId, refTime }, { $inc: { score }, $setOnInsert: { received: [], receiveNum: 0, takeoutRewardCnt: 0 } }, { new: true, upsert: true }).lean();
return result;
}
public static async receive(roleId: string, targetScore: number, index: number) {
let refTime = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
let result: RougelikeScoreType = await RougelikeScoreModel.findOneAndUpdate({ roleId, refTime, score: { $gte: targetScore } }, { $push: { received: index }, $inc: { receiveNum: 1 } }, { new: true }).lean();
return result;
}
public static async findByReceiveNum(refTime: Date, maxNum: number) {
let result: RougelikeScoreType[] = await RougelikeScoreModel.find({ refTime, receiveNum: { $lt: maxNum } }).lean();
return result;
}
public static async receiveAll(_ids: string[], maxNum: number) {
await RougelikeScoreModel.updateMany({ _id: { $in: _ids } }, { $set: { receiveNum: maxNum } });
}
public static async receiveTakeoutReward(roleId: string, maxNum: number) {
let refTime = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
await RougelikeScoreModel.findOneAndUpdate({ roleId, refTime }, { $setOnInsert: { score: 0, received: [], receiveNum: 0, takeoutRewardCnt: 0 } }, { upsert: true });
let result: RougelikeScoreType = await RougelikeScoreModel.findOneAndUpdate({ roleId, refTime, takeoutRewardCnt: { $lt: maxNum } }, { $inc: { takeoutRewardCnt: 1 } }, { new: true }).lean();
return result;
}
}
export const RougelikeScoreModel = getModelForClass(RougelikeScore);
export interface RougelikeScoreType extends Pick<DocumentType<RougelikeScore>, keyof RougelikeScore> { };
export type RougelikeScorePara = Partial<RougelikeScoreType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,95 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index } from '@typegoose/typegoose';
export class Circle {
@prop({ required: true, default: 0 })
techId: number; // 科技点
@prop({ required: true, default: 0 })
circleId: number; // 法阵的索引
@prop({ required: true, default: 0 })
hid: number; // 玩家放上的武将
@prop({ required: true, default: 0 })
ce: number; // 武将的战力
constructor(techId: number, circleId: number) {
this.techId = techId;
this.circleId = circleId;
this.hid = 0;
this.ce = 0;
}
}
@index({ roleId: 1 })
export default class RougelikeTech extends BaseModel {
@prop({ required: true })
roleId: string;
@prop({ required: true, default: 0 })
techScore: number; // 获得了的总科技点
@prop({ required: true, type: Number, default: [] })
unlockedTech: number[]; // 科技点id
@prop({ required: true, type: Circle, _id: false, default: [] })
circles: Circle[] // 法阵
@prop({ required: true, type: Number, default: [] })
effectIds: number[]; // 科技点id
// 查询
public static async findByRoleId(roleId: string, select = '') {
const result: RougelikeTechType = await RougelikeTechModel.findOne({ roleId }).select(select).lean();
return result;
}
// 增加
public static async increaseScore(roleId: string, techScore: number) {
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId }, { $setOnInsert: { unlockedTech: [], circles: [] }, $inc: { techScore } }, { new: true, upsert: true }).lean();
return result;
}
// 解锁科技点
public static async unlockTech(roleId: string, techId: number, circleIds: number[]) {
let circles = circleIds.map(circleId => new Circle(techId, circleId));
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId }, { $push: { unlockedTech: techId, circles: { $each: circles } } }, { new: true, upsert: true }).lean();
return result;
}
// 法阵放武将
public static async putOnCircle(roleId: string, circleId: number, hid: number, ce: number) {
if(hid > 0) await this.putOffCircle(roleId, hid);
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId, 'circles.circleId': circleId }, { $set: { 'circles.$.hid': hid, 'circles.$.ce': ce } }, { new: true }).lean();
return result;
}
// 法阵撤下
public static async putOffCircle(roleId: string, hid: number) {
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId, 'circles.hid': hid }, { $set: { 'circles.$.hid': 0, 'circles.$.ce': 0 } }, { new: true }).lean();
return result;
}
public static async updateEffectId(roleId: string, effectIds: number[]) {
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId }, { $set: { effectIds } }, { new: true }).lean();
return result;
}
// 更新武将战力
public static async updateCircle(roleId: string, circles: Circle[], effectIds: number[]) {
let result: RougelikeTechType = await RougelikeTechModel.findOneAndUpdate({ roleId }, { $set: { circles, effectIds } }, { new: true }).lean();
return result;
}
// 清空科技树
public static async clearTech(roleId: string) {
await RougelikeTechModel.deleteMany({ roleId });
}
}
export const RougelikeTechModel = getModelForClass(RougelikeTech);
export interface RougelikeTechType extends Pick<DocumentType<RougelikeTech>, keyof RougelikeTech> { };
export type RougelikeTechPara = Partial<RougelikeTechType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,32 @@
/**
* 角色卡奖励卡池方案
*/
import { FILENAME } from "../consts";
import { readFileAndParse } from "./util";
export interface DicRougeCharaCardPlan {
readonly id: number;
readonly planId: number; // 方案编号
readonly cardId: number; // 角色卡id
readonly weight: number; // 权重
}
export const dicRougeCharaCardPlan = new Map<number, DicRougeCharaCardPlan[]>();
export function loadRougeCharaCardPlan() {
dicRougeCharaCardPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_CHARA_CARD_PLAN);
arr.forEach(o => {
if (!dicRougeCharaCardPlan.has(o.planId)) {
dicRougeCharaCardPlan.set(o.planId, []);
}
dicRougeCharaCardPlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,32 @@
/**
* 圣物卡奖励卡池方案
*/
import { FILENAME } from "../consts";
import { readFileAndParse } from "./util";
export interface DicRougeHolyCardPlan {
readonly id: number;
readonly planId: number; // 方案编号
readonly cardId: number; // 角色卡id
readonly weight: number; // 权重
}
export const dicRougeHolyCardPlan = new Map<number, DicRougeHolyCardPlan[]>();
export function loadRougeHolyCardPlan() {
dicRougeHolyCardPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_HOLY_CARD_PLAN);
arr.forEach(o => {
if (!dicRougeHolyCardPlan.has(o.planId)) {
dicRougeHolyCardPlan.set(o.planId, []);
}
dicRougeHolyCardPlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -141,6 +141,37 @@ import { dicAuthorsBookMaxProgress, dicAuthorsBookSubs, dicAuthorsBookSubStar, l
import { dicAuthorsBookPoint, loadAuthorsBookPoint } from "./dictionary/DicAuthorsBookPoint";
import { dicAuthorsBook, loadAuthorsBook } from './dictionary/DicAuthorsBook';
import { dicBossRankActivePoint, loadBossRankActivePoint } from "./dictionary/DicBossRankActivePoint";
// import { dicRougeType, loadRougeType } from "./dictionary/DicRougeType";
import { dicRougeChara, dicRougeCharaByInitial, loadRougeChara } from "./dictionary/DicRougeChara";
import { dicRougePassiveCardPlan, loadRougePassiveCardPlan } from "./dictionary/DicRougePassiveCardPlan";
import { dicRougePassiveCard, dicRougePassiveCardByGroup, loadRougePassiveCard } from "./dictionary/DicRougePassiveCard";
import { dicRougeSkillCard, loadRougeSkillCard } from "./dictionary/DicRougeSkillCard";
import { dicRougeHolyCard, loadRougeHolyCard } from "./dictionary/DicRougeHolyCard";
import { dicRougeLayerRewardPlan, loadRougeLayerRewardPlan } from "./dictionary/DicRougeLayerReward";
import { dicRougeNode, loadRougeNode } from "./dictionary/DicRougeNode";
import { dicRougeShopPlan, loadRougeShopPlan } from "./dictionary/DicRougeShopPlan";
import { dicRougeTypeGrade, dicRougeTypeGradeById, loadRougeTypeGrade } from "./dictionary/DicRougeTypeGrade";
import { dicRougeLayerPlan, dicRougeLayerPlanByPlanId, loadRougeLayerPlan } from "./dictionary/DicRougeLayerPlan";
import { dicRougeLayerNodeNumPlan, loadRougeLayerNodeNumPlan } from "./dictionary/DicRougeLayerNodeNumPlan";
import { dicRougeLayerNodePlan, loadRougeLayerNodePlan } from "./dictionary/DicRougeLayerNodePlan";
import { dicRougeAuthorType, loadRougeAuthorType } from "./dictionary/DicRougeAuthorType";
import { dicRougeChallenge, loadRougeChallenge } from "./dictionary/DicRougeChallenge";
import { dicRougeChallengePlan, loadRougeChallengePlan } from "./dictionary/DicRougeChallengePlan";
import { dicRougeQuestionMarkPlan, loadRougeQuestionMarkPlan } from "./dictionary/DicRougeQuestionMarkPlan";
import { dicRougeRandomEventPlan, loadRougeRandomEventPlan } from "./dictionary/DicRougeRandomEventPlan";
import { dicRougeCharaCardPlan, loadRougeCharaCardPlan } from "./DicRougeCharaCardPlan";
import { dicRougeHolyCardPlan, loadRougeHolyCardPlan } from "./DicRougeHolyCardPlan";
import { dicRougeEventOption, loadRougeEventOption } from "./dictionary/DicRougeEventOption";
import { dicRougeTech, loadRougeTech, dicRougeTechIdByRow } from "./dictionary/DicRougeTech";
import { dicRougeTechCircle, dicRougeTechCircleByTechId, loadRougeTechCircle } from "./dictionary/DicRougeTechCircle";
import { dicRougeTechLevel, loadRougeTechLevel } from "./dictionary/DicRougeTechLevel";
import { dicRougeOptionGroup, loadRougeOptionGroup } from "./dictionary/DicRougeOptionGroup";
import { dicRougePassiveCollect, loadRougePassiveCollect } from "./dictionary/DicRougePassiveCollect";
import { dicRougeScoreNum, dicRougeScoreReward, loadRougeScoreReward } from "./dictionary/DicRougeScoreReward";
import { dicRougeEffect, loadRougeEffect } from "./dictionary/DicRougeEffect";
import { dicRougeEffectType, loadRougeEffectType } from "./dictionary/DicRougeEffectType";
import { dicSpiritPlan, loadSpiritPlan } from "./dictionary/DicSpiritPlan";
export const gameData = {
daily: dicDaily,
@@ -361,6 +392,46 @@ export const gameData = {
authorBookPoint: dicAuthorsBookPoint,
authorBookMaxProgress: dicAuthorsBookMaxProgress,
bossRankActivePoint: dicBossRankActivePoint,
// rougeType: dicRougeType, //暂时用不到
rougeAuthorType: dicRougeAuthorType,
rougeTypeGrade: dicRougeTypeGrade,
rougeTypeGradeById: dicRougeTypeGradeById,
rougeLayerPlan: dicRougeLayerPlan,
spiritPlan: dicSpiritPlan,
rougeLayerPlanByPlanId: dicRougeLayerPlanByPlanId,
rougeLayerNodeNumPlan: dicRougeLayerNodeNumPlan,
rougeLayerNodePlan: dicRougeLayerNodePlan,
rougeNode: dicRougeNode,
rougeLayerRewardPlan: dicRougeLayerRewardPlan,
rougeShopPlan: dicRougeShopPlan,
rougeChara: dicRougeChara,
rougeCharaByInitial: dicRougeCharaByInitial,
rougePassiveCard: dicRougePassiveCard,
rougePassiveCardByGroup: dicRougePassiveCardByGroup,
rougeSkillCard: dicRougeSkillCard,
rougeHolyCard: dicRougeHolyCard,
rougeCharaCardPlan: dicRougeCharaCardPlan,
rougePassiveCardPlan: dicRougePassiveCardPlan,
rougeHolyCardPlan: dicRougeHolyCardPlan,
rougeChallenge: dicRougeChallenge,
rougeChallengePlan: dicRougeChallengePlan,
rougeQuestionMarkPlan: dicRougeQuestionMarkPlan,
rougeRandomEventPlan: dicRougeRandomEventPlan,
rougeEventOption: dicRougeEventOption,
rougeOptionGroup: dicRougeOptionGroup,
rougePassiceCollect: dicRougePassiveCollect,
rougeScoreReward: dicRougeScoreReward,
rougeScoreNum: dicRougeScoreNum,
rougeEffect: dicRougeEffect,
rougeEffectType: dicRougeEffectType,
rougeTech: dicRougeTech,
rougeTechCircle: dicRougeTechCircle,
rougeCircleByTech: dicRougeTechCircleByTechId,
rougeTechByRow: dicRougeTechIdByRow,
rougeTechLevel: dicRougeTechLevel,
};
// 在此提供一些原先在gamedata中提供的方法以便更方便获取gameData数据
@@ -1298,6 +1369,16 @@ export function getDicServerName(env: string, serverId: number) {
return dic.get(serverId);
}
export function getRougeEffectTypeKind(effectTypes: number[]) {
let kinds: number[] = [];
for (let effectType of effectTypes) {
let dicEffectType = gameData.rougeEffectType.get(effectType);
if (!dicEffectType) continue;
if (!kinds.includes(dicEffectType.kind)) kinds.push(dicEffectType.kind);
}
return kinds;
}
// 初始加载
function initDatas() {
parseDicParam();
@@ -1675,9 +1756,41 @@ function loadDatas(type?: string) {
loadAuthorsBookPoint();
if (type == undefined || type == 'loadAuthorsBook')
loadAuthorsBook();
if (type == undefined || type == 'loadBossRankActivePoint')
loadBossRankActivePoint();
// if (type == undefined || type == 'loadRougeType') loadRougeType();//暂时用不到
if (type == undefined || type == 'loadRougeAuthorType') loadRougeAuthorType();
if (type == undefined || type == 'loadRougeTypeGrade') loadRougeTypeGrade();
if (type == undefined || type == 'loadRougeLayerPlan') loadRougeLayerPlan();
if (type == undefined || type == 'loadSpiritPlan') loadSpiritPlan();
if (type == undefined || type == 'loadRougeLayerNodeNumPlan') loadRougeLayerNodeNumPlan();
if (type == undefined || type == 'loadRougeLayerNodePlan') loadRougeLayerNodePlan();
if (type == undefined || type == 'loadRougeNode') loadRougeNode();
if (type == undefined || type == 'loadRougeLayerRewardPlan') loadRougeLayerRewardPlan();
if (type == undefined || type == 'loadRougeShopPlan') loadRougeShopPlan();
if (type == undefined || type == 'loadRougeChara') loadRougeChara();
if (type == undefined || type == 'loadRougePassiveCard') loadRougePassiveCard();
if (type == undefined || type == 'loadRougeSkillCard') loadRougeSkillCard();
if (type == undefined || type == 'loadRougeHolyCard') loadRougeHolyCard();
if (type == undefined || type == 'loadRougeCharaCardPlan') loadRougeCharaCardPlan();
if (type == undefined || type == 'loadRougePassiveCardPlan') loadRougePassiveCardPlan();
if (type == undefined || type == 'loadRougeHolyCardPlan') loadRougeHolyCardPlan();
if (type == undefined || type === 'loadRougeChallenge') loadRougeChallenge();
if (type == undefined || type == 'loadRougeChallengePlan') loadRougeChallengePlan();
if (type == undefined || type == 'loadRougeQuestionMarkPlan') loadRougeQuestionMarkPlan();
if (type == undefined || type == 'loadRougeRandomEventPlan') loadRougeRandomEventPlan();
if (type == undefined || type == 'loadRougeEventOption') loadRougeEventOption();
if (type == undefined || type == 'loadRougeOptionGroup') loadRougeOptionGroup();
if (type == undefined || type == 'loadRougePassiveCollect') loadRougePassiveCollect();
if (type == undefined || type == 'loadRougeScoreReward') loadRougeScoreReward();
if (type == undefined || type == 'loadRougeEffect') loadRougeEffect();
if (type == undefined || type == 'loadRougeEffectType') loadRougeEffectType();
if (type == undefined || type == 'loadRougeTech') loadRougeTech();
if (type == undefined || type == 'loadRougeTechCircle') loadRougeTechCircle();
if (type == undefined || type == 'loadRougeTechLevel') loadRougeTechLevel();
console.log('loadDatas type: ', type || 'all');
}

View File

@@ -365,9 +365,14 @@ export const ACTIVITY = {
ACTIVITY_CATCH_FISH_PROBABILITY: '1&45|2&40|3&15', // 新出现的鱼是什么类型的概率 type&概率type=1:小黑鱼 type=2:大黑鱼 type=3:锦鲤)
ACTIVITY_WATERCHANNEL_SCORE: '1&30|10&20|15&15|30&10', // 水渠小游戏的得分规则min&socre区间下限至下一档之间的得分
ACTIVITY_FLAPPY_BIRD_COUNTDOWN: 60, // 飞鸟小游戏倒计时s
ACTIVITY_FLAPPY_BIRD_SCORE: 1, // 飞过每根柱子的得分
ACTIVITY_FLAPPY_BIRD_SCORE: 2, // 飞过每根柱子的得分
ACTIVITY_LAYER_CAKE_COUNTDOWN: 60, // 叠糕小游戏倒计时s
ACTIVITY_LAYER_CAKE_SCORE: 1, // 每叠一层糕点的得分
ACTIVITY_LAYER_CAKE_SCORE: 2, // 每叠一层糕点的得分
ACTIVITY_RABBIT_FINDING_TIME: 20, // 大家来找茬每轮总次数
ACTIVITY_RABBIT_PUSH_BOX_TIME: 60, // 推箱子小游戏倒计时
ACTIVITY_RABBIT_PUSH_BOX_SCORE: 2, // 到达指定位置获得积分
ACTIVITY_BEATING_TOWER: 15, // 敲塔小游戏总层数
ACTIVITY_BEATING_SCORE: 2, // 敲塔小游戏成功敲掉一层所加分数
};
export const BATTLE_PREPARING = {
CHANGE_ORDER_OPEN: 109, // 出兵界面行动顺序按钮开启关卡
@@ -454,3 +459,18 @@ export const PLATFORM_CONFIG = {
export const COMMUNICATION = {
COMMUNICATION_FOLLOW: '31002&100|22001&2', // 关注公众号奖励
};
export const ROUGELIKE = {
INIT_RANDOM_CHARA_COUNT: 3, // 初始需要随机的角色卡数量
AUTHOR_ADD_RANDOM: 10, // 选择流派后该流派百家特性卡增加的权重X
PASSIVE_LABLE_NUM: 3, // 获得X张同passiveLable的特性卡时该label的特性卡权重增加
PASSIVE_LABLE_ADD_RANDOM: 5, // 获得N张同passiveLable的特性卡时该label的特性卡权重增加X
HOLY_LABLE_NUM: 3, // 获得X张同hollyLable的特性卡时该label的圣物权重增加
HOLY_LABLE_ADD_RANDOM: 5, // 获得N张同hollyLable的特性卡时该label的圣物权重增加X
RECOVERY_RATIO: 50, // 休整点恢复系数,填整数,百分比
TAKEOUT_REWARD_CNT: 3, // 每周可领取的额外奖励次数
SPIRIT_RANDOM_NUM: 5, // 额外带出奖励的英灵随机数量
SELECT_PASSIVECARD_WEIGHT: 30, // 选择的特性卡后该特性卡权重减少比例(%
RANDOM_PASSIVECARD_WEIGHT: 10, // 随机出的特性卡后该特性卡权重减少比例(%
SELECT_HOLLYCARD_WEIGHT: 30, // 选择的圣物卡后该特性卡权重减少比例(%
RANDOM_HOLLYCARD_WEIGHT: 10, // 随机出的圣物卡后该特性卡权重减少比例(%
};

View File

@@ -41,10 +41,12 @@ export interface DicHero {
readonly urType: number;
// 武将id
readonly actorId: number;
readonly hp: 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, initialStar: true, initialColorStar: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true, talentId: true, urType: true, actorId: true };
const DicHeroKeys: KeysEnum<DicHero> = {heroId: true, name: true, quality: true, camp: true, jobClass: true, jobid: true, skill: true, pieceId: true, initialStar: true, initialColorStar: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true, talentId: true, urType: true, actorId: true, hp: true };
export const dicHero = new Map<number, DicHero>();
export function loadHero() {
dicHero.clear();

View File

@@ -0,0 +1,25 @@
/**
* 流派类型配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeAuthorType {
readonly id: number;
readonly authorType: number; // 流派类型
// readonly holyCard: number; // 圣物奖励
}
export const dicRougeAuthorType = new Map<number, DicRougeAuthorType>();
export function loadRougeAuthorType() {
dicRougeAuthorType.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_AUTHOR_TYPE);
arr.forEach(o => {
dicRougeAuthorType.set(o.authorType, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 挑战类型配置表
*/
import { parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeChallenge {
readonly id: number;
readonly challengeId: number; // 挑战
readonly type: number; // 挑战的类型,具体是啥需要一个文档
readonly effectId: number[]; // 挑战达成的参数
readonly condition: number; // 客户端显示的 x/n里面的n
}
export const dicRougeChallenge = new Map<number, DicRougeChallenge>();
export function loadRougeChallenge() {
dicRougeChallenge.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_CHALLANGE);
arr.forEach(o => {
o.effectId = parseNumberList(o.effectId);
dicRougeChallenge.set(o.challengeId, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 挑战关随机配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeChallengePlan {
readonly id: number;
readonly planId: number;
readonly challengeId: number; // 挑战关卡的id dicRougeChallenge的id
readonly weight: number; // 权重
}
export const dicRougeChallengePlan = new Map<number, DicRougeChallengePlan[]>();
export function loadRougeChallengePlan() {
dicRougeChallengePlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_CHALLANGE_PLAN);
arr.forEach(o => {
if (!dicRougeChallengePlan.has(o.planId)) {
dicRougeChallengePlan.set(o.planId, []);
}
dicRougeChallengePlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,39 @@
/**
* 角色卡配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeChara {
readonly id: number;
readonly heroId: number; // 角色id
readonly charaType: number; // 1-普通卡 2-高级卡
readonly initial: number; // 是否能被初始随机到
readonly initCardCnt: number; // 初始获得多少特性卡装在身上
readonly recruitConsume: number; // 试炼币购买
}
export const dicRougeChara = new Map<number, DicRougeChara>();
export const dicRougeCharaByInitial = new Map<number, DicRougeChara[]>();
export function loadRougeChara() {
dicRougeChara.clear();
dicRougeCharaByInitial.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_CHARA);
arr.forEach(o => {
dicRougeChara.set(o.id, o);
if (!dicRougeCharaByInitial.has(o.initial)) {
dicRougeCharaByInitial.set(o.initial, []);
}
dicRougeCharaByInitial.get(o.initial).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,47 @@
/**
* 圣物效果配置表
*/
import { decodeArrayListStr, readFileAndParse } from '../util'
import { ABI_TYPE, FILENAME, ROUGE_EFFECT_TYPE } from '../../consts'
export interface DicRougeEffect {
readonly id: number;
readonly effectId: number;
readonly effectType: number; // 效果的类型具体什么type写个文档
readonly effectParam: number[]; // 效果的具体参数不同的type对这个param的解释不同需要分别定义用&连接
}
export const dicRougeEffect = new Map<number, DicRougeEffect>();
export function loadRougeEffect() {
dicRougeEffect.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_EFFECT);
arr.forEach(o => {
o.effectParam = parseEffectParam(o.effectType, o.effectParam);
// console.log('effectParam', o.effectParam)
// if (!dicRougeEffect.has(o.effectType)) {
// dicRougeEffect.set(o.effectType, []);
// }
// dicRougeEffect.get(o.effectType).push(o);
dicRougeEffect.set(o.effectId, o);
});
arr = undefined;
}
function parseEffectParam(effectType: number, str: string) {
let arr = decodeArrayListStr(str);
switch(effectType) {
case ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP:
case ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP:
case ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP:
case ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP:
{
arr = arr.filter(cur => cur[0] == ABI_TYPE.ABI_HP.toString());
break;
}
}
return arr.length > 0? arr[0].map(cur => parseFloat(cur)): [];
}

View File

@@ -0,0 +1,32 @@
/**
* 圣物效果配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
const _ = require('lodash');
export interface DicRougeEffectType {
readonly id: number;
readonly effectType: number; // 效果的类型具体什么type写个文档
readonly kind: number;
}
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const DicRougeEffectTypeKeys: KeysEnum<DicRougeEffectType> = {
id: true,
effectType: true,
kind: true,
}
export const dicRougeEffectType = new Map<number, DicRougeEffectType>();
export function loadRougeEffectType() {
dicRougeEffectType.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_EFFECT_TYPE);
arr.forEach(o => {
dicRougeEffectType.set(o.effectType, _.pick(o, Object.keys(DicRougeEffectTypeKeys)));
});
arr = undefined;
}

View File

@@ -0,0 +1,29 @@
/**
* 随机事件配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeEventOption {
readonly id: number;
readonly randomEventId: number; // 事件id
readonly optionGroup: number; // 一组选项的组id
readonly title: string //标题
readonly index: number; // 选项在他这组里的索引
readonly text: string; // 选项
readonly afterGroup: number; // 选了这个选项之后的选项组
readonly holyCardPlan: number; // 奖励的圣物
}
export const dicRougeEventOption = new Map<number, DicRougeEventOption>();
export function loadRougeEventOption() {
dicRougeEventOption.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_EVENT_OPTION);
arr.forEach(o => {
dicRougeEventOption.set(o.id, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,38 @@
/**
* 圣物
*/
import { parseGoodStr, parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeHolyCard {
readonly id: number;
readonly name: string;
readonly imageName: string;
readonly quality: number; // 品质
readonly authorType: number; // 所属百家流派
readonly skillId: number; // ?待解释,可能是战场技能
readonly content: string;
readonly useCount: number;
readonly label: number; // 当获得同标签的百家特性卡达到X个同标签的圣物获得概率增加
readonly purchasePrice: number; // 试炼币购买
readonly collectReward: RewardInter[];
readonly effectId: number[];
readonly getLimit: number; //获取上限
}
export const dicRougeHolyCard = new Map<number, DicRougeHolyCard>();
export function loadRougeHolyCard() {
dicRougeHolyCard.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_HOLY_CARD);
arr.forEach(o => {
o.collectReward = parseGoodStr(o.collectReward);
o.effectId = parseNumberList(o.effectId);
dicRougeHolyCard.set(o.id, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 每层可以随机的点的数量的池子
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeLayerNodeNumPlan {
readonly id: number;
readonly nodeNumPlanId: number; // 随机方案dicRougeLayer的nodeNumPlan引用
readonly nodeNum: number; // 节点数量
readonly weight: number; // 他的权重
}
export const dicRougeLayerNodeNumPlan = new Map<number, DicRougeLayerNodeNumPlan[]>();
export function loadRougeLayerNodeNumPlan() {
dicRougeLayerNodeNumPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_LAYER_NODE_NUM_PLAN);
arr.forEach(o => {
if (!dicRougeLayerNodeNumPlan.get(o.nodeNumPlanId)) dicRougeLayerNodeNumPlan.set(o.nodeNumPlanId, []);
dicRougeLayerNodeNumPlan.get(o.nodeNumPlanId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,30 @@
/**
* 试炼难度配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeLayerNodePlan {
readonly id: number;
readonly nodePlanId: number; // 随机方案dicRougeLayer的nodePlan引用
readonly nodeId: number; // 节点的类型,引用的是 dicRougeNode 表的nodeId
readonly weight: number;
}
// export const dicRougeLayerNodePlan = new Map<string, DicRougeLayerNodePlan>();
export const dicRougeLayerNodePlan = new Map<number, DicRougeLayerNodePlan[]>();
export function loadRougeLayerNodePlan() {
dicRougeLayerNodePlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_LAYER_NODE_PLAN);
arr.forEach(o => {
if (!dicRougeLayerNodePlan.get(o.nodePlanId)) dicRougeLayerNodePlan.set(o.nodePlanId, []);
dicRougeLayerNodePlan.get(o.nodePlanId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,39 @@
/**
* 试炼难度配置表
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeLayerPlan {
readonly id: number;
readonly planId: number; // 试炼类型
readonly layerIndex: number; // 层
readonly nodeNumPlan: number; // 每层可以随机的点的数量
readonly nodePlan: number; // 每层可以随机到的节点
readonly rewardPlan: number; // 每层可以赠送的奖励
readonly shopPlan: number; // 该层可以随机到的商店方案
readonly takeoutReward: RewardInter[]; //额外奖励
readonly spiritPlan: number; //英灵随机奖励
}
export const dicRougeLayerPlan = new Map<string, DicRougeLayerPlan>();
export const dicRougeLayerPlanByPlanId = new Map<number, DicRougeLayerPlan[]>();
export function loadRougeLayerPlan() {
dicRougeLayerPlan.clear();
dicRougeLayerPlanByPlanId.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_LAYER_PLAN);
arr.forEach(o => {
o.takeoutReward = parseGoodStr(o.takeoutReward);
dicRougeLayerPlan.set(o.planId + '_' + o.layerIndex, o);
if (!dicRougeLayerPlanByPlanId.get(o.planId)) dicRougeLayerPlanByPlanId.set(o.planId, []);
dicRougeLayerPlanByPlanId.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,41 @@
/**
* 每层可随机到的奖励
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeLayerRewardPlan {
readonly id: number;
readonly planId: number;
readonly nodeType: number; // 精英关、普通关、boss关、挑战、随机事件、休整点
readonly charaPlan: number; // 角色卡
readonly charaRandomNum: number; // 玩家可以随机出多少奖励
readonly charaChooseNum: number; // 玩家可以从随机出的里选择多少奖励
readonly charaPassivePlan: number; // 高级卡自带的特性卡
readonly passiveCardPlan: number; // 特性卡
readonly passiveCardRandomNum: number; // 玩家可以随机出多少奖励
readonly passiveCardChooseNum: number; // 玩家可以从随机出的里选择多少奖励
readonly holyCardPlan: number; // 圣物
readonly holyCardRandomNum: number; // 玩家可以随机出多少奖励
readonly holyCardChooseNum: number; // 玩家可以从随机出的里选择多少奖励
readonly coin: number; // 试炼币
readonly score: number; // 学分
readonly tech: number; // 科技点
// readonly goods: RewardInter[]; // 灵石 物品表id&count
}
export const dicRougeLayerRewardPlan = new Map<string, DicRougeLayerRewardPlan>();
export function loadRougeLayerRewardPlan() {
dicRougeLayerRewardPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_LAYER_REWARD_PLAN);
arr.forEach(o => {
o.goods = parseGoodStr(o.goods);
dicRougeLayerRewardPlan.set(o.planId + '_' + o.nodeType, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,26 @@
/**
* 关卡配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeNode {
readonly id: number;
readonly nodeId: number; // 关卡id
readonly nodeType: number; // 试炼类型 普通关、精英关、boss关、挑战点、问号点、休整点、商店
readonly param: number; // 普通关、精英关、boss关的对应关卡id
}
export const dicRougeNode = new Map<number, DicRougeNode>();
export function loadRougeNode() {
dicRougeNode.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_NODE);
arr.forEach(o => {
dicRougeNode.set(o.nodeId, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,25 @@
/**
* 随机事件图鉴
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeOptionGroup {
readonly id: number;
readonly optionGroup: number; // 一组选项的组id
readonly collectReward: RewardInter[]; // 图鉴收集奖励同Group只领取一次奖励
}
export const dicRougeOptionGroup = new Map<number, DicRougeOptionGroup>();
export function loadRougeOptionGroup() {
dicRougeOptionGroup.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_OPTION_GROUP);
arr.forEach(o => {
o.collectReward = parseGoodStr(o.collectReward);
dicRougeOptionGroup.set(o.optionGroup, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,44 @@
/**
* 特性卡
*/
import { parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougePassiveCard {
readonly id: number;
readonly group: number; // 同样的group之间才可以特训
readonly lv: number; // 特训等级,可以初始获得不同等级
readonly name: string;
readonly quality: number; // 品质
readonly authorType: number; // 所属百家流派,在该流派试炼中出现概率提升
readonly seid: string; // 纯战场、服务器不读
readonly content: string;
readonly passiveLabel: number[]; // 关联其他特性卡获得这个特性卡之后他relationId的概率提升
readonly holyLabel: number[]; // 关联圣物,获得这个特性卡之后圣物概率提升
readonly strengthConsume: number; // 强化消耗
readonly price: number; // 试炼币购买
readonly getLimit: number; //获取上限
}
export const dicRougePassiveCard = new Map<number, DicRougePassiveCard>();
export const dicRougePassiveCardByGroup = new Map<number, DicRougePassiveCard[]>();
export function loadRougePassiveCard() {
dicRougePassiveCard.clear();
dicRougePassiveCardByGroup.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_PASSIVE_CARD);
arr.forEach(o => {
o.passiveLabel = parseNumberList(o.passiveLabel);
o.holyLabel = parseNumberList(o.holyLabel);
dicRougePassiveCard.set(o.id, o);
if (!dicRougePassiveCardByGroup.has(o.group)) {
dicRougePassiveCardByGroup.set(o.group, []);
}
dicRougePassiveCardByGroup.get(o.group).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,32 @@
/**
* 特性卡奖励卡池方案
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougePassiveCardPlan {
readonly id: number;
readonly planId: number; // 方案编号
readonly cardId: number; // 角色卡id
readonly weight: number; // 权重
}
export const dicRougePassiveCardPlan = new Map<number, DicRougePassiveCardPlan[]>();
export function loadRougePassiveCardPlan() {
dicRougePassiveCardPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_PASSIVE_CARD_PLAN);
arr.forEach(o => {
if (!dicRougePassiveCardPlan.has(o.planId)) {
dicRougePassiveCardPlan.set(o.planId, []);
}
dicRougePassiveCardPlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,27 @@
/**
* 特性卡
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougePassiveCollect {
readonly id: number;
readonly num: number; // 收集数量
readonly collectReward: RewardInter[]; // 奖励
}
export const dicRougePassiveCollect = new Map<number, DicRougePassiveCollect>();
export function loadRougePassiveCollect() {
dicRougePassiveCollect.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_PASSIVE_COLLECT);
arr.forEach(o => {
o.collectReward = parseGoodStr(o.reward);
dicRougePassiveCollect.set(o.id, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,32 @@
/**
* 问好点随机配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeQuestionMarkPlan {
readonly id: number;
readonly questionMarkPlanId: number; // 问号点随机方案编号
readonly questionMarkIndex: number; // 方案内node编号
readonly nodeType: number; // 关卡类型 普通关、精英关、boss关、挑战点问号点、休整点、商店
readonly param: number; // 普通关、精英关对应的warId
readonly weight: number; //随机权重
}
export const dicRougeQuestionMarkPlan = new Map<number, DicRougeQuestionMarkPlan[]>();
export function loadRougeQuestionMarkPlan() {
dicRougeQuestionMarkPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_QUESTION_MARK_PLAN);
arr.forEach(o => {
if (!dicRougeQuestionMarkPlan.get(o.questionMarkPlanId)) dicRougeQuestionMarkPlan.set(o.questionMarkPlanId, []);
dicRougeQuestionMarkPlan.get(o.questionMarkPlanId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 随机关卡配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeRandomEventPlan {
readonly id: number;
readonly planId: number;
readonly randomEventId: number; // 随机关卡的id dicRougeEventOption中的randomEventId
readonly weight: number; // 权重
}
export const dicRougeRandomEventPlan = new Map<number, DicRougeRandomEventPlan[]>();
export function loadRougeRandomEventPlan() {
dicRougeRandomEventPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_RANDOM_EVENT_PLAN);
arr.forEach(o => {
if (!dicRougeRandomEventPlan.has(o.planId)) {
dicRougeRandomEventPlan.set(o.planId, []);
}
dicRougeRandomEventPlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -0,0 +1,27 @@
/**
* 随机事件图鉴
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeScoreReward {
readonly index: number;
readonly score: number; // 积分
readonly reward: RewardInter[]; // 图鉴收集奖励同Group只领取一次奖励
}
export const dicRougeScoreReward = new Map<number, DicRougeScoreReward>();
export const dicRougeScoreNum = { num: 0 }
export function loadRougeScoreReward() {
dicRougeScoreReward.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_SCORE_REWARD);
arr.forEach(o => {
o.reward = parseGoodStr(o.reward);
dicRougeScoreReward.set(o.index, o);
dicRougeScoreNum.num++;
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 试炼类型配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeShopPlan {
readonly id: number;
readonly planId: number;
readonly passivecardPlanId: number; // 特性卡
readonly passiveCardRandomNum: number; // 玩家可以在商店随机出多少奖励
readonly holyCardPlanId: number; // 圣物
readonly holyCardRandomNum: number; // 玩家可以商店随机出多少奖励
}
export const dicRougeShopPlan = new Map<number, DicRougeShopPlan>();
export function loadRougeShopPlan() {
dicRougeShopPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_SHOP_PLAN);
arr.forEach(o => {
dicRougeShopPlan.set(o.planId, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,30 @@
/**
* 技能卡
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeSkillCard {
readonly id: number;
readonly name: string;
readonly quality: number; // 品质
readonly skillType: number; // 技能类型
readonly authorType: number; // 所属百家流派,在该流派试炼中出现概率提升
readonly skillId: number; // 战场技能
readonly collectReward: RewardInter[];
}
export const dicRougeSkillCard = new Map<number, DicRougeSkillCard>();
export function loadRougeSkillCard() {
dicRougeSkillCard.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_SKILL_CARD);
arr.forEach(o => {
o.collectReward = parseGoodStr(o.collectReward);
dicRougeSkillCard.set(o.id, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,47 @@
/**
* 科技树配置
*/
import { parseGoodStr, parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
const _ = require('lodash');
export interface DicRougeTech {
readonly id: number;
readonly techId: number; // 科技点
readonly rowId: number; // 列
readonly index: number; // 第几个
readonly preTechId: number[]; // 前置节点
readonly cost: RewardInter[]; // 消耗的科技点
}
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const DicRougeTechKeys: KeysEnum<DicRougeTech> = {
id: true,
techId: true,
rowId: true,
index: true,
preTechId: true,
cost: true,
}
export const dicRougeTech = new Map<number, DicRougeTech>();
export const dicRougeTechIdByRow = new Map<number, number[]>();
export function loadRougeTech() {
dicRougeTech.clear();
dicRougeTechIdByRow.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_TECH);
arr.forEach(o => {
o.preTechId = parseNumberList(o.preTechId);
o.cost = parseGoodStr(o.cost);
dicRougeTech.set(o.techId, _.pick(o, Object.keys(DicRougeTechKeys)));
if(!dicRougeTechIdByRow.has(o.rowId)) dicRougeTechIdByRow.set(o.rowId, []);
dicRougeTechIdByRow.get(o.rowId)?.push(o.techId);
});
arr = undefined;
}

View File

@@ -0,0 +1,29 @@
/**
* 科技树法阵配置
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicRougeTechCircle {
readonly id: number;
readonly techId: number; // 科技树
readonly circleId: number; // 对应法阵id
}
export const dicRougeTechCircle = new Map<number, number>();
export const dicRougeTechCircleByTechId = new Map<number, number[]>();
export function loadRougeTechCircle() {
dicRougeTechCircle.clear();
dicRougeTechCircleByTechId.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_TECH_CIRCLE);
arr.forEach(o => {
if(!dicRougeTechCircle.has(o.circleId)) dicRougeTechCircle.set(o.circleId, o.techId);
if(!dicRougeTechCircleByTechId.has(o.techId)) dicRougeTechCircleByTechId.set(o.techId, []);
if(!dicRougeTechCircleByTechId.get(o.techId).includes(o.circleId)) dicRougeTechCircleByTechId.get(o.techId).push(o.circleId);
});
arr = undefined;
}

View File

@@ -0,0 +1,37 @@
/**
* 科技树法阵配置
*/
import { parseNumberList, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
const _ = require('lodash');
export interface DicRougeTechLevel {
readonly techId: number; // 对应等级
readonly level: number; // 等级
readonly ce: number; // 战力
readonly techEffectIds: number[]; // 加成
}
type KeysEnum<T> = { [P in keyof Required<T>]: boolean };
const DicRougeTechCircleKeys: KeysEnum<DicRougeTechLevel> = {
techId: true,
level: true,
ce: true,
techEffectIds: true,
}
export const dicRougeTechLevel = new Map<number, DicRougeTechLevel[]>();
export function loadRougeTechLevel() {
dicRougeTechLevel.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_TECH_LEVEL);
arr.forEach(o => {
o.techEffectIds = parseNumberList(o.techEffectId);
if(!dicRougeTechLevel.has(o.techId)) dicRougeTechLevel.set(o.techId, []);
dicRougeTechLevel.get(o.techId)?.push(_.pick(o, Object.keys(DicRougeTechCircleKeys)));
});
arr = undefined;
}

View File

@@ -0,0 +1,22 @@
/**
* 试炼类型配置表
*/
export interface DicRougeType {
readonly id: number;
readonly type: number; // 试炼类型
readonly grade: number; // 共有多少难度
}
export const dicRougeType = new Map<number, DicRougeType>();
export function loadRougeType() {
dicRougeType.clear();
// let arr = readFileAndParse(FILENAME.DIC_ROUGE_TYPE);
// arr.forEach(o => {
// dicRougeType.set(o.type, o);
// });
// arr = undefined;
}

View File

@@ -0,0 +1,41 @@
/**
* 试炼难度配置表
*/
import { parseGoodStr, readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
import { RewardInter } from '../interface';
export interface DicRougeTypeGrade {
readonly id: number;
readonly type: number; // 试炼类型
readonly gradeIndex: number; // 难度
readonly lvLimit: number; // 等级限制
readonly limitId: number; //解锁需要的前置id
readonly buyRewardPlan: number; // 该试炼给的英灵奖励方案dic_spiritPlan的id
readonly layerCount: number; // 共有多少层
readonly layerPlan: number; // 每一层的配置dicRougeLayerPlan的planId
readonly challengePlan: number; // 这个试炼会随机出的挑战关卡的池子
readonly randomEventPlan: number; // 该试炼随机事件的随机池方案
readonly firstReward: RewardInter[]; // 首通奖励
readonly heroValue: number;
}
export const dicRougeTypeGrade = new Map<string, DicRougeTypeGrade>();
export const dicRougeTypeGradeById = new Map<number, DicRougeTypeGrade>();
export function loadRougeTypeGrade() {
dicRougeTypeGrade.clear();
dicRougeTypeGradeById.clear();
let arr = readFileAndParse(FILENAME.DIC_ROUGE_TYPE_GRADE);
arr.forEach(o => {
o.firstReward = parseGoodStr(o.firstReward);
dicRougeTypeGrade.set(o.type + '_' + o.gradeIndex, o);
dicRougeTypeGradeById.set(o.id, o);
});
arr = undefined;
}

View File

@@ -0,0 +1,28 @@
/**
* 英灵随机奖励配置表
*/
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
export interface DicSpiritPlan {
readonly id: number;
readonly planId: number;
readonly spiritId: number;
readonly weight: number;
}
export const dicSpiritPlan = new Map<number, DicSpiritPlan[]>();
export function loadSpiritPlan() {
dicSpiritPlan.clear();
let arr = readFileAndParse(FILENAME.DIC_SPIRIT_PLAN);
arr.forEach(o => {
if (!dicSpiritPlan.has(o.planId)) dicSpiritPlan.set(o.planId, []);
dicSpiritPlan.get(o.planId).push(o);
});
arr = undefined;
}

View File

@@ -1,5 +1,8 @@
// 一些通用的interface定义
import { RougelikeCardPara } from "../db/RougelikeCard";
import { RougelikeCharaPara } from "../db/RougelikeChara";
import { RougelikeCollectionType } from "../db/RougelikeCollection";
import { UserGuildType } from "../db/UserGuild";
export interface RewardInter {
@@ -39,6 +42,16 @@ export interface pvpEndParamInter {
underDamage: number;
}
export interface RougeDamageInter {
charaCode: string;
hp: number;
ap: number;
shield: number;
damage: number;
heal: number;
unserDamage: number;
}
export interface Uid {
uid: string;
sid: string;
@@ -70,3 +83,118 @@ export interface recycleSoulFastPara {
hid: number;
count: number;
}
export class CommonCard {
cardCode: string; // 卡code
cardId: number; // 卡ID
type: number; // 卡类型
charaId: number; // 装备在哪个角色上没有装备为0
lv: number; // 卡的等级
useCount: number;
constructor(card: RougelikeCardPara) {
this.cardCode = card?.cardCode || '';
this.cardId = card?.cardId || 0;
this.type = card?.type || 0;
this.charaId = card?.charaId || 0;
this.lv = card?.lv || 0;
this.useCount = card?.useCount || 0;
}
};
export class CommonChara {
charaCode: string; // 角色卡唯一id
seqId: number; // 排序
charaId: number; // 角色卡id
cards: { // 卡槽没有那个index表示没有解锁
index: number;
cardCode: string;
cardId: number; // 当为0的时候表示没有装入卡片
}[];
hp: number; // 当前hp
maxHp: number; // 最大hp
ap: number; // 当前怒气
shield: number;
roundSkill: number; // 玩家选择的回合技能卡
apSkill: number; // 玩家选择的怒气技能卡
constructor(chara: RougelikeCharaPara) {
this.charaCode = chara?.charaCode || '';
this.seqId = chara?.seqId || 0;
this.charaId = chara?.charaId || 0;
this.cards = chara?.cards || [];
this.hp = chara?.hp || 0;
this.maxHp = chara?.maxHp || 0;
this.ap = chara?.ap || 0;
this.shield = chara?.shield || 0;
this.roundSkill = chara?.roundSkill || 0;
this.apSkill = chara?.apSkill || 0;
}
};
export class CollectionReturnParam {
type: number = 0; // 类型
id: number = 0; // 图鉴id
num: number = 0; // 图鉴达成数量
received: number[] = []; // 是否领取
constructor(collect: RougelikeCollectionType) {
this.type = collect?.type || 0;
this.id = collect?.id || 0;
this.num = collect?.num || 0;
this.received = collect?.received || [];
}
}
export interface layerNode {
detailCode: string;
index: number; // 索引
nodeId: number; // 关卡id
preNodeIndexs: number[]; // 连线的关卡,填上一层节点的索引
type: number; // 类型
isChoose: number; // 玩家选择,0-未选择1-选择
}
export interface CommonNode {
layer: number; // 层
layerNodes: layerNode[];
};
export interface WeightRecord {
originalWight?: number;
passiveRedWight?: number;
holyRedWight?: number;
authorAddWeight?: number;
passiveLableNum?: number;
passiveLableNumAddWeight?: number;
holyLableNum?: number;
holyLableNumAddWeight?: number;
finalWeight?: number;
}
export interface RewardOption {
optionIndex: number; // 第几个选项
rewardId: number; // 角色卡的id或特性卡的id或圣物的id
optionStatus: number; // 0-没有选择这个奖励 1-选择了这个奖励
passiveCardIds?: number[]; //高级学员自带特性卡
weightRecord?: WeightRecord //用于测试权重记录
}
export interface CommonReward {
rewards?: {
groupIndex: number; // 奖励的索引值
rewardType: number; // 奖励的类型 1-角色卡 2-特性卡 3-圣物
options?: RewardOption[]; // 奖励的选项,试炼币大概就不用了
groupStatus: number; // 组选择 0-未选择 1-已选择
chooseNum?: number; // 这一组总共能选的数量3选2
}[];
takeoutReward?: RewardInter[]; // 可以外带的奖励 id&count
score?: number; // 增加的积分
techScore?: number; // 增加的科技分
}
export interface SlotCard {
index: number; //卡槽标记
cardCode: string; //安装的特性卡唯一code
}

View File

@@ -80,11 +80,11 @@ export function genCode(len) {
return code;
}
/**
* 生成 len 长度的随机字符串
* @param len 长度
* @param radix 基数
*/
/**
* 生成 len 长度的随机字符串
* @param len 长度
* @param radix 基数
*/
export function generateStr(len: number, radix = 36) {
return `${csprng(len, radix)}`;
}
@@ -140,8 +140,8 @@ export function decodeIdCntArrayStr(str: string, multi: number) {
* @param proTime 之后的时间
*/
export function deltaDays(preTime: Date, proTime: Date, useNaturalZero = false): number {
let beginZeroPoint = getZeroPointOfTimeD(preTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero? 0: REFRESH_TIME);
let endZeroPoint = getZeroPointOfTimeD(proTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero? 0: REFRESH_TIME);
let beginZeroPoint = getZeroPointOfTimeD(preTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero ? 0 : REFRESH_TIME);
let endZeroPoint = getZeroPointOfTimeD(proTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero ? 0 : REFRESH_TIME);
return moment(endZeroPoint).diff(moment(beginZeroPoint), "days");
}
@@ -227,7 +227,7 @@ export function getRandSingleIndex(len: number) {
*/
export function getRandEelmWithWeight<T extends { weight: number }>(randomList: T[]): { dic: T, index: number } {
let len = randomList.reduce((pre, cur) => {
return pre + (cur.weight||0);
return pre + (cur.weight || 0);
}, 0);
let index = Math.floor(Math.random() * len);
let result = { dic: null, index: -1 };
@@ -243,6 +243,45 @@ export function getRandEelmWithWeight<T extends { weight: number }>(randomList:
return result
}
export function getRandEelmWithWeightAndNum<T extends { weight: number }>(randomList: T[], num: number): { dic: T, index: number }[] {
let result: { dic: T, index: number }[] = [];
let remainingList = randomList.slice(); // Make a copy of randomList to work with
for (let n = 0; n < Math.min(num, randomList.length); n++) {
if (remainingList.length === 0) {
// If there are no more elements to choose from, exit the loop
break;
}
let len = remainingList.reduce((pre, cur) => {
return pre + (cur.weight || 0);
}, 0);
let index = Math.floor(Math.random() * len);
let found = false;
for (let i = 0; i < remainingList.length; i++) {
let { weight = 0 } = remainingList[i];
if (index < weight) {
result.push({ dic: remainingList[i], index: randomList.indexOf(remainingList[i]) });
remainingList.splice(i, 1); // Remove the selected element from the list
found = true;
break;
}
index -= weight;
}
if (!found) {
// In case the index exceeds the weights, add a default value
result.push({ dic: null, index: -1 });
}
}
return result;
}
/**
* 不改变原数组长度,将内部元素打乱
* @param source
@@ -271,10 +310,12 @@ export function getRandValue(base: number, ratio: number, decimal = 2): number {
*/
export function getRandValueByMinMax(min: number, max: number, decimal = 2): number {
let pow = Math.pow(10, decimal);
return Math.floor((min + (max - min) * Math.random()) * pow)/pow;
return Math.floor((min + (max - min) * Math.random()) * pow) / pow;
}
export function resResult<T>(status: { code: number, simStr: string }, data: T = <T>{}, customMsg = ''): { code: number, msg: string, data: T } {
const { code, simStr } = status;
if (code !== STATUS.SUCCESS.code) {
@@ -349,7 +390,7 @@ export const cal = {
export function getDecimalCnt(num: number) {
let str = num.toString();
return str.split('.')[1]? str.split('.')[1].length: 0;
return str.split('.')[1] ? str.split('.')[1].length : 0;
}
//计算公式
@@ -371,9 +412,9 @@ export function getDecimalCnt(num: number) {
// }
// }
export function ratioReward(reward: {id: number, count: number}[], ratio: number): {id: number, count: number}[] {
export function ratioReward(reward: { id: number, count: number }[], ratio: number): { id: number, count: number }[] {
return reward.map(cur => {
return {id: cur.id, count: cur.count * ratio}
return { id: cur.id, count: cur.count * ratio }
});
}
@@ -426,7 +467,7 @@ export function readFileAndParseJson(path: string) {
try {
let readResult = readFile(path);
return JSON.parse(readResult);
} catch(e) {
} catch (e) {
throw new Error(`connectors.json 格式错误:${(<Error>e).message}`);
}
}
@@ -462,9 +503,9 @@ export function readServerNameFileList() {
export function readWordTxt(fileName: string) {
try {
let file = fs.readFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`)).toString('utf8').replace(/^\uFEFF/, '');
let file = fs.readFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`)).toString('utf8').replace(/^\uFEFF/, '');
return file;
} catch(e) {
} catch (e) {
console.log(e)
return null
}
@@ -472,18 +513,18 @@ export function readWordTxt(fileName: string) {
export function writeWordTxt(fileName: string, words: string) {
try {
let file = fs.writeFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`), words);
let file = fs.writeFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`), words);
return file;
} catch(e) {
} catch (e) {
return null
}
}
export function readTsFile(fileName: string) {
try {
let file = fs.readFileSync(path.resolve(__dirname, `../pubUtils/${fileName}.js`)).toString('utf8').replace(/^\uFEFF/, '');
let file = fs.readFileSync(path.resolve(__dirname, `../pubUtils/${fileName}.js`)).toString('utf8').replace(/^\uFEFF/, '');
return file;
} catch(e) {
} catch (e) {
return null
}
}
@@ -492,7 +533,7 @@ export function readFileAndParse(fileName: string) {
try {
let readResult = readJsonFile(fileName);
return JSON.parse(readResult);
} catch(e) {
} catch (e) {
throw new Error(`${fileName}格式错误:${(<Error>e).message}`);
}
}
@@ -500,11 +541,11 @@ export function readFileAndParse(fileName: string) {
export function readWarJsonFileAndParse() {
let warJsons = readWarJsonFileList();
let result = [];
for(let { name, str } of warJsons) {
for (let { name, str } of warJsons) {
try {
let json = JSON.parse(str);
result.push(json);
} catch(e) {
} catch (e) {
throw new Error(`${name}格式错误:${(<Error>e).message}`);
}
}
@@ -622,7 +663,7 @@ export function checkRoleIsRobot(roleId: string) {
// 将一般的roleId转为带_r的
export function makeRobotId(roleId: string, sysType?: ROBOT_SYS_TYPE) {
if(sysType) {
if (sysType) {
return `${sysType}|${roleId}_r`;
} else {
return `${roleId}_r`;
@@ -631,7 +672,7 @@ export function makeRobotId(roleId: string, sysType?: ROBOT_SYS_TYPE) {
// 获取来源系统
export function getRobotSysType(roleId: string) {
let type = roleId.split('|')[0];
if(isNaN(parseInt(type))) {
if (isNaN(parseInt(type))) {
return 0
} else {
return parseInt(type);
@@ -658,13 +699,13 @@ export function splitString(dataString: string, key: string) {
export function isTimestamp(time: number, len = 10) {
if(!isNumber(time)) return false;
if(time.toString().length != len) return false;
if (!isNumber(time)) return false;
if (time.toString().length != len) return false;
return true;
}
export function getReasonByWarType(warType: number) {
switch(warType) {
switch (warType) {
case WAR_TYPE.NORMAL:
return ITEM_CHANGE_REASON.NORMAL_BATTLE_END;
case WAR_TYPE.VESTIGE:
@@ -714,49 +755,49 @@ export function getReasonByWarType(warType: number) {
}
export function getWarTypeName(warType: number) {
switch(warType) {
case WAR_TYPE.NORMAL: return '主线';
case WAR_TYPE.VESTIGE: return '支线';
case WAR_TYPE.EVENT: return '事件';
case WAR_TYPE.DAILY: return '每日';
case WAR_TYPE.EXPEDITION: return '远征';
case WAR_TYPE.MYSTERY: return '秘境';
case WAR_TYPE.COM_BATTLE: return '寻宝';
case WAR_TYPE.TOWER: return '镇念塔';
case WAR_TYPE.PVP: return '竞技';
case WAR_TYPE.GUILD_ACTIVITY: return '军团活动';
case WAR_TYPE.GUILD_TRAIN: return '训练场';
case WAR_TYPE.MAIN_ELITE: return '主线精英';
case WAR_TYPE.BRANCH_ELITE: return '梦魇支线';
case WAR_TYPE.BRANCH: return '支线';
case WAR_TYPE.ACT_TREASURE_HUNT: return '运营活动-神州探秘';
case WAR_TYPE.ACT_SELF_SHOP: return '运营活动-糜家商队';
case WAR_TYPE.ACT_DAILY_GK: return '运营活动-节日活动';
case WAR_TYPE.ACT_NEW_HERO_GK: return '新武将活动关卡';
case WAR_TYPE.TRY: return '试用关卡';
case WAR_TYPE.BOSS: return '演武台';
switch (warType) {
case WAR_TYPE.NORMAL: return '主线';
case WAR_TYPE.VESTIGE: return '支线';
case WAR_TYPE.EVENT: return '事件';
case WAR_TYPE.DAILY: return '每日';
case WAR_TYPE.EXPEDITION: return '远征';
case WAR_TYPE.MYSTERY: return '秘境';
case WAR_TYPE.COM_BATTLE: return '寻宝';
case WAR_TYPE.TOWER: return '镇念塔';
case WAR_TYPE.PVP: return '竞技';
case WAR_TYPE.GUILD_ACTIVITY: return '军团活动';
case WAR_TYPE.GUILD_TRAIN: return '训练场';
case WAR_TYPE.MAIN_ELITE: return '主线精英';
case WAR_TYPE.BRANCH_ELITE: return '梦魇支线';
case WAR_TYPE.BRANCH: return '支线';
case WAR_TYPE.ACT_TREASURE_HUNT: return '运营活动-神州探秘';
case WAR_TYPE.ACT_SELF_SHOP: return '运营活动-糜家商队';
case WAR_TYPE.ACT_DAILY_GK: return '运营活动-节日活动';
case WAR_TYPE.ACT_NEW_HERO_GK: return '新武将活动关卡';
case WAR_TYPE.TRY: return '试用关卡';
case WAR_TYPE.BOSS: return '演武台';
}
}
}
/**
* 一群人分总数固定的东西
* @param total 总数
* @param max 每个人能拿到的最大数量
* @param memberCnt 人数
*/
export function getRandResultByMember(total: number, max: number, memberCnt: number) {
let arr: number[] = [];
for(let i = 1; i <= memberCnt; i++) {
let randMax = total > max? max: total;
let randMin = total - (memberCnt - i) * max;
if(randMin < 0) randMin = 0;
if(randMin > max) randMin = max;
let rand = getRandValueByMinMax(randMin, randMax + 1, 0);
arr.push(rand);
total -= rand;
}
return { arr, remain: total }
}
/**
* 一群人分总数固定的东西
* @param total 总数
* @param max 每个人能拿到的最大数量
* @param memberCnt 人数
*/
export function getRandResultByMember(total: number, max: number, memberCnt: number) {
let arr: number[] = [];
for (let i = 1; i <= memberCnt; i++) {
let randMax = total > max ? max : total;
let randMin = total - (memberCnt - i) * max;
if (randMin < 0) randMin = 0;
if (randMin > max) randMin = max;
let rand = getRandValueByMinMax(randMin, randMax + 1, 0);
arr.push(rand);
total -= rand;
}
return { arr, remain: total }
}
//数据格式转换'id&数量|id&数量|' ->> Array<RewardInter> 老资源格式
export function stringToRewardInter(rewardStr: string): Array<RewardInter> {
@@ -773,16 +814,16 @@ export function stringToRewardInter(rewardStr: string): Array<RewardInter> {
}
export function addToMap<T>(map: Map<T, number>, id: T, value: number) {
if(!map.has(id)) {
if (!map.has(id)) {
map.set(id, value);
} else {
map.set(id, map.get(id) + value);
}
}
export function arrToMap<T>(arr: T[], getKey: (obj: T) => number|string): Map<number, T> {
export function arrToMap<T>(arr: T[], getKey: (obj: T) => number | string): Map<number, T> {
let map = new Map();
for(let obj of arr) {
for (let obj of arr) {
let key = getKey(obj);
map.set(key, obj);
}
@@ -841,12 +882,12 @@ export function getGachaRemainFloor(gachaId: number, userFloor: Floor[]) {
let dicGacha = gameData.gacha.get(gachaId);
if(dicGacha.gachaType != GACHA_TYPE.NORMAL && dicGacha.gachaType != GACHA_TYPE.ACTIVITY && dicGacha.gachaType != GACHA_TYPE.TAUTOR) return 0;
for(let floorId of dicGacha.floor) {
for (let floorId of dicGacha.floor) {
let dicGachaFloor = gameData.gachaFloor.get(floorId);
if(dicGachaFloor && dicGachaFloor.floorType == GACHA_FLOOR_TYPE.MAIN_FLOOR) {
if (dicGachaFloor && dicGachaFloor.floorType == GACHA_FLOOR_TYPE.MAIN_FLOOR) {
let myFloor = userFloor.find(cur => cur.id == floorId);
return dicGachaFloor.param - (myFloor?.count||0);
return dicGachaFloor.param - (myFloor?.count || 0);
}
}
return 0
@@ -859,7 +900,7 @@ export function isDevelopEnv(env: string) {
export function getArrayOfNumber(len: number) {
let arr: number[] = [];
for(let i = 1; i <= len; i++) arr.push(i);
for (let i = 1; i <= len; i++) arr.push(i);
return arr;
}
@@ -891,3 +932,16 @@ export function swapFields(originObj: object, targetObj: object, fieldsToSwap: s
targetObj[field] = temp;
}
}
export function compareNumberArray(arrA: number[], arrB: number[]) {
if(arrA.length != arrB.length) return false;
let sortArrA: number[] = [], sortArrB: number[] = [];
for(let a of arrA) sortArrA.push(a);
for(let b of arrB) sortArrB.push(b);
sortArrA.sort();
sortArrB.sort();
for(let i = 0; i < sortArrA.length; i++) {
if(sortArrA[i] != sortArrB[i]) return false;
}
return true;
}

View File

@@ -341,5 +341,12 @@
"sendName": "学宫驿使",
"content": "亲爱的百家传人,您在本期集会活动中有高级签到的奖励未领取,现发送至邮箱,请查收",
"time": 2160
},
{
"id": 49,
"title": "&",
"sendName": "学宫驿使",
"content": "亲爱的百家传人,您在稷下学宫上周的学分进度奖励尚未领取,现发送至邮箱,请查收",
"time": 720
}
]

View File

@@ -0,0 +1,56 @@
[
{
"id": 1,
"questionMarkPlanId": 1,
"questionMarkIndex": 1,
"nodeType": 1,
"name": "普通关",
"param": "201&",
"weight": 1
},
{
"id": 2,
"questionMarkPlanId": 1,
"questionMarkIndex": 1,
"nodeType": 1,
"name": "普通关",
"param": "202&",
"weight": 1
},
{
"id": 3,
"questionMarkPlanId": 1,
"questionMarkIndex": 2,
"nodeType": 2,
"name": "精英关",
"param": "203&",
"weight": 1
},
{
"id": 4,
"questionMarkPlanId": 1,
"questionMarkIndex": 2,
"nodeType": 2,
"name": "精英关",
"param": "107&",
"weight": 3
},
{
"id": 5,
"questionMarkPlanId": 1,
"questionMarkIndex": 3,
"nodeType": 7,
"name": "商店",
"param": "&",
"weight": 3
},
{
"id": 6,
"questionMarkPlanId": 1,
"questionMarkIndex": 4,
"nodeType": 0,
"name": "随机事件",
"param": "&",
"weight": 3
}
]

View File

@@ -0,0 +1,58 @@
[
{
"id": 1,
"authorType": 1,
"name": "儒家",
"icon": "tubiao_rujia",
"holyCard": 20001
},
{
"id": 2,
"authorType": 2,
"name": "道家",
"icon": "tubiao_daojia",
"holyCard": 20002
},
{
"id": 3,
"authorType": 3,
"name": "墨家",
"icon": "tubiao_mojia",
"holyCard": 20003
},
{
"id": 4,
"authorType": 4,
"name": "法家",
"icon": "tubiao_fajia",
"holyCard": 20004
},
{
"id": 5,
"authorType": 5,
"name": "医家",
"icon": "tubiao_yijia",
"holyCard": 20005
},
{
"id": 6,
"authorType": 6,
"name": "兵家",
"icon": "tubiao_bingjia",
"holyCard": 20006
},
{
"id": 7,
"authorType": 7,
"name": "阴阳",
"icon": "tubiao_yinyangjia",
"holyCard": 20007
},
{
"id": 8,
"authorType": 8,
"name": "纵横",
"icon": "tubiao_zonghengjia",
"holyCard": 20008
}
]

View File

@@ -0,0 +1,74 @@
[
{
"id": 1,
"challengeId": 1,
"effectId": "10010103&",
"content": "<color=#2e190a>接下来2场战斗敌军攻击提高30%</color>",
"condition": 2,
"reward": "31002&10"
},
{
"id": 2,
"challengeId": 2,
"effectId": "10020101&",
"content": "<color=#2e190a>接下来2场战斗敌军破格+10</color>",
"condition": 2,
"reward": "31002&20"
},
{
"id": 3,
"challengeId": 3,
"effectId": "10030603&",
"content": "<color=#2e190a>接下来2场战斗我军学员物防降低30%</color>",
"condition": 2,
"reward": "31002&30"
},
{
"id": 4,
"challengeId": 4,
"effectId": "10040501&",
"content": "<color=#2e190a>接下来1场战斗我军学员暴击-10</color>",
"condition": 1,
"reward": "31002&40"
},
{
"id": 5,
"challengeId": 5,
"effectId": "10050203&",
"content": "<color=#2e190a>接下来2场战斗战斗结束后我军学员生命不低于80%</color>",
"condition": 2,
"reward": "31002&50"
},
{
"id": 6,
"challengeId": 6,
"effectId": "10060102&",
"content": "<color=#2e190a>接下来2场战斗战斗过程中我军学员无法使用怒气技</color>",
"condition": 2,
"reward": "31002&60"
},
{
"id": 7,
"challengeId": 7,
"effectId": "10070102&",
"content": "<color=#2e190a>接下来2场战斗战斗过程中我军学员无法使用回合技</color>",
"condition": 2,
"reward": "31002&70"
},
{
"id": 8,
"challengeId": 8,
"effectId": "10080102&",
"content": "<color=#2e190a>接下来2次选择特性卡时可选择的卡片数量少1</color>",
"condition": 2,
"reward": "31002&80"
},
{
"id": 9,
"challengeId": 9,
"effectId": "10090102&",
"content": "<color=#2e190a>接下来2场战斗每场战斗只能上阵2名学员</color>",
"condition": 2,
"reward": "31002&90"
}
]

View File

@@ -0,0 +1,56 @@
[
{
"id": 1,
"planId": 1,
"challengeId": 1,
"weight": 1
},
{
"id": 2,
"planId": 2,
"challengeId": 2,
"weight": 1
},
{
"id": 3,
"planId": 3,
"challengeId": 3,
"weight": 1
},
{
"id": 4,
"planId": 4,
"challengeId": 4,
"weight": 1
},
{
"id": 5,
"planId": 5,
"challengeId": 5,
"weight": 1
},
{
"id": 6,
"planId": 6,
"challengeId": 6,
"weight": 1
},
{
"id": 7,
"planId": 7,
"challengeId": 7,
"weight": 1
},
{
"id": 8,
"planId": 8,
"challengeId": 8,
"weight": 1
},
{
"id": 9,
"planId": 9,
"challengeId": 9,
"weight": 1
}
]

View File

@@ -0,0 +1,114 @@
[
{
"id": 40001,
"heroId": 7001,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40002,
"heroId": 7002,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40003,
"heroId": 7003,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40004,
"heroId": 7004,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40005,
"heroId": 7005,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40006,
"heroId": 7006,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40007,
"heroId": 7007,
"charaType": 1,
"initial": 1,
"initCardCnt": 0,
"recruitConsume": 10
},
{
"id": 40008,
"heroId": 7011,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40009,
"heroId": 7012,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40010,
"heroId": 7013,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40011,
"heroId": 7014,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40012,
"heroId": 7015,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40013,
"heroId": 7016,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
},
{
"id": 40014,
"heroId": 7017,
"charaType": 2,
"initial": 0,
"initCardCnt": 2,
"recruitConsume": 20
}
]

View File

@@ -0,0 +1,176 @@
[
{
"id": 1,
"planId": 1,
"cardId": 40001,
"weight": 1
},
{
"id": 2,
"planId": 1,
"cardId": 40002,
"weight": 1
},
{
"id": 3,
"planId": 1,
"cardId": 40003,
"weight": 1
},
{
"id": 4,
"planId": 1,
"cardId": 40004,
"weight": 1
},
{
"id": 5,
"planId": 1,
"cardId": 40005,
"weight": 1
},
{
"id": 6,
"planId": 1,
"cardId": 40006,
"weight": 1
},
{
"id": 7,
"planId": 1,
"cardId": 40007,
"weight": 1
},
{
"id": 8,
"planId": 2,
"cardId": 40001,
"weight": 1
},
{
"id": 9,
"planId": 2,
"cardId": 40002,
"weight": 1
},
{
"id": 10,
"planId": 2,
"cardId": 40003,
"weight": 1
},
{
"id": 11,
"planId": 2,
"cardId": 40004,
"weight": 1
},
{
"id": 12,
"planId": 2,
"cardId": 40005,
"weight": 1
},
{
"id": 13,
"planId": 2,
"cardId": 40006,
"weight": 1
},
{
"id": 14,
"planId": 2,
"cardId": 40007,
"weight": 1
},
{
"id": 15,
"planId": 2,
"cardId": 40008,
"weight": 1
},
{
"id": 16,
"planId": 2,
"cardId": 40009,
"weight": 1
},
{
"id": 17,
"planId": 2,
"cardId": 40010,
"weight": 1
},
{
"id": 18,
"planId": 2,
"cardId": 40011,
"weight": 1
},
{
"id": 19,
"planId": 2,
"cardId": 40012,
"weight": 1
},
{
"id": 20,
"planId": 2,
"cardId": 40013,
"weight": 1
},
{
"id": 21,
"planId": 2,
"cardId": 40014,
"weight": 1
},
{
"id": 22,
"planId": 3,
"cardId": 40007,
"weight": 1
},
{
"id": 23,
"planId": 3,
"cardId": 40008,
"weight": 1
},
{
"id": 24,
"planId": 3,
"cardId": 40009,
"weight": 1
},
{
"id": 25,
"planId": 3,
"cardId": 40010,
"weight": 1
},
{
"id": 26,
"planId": 3,
"cardId": 40011,
"weight": 1
},
{
"id": 27,
"planId": 3,
"cardId": 40012,
"weight": 1
},
{
"id": 28,
"planId": 3,
"cardId": 40013,
"weight": 1
},
{
"id": 29,
"planId": 3,
"cardId": 40014,
"weight": 1
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,422 @@
[
{
"id": 1001,
"effectType": 1001,
"kind": 1,
"param": "count&基础属性Id&num",
"name": "挑战效果",
"info": "接下来X场战斗敌军属性id提高num",
"conditon": "count",
"tips": "num填多少表示num%"
},
{
"id": 1002,
"effectType": 1002,
"kind": 1,
"param": "count&次级属性Id&num",
"name": "挑战效果",
"info": "接下来X场战斗敌军属性id提高num",
"conditon": "count",
"tips": "num填多少表示对饮的次级属性直接+num。最后以1000转化为1%计算"
},
{
"id": 1003,
"effectType": 1003,
"kind": 1,
"param": "count&基础属性Id&num",
"name": "挑战效果",
"info": "接下来X场战斗我军学员属性id降低num",
"conditon": "count",
"tips": "num填多少表示num%"
},
{
"id": 1004,
"effectType": 1004,
"kind": 1,
"param": "count&次级属性Id&num",
"name": "挑战效果",
"info": "接下来X场战斗我军学员属性id降低num",
"conditon": "count",
"tips": "num填多少表示对饮的次级属性直接+num。最后以1000转化为1%计算"
},
{
"id": 1005,
"effectType": 1005,
"kind": 1,
"param": "count&num",
"name": "挑战效果",
"info": "接下来X场战斗战斗结束后我军学员生命不低于num",
"conditon": "count",
"tips": "num填多少表示num%"
},
{
"id": 1006,
"effectType": 1006,
"kind": 1,
"param": "count&",
"name": "挑战效果",
"info": "接下来X场战斗战斗过程中我军学员无法使用怒气技",
"conditon": "count",
"tips": "&"
},
{
"id": 1007,
"effectType": 1007,
"kind": 1,
"param": "count&",
"name": "挑战效果",
"info": "接下来X场战斗战斗过程中我军学员无法使用回合技",
"conditon": "count",
"tips": "&"
},
{
"id": 1008,
"effectType": 1008,
"kind": 1,
"param": "count&",
"name": "挑战效果",
"info": "接下来X次选择特性卡时可选择的卡片数量少1",
"conditon": "count",
"tips": "&"
},
{
"id": 1009,
"effectType": 1009,
"kind": 1,
"param": "count&",
"name": "挑战效果",
"info": "接下来X场战斗每场战斗只能上阵2名学员",
"conditon": "count",
"tips": "&"
},
{
"id": 2001,
"effectType": 2001,
"kind": 2,
"param": "value&",
"name": "圣物效果",
"info": "每场战斗结束后学员恢复血量上限X%的生命",
"conditon": "&",
"tips": "&"
},
{
"id": 2002,
"effectType": 2002,
"kind": 2,
"param": "count&",
"name": "圣物效果",
"info": "获得该圣物时所有学员立刻解锁X个特性槽",
"conditon": "&",
"tips": "&"
},
{
"id": 2003,
"effectType": 2003,
"kind": 2,
"param": "num&count",
"name": "圣物效果",
"info": "获得该圣物时随机解锁X个学员的Y个特性槽",
"conditon": "&",
"tips": "&"
},
{
"id": 2004,
"effectType": 2004,
"kind": 2,
"param": "type&value",
"name": "圣物效果",
"info": "战斗胜利后获得的试炼币增加X",
"conditon": "&",
"tips": "type=1 固定值增加\r\ntype=2 百分比增加"
},
{
"id": 2005,
"effectType": 2005,
"kind": 2,
"param": "count&id&value",
"name": "圣物效果",
"info": "每累积X个试炼币全员基础属性id提高Y",
"conditon": "&",
"tips": "id属性id value填多少表示value%"
},
{
"id": 2006,
"effectType": 2006,
"kind": 2,
"param": "count&",
"name": "圣物效果",
"info": "随机升级X个已装备的特性",
"conditon": "&",
"tips": "&"
},
{
"id": 2007,
"effectType": 2007,
"kind": 2,
"param": "authorType&value",
"name": "圣物效果",
"info": "获得圣物时X流派特性卡的权重增加Y",
"conditon": "&",
"tips": "authorType百家流派"
},
{
"id": 2008,
"effectType": 2008,
"kind": 2,
"param": "属性id&value",
"name": "圣物效果",
"info": "进入战斗后所有敌军扣减X的某基础属性id",
"conditon": "&",
"tips": "num填多少表示num%"
},
{
"id": 2009,
"effectType": 2009,
"kind": 2,
"param": "&",
"name": "圣物效果",
"info": "非首领敌人战斗失败视为胜利,并且满血复活",
"conditon": "&",
"tips": "&"
},
{
"id": 2010,
"effectType": 2010,
"kind": 2,
"param": "num&count",
"name": "圣物效果",
"info": "战斗胜利后若有学员死亡则满血复活X名死亡学员",
"conditon": "&",
"tips": "&"
},
{
"id": 2011,
"effectType": 2011,
"kind": 2,
"param": "discount&",
"name": "圣物效果",
"info": "试炼商店中所有商品X折出售",
"conditon": "&",
"tips": "&"
},
{
"id": 2012,
"effectType": 2012,
"kind": 2,
"param": "level&",
"name": "圣物效果",
"info": "获得该圣物时立即升级所有X星特性卡",
"conditon": "&",
"tips": "&"
},
{
"id": 2013,
"effectType": 2013,
"kind": 2,
"param": "level&",
"name": "圣物效果",
"info": "下次选择特性卡时必定出现X星特性卡",
"conditon": "&",
"tips": "&"
},
{
"id": 2014,
"effectType": 2014,
"kind": 2,
"param": "num&",
"name": "圣物效果",
"info": "下次选择特性卡时可多选X张特性卡",
"conditon": "&",
"tips": "&"
},
{
"id": 2015,
"effectType": 2015,
"kind": 2,
"param": "count&",
"name": "圣物效果",
"info": "获得该圣物后随机修复X个已损毁的圣物",
"conditon": "&",
"tips": "&"
},
{
"id": 2017,
"effectType": 2017,
"kind": 2,
"param": "value&",
"name": "圣物效果",
"info": "休整点额外恢复X%的生命",
"conditon": "&",
"tips": "&"
},
{
"id": 2018,
"effectType": 2018,
"kind": 2,
"param": "discount&",
"name": "圣物效果",
"info": "休整点特训价格X折",
"conditon": "&",
"tips": "&"
},
{
"id": 2019,
"effectType": 2019,
"kind": 2,
"param": "count&id&value",
"name": "圣物效果",
"info": "每累积X个试炼币全员次级属性id提高Y",
"conditon": "&",
"tips": "次级id属性id num填多少表示对饮的次级属性直接+num。最后以1000转化为1%计算"
},
{
"id": 2020,
"effectType": 2020,
"kind": 2,
"param": "基础属性Id&num|基础属性Id&num",
"name": "圣物效果",
"info": "我军全员基础属性id1提高num属性id2提高num",
"conditon": "&",
"tips": "num填多少表示num%"
},
{
"id": 2021,
"effectType": 2021,
"kind": 2,
"param": "次级属性Id&num|次级属性Id&num",
"name": "圣物效果",
"info": "我军全员次级属性id1提高num属性id2提高num",
"conditon": "&",
"tips": "num填多少表示对饮的次级属性直接+num。最后以1000转化为1%计算"
},
{
"id": 2022,
"effectType": 2022,
"kind": 2,
"param": "num&属性id&value",
"name": "圣物效果",
"info": "每场战斗第X回合后全员属性id提高Y",
"conditon": "&",
"tips": "num填多少表示num%"
},
{
"id": 2023,
"effectType": 2023,
"kind": 2,
"param": "X-1号位置",
"name": "圣物效果",
"info": "拥有该圣物时所有角色解锁X号位置的特性槽",
"conditon": "&",
"tips": "从0开始"
},
{
"id": 3001,
"effectType": 3001,
"kind": 3,
"param": "基础属性Id&num|基础属性Id&num",
"name": "法阵效果",
"info": "我军全员基础属性id1提高num属性id2提高num",
"conditon": "&",
"tips": "num填多少表示num%"
},
{
"id": 3002,
"effectType": 3002,
"kind": 3,
"param": "次级属性Id&num|次级属性Id&num",
"name": "法阵效果",
"info": "我军全员次级属性id1提高num属性id2提高num",
"conditon": "&",
"tips": "num填多少表示对饮的次级属性直接+num。最后以1000转化为1%计算"
},
{
"id": 3003,
"effectType": 3003,
"kind": 3,
"param": "可获得的流派圣物id池",
"name": "法阵效果",
"info": "选择百家流派后获得1个流派专属圣物XX圣物池",
"conditon": "&",
"tips": "填写圣物池 给玩家选择的流派对应的流派圣物"
},
{
"id": 3004,
"effectType": 3004,
"kind": 3,
"param": "cout&skillType",
"name": "法阵效果",
"info": "装备X个同百家流派特性的角色可额外选择流派专属Y技能类型",
"conditon": "&",
"tips": "技能类型1怒气技 技能类型2回合技"
},
{
"id": 3005,
"effectType": 3005,
"kind": 3,
"param": "cout&",
"name": "法阵效果",
"info": "初始获得X个试炼币",
"conditon": "&",
"tips": "&"
},
{
"id": 3006,
"effectType": 3006,
"kind": 3,
"param": "value&",
"name": "法阵效果",
"info": "休整点恢复额外恢复血量上限X%的生命",
"conditon": "&",
"tips": "&"
},
{
"id": 3007,
"effectType": 3007,
"kind": 3,
"param": "nodeType&nodeType|X",
"name": "法阵效果",
"info": "某些nodeType后获得的试炼币增加X%",
"conditon": "&",
"tips": "&"
},
{
"id": 3008,
"effectType": 3008,
"kind": 3,
"param": "奖励type&value",
"name": "法阵效果",
"info": "选择某种奖励type时可消耗X试炼币重置1次",
"conditon": "&",
"tips": "type=1角色卡 type=2 特性卡 type=3 圣物"
},
{
"id": 3009,
"effectType": 3009,
"kind": 3,
"param": "value&",
"name": "法阵效果",
"info": "休整点特训价格降低X%",
"conditon": "&",
"tips": "&"
},
{
"id": 3010,
"effectType": 3010,
"kind": 3,
"param": "&",
"name": "法阵效果",
"info": "挑战boss关前所有角色怒气值充满",
"conditon": "&",
"tips": "&"
},
{
"id": 3011,
"effectType": 3011,
"kind": 3,
"param": "&",
"name": "法阵效果",
"info": "挑战boss关前所有角色生命恢复至100%",
"conditon": "&",
"tips": "&"
}
]

View File

@@ -0,0 +1,155 @@
[
{
"id": 1,
"randomEventId": 1,
"optionGroup": 1,
"index": 1,
"text": "深入洞穴",
"afterGroup": 2,
"holyCardPlan": 0
},
{
"id": 2,
"randomEventId": 1,
"optionGroup": 1,
"index": 2,
"text": "止步于洞口",
"afterGroup": 3,
"holyCardPlan": 0
},
{
"id": 4,
"randomEventId": 1,
"optionGroup": 2,
"index": 1,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 5,
"randomEventId": 1,
"optionGroup": 2,
"index": 2,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 6,
"randomEventId": 1,
"optionGroup": 2,
"index": 3,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 7,
"randomEventId": 1,
"optionGroup": 3,
"index": 1,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 8,
"randomEventId": 1,
"optionGroup": 3,
"index": 2,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 9,
"randomEventId": 1,
"optionGroup": 3,
"index": 3,
"text": "&",
"afterGroup": 4,
"holyCardPlan": 0
},
{
"id": 10,
"randomEventId": 1,
"optionGroup": 4,
"index": 1,
"text": "&",
"afterGroup": 5,
"holyCardPlan": 0
},
{
"id": 11,
"randomEventId": 1,
"optionGroup": 4,
"index": 2,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 1
},
{
"id": 12,
"randomEventId": 1,
"optionGroup": 4,
"index": 3,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 1
},
{
"id": 13,
"randomEventId": 1,
"optionGroup": 5,
"index": 1,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 2
},
{
"id": 14,
"randomEventId": 1,
"optionGroup": 5,
"index": 2,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 2
},
{
"id": 15,
"randomEventId": 1,
"optionGroup": 5,
"index": 3,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 2
},
{
"id": 16,
"randomEventId": 2,
"optionGroup": 6,
"index": 1,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 1
},
{
"id": 17,
"randomEventId": 2,
"optionGroup": 6,
"index": 2,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 1
},
{
"id": 18,
"randomEventId": 2,
"optionGroup": 6,
"index": 3,
"text": "&",
"afterGroup": 0,
"holyCardPlan": 1
}
]

View File

@@ -0,0 +1,542 @@
[
{
"id": 20001,
"name": "儒家圣物2",
"quality": 1,
"authorType": 1,
"imageName": "baowu10",
"seid": 31,
"effectId": "&",
"content": "进入战斗后学员在战斗开始时获得250点怒气怒气上限+500",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20002,
"name": "道家圣物2",
"quality": 1,
"authorType": 2,
"imageName": "baowu10",
"seid": 801,
"effectId": "&",
"content": "进入战斗后,学员移动+1",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20003,
"name": "墨家圣物2",
"quality": 1,
"authorType": 3,
"imageName": "baowu10",
"seid": 3601121,
"effectId": "&",
"content": "进入战斗后,学员获得初始护盾",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20004,
"name": "法家圣物2",
"quality": 1,
"authorType": 4,
"imageName": "baowu10",
"seid": 52203,
"effectId": "&",
"content": "进入战斗后,学员攻击+5%",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20005,
"name": "医家圣物2",
"quality": 1,
"authorType": 5,
"imageName": "baowu10",
"seid": 0,
"effectId": "20010101&",
"content": "每场战斗结束后学员恢复血量上限5%的生命",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20006,
"name": "兵家圣物2",
"quality": 1,
"authorType": 6,
"imageName": "baowu10",
"seid": 360401312,
"effectId": "&",
"content": "进入战斗后,攻击敌军时有概率眩晕敌军",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20007,
"name": "阴阳圣物2",
"quality": 1,
"authorType": 7,
"imageName": "baowu10",
"seid": 4121702311,
"effectId": "&",
"content": "进入战斗后敌军身上每有1个debuff防御降低",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20008,
"name": "纵横圣物2",
"quality": 1,
"authorType": 8,
"imageName": "baowu10",
"seid": 5400101711,
"effectId": "&",
"content": "进入战斗后,连携时回复怒气+50",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20009,
"name": "圣物9",
"quality": 2,
"authorType": 0,
"imageName": "baowu15",
"seid": 4110201411,
"effectId": "&",
"content": "进入战斗后,敌军防御降低-10%",
"useCount": 1,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20010,
"name": "圣物10",
"quality": 2,
"authorType": 0,
"imageName": "baowu19",
"seid": 4110201412,
"effectId": "&",
"content": "进入战斗后每5回合学员攻击提升100%",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20011,
"name": "圣物11",
"quality": 2,
"authorType": 0,
"imageName": "baowu12",
"seid": 0,
"effectId": "20020101&",
"content": "获得该圣物时所有学员立刻解锁1个特性槽",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20012,
"name": "圣物12",
"quality": 2,
"authorType": 0,
"imageName": "baowu9",
"seid": 0,
"effectId": "20030101&",
"content": "获得该圣物时随机解锁1个学员的特性槽",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20013,
"name": "圣物13",
"quality": 2,
"authorType": 0,
"imageName": "baowu1",
"seid": 0,
"effectId": "20040101&",
"content": "战斗胜利后获得的试炼币增加30%",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20014,
"name": "圣物14",
"quality": 2,
"authorType": 0,
"imageName": "baowu2",
"seid": 0,
"effectId": "20050101&",
"content": "每累积获得100个试炼币全员攻击提高2%",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20015,
"name": "圣物15",
"quality": 2,
"authorType": 0,
"imageName": "baowu3",
"seid": 0,
"effectId": "20060101&",
"content": "随机升级2个已装备的特性",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20016,
"name": "儒家圣物1",
"quality": 2,
"authorType": 1,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070101&",
"content": "获得儒家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20017,
"name": "道家圣物1",
"quality": 2,
"authorType": 2,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070201&",
"content": "获得道家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20018,
"name": "墨家圣物1",
"quality": 2,
"authorType": 3,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070301&",
"content": "获得墨家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20019,
"name": "法家圣物1",
"quality": 2,
"authorType": 4,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070401&",
"content": "获得法家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20020,
"name": "医家圣物1",
"quality": 2,
"authorType": 5,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070501&",
"content": "获得医家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20021,
"name": "兵家圣物1",
"quality": 2,
"authorType": 6,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070601&",
"content": "获得兵家流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20022,
"name": "阴阳圣物1",
"quality": 2,
"authorType": 7,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070701&",
"content": "获得阴阳流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20023,
"name": "纵横圣物1",
"quality": 2,
"authorType": 8,
"imageName": "baowu4",
"seid": 0,
"effectId": "20070801&",
"content": "获得纵横流派特性卡概率提高",
"useCount": 0,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20024,
"name": "圣物24",
"quality": 2,
"authorType": 0,
"imageName": "baowu15",
"seid": 0,
"effectId": "20080101&",
"content": "进入战斗后所有敌军扣减30%的生命触发3次后损毁",
"useCount": 3,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20025,
"name": "圣物25",
"quality": 3,
"authorType": 0,
"imageName": "baowu11",
"seid": 0,
"effectId": "20090101&",
"content": "非首领敌人战斗失败视为胜利并且满血复活生效1次后损毁",
"useCount": 1,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20026,
"name": "圣物26",
"quality": 2,
"authorType": 0,
"imageName": "baowu20",
"seid": 0,
"effectId": "20100101&",
"content": "战斗胜利后若有学员死亡则满血复活一名死亡学员触发1次后损毁",
"useCount": 1,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20027,
"name": "圣物27",
"quality": 2,
"authorType": 0,
"imageName": "baowu6",
"seid": 0,
"effectId": "20110101&",
"content": "试炼商店中所有商品7折出售",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20028,
"name": "圣物28",
"quality": 3,
"authorType": 0,
"imageName": "baowu7",
"seid": 0,
"effectId": "20120101&",
"content": "获得该圣物时立即升级所有1星特性卡",
"useCount": 0,
"label": 1,
"collectReward": "31002&50",
"purchasePrice": 10,
"getLimit": 1
},
{
"id": 20029,
"name": "圣物29",
"quality": 3,
"authorType": 0,
"imageName": "baowu5",
"seid": 0,
"effectId": "20130101&",
"content": "下次选择特性卡时必定出现2星特性卡触发1次后损毁",
"useCount": 1,
"label": 2,
"collectReward": "31002&50",
"purchasePrice": 20,
"getLimit": 1
},
{
"id": 20030,
"name": "圣物30",
"quality": 2,
"authorType": 0,
"imageName": "baowu13",
"seid": 0,
"effectId": "20140101&",
"content": "下次选择特性卡时可多选1张特性卡触发2次后损毁",
"useCount": 2,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20031,
"name": "圣物31",
"quality": 2,
"authorType": 0,
"imageName": "baowu14",
"seid": 0,
"effectId": "20150101&",
"content": "获得该圣物后随机修复2个已损毁的圣物",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 40,
"getLimit": 1
},
{
"id": 20032,
"name": "圣物33",
"quality": 2,
"authorType": 0,
"imageName": "baowu17",
"seid": 0,
"effectId": "20170101&",
"content": "休整点额外恢复10%的生命",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 40,
"getLimit": 1
},
{
"id": 20033,
"name": "圣物34",
"quality": 2,
"authorType": 0,
"imageName": "baowu18",
"seid": 0,
"effectId": "20180101&",
"content": "休整点特训价格降低20%",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
},
{
"id": 20034,
"name": "圣物35",
"quality": 2,
"authorType": 0,
"imageName": "baowu14",
"seid": 0,
"effectId": "20230101&",
"content": "<color=#2e190a>拥有该圣物时所有角色解锁1号位特性槽</color>",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 40,
"getLimit": 1
},
{
"id": 20035,
"name": "圣物36",
"quality": 2,
"authorType": 0,
"imageName": "baowu17",
"seid": 0,
"effectId": "20230102&",
"content": "<color=#2e190a>拥有该圣物时所有角色解锁2号位特性槽</color>",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 40,
"getLimit": 1
},
{
"id": 20036,
"name": "圣物37",
"quality": 2,
"authorType": 0,
"imageName": "baowu18",
"seid": 0,
"effectId": "20230103&",
"content": "<color=#2e190a>拥有该圣物时所有角色解锁3号位特性槽</color>",
"useCount": 0,
"label": 3,
"collectReward": "31002&50",
"purchasePrice": 30,
"getLimit": 1
}
]

View File

@@ -0,0 +1,404 @@
[
{
"id": 1,
"planId": 1,
"cardId": 20001,
"weight": 1
},
{
"id": 2,
"planId": 1,
"cardId": 20002,
"weight": 1
},
{
"id": 3,
"planId": 1,
"cardId": 20003,
"weight": 1
},
{
"id": 4,
"planId": 1,
"cardId": 20004,
"weight": 1
},
{
"id": 5,
"planId": 1,
"cardId": 20005,
"weight": 1
},
{
"id": 6,
"planId": 1,
"cardId": 20006,
"weight": 1
},
{
"id": 7,
"planId": 1,
"cardId": 20007,
"weight": 1
},
{
"id": 8,
"planId": 1,
"cardId": 20008,
"weight": 1
},
{
"id": 9,
"planId": 2,
"cardId": 20009,
"weight": 1
},
{
"id": 10,
"planId": 2,
"cardId": 20010,
"weight": 1
},
{
"id": 11,
"planId": 2,
"cardId": 20011,
"weight": 1
},
{
"id": 12,
"planId": 2,
"cardId": 20012,
"weight": 1
},
{
"id": 13,
"planId": 2,
"cardId": 20013,
"weight": 1
},
{
"id": 14,
"planId": 2,
"cardId": 20014,
"weight": 1
},
{
"id": 15,
"planId": 2,
"cardId": 20015,
"weight": 1
},
{
"id": 16,
"planId": 2,
"cardId": 20016,
"weight": 1
},
{
"id": 17,
"planId": 2,
"cardId": 20017,
"weight": 1
},
{
"id": 18,
"planId": 2,
"cardId": 20018,
"weight": 1
},
{
"id": 19,
"planId": 2,
"cardId": 20019,
"weight": 1
},
{
"id": 20,
"planId": 2,
"cardId": 20020,
"weight": 1
},
{
"id": 21,
"planId": 3,
"cardId": 20021,
"weight": 1
},
{
"id": 22,
"planId": 3,
"cardId": 20022,
"weight": 1
},
{
"id": 23,
"planId": 3,
"cardId": 20023,
"weight": 1
},
{
"id": 24,
"planId": 3,
"cardId": 20024,
"weight": 1
},
{
"id": 25,
"planId": 3,
"cardId": 20025,
"weight": 1
},
{
"id": 26,
"planId": 3,
"cardId": 20026,
"weight": 1
},
{
"id": 27,
"planId": 3,
"cardId": 20027,
"weight": 1
},
{
"id": 28,
"planId": 3,
"cardId": 20028,
"weight": 1
},
{
"id": 29,
"planId": 3,
"cardId": 20029,
"weight": 1
},
{
"id": 30,
"planId": 3,
"cardId": 20030,
"weight": 1
},
{
"id": 31,
"planId": 3,
"cardId": 20031,
"weight": 1
},
{
"id": 32,
"planId": 3,
"cardId": 20032,
"weight": 1
},
{
"id": 33,
"planId": 3,
"cardId": 20033,
"weight": 1
},
{
"id": 34,
"planId": 7,
"cardId": 20011,
"weight": 1
},
{
"id": 35,
"planId": 8,
"cardId": 20001,
"weight": 1
},
{
"id": 36,
"planId": 9,
"cardId": 20002,
"weight": 1
},
{
"id": 37,
"planId": 10,
"cardId": 20003,
"weight": 1
},
{
"id": 38,
"planId": 11,
"cardId": 20004,
"weight": 1
},
{
"id": 39,
"planId": 12,
"cardId": 20005,
"weight": 1
},
{
"id": 40,
"planId": 13,
"cardId": 20006,
"weight": 1
},
{
"id": 41,
"planId": 14,
"cardId": 20007,
"weight": 1
},
{
"id": 42,
"planId": 15,
"cardId": 20008,
"weight": 1
},
{
"id": 43,
"planId": 16,
"cardId": 20009,
"weight": 1
},
{
"id": 44,
"planId": 17,
"cardId": 20010,
"weight": 1
},
{
"id": 45,
"planId": 18,
"cardId": 20011,
"weight": 1
},
{
"id": 46,
"planId": 19,
"cardId": 20012,
"weight": 1
},
{
"id": 47,
"planId": 20,
"cardId": 20013,
"weight": 1
},
{
"id": 48,
"planId": 21,
"cardId": 20014,
"weight": 1
},
{
"id": 49,
"planId": 22,
"cardId": 20015,
"weight": 1
},
{
"id": 50,
"planId": 23,
"cardId": 20016,
"weight": 1
},
{
"id": 51,
"planId": 24,
"cardId": 20017,
"weight": 1
},
{
"id": 52,
"planId": 25,
"cardId": 20018,
"weight": 1
},
{
"id": 53,
"planId": 26,
"cardId": 20019,
"weight": 1
},
{
"id": 54,
"planId": 27,
"cardId": 20020,
"weight": 1
},
{
"id": 55,
"planId": 28,
"cardId": 20021,
"weight": 1
},
{
"id": 56,
"planId": 29,
"cardId": 20022,
"weight": 1
},
{
"id": 57,
"planId": 30,
"cardId": 20023,
"weight": 1
},
{
"id": 58,
"planId": 31,
"cardId": 20024,
"weight": 1
},
{
"id": 59,
"planId": 32,
"cardId": 20025,
"weight": 1
},
{
"id": 60,
"planId": 33,
"cardId": 20026,
"weight": 1
},
{
"id": 61,
"planId": 34,
"cardId": 20027,
"weight": 1
},
{
"id": 62,
"planId": 35,
"cardId": 20028,
"weight": 1
},
{
"id": 63,
"planId": 36,
"cardId": 20029,
"weight": 1
},
{
"id": 64,
"planId": 37,
"cardId": 20030,
"weight": 1
},
{
"id": 65,
"planId": 38,
"cardId": 20031,
"weight": 1
},
{
"id": 66,
"planId": 39,
"cardId": 20032,
"weight": 1
},
{
"id": 67,
"planId": 40,
"cardId": 20033,
"weight": 1
}
]

View File

@@ -0,0 +1,68 @@
[
{
"id": 1,
"nodeNumPlanId": 1,
"nodeNum": 1,
"weight": 100
},
{
"id": 3,
"nodeNumPlanId": 2,
"nodeNum": 2,
"weight": 30
},
{
"id": 4,
"nodeNumPlanId": 2,
"nodeNum": 3,
"weight": 50
},
{
"id": 5,
"nodeNumPlanId": 2,
"nodeNum": 4,
"weight": 20
},
{
"id": 6,
"nodeNumPlanId": 3,
"nodeNum": 1,
"weight": 10
},
{
"id": 7,
"nodeNumPlanId": 3,
"nodeNum": 2,
"weight": 50
},
{
"id": 8,
"nodeNumPlanId": 3,
"nodeNum": 3,
"weight": 40
},
{
"id": 9,
"nodeNumPlanId": 4,
"nodeNum": 1,
"weight": 30
},
{
"id": 10,
"nodeNumPlanId": 4,
"nodeNum": 2,
"weight": 70
},
{
"id": 11,
"nodeNumPlanId": 5,
"nodeNum": 2,
"weight": 40
},
{
"id": 12,
"nodeNumPlanId": 5,
"nodeNum": 3,
"weight": 60
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
[
{
"id": 1,
"nodeType": 1,
"name": "ORDINARY",
"string": "普通关",
"iconName": "putongguan"
},
{
"id": 2,
"nodeType": 2,
"name": "ELITE",
"string": "精英关",
"iconName": "jingyingguan"
},
{
"id": 3,
"nodeType": 3,
"name": "CHALLENGE",
"string": "挑战关",
"iconName": "tiaozhandian"
},
{
"id": 4,
"nodeType": 4,
"name": "SHOP",
"string": "试炼商店",
"iconName": "shilianshangdian"
},
{
"id": 5,
"nodeType": 5,
"name": "REST_POINT",
"string": "休整点",
"iconName": "xiuzhengdian"
},
{
"id": 6,
"nodeType": 6,
"name": "QUEST_POINT",
"string": "问号点",
"iconName": "wenhaodian"
},
{
"id": 7,
"nodeType": 7,
"name": "BOSS",
"string": "boss关",
"iconName": "BOSS"
},
{
"id": 8,
"nodeType": 8,
"name": "EVENT",
"string": "事件",
"iconName": "&"
}
]

View File

@@ -0,0 +1,218 @@
[
{
"id": 1,
"randomEventId": 1,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 2,
"holyCardPlan": "&",
"collectReward": "31002&50"
},
{
"id": 2,
"randomEventId": 1,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 3,
"holyCardPlan": "&",
"collectReward": "31002&50"
},
{
"id": 3,
"randomEventId": 1,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 2,
"holyCardPlan": "&",
"collectReward": "31002&50"
},
{
"id": 4,
"randomEventId": 1,
"optionGroup": 2,
"title": "名字是七个字2",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&100"
},
{
"id": 5,
"randomEventId": 1,
"optionGroup": 2,
"title": "名字是七个字2",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&100"
},
{
"id": 6,
"randomEventId": 1,
"optionGroup": 2,
"title": "名字是七个字2",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&100"
},
{
"id": 7,
"randomEventId": 1,
"optionGroup": 3,
"title": "名字是七个字3",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&200"
},
{
"id": 8,
"randomEventId": 1,
"optionGroup": 3,
"title": "名字是七个字3",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&200"
},
{
"id": 9,
"randomEventId": 1,
"optionGroup": 3,
"title": "名字是七个字3",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 4,
"holyCardPlan": "&",
"collectReward": "31002&200"
},
{
"id": 10,
"randomEventId": 1,
"optionGroup": 4,
"title": "名字是七个字4",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 5,
"holyCardPlan": "&",
"collectReward": "31002&300"
},
{
"id": 11,
"randomEventId": 1,
"optionGroup": 4,
"title": "名字是七个字4",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 1,
"collectReward": "31002&300"
},
{
"id": 12,
"randomEventId": 1,
"optionGroup": 4,
"title": "名字是七个字4",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 1,
"collectReward": "31002&300"
},
{
"id": 13,
"randomEventId": 1,
"optionGroup": 5,
"title": "名字是七个字5",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 2,
"collectReward": "31002&500"
},
{
"id": 14,
"randomEventId": 1,
"optionGroup": 5,
"title": "名字是七个字5",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 2,
"collectReward": "31002&500"
},
{
"id": 15,
"randomEventId": 1,
"optionGroup": 5,
"title": "名字是七个字5",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 2,
"collectReward": "31002&500"
},
{
"id": 16,
"randomEventId": 2,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 1,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 1,
"collectReward": "31002&50"
},
{
"id": 17,
"randomEventId": 2,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 2,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 1,
"collectReward": "31002&50"
},
{
"id": 18,
"randomEventId": 2,
"optionGroup": 1,
"title": "名字是七个字1",
"content": "阿巴阿巴",
"index": 3,
"text": 0,
"afterGroup": 0,
"holyCardPlan": 1,
"collectReward": "31002&50"
}
]

View File

@@ -0,0 +1,50 @@
[
{
"id": 1,
"optionGroup": 1,
"title": "梦境",
"content": 0,
"imageName": "tu_luori",
"collectReward": "31002&50"
},
{
"id": 2,
"optionGroup": 2,
"title": "虚构历史",
"content": 0,
"imageName": "tu_luori",
"collectReward": "31002&100"
},
{
"id": 3,
"optionGroup": 3,
"title": "名字是七个字3",
"content": "阿巴阿巴",
"imageName": "tu_milin",
"collectReward": "31002&150"
},
{
"id": 4,
"optionGroup": 4,
"title": "名字是七个字4",
"content": "阿巴阿巴",
"imageName": "tu_pubu",
"collectReward": "31002&200"
},
{
"id": 5,
"optionGroup": 5,
"title": "名字是七个字5",
"content": "阿巴阿巴",
"imageName": "tu_pubu",
"collectReward": "31002&250"
},
{
"id": 6,
"optionGroup": 6,
"title": "名字是七个字6",
"content": "阿巴阿巴",
"imageName": "tu_shamo",
"collectReward": "31002&300"
}
]

View File

@@ -0,0 +1,14 @@
[
{
"id": 1,
"planId": 1,
"randomEventId": 1,
"weight": 1
},
{
"id": 2,
"planId": 1,
"randomEventId": 2,
"weight": 1
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
[
{
"id": 1,
"num": 5,
"content": "收集5张",
"reward": "31002&50|31001&100"
},
{
"id": 2,
"num": 6,
"content": "收集6张",
"reward": "31002&50|31001&100"
},
{
"id": 3,
"num": 10,
"content": "收集10张",
"reward": "31002&50|31001&200"
},
{
"id": 4,
"num": 12,
"content": "收集12张",
"reward": "31002&50|31001&300"
},
{
"id": 5,
"num": 14,
"content": "收集14张",
"reward": "31002&50|31001&400"
},
{
"id": 6,
"num": 16,
"content": "收集16张",
"reward": "31002&50|31001&500"
},
{
"id": 7,
"num": 18,
"content": "收集18张",
"reward": "31002&50|31001&600"
},
{
"id": 8,
"num": 20,
"content": "收集20张",
"reward": "31002&50|31001&700"
},
{
"id": 9,
"num": 22,
"content": "收集22张",
"reward": "31002&50|31001&800"
},
{
"id": 10,
"num": 24,
"content": "收集24张",
"reward": "31002&50|31001&900"
},
{
"id": 11,
"num": 26,
"content": "收集26张",
"reward": "31002&50|31001&1000"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
[
{
"id": 1,
"questionMarkPlanId": 1,
"questionMarkIndex": 1,
"nodeType": 1,
"name": "普通关",
"param": 101110101,
"weight": 1
},
{
"id": 2,
"questionMarkPlanId": 1,
"questionMarkIndex": 1,
"nodeType": 1,
"name": "普通关",
"param": 101110201,
"weight": 1
},
{
"id": 3,
"questionMarkPlanId": 1,
"questionMarkIndex": 2,
"nodeType": 2,
"name": "精英关",
"param": 101110301,
"weight": 1
},
{
"id": 4,
"questionMarkPlanId": 1,
"questionMarkIndex": 2,
"nodeType": 2,
"name": "精英关",
"param": 101110401,
"weight": 1
},
{
"id": 5,
"questionMarkPlanId": 1,
"questionMarkIndex": 3,
"nodeType": 4,
"name": "商店",
"param": 0,
"weight": 2
},
{
"id": 6,
"questionMarkPlanId": 1,
"questionMarkIndex": 4,
"nodeType": 8,
"name": "随机事件",
"param": 0,
"weight": 2
}
]

View File

@@ -0,0 +1,14 @@
[
{
"id": 1,
"planId": 1,
"randomEventId": 1,
"weight": 1
},
{
"id": 2,
"planId": 1,
"randomEventId": 2,
"weight": 1
}
]

View File

@@ -0,0 +1,44 @@
[
{
"id": 1,
"index": 1,
"score": 10,
"reward": "31002&50"
},
{
"id": 2,
"index": 2,
"score": 20,
"reward": "31002&60"
},
{
"id": 3,
"index": 3,
"score": 30,
"reward": "31002&70"
},
{
"id": 4,
"index": 4,
"score": 40,
"reward": "31002&80"
},
{
"id": 5,
"index": 5,
"score": 50,
"reward": "31002&90"
},
{
"id": 6,
"index": 6,
"score": 60,
"reward": "31002&100"
},
{
"id": 7,
"index": 7,
"score": 70,
"reward": "31002&110"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,434 @@
[
{
"id": 3011001,
"name": "1怒气1",
"quality": 3,
"skillType": 1,
"authorType": 1,
"skillId": 70211,
"collectReward": "31002&50"
},
{
"id": 3011002,
"name": "1怒气2",
"quality": 3,
"skillType": 1,
"authorType": 1,
"skillId": 70212,
"collectReward": "31002&50"
},
{
"id": 3011003,
"name": "1怒气3",
"quality": 3,
"skillType": 1,
"authorType": 1,
"skillId": 80111,
"collectReward": "31002&50"
},
{
"id": 3012001,
"name": "1回合1",
"quality": 3,
"skillType": 2,
"authorType": 1,
"skillId": 80112,
"collectReward": "31002&50"
},
{
"id": 3012002,
"name": "1回合2",
"quality": 3,
"skillType": 2,
"authorType": 1,
"skillId": 80121,
"collectReward": "31002&50"
},
{
"id": 3012003,
"name": "1回合3",
"quality": 3,
"skillType": 2,
"authorType": 1,
"skillId": 80121,
"collectReward": "31002&50"
},
{
"id": 3021001,
"name": "2怒气1",
"quality": 3,
"skillType": 1,
"authorType": 2,
"skillId": 70211,
"collectReward": "31002&50"
},
{
"id": 3021002,
"name": "2怒气2",
"quality": 3,
"skillType": 1,
"authorType": 2,
"skillId": 70212,
"collectReward": "31002&50"
},
{
"id": 3021003,
"name": "2怒气3",
"quality": 3,
"skillType": 1,
"authorType": 2,
"skillId": 80111,
"collectReward": "31002&50"
},
{
"id": 3022001,
"name": "2回合1",
"quality": 3,
"skillType": 2,
"authorType": 2,
"skillId": 80112,
"collectReward": "31002&50"
},
{
"id": 3022002,
"name": "2回合2",
"quality": 3,
"skillType": 2,
"authorType": 2,
"skillId": 80121,
"collectReward": "31002&50"
},
{
"id": 3022003,
"name": "2回合3",
"quality": 3,
"skillType": 2,
"authorType": 2,
"skillId": 80122,
"collectReward": "31002&50"
},
{
"id": 3031001,
"name": "3怒气1",
"quality": 3,
"skillType": 1,
"authorType": 3,
"skillId": 100111,
"collectReward": "31002&50"
},
{
"id": 3031002,
"name": "3怒气2",
"quality": 3,
"skillType": 1,
"authorType": 3,
"skillId": 100112,
"collectReward": "31002&50"
},
{
"id": 3031003,
"name": "3怒气3",
"quality": 3,
"skillType": 1,
"authorType": 3,
"skillId": 100121,
"collectReward": "31002&50"
},
{
"id": 3032001,
"name": "3回合1",
"quality": 3,
"skillType": 2,
"authorType": 3,
"skillId": 100122,
"collectReward": "31002&50"
},
{
"id": 3032002,
"name": "3回合2",
"quality": 3,
"skillType": 2,
"authorType": 3,
"skillId": 110111,
"collectReward": "31002&50"
},
{
"id": 3032003,
"name": "3回合3",
"quality": 3,
"skillType": 2,
"authorType": 3,
"skillId": 110112,
"collectReward": "31002&50"
},
{
"id": 3041001,
"name": "4怒气1",
"quality": 3,
"skillType": 1,
"authorType": 4,
"skillId": 110121,
"collectReward": "31002&50"
},
{
"id": 3041002,
"name": "4怒气2",
"quality": 3,
"skillType": 1,
"authorType": 4,
"skillId": 110122,
"collectReward": "31002&50"
},
{
"id": 3041003,
"name": "4怒气3",
"quality": 3,
"skillType": 1,
"authorType": 4,
"skillId": 120111,
"collectReward": "31002&50"
},
{
"id": 3042001,
"name": "4回合1",
"quality": 3,
"skillType": 2,
"authorType": 4,
"skillId": 120112,
"collectReward": "31002&50"
},
{
"id": 3042002,
"name": "4回合2",
"quality": 3,
"skillType": 2,
"authorType": 4,
"skillId": 120121,
"collectReward": "31002&50"
},
{
"id": 3042003,
"name": "4回合3",
"quality": 3,
"skillType": 2,
"authorType": 4,
"skillId": 120122,
"collectReward": "31002&50"
},
{
"id": 3051001,
"name": "5怒气1",
"quality": 3,
"skillType": 1,
"authorType": 5,
"skillId": 130111,
"collectReward": "31002&50"
},
{
"id": 3051002,
"name": "5怒气2",
"quality": 3,
"skillType": 1,
"authorType": 5,
"skillId": 130112,
"collectReward": "31002&50"
},
{
"id": 3051003,
"name": "5怒气3",
"quality": 3,
"skillType": 1,
"authorType": 5,
"skillId": 130121,
"collectReward": "31002&50"
},
{
"id": 3051004,
"name": "5回合1",
"quality": 3,
"skillType": 2,
"authorType": 5,
"skillId": 130122,
"collectReward": "31002&50"
},
{
"id": 3051005,
"name": "5回合2",
"quality": 3,
"skillType": 2,
"authorType": 5,
"skillId": 140111,
"collectReward": "31002&50"
},
{
"id": 3051006,
"name": "5回合3",
"quality": 3,
"skillType": 2,
"authorType": 5,
"skillId": 140112,
"collectReward": "31002&50"
},
{
"id": 3061001,
"name": "6怒气1",
"quality": 3,
"skillType": 1,
"authorType": 6,
"skillId": 140121,
"collectReward": "31002&50"
},
{
"id": 3061002,
"name": "6怒气2",
"quality": 3,
"skillType": 1,
"authorType": 6,
"skillId": 140122,
"collectReward": "31002&50"
},
{
"id": 3061003,
"name": "6怒气3",
"quality": 3,
"skillType": 1,
"authorType": 6,
"skillId": 150111,
"collectReward": "31002&50"
},
{
"id": 3062001,
"name": "6回合1",
"quality": 3,
"skillType": 2,
"authorType": 6,
"skillId": 150112,
"collectReward": "31002&50"
},
{
"id": 3062002,
"name": "6回合2",
"quality": 3,
"skillType": 2,
"authorType": 6,
"skillId": 150113,
"collectReward": "31002&50"
},
{
"id": 3062003,
"name": "6回合3",
"quality": 3,
"skillType": 2,
"authorType": 6,
"skillId": 150114,
"collectReward": "31002&50"
},
{
"id": 3071001,
"name": "7怒气1",
"quality": 3,
"skillType": 1,
"authorType": 7,
"skillId": 150121,
"collectReward": "31002&50"
},
{
"id": 3071002,
"name": "7怒气2",
"quality": 3,
"skillType": 1,
"authorType": 7,
"skillId": 150122,
"collectReward": "31002&50"
},
{
"id": 3071003,
"name": "7怒气3",
"quality": 3,
"skillType": 1,
"authorType": 7,
"skillId": 160111,
"collectReward": "31002&50"
},
{
"id": 3072001,
"name": "7回合1",
"quality": 3,
"skillType": 2,
"authorType": 7,
"skillId": 160112,
"collectReward": "31002&50"
},
{
"id": 3072002,
"name": "7回合2",
"quality": 3,
"skillType": 2,
"authorType": 7,
"skillId": 160121,
"collectReward": "31002&50"
},
{
"id": 3072003,
"name": "7回合3",
"quality": 3,
"skillType": 2,
"authorType": 7,
"skillId": 160122,
"collectReward": "31002&50"
},
{
"id": 3081001,
"name": "8怒气1",
"quality": 3,
"skillType": 1,
"authorType": 8,
"skillId": 170111,
"collectReward": "31002&50"
},
{
"id": 3081002,
"name": "8怒气2",
"quality": 3,
"skillType": 1,
"authorType": 8,
"skillId": 170112,
"collectReward": "31002&50"
},
{
"id": 3081003,
"name": "8怒气3",
"quality": 3,
"skillType": 1,
"authorType": 8,
"skillId": 170121,
"collectReward": "31002&50"
},
{
"id": 3082001,
"name": "8回合1",
"quality": 3,
"skillType": 2,
"authorType": 8,
"skillId": 170122,
"collectReward": "31002&50"
},
{
"id": 3082002,
"name": "8回合2",
"quality": 3,
"skillType": 2,
"authorType": 8,
"skillId": 180111,
"collectReward": "31002&50"
},
{
"id": 3082003,
"name": "8回合3",
"quality": 3,
"skillType": 2,
"authorType": 8,
"skillId": 180112,
"collectReward": "31002&50"
}
]

View File

@@ -0,0 +1,587 @@
[
{
"id": 1,
"techId": 1,
"name": "选择百家流派后获得1个流派专属圣物",
"rowId": 1,
"index": 1,
"preTechId": "&",
"pointImageName": "fazhen1_xiao",
"imageName": "fazhen1_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 2,
"techId": 2,
"name": "攻击1",
"rowId": 2,
"index": 1,
"preTechId": "1&",
"pointImageName": "fazhen12_xiao",
"imageName": "fazhen12_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "1&2&3"
},
{
"id": 3,
"techId": 3,
"name": "物防1",
"rowId": 2,
"index": 2,
"preTechId": "1&",
"pointImageName": "fazhen15_xiao",
"imageName": "fazhen15_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "4&5&6"
},
{
"id": 4,
"techId": 4,
"name": "生命上限提高1",
"rowId": 2,
"index": 3,
"preTechId": "1&",
"pointImageName": "fazhen14_xiao",
"imageName": "fazhen14_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "7&8&9"
},
{
"id": 5,
"techId": 5,
"name": "装备3个同百家流派特性的角色可额外选择流派专属怒气技",
"rowId": 3,
"index": 1,
"preTechId": "2&3&4",
"pointImageName": "fazhen2_xiao",
"imageName": "fazhen2_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 6,
"techId": 6,
"name": "攻击2",
"rowId": 4,
"index": 1,
"preTechId": "5&",
"pointImageName": "fazhen12_xiao",
"imageName": "fazhen12_da",
"cost": "40022&100",
"circleNum": 4,
"circleId": "10&11&12&13"
},
{
"id": 7,
"techId": 7,
"name": "策防1",
"rowId": 4,
"index": 2,
"preTechId": "5&",
"pointImageName": "fazhen16_xiao",
"imageName": "fazhen16_da",
"cost": "40022&100",
"circleNum": 4,
"circleId": "14&15&16&17"
},
{
"id": 8,
"techId": 8,
"name": "生命上限提高2",
"rowId": 4,
"index": 3,
"preTechId": "5&",
"pointImageName": "fazhen14_xiao",
"imageName": "fazhen14_da",
"cost": "40022&100",
"circleNum": 4,
"circleId": "18&19&20&21"
},
{
"id": 9,
"techId": 9,
"name": "初始获得X个试炼币",
"rowId": 5,
"index": 1,
"preTechId": "6&7&8",
"pointImageName": "fazhen3_xiao",
"imageName": "fazhen3_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 10,
"techId": 10,
"name": "攻击3",
"rowId": 6,
"index": 1,
"preTechId": "9&",
"pointImageName": "fazhen12_xiao",
"imageName": "fazhen12_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "22&23"
},
{
"id": 11,
"techId": 11,
"name": "物防3",
"rowId": 6,
"index": 2,
"preTechId": "9&",
"pointImageName": "fazhen15_xiao",
"imageName": "fazhen15_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "24&25"
},
{
"id": 12,
"techId": 12,
"name": "策防3",
"rowId": 6,
"index": 3,
"preTechId": "9&",
"pointImageName": "fazhen16_xiao",
"imageName": "fazhen16_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "26&27"
},
{
"id": 13,
"techId": 13,
"name": "生命上限提高3",
"rowId": 6,
"index": 4,
"preTechId": "9&",
"pointImageName": "fazhen14_xiao",
"imageName": "fazhen14_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "28&29"
},
{
"id": 14,
"techId": 14,
"name": "选择百家流派后额外再获得1个流派专属圣物",
"rowId": 7,
"index": 1,
"preTechId": "10&11&12&13",
"pointImageName": "fazhen4_xiao",
"imageName": "fazhen4_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 15,
"techId": 15,
"name": "物防4",
"rowId": 8,
"index": 1,
"preTechId": "14&",
"pointImageName": "fazhen15_xiao",
"imageName": "fazhen15_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "30&31"
},
{
"id": 16,
"techId": 16,
"name": "策防4",
"rowId": 8,
"index": 2,
"preTechId": "14&",
"pointImageName": "fazhen16_xiao",
"imageName": "fazhen16_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "32&33"
},
{
"id": 17,
"techId": 17,
"name": "物防5",
"rowId": 9,
"index": 1,
"preTechId": "15&",
"pointImageName": "fazhen15_xiao",
"imageName": "fazhen15_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "34&35"
},
{
"id": 18,
"techId": 18,
"name": "策防5",
"rowId": 9,
"index": 2,
"preTechId": "16&",
"pointImageName": "fazhen16_xiao",
"imageName": "fazhen16_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "36&37"
},
{
"id": 19,
"techId": 19,
"name": "休整点恢复额外恢复X的生命",
"rowId": 10,
"index": 1,
"preTechId": "17&18",
"pointImageName": "fazhen5_xiao",
"imageName": "fazhen5_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 20,
"techId": 20,
"name": "破格1",
"rowId": 11,
"index": 1,
"preTechId": "19&",
"pointImageName": "fazhen18_xiao",
"imageName": "fazhen18_da",
"cost": "40022&100",
"circleNum": 1,
"circleId": "38&"
},
{
"id": 21,
"techId": 21,
"name": "暴击1",
"rowId": 11,
"index": 2,
"preTechId": "19&",
"pointImageName": "fazhen17_xiao",
"imageName": "fazhen17_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "39&40"
},
{
"id": 22,
"techId": 22,
"name": "格挡1",
"rowId": 12,
"index": 1,
"preTechId": "20&",
"pointImageName": "fazhen19_xiao",
"imageName": "fazhen19_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "41&42"
},
{
"id": 23,
"techId": 23,
"name": "抗暴1",
"rowId": 12,
"index": 2,
"preTechId": "21&",
"pointImageName": "fazhen20_xiao",
"imageName": "fazhen20_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "43&44"
},
{
"id": 24,
"techId": 24,
"name": "装备5个同百家流派特性的角色可额外选择流派专属回合技",
"rowId": 13,
"index": 1,
"preTechId": "22&23",
"pointImageName": "fazhen6_xiao",
"imageName": "fazhen6_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 25,
"techId": 25,
"name": "暴击伤害1",
"rowId": 14,
"index": 1,
"preTechId": "24&",
"pointImageName": "fazhen21_xiao",
"imageName": "fazhen21_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "45&46&47"
},
{
"id": 26,
"techId": 26,
"name": "吸血1",
"rowId": 14,
"index": 2,
"preTechId": "24&",
"pointImageName": "fazhen22_xiao",
"imageName": "fazhen22_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "48&49&50"
},
{
"id": 27,
"techId": 27,
"name": "反击伤害1",
"rowId": 14,
"index": 3,
"preTechId": "24&",
"pointImageName": "fazhen23_xiao",
"imageName": "fazhen23_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "51&52&53"
},
{
"id": 28,
"techId": 28,
"name": "击败敌人获得的试炼币增加10%",
"rowId": 15,
"index": 1,
"preTechId": "25&26&27",
"pointImageName": "fazhen7_xiao",
"imageName": "fazhen7_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 29,
"techId": 29,
"name": "物攻抗性1",
"rowId": 16,
"index": 1,
"preTechId": "28&",
"pointImageName": "fazhen24_xiao",
"imageName": "fazhen24_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "54&55&56"
},
{
"id": 30,
"techId": 30,
"name": "策攻抗性1",
"rowId": 16,
"index": 2,
"preTechId": "28&",
"pointImageName": "fazhen25_xiao",
"imageName": "fazhen25_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "57&58&59"
},
{
"id": 31,
"techId": 31,
"name": "选择特性卡时可消耗试炼币重置1次",
"rowId": 17,
"index": 1,
"preTechId": "29&30",
"pointImageName": "fazhen8_xiao",
"imageName": "fazhen8_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 32,
"techId": 32,
"name": "物攻强度1",
"rowId": 18,
"index": 1,
"preTechId": "31&",
"pointImageName": "fazhen26_xiao",
"imageName": "fazhen26_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "60&61"
},
{
"id": 33,
"techId": 33,
"name": "策攻强度1",
"rowId": 18,
"index": 2,
"preTechId": "31&",
"pointImageName": "fazhen27_xiao",
"imageName": "fazhen27_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "62&63"
},
{
"id": 34,
"techId": 34,
"name": "特训价格降低10%",
"rowId": 19,
"index": 1,
"preTechId": "32&33",
"pointImageName": "fazhen9_xiao",
"imageName": "fazhen9_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 35,
"techId": 35,
"name": "攻击4",
"rowId": 20,
"index": 1,
"preTechId": "34&",
"pointImageName": "fazhen12_xiao",
"imageName": "fazhen12_da",
"cost": "40022&100",
"circleNum": 1,
"circleId": "64&"
},
{
"id": 36,
"techId": 36,
"name": "生命上限提高4",
"rowId": 20,
"index": 2,
"preTechId": "34&",
"pointImageName": "fazhen14_xiao",
"imageName": "fazhen14_da",
"cost": "40022&100",
"circleNum": 1,
"circleId": "65&"
},
{
"id": 37,
"techId": 37,
"name": "反弹1",
"rowId": 20,
"index": 3,
"preTechId": "34&",
"pointImageName": "fazhen28_xiao",
"imageName": "fazhen28_da",
"cost": "40022&100",
"circleNum": 1,
"circleId": "66&"
},
{
"id": 38,
"techId": 38,
"name": "挑战boss关前所有角色怒气值充满",
"rowId": 21,
"index": 1,
"preTechId": "35&36&37",
"pointImageName": "fazhen10_xiao",
"imageName": "fazhen10_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
},
{
"id": 39,
"techId": 39,
"name": "物攻强度2",
"rowId": 22,
"index": 1,
"preTechId": "38&",
"pointImageName": "fazhen26_xiao",
"imageName": "fazhen26_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "67&68&69"
},
{
"id": 40,
"techId": 40,
"name": "策攻强度2",
"rowId": 22,
"index": 2,
"preTechId": "38&",
"pointImageName": "fazhen27_xiao",
"imageName": "fazhen27_da",
"cost": "40022&100",
"circleNum": 1,
"circleId": "70&"
},
{
"id": 41,
"techId": 41,
"name": "暴击2",
"rowId": 22,
"index": 3,
"preTechId": "38&",
"pointImageName": "fazhen17_xiao",
"imageName": "fazhen17_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "71&72&73"
},
{
"id": 42,
"techId": 42,
"name": "物攻强度3",
"rowId": 23,
"index": 1,
"preTechId": "39&",
"pointImageName": "fazhen26_xiao",
"imageName": "fazhen26_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "74&75&76"
},
{
"id": 43,
"techId": 43,
"name": "策攻强度3",
"rowId": 23,
"index": 2,
"preTechId": "40&",
"pointImageName": "fazhen27_xiao",
"imageName": "fazhen27_da",
"cost": "40022&100",
"circleNum": 2,
"circleId": "77&78"
},
{
"id": 44,
"techId": 44,
"name": "暴伤2",
"rowId": 23,
"index": 3,
"preTechId": "41&",
"pointImageName": "fazhen21_xiao",
"imageName": "fazhen21_da",
"cost": "40022&100",
"circleNum": 3,
"circleId": "79&80&81"
},
{
"id": 45,
"techId": 45,
"name": "挑战boss关前所有角色生命恢复至100%",
"rowId": 24,
"index": 1,
"preTechId": "42&43&44",
"pointImageName": "fazhen11_xiao",
"imageName": "fazhen11_da",
"cost": "40022&100",
"circleNum": 0,
"circleId": "&"
}
]

View File

@@ -0,0 +1,488 @@
[
{
"id": 1,
"techId": 2,
"circleId": 1,
"rotation": "250&0"
},
{
"id": 2,
"techId": 2,
"circleId": 2,
"rotation": "0&250"
},
{
"id": 3,
"techId": 2,
"circleId": 3,
"rotation": "170&170"
},
{
"id": 4,
"techId": 3,
"circleId": 4,
"rotation": "-170&-170"
},
{
"id": 5,
"techId": 3,
"circleId": 5,
"rotation": "-250&250"
},
{
"id": 6,
"techId": 3,
"circleId": 6,
"rotation": "250&0"
},
{
"id": 7,
"techId": 4,
"circleId": 7,
"rotation": "0&250"
},
{
"id": 8,
"techId": 4,
"circleId": 8,
"rotation": "170&170"
},
{
"id": 9,
"techId": 4,
"circleId": 9,
"rotation": "-170&-170"
},
{
"id": 10,
"techId": 6,
"circleId": 10,
"rotation": "-250&250"
},
{
"id": 11,
"techId": 6,
"circleId": 11,
"rotation": "250&0"
},
{
"id": 12,
"techId": 6,
"circleId": 12,
"rotation": "0&250"
},
{
"id": 13,
"techId": 6,
"circleId": 13,
"rotation": "170&170"
},
{
"id": 14,
"techId": 7,
"circleId": 14,
"rotation": "-170&-170"
},
{
"id": 15,
"techId": 7,
"circleId": 15,
"rotation": "-250&250"
},
{
"id": 16,
"techId": 7,
"circleId": 16,
"rotation": "250&0"
},
{
"id": 17,
"techId": 7,
"circleId": 17,
"rotation": "0&250"
},
{
"id": 18,
"techId": 8,
"circleId": 18,
"rotation": "170&170"
},
{
"id": 19,
"techId": 8,
"circleId": 19,
"rotation": "-170&-170"
},
{
"id": 20,
"techId": 8,
"circleId": 20,
"rotation": "-250&250"
},
{
"id": 21,
"techId": 8,
"circleId": 21,
"rotation": "250&0"
},
{
"id": 22,
"techId": 10,
"circleId": 22,
"rotation": "0&250"
},
{
"id": 23,
"techId": 10,
"circleId": 23,
"rotation": "170&170"
},
{
"id": 24,
"techId": 11,
"circleId": 24,
"rotation": "-170&-170"
},
{
"id": 25,
"techId": 11,
"circleId": 25,
"rotation": "-250&250"
},
{
"id": 26,
"techId": 12,
"circleId": 26,
"rotation": "250&0"
},
{
"id": 27,
"techId": 12,
"circleId": 27,
"rotation": "0&250"
},
{
"id": 28,
"techId": 13,
"circleId": 28,
"rotation": "170&170"
},
{
"id": 29,
"techId": 13,
"circleId": 29,
"rotation": "-170&-170"
},
{
"id": 30,
"techId": 15,
"circleId": 30,
"rotation": "-250&250"
},
{
"id": 31,
"techId": 15,
"circleId": 31,
"rotation": "250&0"
},
{
"id": 32,
"techId": 16,
"circleId": 32,
"rotation": "0&250"
},
{
"id": 33,
"techId": 16,
"circleId": 33,
"rotation": "170&170"
},
{
"id": 34,
"techId": 17,
"circleId": 34,
"rotation": "-170&-170"
},
{
"id": 35,
"techId": 17,
"circleId": 35,
"rotation": "-250&250"
},
{
"id": 36,
"techId": 18,
"circleId": 36,
"rotation": "250&0"
},
{
"id": 37,
"techId": 18,
"circleId": 37,
"rotation": "0&250"
},
{
"id": 38,
"techId": 20,
"circleId": 38,
"rotation": "170&170"
},
{
"id": 39,
"techId": 21,
"circleId": 39,
"rotation": "-170&-170"
},
{
"id": 40,
"techId": 21,
"circleId": 40,
"rotation": "-250&250"
},
{
"id": 41,
"techId": 22,
"circleId": 41,
"rotation": "250&0"
},
{
"id": 42,
"techId": 22,
"circleId": 42,
"rotation": "0&250"
},
{
"id": 43,
"techId": 23,
"circleId": 43,
"rotation": "170&170"
},
{
"id": 44,
"techId": 23,
"circleId": 44,
"rotation": "-170&-170"
},
{
"id": 45,
"techId": 25,
"circleId": 45,
"rotation": "-250&250"
},
{
"id": 46,
"techId": 25,
"circleId": 46,
"rotation": "250&0"
},
{
"id": 47,
"techId": 25,
"circleId": 47,
"rotation": "0&250"
},
{
"id": 48,
"techId": 26,
"circleId": 48,
"rotation": "170&170"
},
{
"id": 49,
"techId": 26,
"circleId": 49,
"rotation": "-170&-170"
},
{
"id": 50,
"techId": 26,
"circleId": 50,
"rotation": "-250&250"
},
{
"id": 51,
"techId": 27,
"circleId": 51,
"rotation": "250&0"
},
{
"id": 52,
"techId": 27,
"circleId": 52,
"rotation": "0&250"
},
{
"id": 53,
"techId": 27,
"circleId": 53,
"rotation": "170&170"
},
{
"id": 54,
"techId": 29,
"circleId": 54,
"rotation": "-170&-170"
},
{
"id": 55,
"techId": 29,
"circleId": 55,
"rotation": "-250&250"
},
{
"id": 56,
"techId": 29,
"circleId": 56,
"rotation": "250&0"
},
{
"id": 57,
"techId": 30,
"circleId": 57,
"rotation": "0&250"
},
{
"id": 58,
"techId": 30,
"circleId": 58,
"rotation": "170&170"
},
{
"id": 59,
"techId": 30,
"circleId": 59,
"rotation": "-170&-170"
},
{
"id": 60,
"techId": 32,
"circleId": 60,
"rotation": "-250&250"
},
{
"id": 61,
"techId": 32,
"circleId": 61,
"rotation": "250&0"
},
{
"id": 62,
"techId": 33,
"circleId": 62,
"rotation": "0&250"
},
{
"id": 63,
"techId": 33,
"circleId": 63,
"rotation": "170&170"
},
{
"id": 64,
"techId": 35,
"circleId": 64,
"rotation": "-170&-170"
},
{
"id": 65,
"techId": 36,
"circleId": 65,
"rotation": "-250&250"
},
{
"id": 66,
"techId": 37,
"circleId": 66,
"rotation": "250&0"
},
{
"id": 67,
"techId": 39,
"circleId": 67,
"rotation": "0&250"
},
{
"id": 68,
"techId": 39,
"circleId": 68,
"rotation": "170&170"
},
{
"id": 69,
"techId": 39,
"circleId": 69,
"rotation": "-170&-170"
},
{
"id": 70,
"techId": 40,
"circleId": 70,
"rotation": "-250&250"
},
{
"id": 71,
"techId": 41,
"circleId": 71,
"rotation": "250&0"
},
{
"id": 72,
"techId": 41,
"circleId": 72,
"rotation": "0&250"
},
{
"id": 73,
"techId": 41,
"circleId": 73,
"rotation": "170&170"
},
{
"id": 74,
"techId": 42,
"circleId": 74,
"rotation": "-170&-170"
},
{
"id": 75,
"techId": 42,
"circleId": 75,
"rotation": "-250&250"
},
{
"id": 76,
"techId": 42,
"circleId": 76,
"rotation": "250&0"
},
{
"id": 77,
"techId": 43,
"circleId": 77,
"rotation": "0&250"
},
{
"id": 78,
"techId": 43,
"circleId": 78,
"rotation": "170&170"
},
{
"id": 79,
"techId": 44,
"circleId": 79,
"rotation": "-170&-170"
},
{
"id": 80,
"techId": 44,
"circleId": 80,
"rotation": "-250&250"
},
{
"id": 81,
"techId": 44,
"circleId": 81,
"rotation": "250&0"
}
]

View File

@@ -0,0 +1,26 @@
[
{
"id": 1,
"rotation": "0&250"
},
{
"id": 2,
"rotation": "0&250|-250&0"
},
{
"id": 3,
"rotation": "0&250|170&170|250&0"
},
{
"id": 4,
"rotation": "0&250|250&0|0&-250|-250&0"
},
{
"id": 5,
"rotation": "0&250|170&170|250&0|0&-250|-250&0"
},
{
"id": 6,
"rotation": "0&250|170&170|250&0|0&-250|-250&0|-170&-170"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
[
{
"id": 1,
"type": 1,
"name": "入学试炼",
"grade": 1,
"gradeList": "1&",
"icon": "zi_ruxueshilian",
"imageName": "zi_ruxueshilian"
},
{
"id": 2,
"type": 2,
"name": "新手试炼",
"grade": 1,
"gradeList": "2&",
"icon": "zi_xinshoushilian",
"imageName": "zi_xinshoushilian"
},
{
"id": 3,
"type": 3,
"name": "儒家学派",
"grade": 5,
"gradeList": "3&4&5&6&7",
"icon": "zi_rujiashilian",
"imageName": "zi_rujiashilian"
},
{
"id": 4,
"type": 4,
"name": "道家学派",
"grade": 5,
"gradeList": "8&9&10&11&12",
"icon": "zi_daojiashilian",
"imageName": "zi_daojiashilian"
},
{
"id": 5,
"type": 5,
"name": "墨家学派",
"grade": 5,
"gradeList": "13&14&15&16&17",
"icon": "zi_mojiashilian",
"imageName": "zi_mojiashilian"
},
{
"id": 6,
"type": 6,
"name": "法家学派",
"grade": 5,
"gradeList": "18&19&20&21&22",
"icon": "zi_fajiashilian",
"imageName": "zi_fajiashilian"
},
{
"id": 7,
"type": 7,
"name": "医家学派",
"grade": 5,
"gradeList": "23&24&25&26&27",
"icon": "zi_yijiashilian",
"imageName": "zi_yijiashilian"
},
{
"id": 8,
"type": 8,
"name": "兵家学派",
"grade": 5,
"gradeList": "28&29&30&31&32",
"icon": "zi_bijingshilian",
"imageName": "zi_bijingshilian"
},
{
"id": 9,
"type": 9,
"name": "阴阳学派",
"grade": 5,
"gradeList": "33&34&35&36&37",
"icon": "zi_yinyangshilian",
"imageName": "zi_yinyangshilian"
},
{
"id": 10,
"type": 10,
"name": "纵横学派",
"grade": 5,
"gradeList": "38&39&40&41&42",
"icon": "zi_zonghengshilian",
"imageName": "zi_zonghengshilian"
}
]

View File

@@ -0,0 +1,758 @@
[
{
"id": 1,
"type": 1,
"gradeIndex": 1,
"name": "入学试炼",
"lvLimit": 53,
"limitId": 0,
"buyRewardPlan": 0,
"layerCount": 5,
"layerPlan": 101,
"challengePlan": 1,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1000",
"heroRatioPlan": 1,
"heroValue": 300000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "&"
},
{
"id": 2,
"type": 2,
"gradeIndex": 1,
"name": "新手试炼",
"lvLimit": 53,
"limitId": 1,
"buyRewardPlan": 0,
"layerCount": 10,
"layerPlan": 201,
"challengePlan": 2,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1000",
"heroRatioPlan": 1,
"heroValue": 400000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "&"
},
{
"id": 3,
"type": 3,
"gradeIndex": 1,
"name": "儒家学派",
"lvLimit": 53,
"limitId": 2,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 301,
"challengePlan": 3,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1001",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "1&1&5|1&2&3"
},
{
"id": 4,
"type": 3,
"gradeIndex": 2,
"name": "儒家学派",
"lvLimit": 55,
"limitId": 3,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 302,
"challengePlan": 4,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1001",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "1&1&10|1&2&5"
},
{
"id": 5,
"type": 3,
"gradeIndex": 3,
"name": "儒家学派",
"lvLimit": 60,
"limitId": 4,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 303,
"challengePlan": 5,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1002",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "1&1&10|1&2&7|1&3&3"
},
{
"id": 6,
"type": 3,
"gradeIndex": 4,
"name": "儒家学派",
"lvLimit": 65,
"limitId": 5,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 304,
"challengePlan": 6,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1002",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "1&1&12|1&2&10|1&3&5"
},
{
"id": 7,
"type": 3,
"gradeIndex": 5,
"name": "儒家学派",
"lvLimit": 70,
"limitId": 6,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 305,
"challengePlan": 7,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1003",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "1&1&12|1&2&10|1&3&5|1&4&1"
},
{
"id": 8,
"type": 4,
"gradeIndex": 1,
"name": "道家学派",
"lvLimit": 53,
"limitId": 3,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 401,
"challengePlan": 8,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1003",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "2&1&5|2&2&3"
},
{
"id": 9,
"type": 4,
"gradeIndex": 2,
"name": "道家学派",
"lvLimit": 55,
"limitId": 8,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 402,
"challengePlan": 9,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1004",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "2&1&10|2&2&5"
},
{
"id": 10,
"type": 4,
"gradeIndex": 3,
"name": "道家学派",
"lvLimit": 60,
"limitId": 9,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 403,
"challengePlan": 1,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1004",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "2&1&10|2&2&7|2&3&3"
},
{
"id": 11,
"type": 4,
"gradeIndex": 4,
"name": "道家学派",
"lvLimit": 65,
"limitId": 10,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 404,
"challengePlan": 2,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1005",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "2&1&12|2&2&10|2&3&5"
},
{
"id": 12,
"type": 4,
"gradeIndex": 5,
"name": "道家学派",
"lvLimit": 70,
"limitId": 11,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 405,
"challengePlan": 3,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1005",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "2&1&12|2&2&10|2&3&5|2&4&1"
},
{
"id": 13,
"type": 5,
"gradeIndex": 1,
"name": "墨家学派",
"lvLimit": 53,
"limitId": 8,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 501,
"challengePlan": 4,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1006",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "3&1&5|3&2&3"
},
{
"id": 14,
"type": 5,
"gradeIndex": 2,
"name": "墨家学派",
"lvLimit": 55,
"limitId": 13,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 502,
"challengePlan": 5,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1006",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "3&1&10|3&2&5"
},
{
"id": 15,
"type": 5,
"gradeIndex": 3,
"name": "墨家学派",
"lvLimit": 60,
"limitId": 14,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 503,
"challengePlan": 6,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1007",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "3&1&10|3&2&7|3&3&3"
},
{
"id": 16,
"type": 5,
"gradeIndex": 4,
"name": "墨家学派",
"lvLimit": 65,
"limitId": 15,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 504,
"challengePlan": 7,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1007",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "3&1&12|3&2&10|3&3&5"
},
{
"id": 17,
"type": 5,
"gradeIndex": 5,
"name": "墨家学派",
"lvLimit": 70,
"limitId": 16,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 505,
"challengePlan": 8,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1008",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "3&1&12|3&2&10|3&3&5|3&4&1"
},
{
"id": 18,
"type": 6,
"gradeIndex": 1,
"name": "法家学派",
"lvLimit": 53,
"limitId": 13,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 601,
"challengePlan": 9,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1008",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "4&1&5|4&2&3"
},
{
"id": 19,
"type": 6,
"gradeIndex": 2,
"name": "法家学派",
"lvLimit": 55,
"limitId": 18,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 602,
"challengePlan": 1,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1009",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "4&1&10|4&2&5"
},
{
"id": 20,
"type": 6,
"gradeIndex": 3,
"name": "法家学派",
"lvLimit": 60,
"limitId": 19,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 603,
"challengePlan": 2,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1009",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "4&1&10|4&2&7|4&3&3"
},
{
"id": 21,
"type": 6,
"gradeIndex": 4,
"name": "法家学派",
"lvLimit": 65,
"limitId": 20,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 604,
"challengePlan": 3,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1010",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "4&1&12|4&2&10|4&3&5"
},
{
"id": 22,
"type": 6,
"gradeIndex": 5,
"name": "法家学派",
"lvLimit": 70,
"limitId": 21,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 605,
"challengePlan": 4,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1010",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "4&1&12|4&2&10|4&3&5|4&4&1"
},
{
"id": 23,
"type": 7,
"gradeIndex": 1,
"name": "医家学派",
"lvLimit": 53,
"limitId": 18,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 701,
"challengePlan": 5,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1011",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "5&1&5|5&2&3"
},
{
"id": 24,
"type": 7,
"gradeIndex": 2,
"name": "医家学派",
"lvLimit": 55,
"limitId": 23,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 702,
"challengePlan": 6,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1011",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "5&1&10|5&2&5"
},
{
"id": 25,
"type": 7,
"gradeIndex": 3,
"name": "医家学派",
"lvLimit": 60,
"limitId": 24,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 703,
"challengePlan": 7,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1012",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "5&1&10|5&2&7|5&3&3"
},
{
"id": 26,
"type": 7,
"gradeIndex": 4,
"name": "医家学派",
"lvLimit": 65,
"limitId": 25,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 704,
"challengePlan": 8,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1012",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "5&1&12|5&2&10|5&3&5"
},
{
"id": 27,
"type": 7,
"gradeIndex": 5,
"name": "医家学派",
"lvLimit": 70,
"limitId": 26,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 705,
"challengePlan": 9,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1013",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "5&1&12|5&2&10|5&3&5|5&4&1"
},
{
"id": 28,
"type": 8,
"gradeIndex": 1,
"name": "兵家学派",
"lvLimit": 53,
"limitId": 23,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 801,
"challengePlan": 1,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1013",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "6&1&5|6&2&3"
},
{
"id": 29,
"type": 8,
"gradeIndex": 2,
"name": "兵家学派",
"lvLimit": 55,
"limitId": 28,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 802,
"challengePlan": 2,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1014",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "6&1&10|6&2&5"
},
{
"id": 30,
"type": 8,
"gradeIndex": 3,
"name": "兵家学派",
"lvLimit": 60,
"limitId": 29,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 803,
"challengePlan": 3,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1014",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "6&1&10|6&2&7|6&3&3"
},
{
"id": 31,
"type": 8,
"gradeIndex": 4,
"name": "兵家学派",
"lvLimit": 65,
"limitId": 30,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 804,
"challengePlan": 4,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1015",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "6&1&12|6&2&10|6&3&5"
},
{
"id": 32,
"type": 8,
"gradeIndex": 5,
"name": "兵家学派",
"lvLimit": 70,
"limitId": 31,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 805,
"challengePlan": 5,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1015",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "6&1&12|6&2&10|6&3&5|6&4&1"
},
{
"id": 33,
"type": 9,
"gradeIndex": 1,
"name": "阴阳学派",
"lvLimit": 53,
"limitId": 28,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 901,
"challengePlan": 6,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1016",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "7&1&5|7&2&3"
},
{
"id": 34,
"type": 9,
"gradeIndex": 2,
"name": "阴阳学派",
"lvLimit": 55,
"limitId": 33,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 902,
"challengePlan": 7,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1016",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "7&1&10|7&2&5"
},
{
"id": 35,
"type": 9,
"gradeIndex": 3,
"name": "阴阳学派",
"lvLimit": 60,
"limitId": 34,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 903,
"challengePlan": 8,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1017",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "7&1&10|7&2&7|7&3&3"
},
{
"id": 36,
"type": 9,
"gradeIndex": 4,
"name": "阴阳学派",
"lvLimit": 65,
"limitId": 35,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 904,
"challengePlan": 9,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1017",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "7&1&12|7&2&10|7&3&5"
},
{
"id": 37,
"type": 9,
"gradeIndex": 5,
"name": "阴阳学派",
"lvLimit": 70,
"limitId": 36,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 905,
"challengePlan": 1,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1018",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "7&1&12|7&2&10|7&3&5|7&4&1"
},
{
"id": 38,
"type": 10,
"gradeIndex": 1,
"name": "纵横学派",
"lvLimit": 53,
"limitId": 33,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 1001,
"challengePlan": 2,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1018",
"heroRatioPlan": 1,
"heroValue": 500000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "8&1&5|8&2&3"
},
{
"id": 39,
"type": 10,
"gradeIndex": 2,
"name": "纵横学派",
"lvLimit": 55,
"limitId": 38,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 1002,
"challengePlan": 3,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1019",
"heroRatioPlan": 1,
"heroValue": 600000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "8&1&10|8&2&5"
},
{
"id": 40,
"type": 10,
"gradeIndex": 3,
"name": "纵横学派",
"lvLimit": 60,
"limitId": 39,
"buyRewardPlan": 0,
"layerCount": 15,
"layerPlan": 1003,
"challengePlan": 4,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1019",
"heroRatioPlan": 1,
"heroValue": 700000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "8&1&10|8&2&7|8&3&3"
},
{
"id": 41,
"type": 10,
"gradeIndex": 4,
"name": "纵横学派",
"lvLimit": 65,
"limitId": 40,
"buyRewardPlan": 0,
"layerCount": 17,
"layerPlan": 1004,
"challengePlan": 5,
"randomEventPlan": 1,
"firstReward": "31002&50|31001&1020",
"heroRatioPlan": 1,
"heroValue": 800000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "8&1&12|8&2&10|8&3&5"
},
{
"id": 42,
"type": 10,
"gradeIndex": 5,
"name": "纵横学派",
"lvLimit": 70,
"limitId": 41,
"buyRewardPlan": 0,
"layerCount": 20,
"layerPlan": 1005,
"challengePlan": 6,
"randomEventPlan": 1,
"firstReward": "31002&100|31001&1020",
"heroRatioPlan": 1,
"heroValue": 900000,
"heroSecondAttrLevel": 1,
"takeoutRewardShow": "8&1&12|8&2&10|8&3&5|8&4&1"
}
]

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More