Files
ZYZ/game-server/app/services/roleService.ts
2022-05-05 13:05:07 +08:00

255 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Channel, pinus } from 'pinus';
import { getRandValueByMinMax, getRandEelm, decodeIdCntArrayStr } from '../pubUtils/util';
import { DEFAULT_HEROES, LINEUP_NUM, ROLE_SELECT, TALENT_RELATION_TYPE, TERAPH_RANDOM, SYSTEM_OPEN_ID, GuideUnloadNum } from "../consts";
import { DicTeraph } from '../pubUtils/dictionary/DicTeraph';
import { Teraph, RoleModel, RoleType, RoleUpdate } from '../db/Role';
import { SCHOOL } from '../pubUtils/dicParam';
import { gameData, getHeroInitTalent } from '../pubUtils/data';
import { SchoolModel } from '../db/School';
import { SclResultInter, SclPosInter, RewardInter, ItemInter } from '../pubUtils/interface';
import { HeroModel, HeroSkin, HeroUpdate, Talent } from '../db/Hero';
import { SkinUpdate } from '../db/Skin';
import { Figure } from '../domain/dbGeneral';
import { pick } from 'underscore';
import { Reward } from '../domain/battleField/pvp';
import { CheckMeterial } from './role/checkMaterial';
export async function getTeraphStrengthenResult(role: RoleType, count: number, dicTeraph: DicTeraph, teraph: Teraph) {
let criAttr: number[] = [], times = 0;
let check = new CheckMeterial(role.roleId, role);
for(let i = 0; i < count; i++) {
let attrs: number[] = []; // 可以强化的属性
dicTeraph.mainAttrMax.forEach((max, id) => {
if (teraph.attr.get(id) < max) {
attrs.push(id);
}
});
if(attrs.length <= 0) break; // 如果所有属性都到最高
let isEnough = await check.decrease(dicTeraph.upMaterial);
if(!isEnough) break; // 消耗不足
let num = getRandValueByMinMax(TERAPH_RANDOM.MIN, TERAPH_RANDOM.MAX); // 强化时随机增加 2-4 属性
let arr = getRandEelm(attrs, num); // 随机出的属性id
let critical = getRandValueByMinMax(0, 100);//属性暴击率
if(teraph.criCount == undefined || teraph.count == undefined) {
teraph.criCount = 0;
teraph.count = 0;
}
let isCritical = critical <= dicTeraph.criRate; // 每10次需要2次保底暴击
if(!isCritical && Math.floor((teraph.count + 2)/10) * 2 > teraph.criCount) {
isCritical = true;
} else if (isCritical && Math.ceil(teraph.count/10) * 2 <= teraph.criCount) {
isCritical = false;
}
teraph.count ++;
if(isCritical) teraph.criCount ++;
let criEffect = isCritical?dicTeraph.criEffect: 1; // 暴击效果
for (let attrId of arr) {
let val = teraph.attr.get(attrId); // 已有的强化值
val += dicTeraph.mainAttrUp.get(attrId) * criEffect;
let max = dicTeraph.mainAttrMax.get(attrId);
if(val > max) {
val = max;
let attrIndex = attrs.indexOf(attrId);
attrs.splice(attrIndex, 1);
}
teraph.attr.set(attrId, val);
if(isCritical) criAttr.push(attrId);
}
times++;
}
return { times, consumes: check.getConsume(), criAttr }
}
export async function getSimpleRoleInfo(roleId: string) {
if (!roleId) return null;
let role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.SHOW_SIMPLE, true);
return pick(role, ['roleId', 'roleName', 'head', 'frame', 'spine', 'lv', 'title', 'job', 'quitTime', 'loginTime', 'vLv', 'guildName', 'serverId', 'userInfo']);
}
export async function getSimpleRoleInfos(roleIds: string[]) {
if (!roleIds || !roleIds.length) return null;
let roles = await RoleModel.findByRoleIds(roleIds, ROLE_SELECT.SHOW_SIMPLE, true);
return roles.map(role => pick(role, ['roleId', 'roleName', 'head', 'frame', 'spine', 'lv', 'title', 'job', 'quitTime', 'loginTime', 'vLv', 'guildName', 'serverId', 'userInfo']));
}
/**
* 百家学宫
* @param roleId
*/
export async function getSchoolList(roleId: string) {
const dicPosition = decodeIdCntArrayStr(SCHOOL.SCHOOL_POSITION, 1); // id=>isOpen
const userSchoolList = await SchoolModel.findByRoleId(roleId);
let school = new Array<SclResultInter>();
gameData.school.forEach((dicSchool) => {
let position = new Array<SclPosInter>();
dicPosition.forEach((isOpen, dicId) => {
let id = parseInt(dicId);
let userSchool = userSchoolList.find(cur => cur.schoolId == dicSchool.id && cur.positionId == id);
if (userSchool) {
position.push({
id,
hid: userSchool.hid,
isOpen: userSchool.isOpen
});
} else {
position.push({
id,
hid: 0,
isOpen: !!isOpen
});
}
});
school.push({
id: dicSchool.id,
position
});
});
return school;
}
function getDefaultHeroInfos(heroes: Map<number, HeroUpdate>, skins: Map<number, SkinUpdate>) {
const initInfos: { heroInfo: HeroUpdate, skinInfo: SkinUpdate}[] = [];
for(let hid of DEFAULT_HEROES) {
initInfos.push({
heroInfo: heroes.get(hid),
skinInfo: skins.get(hid)
});
}
return initInfos;
}
export function getDefaultRoleInfo(heroes: Map<number, HeroUpdate>, skins: Map<number, SkinUpdate>, role:RoleUpdate, figureInfo: { heads: Figure[], frames: Figure[], spines: Figure[] }) {
const initInfos = getDefaultHeroInfos(heroes, skins);
return { initInfos, role, figureInfo };
}
export function getInitHeroById(hid: number) {
return {
heroInfo: pinus.app.get('initHeroes').get(hid),
skinInfo: pinus.app.get('initSkins').get(hid)
}
}
export function addConsumeToHero(oldConsume: Reward[] = [], consumes: ItemInter[] = []) {
if(!oldConsume) oldConsume = [];
let consumeMap = new Map<number, number>();
for(let { id, count = 1 } of consumes) {
if(!consumeMap.has(id)) {
consumeMap.set(id, count);
} else {
consumeMap.set(id, consumeMap.get(id) + count);
}
}
let newConsume: Reward[] = [];
for(let {id, count} of oldConsume) {
if(consumeMap.has(id)) {
newConsume.push({ id, count: count + consumeMap.get(id)});
consumeMap.delete(id);
} else {
newConsume.push({ id, count });
}
}
for(let [id, count] of consumeMap) {
newConsume.push({ id, count });
}
return newConsume;
}
export function checkUnlockTalentCondition(hid: number, id: number, talents: Talent[], usedTalentPoint: number) {
let dicHero = gameData.hero.get(hid);
let dicHeroTalent = gameData.heroTalent.get(id);
if(!dicHeroTalent) return false;
if(dicHero.talentId != dicHeroTalent.talentId) return false;
// 累计消耗n点天赋点
if(dicHeroTalent.preTotalPoint > usedTalentPoint) return false;
// 互斥的天赋没有被解锁
for(let { type, ids } of dicHeroTalent.relation) {
if(type == TALENT_RELATION_TYPE.CONFLICT) {
let hasTalent = talents.find(talent => ids.indexOf(talent.id) != -1);
if(hasTalent) return false;
}
}
// 前置节点
let orFlag = false; // 只要其中一个满足就可以
let maxPrecost = 0; // 前置节点最多的消耗
for(let arr of dicHeroTalent.prepositionId) {
let andFlag = true; // arr内所有节点都需要满足
for(let id of arr) {
let curTalent = talents.find(cur => cur.id == id);
if(curTalent) {
let dic = gameData.heroTalent.get(id);
if(dic) {
let allCost = 0;
for(let { lv, cost } of dic.level) {
if(curTalent.level >= lv) allCost += cost;
}
if(allCost > maxPrecost) maxPrecost = allCost;
}
} else {
andFlag = false;
}
}
if(andFlag) orFlag = true;
}
if(!orFlag) return false;
// 在前置节点中消耗至少n点天赋点在有多个前置节点时取最高的1个
if(dicHeroTalent.preSinglePoint > maxPrecost) return false;
return true;
}
export function updateSkinTalent(skins: HeroSkin[], newTalent: Talent, usedTalentPoint: number) {
let newSkins: HeroSkin[] = [];
let newTalents: Talent[] = [];
for(let skin of skins) {
if(skin.enable) {
let hasNewTalent = false;
for(let talent of skin.talent) {
if(talent.id == newTalent.id) {
newTalents.push(newTalent);
hasNewTalent = true;
} else {
newTalents.push(talent);
}
}
if(!hasNewTalent) newTalents.push(newTalent);
newSkins.push({...skin, talent: newTalents, usedTalentPoint })
} else {
newSkins.push(skin);
}
}
return { newSkins, newTalents };
}
export function initSkinTalent(skins: HeroSkin[], isAll = false) {
let newSkins: HeroSkin[] = [];
for(let skin of skins) {
if(isAll || skin.enable) {
newSkins.push({ ...skin, talent: getHeroInitTalent(skin.skinId), usedTalentPoint: 0 });
} else {
newSkins.push(skin);
}
}
return newSkins
}
export function checkSystemIsOpen(role: RoleType, id: SYSTEM_OPEN_ID) {
if(!role || !role.hasInit || !role.guide) return false;
let dicSystemOpenTime = gameData.sysOpenTime.get(id);
if(!dicSystemOpenTime) return false;
let guideId = dicSystemOpenTime.warId > 0? GuideUnloadNum.GkNewFuncNum + dicSystemOpenTime.warId: GuideUnloadNum.LvUpNum + dicSystemOpenTime.lv;
return role.guide.indexOf(guideId) != -1;
}