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 = new Map(); // 玩家已有的东西 private notEnoughItems: Map = 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(); 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) { 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(); 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(); let allCostItem = new Map(); //计算升品所需消耗 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; }