import { mergeSameGoods, getRandEelm, getRandValueByMinMax } from '../pubUtils/util'; import { EquipModel, RandMain, RandSe } from "../db/Equip"; import { HeroModel, HeroType } from "../db/Hero"; import { getGoodById, gameData, getJewelById, getQuenchGradeByValue, getQuenchConsume, getQuenchByQualityAndGrade } from "../pubUtils/data"; import { calPlayerCeAndSave } from "./playerCeService"; import { CONSUME_TYPE, HERO_SYSTEM_TYPE, ITID, TASK_TYPE } from "../consts"; import { EquipType } from "../db/Equip"; import { calEquipSeids } from '../pubUtils/playerCe'; import { checkTask, checkTaskWithHero, checkTaskWithEquip, checkActivityTask } from './taskService'; import { handleCost } from './rewardService'; import { dicGoods, DicGoods } from '../pubUtils/dictionary/DicGoods'; import { QuenchLogParam } from '../domain/roleField/equip'; import { QUENCH } from '../pubUtils/dicParam'; import { DicQuenchQuality } from '../pubUtils/dictionary/DicQuenchQuality'; /** * 校验前端传入的消耗数量是否准确,并返回消耗的道具并加上特殊材料needConsumes * @param consumes * @param jewel * @param jewelCount */ export function checkMaterialEnough(consumes: Array<{ id: number, count: number }>, jewel: number, jewelCount: number) { let comJewelMap = new Map(); // good_id => count let needConsumes:{ id: number, count: number, ratio?: number }[] = [] for(let {id, count} of consumes) { if(!comJewelMap.has(id)) { comJewelMap.set(id, count); } else { comJewelMap.set(id, comJewelMap.get(id) + count); } } function checkCurMeterial(target: number, targetCount: number) { let dic = getGoodById(target); if(!dic) return false; let { composeMaterial } = dic; let isEnough = true; for(let { id, count } of composeMaterial) { let consumeCount = comJewelMap.get(id)||0; let dicGood = getGoodById(id); if(!dicGoods) { isEnough = false; break; } let dicItid = ITID.get(dicGood.itid); if(dicItid.type != CONSUME_TYPE.JEWEL) { if(consumeCount < count * targetCount) { isEnough = false; break; } else { comJewelMap.set(id, consumeCount - count * targetCount); needConsumes.push({ id, count: count * targetCount }); } } else { if(consumeCount < count * targetCount) { comJewelMap.set(id, 0); needConsumes.push({ id, count: consumeCount }); isEnough = checkCurMeterial(id, count * targetCount - consumeCount); } else { comJewelMap.set(id, consumeCount - count * targetCount); needConsumes.push({ id, count: count * targetCount }); } } } return isEnough } let isEnough = checkCurMeterial(jewel, jewelCount); return isEnough? needConsumes: false; } /** * 将装备卸载下来,并检查是否有替换装备的武将,若有则替换 * 武将A(装备A)&武将B(装备B) ==> 武将A(装备B)&武将B(装备A) * 武将A(装备A)& 装备B ==> 武将A(装备B)& 装备A * @param roleId 玩家id * @param sid * @param equip 目标武将要卸下的装备,装备A * @param hid 要装上的装备备原来装备着的武将id, 武将B * @param id 装备类型 * @param seqId 要装上的装备的唯一id 装备B */ export async function changeEquip(serverId: number, roleId: string, sid: string, equipA: EquipType, hid: number, id: number, equipB: EquipType, funcs: number[]) { let heroB: HeroType; if (!!hid) //需要卸下或者替换的武将 heroB = await HeroModel.findByHidAndRoleWithEquip(hid, roleId);//需要替换的武将 if (!!equipA) {//需要卸下的装备 if (!!heroB) { let goodInfo = getGoodById(equipA.id); if (goodInfo.lvLimited > heroB.lv) { let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力 return res; } if (checkEquipCanPut(hid, equipA.id)) { let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力 return res; } let res = await dressEquip(serverId, roleId, sid, heroB, equipA, funcs);//替换给武将,并计算战力 return res; } else { let res = await takeOffEquipAndCalPlayerCe(roleId, sid, null, equipA, id, funcs);//卸下装备并重算战力 return res; } } else if (!!heroB) {//从穿戴装备的武将上卸下装备 let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力 return res } } /** * 从穿戴装备的武将上卸下装备,并重算战力 * @param roleId * @param sid * @param seqId * @param hero * @param id */ export async function takeOffEquipAndCalPlayerCe(roleId: string, sid: string, hero: HeroType, equip: EquipType, id: number, funcs: number[]) { console.log(roleId, sid, hero, equip, id) if (hero) { let args = calEquipSeids(hero); hero = await HeroModel.removeEquip(roleId, hero.hid, id, equip._id); await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args); await checkTaskWithHero(roleId, sid, funcs, TASK_TYPE.EQUIP_BY_HERO, hero, [-1]); } else { await EquipModel.putOnOrOff(equip._id, 0); } // 任务 await checkTask(roleId, sid, funcs, TASK_TYPE.EQUIP_SUM, -1, true, {}); await checkTaskWithEquip(roleId, sid, funcs, TASK_TYPE.EQUIP_QUALITY, equip, [-1]); return { seqId: equip.seqId, hid: 0, id: equip.id, ePlaceId: equip.ePlaceId }; } /** * 穿戴装备并重算战力 * @param roleId * @param sid * @param hero * @param equip */ export async function dressEquip(serverId: number, roleId: string, sid: string, hero: HeroType, equip: EquipType, funcs: number[]) { let args = calEquipSeids(hero); hero = await HeroModel.addEquip(roleId, hero.hid, equip.ePlaceId, equip._id); await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args); // 任务 await checkTask(roleId, sid, funcs, TASK_TYPE.EQUIP_SUM, 1, true, {}); await checkTaskWithHero(roleId, sid, funcs, TASK_TYPE.EQUIP_BY_HERO, hero, [1]); await checkTaskWithEquip(roleId, sid, funcs, TASK_TYPE.EQUIP_QUALITY, equip, [1]); await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.EQUIP_QUALITY, 1, { quality: equip.quality }) await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.EQUIP_SUM, 1) return { seqId: equip.seqId, hid: hero.hid, id: equip.id, ePlaceId: equip.ePlaceId }; } export function checkEquipCanPut(hid: number, id: number) { let dicGood = gameData.goods.get(id); let dicHero = gameData.hero.get(hid); let dicJob = gameData.job.get(dicHero.jobid); if(dicGood.jobLimited.indexOf(0) == -1 && dicGood.jobLimited.indexOf(dicJob.job_class) == -1) return false; if(dicGood.charLimited.indexOf(0) == -1 && dicGood.charLimited.indexOf(hid) != -1) return false; return true } /** * 淬火一次 * @param roleId 玩家id * @param sid 玩家sid * @param randMain 装备上的属性随机值 * @param dicQuench 淬火表 * @param dicGoods 物品表 * @returns */ export async function quenchOnce(roleId: string, sid: string, randMain: RandMain[], dicQuench: DicQuenchQuality, dicGoods: DicGoods) { let { quality, equipLvl } = dicGoods; let canRandMain = randMain.filter(cur => { // 已升满的属性就不再淬火了 return cur.rand < dicQuench.singleRatioMax; }); let randMainResult = getRandEelm(canRandMain); if(randMainResult.length == 0) return false; let add = new Map(); // id => value,增加的数量 let isCriticle = Math.random() * 100 < dicQuench.critProbability; // 暴击 let addAttr = isCriticle? dicQuench.critEffect * QUENCH.QUENCH_UNIT_UPRATIO: QUENCH.QUENCH_UNIT_UPRATIO; let overAttr = randMainResult[0].rand + addAttr - dicQuench.singleRatioMax; // 如果有暴击,超出当前品相上限时 if(overAttr > 0) { // 超出,转到另一条属性 let anotherRandMain = canRandMain.filter(cur => { return cur.id != randMainResult[0].id; }); if(anotherRandMain.length > 0) { let anotherOverAttr = anotherRandMain[0].rand + overAttr - dicQuench.singleRatioMax; if(anotherOverAttr > 0) { add.set(anotherRandMain[0].id, overAttr - anotherOverAttr); } else { add.set(anotherRandMain[0].id, overAttr); } } add.set(randMainResult[0].id, addAttr - overAttr); } else { add.set(randMainResult[0].id, addAttr); } let value = 0; for(let r of randMain) { if(add.has(r.id)) { r.rand += add.get(r.id); } value += r.rand; } let grade = getQuenchGradeByValue(quality, value/2); // 消耗 let consumes = getQuenchConsume(equipLvl, quality); let result = await handleCost(roleId, sid, consumes); if(!result) return false; let log = new QuenchLogParam(isCriticle, add); return { randMain, grade, log }; } /** * 检查该品相是否到顶 * @param quality 品质 * @param grade 品相 * @param randMain 装备上的随机值 * @returns */ export function checkQuenchMaxByQualityAndGrade(quality: number, grade: number, randMain: RandMain[]) { let isMax = true; let dic = getQuenchByQualityAndGrade(quality, grade); if(!dic) return true; for(let { rand } of randMain) { if(rand < dic.max) isMax = false; } return isMax; } export function getRandSeResult(id: number, randSe: RandSe[]) { let dicGoods = gameData.goods.get(id); if (!dicGoods) return false; let { randomEffect } = dicGoods; // 配置的可随机seid let chosen = randSe.filter(cur => cur.locked).map(cur => cur.seid); // 上一轮随机出来的 let randomResult: number[] = getRandEelm(randomEffect.filter(cur => !chosen.includes(cur)), randSe.length); // 随机出的结果 for (let i = 0; i < randSe.length; i++) { if (!randSe[i].locked) { let random = gameData.randomEffectPool.get(randomResult[i]); if (!random) break; let rand = 0; if (random.id > 0) rand = getRandValueByMinMax(random.Min, random.Max, 0); randSe[i].seid = random.id; randSe[i].rand = rand; } } return randSe } export async function refineOnce(roleId: string, sid: string, lv: number, refineLv: number) { let dicRefine = gameData.refine.get(refineLv + 1); if (!dicRefine) return false; if(lv < dicRefine.levelLimited) return false; // 消耗 let result = await handleCost(roleId, sid, dicRefine.consume); if (!result) return false; return refineLv + 1; } export function checkRefineReachNextLv(oldRefineLv: number, refineLv: number) { let oldDic = gameData.refine.get(oldRefineLv); let dic = gameData.refine.get(refineLv); if(!oldDic || !dic) return true; return dic.level > oldDic.level; } export function calEquipCe(goodsAbility: Map, randMain: RandMain[]) { let ce = 0; for(let [ id, ratio ] of gameData.equipAttributeRatio) { let valueBase = goodsAbility.get(id); let curRand = randMain.find(cur => cur.id == id); let valueRand = curRand?curRand.rand: 0; ce += Math.floor(valueBase * valueRand * ratio / 100); } return ce }