refactor: 统一将游戏内的「波次」术语替换为「回合」
本次提交将全项目中所有与「波次」相关的术语、注释、配置描述、UI文本全部替换为「回合」,包括: 1. 技能卡牌、怪物刷新、经济系统的相关注释与变量名 2. 配置表中的波次相关常量与描述文本 3. UI预制体中的波次显示文本 4. 所有相关的文档注释与接口说明 统一术语后,游戏的关卡流程描述将更符合常规肉鸽游戏的表达习惯,避免与「波次」字面含义混淆,提升代码可读性与团队协作一致性。
This commit is contained in:
@@ -88,7 +88,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
hero_num: 0,//英雄数量
|
||||
hero_max_num: FightSet.HERO_MAX_NUM,//英雄可召唤上限
|
||||
hero_extend_max_num: FightSet.HERO_MAX_NUM + 1,//英雄可拓展上限
|
||||
wave_time_num: 0,//波次时间
|
||||
wave_time_num: 0,//回合时间
|
||||
in_fight: false,
|
||||
fight_time: 0,//战斗时间
|
||||
level: 1,//关卡等级
|
||||
|
||||
@@ -46,7 +46,7 @@ export enum CardTriggerType {
|
||||
Interval = 2, // 定时循环:战斗中按 t_inv 间隔重复触发
|
||||
Field = 3, // 驻场光环(俗称「装备」):被动生效,由 field 数组驱动,支持单卡多词条
|
||||
FightStart = 4, // 战斗开始时触发
|
||||
FightEnd = 5, // 战斗结束时触发(每波结束)
|
||||
FightEnd = 5, // 战斗结束时触发(每回合结束)
|
||||
HeroDead = 6, // 场上己方英雄死亡时触发
|
||||
HeroCall = 7, // 英雄上场时触发(主角召唤 + 技能召唤 + 复活)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export interface CardConfig {
|
||||
weight: number
|
||||
kind: CKind
|
||||
card_lv: number // 卡牌等级(驱动 bg_node 颜色:1=green 2=blue 3=purple 4=red 5=yellow)
|
||||
wave?: number // 针对技能卡:仅在指定波次(wave)才能抽到
|
||||
wave?: number // 针对技能卡:仅在指定回合(wave)才能抽到
|
||||
hero_lv?: number
|
||||
base_card_lv?: number
|
||||
|
||||
@@ -71,7 +71,7 @@ export interface CardConfig {
|
||||
is_inst?: boolean // 是否即时起效
|
||||
t_times?: number // 触发次数
|
||||
t_inv?: number // 触发间隔(秒)
|
||||
keep_waves?: number // 维持的波次数(-1表示持续到战斗结束,0或undefined表示仅本波次)
|
||||
keep_waves?: number // 维持的回合数(-1表示持续到战斗结束,0或undefined表示仅本回合)
|
||||
overrides?: SkillOverrides // 技能参数覆写(如自定义伤害ap、buff值、金币数等)
|
||||
field?: number[] // 装备词条数组:驻场光环卡(trigger_type=Field)的属性词条,支持单卡多词条(如 [7002, 7004, 7005] 同时提供攻击/暴击/暴伤)
|
||||
|
||||
@@ -80,7 +80,7 @@ export interface CardConfig {
|
||||
/**
|
||||
* 事件型触发的全局次数上限(仅 FightStart/FightEnd/HeroDead/HeroCall 有效)
|
||||
* 默认 Infinity;达到上限后销毁节点
|
||||
* 注意:与 t_times 语义不同——t_times 控制每波内 Interval 的次数
|
||||
* 注意:与 t_times 语义不同——t_times 控制每回合内 Interval 的次数
|
||||
*/
|
||||
trigger_limit?: number;
|
||||
|
||||
@@ -242,7 +242,7 @@ export const drawCardsByRule = (
|
||||
})
|
||||
}
|
||||
|
||||
// 如果传入了波次并且是技能卡,则根据 wave 过滤
|
||||
// 如果传入了回合并且是技能卡,则根据 wave 过滤
|
||||
if (options.wave !== undefined) {
|
||||
pool = pool.filter(card => {
|
||||
if (card.type === CardType.Skill) {
|
||||
|
||||
@@ -23,9 +23,9 @@ export enum FacSet {
|
||||
MON = 1,
|
||||
}
|
||||
export enum FightSet {
|
||||
WAVE_COIN_BASE = 7, // 波次金币基础奖励
|
||||
WAVE_COIN_GROW = 2, // 波次金币递增值
|
||||
WAVE_COIN_MAX = 17, // 波次金币最大基础奖励
|
||||
WAVE_COIN_BASE = 7, // 回合金币基础奖励
|
||||
WAVE_COIN_GROW = 2, // 回合金币递增值
|
||||
WAVE_COIN_MAX = 17, // 回合金币最大基础奖励
|
||||
CRIT_DAMAGE = 50,//暴击伤害
|
||||
MORE_RC = 10,//更多次数 广告获取的次数
|
||||
HEARTPOS = -320,//基地位置
|
||||
@@ -55,11 +55,11 @@ export enum FightSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* 技能卡牌出现的波次配置(单一数据源)。
|
||||
* 技能卡牌出现的回合配置(单一数据源)。
|
||||
* 数组索引 i 对应卡牌档位 card_lv = i + 1:
|
||||
* - 第 1 个波次 → LV1 档(基础强度)
|
||||
* - 第 2 个波次 → LV2 档(强度 ×2)
|
||||
* - 第 3 个波次 → LV3 档(强度 ×3)
|
||||
* - 第 1 个回合 → LV1 档(基础强度)
|
||||
* - 第 2 个回合 → LV2 档(强度 ×2)
|
||||
* - 第 3 个回合 → LV3 档(强度 ×3)
|
||||
* 需与 CardSet.SkillCardData 的 wave 字段严格对齐,否则抽卡时池子为空。
|
||||
*/
|
||||
export const SKILL_CARD_WAVES: number[] = [1, 5, 8];
|
||||
|
||||
@@ -29,7 +29,7 @@ interface SkillCardRaw {
|
||||
is_inst: boolean;
|
||||
t_times?: number; // 触发次数(未设置时按 is_inst 取默认值:即时=1,定时=3)
|
||||
t_inv?: number;
|
||||
keep_waves?: number; // 维持波次数(默认 0=仅本波次)
|
||||
keep_waves?: number; // 维持回合数(默认 0=仅本回合)
|
||||
trigger_type: CardTriggerType;
|
||||
overrides?: SkillOverrides;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "召唤陨石范围攻击敌人,有概率击晕",
|
||||
},
|
||||
|
||||
//============================= ====== 辅助技能 技能卡牌 1 波技能 ====== ==========================
|
||||
//============================= ====== 辅助技能 技能卡牌 1 回合技能 ====== ==========================
|
||||
6301: {
|
||||
uuid: 6301, name: "护盾", sp_name: "buff_wind", icon: "Stat_Defense", TGroup: TGroup.Self, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Shield, ap: 3, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
@@ -328,7 +328,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
DTType: DTType.single, kind: SkillKind.Heal, ap: 300, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "治疗伙伴/自己",
|
||||
},
|
||||
//==========================buff 技能 也是 技能卡牌 5 波技能
|
||||
//==========================buff 技能 也是 技能卡牌 5 回合技能
|
||||
6303: {
|
||||
uuid: 6303, name: "获取金币", sp_name: "buff_wind", icon: "Stat_GoldGainIncrease_01", TGroup: TGroup.Self, readyAnm: "up_blue", endAnm: "gold", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Gold, ap: 0, gold: 1, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
|
||||
@@ -304,9 +304,9 @@ export interface LvBonusEntry {
|
||||
* dead 战士/刺客 死亡触发,一次性全队遗产
|
||||
* fstart 法师 战斗开始前触发一次,必然生效的全队增益
|
||||
* field 法师 驻场光环,存活期间持续生效,死亡消失
|
||||
* fend 辅助 每波结束触发,跨波次累积增益
|
||||
* fend 辅助 每回合结束触发,跨回合累积增益
|
||||
*
|
||||
* 触发节奏:atked 3次/5次,atking 5次/7次,fstart/fend 1次/波
|
||||
* 触发节奏:atked 3次/5次,atking 5次/7次,fstart/fend 1次/回合
|
||||
*
|
||||
* skills[0]是普通攻击技能
|
||||
*/
|
||||
@@ -724,7 +724,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
5051: {
|
||||
uuid: 5051, name: "占卜师", path: "hm1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, hp: 143, ap: 40,
|
||||
skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid3].cd, ccd: 0 } },
|
||||
// 战前计时 buff:每波开始全队 AP 限时提升(+30/5s → +60/7s → +90/10s)
|
||||
// 战前计时 buff:每回合开始全队 AP 限时提升(+30/5s → +60/7s → +90/10s)
|
||||
// 统一复用 7111 基础配置,通过 buff_value/buff_duration 覆写实现三档成长
|
||||
fstart: {
|
||||
6401: [
|
||||
@@ -810,7 +810,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
info: "<color=#27AE60>✧</color>光环全队提升攻击\n<color=#9B59B6>✦</color>追加提升攻速",
|
||||
},
|
||||
|
||||
// ========== fend + atking 类(辅助 · 治疗续航 + 波次增益) ==========
|
||||
// ========== fend + atking 类(辅助 · 治疗续航 + 回合增益) ==========
|
||||
5071: {
|
||||
uuid: 5071, name: "治愈牧师", path: "hh1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, hp: 143, ap: 40,
|
||||
skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal3].cd, ccd: 0 } },
|
||||
@@ -831,21 +831,21 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
// skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid1].cd, ccd: 0 } },
|
||||
// atking: [{ s_uuid: 6302, t_num: 5, overrides: { TGroup: TGroup.Team, ap: 200 } }],
|
||||
// fend: [{ s_uuid: 6303, t_num: 1, overrides: { gold: 1 } }],
|
||||
// info: "攻击5次治疗全队,每波结束获得1金币"
|
||||
// info: "攻击5次治疗全队,每回合结束获得1金币"
|
||||
// },
|
||||
// 5073: {
|
||||
// uuid: 5073, name: "强化牧师", path: "hh3", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, hp: 430, ap: 120,
|
||||
// skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal3].cd, ccd: 0 } },
|
||||
// atking: [{ s_uuid: 6302, t_num: 5, overrides: { TGroup: TGroup.Team, ap: 250 } }],
|
||||
// fend: [{ s_uuid: 6401, t_num: 1, overrides: { TGroup: TGroup.Team, ap: 10 } }],
|
||||
// info: "攻击5次治疗全队,每波结束全队永久+10攻击力"
|
||||
// info: "攻击5次治疗全队,每回合结束全队永久+10攻击力"
|
||||
// },
|
||||
// 5074: {
|
||||
// uuid: 5074, name: "生命牧师", path: "hh4", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, hp: 573, ap: 160,
|
||||
// skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal3].cd, ccd: 0 } },
|
||||
// atking: [{ s_uuid: 6302, t_num: 5, overrides: { TGroup: TGroup.Team, ap: 250 } }],
|
||||
// fend: [{ s_uuid: 6402, t_num: 1, overrides: { TGroup: TGroup.Team, ap: 80 } }],
|
||||
// info: "攻击5次治疗全队,每波结束全队永久+80最大生命值"
|
||||
// info: "攻击5次治疗全队,每回合结束全队永久+80最大生命值"
|
||||
// },
|
||||
// 5075: {
|
||||
// uuid: 5075, name: "全能牧师", path: "hh5", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, hp: 717, ap: 200,
|
||||
@@ -855,7 +855,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
// { s_uuid: 6401, t_num: 1, overrides: { TGroup: TGroup.Team, ap: 12 } },
|
||||
// { s_uuid: 6402, t_num: 1, overrides: { TGroup: TGroup.Team, ap: 60 } }
|
||||
// ],
|
||||
// info: "攻击5次治疗全队300%AP,每波结束全队永久+12攻击力、+60最大生命值"
|
||||
// info: "攻击5次治疗全队300%AP,每回合结束全队永久+12攻击力、+60最大生命值"
|
||||
// },
|
||||
|
||||
|
||||
@@ -959,7 +959,7 @@ export const HeroList: number[] = [
|
||||
// 5053, 5054, 5055, 5056,
|
||||
// field 类(法师 · 驻场光环)
|
||||
5061,
|
||||
// fend + atking 类(辅助 · 治疗 + 波次增益)
|
||||
// fend + atking 类(辅助 · 治疗 + 回合增益)
|
||||
5071,
|
||||
// 5072, 5073, 5074, 5075,
|
||||
];
|
||||
@@ -971,7 +971,7 @@ export const HeroList: number[] = [
|
||||
* - W_HP: 每 1 点生命值折算 1 分(生命值不随时间变化)
|
||||
* - W_DPS_PER_SEC: 每 1 点 DPS 持续 1 秒折算 0.5 分
|
||||
* (默认 60 秒评估窗下,1 DPS ≈ 30 分,与旧版 W_DPS=30 等效)
|
||||
* - WAVE_DURATION / HITS_PER_WAVE: 波次参数,用于估算 atked/fstart/fend/dead 触发次数
|
||||
* - WAVE_DURATION / HITS_PER_WAVE: 回合参数,用于估算 atked/fstart/fend/dead 触发次数
|
||||
* - DEFAULT_EVAL_SECONDS: calcHeroPower 默认使用的评估时间窗
|
||||
*/
|
||||
export const HERO_POWER_WEIGHTS = {
|
||||
@@ -1086,7 +1086,7 @@ function getHitCount(seconds: number): number {
|
||||
return (seconds / weights.WAVE_DURATION) * weights.HITS_PER_WAVE;
|
||||
}
|
||||
|
||||
/** 计算目标时间窗内的波次数 */
|
||||
/** 计算目标时间窗内的回合数 */
|
||||
function getWaveCount(seconds: number): number {
|
||||
return seconds / HERO_POWER_WEIGHTS.WAVE_DURATION;
|
||||
}
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
* 4. 触发结束后自动销毁。
|
||||
*
|
||||
* 触发类型(CardTriggerType):
|
||||
* - Instant (1):init 时立即触发一次(按 t_times 控制次数,跨波次 NewWave 时再次触发)
|
||||
* - Interval (2):监听 FightStart → update 帧驱动按 t_inv 间隔重复触发(按 t_times 控制每波次数)
|
||||
* - Instant (1):init 时立即触发一次(按 t_times 控制次数,跨回合 NewWave 时再次触发)
|
||||
* - Interval (2):监听 FightStart → update 帧驱动按 t_inv 间隔重复触发(按 t_times 控制每回合次数)
|
||||
* - Field (3):被动生效,不主动施法(实际由 FieldSkillSet 处理)
|
||||
* - FightStart (4):监听 FightStart 事件,按 trigger_limit 全局累计上限
|
||||
* - FightEnd (5):监听 FightEnd 事件(每波结束派发),按 trigger_limit 全局累计上限
|
||||
* - FightEnd (5):监听 FightEnd 事件(每回合结束派发),按 trigger_limit 全局累计上限
|
||||
* - HeroDead (6):监听 HeroDead 事件(仅英雄阵营派发,怪物死亡不触发)
|
||||
* - HeroCall (7):监听 MasterCalled(主角/技能召唤)+ ReviveSuccess(复活)
|
||||
*
|
||||
* 关键设计:
|
||||
* - 事件型(4-7)统一走 onEventTrigger 入口,仅作触发信号,不读取 payload
|
||||
* - 触发上限:Instant/Interval 按 t_times(每波内),事件型按 trigger_limit(全局)
|
||||
* - 跨波次:keep_waves 控制存活;事件型 trigger_count 不随波次重置
|
||||
* - 触发上限:Instant/Interval 按 t_times(每回合内),事件型按 trigger_limit(全局)
|
||||
* - 跨回合:keep_waves 控制存活;事件型 trigger_count 不随回合重置
|
||||
* - 销毁时通过 GameEvent.RemoveSkillBox 通知 MissSkillsComp 回收槽位
|
||||
*
|
||||
* 依赖:
|
||||
@@ -89,7 +89,7 @@ export class EquipBoxComp extends CCComp {
|
||||
private trigger_times: number = 1;
|
||||
/** 触发间隔(秒,仅持续技能有效) */
|
||||
private trigger_interval: number = 0;
|
||||
/** 维持的波次数(-1表示直到战斗结束,0表示不跨波次,>0表示维持的具体波次数) */
|
||||
/** 维持的回合数(-1表示直到战斗结束,0表示不跨回合,>0表示维持的具体回合数) */
|
||||
private keep_waves: number = 0;
|
||||
/** 技能覆写参数(自定义伤害、Buff等) */
|
||||
private overrides?: SkillOverrides;
|
||||
@@ -123,7 +123,7 @@ export class EquipBoxComp extends CCComp {
|
||||
/**
|
||||
* 注册全局事件:
|
||||
* - MissionEnd:所有类型都需要监听,任务结束时强制销毁
|
||||
* - NewWave:处理 keep_waves 跨波次逻辑(所有类型统一)
|
||||
* - NewWave:处理 keep_waves 跨回合逻辑(所有类型统一)
|
||||
* - 其它触发事件由 registerTrigger 按 trigger_type 动态注册
|
||||
*/
|
||||
onLoad() {
|
||||
@@ -354,14 +354,14 @@ export class EquipBoxComp extends CCComp {
|
||||
this.current_trigger_times++;
|
||||
this.updateUI();
|
||||
|
||||
// 单次触发 + 不跨波次维持 → 延迟销毁(保留短暂视觉反馈)
|
||||
// 单次触发 + 不跨回合维持 → 延迟销毁(保留短暂视觉反馈)
|
||||
if (this.keep_waves === 0 && this.current_trigger_times >= this.trigger_times) {
|
||||
this.scheduleOnce(() => this.destroySelf(), 1.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 事件型:上限由 trigger_limit 控制(全局累计,跨波次不重置)
|
||||
// 事件型:上限由 trigger_limit 控制(全局累计,跨回合不重置)
|
||||
if (this.trigger_count >= this.trigger_limit) {
|
||||
this.destroySelf();
|
||||
return;
|
||||
@@ -498,30 +498,30 @@ export class EquipBoxComp extends CCComp {
|
||||
this.timer = 0; // 重置计时器
|
||||
}
|
||||
|
||||
/** 节点级新一波事件处理 */
|
||||
/** 节点级新一回合事件处理 */
|
||||
private onNewWave() {
|
||||
this.handleNewWave();
|
||||
}
|
||||
|
||||
/** 全局级新一波事件处理 */
|
||||
/** 全局级新一回合事件处理 */
|
||||
private onNewWaveGlobal() {
|
||||
this.handleNewWave();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新一波:退出战斗状态。
|
||||
* 处理维持波次逻辑:递减剩余波次,或者重置触发次数。
|
||||
* 新一回合:退出战斗状态。
|
||||
* 处理维持回合逻辑:递减剩余回合,或者重置触发次数。
|
||||
*
|
||||
* 各类型在新一波的行为:
|
||||
* - Instant/Interval/FightStart/FightEnd:按 keep_waves 决定维持/销毁,并在新一波开始时重置本地计数
|
||||
* 各类型在新一回合的行为:
|
||||
* - Instant/Interval/FightStart/FightEnd:按 keep_waves 决定维持/销毁,并在新一回合开始时重置本地计数
|
||||
* - Field:被动生效,跟随 keep_waves 决定存活
|
||||
* - HeroDead/HeroCall:跨波次触发的事件型,trigger_count(全局)不重置,仅 keep_waves 控制存活
|
||||
* - HeroDead/HeroCall:跨回合触发的事件型,trigger_count(全局)不重置,仅 keep_waves 控制存活
|
||||
*/
|
||||
private handleNewWave() {
|
||||
if (!this.initialized) return;
|
||||
this.in_combat = false;
|
||||
|
||||
// 事件型触发(HeroDead / HeroCall):trigger_count 全局累计,不随波次重置
|
||||
// 事件型触发(HeroDead / HeroCall):trigger_count 全局累计,不随回合重置
|
||||
const isGlobalEventType =
|
||||
this.trigger_type === CardTriggerType.HeroDead ||
|
||||
this.trigger_type === CardTriggerType.HeroCall;
|
||||
@@ -534,21 +534,21 @@ export class EquipBoxComp extends CCComp {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 跨波次维持:重置本地计数与计时器(事件型 trigger_count 不重置)
|
||||
// 跨回合维持:重置本地计数与计时器(事件型 trigger_count 不重置)
|
||||
if (!isGlobalEventType) {
|
||||
this.current_trigger_times = 0;
|
||||
this.trigger_count = 0;
|
||||
}
|
||||
this.timer = 0;
|
||||
|
||||
// 即时/事件型触发一次(保持旧行为:Instant 在新一波开始立即触发一次)
|
||||
// 即时/事件型触发一次(保持旧行为:Instant 在新一回合开始立即触发一次)
|
||||
if (this.trigger_type === CardTriggerType.Instant) {
|
||||
this.triggerSkill();
|
||||
this.current_trigger_times++;
|
||||
}
|
||||
this.updateUI();
|
||||
} else {
|
||||
// 不跨波次维持:达到上限即销毁
|
||||
// 不跨回合维持:达到上限即销毁
|
||||
// - Interval / Instant:按 t_times 判定
|
||||
// - 事件型:按 trigger_limit 判定
|
||||
const reachedLimit = isGlobalEventType
|
||||
@@ -598,7 +598,7 @@ export class EquipBoxComp extends CCComp {
|
||||
this.current_trigger_times++;
|
||||
this.updateUI();
|
||||
|
||||
// 次数用完且不跨波次维持 → 延迟销毁
|
||||
// 次数用完且不跨回合维持 → 延迟销毁
|
||||
if (this.keep_waves === 0 && this.current_trigger_times >= this.trigger_times) {
|
||||
this.scheduleOnce(() => this.destroySelf(), 0.5);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ const { ccclass, property } = _decorator;
|
||||
* MSkillBoxComp —— 技能卡牌系统核心控制器
|
||||
*
|
||||
* 管理 3 个卡牌槽位的抽卡分发、卡池升级、金币费用、
|
||||
* 在 1,5,10,15,20 波次弹出技能卡牌三选一
|
||||
* 在 1,5,10,15,20 回合弹出技能卡牌三选一
|
||||
*/
|
||||
@ccclass('MSkillBoxComp')
|
||||
@ecs.register('MissionCard', false)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 1. 管理单局游戏的 **完整生命周期**:初始化 → 准备阶段 → 战斗阶段 → 结算。
|
||||
* 2. 在战斗阶段每帧更新战斗计时器、同步怪物数量、检测英雄全灭。
|
||||
* 3. 管理怪物数量阈值(暂停 / 恢复刷怪的上下限)。
|
||||
* 4. 处理新一波事件(NewWave),进入准备阶段并发放金币奖励。
|
||||
* 4. 处理新一回合事件(NewWave),进入准备阶段并发放金币奖励。
|
||||
* 5. 提供战斗结束后的结算弹窗入口(VictoryComp)。
|
||||
* 6. (可选)内建性能监控面板,显示内存、帧率、实体数量等开发信息。
|
||||
*
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
* 依赖:
|
||||
* - smc.mission —— 全局任务运行状态(play / pause / in_fight / stop_spawn_mon 等)
|
||||
* - smc.vmdata.mission_data —— 局内数据(金币 / 波数 / 怪物数量等)
|
||||
* - smc.vmdata.mission_data —— 局内数据(金币 / 回合数 / 怪物数量等)
|
||||
* - FightSet —— 战斗常量配置
|
||||
* - CardInitCoins —— 初始金币数
|
||||
* - UIID.Victory —— 结算弹窗
|
||||
@@ -92,7 +92,7 @@ export class MissionComp extends CCComp {
|
||||
/** 开始战斗按钮 */
|
||||
@property(Node)
|
||||
start_btn: Node = null!
|
||||
/** 时间/波数显示节点 */
|
||||
/** 时间/回合数显示节点 */
|
||||
@property(Node)
|
||||
time_node: Node = null!
|
||||
@property(Node)
|
||||
@@ -112,7 +112,7 @@ export class MissionComp extends CCComp {
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 本波战斗已耗时(秒),正向计时,用于自适应难度评估 */
|
||||
/** 本回合战斗已耗时(秒),正向计时,用于自适应难度评估 */
|
||||
clearTime: number = 0
|
||||
/** 剩余复活次数 */
|
||||
revive_times: number = 1;
|
||||
@@ -126,9 +126,9 @@ export class MissionComp extends CCComp {
|
||||
}
|
||||
/**秒计时 */
|
||||
PhaseTime: Timer = new Timer(1)
|
||||
/** 波次间倒计时(秒) */
|
||||
/** 回合间倒计时(秒) */
|
||||
private waveCountdown: number = 0;
|
||||
/** 波次间倒计时总时长(秒) */
|
||||
/** 回合间倒计时总时长(秒) */
|
||||
private readonly WAVE_COUNTDOWN_DURATION: number = 5;
|
||||
/** 上一次显示的时间字符串(避免重复设置) */
|
||||
private lastTimeStr: string = "";
|
||||
@@ -156,13 +156,13 @@ export class MissionComp extends CCComp {
|
||||
private heapTrendBaseMB: number = -1;
|
||||
/** 怪物数量同步计时器(降低同步频率) */
|
||||
private monsterCountSyncTimer: number = 0;
|
||||
/** 当前波数 */
|
||||
/** 当前回合数 */
|
||||
private currentWave: number = 0;
|
||||
/** 是否为Boss波次 */
|
||||
/** 是否为Boss回合 */
|
||||
private isBossWave: boolean = false;
|
||||
/** 当前任务阶段 */
|
||||
public currentPhase: MissionPhase = MissionPhase.None;
|
||||
/** 是否处于波次间倒计时状态 */
|
||||
/** 是否处于回合间倒计时状态 */
|
||||
private isWaveCountdown: boolean = false;
|
||||
|
||||
// ======================== ECS 查询匹配器(预缓存) ========================
|
||||
@@ -186,7 +186,7 @@ export class MissionComp extends CCComp {
|
||||
this.on(GameEvent.NewWave, this.onNewWave, this)
|
||||
this.on(GameEvent.DO_AD_BACK, this.do_ad, this)
|
||||
this.start_btn?.on(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this)
|
||||
// 第一波准备阶段,首个英雄召唤后自动开始战斗(无需玩家点击开始按钮)
|
||||
// 第一回合准备阶段,首个英雄召唤后自动开始战斗(无需玩家点击开始按钮)
|
||||
oops.message.on(GameEvent.MasterCalled, this.onHeroSummoned, this);
|
||||
this.removeMemoryPanel()
|
||||
}
|
||||
@@ -223,7 +223,7 @@ export class MissionComp extends CCComp {
|
||||
// 如果是暂停状态,且不在 BattleEnd 阶段(全灭时需要播放完 fend 技能动画并自动流转),才真正停止 update 逻辑
|
||||
if (smc.mission.pause && this.currentPhase !== MissionPhase.BattleEnd) return
|
||||
|
||||
// 波次间倒计时:PrepareStart 复用为倒计时阶段,5 秒后自动进入下一波
|
||||
// 回合间倒计时:PrepareStart 复用为倒计时阶段,5 秒后自动进入下一回合
|
||||
if (this.currentPhase === MissionPhase.PrepareStart) {
|
||||
this.waveCountdown -= dt;
|
||||
this.updateCountdownUI();
|
||||
@@ -253,7 +253,7 @@ export class MissionComp extends CCComp {
|
||||
|
||||
// ======================== 时间显示 ========================
|
||||
|
||||
/** 更新时间/波数显示(仅在秒数变化时更新以减少 Label 操作) */
|
||||
/** 更新时间/回合数显示(仅在秒数变化时更新以减少 Label 操作) */
|
||||
update_time() {
|
||||
const remainSecond = Math.floor(smc.vmdata.mission_data.fight_time);
|
||||
if (remainSecond === this.lastTimeSecond) return;
|
||||
@@ -273,9 +273,9 @@ export class MissionComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 波次倒计时 ========================
|
||||
// ======================== 回合倒计时 ========================
|
||||
|
||||
/** 进入波次间倒计时:重置倒计时并显示提示 */
|
||||
/** 进入回合间倒计时:重置倒计时并显示提示 */
|
||||
private startWaveCountdown() {
|
||||
this.waveCountdown = this.WAVE_COUNTDOWN_DURATION;
|
||||
this.isWaveCountdown = true;
|
||||
@@ -294,13 +294,13 @@ export class MissionComp extends CCComp {
|
||||
if (phaseNode) {
|
||||
const label = phaseNode.getComponent(Label);
|
||||
if (label) {
|
||||
label.string = `下一波 ${remain}s`;
|
||||
label.string = `下一回合 ${remain}s`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 结束波次间倒计时 */
|
||||
/** 结束回合间倒计时 */
|
||||
private stopWaveCountdown() {
|
||||
this.isWaveCountdown = false;
|
||||
this.lastTimeSecond = -1;
|
||||
@@ -446,7 +446,7 @@ export class MissionComp extends CCComp {
|
||||
const label = phaseNode.getComponent(Label);
|
||||
if (label) {
|
||||
const wave = Math.max(1, this.currentWave || (smc.vmdata && smc.vmdata.mission_data ? smc.vmdata.mission_data.level : 1) || 1);
|
||||
label.string = `第 ${wave} 波`;
|
||||
label.string = `第 ${wave} 回合`;
|
||||
}
|
||||
|
||||
// 阶段切换动感表现:只在进入战斗阶段跳动一下,让流程充满心流体验
|
||||
@@ -471,12 +471,12 @@ export class MissionComp extends CCComp {
|
||||
smc.mission.in_fight = false;
|
||||
smc.vmdata.mission_data.in_fight = false;
|
||||
smc.mission.stop_spawn_mon = true;
|
||||
// 波次间倒计时:隐藏开始按钮(nobg 激活表示不可点击状态)
|
||||
// 回合间倒计时:隐藏开始按钮(nobg 激活表示不可点击状态)
|
||||
if (this.start_btn && this.start_btn.isValid) {
|
||||
const nobg = this.start_btn.getChildByName("nobg");
|
||||
if (nobg) nobg.active = true;
|
||||
}
|
||||
// 启动 5 秒倒计时,由 update 驱动自动进入下一波
|
||||
// 启动 5 秒倒计时,由 update 驱动自动进入下一回合
|
||||
this.startWaveCountdown();
|
||||
oops.message.dispatchEvent("PhasePrepareStart");
|
||||
break;
|
||||
@@ -536,7 +536,7 @@ export class MissionComp extends CCComp {
|
||||
}
|
||||
});
|
||||
|
||||
// 【动态难度调节】根据本波战况自动放水 / 加压
|
||||
// 【动态难度调节】根据本回合战况自动放水 / 加压
|
||||
DynamicTuner.adjust(this.clearTime, heroDeathCount);
|
||||
mLogger.log(this.debugMode, 'MissionComp', `[DynamicTuner] wave=${this.currentWave} clearTime=${this.clearTime.toFixed(1)}s deaths=${heroDeathCount} factor=${DynamicTuner.factor.toFixed(2)}`);
|
||||
// 【评分系统 - 战绩分】记录全员存活的胜利回合数(额外加分)
|
||||
@@ -556,7 +556,7 @@ export class MissionComp extends CCComp {
|
||||
// 战斗结束阶段,给予所有英雄恢复70%血量的技能效果
|
||||
this.healAllHeroes();
|
||||
|
||||
// 【新增】派发每波战斗结束事件,供卡牌技能监听(区别于整局结束的 MissionEnd)
|
||||
// 【新增】派发每回合战斗结束事件,供卡牌技能监听(区别于整局结束的 MissionEnd)
|
||||
oops.message.dispatchEvent(GameEvent.FightEnd);
|
||||
break;
|
||||
|
||||
@@ -586,7 +586,7 @@ export class MissionComp extends CCComp {
|
||||
private autoNextPhase() {
|
||||
switch (this.currentPhase) {
|
||||
case MissionPhase.PrepareStart:
|
||||
// 波次间倒计时结束,停止倒计时状态,直接进入 PrepareEnd(不再等待玩家点击)
|
||||
// 回合间倒计时结束,停止倒计时状态,直接进入 PrepareEnd(不再等待玩家点击)
|
||||
this.stopWaveCountdown();
|
||||
this.changePhase(MissionPhase.PrepareEnd);
|
||||
break;
|
||||
@@ -599,7 +599,7 @@ export class MissionComp extends CCComp {
|
||||
case MissionPhase.BattleEnd:
|
||||
// BattleEnd 计时结束后,如果是因为全灭或手动调用的 fight_end,进入 Settle
|
||||
// 需要注意的是,open_Victory / fight_end 现在只需切换到 BattleEnd 即可,Settle 由这里自动接管
|
||||
// 如果游戏正在运行(波次更迭),则自动进入 PrepareStart 阶段
|
||||
// 如果游戏正在运行(回合更迭),则自动进入 PrepareStart 阶段
|
||||
if (smc.mission.play && !smc.mission.pause) {
|
||||
this.changePhase(MissionPhase.PrepareStart);
|
||||
} else {
|
||||
@@ -712,9 +712,9 @@ export class MissionComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 英雄召唤事件回调:
|
||||
* 第一波准备阶段(Prepare)只有第 1 波才会进入,
|
||||
* 第一回合准备阶段(Prepare)只有第 1 回合才会进入,
|
||||
* 此时首个英雄一旦召唤即自动开战,无需玩家点击开始按钮。
|
||||
* 后续波次走 PrepareStart 倒计时自动流转,不会进入 Prepare。
|
||||
* 后续回合走 PrepareStart 倒计时自动流转,不会进入 Prepare。
|
||||
*/
|
||||
private onHeroSummoned() {
|
||||
if (this.currentPhase !== MissionPhase.Prepare) return;
|
||||
@@ -732,7 +732,7 @@ export class MissionComp extends CCComp {
|
||||
* @param is_hero_dead 是否因英雄全灭触发
|
||||
*/
|
||||
open_Victory(e: any, is_hero_dead: boolean = false) {
|
||||
// 战斗失败或胜利,标记暂停状态以切断波次流转逻辑
|
||||
// 战斗失败或胜利,标记暂停状态以切断回合流转逻辑
|
||||
smc.mission.pause = true;
|
||||
// 直接切入 BattleEnd,触发 fend 表现
|
||||
// 倒计时逻辑已在 update 中由 PhaseTime 接管,2s 后将触发 autoNextPhase 弹窗结算
|
||||
@@ -767,7 +767,7 @@ export class MissionComp extends CCComp {
|
||||
/**
|
||||
* 初始化全部局内数据:
|
||||
* - 全局运行标志
|
||||
* - 战斗时间 / 怪物数量 / 金币 / 波数
|
||||
* - 战斗时间 / 怪物数量 / 金币 / 回合数
|
||||
* - 奖励列表 / 复活次数
|
||||
* - 性能监控基准值
|
||||
*/
|
||||
@@ -816,15 +816,15 @@ export class MissionComp extends CCComp {
|
||||
smc.vmdata.scores.gold_earned += smc.vmdata.mission_data.coin;
|
||||
}
|
||||
|
||||
// ======================== 波次管理 ========================
|
||||
// ======================== 回合管理 ========================
|
||||
|
||||
/**
|
||||
* 新一波事件回调:
|
||||
* 新一回合事件回调:
|
||||
* 1. 进入准备阶段。
|
||||
* 2. 更新当前波数。
|
||||
* 2. 更新当前回合数。
|
||||
* 3. 刷新时间显示。
|
||||
*
|
||||
* 注意:金币不再按波次固定发放,改为怪物死亡时掉落(见 HeroAtkSystem)。
|
||||
* 注意:金币不再按回合固定发放,改为怪物死亡时掉落(见 HeroAtkSystem)。
|
||||
*
|
||||
* @param event 事件名
|
||||
* @param data { wave: number }
|
||||
@@ -836,20 +836,20 @@ export class MissionComp extends CCComp {
|
||||
this.isBossWave = !!data?.bossWave;
|
||||
|
||||
if (wave > 1) {
|
||||
// 在新一波到来时,先进入 BattleEnd,触发上一波的战斗结束技能 (fend),2秒后自动进入下一波的准备阶段
|
||||
// 在新一回合到来时,先进入 BattleEnd,触发上一回合的战斗结束技能 (fend),2秒后自动进入下一回合的准备阶段
|
||||
this.changePhase(MissionPhase.BattleEnd);
|
||||
} else {
|
||||
// 第1波不需要结束上一波,延迟一点播放提示,避免被开始游戏的loading遮挡
|
||||
// 第1回合不需要结束上一回合,延迟一点播放提示,避免被开始游戏的loading遮挡
|
||||
this.scheduleOnce(() => {
|
||||
if (this.currentPhase === MissionPhase.Prepare) {
|
||||
this.playTooltipAnim(`第 ${wave} 波`);
|
||||
this.playTooltipAnim(`第 ${wave} 回合`);
|
||||
}
|
||||
}, 0.5);
|
||||
}
|
||||
|
||||
this.currentWave = wave;
|
||||
smc.vmdata.mission_data.level = wave;
|
||||
// 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每波固定发放
|
||||
// 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每回合固定发放
|
||||
this.lastTimeSecond = -1;
|
||||
this.clearTime = 0;
|
||||
this.update_time();
|
||||
@@ -894,11 +894,11 @@ export class MissionComp extends CCComp {
|
||||
});
|
||||
this.handleHeroWipe(heroCount);
|
||||
|
||||
// 怪物全灭检测:如果战斗阶段场上没有任何活着的怪物,且待刷新的怪物队列也为空,直接结束战斗进入下一波的准备阶段
|
||||
// 怪物全灭检测:如果战斗阶段场上没有任何活着的怪物,且待刷新的怪物队列也为空,直接结束战斗进入下一回合的准备阶段
|
||||
const pendingCount = smc.vmdata.mission_data.pending_mon_num || 0;
|
||||
if (monsterCount === 0 && pendingCount === 0 && smc.mission.play && !smc.mission.pause && this.currentPhase === MissionPhase.Battle) {
|
||||
if (this.currentWave >= MAX_WAVE) {
|
||||
// 20 波通关
|
||||
// 20 回合通关
|
||||
this.open_Victory(null, false);
|
||||
} else {
|
||||
oops.message.dispatchEvent("TimeUpAdvanceWave");
|
||||
|
||||
@@ -149,7 +149,7 @@ export class MissionEconomy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算每波基础金币收益
|
||||
* 计算每回合基础金币收益
|
||||
*/
|
||||
static getWaveGold(baseReward: number): number {
|
||||
let reward = Math.max(0, Math.floor(baseReward));
|
||||
@@ -159,7 +159,7 @@ export class MissionEconomy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行发放每波金币
|
||||
* 执行发放每回合金币
|
||||
*/
|
||||
static executeWaveGold(baseReward: number): number {
|
||||
const reward = this.getWaveGold(baseReward);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* @file MissionMonComp.ts
|
||||
* @description 怪物(Monster)波次刷新管理组件(逻辑层)
|
||||
* @description 怪物(Monster)回合刷新管理组件(逻辑层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 管理每一波怪物的生成计划:根据 RogueConfig 生成怪物。
|
||||
* 2. 自动推进波次:在准备阶段结束时(PhasePrepareEnd)启动分批释放。
|
||||
* 3. 分批刷怪:每波固定 3 批,每 10 秒释放一批,批内按 MON_SPAWN_INTERVAL 逐个刷出。
|
||||
* 1. 管理每一回合怪物的生成计划:根据 RogueConfig 生成怪物。
|
||||
* 2. 自动推进回合:在准备阶段结束时(PhasePrepareEnd)启动分批释放。
|
||||
* 3. 分批刷怪:每回合固定 3 批,每 10 秒释放一批,批内按 MON_SPAWN_INTERVAL 逐个刷出。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 所有怪物统一从右侧 X=400 出生点逐个刷出(MON_SPAWN_INTERVAL 节奏控制)。
|
||||
* - 实际阵型与推进由 MonMoveComp 在战斗中向左移动自然形成,不再使用固定网格点。
|
||||
* - 槽位索引(3行×4列)仅用于 monGrid 寻路与 SCastSystem 索敌定位。
|
||||
* - 上一波残留怪在波次结束/开始时统一清理。
|
||||
* - 上一回合残留怪在回合结束/开始时统一清理。
|
||||
*/
|
||||
import { _decorator, v3, Vec3 } from "cc";
|
||||
import { mLogger } from "../common/Logger";
|
||||
@@ -44,7 +44,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
* 怪物占位点:所有槽位统一以右侧出生点 (X=400) 作为坐标,
|
||||
* 实际阵型由 MonMoveComp 在战斗中向左推进时自然拉开。
|
||||
* 槽位索引仍保留 3 行 × 4 列结构,供 monGrid 寻路与 SCastSystem 索敌使用。
|
||||
* 超出 12 个槽位的怪物(放松波)按 spawnIndex % 12 复用槽位。
|
||||
* 超出 12 个槽位的怪物(放松回合)按 spawnIndex % 12 复用槽位。
|
||||
*/
|
||||
public static readonly MON_POSITIONS: Vec3[] = [
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 0: Col1-Top
|
||||
@@ -70,11 +70,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
/** 全局生成顺序计数器(用于渲染层级排序) */
|
||||
private globalSpawnOrder: number = 0;
|
||||
/** 当前波数 */
|
||||
/** 当前回合数 */
|
||||
private currentWave: number = 0;
|
||||
/** 当前波的目标怪物总数 */
|
||||
/** 当前回合的目标怪物总数 */
|
||||
private waveTargetCount: number = 0;
|
||||
/** 当前波已生成的怪物数量 */
|
||||
/** 当前回合已生成的怪物数量 */
|
||||
private waveSpawnedCount: number = 0;
|
||||
/** 等待生成的怪物队列(按批次分组,batch 0~2) */
|
||||
private pendingBatches: GeneratedMonster[][] = [[], [], []];
|
||||
@@ -142,7 +142,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
let hasBoss = monsters.some(m => m.isBoss);
|
||||
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', `[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', `[MissionMonComp] 回合 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
@@ -152,7 +152,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
|
||||
/**
|
||||
* 战斗准备:重置所有运行时状态并开始第一波。
|
||||
* 战斗准备:重置所有运行时状态并开始第一回合。
|
||||
*/
|
||||
fight_ready() {
|
||||
smc.vmdata.mission_data.mon_num = 0;
|
||||
@@ -168,7 +168,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
this.spawnQueue = [];
|
||||
this.spawnTimer = 0;
|
||||
|
||||
// 预生成第一波数据以获取数量和 Boss 信息
|
||||
// 预生成第一回合数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.setupWaveData(monsters);
|
||||
|
||||
@@ -179,10 +179,10 @@ export class MissionMonCompComp extends CCComp {
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||
}
|
||||
|
||||
// ======================== 波次管理 ========================
|
||||
// ======================== 回合管理 ========================
|
||||
|
||||
/**
|
||||
* 开始下一波:波数 +1 并预生成数据
|
||||
* 开始下一回合:回合数 +1 并预生成数据
|
||||
*/
|
||||
private onTimeUpAdvanceWave() {
|
||||
this.currentWave += 1;
|
||||
@@ -247,7 +247,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
// ======================== 槽位管理 ========================
|
||||
|
||||
/**
|
||||
* 清理上一波残留怪物,并重置生成计数与逐个刷怪队列
|
||||
* 清理上一回合残留怪物,并重置生成计数与逐个刷怪队列
|
||||
*/
|
||||
private resetSlotSpawnData() {
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => {
|
||||
@@ -258,7 +258,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
});
|
||||
|
||||
this.waveSpawnedCount = 0;
|
||||
// 同步丢弃上一波未释放的队列,避免与新一波混合
|
||||
// 同步丢弃上一回合未释放的队列,避免与新一回合混合
|
||||
this.spawnQueue = [];
|
||||
this.spawnTimer = 0;
|
||||
this.isReleasing = false;
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
* @description 肉鸽刷怪系统(基于英雄强度的动态难度 + 心流循环)
|
||||
*
|
||||
* 设计层次:
|
||||
* 1. WaveType - 波型(普通 / 压力 / 放松),5 波一个心流循环
|
||||
* 2. WaveConfig - 每波硬编码(数量 + 小队池 + HP/AP 倍率 + 强度微调)
|
||||
* 1. WaveType - 回合类型(普通 / 压力 / 放松),5 回合一个心流循环
|
||||
* 2. WaveConfig - 每回合硬编码(数量 + 小队池 + HP/AP 倍率 + 强度微调)
|
||||
* 3. DynamicTuner - 动态难度调节器(系统根据战况放水 / 加压)
|
||||
* 4. MonSkillSet - 怪物技能池(atking / atked / dead 等全触发类型)
|
||||
* 5. RogueSpawningEngine - 生成引擎(按英雄强度反推怪物强度)
|
||||
*
|
||||
* 核心公式:
|
||||
* heroPower = Σ calcHeroPower(HeroInfo[uuid], lv) (场上存活英雄)
|
||||
* targetPower = heroPower × 波型系数 × wave.power_adjust × DynamicTuner.factor
|
||||
* targetPower = heroPower × 回合类型系数 × wave.power_adjust × DynamicTuner.factor
|
||||
* scale = targetPower ÷ Σ 怪物基础强度
|
||||
* 每只怪: hp ×= scale, ap ×= scale
|
||||
*
|
||||
* 波次节奏:
|
||||
* - 最大 20 波,第 20 波通关
|
||||
* - 每波 30 秒,固定分 3 批,每 10 秒释放一批
|
||||
* - 普通波 18~36 只,放松波 × 1.5 = 27~54 只
|
||||
* - wave % 5 === 0 → 压力波(必带 Boss,强度高、数量少)
|
||||
* - wave % 5 === 1 → 放松波(数量 × 1.5,强度低,爽快清屏)
|
||||
* 回合节奏:
|
||||
* - 最大 20 回合,第 20 回合通关
|
||||
* - 每回合 30 秒,固定分 3 批,每 10 秒释放一批
|
||||
* - 普通回合 18~36 只,放松回合 × 1.5 = 27~54 只
|
||||
* - wave % 5 === 0 → 压力回合(必带 Boss,强度高、数量少)
|
||||
* - wave % 5 === 1 → 放松回合(数量 × 1.5,强度低,爽快清屏)
|
||||
*/
|
||||
|
||||
import { HeroInfo, MonType, MonTypeName, calcHeroPower, TriggerGrouped, LvReviveEntry, heroInfo } from "../common/config/heroSet";
|
||||
@@ -29,50 +29,50 @@ import { FacSet } from "../common/config/GameSet";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
|
||||
// ======================== 1. 波型与节奏常量 ========================
|
||||
// ======================== 1. 回合类型与节奏常量 ========================
|
||||
|
||||
/** 波型枚举 */
|
||||
/** 回合类型枚举 */
|
||||
export enum WaveType {
|
||||
Normal = 0, // 普通波
|
||||
Pressure = 1, // 压力波(wave % 5 === 0,必带 Boss)
|
||||
Relax = 2, // 放松波(wave % 5 === 1,量大强度低)
|
||||
Normal = 0, // 普通回合
|
||||
Pressure = 1, // 压力回合(wave % 5 === 0,必带 Boss)
|
||||
Relax = 2, // 放松回合(wave % 5 === 1,量大强度低)
|
||||
}
|
||||
|
||||
/** 波型名称 */
|
||||
/** 回合类型名称 */
|
||||
export const WaveTypeName: Record<WaveType, string> = {
|
||||
[WaveType.Normal]: "普通",
|
||||
[WaveType.Pressure]: "压力",
|
||||
[WaveType.Relax]: "放松",
|
||||
};
|
||||
|
||||
/** 波型强度系数(硬编码) */
|
||||
/** 回合类型强度系数(硬编码) */
|
||||
export const WAVE_TYPE_POWER_RATIO: Record<WaveType, number> = {
|
||||
[WaveType.Normal]: 0.9, // 普通波:标准强度
|
||||
[WaveType.Pressure]: 1.2, // 压力波:强度高、数量少
|
||||
[WaveType.Relax]: 0.6, // 放松波:量大、强度低
|
||||
[WaveType.Normal]: 0.9, // 普通回合:标准强度
|
||||
[WaveType.Pressure]: 1.2, // 压力回合:强度高、数量少
|
||||
[WaveType.Relax]: 0.6, // 放松回合:量大、强度低
|
||||
};
|
||||
|
||||
/** 放松波数量倍率(相对普通波) */
|
||||
/** 放松回合数量倍率(相对普通回合) */
|
||||
export const RELAX_COUNT_MUL = 1.5;
|
||||
|
||||
/** 最大波次(第 20 波通关) */
|
||||
/** 最大回合数(第 20 回合通关) */
|
||||
export const MAX_WAVE = 20;
|
||||
|
||||
/** 每波时长(秒) */
|
||||
/** 每回合时长(秒) */
|
||||
export const WAVE_DURATION = 30;
|
||||
|
||||
/** 每波分批次数 */
|
||||
/** 每回合分批次数 */
|
||||
export const BATCH_COUNT = 3;
|
||||
|
||||
/** 每批间隔(秒):30 秒 / 3 批 = 10 秒 */
|
||||
export const BATCH_INTERVAL = WAVE_DURATION / BATCH_COUNT;
|
||||
|
||||
/** 每波怪物硬上限(放松波 36 × 1.5 = 54) */
|
||||
/** 每回合怪物硬上限(放松回合 36 × 1.5 = 54) */
|
||||
export const MAX_MONSTERS = 54;
|
||||
|
||||
/**
|
||||
* 获取指定波次的波型
|
||||
* @param wave 波次(1 起)
|
||||
* 获取指定回合的回合类型
|
||||
* @param wave 回合(1 起)
|
||||
* @returns WaveType
|
||||
*/
|
||||
export function getWaveType(wave: number): WaveType {
|
||||
@@ -87,7 +87,7 @@ export function getWaveType(wave: number): WaveType {
|
||||
* 动态难度调节器(系统控制放水 / 加压)
|
||||
* 与硬编码系数并存,用于根据战况实时微调难度。
|
||||
*
|
||||
* 用法示例(MissionComp 每波结束时调用):
|
||||
* 用法示例(MissionComp 每回合结束时调用):
|
||||
* DynamicTuner.adjust(clearTime, heroDeathCount);
|
||||
*
|
||||
* 调节规则(内部硬编码):
|
||||
@@ -107,7 +107,7 @@ export const DynamicTuner = {
|
||||
STEP: 0.05,
|
||||
|
||||
/**
|
||||
* 根据上一波战况自动调节难度
|
||||
* 根据上一回合战况自动调节难度
|
||||
* @param clearTime 清场耗时(秒)
|
||||
* @param heroDeathCount 英雄死亡数
|
||||
*/
|
||||
@@ -228,7 +228,7 @@ export interface MonSkillSet {
|
||||
|
||||
/**
|
||||
* 怪物技能池(硬编码)
|
||||
* 压力波 / Boss 可配置专属技能,普通波随机挂载增加变数。
|
||||
* 压力回合 / Boss 可配置专属技能,普通回合随机挂载增加变数。
|
||||
*
|
||||
* 技能 uuid 引用 SkillSet 中的 6000~6500 段触发技能。
|
||||
*/
|
||||
@@ -270,7 +270,7 @@ export const MonSkillPool: Record<string, MonSkillSet> = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Boss 专属技能池(压力波 Boss 随机挂载) */
|
||||
/** Boss 专属技能池(压力回合 Boss 随机挂载) */
|
||||
export const BossSkillPool: Record<string, MonSkillSet> = {
|
||||
/** 狂暴领主:攻击触发全队攻击提升 */
|
||||
boss_rage: {
|
||||
@@ -301,37 +301,37 @@ export const BossSkillPool: Record<string, MonSkillSet> = {
|
||||
},
|
||||
};
|
||||
|
||||
// ======================== 6. 波次配置表 ========================
|
||||
// ======================== 6. 回合配置表 ========================
|
||||
|
||||
/** 单波次完整配置 */
|
||||
/** 单回合完整配置 */
|
||||
export interface WaveConfig {
|
||||
/** 基础怪物总数(普通波 36 为上限,放松波自动 × 1.5 = 54) */
|
||||
/** 基础怪物总数(普通回合 36 为上限,放松回合自动 × 1.5 = 54) */
|
||||
base_count: number;
|
||||
/** 可选小队 id 池,引擎按权重抽取拼装到 base_count */
|
||||
squad_pool: string[];
|
||||
/** HP 强化倍率(硬编码,逐波递进) */
|
||||
/** HP 强化倍率(硬编码,逐回合递进) */
|
||||
hp_mul: number;
|
||||
/** AP 强化倍率(硬编码,逐波递进) */
|
||||
/** AP 强化倍率(硬编码,逐回合递进) */
|
||||
ap_mul: number;
|
||||
/** 强度微调(放水 / 加压,默认 1.0) */
|
||||
power_adjust?: number;
|
||||
/** 是否 Boss 波(压力波必为 true) */
|
||||
/** 是否 Boss 回合(压力回合必为 true) */
|
||||
boss_wave?: boolean;
|
||||
/** 普通怪技能池 id(可选,随机挂载) */
|
||||
skill_pool?: string[];
|
||||
/** Boss 技能池 id(Boss 波专用,随机挂载) */
|
||||
/** Boss 技能池 id(Boss 回合专用,随机挂载) */
|
||||
boss_skill_pool?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 波次配置表(硬编码 wave 1~20)
|
||||
* 回合配置表(硬编码 wave 1~20)
|
||||
*
|
||||
* 心流循环(5 波一循环):
|
||||
* wave % 5 === 0 → 压力波(必带 Boss,强度高、数量少)
|
||||
* wave % 5 === 1 → 放松波(数量 × 1.5,强度低)
|
||||
* 其余 → 普通波(标准强度)
|
||||
* 心流循环(5 回合一循环):
|
||||
* wave % 5 === 0 → 压力回合(必带 Boss,强度高、数量少)
|
||||
* wave % 5 === 1 → 放松回合(数量 × 1.5,强度低)
|
||||
* 其余 → 普通回合(标准强度)
|
||||
*
|
||||
* 强度递进:hp_mul / ap_mul 每 5 波一档,压力波额外提升。
|
||||
* 强度递进:hp_mul / ap_mul 每 5 回合一档,压力回合额外提升。
|
||||
*/
|
||||
export const WaveConfigs: Record<number, WaveConfig> = {
|
||||
// ===== 第一循环:教学期 =====
|
||||
@@ -339,34 +339,34 @@ export const WaveConfigs: Record<number, WaveConfig> = {
|
||||
2: { base_count: 21, squad_pool: ["melee_grunt", "mixed_balanced"], hp_mul: 1.00, ap_mul: 1.00 },
|
||||
3: { base_count: 24, squad_pool: ["melee_grunt", "mixed_balanced", "long_line"], hp_mul: 1.05, ap_mul: 1.00 },
|
||||
4: { base_count: 27, squad_pool: ["mixed_balanced", "long_line", "heavy_shield"], hp_mul: 1.10, ap_mul: 1.05 },
|
||||
// 压力波:第一 Boss
|
||||
// 压力回合:第一 Boss
|
||||
5: { base_count: 21, squad_pool: ["melee_grunt", "mixed_balanced", "heavy_shield"], hp_mul: 1.15, ap_mul: 1.10, boss_wave: true, boss_skill_pool: ["boss_rage"] },
|
||||
|
||||
// ===== 第二循环:引入技能怪 =====
|
||||
// 放松波:量大好清
|
||||
// 放松回合:量大好清
|
||||
6: { base_count: 30, squad_pool: ["melee_grunt", "mixed_balanced", "long_line"], hp_mul: 1.10, ap_mul: 1.05 },
|
||||
7: { base_count: 30, squad_pool: ["melee_grunt", "heavy_shield", "long_line"], hp_mul: 1.15, ap_mul: 1.10, skill_pool: ["tough"] },
|
||||
8: { base_count: 33, squad_pool: ["assassin_squad", "mixed_balanced", "summoner_cult"], hp_mul: 1.20, ap_mul: 1.15, skill_pool: ["berserk"] },
|
||||
9: { base_count: 33, squad_pool: ["heavy_shield", "long_line", "mixed_balanced"], hp_mul: 1.25, ap_mul: 1.20, skill_pool: ["berserk", "tough"] },
|
||||
// 压力波:第二 Boss
|
||||
// 压力回合:第二 Boss
|
||||
10: { base_count: 24, squad_pool: ["melee_grunt", "assassin_squad", "mixed_balanced"], hp_mul: 1.30, ap_mul: 1.25, boss_wave: true, boss_skill_pool: ["boss_rage", "boss_iron"] },
|
||||
|
||||
// ===== 第三循环:组合多样化 =====
|
||||
// 放松波
|
||||
// 放松回合
|
||||
11: { base_count: 33, squad_pool: ["assassin_squad", "long_line", "summoner_cult", "mixed_balanced"], hp_mul: 1.25, ap_mul: 1.20, skill_pool: ["leech"] },
|
||||
12: { base_count: 33, squad_pool: ["heavy_shield", "melee_grunt", "mixed_balanced", "long_line"], hp_mul: 1.30, ap_mul: 1.25, skill_pool: ["tough", "warcry"] },
|
||||
13: { base_count: 36, squad_pool: ["assassin_squad", "summoner_cult", "mixed_balanced"], hp_mul: 1.35, ap_mul: 1.30, skill_pool: ["berserk", "leech"] },
|
||||
14: { base_count: 36, squad_pool: ["heavy_shield", "long_line", "melee_grunt"], hp_mul: 1.40, ap_mul: 1.35, skill_pool: ["berserk", "tough", "legacy"] },
|
||||
// 压力波:第三 Boss(中期高潮)
|
||||
// 压力回合:第三 Boss(中期高潮)
|
||||
15: { base_count: 27, squad_pool: ["assassin_squad", "mixed_balanced", "summoner_cult"], hp_mul: 1.50, ap_mul: 1.40, boss_wave: true, boss_skill_pool: ["boss_rage", "boss_iron", "boss_doom"] },
|
||||
|
||||
// ===== 第四循环:终极阶段 =====
|
||||
// 放松波
|
||||
// 放松回合
|
||||
16: { base_count: 36, squad_pool: ["assassin_squad", "heavy_shield", "long_line"], hp_mul: 1.45, ap_mul: 1.40, skill_pool: ["leech", "warcry"] },
|
||||
17: { base_count: 36, squad_pool: ["melee_grunt", "summoner_cult", "mixed_balanced"], hp_mul: 1.50, ap_mul: 1.45, skill_pool: ["berserk", "legacy"] },
|
||||
18: { base_count: 36, squad_pool: ["assassin_squad", "long_line", "heavy_shield"], hp_mul: 1.55, ap_mul: 1.50, skill_pool: ["berserk", "tough", "leech"] },
|
||||
19: { base_count: 36, squad_pool: ["mixed_balanced", "summoner_cult", "melee_grunt"], hp_mul: 1.60, ap_mul: 1.55, skill_pool: ["berserk", "tough", "legacy", "warcry"] },
|
||||
// 压力波:最终 Boss
|
||||
// 压力回合:最终 Boss
|
||||
20: { base_count: 30, squad_pool: ["assassin_squad", "heavy_shield", "summoner_cult", "mixed_balanced"], hp_mul: 1.80, ap_mul: 1.70, boss_wave: true, boss_skill_pool: ["boss_doom", "boss_rage"] },
|
||||
};
|
||||
|
||||
@@ -472,13 +472,13 @@ export const TestModeConfig = {
|
||||
|
||||
/**
|
||||
* 肉鸽刷怪生成引擎
|
||||
* 按英雄强度反推怪物强度,结合波型系数与动态调节器生成怪物列表
|
||||
* 按英雄强度反推怪物强度,结合回合类型系数与动态调节器生成怪物列表
|
||||
*/
|
||||
export class RogueSpawningEngine {
|
||||
|
||||
/**
|
||||
* 生成指定波次的怪物列表
|
||||
* @param waveNumber 波次(1 起,>MAX_WAVE 时复用 wave MAX_WAVE 配置)
|
||||
* 生成指定回合的怪物列表
|
||||
* @param waveNumber 回合(1 起,>MAX_WAVE 时复用 wave MAX_WAVE 配置)
|
||||
* @returns 怪物列表,长度 ≤ MAX_MONSTERS
|
||||
*/
|
||||
generateWave(waveNumber: number): GeneratedMonster[] {
|
||||
@@ -499,14 +499,14 @@ export class RogueSpawningEngine {
|
||||
const powerAdjust = cfg.power_adjust ?? 1.0;
|
||||
const targetPower = heroPower * typeRatio * powerAdjust * DynamicTuner.factor;
|
||||
|
||||
// 2. 确定怪物总数(放松波 × 1.5)
|
||||
// 2. 确定怪物总数(放松回合 × 1.5)
|
||||
let totalCount = cfg.base_count;
|
||||
if (waveType === WaveType.Relax) {
|
||||
totalCount = Math.round(totalCount * RELAX_COUNT_MUL);
|
||||
}
|
||||
totalCount = Math.min(totalCount, MAX_MONSTERS);
|
||||
|
||||
// 3. Boss 位(压力波必带 Boss,占 1 个名额)
|
||||
// 3. Boss 位(压力回合必带 Boss,占 1 个名额)
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
let remaining = totalCount;
|
||||
if (cfg.boss_wave) {
|
||||
@@ -563,8 +563,8 @@ export class RogueSpawningEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定波次的怪物总数
|
||||
* @param waveNumber 目标波数
|
||||
* 获取指定回合的怪物总数
|
||||
* @param waveNumber 目标回合数
|
||||
* @returns 预计生成的怪物总数
|
||||
*/
|
||||
getWaveMonsterCount(waveNumber: number): number {
|
||||
@@ -672,7 +672,7 @@ export class RogueSpawningEngine {
|
||||
const baseHp = baseInfo ? baseInfo.hp : 500;
|
||||
const baseAp = baseInfo ? baseInfo.ap : 30;
|
||||
|
||||
// Boss 自带额外血量加成:每 5 波递增 20%(wave 5=1.0, 10=1.2, 15=1.4...)
|
||||
// Boss 自带额外血量加成:每 5 回合递增 20%(wave 5=1.0, 10=1.2, 15=1.4...)
|
||||
const bossBonusHpMul = 1 + 0.20 * Math.floor(Math.max(0, wave - 5) / 5);
|
||||
|
||||
return {
|
||||
@@ -753,21 +753,21 @@ export class RogueSpawningEngine {
|
||||
|
||||
export const spawningEngine = new RogueSpawningEngine();
|
||||
|
||||
/** 历史接口:波次槽位(保留兼容) */
|
||||
/** 历史接口:回合槽位(保留兼容) */
|
||||
export interface IWaveSlot {
|
||||
type: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定波次预计的怪物总数量
|
||||
* @param waveNumber 目标波数
|
||||
* 获取指定回合预计的怪物总数量
|
||||
* @param waveNumber 目标回合数
|
||||
*/
|
||||
export function getWaveMonsterCount(waveNumber: number): number {
|
||||
return spawningEngine.getWaveMonsterCount(waveNumber);
|
||||
}
|
||||
|
||||
/** 获取波次槽位配置(向后兼容,从 generateWave 反推) */
|
||||
/** 获取回合槽位配置(向后兼容,从 generateWave 反推) */
|
||||
export function getWaveSlotConfig(waveNumber: number): IWaveSlot[] {
|
||||
const generated = spawningEngine.generateWave(waveNumber);
|
||||
const slotMap = new Map<number, number>();
|
||||
@@ -785,7 +785,7 @@ export const DefaultWaveSlot: IWaveSlot[] = [
|
||||
{ type: MonType.Support, count: 5 },
|
||||
];
|
||||
|
||||
/** 波次槽位配置代理(按需生成) */
|
||||
/** 回合槽位配置代理(按需生成) */
|
||||
export const WaveSlotConfig: { [wave: number]: IWaveSlot[] } = new Proxy(
|
||||
{} as { [wave: number]: IWaveSlot[] },
|
||||
{
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
* 4. 触发结束后自动销毁。
|
||||
*
|
||||
* 触发类型(CardTriggerType):
|
||||
* - Instant (1):init 时立即触发一次(按 t_times 控制次数,跨波次 NewWave 时再次触发)
|
||||
* - Interval (2):监听 FightStart → update 帧驱动按 t_inv 间隔重复触发(按 t_times 控制每波次数)
|
||||
* - Instant (1):init 时立即触发一次(按 t_times 控制次数,跨回合 NewWave 时再次触发)
|
||||
* - Interval (2):监听 FightStart → update 帧驱动按 t_inv 间隔重复触发(按 t_times 控制每回合次数)
|
||||
* - Field (3):被动生效,不主动施法(实际由 FieldSkillSet 处理)
|
||||
* - FightStart (4):监听 FightStart 事件,按 trigger_limit 全局累计上限
|
||||
* - FightEnd (5):监听 FightEnd 事件(每波结束派发),按 trigger_limit 全局累计上限
|
||||
* - FightEnd (5):监听 FightEnd 事件(每回合结束派发),按 trigger_limit 全局累计上限
|
||||
* - HeroDead (6):监听 HeroDead 事件(仅英雄阵营派发,怪物死亡不触发)
|
||||
* - HeroCall (7):监听 MasterCalled(主角/技能召唤)+ ReviveSuccess(复活)
|
||||
*
|
||||
* 关键设计:
|
||||
* - 事件型(4-7)统一走 onEventTrigger 入口,仅作触发信号,不读取 payload
|
||||
* - 触发上限:Instant/Interval 按 t_times(每波内),事件型按 trigger_limit(全局)
|
||||
* - 跨波次:keep_waves 控制存活;事件型 trigger_count 不随波次重置
|
||||
* - 触发上限:Instant/Interval 按 t_times(每回合内),事件型按 trigger_limit(全局)
|
||||
* - 跨回合:keep_waves 控制存活;事件型 trigger_count 不随回合重置
|
||||
* - 销毁时通过 GameEvent.RemoveSkillBox 通知 MissSkillsComp 回收槽位
|
||||
*
|
||||
* 依赖:
|
||||
@@ -89,7 +89,7 @@ export class SkillBoxComp extends CCComp {
|
||||
private trigger_times: number = 1;
|
||||
/** 触发间隔(秒,仅持续技能有效) */
|
||||
private trigger_interval: number = 0;
|
||||
/** 维持的波次数(-1表示直到战斗结束,0表示不跨波次,>0表示维持的具体波次数) */
|
||||
/** 维持的回合数(-1表示直到战斗结束,0表示不跨回合,>0表示维持的具体回合数) */
|
||||
private keep_waves: number = 0;
|
||||
/** 技能覆写参数(自定义伤害、Buff等) */
|
||||
private overrides?: SkillOverrides;
|
||||
@@ -123,7 +123,7 @@ export class SkillBoxComp extends CCComp {
|
||||
/**
|
||||
* 注册全局事件:
|
||||
* - MissionEnd:所有类型都需要监听,任务结束时强制销毁
|
||||
* - NewWave:处理 keep_waves 跨波次逻辑(所有类型统一)
|
||||
* - NewWave:处理 keep_waves 跨回合逻辑(所有类型统一)
|
||||
* - 其它触发事件由 registerTrigger 按 trigger_type 动态注册
|
||||
*/
|
||||
onLoad() {
|
||||
@@ -304,7 +304,7 @@ export class SkillBoxComp extends CCComp {
|
||||
case CardTriggerType.Interval:
|
||||
// 定时循环:监听 FightStart 进入战斗后启动计时
|
||||
oops.message.on(GameEvent.FightStart, this.onFightStart, this);
|
||||
// 若购买时战斗已在进行(FightStart 已派发过),立即进入战斗态,避免空等下一波
|
||||
// 若购买时战斗已在进行(FightStart 已派发过),立即进入战斗态,避免空等下一回合
|
||||
if (smc.mission.in_fight) {
|
||||
this.in_combat = true;
|
||||
this.timer = 0;
|
||||
@@ -361,14 +361,14 @@ export class SkillBoxComp extends CCComp {
|
||||
this.current_trigger_times++;
|
||||
this.updateUI();
|
||||
|
||||
// 单次触发 + 不跨波次维持 → 延迟销毁(保留短暂视觉反馈)
|
||||
// 单次触发 + 不跨回合维持 → 延迟销毁(保留短暂视觉反馈)
|
||||
if (this.keep_waves === 0 && this.current_trigger_times >= this.trigger_times) {
|
||||
this.scheduleOnce(() => this.destroySelf(), 1.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 事件型:上限由 trigger_limit 控制(全局累计,跨波次不重置)
|
||||
// 事件型:上限由 trigger_limit 控制(全局累计,跨回合不重置)
|
||||
if (this.trigger_count >= this.trigger_limit) {
|
||||
this.destroySelf();
|
||||
return;
|
||||
@@ -504,30 +504,30 @@ export class SkillBoxComp extends CCComp {
|
||||
this.timer = 0; // 重置计时器
|
||||
}
|
||||
|
||||
/** 节点级新一波事件处理 */
|
||||
/** 节点级新一回合事件处理 */
|
||||
private onNewWave() {
|
||||
this.handleNewWave();
|
||||
}
|
||||
|
||||
/** 全局级新一波事件处理 */
|
||||
/** 全局级新一回合事件处理 */
|
||||
private onNewWaveGlobal() {
|
||||
this.handleNewWave();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新一波:退出战斗状态。
|
||||
* 处理维持波次逻辑:递减剩余波次,或者重置触发次数。
|
||||
* 新一回合:退出战斗状态。
|
||||
* 处理维持回合逻辑:递减剩余回合,或者重置触发次数。
|
||||
*
|
||||
* 各类型在新一波的行为:
|
||||
* - Instant/Interval/FightStart/FightEnd:按 keep_waves 决定维持/销毁,并在新一波开始时重置本地计数
|
||||
* 各类型在新一回合的行为:
|
||||
* - Instant/Interval/FightStart/FightEnd:按 keep_waves 决定维持/销毁,并在新一回合开始时重置本地计数
|
||||
* - Field:被动生效,跟随 keep_waves 决定存活
|
||||
* - HeroDead/HeroCall:跨波次触发的事件型,trigger_count(全局)不重置,仅 keep_waves 控制存活
|
||||
* - HeroDead/HeroCall:跨回合触发的事件型,trigger_count(全局)不重置,仅 keep_waves 控制存活
|
||||
*/
|
||||
private handleNewWave() {
|
||||
if (!this.initialized) return;
|
||||
this.in_combat = false;
|
||||
|
||||
// 事件型触发(HeroDead / HeroCall):trigger_count 全局累计,不随波次重置
|
||||
// 事件型触发(HeroDead / HeroCall):trigger_count 全局累计,不随回合重置
|
||||
const isGlobalEventType =
|
||||
this.trigger_type === CardTriggerType.HeroDead ||
|
||||
this.trigger_type === CardTriggerType.HeroCall;
|
||||
@@ -540,21 +540,21 @@ export class SkillBoxComp extends CCComp {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 跨波次维持:重置本地计数与计时器(事件型 trigger_count 不重置)
|
||||
// 跨回合维持:重置本地计数与计时器(事件型 trigger_count 不重置)
|
||||
if (!isGlobalEventType) {
|
||||
this.current_trigger_times = 0;
|
||||
this.trigger_count = 0;
|
||||
}
|
||||
this.timer = 0;
|
||||
|
||||
// 即时/事件型触发一次(保持旧行为:Instant 在新一波开始立即触发一次)
|
||||
// 即时/事件型触发一次(保持旧行为:Instant 在新一回合开始立即触发一次)
|
||||
if (this.trigger_type === CardTriggerType.Instant) {
|
||||
this.triggerSkill();
|
||||
this.current_trigger_times++;
|
||||
}
|
||||
this.updateUI();
|
||||
} else {
|
||||
// 不跨波次维持:达到上限即销毁
|
||||
// 不跨回合维持:达到上限即销毁
|
||||
// - Interval / Instant:按 t_times 判定
|
||||
// - 事件型:按 trigger_limit 判定
|
||||
const reachedLimit = isGlobalEventType
|
||||
@@ -604,7 +604,7 @@ export class SkillBoxComp extends CCComp {
|
||||
this.current_trigger_times++;
|
||||
this.updateUI();
|
||||
|
||||
// 次数用完且不跨波次维持 → 延迟销毁
|
||||
// 次数用完且不跨回合维持 → 延迟销毁
|
||||
if (this.keep_waves === 0 && this.current_trigger_times >= this.trigger_times) {
|
||||
this.scheduleOnce(() => this.destroySelf(), 0.5);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user