Files
ZYZ/game-server/app/services/role/checkMaterial.ts
luying f09ebd56b1 feat(将魂出售): 修复将魂回收的问题
4cfbce94e - 2fa8c7a91 by zhangxk
2023-07-19 15:51:04 +08:00

423 lines
16 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 { CURRENCY_TYPE, HANDLE_REWARD_TYPE, CURRENCY_BY_TYPE, CONSUME_TYPE, ITID_STONE_LIMIT, HERO_GROW_MAX, ABI_STAGE } from '../../consts';
import { RoleModel, RoleType } from '../../db/Role';
import { ItemModel, ItemType } from '../../db/Item';
import { ItemInter, RewardInter, } from '../../pubUtils/interface';
import { gameData, getHeroStarByQuality, getHeroWakeByQuality } from '../../pubUtils/data';
import { sortItems } from './util';
import { HeroType } from '../../db/Hero';
export class CheckMeterial {
private roleId: string;
private itemsIndb: Map<number, number> = new Map(); // 玩家已有的东西
private notEnoughItems: Map<number, number> = new Map(); // 缺少的数量
private consumes: ItemInter[] = []; // 消耗,正向数
private canReplace: boolean = false; // 是否可以被通用的啥代替代替
private tempConsumes: ItemInter[] = [];
private goldId = CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD);
private coinId = CURRENCY_BY_TYPE.get(CURRENCY_TYPE.COIN);
constructor(roleId: string, role?: RoleType, items?: ItemType[]) {
this.roleId = roleId;
if (role) {
this.itemsIndb.set(this.goldId, role.gold);
this.itemsIndb.set(this.coinId, role.coin);
}
if (items && items.length) {
for (let { id, count } of items) {
this.itemsIndb.set(id, count);
}
}
}
private pushToNotEnoughItems(id: number, count: number) {
if (!this.notEnoughItems.has(id)) {
this.notEnoughItems.set(id, 0);
}
this.notEnoughItems.set(id, this.notEnoughItems.get(id) + count);
}
public getNotEnoughItems() {
let map = new Map<number, number>();
for (let [id, count] of this.notEnoughItems) {
map.set(id, count);
}
return map;
}
public async decrease(goods: { id: number, count: number }[]) {
this.tempConsumes.splice(0, this.tempConsumes.length);
this.notEnoughItems.clear();
let { items, gold, coin } = sortItems(goods, HANDLE_REWARD_TYPE.COST);
for (let { id, count } of items) {
let notEnoughCount = await this.decreaseItem(id, count);
if (notEnoughCount > 0) {
let isEnough = await this.checkReplaceItem(id, notEnoughCount);
if (isEnough) {
this.tempConsumes.push({ id, count: count - notEnoughCount });
} else {
return false;
}
}
}
if (gold.length > 0) {
let isEnough = await this.decreaseGold(gold);
if (!isEnough) return false;
}
if (coin.length > 0) {
let isEnough = await this.decreaseCoin(coin);
if (!isEnough) return false;
}
this.consumes.push(...this.tempConsumes);
return true;
}
// 当消耗不足的时候,不提前返回,也不去算元宝和铜币
public async decreaseItemsContinue(goods: { id: number, count: number }[]) {
this.tempConsumes.splice(0, this.tempConsumes.length);
this.notEnoughItems.clear();
let { items } = sortItems(goods, HANDLE_REWARD_TYPE.COST);
let itemIsEnough = true;
for (let { id, count } of items) {
let notEnoughCount = await this.decreaseItem(id, count);
if (notEnoughCount > 0) {
let isEnough = await this.checkReplaceItem(id, notEnoughCount);
if (isEnough) {
this.tempConsumes.push({ id, count: count - notEnoughCount });
} else {
itemIsEnough = false;
}
}
}
this.consumes.push(...this.tempConsumes);
return itemIsEnough;
}
public setCanReplace(canReplace: boolean) {
this.canReplace = canReplace;
}
private async decreaseItem(id: number, count: number) {
if (!this.itemsIndb.has(id)) {
let item = await ItemModel.findbyRoleAndGid(this.roleId, id);
if (!item) {
this.pushToNotEnoughItems(id, count);
return count;
}
this.itemsIndb.set(id, item.count);
}
if (this.itemsIndb.get(id) < count) {
let notEnoughCount = count - this.itemsIndb.get(id);
this.pushToNotEnoughItems(id, notEnoughCount);
this.itemsIndb.set(id, 0);
return notEnoughCount;
} else {
this.itemsIndb.set(id, this.itemsIndb.get(id) - count);
this.tempConsumes.push({ id, count });
return 0
}
}
private async checkReplaceItem(id: number, count: number) {
if (!this.canReplace) return false;
let relationGoodId = gameData.relationGoods.get(id);
if (!relationGoodId) return false;
if (relationGoodId == this.goldId) {
return await this.decreaseGold([{ count }]);
} else if (relationGoodId == this.coinId) {
return await this.decreaseCoin([count]);
} else {
let cnt = await this.decreaseItem(relationGoodId, count);
return cnt == 0
}
}
private async decreaseGold(gold: { count: number }[]) {
if (!this.itemsIndb.has(this.goldId)) {
let role = await RoleModel.findByRoleId(this.roleId, 'gold coin');
this.itemsIndb.set(this.goldId, role.gold);
this.itemsIndb.set(this.coinId, role.coin);
}
let goldCost = gold.reduce((pre, cur) => { return pre + cur.count }, 0);
if (this.itemsIndb.get(this.goldId) < goldCost) {
this.pushToNotEnoughItems(this.goldId, goldCost - this.itemsIndb.get(this.goldId));
this.itemsIndb.set(this.goldId, 0);
return false;
}
this.itemsIndb.set(this.goldId, this.itemsIndb.get(this.goldId) - goldCost);
this.tempConsumes.push({ id: this.goldId, count: goldCost });
return true
}
private async decreaseCoin(coin: number[]) {
if (!this.itemsIndb.has(this.coinId)) {
let role = await RoleModel.findByRoleId(this.roleId, 'gold coin');
this.itemsIndb.set(this.goldId, role.gold);
this.itemsIndb.set(this.coinId, role.coin);
}
let coinCost = coin.reduce((pre, cur) => pre + cur, 0);
if (this.itemsIndb.get(this.coinId) < coinCost) {
this.pushToNotEnoughItems(this.coinId, coinCost - this.itemsIndb.get(this.coinId));
this.itemsIndb.set(this.coinId, 0);
return false;
}
this.itemsIndb.set(this.coinId, this.itemsIndb.get(this.coinId) - coinCost);
this.tempConsumes.push({ id: this.coinId, count: coinCost });
return true;
}
private getMaterialEnough(materials: RewardInter[], notEnoughItems: Map<number, number>) {
let newMaterials: RewardInter[] = [];
for (let { id, count } of materials) {
if (notEnoughItems.has(id)) {
newMaterials.push({ id, count: count - notEnoughItems.get(id) });
} else {
newMaterials.push({ id, count });
}
}
return newMaterials;
}
// 检查地玉石是否可以合成
public async composeStone(id: number, count: number) {
let dicStone = gameData.stone.get(id);
if (!dicStone || dicStone.composeMaterial.length <= 0) return false; // 1阶石头不能再从下合成返回不行
let materials = dicStone.composeMaterial.map(cur => ({ ...cur, count: cur.count * count }));
let isEnough = await this.decrease(materials);
if (!isEnough) {
let notEnoughItems = this.getNotEnoughItems();
let newMaterials = this.getMaterialEnough(materials, notEnoughItems);
let isEnough = await this.decrease(newMaterials); // 消耗掉除了不足的部分以外的其他部分
if (!isEnough) return false;
let isAllOK = true; // 如果有石头不足向下补充isAllOK标识不足的都能补充上
for (let [id, count] of notEnoughItems) {
let isEnough = await this.composeStone(id, count);
if (!isEnough) {
isAllOK = false; break;
}
}
return isAllOK;
} else {
return true;
}
}
public getConsume() {
return this.consumes;
}
};
/**
* 获取升品所需消耗
* @param id
* @returns
*/
export async function getComposeStoneNeedCost(id: number) {
let dicStone = gameData.stone.get(id);
if (!dicStone || dicStone.composeMaterial.length <= 0) return false;
return dicStone.composeMaterial;
}
/**
* 获取当前类型6品以下玉石升级相关道具
* @param {string} roleId
* @param {number} itId
* @returns
*/
export async function getCurItem(roleId: string, itId: number) {
let curItem = new Map<number, number>();
let stoneItId = gameData.stoneItId.get(itId);
let goodIds = [];
for (const { good_id, lv } of stoneItId) {
if (lv > ITID_STONE_LIMIT) continue;
let nextLvMaterial = await getComposeStoneNeedCost(good_id);
if (!nextLvMaterial) continue;
for (let material of nextLvMaterial) {
goodIds.push(material.id);
}
}
let items = await ItemModel.find({ roleId, id: { $in: goodIds } });
if (!items || items.length == 0) return curItem;
for (let { id, count } of items) {
if (count == 0) continue;
curItem.set(id, count);
}
return curItem;
}
/**
* 计算玉石一键升品总产出与消耗
* @param initialJewel
* @param curItem
* @returns
*/
export async function getComposeStoneCostAndAdd(curItem, itId) {
let allAddItem = new Map<number, number>();
let allCostItem = new Map<number, number>();
//计算升品所需消耗
for (let lv = ITID_STONE_LIMIT - 1; lv >= 1; lv--) {
for (let indexLv = lv; indexLv < ITID_STONE_LIMIT; indexLv++) {
let id = gameData.stoneItIdLv.get(`${itId}_${indexLv}`);
let tempItem1 = curItem.get(id) || 0;
let tempItem2 = allAddItem.get(id) || 0
let count = tempItem1 + tempItem2;
if (count == 0) continue;//当前品没有,无法进行升下一品
let nextLvId = gameData.stoneItIdLv.get(`${itId}_${indexLv + 1}`);
if (!nextLvId) continue; //不存在下一品
//计算升到下一阶消耗
let nextLvMaterial = await getComposeStoneNeedCost(nextLvId);
if (!nextLvMaterial || nextLvMaterial.length == 0) {
//升下一品不存在消耗
//产出
let addCount = allAddItem.get(nextLvId) || 0
allAddItem.set(nextLvId, addCount + count);
continue;
}
// 计算能升品的下一品新增数量
//设置初始数量
let initial = nextLvMaterial[0];
if (!initial.count || initial.count == 0) {
console.error("dic_zyz_stone配置错误, good_id=%s", nextLvId);
continue;
}
let val1 = curItem.get(initial.id) || 0;
let val2 = allAddItem.get(initial.id) || 0;
let nextLvCount = Math.floor((val1 + val2) / initial.count);//设置初始值
for (let material of nextLvMaterial) {
if (!material.count || material.count == 0) {
nextLvCount = 0;
console.error("dic_zyz_stone配置错误, good_id=%s", nextLvId);
continue;
}
let tempCount1 = curItem.get(material.id) || 0;
let tempCount2 = allAddItem.get(material.id) || 0;
nextLvCount = Math.min(nextLvCount, Math.floor((tempCount1 + tempCount2) / material.count));
}
if (nextLvCount == 0) {
// console.log('---------------- curItem', curItem);
// console.log('---------------- indexLv', indexLv);
// console.log('---------------- nextLvCount', nextLvCount);
// console.log('---------------- allCostItem', allCostItem);
// console.log('---------------- allAddItem', allAddItem);
continue;// 不能升品
}
// 消耗
for (let material of nextLvMaterial) {
let needCostCount = nextLvCount * material.count; //需要消耗数量
let tempCount1 = curItem.get(material.id) || 0; // 当前item中已有的数量
let tempCount2 = allAddItem.get(material.id) || 0; // 当前总产出中已有的数量
let tempCostCount = allCostItem.get(material.id) || 0; // 当前总消耗中已有的数量
let diff = tempCount1 - needCostCount;
if (diff > 0) {// 先消耗item中的
curItem.set(material.id, diff);
allCostItem.set(material.id, tempCostCount + needCostCount); //记录入总消耗(仅item中allAddItem消耗会在其中减掉)
continue;
}
curItem.delete(material.id);
if (tempCount1 != 0) allCostItem.set(material.id, tempCostCount + tempCount1);//记录入总消耗0不记录
if (tempCount2 - Math.abs(diff) < 0) return;//异常
allAddItem.set(material.id, (tempCount2 - Math.abs(diff)));
}
// 产出
let addCount = allAddItem.get(nextLvId) || 0
allAddItem.set(nextLvId, addCount + nextLvCount);
}
}
// console.log('---------------- allCostItem', allCostItem);
// console.log('---------------- allAddItem', allAddItem);
return { allCostItem, allAddItem };
}
/**
* 计算升到6彩后剩余碎片
* @param roleId
* @param hid
* @returns
*/
export async function calUpSixColorsResidueFragment(roleId: string, hero: HeroType, hid: number, count?: number) {
let needFragment = 0;
let dicHero = gameData.hero.get(hid);
if (!dicHero) return;
let { pieceId, jobid } = dicHero;
let dicJob = gameData.job.get(jobid);
if (!dicJob) return;
let curItemCount = count;
if (!count) {
let item = await ItemModel.findbyRoleAndGid(roleId, pieceId);
curItemCount = item?.count || 0;
}
if (curItemCount < 0) return;
let { star: oldStar, starStage: oldStarStage, quality: oldQuality, colorStar: oldColorStar, colorStarStage: oldColorStarStage, } = hero;
// 计算升星
if (oldStar < HERO_GROW_MAX.STAR) {
for (let starIndex = oldStar; starIndex < HERO_GROW_MAX.STAR; starIndex++) {
const curDicHeroStar = getHeroStarByQuality(dicJob.job_class, oldQuality, starIndex);
if (starIndex == oldStar) {
needFragment += (curDicHeroStar?.advanceUpFragmentNum || 0) * (ABI_STAGE.END - oldStarStage);
continue;
}
needFragment += (curDicHeroStar?.advanceUpFragmentNum || 0) * ABI_STAGE.END;
}
}
if (curItemCount < needFragment) return;
// 计算升品
if (oldQuality < HERO_GROW_MAX.QUALITY) {
for (let qualityIndex = oldQuality; qualityIndex < HERO_GROW_MAX.QUALITY; qualityIndex++) {
const curDicHeroQualityUp = gameData.heroQualityUp.get(qualityIndex);
needFragment += curDicHeroQualityUp?.fragmentNum || 0;
}
}
if (curItemCount < needFragment) return;
// 计算觉醒升6彩
if (oldColorStar < HERO_GROW_MAX.COLORSTAR) {
for (let colorStarIndex = oldColorStar; colorStarIndex < 6; colorStarIndex++) {
const curDicHeroStar = getHeroWakeByQuality(dicJob.job_class, dicHero.quality, colorStarIndex)
if (colorStarIndex == 0) {
needFragment += curDicHeroStar?.fragmentNum || 0;
continue;
}
if (colorStarIndex == oldColorStar) {
needFragment += (curDicHeroStar?.fragmentNum || 0) * (ABI_STAGE.END - oldColorStarStage);
continue;
}
needFragment += (curDicHeroStar?.fragmentNum || 0) * ABI_STAGE.END;
}
}
if (curItemCount < needFragment) return;
return curItemCount - needFragment;
}