From dfe406d57a404835b58cfaa64127ccea0b62435a Mon Sep 17 00:00:00 2001 From: chenanghui <220722433@qq.com> Date: Mon, 12 Oct 2026 15:10:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=85=E8=A7=A3=E9=94=81=E6=A0=BC=E5=AD=90?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E5=A2=9E=E5=8A=A0=E5=B8=B8=E9=87=8F=E8=A1=A8?= =?UTF-8?q?=E7=AD=89=E7=BA=A7=E7=B4=AF=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../battle/ai/runtime/AiHeadlessBagHost.ts | 10 ++-- assets/script/battle/bag/BattleBagSession.ts | 59 +++++++++++++++++-- .../script/battle/view/CocosBagBoardView.ts | 9 +-- assets/script/battle/view/TextListLandHost.ts | 57 ++++++++++++++++-- assets/script/game/GameDataEnums.ts | 2 + 5 files changed, 117 insertions(+), 20 deletions(-) diff --git a/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts b/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts index 468fc66..07c0c18 100644 --- a/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts +++ b/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts @@ -146,12 +146,10 @@ export class AiHeadlessBagHost { const bag = this._bagSession; if (!bag) return; if (this._land.stateOf(slotIndex) !== TextListCellState.OpenNoDrag) return; - const born = this._land.promoteAround(slotIndex); - for (let i = 0; i < born.length; i++) { - bag.fillGateUnlockSlot(born[i]); - } - if (born.length > 0) { - aiOp(`AI 待开启推进 slot=${slotIndex} born=${born.join(',')}`); + const promoted = this._land.promoteAround(slotIndex); + bag.fillGateUnlockSlots(promoted.born, promoted.levelAdd); + if (promoted.born.length > 0) { + aiOp(`AI 待开启推进 slot=${slotIndex} born=${promoted.born.join(',')}`); this._logBagSlots('gateUnlock'); } } diff --git a/assets/script/battle/bag/BattleBagSession.ts b/assets/script/battle/bag/BattleBagSession.ts index c8b0fc4..fe727e7 100644 --- a/assets/script/battle/bag/BattleBagSession.ts +++ b/assets/script/battle/bag/BattleBagSession.ts @@ -341,21 +341,68 @@ export class BattleBagSession { /** * 新的待开启格补一个五行随机字(不广播整包刷新)。 + * 显示等级 = 抽取等级 + 本次解锁加值,不超过该五行上限。 * @param slotIndex 待开启槽下标 - * @returns 是否写入成功 + * @param levelAdd 本次解锁的等级加值(Const 39);0 不加 + * @returns 随机出来的显示等级;未写入返回 null */ - fillGateUnlockSlot(slotIndex: number): boolean { + fillGateUnlockSlot(slotIndex: number, levelAdd: number): number | null { if (this.landStateOf?.(slotIndex) !== TextListCellState.OpenNoDrag) { console.log('[BattleBagSession] 非待开启格不出字', slotIndex); - return false; + return null; } const roll = this._textPool.rollOneForLand(true); if (roll == null) { console.log('[BattleBagSession] 待开启格字池抽空', slotIndex); - return false; + return null; } - this.merge.bag.setSlot(slotIndex, { weapon2Id: roll.weapon2Id, level: roll.level }); - return true; + const level = this._gateLevel(roll.weapon2Id, roll.level, levelAdd); + this.merge.bag.setSlot(slotIndex, { weapon2Id: roll.weapon2Id, level }); + return Math.floor(roll.level); + } + + /** + * 给本次解锁新生的待开启格出字。 + * @param slotIndices 新生槽 + * @param levelAdd 本次解锁的等级加值 + * @returns 各格随机等级,形如「槽:等级」 + */ + fillGateUnlockSlots(slotIndices: readonly number[], levelAdd: number): string[] { + const rolls: string[] = []; + for (let i = 0; i < slotIndices.length; i++) { + const slot = slotIndices[i]; + const rolled = this.fillGateUnlockSlot(slot, levelAdd); + rolls.push(rolled == null ? `${slot}:无` : `${slot}:${rolled}`); + } + return rolls; + } + + /** + * 待开启出字等级:抽取等级加上解锁加值,不超过该五行上限。 + * @param weapon2Id Text.id + * @param level 抽取显示等级 + * @param levelAdd Const 39 加值 + */ + private _gateLevel(weapon2Id: number, level: number, levelAdd: number): number { + const base = Math.floor(level); + const add = Math.floor(Number(levelAdd)); + if (!Number.isFinite(add) || add < 0) { + console.log('[BattleBagSession] 解锁等级加值非法', weapon2Id, levelAdd); + return base; + } + if (add === 0) return base; + const w2Type = Math.floor(WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id)); + if (w2Type < 1 || w2Type > 5) { + console.log('[BattleBagSession] 解锁加值目标非五行', weapon2Id, w2Type); + return base; + } + const maxLv = WeaponComposeConfigProvider.instance.getElementMaxLevel(w2Type); + const sum = base + add; + if (sum > maxLv) { + console.log('[BattleBagSession] 解锁加值超过五行上限', weapon2Id, base, add, maxLv); + return maxLv; + } + return sum; } /** 两个字是否五行类型相同且显示等级相同 */ diff --git a/assets/script/battle/view/CocosBagBoardView.ts b/assets/script/battle/view/CocosBagBoardView.ts index be1745a..bc96921 100644 --- a/assets/script/battle/view/CocosBagBoardView.ts +++ b/assets/script/battle/view/CocosBagBoardView.ts @@ -4409,10 +4409,11 @@ export class CocosBagBoardView { case MergeEventType.BagMerged: // 待开启格吃到同类型同等级:自身变开启,四周未解锁格变待开启并各生成一个字 if (this._land.stateOf(event.slotIndex) === TextListCellState.OpenNoDrag) { - const born = this._land.promoteAround(event.slotIndex); - for (let i = 0; i < born.length; i++) { - this._bagSession?.fillGateUnlockSlot(born[i]); - } + const promoted = this._land.promoteAround(event.slotIndex); + const rolls = this._bagSession + ? this._bagSession.fillGateUnlockSlots(promoted.born, promoted.levelAdd) + : []; + this._land.printUnlock(rolls); this._fillMissingBagSlotGrids(); } this._reportMergeUpgraded(event.weapon1Id, event.level); diff --git a/assets/script/battle/view/TextListLandHost.ts b/assets/script/battle/view/TextListLandHost.ts index c22d61f..bc3d41f 100644 --- a/assets/script/battle/view/TextListLandHost.ts +++ b/assets/script/battle/view/TextListLandHost.ts @@ -1,5 +1,6 @@ import { Node } from 'cc'; import { TableNames } from '../../game/ConfigTableData'; +import { ConstNumType } from '../../game/GameDataEnums'; /** ui_textList 格子状态 */ export enum TextListCellState { @@ -25,10 +26,20 @@ const TEMP_NODE = 'temp'; /** 空装饰格下标(grid17):预制体底图保持关闭,逻辑不处理 */ const BLANK_INDEX = 17; +/** 一次待开启推进:新生待解锁格,以及本次要累加到这些格子数字上的等级 */ +export interface TextListPromoteResult { + /** 新变成待开启、需要出字的格子 */ + readonly born: readonly number[]; + /** 本次解锁对应的显示等级加值(Const 39);无加值为 0 */ + readonly levelAdd: number; +} + /** * 按关卡 normalland / tolockland 管理 ui_textList 格子状态与拖入解锁。 * normalland 为开启且开局不放字;tolockland 为待开启(有字、不能拖、靠同类型同等级合成打开)。 * 待开启被合成后自身变为开启,上下左右的未解锁格变为待开启。其余为未解锁。 + * 每局记录解锁次数,bind 时清零。第 1 次读 Const 39 的 index 0,依次类推;超出则用最后一项。 + * 该加值累加到本次上下左右新待解锁格的数字等级上。 * grid17 是空装饰格,不刷底、不出字、不可拖放。名为 temp 的节点跳过。 * 格子上的字块是背包槽位数据(BattleBagSession),由视图按槽位记录生成标准 TextGrid; * 拖拽预览、合成解锁走既有背包管线,本类只负责格子底图状态与解锁规则。 @@ -44,6 +55,10 @@ export class TextListLandHost { private readonly _open: number[] = []; /** 待解锁下标(开启但不能拖) */ private readonly _gate: number[] = []; + /** 本局已解锁次数;bind / clear 清零。下次解锁用这个下标读 Const 39 */ + private _unlockCount = 0; + /** 最近一次解锁的邻格等级加值,供本条解锁日志使用 */ + private _lastLevelAdd = 0; /** * 读取关卡并刷新格子底图。 @@ -111,6 +126,8 @@ export class TextListLandHost { this._headless = false; this._open.length = 0; this._gate.length = 0; + this._unlockCount = 0; + this._lastLevelAdd = 0; } /** @@ -164,13 +181,13 @@ export class TextListLandHost { /** * 待开启格被同类型同等级合成:自身改为开启,上下左右的未解锁格改为待开启。 + * 成功解锁计一次,并按本局次数取 Const 39 等级加值。 * @param gateIndex 待开启格下标 - * @returns 新变成待开启、需要生成文字的格子 */ - promoteAround(gateIndex: number): number[] { + promoteAround(gateIndex: number): TextListPromoteResult { if (this.isBlank(gateIndex) || this.stateOf(gateIndex) !== TextListCellState.OpenNoDrag) { console.log('[TextListLand] 非待开启格', gateIndex); - return []; + return { born: [], levelAdd: 0 }; } const gateAt = this._gate.indexOf(gateIndex); if (gateAt >= 0) this._gate.splice(gateAt, 1); @@ -192,7 +209,39 @@ export class TextListLandHost { } born.push(index); } - return born; + const levelAdd = this._unlockLevelAdd(this._unlockCount); + this._lastLevelAdd = levelAdd; + this._unlockCount++; + return { born, levelAdd }; + } + + /** + * 玩家本次解锁只打一条:解锁次数、上下左右累加等级、各新生格随机等级。AI 不打印。 + * @param rolls 各格随机等级,形如「槽:等级」;没有新生格传空数组 + */ + printUnlock(rolls: readonly string[]): void { + if (this._headless) return; + const randomText = rolls.length > 0 ? rolls.join(',') : '无'; + console.log('[TextListLand] 玩家 解锁次数', this._unlockCount, '上下左右累加等级', this._lastLevelAdd, '随机等级', randomText); + } + + /** + * Const 39:第 1 次解锁读 index 0,依次类推;下标超出数组则读最后一项。 + * @param unlockIndex 本次解锁前已解锁次数 + */ + private _unlockLevelAdd(unlockIndex: number): number { + const list = gg.data.table.getConstArray(ConstNumType.UnlockLandLevelAdd); + if (!list.length) { + console.log('[TextListLand] Const 解锁格子等级加值为空', ConstNumType.UnlockLandLevelAdd); + return 0; + } + const index = unlockIndex >= 0 && unlockIndex < list.length ? unlockIndex : list.length - 1; + const value = Math.floor(Number(list[index])); + if (!Number.isFinite(value) || value < 0) { + console.log('[TextListLand] 解锁格子等级加值非法', unlockIndex, list[index]); + return 0; + } + return value; } /** diff --git a/assets/script/game/GameDataEnums.ts b/assets/script/game/GameDataEnums.ts index 31a0b75..997c9fc 100644 --- a/assets/script/game/GameDataEnums.ts +++ b/assets/script/game/GameDataEnums.ts @@ -552,6 +552,8 @@ export enum ConstNumType { WeekMapSun = 37, /** 战斗中看视频加金币:para1 为每次奖励数量,次数=数组长度 */ BattleCoinAdRewards = 38, + /** 解锁格子次数等级加值 para1:第1次起按下标,越界读最后一项 */ + UnlockLandLevelAdd = 39, } export enum TaskType {