282 lines
10 KiB
TypeScript
282 lines
10 KiB
TypeScript
import { mergeSameGoods, getRandEelm, getRandValueByMinMax } from '../pubUtils/util';
|
||
import { EquipModel, RandMain } from "../db/Equip";
|
||
import { EPlace, HeroModel, HeroType, Stone } from "../db/Hero";
|
||
import { getGoodById, gameData, getQuenchGradeByValue, getQuenchConsume, getQuenchByQualityAndGrade } from "../pubUtils/data";
|
||
import { calPlayerCeAndSave } from "./playerCeService";
|
||
import { CONSUME_TYPE, HERO_SYSTEM_TYPE, ITID, TASK_TYPE } from "../consts";
|
||
import { dicGoods, DicGoods } from '../pubUtils/dictionary/DicGoods';
|
||
import { QuenchLogParam } from '../domain/roleField/equip';
|
||
import { QUENCH } from '../pubUtils/dicParam';
|
||
import { DicQuenchQuality } from '../pubUtils/dictionary/DicQuenchQuality';
|
||
import { JewelType, RandSe } from '../db/Jewel';
|
||
import { getJewelRandSe } from '../pubUtils/itemUtils';
|
||
|
||
/**
|
||
* 校验前端传入的消耗数量是否准确,并返回消耗的道具并加上特殊材料needConsumes
|
||
* @param consumes
|
||
* @param jewel
|
||
* @param jewelCount
|
||
*/
|
||
export function checkMaterialEnough(consumes: Array<{ id: number, count: number }>, jewel: number, jewelCount: number) {
|
||
let comJewelMap = new Map<number, number>(); // good_id => count
|
||
let needConsumes:{ id: number, count: 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;
|
||
}
|
||
|
||
export function checkEquipCanPut(hero: HeroType, id: number) {
|
||
let hid = hero.skinId;
|
||
let dicGood = gameData.goods.get(id);
|
||
if(dicGood.lvLimited > hero.lv) return false;
|
||
let dicHero = gameData.hero.get(hid);
|
||
if(dicGood.jobLimited.indexOf(0) == -1 && dicGood.jobLimited.indexOf(dicHero.jobClass) == -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(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<number, number>(); // 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 log = new QuenchLogParam(isCriticle, add);
|
||
return { randMain, grade, log, consumes };
|
||
}
|
||
|
||
/**
|
||
* 检查该品相是否到顶
|
||
* @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 { randomEffect, effectCount } = gameData.jewel.get(id);
|
||
|
||
let chosen = randSe.filter(cur => cur.locked).map(cur => cur.seid); // 上一轮随机出来的
|
||
let randomResult: number[] = getRandEelm(randomEffect.filter(cur => !chosen.includes(cur)), effectCount); // 随机出的结果
|
||
if(randomResult.length < effectCount) { // 去上轮之后不够,把上轮加入
|
||
let chosenRandom = getRandEelm(chosen, effectCount - randomResult.length);
|
||
randomResult.push(...chosenRandom);
|
||
}
|
||
if(randomResult.length < effectCount) { // 还是不够
|
||
let allRandom = getRandEelm(randomEffect, effectCount - randomResult.length);
|
||
randomResult.push(...allRandom);
|
||
}
|
||
|
||
let newRandSe: RandSe[] = [];
|
||
for (let i = 0; i < effectCount; i++) {
|
||
if(randSe[i]) {
|
||
if(randSe[i] && randSe[i].locked) {
|
||
newRandSe.push(randSe[i]);
|
||
} else {
|
||
newRandSe.push(getJewelRandSe(randSe[i].id, randomResult[i]));
|
||
}
|
||
} else {
|
||
newRandSe.push(getJewelRandSe(i + 1, randomResult[i]));
|
||
}
|
||
}
|
||
|
||
return newRandSe
|
||
}
|
||
|
||
export async function refineOnce(lv: number, refineLv: number) {
|
||
|
||
let dicRefine = gameData.refine.get(refineLv + 1);
|
||
if (!dicRefine) return false;
|
||
|
||
if(lv < dicRefine.levelLimited) return false;
|
||
|
||
return {
|
||
refineLv: refineLv + 1,
|
||
consumes: dicRefine.consume
|
||
}
|
||
}
|
||
|
||
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<number, number>, 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
|
||
}
|
||
|
||
export function updateStone(origin: Stone[], id: number, target: number) {
|
||
let newStones: Stone[] = [];
|
||
let hasTarget = false;
|
||
for(let stone of origin) {
|
||
if(stone.id == id) {
|
||
newStones.push({ id, stone: target });
|
||
hasTarget = true;
|
||
} else {
|
||
newStones.push(stone);
|
||
}
|
||
}
|
||
if(!hasTarget) {
|
||
newStones.push({ id, stone: target });
|
||
}
|
||
return newStones;
|
||
}
|
||
|
||
export function updateEplace(eplace: EPlace[], eplaceId: number, update: Partial<EPlace>) {
|
||
let newEplace: EPlace[] = [];
|
||
let updatedEplace: Partial<EPlace>[] = [];
|
||
for(let equip of eplace) {
|
||
if(equip.id == eplaceId) {
|
||
newEplace.push({ ...equip, ...update });
|
||
updatedEplace.push({ id: equip.id, equipId: equip.equipId, ...update });
|
||
} else {
|
||
newEplace.push(equip);
|
||
}
|
||
}
|
||
return {newEplace, updatedEplace};
|
||
}
|
||
|
||
export function updateEplaces(eplace: EPlace[], update: Map<number, Partial<EPlace>>) {
|
||
let newEplace: EPlace[] = [];
|
||
let updatedEplace: Partial<EPlace>[] = [];
|
||
for(let equip of eplace) {
|
||
if(update.has(equip.id)) {
|
||
newEplace.push({ ...equip, ...update.get(equip.id) });
|
||
updatedEplace.push({ id: equip.id, equipId: equip.equipId, ...update.get(equip.id) });
|
||
} else {
|
||
newEplace.push(equip);
|
||
}
|
||
}
|
||
return {newEplace, updatedEplace};
|
||
}
|
||
|
||
/**
|
||
* 检查天晶石能否装备上这个装备
|
||
* @param equip
|
||
* @param jewel
|
||
*/
|
||
export function checkJewelCanPutOnEquip(equip: EPlace, jewel: JewelType) {
|
||
// 位置是否满足
|
||
let dicJewel = gameData.jewel.get(jewel.id);
|
||
if(!dicJewel || dicJewel.eplaceId != equip.id) return false;
|
||
// 品质是否满足
|
||
let dicEquipQualityExtra = gameData.equipQualityExtra.get(equip.quality);
|
||
if(!dicEquipQualityExtra || dicEquipQualityExtra.jewelCnt == 0) return false;
|
||
return true
|
||
}
|
||
|
||
export function checkStoneCanPutOnEquip(equip: EPlace, id: number, stone: number) {
|
||
if(stone == 0) return true; // 卸载
|
||
// 位置是否满足
|
||
let dicStone = gameData.stone.get(stone);
|
||
if(!dicStone || dicStone.eplaceId != equip.id) return false;
|
||
// 品质是否满足
|
||
let dicEquipQualityExtra = gameData.equipQualityExtra.get(equip.quality);
|
||
if(!dicEquipQualityExtra || dicEquipQualityExtra.stoneCnt < id) return false;
|
||
return true;
|
||
} |