From 350bbafcfbd4d3834165d325c5eeedd60b0032dd Mon Sep 17 00:00:00 2001 From: panw Date: Wed, 11 Mar 2026 17:32:29 +0800 Subject: [PATCH] =?UTF-8?q?refactor(hero):=20=E7=A7=BB=E9=99=A4=E5=A4=A9?= =?UTF-8?q?=E8=B5=8B=E7=B3=BB=E7=BB=9F=E5=92=8C=E7=9B=B8=E5=85=B3=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=EF=BC=8C=E7=AE=80=E5=8C=96=E8=8B=B1=E9=9B=84=E6=9E=B6?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 SCDSystem、HeroAttrSystem 等独立系统,将功能整合到现有组件 - 移除 TalComp 天赋组件及相关配置(TalSet、AttrSet、CardSet) - 清理 HeroAttrs 中未使用的属性枚举,保留核心战斗属性 - 简化 Hero 实体创建逻辑,不再为主角挂载天赋组件 - 移除 SingletonModuleComp 中与天赋、经验、收集相关的数据管理 --- .../script/game/common/SingletonModuleComp.ts | 188 +----- assets/script/game/common/config/AttrSet.ts | 56 -- assets/script/game/common/config/CardSet.ts | 372 ----------- assets/script/game/common/config/HeroAttrs.ts | 77 +-- assets/script/game/common/config/TalSet.ts | 153 ----- assets/script/game/common/config/heroSet.ts | 40 +- assets/script/game/hero/Hero.ts | 13 - assets/script/game/hero/HeroAttrsComp.ts | 557 +--------------- assets/script/game/hero/HeroAttrsSystem.ts | 140 ---- assets/script/game/hero/SACastSystem.ts | 621 ------------------ assets/script/game/hero/SCDSystem.ts | 51 -- assets/script/game/hero/TalComp.ts | 296 --------- 12 files changed, 44 insertions(+), 2520 deletions(-) delete mode 100644 assets/script/game/common/config/AttrSet.ts delete mode 100644 assets/script/game/common/config/CardSet.ts delete mode 100644 assets/script/game/common/config/TalSet.ts delete mode 100644 assets/script/game/hero/HeroAttrsSystem.ts delete mode 100644 assets/script/game/hero/SACastSystem.ts delete mode 100644 assets/script/game/hero/SCDSystem.ts delete mode 100644 assets/script/game/hero/TalComp.ts diff --git a/assets/script/game/common/SingletonModuleComp.ts b/assets/script/game/common/SingletonModuleComp.ts index 7c76dab7..015a081c 100644 --- a/assets/script/game/common/SingletonModuleComp.ts +++ b/assets/script/game/common/SingletonModuleComp.ts @@ -5,12 +5,7 @@ import { GameMap } from "../map/GameMap"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { WxCloudApi } from "../wx_clound_client_api/WxCloudApi"; import { GameEvent } from "./config/GameEvent"; -import * as exp from "constants"; -import { HeroAttrsComp } from "../hero/HeroAttrsComp"; -import { Attrs, GameScoreStats } from "./config/HeroAttrs"; -import { count, time } from "console"; -import { getLevelExp } from "../map/RogueConfig"; -import { FightSet } from "./config/GameSet"; +import { GameScoreStats } from "./config/HeroAttrs"; import { mLogger } from "./Logger"; /** * 用远程数据覆盖本地数据(统一方法) @@ -107,126 +102,13 @@ export class SingletonModuleComp extends ecs.Comp { elite_kill_count: 0, // 精英怪击杀数量 boss_kill_count: 0, // Boss击杀数 } as GameScoreStats, - hero:{ - name:'', - path:'', - as:0, - type:0, - lv:1, - exp:0, - exp_max:100, - exp_pre:0, - hp:50, - hp_max:100, - mp:50, - mp_max:100, - def:0, - ap:0, - crt:0, - dodge:0, - skills:[], - buff:[], - tal:[], - info:'', - }, - // 收集记录 - collection: { - talents: {} as Record, - skill: {uuid:0,count:0}, - friend:{uuid:0,count:0}, - }, + gold: 0, // 金币数据(MVVM绑定字段) }; - // 全局属性加成 {attrIndex: [value, count]} - global_attrs: Record = { - [Attrs.AP]: [1, 0], // 攻击力 - [Attrs.HP_MAX]: [10, 10], // 生命上限 - [Attrs.DEF]: [1, 0], // 防御 - [Attrs.DODGE]: [1, 0], // 闪避率 - [Attrs.CRITICAL]: [1, 0], // 暴击率 - [Attrs.STUN_CHANCE]: [1, 0], // 眩晕率 - [Attrs.WFUNY]: [1, 0], // 风怒率 - }; - - /** 主角实体引用 */ - // role: ecs.Entity | null = null; - - /** - * 记录天赋获取 - * @param id 天赋ID - */ - addTalentRecord(id: number) { - if (!this.vmdata.collection.talents[id]) { - this.vmdata.collection.talents[id] = 0; - } - this.vmdata.collection.talents[id]++; - mLogger.log(this.debugMode, 'SMC', `[SMC] 记录天赋获取: ID=${id}, 次数=${this.vmdata.collection.talents[id]}`); - oops.message.dispatchEvent(GameEvent.UpdateCollection); - } - - /** - * 记录技能获取 - * @param id 技能ID - */ - addSkillRecord(id: number) { - if (!this.vmdata.collection.skill.uuid) { - this.vmdata.collection.skill.uuid = id; - } - this.vmdata.collection.skill.count++; - mLogger.log(this.debugMode, 'SMC', `[SMC] 记录技能获取: ID=${id}, 次数=${this.vmdata.collection.skill.count}`); - oops.message.dispatchEvent(GameEvent.UpdateCollection); - } - /** - * 记录好友获取 - * @param id 好友ID - */ - addFriendHero(id: number) { - if (!this.vmdata.collection.friend.uuid) { - this.vmdata.collection.friend.uuid = id; - } - this.vmdata.collection.friend.count++; - mLogger.log(this.debugMode, 'SMC', `[SMC] 记录好友获取: ID=${id}, 次数=${this.vmdata.collection.friend.count}`); - oops.message.dispatchEvent(GameEvent.UpdateCollection); - } - - /** - * 增加经验并处理升级逻辑 - * @param exp 获得的经验值 - */ - addExp(exp: number) { - if (exp <= 0) return; - - const h = this.vmdata.hero; - // 确保等级至少为1 - if (h.lv < 1) h.lv = 1; - // 确保经验上限正确 - if (h.exp_max <= 0) h.exp_max = getLevelExp(h.lv); - - h.exp += exp; - - // 检查升级 - let isLevelUp = false; - while (h.exp >= h.exp_max) { - h.exp -= h.exp_max; - h.lv++; - isLevelUp = true; - - // 更新下一级所需经验 - h.exp_max = getLevelExp(h.lv); - - mLogger.log(this.debugMode, 'SMC', `[SMC] 升级! Lv.${h.lv - 1} -> Lv.${h.lv}, 下级所需: ${h.exp_max}`); - } - h.exp_pre=Math.round(h.exp/h.exp_max*100) - if (isLevelUp) { - mLogger.log(this.debugMode, 'SMC', `[SMC] 触发升级事件: Lv.${h.lv}`); - // 发送升级事件 - oops.message.dispatchEvent(GameEvent.CanUpdateLv, { lv: h.lv }); - } - } - + vmAdd() { VM.add(this.vmdata, "data"); // mLogger.log(this.debugMode, 'SMC', "[MissionComp]局内数据初始化",smc.vmdata.mission_data) @@ -332,19 +214,7 @@ export class SingletonModuleComp extends ecs.Comp { return true } - // 设置单个出战英雄 - updateFihgtHero(heroId: number) { - this.fight_hero = heroId; - if(this.isWxClient()){ - let res = this.updateCloudData() - if (res){ - return true - }else{ - return false - } - } - return true - } + updateGold(gold:number, is_sync: boolean = true){ this.vmdata.gold += gold; if(this.isWxClient() && is_sync){ @@ -361,56 +231,6 @@ export class SingletonModuleComp extends ecs.Comp { return true } - /** - * 更新主角英雄数据到 VM - * @param heroAttrs 英雄属性组件 - */ - updateHeroInfo(heroAttrs: HeroAttrsComp) { - if (!heroAttrs || !heroAttrs.is_master) return; - - const h = this.vmdata.hero; - - // 基础信息 - h.name = heroAttrs.hero_name; - h.type = heroAttrs.type; - - // 防止 ECS 旧数据覆盖 VM 新数据 (如果 VM 里的等级更高,说明刚升级还没同步到 ECS) - if (heroAttrs.lv > h.lv) { - h.lv = heroAttrs.lv; - } else if (h.lv > heroAttrs.lv) { - // 此时应该反向同步?或者等待 CanUpdateLv 事件处理 - // 这里暂时保持 VM 的高等级,不被 ECS 覆盖 - } else { - h.lv = heroAttrs.lv; - } - - // 动态属性 - h.hp = Math.floor(heroAttrs.hp); - h.mp = Math.floor(heroAttrs.mp); - - // 计算属性 - h.hp_max = Math.floor(heroAttrs.Attrs[Attrs.HP_MAX] || 0); - h.mp_max = Math.floor(heroAttrs.Attrs[Attrs.MP_MAX] || 0); - h.def = Math.floor(heroAttrs.Attrs[Attrs.DEF] || 0); - h.ap = Math.floor(heroAttrs.Attrs[Attrs.AP] || 0); - h.dodge = Math.floor(heroAttrs.Attrs[Attrs.DODGE] || 0); - h.crt = Math.floor(heroAttrs.Attrs[Attrs.CRITICAL] || 0); - h.as = Math.floor(heroAttrs.Attrs[Attrs.AS] || 0); - - // 强制触发 VM 更新 - // 如果 VM 监听的是 smc.vmdata.hero 的属性变化,上面的赋值应该有效。 - // 但如果 UI 绑定的是 hero 整体对象,或者因为深层监听问题,可能需要手动通知。 - // 为了保险,我们可以重新赋值一次(如果是对象引用可能不会触发),或者使用 VM 提供的 set 方法 - // 这里尝试直接重新赋值整个对象属性来触发更新,或者假设 VM 已经处理好了深层监听。 - // 如果 UI 没变,可能是 VM 没有检测到深层属性变化。 - - // 尝试手动通知或重新赋值关键路径 - // 注意:Oops Framework 的 VM 通常支持对象属性修改的监听,前提是初始化时已经建立了监听。 - // 这里我们尝试显式调用 VM.modify 来通知更新(如果有这个 API),或者重新赋值给 vmdata - - // 方案:重新设置 vmdata.hero 来触发根节点的更新通知 - this.vmdata.hero = h; - } error(){ oops.gui.toast("数据处理异常,请重试或重新登录") } diff --git a/assets/script/game/common/config/AttrSet.ts b/assets/script/game/common/config/AttrSet.ts deleted file mode 100644 index 808dff9f..00000000 --- a/assets/script/game/common/config/AttrSet.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Attrs } from "./HeroAttrs"; - - export interface AttrInfo { - uuid: number; - icon:string; // 属性图标 - attr: Attrs; // 属性类型 - value: number;// 属性值 - desc: string;// 属性描述 - isSpecial: boolean;// 是否为特殊属性 - name?: string;// 属性备注 - } - export const AttrCards: Record = { - //*一阶 */ - 2001:{uuid:2001, icon:"1020", attr: Attrs.AP, value: 20, desc: "攻击力 +20%", isSpecial: false,name: "攻击" }, - 2002:{uuid:2002, icon:"1020", attr: Attrs.HP_MAX, value: 20, desc: "生命上限 +20%", isSpecial: false,name: "生命" }, - 2003:{uuid:2003, icon:"1020", attr: Attrs.DEF, value: 20, desc: "防御力 +20%", isSpecial: false,name: "防御" }, - 2004:{uuid:2004, icon:"1020", attr: Attrs.AS, value: 5, desc: "攻击速度 +5%", isSpecial: false,name: "攻速" }, - 2005:{uuid:2007, icon:"1020", attr: Attrs.CRITICAL_DMG, value: 10, desc: "暴击伤害 +10%", isSpecial: true,name: "爆伤" }, - 2006:{uuid:2013, icon:"1020", attr: Attrs.DODGE, value: 5, desc: "闪避率 +5%", isSpecial: true,name: "闪避" }, - - } - - export interface PotionInfo extends AttrInfo { - duration: number; // 持续时间 -} - -export const PotionCards: Record = { - // 持续时间20秒的强力药水 - 3001: { uuid: 3001, icon: "1020", attr: Attrs.AP, value: 100, desc: "15秒内攻击力 +100%", isSpecial: false,name: "狂暴药水", duration: 15 }, - 3002: { uuid: 3002, icon: "1020", attr: Attrs.AS, value: 100, desc: "15秒内攻速 +100%", isSpecial: false,name: "急速药水", duration: 15 }, - 3003: { uuid: 3003, icon: "1020", attr: Attrs.DEF, value: 100, desc: "15秒内防御 +100%", isSpecial: false,name: "防御药水", duration: 15 }, - 3004: { uuid: 3004, icon: "1020", attr: Attrs.SPEED, value: 100, desc: "15秒内移速 +100%", isSpecial: false,name: "神行药水", duration: 15 }, - - // 持续时间60秒的普通药水 - 3005: { uuid: 3005, icon: "1020", attr: Attrs.AP, value: 25, desc: "60秒内攻击力 +25%", isSpecial: false,name: "力量药剂", duration: 60 }, - 3006: { uuid: 3006, icon: "1020", attr: Attrs.AS, value: 25, desc: "60秒内攻速 +25%", isSpecial: false,name: "敏捷药剂", duration: 60 }, - 3007: { uuid: 3007, icon: "1020", attr: Attrs.DEF, value: 25, desc: "60秒内防御 +25%", isSpecial: false,name: "护甲药剂", duration: 60 }, - 3008: { uuid: 3008, icon: "1020", attr: Attrs.SPEED, value: 25, desc: "60秒内移速 +25%", isSpecial: false,name: "轻灵药剂", duration: 60 }, - - // 闪避药水 - 3009: { uuid: 3009, icon: "1020", attr: Attrs.DODGE, value: 100, desc: "20秒内闪避率 +100%", isSpecial: false,name: "残影药水", duration: 15 }, - 3010: { uuid: 3010, icon: "1020", attr: Attrs.DODGE, value: 25, desc: "60秒内闪避率 +25%", isSpecial: false,name: "闪避药剂", duration: 60 }, - // 回血药水 - 3011: { uuid: 3011, icon: "1020", attr: Attrs.HP_REGEN, value: 30, desc: "每5秒回血生命最大值的30%", isSpecial: false,name: "生命药水", duration: 15 }, - 3012: { uuid: 3012, icon: "1020", attr: Attrs.HP_REGEN, value: 10, desc: "每5秒回血生命最大值的10%", isSpecial: false,name: "回春药剂", duration: 60 }, -}; - -export const CanSelectAttrs: Record = { - // 1阶属性 - 1: [2001, 2002, 2003, 2004, 2005, 2006], -}; - -export const CanSelectPotions: Record = { - // 全药水 - 1: [3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012] -}; \ No newline at end of file diff --git a/assets/script/game/common/config/CardSet.ts b/assets/script/game/common/config/CardSet.ts deleted file mode 100644 index 92092a63..00000000 --- a/assets/script/game/common/config/CardSet.ts +++ /dev/null @@ -1,372 +0,0 @@ -import { AttrCards, AttrInfo, CanSelectAttrs, PotionCards, CanSelectPotions } from "./AttrSet"; -import { talConf, ItalConf, CanSelectTalents } from "./TalSet"; -import { SkillSet, SkillConfig, CanSelectSkills } from "./SkillSet"; -import { HeroInfo, heroInfo, CanSelectHeros } from "./heroSet"; -import { CardType, CardKind } from "./GameSet"; - -/** - * 获取等级对应的奖励类型 - * @param level 当前等级 - * @returns 奖励类型 CardType - */ -export function getLevelRewardType(level: number): CardType { - switch (level) { - case 2: return CardType.Talent; - case 3: return CardType.Attr; - case 4: return CardType.Attr; - case 5: return CardType.Talent; - case 6: return CardType.Attr; - case 7: return CardType.Attr; - case 8: return CardType.Attr; - case 9: return CardType.Attr; - case 10: return CardType.Talent; - case 11: return CardType.Attr; - case 12: return CardType.Attr; - case 13: return CardType.Attr; - case 14: return CardType.Attr; - case 15: return CardType.Talent; - case 16: return CardType.Attr; - case 17: return CardType.Attr; - case 18: return CardType.Attr; - case 19: return CardType.Attr; - case 20: return CardType.Attr; - default: - return null - } -} - -/** - * 统一卡牌信息接口 (用于UI显示和逻辑处理) - */ -export interface ICardInfo { - uuid: number; - type: CardType; - kind: CardKind; - name: string; - desc: string; - icon: string; - weight: number; // 抽取权重 - tag?: string; // 标签 (如 "special" 表示特殊属性) - payload: any; // 原始配置数据 -} - -/** - * 具体卡牌配置项 (内部使用) - */ -export interface IPoolItem { - id: number; // 卡牌UUID - weight: number; // 该卡牌在池中的权重 -} - -/** - * 等级池配置项 - * 仅定义类型和权重,具体卡牌内容由各模块的 CanSelectXXX 配置决定 - */ -export interface IPoolConfig { - type: CardType; // 卡牌类型 - poolWeight: number; // 该类型池被选中的概率权重 - tag?: string; // 辅助筛选(从全池中筛选带tag的,如 "special") -} - -// 默认单卡权重 -const DEFAULT_CARD_WEIGHT = 100; - -/** - * 1-20 级卡牌池配置表 - * 定义每个等级可能出现的卡牌类型及其权重 - */ -export const LevelPoolConfigs: Record = { - 1: [{ type: CardType.Skill, poolWeight: 100 }], - 2: [{ type: CardType.Attr, poolWeight: 100 }], // 常规属性 - 3: [{ type: CardType.Talent, poolWeight: 50 }, { type: CardType.Attr, poolWeight: 50, tag: "special" }], // 天赋或特殊属性 - 4: [{ type: CardType.Attr, poolWeight: 100 }], - 5: [{ type: CardType.Talent, poolWeight: 100 }], - 6: [{ type: CardType.Partner, poolWeight: 100 }], // 伙伴节点 - 7: [{ type: CardType.Attr, poolWeight: 80 }, { type: CardType.Skill, poolWeight: 20 }], - 8: [{ type: CardType.Attr, poolWeight: 80 }, { type: CardType.Skill, poolWeight: 20 }], - 9: [{ type: CardType.Attr, poolWeight: 50, tag: "special" }, { type: CardType.Talent, poolWeight: 50 }], - 10: [{ type: CardType.Talent, poolWeight: 100 }], - 11: [{ type: CardType.Attr, poolWeight: 70 }, { type: CardType.Skill, poolWeight: 30 }], - 12: [{ type: CardType.Attr, poolWeight: 70 }, { type: CardType.Skill, poolWeight: 30 }], - 13: [{ type: CardType.Attr, poolWeight: 100 }], - 14: [{ type: CardType.Attr, poolWeight: 50, tag: "special" }, { type: CardType.Talent, poolWeight: 50 }], - 15: [{ type: CardType.Talent, poolWeight: 100 }], - 16: [{ type: CardType.Attr, poolWeight: 60 }, { type: CardType.Skill, poolWeight: 40 }], - 17: [{ type: CardType.Attr, poolWeight: 60 }, { type: CardType.Skill, poolWeight: 40 }], - 18: [{ type: CardType.Attr, poolWeight: 50, tag: "special" }, { type: CardType.Talent, poolWeight: 50 }], - 19: [{ type: CardType.Attr, poolWeight: 100 }], - 20: [{ type: CardType.Talent, poolWeight: 100 }], -}; - -// ========== 卡牌池构建逻辑 ========== - -/** - * 获取指定类型的卡牌信息(不含权重,仅基础信息) - */ -function getCardBaseInfo(type: CardType, uuid: number): ICardInfo | null { - let baseInfo: any = null; - let name = ""; - let desc = ""; - let icon = ""; - let kind = CardKind.Attr; - let tag = undefined; - - switch (type) { - case CardType.Attr: - baseInfo = AttrCards[uuid]; - if (!baseInfo) return null; - name = baseInfo.name || "属性"; - desc = baseInfo.desc; - icon = baseInfo.icon; - kind = CardKind.Attr; - tag = baseInfo.isSpecial ? "special" : undefined; - break; - case CardType.Talent: - baseInfo = talConf[uuid]; - if (!baseInfo) return null; - name = baseInfo.name; - desc = baseInfo.desc; - icon = baseInfo.icon; - kind = baseInfo.kind; - break; - case CardType.Skill: - baseInfo = SkillSet[uuid]; - if (!baseInfo) return null; - name = baseInfo.name; - desc = baseInfo.info; - icon = baseInfo.icon; - kind = CardKind.Skill; - break; - case CardType.Partner: - baseInfo = HeroInfo[uuid]; - if (!baseInfo) return null; - name = baseInfo.name; - desc = baseInfo.info; - icon = baseInfo.icon; - kind = CardKind.Partner; - break; - case CardType.Potion: - baseInfo = PotionCards[uuid]; - if (!baseInfo) return null; - name = baseInfo.name || "药水"; - desc = baseInfo.desc; - icon = baseInfo.icon; - kind = CardKind.Buff; // 药水归类为 Buff 类型的卡片显示 - break; - } - - return { - uuid, - type, - kind, - name, - desc, - icon, - weight: 0, // 基础信息不包含权重,权重由配置决定 - tag, - payload: baseInfo - }; -} - -/** - * 获取指定类型的全量池 - * 自动累加所有 <= level 的配置项 - * @param type 卡牌类型 - * @param level 当前等级 - */ -function getDefaultPool(type: CardType, level: number = 1): IPoolItem[] { - const items: IPoolItem[] = []; - let configMap: Record | null = null; - let defaultWeight = 100; - - switch (type) { - case CardType.Attr: - configMap = CanSelectAttrs; - defaultWeight = 100; - break; - case CardType.Talent: - configMap = CanSelectTalents; - defaultWeight = 50; - break; - case CardType.Skill: - configMap = CanSelectSkills; - defaultWeight = 80; - break; - case CardType.Partner: - configMap = CanSelectHeros; - defaultWeight = 100; - break; - case CardType.Potion: - configMap = CanSelectPotions; - defaultWeight = 100; - break; - } - - if (configMap) { - // 1. 找到符合条件的最大等级 Key (<= level 且 != 99) - let targetKey = -1; - let maxLv = -1; - - Object.keys(configMap).forEach(lvlStr => { - const lv = parseInt(lvlStr); - if (lv !== 99 && lv <= level) { - if (lv > maxLv) { - maxLv = lv; - targetKey = lv; - } - } - }); - - // 2. 如果找到了目标等级配置,则使用该配置 - if (targetKey !== -1 && configMap[targetKey]) { - const ids = configMap[targetKey]; - ids.forEach(id => { - items.push({ id, weight: defaultWeight }); - }); - } - // 3. 如果没找到(等级过低),且存在 99 号默认配置,则使用 99 号配置 - else if (configMap[99]) { - configMap[99].forEach(id => { - items.push({ id, weight: defaultWeight }); - }); - } - } else { - // 兜底逻辑:如果该类型没有配置表 (理论上不应发生,除非新增类型未配置) - // 这里保留原有的全量兜底逻辑作为最后的防线 - switch (type) { - case CardType.Attr: - Object.keys(AttrCards).forEach(key => items.push({ id: Number(key), weight: 100 })); - break; - case CardType.Talent: - Object.keys(talConf).forEach(key => items.push({ id: Number(key), weight: 50 })); - break; - case CardType.Skill: - Object.keys(SkillSet).forEach(key => items.push({ id: Number(key), weight: 80 })); - break; - case CardType.Partner: - Object.keys(HeroInfo).forEach(key => { - const id = Number(key); - if (id < 5200) items.push({ id, weight: 100 }); - }); - break; - case CardType.Potion: - Object.keys(PotionCards).forEach(key => items.push({ id: Number(key), weight: 100 })); - break; - } - } - - return items; -} - -/** - * 根据等级获取随机卡牌选项 - * @param level 当前等级 - * @param count 选项数量 (默认3个) - * @param excludeUuids 排除的卡牌UUID列表 (用于去重或排除已拥有) - * @param forcedType 强制指定卡牌类型 (用于特殊获取,如商店、技能书等) - * @param preferredAttrs 偏好的属性类型列表 (用于增加权重) - */ -export function getCardOptions(level: number, count: number = 3, excludeUuids: number[] = [], forcedType?: CardType, preferredAttrs: number[] = []): ICardInfo[] { - // 1. 确定类型:强制指定 > 默认为属性 - const type = forcedType !== undefined ? forcedType : CardType.Attr; - - const result: ICardInfo[] = []; - const excludeSet = new Set(excludeUuids); - - // 2. 获取该类型的候选池 - const rawItems = getDefaultPool(type, level); - - // 3. 构建候选列表(包含完整信息) - const candidates: ICardInfo[] = []; - for (const item of rawItems) { - if (excludeSet.has(item.id)) continue; - - const info = getCardBaseInfo(type, item.id); - if (info) { - info.weight = item.weight; - - // 如果是属性卡,且该属性在偏好列表中,增加权重 - if (type === CardType.Attr && preferredAttrs.length > 0) { - // AttrCards 的 payload 就是 AttrInfo,包含 attr 字段 - if (info.payload && preferredAttrs.includes(info.payload.attr)) { - // 增加权重,这里设置为 2 倍 - info.weight *= 2; - } - } - - candidates.push(info); - } - } - - // 4. 抽取 - for (let i = 0; i < count; i++) { - if (candidates.length === 0) break; - - const card = weightedRandomCard(candidates); - if (card) { - result.push(card); - // 移除已选,防止重复 - const idx = candidates.indexOf(card); - if (idx > -1) candidates.splice(idx, 1); - } - } - - // 5. 兜底逻辑:如果数量不足,且当前类型不是属性,则用属性卡补齐 - if (result.length < count && type !== CardType.Attr) { - const attrItems = getDefaultPool(CardType.Attr); // 兜底可以用全量属性池 - for (const item of attrItems) { - if (result.length >= count) break; - - // 检查是否已存在(ID去重) - if (excludeSet.has(item.id) || result.some(r => r.uuid === item.id)) continue; - - const info = getCardBaseInfo(CardType.Attr, item.id); - if (info) { - info.weight = 100; - result.push(info); - } - } - } - - shuffleArray(result); - return result; -} - -// ========== 工具函数 ========== - -function weightedRandomPool(configs: IPoolConfig[]): IPoolConfig | null { - if (!configs || configs.length === 0) return null; - - const totalWeight = configs.reduce((sum, item) => sum + item.poolWeight, 0); - let randomVal = Math.random() * totalWeight; - - for (const config of configs) { - randomVal -= config.poolWeight; - if (randomVal <= 0) { - return config; - } - } - return configs[configs.length - 1]; -} - -function weightedRandomCard(cards: ICardInfo[]): ICardInfo | null { - if (!cards || cards.length === 0) return null; - - const totalWeight = cards.reduce((sum, item) => sum + item.weight, 0); - let randomVal = Math.random() * totalWeight; - - for (const card of cards) { - randomVal -= card.weight; - if (randomVal <= 0) { - return card; - } - } - return cards[cards.length - 1]; -} - -function shuffleArray(array: any[]) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } -} diff --git a/assets/script/game/common/config/HeroAttrs.ts b/assets/script/game/common/config/HeroAttrs.ts index 33778b31..2a02d5d1 100644 --- a/assets/script/game/common/config/HeroAttrs.ts +++ b/assets/script/game/common/config/HeroAttrs.ts @@ -13,8 +13,6 @@ export enum BType { export enum NeAttrs { IN_FROST = 0, // 冰冻状态 IN_STUN = 1, // 眩晕状态 - IN_BURN = 2, // 灼烧状态 - IN_POISON = 3, // 中毒状态 } // ========== 属性枚举 ========== @@ -26,53 +24,27 @@ export enum NeAttrs { export enum Attrs { // ========== 基础生存属性 (0-9) ========== HP_MAX = 0, // 最大生命值 - MP_MAX = 1, // 最大魔法值 SHIELD_MAX = 2, // 最大护盾值 - HP_REGEN = 3, // 生命回复 - MP_REGEN = 4, // 魔法回复 - LUCK = 5, // 幸运值 + SPEED = 3, // 移动速度 // ========== 攻击属性 (10-19) ========== AP = 10, // 攻击力 DIS = 12, // 攻击距离 AS = 13, // 攻击速度(减少技能skills[0]CD) SS = 14, // 技能速度 (减少skills[0] 以外的cd) - SKILL_DURATION = 15, // 技能持续时间 - AREA_OF_EFFECT = 16, // 作用范围 - - // ========== 防御属性 (20-29) ========== - DEF = 20, // 防御 伤害减免 - DODGE = 22, // 闪避率 - THORNS = 25, // 反伤 - CRITICAL_RES = 26, // 暴击抗性 - CON_RES = 27, // 控制抗性 // ========== 暴击与命中属性 (30-39) ========== CRITICAL = 30, // 暴击率 CRITICAL_DMG = 31, // 暴击伤害 - HIT = 32, // 命中率 // ========== 特殊效果属性 (50-59) ========== - LIFESTEAL = 50, // 吸血比率 - MANASTEAL = 51, // 吸蓝比率 FREEZE_CHANCE = 52, // 冰冻概率 - BURN_CHANCE = 53, // 燃烧概率 STUN_CHANCE = 54, // 眩晕概率 BACK_CHANCE = 55, // 击退概率 SLOW_CHANCE = 56, // 减速概率 - POISON_CHANCE = 57, // 中毒概率 - SILENCE_CHANCE = 58, // 沉默概率 - EXPLOSION_CHANCE = 59, // 爆炸概率 // ========== 增益效果属性 (60-69) ========== - BUFF_UP = 60, // Buff效果提升 - DBUFF_UP = 61, // Debuff效果提升 - SHIELD_UP = 62, // 护盾效果提升 - SPEED = 63, // 移动速度加成 - EXP_GAIN = 64, // 经验获取 - GOLD_GAIN = 65, // 金币获取 - DROP_CHANCE = 66, // 掉落率 REVIVE_COUNT = 67, // 复活次数 REVIVE_TIME = 68, // 复活时间 INVINCIBLE_TIME = 69, // 无敌时间 @@ -80,23 +52,14 @@ export enum Attrs { // ========== 武器进化相关 (70-79) ========== PUNCTURE = 70, // 穿刺次数 PUNCTURE_DMG = 71, // 穿刺伤害 - MOVE_SPEED = 74, // 移动速度 - BURN = 75, // 易伤效果 WFUNY = 77, // 风怒 - // ========== 负面状态相关 (80-89) ========== - DMG_INVUL = 80, //易伤 - // ========== 怪物特殊属性 (90-99)========== - ATK_TRI_RESET = 90, // 英雄攻击触发计数重置 - DMG_TRI_RESET = 91, // 英雄伤害触发计数重置 BOOM = 92, // 自爆怪 } export const defaultAttrs = { [Attrs.BACK_CHANCE]:0, - [Attrs.DODGE]:0, - [Attrs.CON_RES]:0, } /** * 初始化英雄属性对象 @@ -136,55 +99,27 @@ export const getNeAttrs = () => { export const AttrsType: Record = { // ========== 基础生存属性(数值型) ========== [Attrs.HP_MAX]: BType.VALUE, // 最大生命值 - 数值型 - [Attrs.MP_MAX]: BType.VALUE, // 最大魔法值 - 数值型 [Attrs.SHIELD_MAX]: BType.VALUE, // 最大护盾值 - 数值型 - [Attrs.HP_REGEN]: BType.RATIO, // 生命回复 - 百分比型 - [Attrs.MP_REGEN]: BType.VALUE, // 魔法回复 - 数值型 - [Attrs.LUCK]: BType.VALUE, // 幸运 - 数值型 // ========== 攻击属性(数值型) ========== [Attrs.AP]: BType.VALUE, // 攻击力 - 数值型 [Attrs.DIS]: BType.VALUE, // 攻击距离 - 数值型 [Attrs.AS]: BType.RATIO, // 攻击速度 - 百分比型 [Attrs.SS]: BType.RATIO, // 技能速度 - 百分比型 - [Attrs.SKILL_DURATION]: BType.RATIO, // 技能持续时间 - 百分比型 - [Attrs.AREA_OF_EFFECT]: BType.VALUE, // 作用范围 - 数值型 - - // ========== 防御属性(混合类型) ========== - [Attrs.DEF]: BType.VALUE, // 物理防御 - 数值型 - [Attrs.DODGE]: BType.RATIO, // 闪避率 - 百分比型 - [Attrs.THORNS]: BType.RATIO, // 反伤 - 百分比型 // ========== 暴击与命中属性(百分比型) ========== [Attrs.CRITICAL]: BType.RATIO, // 暴击率 - 百分比型 [Attrs.CRITICAL_DMG]: BType.RATIO, // 暴击伤害 - 百分比型 - [Attrs.HIT]: BType.RATIO, // 命中率 - 百分比型 - [Attrs.CRITICAL_RES]: BType.RATIO, // 暴击抗性 - 百分比型 - [Attrs.CON_RES]: BType.RATIO, // 控制抗性 - 百分比型 - // ========== 特殊效果属性(百分比型) ========== - [Attrs.LIFESTEAL]: BType.RATIO, // 吸血比率 - 百分比型 - [Attrs.MANASTEAL]: BType.RATIO, // 吸蓝 - 百分比型 [Attrs.FREEZE_CHANCE]: BType.RATIO, // 冰冻概率 - 百分比型 - [Attrs.BURN_CHANCE]: BType.RATIO, // 燃烧概率 - 百分比型 [Attrs.STUN_CHANCE]: BType.RATIO, // 眩晕概率 - 百分比型 [Attrs.BACK_CHANCE]: BType.RATIO, // 击退概率 - 百分比型 [Attrs.SLOW_CHANCE]: BType.RATIO, // 减速概率 - 百分比型 - [Attrs.POISON_CHANCE]: BType.RATIO, // 中毒概率 - 百分比型 - [Attrs.SILENCE_CHANCE]: BType.RATIO, // 沉默概率 - 百分比型 - [Attrs.EXPLOSION_CHANCE]: BType.RATIO, // 爆炸概率 - 百分比型 // ========== 增益效果属性(百分比型) ========== - [Attrs.BUFF_UP]: BType.RATIO, // Buff效果提升 - 百分比型 - [Attrs.DBUFF_UP]: BType.RATIO, // Debuff效果提升 - 百分比型 - [Attrs.SHIELD_UP]: BType.RATIO, // 护盾效果提升 - 百分比型 - [Attrs.SPEED]: BType.RATIO, // 移动速度加成 - 百分比型 - [Attrs.EXP_GAIN]: BType.RATIO, // 经验获取 - 百分比型 - [Attrs.GOLD_GAIN]: BType.RATIO, // 金币获取 - 百分比型 - [Attrs.DROP_CHANCE]: BType.RATIO, // 掉落率 - 百分比型 [Attrs.REVIVE_COUNT]: BType.VALUE, // 复活次数 - 数值型 [Attrs.REVIVE_TIME]: BType.RATIO, // 复活时间 - 百分比型 [Attrs.INVINCIBLE_TIME]: BType.RATIO, // 无敌时间 - 百分比型 @@ -192,17 +127,7 @@ export const AttrsType: Record = { // ========== 武器进化相关(混合类型) ========== [Attrs.PUNCTURE]: BType.VALUE, // 穿刺次数 - 数值型 [Attrs.PUNCTURE_DMG]: BType.RATIO, // 穿刺伤害 - 百分比型 - [Attrs.MOVE_SPEED]: BType.VALUE, // 移动速度 - 数值型 - [Attrs.BURN]: BType.RATIO, // 易伤效果 - 百分比型 [Attrs.WFUNY]: BType.RATIO, // 未知特殊属性 - 百分比型 - - - // ========== 负面状态相关(混合类型) ========== - [Attrs.DMG_INVUL]: BType.RATIO, //易伤 - - // ========== 怪物独有特殊属性 (90-99)========== - [Attrs.ATK_TRI_RESET]: BType.BOOLEAN, // 英雄攻击触发计数重置 - [Attrs.DMG_TRI_RESET]: BType.BOOLEAN, // 英雄伤害触发计数重置 [Attrs.BOOM]: BType.BOOLEAN, // 自爆怪 }; diff --git a/assets/script/game/common/config/TalSet.ts b/assets/script/game/common/config/TalSet.ts deleted file mode 100644 index 7581fd6c..00000000 --- a/assets/script/game/common/config/TalSet.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { count } from "console"; -import { Attrs, BType } from "./HeroAttrs"; -import { CardKind } from "./GameSet"; - -/** - * 天赋类型枚举,也是触发条件 - */ -export enum TriType { - ATK = 1, // 等级升触发 - DMG = 2, //普通攻击触发 - ATKED=3, - SKILL = 4, // 技能触发 - HPL = 6, // 失去生命值触发 - HPA = 7, // 获得生命值触发 - INIT = 8, // 初始触发,如:多1个技能 - DEAD = 9, // 基于死亡触发 -} - - - -export enum TalEffet { - ATK_DMG=1, // 伤害 次数+伤害加成,如额外5次 伤害+20% - SKILL_DMG=2, // 技能伤害 次数+伤害加成,如额外5次 伤害+20% - DEF=10, // 减伤 次数+减伤加成,如额外5次 伤害-20% - THORNS=14, //反伤 百分比 次数+反伤加成,如额外5次 反伤-20% - /////////////////////////////////////////////////////////////////////// - HP=3, // 回血 百分比 直接触发,回血20% - SHIELD=9, // 护盾 直接触发,获得20%的生命值护盾 -//////////////////////////////////////////////////////////////////////// - BUFF = 5, // 数值叠加 触发后清零: 暴击率,闪避率等,触发后效果取消 -//////////////////////////////////////////////////////////////////////////////// - ATTR=6, // 属性 永久添加 - - WFUNY=7, // 风怒 次数 叠加 ,如额外5次 风怒 - D_SKILL=8, //两次技能 次数 叠加,如额外5次 两次技能 - C_MSKILL=11, // 必杀技能必暴 次数 叠加 ,如额外5次 必杀技能必暴 - C_ATK=12, // 普工必爆 次数 叠加 ,如额外5次 普工必爆 - C_SKILL=13, // 一般技能必暴 次数 叠加 ,如额外5次 一般技能必暴 -} - - -export enum TalTarget { - SELF = 1, // 自己触发 - ENEMY = 2, // 敌人触发 -} - -export enum TalAttrs { - NON=0, - FREEZE_CHANCE=Attrs.FREEZE_CHANCE, // 冰冻概率 - STUN_CHANCE=Attrs.STUN_CHANCE, // 冰冻概率 - BACK_CHANCE=Attrs.BACK_CHANCE, // 击退概率 - SILENCE_CHANCE=Attrs.SILENCE_CHANCE, // 沉默概率 - CRITICAL=Attrs.CRITICAL, // 暴击率 - AP=Attrs.AP, // 攻击力 - HP_MAX=Attrs.HP_MAX, // 最大生命值 - THORNS=Attrs.THORNS, //反伤 百分比 - REVIVE_COUNT=Attrs.REVIVE_COUNT, // 复活次数 - WFUNY=Attrs.WFUNY, // 风怒 -} - -/** - * 天赋配置接口 - * 定义一个完整的天赋效果 - */ - -export interface ItalConf { - uuid: number; // 天赋ID - name: string; // 天赋名称 - icon:string; // 天赋图标 - kind:CardKind; // 天赋类型 - triType: TriType; // 天赋触发类型 - target: TalTarget; // 天赋触发目标 - effet: TalEffet; // 天赋触发效果 - vType:BType; //数值型还是百分比型 - value: number; // 触发的效果值(如增加10%攻击力, 触发的技能uuid,增加1个技能uuid) - attrs?:TalAttrs //触发的attrs效果的对应attrs - Trigger:number //触发值 - Pts:number //添加的天赋点数 - CPts:number //消耗的天赋点数 - desc: string; // 天赋描述(说明触发条件和效果) - count:number //执行次数,及可以触发的次数 -} - -// ========== 天赋配置表 ========== - -/** - * 天赋配置表 - 2行紧凑格式 - * 每个天赋配置压缩为2行:注释行 + 配置对象行 - * - * 格式说明: - * 第1行:// 天赋名称 - 英雄专属/通用 | 触发条件 | 效果描述 - * 第2行:{uuid, name, desc, type, triggerType, chance, t_value, e_value, e_name, e_type, e_scaling, e_count, stackable, maxStack} - * - * 使用说明: - * 1. 等级类天赋:当英雄升级到指定等级时,每次都会触发效果 - * 2. 行为计数类:当特定行为累计达到阈值时触发,支持是否重置计数 - * 3. 受伤计数类:当受伤累计达到阈值时触发,支持是否重置计数 - * 4. 技能触发类:当特定条件满足时自动触发指定技能 - */ -export const talConf: Record = { - /*** 普通攻击触发 ***/ - 7001:{uuid:7001,name:"风怒",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.WFUNY,vType:BType.RATIO, value:50,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"普通攻击3次后, 立即给与目标150%伤害的额外打击"}, - 7003:{uuid:7003,name:"回血",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.HP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"普通攻击3次后, 会回复1%的生命值"}, - 7004:{uuid:7004,name:"回血(大)",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.HP,vType:BType.RATIO, value:2,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"普通攻击5次后, 会回复2%的生命值"}, - 7005:{uuid:7005,name:"冰冻",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:100,attrs:TalAttrs.FREEZE_CHANCE, - Pts:2,CPts:0,desc:"普通攻击3次后, 下一次攻击必定冻结目标"}, - 7006:{uuid:7006,name:"沉默",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:100,attrs:TalAttrs.SILENCE_CHANCE, - Pts:2,CPts:0,desc:"普通攻击3次后, 下一次攻击必定沉默目标"}, - 7007:{uuid:7007,name:"击退",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:100,attrs:TalAttrs.BACK_CHANCE, - Pts:2,CPts:0,desc:"普通攻击3次后, 下一次攻击必定击退目标"}, - 7008:{uuid:7008,name:"会心",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.BUFF,vType:BType.RATIO, value:100,attrs:TalAttrs.CRITICAL, - Pts:2,CPts:0,desc:"普通攻击3次后, 下一次攻击必定获得100%的暴击率"}, - 7009:{uuid:7009,name:"眩晕",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:100,attrs:TalAttrs.STUN_CHANCE, - Pts:2,CPts:0,desc:"普通攻击3次后, 下一次攻击必定获得100%的眩晕率"}, - 7010:{uuid:7010,name:"熟练",icon:"7001",kind:CardKind.Atk,triType:TriType.ATK,Trigger:10,count:1,target:TalTarget.SELF,effet:TalEffet.D_SKILL,vType:BType.RATIO, value:0,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"普通攻击10次后, 下次一般技能额外释放1次,伤害100%"}, - - /*** 受伤触发 ***/ - 7101:{uuid:7101,name:"反击",icon:"7001",kind:CardKind.Atted,triType:TriType.ATKED,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.ATK_DMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"被攻击3次后, 给于目标50%的伤害"}, - 7102:{uuid:7102,name:"护盾",icon:"7001",kind:CardKind.Atted,triType:TriType.ATKED,Trigger:30,count:1,target:TalTarget.SELF,effet:TalEffet.SHIELD,vType:BType.RATIO, value:20,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"被攻击30次后, 获得20%的生命值护盾"}, - 7103:{uuid:7103,name:"减伤",icon:"7001",kind:CardKind.Atted,triType:TriType.ATKED,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.DEF,vType:BType.RATIO, value:50,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"被攻击3次后, 下1次伤害减50%"}, - 7104:{uuid:7104,name:"复苏",icon:"7001",kind:CardKind.Atted,triType:TriType.ATKED,Trigger:100,count:1,target:TalTarget.SELF,effet:TalEffet.BUFF,vType:BType.VALUE, value:1,attrs:TalAttrs.REVIVE_COUNT, - Pts:2,CPts:0,desc:"被攻击100次后, 获得1次复活"}, - - /*** 失去血量触发 ***/ - 7201:{uuid:7201,name:"背水",icon:"7001",kind:CardKind.Hp,triType:TriType.HPL,Trigger:50,count:10,target:TalTarget.SELF,effet:TalEffet.C_ATK,vType:BType.VALUE, value:0,attrs:TalAttrs.NON, - Pts:2,CPts:0,desc:"每失去50%生命值,获得下10次普通攻击暴击"}, - - - - /*** 7400 回血量触发 ***/ - /** 7500 一击必杀触发 */ - }; -export const CanSelectTalents: Record = { - // 3级开放攻击类天赋 - 3: [7001, 7003, 7005, 7008], - // 5级必出防御类 - 5: [7101, 7102, 7103], - // 9级混合 - 9: [7001, 7003, 7005, 7008, 7101, 7102, 7103], - // 20级终极天赋 - 20: [7301, 7302], - // 默认全开 - 99: [7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7101, 7102, 7103, 7104, 7201, 7301, 7302] -}; - -// ========== 工具函数 ========== diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 20e3da4b..a68508fd 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -3,7 +3,6 @@ import { BoxSet, FacSet } from "./GameSet" import { smc } from "../SingletonModuleComp" import { BuffConf, SkillRange } from "./SkillSet" import { Interface } from "readline" -import { TriType } from "./TalSet" export enum AttrSet { ATTR_MAX = 85, @@ -94,11 +93,6 @@ export enum HRegen { HP=0.5 } -export interface ITalPts { - TriType: TriType; //触发添加天赋点数类型 - TriVal: number; //触发添加天赋点需求数值 - TalPts: number; //添加天赋点数值 -} /** * 不同职业升级属性加成配置 * 战士:高血量成长,低攻击成长 @@ -137,8 +131,6 @@ export interface heroInfo { speed: number; // 移动速度(像素/秒) skills: number[]; // 携带技能ID列表 buff: BuffConf[]; // 自带buff配置(通常为空,由技能动态添加) - tal: number[]; // 天赋ID列表 - talPts?: ITalPts[]; // 天赋触发配置 info: string; // 描述文案 } @@ -159,37 +151,37 @@ export const HeroInfo: Record = { 5001:{uuid:5001,name:"盾战士",icon:"1001",path:"hk1", fac:FacSet.HERO, kind:1,as:1, type:HType.warrior,lv:1,hp:300,mp:200,def:5,ap:25,speed:120,skills:[6001,6004], rangeType: SkillRange.Melee, - buff:[],tal:[],talPts:[{TriType:TriType.ATK,TriVal:1,TalPts:1}],info:"盾战士"}, + buff:[],info:"盾战士"}, 5002:{uuid:5002,name:"奥术法师",icon:"1001",path:"hm2", fac:FacSet.HERO, kind:2,as:1, type:HType.mage,lv:1,hp:150,mp:135,def:0,ap:40,speed:95,skills:[6003,6101], rangeType: SkillRange.Long, - buff:[],tal:[],info:"奥术法师"}, + buff:[],info:"奥术法师"}, 5003:{uuid:5003,name:"射手",icon:"1001",path:"ha1", fac:FacSet.HERO, kind:2,as:1, type:HType.remote,lv:1,hp:180,mp:80,def:0,ap:30,speed:140,skills:[6002,6100], rangeType: SkillRange.Long, - buff:[],tal:[],info:"射手"}, + buff:[],info:"射手"}, 5005:{uuid:5005,name:"牧师",icon:"1001",path:"hh1", fac:FacSet.HERO, kind:2,as:1, type:HType.mage,lv:1,hp:160,mp:135,def:0,ap:25,speed:100,skills:[6003,6100], rangeType: SkillRange.Mid, - buff:[],tal:[],info:"牧师"}, + buff:[],info:"牧师"}, 5004:{uuid:5004,name:"火焰法师",icon:"1001",path:"hm1", fac:FacSet.HERO, kind:2,as:1, type:HType.mage,lv:1,hp:150,mp:140,def:0,ap:45,speed:90,skills:[6003,6101], rangeType: SkillRange.Mid, - buff:[],tal:[],info:"火焰法师"}, + buff:[],info:"火焰法师"}, 5006:{uuid:5006,name:"召唤法师",icon:"1001",path:"hz1", fac:FacSet.HERO, kind:2,as:1, type:HType.support,lv:1,hp:200,mp:145,def:0,ap:20,speed:105,skills:[6003,6101], rangeType: SkillRange.Mid, - buff:[],tal:[],info:"召唤法师"}, + buff:[],info:"召唤法师"}, 5007:{uuid:5007,name:"刺客",icon:"1001",path:"hc1", fac:FacSet.HERO, kind:1,as:1, type:HType.assassin,lv:1,hp:140,mp:60,def:0,ap:50,speed:180,skills:[6001,6004], rangeType: SkillRange.Melee, - buff:[],tal:[],info:"刺客"}, + buff:[],info:"刺客"}, @@ -198,48 +190,48 @@ export const HeroInfo: Record = { 5201:{uuid:5201,name:"兽人战士",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.warrior,lv:1,hp:60,mp:100,def:0,ap:8,speed:180,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"标准炮灰:确保英雄能完成3次普攻积累天赋计数"}, + buff:[],info:"标准炮灰:确保英雄能完成3次普攻积累天赋计数"}, // 2. 快速突击型 5301:{uuid:5301,name:"兽人斥候",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:1.2, type:HType.assassin,lv:1,hp:40,mp:100,def:0,ap:12,speed:400,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"}, + buff:[],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"}, // 3. 重型坦克型 5401:{uuid:5401,name:"兽人卫士",icon:"1001",path:"mo3", fac:FacSet.MON, kind:1,as:5.0, type:HType.warrior,lv:1,hp:200,mp:100,def:5,ap:15,speed:60,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"重型坦克:数值墙,检测玩家破甲(7008)与持续输出"}, + buff:[],info:"重型坦克:数值墙,检测玩家破甲(7008)与持续输出"}, // 4. 远程骚扰型 5501:{uuid:5501,name:"兽人射手",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.remote,lv:1,hp:50,mp:100,def:0,ap:10,speed:90,skills:[6203], rangeType: SkillRange.Long, - buff:[],tal:[],info:"远程骚扰:跨屏打击,迫使阵地分散或移动英雄"}, + buff:[],info:"远程骚扰:跨屏打击,迫使阵地分散或移动英雄"}, // 5. 特殊机制型 5601:{uuid:5601,name:"兽人自爆兵",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.assassin,lv:1,hp:80,mp:100,def:0,ap:200,speed:220,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"}, + buff:[],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"}, // 召唤师:持续召唤小怪(后续可在技能系统中实现 SType.zhaohuan) 5602:{uuid:5602,name:"兽人召唤师",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.mage,lv:1,hp:150,mp:300,def:5,ap:10,speed:100,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"战术目标:持续召唤小怪,检测英雄大招清场频率"}, + buff:[],info:"战术目标:持续召唤小怪,检测英雄大招清场频率"}, // 治疗者:为周围怪物回血(此处以提升治疗效果和生命回复为基础被动) 5603:{uuid:5603,name:"兽人祭司",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.support,lv:1,hp:150,mp:300,def:5,ap:10,speed:105,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"战术目标:为怪群回血,检测玩家沉默(7006)覆盖率"}, + buff:[],info:"战术目标:为怪群回血,检测玩家沉默(7006)覆盖率"}, // 光环怪:为周围怪物提供增益(此处以Buff效果提升与移动速度提升为基础被动) // Attrs.BUFF_UP=60 (RATIO=1),Attrs.SPEED=63 (RATIO=1) 5604:{uuid:5604,name:"兽人图腾师",icon:"1001",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, type:HType.support,lv:1,hp:150,mp:250,def:5,ap:10,speed:110,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"战术目标:提供加速光环,改变怪群推进节奏"}, + buff:[],info:"战术目标:提供加速光环,改变怪群推进节奏"}, // 6. 精英/BOSS型 5701:{uuid:5701,name:"兽人首领(BOSS)",icon:"1001",path:"mo4", fac:FacSet.MON, kind:1,as:2.5, type:HType.warrior,lv:3,hp:2000,mp:500,def:10,ap:60,speed:120,skills:[6003], rangeType: SkillRange.Long, - buff:[],tal:[],info:"终极考验:极高HP,检测大招重置与辐射协同输出"}, + buff:[],info:"终极考验:极高HP,检测大招重置与辐射协同输出"}, }; diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index e5489ee1..8af7113e 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -10,7 +10,6 @@ import { GameEvent } from "../common/config/GameEvent"; import { getNeAttrs, getAttrs ,Attrs, defaultAttrs} from "../common/config/HeroAttrs"; import { HeroSkillsComp } from "./HeroSkills"; import { HeroMoveComp } from "./HeroMove"; -import { TalComp } from "./TalComp"; import { mLogger } from "../common/Logger"; import { HeroMasterComp } from "./HeroMasterComp"; /** 角色实体 */ @@ -21,7 +20,6 @@ export class Hero extends ecs.Entity { HeroSkills!: HeroSkillsComp; View!: HeroViewComp; HeroMove!: HeroMoveComp; - TalComp!: TalComp; debugMode: boolean = false; // 是否启用调试模式 protected init() { this.addComponents( @@ -41,7 +39,6 @@ export class Hero extends ecs.Entity { this.remove(HeroViewComp); this.remove(HeroAttrsComp); this.remove(HeroSkillsComp); - this.remove(TalComp); this.remove(HeroMasterComp) super.destroy(); } @@ -85,16 +82,6 @@ export class Hero extends ecs.Entity { model.is_friend = is_friend model.rangeType = hero.rangeType; // 只有主角才挂载天赋组件 - if (is_master) { - mLogger.log(this.debugMode,`[Hero] 主角创建, uuid=${uuid},is_master=${is_master}`); - this.add(TalComp); - this.add(HeroMasterComp) - const talComp = this.get(TalComp); - if (talComp) { - talComp.init(uuid); - } - model.initEvent(); - } // ✅ 初始化技能数据(迁移到 HeroSkillsComp) skillsComp.initSkills(hero.skills, uuid); diff --git a/assets/script/game/hero/HeroAttrsComp.ts b/assets/script/game/hero/HeroAttrsComp.ts index 2ff45bd6..c71cda2b 100644 --- a/assets/script/game/hero/HeroAttrsComp.ts +++ b/assets/script/game/hero/HeroAttrsComp.ts @@ -6,7 +6,6 @@ import { BuffConf, SkillRange } from "../common/config/SkillSet"; import { HeroInfo, AttrSet, HType, JobUpConf } from "../common/config/heroSet"; import { HeroSkillsComp } from "./HeroSkills"; import { smc } from "../common/SingletonModuleComp"; -import { AttrCards, PotionCards } from "../common/config/AttrSet"; import { mLogger } from "../common/Logger"; import { _decorator } from "cc"; @@ -29,23 +28,14 @@ export class HeroAttrsComp extends ecs.Comp { fac: number = 0; // 0:hero 1:monster rangeType:SkillRange = SkillRange.Melee; // ==================== 基础属性(有初始值) ==================== - base_ap: number = 0; // 基础攻击 - base_def: number = 5; // 基础防御 - base_hp: number = 100; // 基础血量 - base_mp: number = 100; // 基础魔法值 - base_speed: number = 100; // 基础移动速度 - base_dis: number = 100; // 基础距离 - - // ==================== 动态属性值 ==================== - hp: number = 100; // 当前血量 - mp: number = 100; // 当前魔法值 + ap: number = 0; // 基础攻击 + hp: number = 100; // 基础血量 + hp_max: number = 100; // 最大血量 + speed: number = 100; // 基础移动速度 + dis: number = 100; // 基础距离 shield: number = 0; // 当前护盾 - Attrs: any = []; // 最终属性数组(经过Buff计算后) - NeAttrs: any = []; // 负面状态数组 - //计数型天赋buff - Talents: Record = {}; - //数值型天赋buff - BUFFS_TAL: Record = {}; + shield_max: number = 0; // 最大护盾值 + // ==================== 脏标签标记 ==================== dirty_hp: boolean = false; // 血量变更标记 @@ -58,11 +48,8 @@ export class HeroAttrsComp extends ecs.Comp { // ==================== Buff/Debuff 系统 ==================== /** 持久型buff数组 - 不会自动过期 */ - BUFFS: Record> = {}; - - /** 临时型buff数组 - 按时间自动过期 */ - BUFFS_TEMP: Record> = {}; - + BUFFS: Record> = {}; + DEBUFFS: Record> = {}; // ==================== 标记状态 ==================== is_dead: boolean = false; @@ -81,103 +68,7 @@ export class HeroAttrsComp extends ecs.Comp { killed_count:number=0; // 注意:技能数据已迁移到 HeroSkillsComp,不再存储在这里 - initEvent() { - // 监听升级事件 - mLogger.log(this.debugMode, 'HeroAttrs', ` 注册升级事件监听`); - oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this); - // 移除卡牌事件监听,改为由 MissionCardComp 直接调用,避免非主角响应 - // oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this); - // oops.message.on(GameEvent.UseAttrCard, this.onUseAttrCard, this); - } - removeEvent() { - mLogger.log(this.debugMode, 'HeroAttrs', ` 移除升级事件监听`); - oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this); - // oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this); - // oops.message.off(GameEvent.UseAttrCard, this.onUseAttrCard, this); - } - - onUseAttrCard(event: string, args: any) { - if (!this.is_master) return; - const uuid = args; - const attrCard = AttrCards[uuid]; - if (attrCard) { - mLogger.log(this.debugMode, 'HeroAttrs', ` 使用属性卡: ${attrCard.desc}`); - // 构造 BuffConf,默认使用 BType.VALUE,永久生效 (time: 0) - const buffConf: BuffConf = { - buff: attrCard.attr, - value: attrCard.value, - BType: BType.VALUE, - time: 0, - chance: 1, // 必中 - }; - this.addBuff(buffConf); - smc.updateHeroInfo(this); // 确保同步到全局数据 - oops.gui.toast(attrCard.desc); - } - } - - onUseItemCard(event: string, args: any) { - if (!this.is_master) return; - const itemId = args; - - // 1. 尝试从 PotionCards 获取 (新版药水) - const potion = PotionCards[itemId]; - if (potion) { - mLogger.log(this.debugMode, 'HeroAttrs', ` 使用药水: ${potion.desc}`); - const buffConf: BuffConf = { - buff: potion.attr, - value: potion.value, - BType: BType.RATIO, // 药水默认是百分比加成 - time: potion.duration, - chance: 1, - }; - this.addBuff(buffConf); - oops.gui.toast(potion.desc); - return; - } - } - - /** - * 处理英雄升级逻辑 - */ - onLevelUp(event: string, args: any) { - mLogger.log(this.debugMode, 'HeroAttrs', ` 收到升级事件: is_master=${this.is_master}, args=${JSON.stringify(args)}`); - // 只有主角才响应升级事件 - if (!this.is_master) return; - const newLv = args.lv; - mLogger.log(this.debugMode, 'HeroAttrs', ` 英雄升级处理: Lv.${this.lv} -> Lv.${newLv}`); - if (newLv > this.lv) { - this.lv = newLv; - - // === 属性成长逻辑 === - // 根据职业获取成长属性 - const jobConf = JobUpConf[this.type as HType] || { hp: 30, ap: 5, def: 1 }; - const hpGrow = jobConf.hp; - const apGrow = jobConf.ap; - const defGrow = jobConf.def; - - this.base_hp += hpGrow; - this.base_ap += apGrow; - this.base_def += defGrow; - - // 重新计算受影响的属性 - this.recalculateSingleAttr(Attrs.HP_MAX); - this.recalculateSingleAttr(Attrs.AP); - this.recalculateSingleAttr(Attrs.DEF); - - // 升级福利:回复 20% 最大生命值 - const healRatio = 0.2; - const healAmount = Math.floor(this.Attrs[Attrs.HP_MAX] * healRatio); - this.add_hp(healAmount, true); - - // 同步数据到全局 - smc.updateHeroInfo(this); - - // 简单的UI提示 - // oops.gui.toast(`升级!HP+${hpGrow} AP+${apGrow}`); - } - } start(){ } @@ -189,55 +80,12 @@ export class HeroAttrsComp extends ecs.Comp { initAttrs() { // 清空现有 buff/debuff this.BUFFS = {}; - this.BUFFS_TEMP = {}; - this.BUFFS_TAL = {}; - this.Talents = {}; - + this.DEBUFFS = {}; // 获取英雄配置 const heroInfo = HeroInfo[this.hero_uuid]; if (!heroInfo) return; - // 1. 重置为基础值 - this.Attrs[Attrs.HP_MAX] = this.base_hp; - this.Attrs[Attrs.MP_MAX] = this.base_mp; - this.Attrs[Attrs.DEF] = this.base_def; - this.Attrs[Attrs.AP] = this.base_ap; - this.Attrs[Attrs.SPEED] = this.base_speed; - - // 2. 初始化其他属性(无初始值的) - for (const attrKey in this.Attrs) { - const attrIndex = parseInt(attrKey); - if ( - attrIndex !== Attrs.HP_MAX && - attrIndex !== Attrs.MP_MAX && - attrIndex !== Attrs.DEF && - attrIndex !== Attrs.AP && - attrIndex !== Attrs.SPEED - ) { - this.Attrs[attrIndex] = 0; - } - } - - // 加载初始 buff - if (heroInfo.buff && heroInfo.buff.length > 0) { - for (const buffConf of heroInfo.buff) { - this.addBuff(buffConf); - } - } - - // 3. 应用全局属性加成 (强制重算受影响的属性) - if (this.fac === 0 && smc.global_attrs) { - for (const key in smc.global_attrs) { - const attrIndex = Number(key); - this.recalculateSingleAttr(attrIndex); - } - } - - // 4. 初始化状态值 (确保满状态) - this.hp = this.Attrs[Attrs.HP_MAX]; - this.mp = this.Attrs[Attrs.MP_MAX]; - - smc.updateHeroInfo(this); + } /*******************基础属性管理********************/ @@ -245,7 +93,7 @@ export class HeroAttrsComp extends ecs.Comp { const oldHp = this.hp; let addValue = value; if(!isValue){ - addValue = value * this.Attrs[Attrs.HP_MAX] / 100; + addValue = value * this.hp_max / 100; } // ✅ 数据层只负责数据修改,不调用视图层 @@ -255,34 +103,16 @@ export class HeroAttrsComp extends ecs.Comp { // } this.hp += addValue; - this.hp = Math.max(0, Math.min(this.hp, this.Attrs[Attrs.HP_MAX])); + this.hp = Math.max(0, Math.min(this.hp, this.hp_max)); this.dirty_hp = true; // ✅ 仅标记需要更新 - smc.updateHeroInfo(this); mLogger.log(this.debugMode, 'HeroAttrs', ` HP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldHp.toFixed(1)} -> ${this.hp.toFixed(1)}`); } - add_mp(value:number,isValue:boolean){ - const oldMp = this.mp; - let addValue = value; - if(!isValue){ - addValue = value * this.Attrs[Attrs.MP_MAX] / 100; - } - - // ✅ 数据层只负责数据修改,不调用视图层 - // let heroView = this.ent.get(HeroViewComp); - // if(heroView){ - // heroView.mp_add(addValue); - // } - - this.mp += addValue; - this.mp = Math.max(0, Math.min(this.mp, this.Attrs[Attrs.MP_MAX])); - this.dirty_mp = true; // ✅ 仅标记需要更新 - mLogger.log(this.debugMode, 'HeroAttrs', ` MP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldMp.toFixed(1)} -> ${this.mp.toFixed(1)}`); - } + add_shield(value:number,isValue:boolean){ const oldShield = this.shield; let addValue = value; if(!isValue){ - addValue = value * this.Attrs[Attrs.HP_MAX] / 100; + addValue = value * this.shield_max / 100; } this.shield += addValue; this.dirty_shield = true; // 标记护盾需要更新 @@ -294,268 +124,21 @@ export class HeroAttrsComp extends ecs.Comp { * @param buffConf buff 配置 (来自 SkillSet.BuffConf heroSet.buff) */ addBuff(buffConf: BuffConf) { - const isPermanent = buffConf.time === 0; - const attrIndex = buffConf.buff; - - if (isPermanent) { - // 添加持久buff到BUFFS - 直接追加到数组 - if (!this.BUFFS[attrIndex]) { - this.BUFFS[attrIndex] = []; - } - this.BUFFS[attrIndex].push({ value: buffConf.value, BType: buffConf.BType }); - } else { - // 添加临时buff到BUFFS_TEMP - 直接追加到数组 - if (!this.BUFFS_TEMP[attrIndex]) { - this.BUFFS_TEMP[attrIndex] = []; - } - this.BUFFS_TEMP[attrIndex].push({ - value: buffConf.value, - BType: buffConf.BType, - remainTime: buffConf.time - }); - } - - // 重新计算受影响的属性 - this.recalculateSingleAttr(attrIndex); - smc.updateHeroInfo(this); // 确保同步到全局数据 + } - // ==================== 属性计算系统 ==================== - private getBaseValue(attrIndex: number): number { - switch (attrIndex) { - case Attrs.HP_MAX: return this.base_hp; - case Attrs.MP_MAX: return this.base_mp; - case Attrs.DEF: return this.base_def; - case Attrs.AP: return this.base_ap; - case Attrs.SPEED: return this.base_speed; - case Attrs.SHIELD_MAX: return 0; - default: return 0; - } - } - - /** - * 重新计算单个属性 - * @param attrIndex 属性索引 - */ - recalculateSingleAttr(attrIndex: number) { - const oldVal = this.Attrs[attrIndex] || 0; - const baseVal = this.getBaseValue(attrIndex); - - // 2. 收集所有数值型 buff/debuff - let totalValue = baseVal; - - // 遍历持久buff数组 - if (this.BUFFS[attrIndex] && this.BUFFS[attrIndex].length > 0) { - for (const buff of this.BUFFS[attrIndex]) { - if (buff.BType === BType.VALUE) { - totalValue += buff.value; - } - } - } - // 遍历临时buff数组 - if (this.BUFFS_TEMP[attrIndex] && this.BUFFS_TEMP[attrIndex].length > 0) { - for (const buff of this.BUFFS_TEMP[attrIndex]) { - if (buff.BType === BType.VALUE) { - totalValue += buff.value; - } - } - } - for (const key in this.BUFFS_TAL) { - const buff = this.BUFFS_TAL[Number(key)]; - if (buff.attrIndex === attrIndex && buff.BType === BType.VALUE) { - totalValue += buff.value; - } - } - - // 3. 收集所有百分比型 buff/debuff - let totalRatio = 0; - - // 遍历持久buff数组 - if (this.BUFFS[attrIndex] && this.BUFFS[attrIndex].length > 0) { - for (const buff of this.BUFFS[attrIndex]) { - if (buff.BType === BType.RATIO) { - totalRatio += buff.value; - } - } - } - // 遍历临时buff数组 - if (this.BUFFS_TEMP[attrIndex] && this.BUFFS_TEMP[attrIndex].length > 0) { - for (const buff of this.BUFFS_TEMP[attrIndex]) { - if (buff.BType === BType.RATIO) { - totalRatio += buff.value; - } - } - } - for (const key in this.BUFFS_TAL) { - const buff = this.BUFFS_TAL[Number(key)]; - if (buff.attrIndex === attrIndex && buff.BType === BType.RATIO) { - totalRatio += buff.value; - } - } - - // 全局属性加成 (只对英雄生效,怪物不生效) - // this.fac === 0 代表英雄 (FacSet.HERO) - if (this.fac === 0 && smc.global_attrs && smc.global_attrs[attrIndex]) { - const [val, count] = smc.global_attrs[attrIndex]; - const globalAdd = val * count; - totalRatio += globalAdd; - // mLogger.log(this.debugMode, 'HeroAttrs', ` 全局加成: ${this.hero_name} Attr=${attrIndex} Val=${val} Count=${count} Add=${globalAdd}%`); - } - - // 4. 根据属性类型计算最终值 - const attrType = AttrsType[attrIndex]; - const isRatioAttr = attrType === BType.RATIO; - - if (isRatioAttr) { - // 百分比型属性:直接加减 - this.Attrs[attrIndex] = totalValue + totalRatio; - } else { - // 数值型属性:(基础值+数值) × (1 + 百分比/100) - this.Attrs[attrIndex] = Math.floor(totalValue * (1 + totalRatio / 100)); - } - - // 5. 确保属性值合理 - this.clampSingleAttr(attrIndex); - - if (oldVal !== this.Attrs[attrIndex]) { - mLogger.log(this.debugMode, 'HeroAttrs', ` 属性重算: ${this.hero_name}, 属性ID=${attrIndex}, ${oldVal} -> ${this.Attrs[attrIndex]} (Base=${baseVal}, Add=${totalValue-baseVal}, Ratio=${totalRatio}%)`); - } - } - - /** - * 确保单个属性值合理 - */ - private clampSingleAttr(attrIndex: number) { - switch(attrIndex) { - case Attrs.HP_MAX: - case Attrs.MP_MAX: - this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]); - break; - case Attrs.DEF: - case Attrs.AP: - this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]); - break; - case Attrs.CRITICAL: - case Attrs.DODGE: - case Attrs.HIT: - this.Attrs[attrIndex] = Math.max(0, Math.min(AttrSet.ATTR_MAX, this.Attrs[attrIndex])); - break; - } - } // ==================== 临时 BUFF/DEBUFF 更新 ==================== /** * 更新临时 buff/debuff 的剩余时间 * @param dt 时间增量 */ - updateTemporaryBuffsDebuffs(dt: number) { - const affectedAttrs = new Set(); + updateBuffsDebuffs(dt: number) { - // 更新临时型buff - for (const attrIndex in this.BUFFS_TEMP) { - const buffs = this.BUFFS_TEMP[attrIndex]; - for (let i = buffs.length - 1; i >= 0; i--) { - const buff = buffs[i]; - buff.remainTime -= dt; - if (buff.remainTime <= 0) { - buffs.splice(i, 1); - } - } - if (buffs.length === 0) { - delete this.BUFFS_TEMP[attrIndex]; - affectedAttrs.add(parseInt(attrIndex)); - } - } - - // 负面状态更新 - for (const key in this.NeAttrs) { - const debuff = this.NeAttrs[key]; - debuff.remainTime -= dt; - if (debuff.remainTime <= 0) { - debuff.remainTime = 0; - } - } - - // 只重新计算受影响的属性 - affectedAttrs.forEach(attrIndex => { - this.recalculateSingleAttr(attrIndex); - }); } - // ==================== BUFF 辅助方法 ==================== - /** - * 清空buff - * @param attrIndex 属性索引,如果为空则清理所有buff - * @param isBuff true时清理value>0的增益buff,false时清理value<0的减益buff - */ - clearBuffs(attrIndex?: number, isBuff: boolean = true): void { - if (attrIndex === undefined) { - for (const attrIndex in this.BUFFS_TEMP) { - this.clearBuffsForAttr(parseInt(attrIndex), isBuff); - } - } else { - this.clearBuffsForAttr(attrIndex, isBuff); - } - } - - /** - * 清理指定属性的buff - * @param attrIndex 属性索引 - * @param isBuff true清理增益buff,false清理减益buff - */ - private clearBuffsForAttr(attrIndex: number, isBuff: boolean): void { - const buffContainer = this.BUFFS_TEMP; - - if (!buffContainer[attrIndex]) return; - - buffContainer[attrIndex] = buffContainer[attrIndex].filter(buff => { - const shouldClear = isBuff ? buff.value > 0 : buff.value < 0; - return !shouldClear; - }); - - if (buffContainer[attrIndex].length === 0) { - delete buffContainer[attrIndex]; - } - - this.recalculateSingleAttr(attrIndex); - } - - // ==================== NeAttrs(负面状态)管理 ==================== - /** - * 清理单个NeAttr(负面状态) - */ - clearNeAttr(neAttrIndex: number): void { - if (this.NeAttrs[neAttrIndex]) { - this.NeAttrs[neAttrIndex].value = 0; - this.NeAttrs[neAttrIndex].time = 0; - } - } - - /** - * 清理所有NeAttrs(负面状态) - */ - clearAllNeAttrs(): void { - for (const key in this.NeAttrs) { - this.NeAttrs[key].value = 0; - this.NeAttrs[key].time = 0; - } - } - - /** - * 检查是否处于眩晕状态 - */ - public isStun(): boolean { - return this.NeAttrs[NeAttrs.IN_STUN]?.time > 0; - } - - /** - * 检查是否处于冰冻状态 - */ - public isFrost(): boolean { - return this.NeAttrs[NeAttrs.IN_FROST]?.time > 0; - } // ==================== 技能距离缓存管理 ==================== /** @@ -591,117 +174,23 @@ export class HeroAttrsComp extends ecs.Comp { public getCachedMinSkillDistance(): number { return this.minSkillDistance; } - - - /** - * 添加数值型天赋buff 数值会进行累加,count 时叠加层数 - * @param t_uuid 天赋唯一标识 - * @param attrIndex 属性索引 - * @param bType buff类型(VALUE:数值型, RATIO:百分比型) - * @param value buff值 - */ - addValueTal(t_uuid: number, attrIndex?: number, bType?: BType, value: number = 0) { - if (attrIndex === undefined || bType === undefined) return; - const buff = this.BUFFS_TAL[t_uuid]; - if (!buff) { - this.BUFFS_TAL[t_uuid] = { count: 1, BType: bType, attrIndex, value }; - } else { - buff.count += 1; - buff.value += value; - } - this.recalculateSingleAttr(attrIndex); - } - - /** - * 添加计数型天赋,每次添加数值已最新额覆盖久的,count为可用次数 - * @param eff 天赋效果ID - * @param value 天赋值 - */ - addCountTal(eff: number, value: number) { - const t = this.Talents[eff] || { value: 0, count: 0 }; - t.value = value; - t.count += 1; - this.Talents[eff] = t; - } - /** - * 使用计数型天赋,如风怒 ,必爆等天赋,只需要返回是否暴击的,使用这个方法 - * @param eff 天赋效果ID - * @returns 是否使用成功 - */ - useCountTal(eff: number): boolean { - const t = this.Talents[eff]; - if (!t || t.count <= 0) return false; - t.count -= 1; - return true; - } - - /** - * 使用计数型天赋并返回天赋值,如额外5次 伤害+20% ,5次受伤,免伤20% 使用这个方法 - * @param eff 天赋效果ID - * @returns 天赋值 - */ - useCountValTal(eff: number): number { - const t = this.Talents[eff]; - if (!t || t.value <= 0) return 0; - t.count -= 1; - return t.value; - } - - /** - * 根据UUID移除数值型天赋buff - * @param t_uuid 天赋唯一标识 - */ - useValueTalByUuid(t_uuid: number) { - const buff = this.BUFFS_TAL[t_uuid]; - if (!buff) return; - buff.count--; - if (buff.count <= 0) { - delete this.BUFFS_TAL[t_uuid]; - } - this.recalculateSingleAttr(buff.attrIndex); - } - - - /** - * 根据属性索引移除数值型天赋buff - * @param attrIndex 属性索引 - */ - useValueTalByAttr(attrIndex: number) { - let changed = false; - for (const key in this.BUFFS_TAL) { - const b = this.BUFFS_TAL[Number(key)]; - if (b && b.attrIndex === attrIndex) { - delete this.BUFFS_TAL[Number(key)]; - changed = true; - } - } - if (changed) this.recalculateSingleAttr(attrIndex); - } - reset() { - this.removeEvent(); // 重置为初始状态 this.hero_uuid = 1001; this.hero_name = "hero"; this.lv = 1; this.type = 0; this.fac = 0; - this.base_ap = 0; - this.base_def = 5; - this.base_hp = 100; - this.base_mp = 100; - this.base_speed = 100; - this.base_dis = 0; + this.ap = 0; + this.hp = 100; + this.speed = 100; + this.dis = 0; this.hp = 100; - this.mp = 100; this.shield = 0; - this.Attrs = []; - this.NeAttrs = []; + this.shield_max = 0; this.BUFFS = {}; - this.BUFFS_TEMP = {}; - this.BUFFS_TAL = {}; - this.Talents = {}; + this.DEBUFFS = {}; // 重置技能距离缓存 this.maxSkillDistance = 0; this.minSkillDistance = 0; diff --git a/assets/script/game/hero/HeroAttrsSystem.ts b/assets/script/game/hero/HeroAttrsSystem.ts deleted file mode 100644 index f0e2c303..00000000 --- a/assets/script/game/hero/HeroAttrsSystem.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Timer } from "db://oops-framework/core/common/timer/Timer"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { smc } from "../common/SingletonModuleComp"; -import { Attrs } from "../common/config/HeroAttrs"; -import { HRegen } from "../common/config/heroSet"; -import { HeroSkillsComp } from "./HeroSkills"; -import { HeroAttrsComp } from "./HeroAttrsComp"; -import { HeroViewComp } from "./HeroViewComp"; -import { mLogger } from "../common/Logger"; -/** - * ==================== 英雄属性更新系统 ==================== - * - * 按照 ECS 设计理念: - * - Component(HeroAttrsComp):存储数据 - * - System(HeroAttrSystem):处理业务逻辑 - * - * 系统职责: - * 1. 每帧更新临时 Buff(时间递减,过期移除) - * 2. 每帧更新 HP/MP 自然回复 - * 3. 限制属性值在合理范围内 - * -/** - * 使用方式: - * 在 RootSystem 中注册此系统,它会自动每帧更新所有拥有 HeroAttrsComp 的实体 - */ -@ecs.register('HeroAttrSystem') -export class HeroAttrSystem extends ecs.ComblockSystem - implements ecs.ISystemUpdate, ecs.IEntityEnterSystem, ecs.ISystemFirstUpdate { - - // ==================== 调试统计(可选)==================== - private entityCount: number = 0; // 本帧处理的实体数 - private frameCount: number = 0; // 总帧数 - public debugMode: boolean = false; // 是否启用调试模式 - private RTimer:Timer=new Timer(5) - /** - * 过滤器:只处理拥有 HeroAttrsComp 的实体 - */ - filter(): ecs.IMatcher { - return ecs.allOf(HeroAttrsComp); - } - - /** - * 实体首次进入系统时调用(每个实体只调用一次) - */ - entityEnter(e: ecs.Entity): void { - const model = e.get(HeroAttrsComp); - if (!model) return; - - mLogger.log(this.debugMode, 'HeroAttrSystem', `[HeroAttrSystem] 英雄进入系统: ${model.hero_name} (uuid: ${model.hero_uuid})`); - } - - /** - * 系统首次更新前调用(整个系统只调用一次) - */ - firstUpdate(): void { - mLogger.log(this.debugMode, 'HeroAttrSystem', "[HeroAttrSystem] 系统首次更新"); - } - - /** - * 每帧更新(为每个英雄调用一次) - * - * ⭐ 关键理解: - * - 如果有 3 个英雄,这个方法每帧会被调用 3 次 - * - 每次调用处理不同的实体 e - * - 这是正确的设计,不是 bug - */ - update(e: ecs.Entity): void { - if(!smc.mission.play ) return; - if(smc.mission.pause) return - const model = e.get(HeroAttrsComp); - if (!model || model.is_dead || model.is_reviving) return; - - // 统计:记录本帧处理的实体数 - this.entityCount++; - - // 调试日志(可选,调试时启用) - if (this.debugMode) { - mLogger.log(this.debugMode, 'HeroAttrSystem', ` [${this.entityCount}] 更新英雄: ${model.hero_name}, HP: ${model.hp.toFixed(2)}`); - } - - // 1. 更新临时 Buff/Debuff(时间递减,过期自动移除) - model.updateTemporaryBuffsDebuffs(this.dt); - // 记录MP变化前的值 - const oldMp = model.mp; - - if(this.RTimer.update(this.dt)){ - - // 每5秒回血1次 - const hpRegen = model.Attrs[Attrs.HP_REGEN] || 0; - // 回血逻辑 + 视图表现 - const totalHpRegen = HRegen.HP + hpRegen; - if (totalHpRegen > 0) { - model.add_hp(totalHpRegen, false); - // 触发视图层回血特效 - const view = e.get(HeroViewComp); - if (view) { - view.health(totalHpRegen); - } - } - } - - // 3. 限制属性值在合理范围内 - if (model.mp > model.Attrs[Attrs.MP_MAX]) { - model.mp = model.Attrs[Attrs.MP_MAX]; - } - if (model.hp > model.Attrs[Attrs.HP_MAX]) { - model.hp = model.Attrs[Attrs.HP_MAX]; - } - - // 4. 如果MP发生变化,更新最大技能距离缓存(最小距离不受MP影响) - if (model.mp !== oldMp) { - const skillsComp = e.get(HeroSkillsComp); - if (skillsComp) { - model.updateSkillDistanceCache(skillsComp); - } - } - - // 每 60 帧输出一次统计 - this.frameCount++; - if (this.frameCount % 60 === 0 && this.entityCount === 1) { - mLogger.log(this.debugMode, 'HeroAttrSystem', `[HeroAttrSystem] 第 ${this.frameCount} 帧,处理 ${this.entityCount} 个英雄`); - } - - // 注意:显示更新由 HeroViewComp 负责,这里只处理数据 - } - - /** - * 启用调试模式(调试时使用) - */ - enableDebug() { - this.debugMode = true; - } - - /** - * 禁用调试模式(正式运行) - */ - disableDebug() { - this.debugMode = false; - } -} diff --git a/assets/script/game/hero/SACastSystem.ts b/assets/script/game/hero/SACastSystem.ts deleted file mode 100644 index 99a4da25..00000000 --- a/assets/script/game/hero/SACastSystem.ts +++ /dev/null @@ -1,621 +0,0 @@ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { Vec3, v3 } from "cc"; -import { HeroAttrsComp } from "./HeroAttrsComp"; -import { HeroViewComp } from "./HeroViewComp"; -import { HSSet, SkillSet, SType, TGroup, SkillConfig } from "../common/config/SkillSet"; -import { HeroSkillsComp, SkillSlot } from "./HeroSkills"; -import { Skill } from "../skill/Skill"; -import { smc } from "../common/SingletonModuleComp"; -import { TalComp } from "./TalComp"; -import { TalEffet, TriType } from "../common/config/TalSet"; -import { BoxSet, FacSet } from "../common/config/GameSet"; -import { GameConst } from "../common/config/GameConst"; -import { Attrs } from "../common/config/HeroAttrs"; -import { mLogger } from "../common/Logger"; - -/** - * ==================== 自动施法系统 ==================== - * - * 职责: - * 1. 检测可施放的技能 - * 2. 根据策略自动施法(AI) - * 3. 选择目标 - * 4. 添加施法请求标记 - * - * 设计理念: - * - 负责"何时施法"的决策 - * - 通过添加 CSRequestComp 触发施法 - * - 可被玩家输入系统或AI系统复用 - * - 支持多种AI策略 - */ -@ecs.register('SACastSystem') -export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { - debugMode: boolean = false; // 是否启用调试模式 - - filter(): ecs.IMatcher { - return ecs.allOf(HeroSkillsComp, HeroAttrsComp, HeroViewComp); - } - - update(e: ecs.Entity): void { - if(!smc.mission.play ) return; - if(smc.mission.pause) return - const skills = e.get(HeroSkillsComp); - if (!skills) return; - - // AI 降频:每0.2秒执行一次 - skills.ai_timer += this.dt; - if (skills.ai_timer < GameConst.Battle.AI_CHECK_INTERVAL) return; - skills.ai_timer = 0; - - const heroAttrs = e.get(HeroAttrsComp); - const heroView = e.get(HeroViewComp); - if (!heroAttrs || !heroView) return; - - // 检查基本条件 - if (heroAttrs.is_dead || heroAttrs.is_reviving || heroAttrs.isStun() || heroAttrs.isFrost()) return; - - // 移除 is_atking 检查,实现只要距离和CD满足即施法 - // if (!heroAttrs.is_atking) return; - - const readySkills = skills.getReadySkills(); - if (readySkills.length === 0) return; - - // 选择第一个可施放的技能(支持伤害/治疗/护盾) - for (const s_uuid of readySkills) { - const skill = skills.getSkill(s_uuid); - if (!skill) continue; - if (skill.hset === HSSet.max && !skills.max_auto) continue; - - const config = SkillSet[skill.s_uuid]; - if (!config) continue; - - // 根据技能类型检查目标 - if (config.SType === SType.damage) { - if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue; - } else if (config.SType === SType.heal || config.SType === SType.shield) { - if (!this.hasTeamInSkillRange(heroView, heroAttrs, skill.dis)) continue; - } else if (config.SType === SType.buff) { - if (!this.hasBuffTarget(heroView, heroAttrs, skill.dis, config.TGroup)) continue; - } - - // ✅ 开始执行施法 - this.startCast(e, skill, skill.hset); - - // 一次只施放一个技能 - break; - } - } - private startCast(e: ecs.Entity,skill:SkillSlot,hset:HSSet): boolean { - if (!skill||!e) return false - const skills = e.get(HeroSkillsComp); - const heroAttrs = e.get(HeroAttrsComp); - const heroView = e.get(HeroViewComp); - // 3. 检查施法条件 - if (!this.checkCastConditions(skills, heroAttrs, skill.s_uuid)) return false - - // 4. 执行施法 - const castSucess = this.executeCast(e, skill.s_uuid, heroView,hset); - // 5. 扣除资源和重置CD - if (castSucess) { - // 🔥 怪物不消耗蓝 - if (heroAttrs.fac !== FacSet.MON) { - // 手动更新技能距离缓存 - heroAttrs.updateSkillDistanceCache(skills); - } - skills.resetCD(skill.s_uuid); - } - return castSucess; - } - public manualCast(e: ecs.Entity, s_uuid: number): boolean { - if (!e) return false - const skills = e.get(HeroSkillsComp) - const heroAttrs = e.get(HeroAttrsComp) - const heroView = e.get(HeroViewComp) - if (!skills || !heroAttrs || !heroView) return false - const slot = skills.getSkill(s_uuid) - if (!slot) return false - return this.startCast(e, slot, slot.hset) - } - public manualCastMax(e: ecs.Entity): boolean { - const skills = e.get(HeroSkillsComp) - if (!skills) return false - for (const key in skills.skills) { - const s_uuid = Number(key) - const slot = skills.getSkill(s_uuid) - if (slot && slot.hset === HSSet.max) { - return this.manualCast(e, s_uuid) - } - } - return false - } - /** - * 检查施法条件 - */ - private checkCastConditions(skills: HeroSkillsComp, heroAttrs: HeroAttrsComp, s_uuid: number): boolean { - // 检查角色状态 - if (heroAttrs.is_dead) { - return false; - } - - // 检查控制状态(眩晕、冰冻) - if (heroAttrs.isStun() || heroAttrs.isFrost()) { - return false; - } - - // 检查CD - if (!skills.canCast(s_uuid)) { - return false; - } - - return true; - } - - /** - * 执行施法 - */ - private executeCast(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp,hset:HSSet): boolean { - const heroAttrs=casterEntity.get(HeroAttrsComp) - const config = SkillSet[s_uuid]; - if (!config) { - mLogger.error(this.debugMode, 'SACastSystem', "[SACastSystem] 技能配置不存在:", s_uuid); - return false; - } - - // 1. 播放施法动画 - heroView.playSkillEffect(s_uuid); -/**********************天赋处理*************************************************************************/ - // 2. 更新攻击类型的天赋触发值,技能和必杀级 - if(casterEntity.has(TalComp)){ - const talComp = casterEntity.get(TalComp); - if (hset === HSSet.atk) talComp.updateCur(TriType.ATK); - if (hset === HSSet.skill) talComp.updateCur(TriType.SKILL); - } -/**********************天赋处理*************************************************************************/ - // 根据技能类型执行不同逻辑 - if (config.SType === SType.heal) { - return this.executeHealSkill(casterEntity, s_uuid, heroView, hset); - } else if (config.SType === SType.shield) { - return this.executeShieldSkill(casterEntity, s_uuid, heroView, hset); - } else if (config.SType === SType.buff) { - return this.executeBuffSkill(casterEntity, s_uuid, heroView, hset); - } - - // 获取目标位置(伤害技能) - let targets = this.sTargets(heroView, s_uuid); - if (targets.length === 0) { - mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 没有找到有效目标"); - return false; - } - // 2.1 普通攻击逻辑 - if (hset === HSSet.atk){ - let delay = GameConst.Battle.SKILL_CAST_DELAY - let ext_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG); - heroView.scheduleOnce(() => { - this.createSkill(s_uuid, heroView,targets,ext_dmg); - }, delay); - //风怒wfuny 只针对 普通攻击起效 - if (heroAttrs.useCountTal(TalEffet.WFUNY)){ - let ext2_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG); - let delay = GameConst.Battle.SKILL_CAST_DELAY - heroView.playSkillEffect(s_uuid); - //需要再添加 风怒动画 - heroView.scheduleOnce(() => { - this.createSkill(s_uuid, heroView,targets,ext2_dmg); - },delay); - } - } - // 2.2 技能攻击逻辑 - if(hset === HSSet.skill){ - let delay = GameConst.Battle.SKILL_CAST_DELAY - let ext_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG); - heroView.scheduleOnce(() => { - this.createSkill(s_uuid, heroView,targets,ext_dmg); - }, delay); - // 双技能 只针对 技能起效 - if(heroAttrs.useCountTal(TalEffet.D_SKILL)){ - let ext2_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG); - let delay = GameConst.Battle.SKILL_CAST_DELAY - heroView.playSkillEffect(s_uuid); - //需要再添加 双技能动画 - heroView.scheduleOnce(() => { - this.createSkill(s_uuid, heroView,targets,ext2_dmg); - },delay); - } - } - // 2.3 必杀技能逻辑 - if(hset === HSSet.max){ - let delay = GameConst.Battle.SKILL_CAST_DELAY - heroView.playSkillEffect(s_uuid); - //需要再添加 最大伤害动画 - heroView.scheduleOnce(() => { - this.createSkill(s_uuid, heroView,targets); - },delay); - } - - - - return true; - } - - - /** - * 创建技能实体 - */ - private createSkill(s_uuid: number, caster: HeroViewComp,targets:Vec3[]=[],ext_dmg:number=0) { - // 检查节点有效性 - if (!caster.node || !caster.node.isValid) { - mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 施法者节点无效"); - return; - } - - // 获取场景节点 - const parent = caster.node.parent; - if (!parent) { - mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 场景节点无效"); - return; - } - - - - // 创建技能实体 - const skill = ecs.getEntity(Skill); - - // 获取施法者位置作为起始位置 - const startPos = caster.node.position.clone(); - - const targetPos = targets[0]; // 使用第一个目标位置 - // mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem]: ${s_uuid}, 起始位置: ${startPos}, 目标位置: ${targetPos}`); - // 加载技能实体(包括预制体、组件初始化等) - skill.load(startPos, parent, s_uuid, targetPos, caster,ext_dmg); - - } - /** - * 选择目标位置 - */ - private sTargets(caster: HeroViewComp, s_uuid: number): Vec3[] { - const heroAttrs = caster.ent.get(HeroAttrsComp); - if (!heroAttrs) return []; - const config = SkillSet[s_uuid]; - if (!config) return this.sDefaultTargets(caster, heroAttrs.fac); - const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, config.t_num ?? 1); - const targets = this.sDamageTargets(caster, config, maxTargets); - if (targets.length === 0) { - targets.push(...this.sDefaultTargets(caster, heroAttrs.fac)); - } - return targets; - } - - /** - * 选择伤害技能目标 - */ - private sDamageTargets(caster: HeroViewComp, config: SkillConfig, maxTargets: number): Vec3[] { - const targets: Vec3[] = []; - const heroAttrs = caster.ent.get(HeroAttrsComp); - if (!heroAttrs) return targets; - - const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - const enemyPositions = this.findNearbyEnemies(caster, heroAttrs.fac, range); - - // 选择最多maxTargets个目标 - for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) { - targets.push(enemyPositions[i]); - } - - // 如果没有找到敌人,使用默认位置 - if (targets.length === 0) { - targets.push(...this.sDefaultTargets(caster, heroAttrs.fac)); - } - - return targets; - } - - - - - /** - * 选择默认目标 - */ - private sDefaultTargets(caster: HeroViewComp, fac: number): Vec3[] { - const targets: Vec3[] = []; - const defaultX = fac === 0 ? GameConst.Battle.DEFAULT_TARGET_X_RIGHT : GameConst.Battle.DEFAULT_TARGET_X_LEFT; - targets.push(v3(defaultX, BoxSet.GAME_LINE, GameConst.Battle.DEFAULT_TARGET_Z)); - return targets; - } - - /** - * 查找附近的敌人 - */ - private findNearbyEnemies(caster: HeroViewComp, fac: number, range: number): Vec3[] { - const enemies: Vec3[] = []; - if (!caster || !caster.node) return enemies; - const currentPos = caster.node.position; - const results: { pos: Vec3; dist: number; laneBias: number }[] = []; - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!model || !view || !view.node) return false; - if (model.is_dead) return false; - if (model.fac === fac) return false; - const pos = view.node.position.clone(); - pos.y += GameConst.Battle.SEARCH_Y_OFFSET; - const dist = Math.abs(currentPos.x - pos.x); - if (dist <= range) { - const laneBias = Math.abs(currentPos.y - pos.y); - results.push({ pos: pos, dist, laneBias }); - } - return false; - }); - results.sort((a, b) => { - if (a.laneBias !== b.laneBias) return a.laneBias - b.laneBias; - return a.dist - b.dist; - }); - for (const r of results) enemies.push(r.pos); - return enemies; - } - - - /** - * 检查技能攻击范围内是否有敌人 - */ - private hasEnemyInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean { - if (!heroView || !heroView.node) return false; - - const currentPos = heroView.node.position; - const team = heroAttrs.fac; - - let found = false; - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!view || !view.node) return false; - const distance = Math.abs(currentPos.x - view.node.position.x); - if (model.fac !== team && !model.is_dead) { - if (distance <= skillDistance) { - found = true; - return true; - } - } - }); - return found; - } - - /** - * 检查技能范围内是否有友军 - */ - private hasTeamInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean { - if (!heroView || !heroView.node) return false; - - const currentPos = heroView.node.position; - const team = heroAttrs.fac; - - let found = false; - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!view || !view.node) return false; - const distance = Math.abs(currentPos.x - view.node.position.x); - if (model.fac === team && !model.is_dead) { - if (distance <= skillDistance) { - found = true; - return true; - } - } - }); - return found; - } - - /** - * 检查Buff技能是否有目标 - */ - private hasBuffTarget(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number, tGroup: TGroup): boolean { - if (tGroup === TGroup.Self) return true; // 自身Buff总是可以释放 - - // 如果是团队Buff,检查范围内是否有队友 - if (tGroup === TGroup.Team || tGroup === TGroup.Ally) { - return this.hasTeamInSkillRange(heroView, heroAttrs, skillDistance); - } - - return false; - } - - /** - * 执行Buff技能 - */ - private executeBuffSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { - const hAttrsCom = casterEntity.get(HeroAttrsComp); - const config = SkillSet[s_uuid]; - if (!config || !config.buffs || config.buffs.length === 0) return false; - - const targets = this.sBuffTargets(casterEntity, heroView, hAttrsCom, config); - if (targets.length === 0) return false; - - const delay = GameConst.Battle.SKILL_CAST_DELAY; - - heroView.scheduleOnce(() => { - for (const targetEntity of targets) { - const targetAttrs = targetEntity.get(HeroAttrsComp); - if (!targetAttrs) continue; - - // 应用所有配置的Buff - for (const buffConf of config.buffs) { - // 检查概率 - if (buffConf.chance >= 1 || Math.random() < buffConf.chance) { - targetAttrs.addBuff(buffConf); - mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] Buff生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, Buff类型=${buffConf.buff}, 值=${buffConf.value}`); - } - } - } - }, delay); - - return true; - } - - /** - * 选择Buff目标 - */ - private sBuffTargets(casterEntity: ecs.Entity, casterView: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { - const targets: ecs.Entity[] = []; - const tGroup = config.TGroup; - - // 1. 自身 - if (tGroup === TGroup.Self) { - targets.push(casterEntity); - return targets; - } - - // 2. 团队/友军 - if (tGroup === TGroup.Team || tGroup === TGroup.Ally) { - const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); - const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!model || !view || !view.node) return; - if (model.fac !== heroAttrs.fac) return; // 必须是同阵营 - if (model.is_dead) return; - - const distance = Math.abs(casterView.node.position.x - view.node.position.x); - if (distance <= range) { - targets.push(e); - } - }); - - return targets.slice(0, maxTargets); - } - - return targets; - } - - /** - * 执行治疗技能 - */ - private executeHealSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { - const hAttrsCom = casterEntity.get(HeroAttrsComp); - const config = SkillSet[s_uuid]; - if (!config) return false; - - const targets = this.sHealTargets(heroView, hAttrsCom, config); - if (targets.length === 0) return false; - - const healAmount = config.ap * hAttrsCom.Attrs[Attrs.HP_MAX]/100; - const delay = GameConst.Battle.SKILL_CAST_DELAY; - - heroView.scheduleOnce(() => { - for (const targetEntity of targets) { - const targetAttrs = targetEntity.get(HeroAttrsComp); - const targetView = targetEntity.get(HeroViewComp); - if (!targetAttrs || !targetView) continue; - - targetAttrs.add_hp(healAmount, true); - targetView.health(healAmount); - mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] 治疗生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, 治疗量=${healAmount}`); - } - }, delay); - - return true; - } - - /** - * 执行护盾技能 - */ - private executeShieldSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { - const hAttrsCom = casterEntity.get(HeroAttrsComp); - const config = SkillSet[s_uuid]; - if (!config) return false; - - const targets = this.sShieldTargets(heroView, hAttrsCom, config); - if (targets.length === 0) return false; - - const shieldAmount = config.ap * hAttrsCom.Attrs[Attrs.HP_MAX]/100; - const delay = GameConst.Battle.SKILL_CAST_DELAY; - - heroView.scheduleOnce(() => { - for (const targetEntity of targets) { - const targetAttrs = targetEntity.get(HeroAttrsComp); - const targetView = targetEntity.get(HeroViewComp); - if (!targetAttrs || !targetView) continue; - - targetAttrs.add_shield(shieldAmount, true); - targetView.add_shield(shieldAmount); - mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] 护盾生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, 护盾量=${shieldAmount}`); - } - }, delay); - - return true; - } - - /** - * 选择治疗目标 - */ - private sHealTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { - const targets: ecs.Entity[] = []; - const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); - const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!model || !view || !view.node) return; - if (model.fac !== heroAttrs.fac) return; - if (model.is_dead) return; - - const distance = Math.abs(caster.node.position.x - view.node.position.x); - if (distance <= range) { - targets.push(e); - } - }); - - targets.sort((a, b) => { - const attrsA = a.get(HeroAttrsComp); - const attrsB = b.get(HeroAttrsComp); - if (!attrsA || !attrsB) return 0; - return attrsA.hp - attrsB.hp; - }); - - return targets.slice(0, maxTargets); - } - - /** - * 选择护盾目标 - */ - private sShieldTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { - const targets: ecs.Entity[] = []; - const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); - const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (!model || !view || !view.node) return; - if (model.fac !== heroAttrs.fac) return; - if (model.is_dead) return; - - const distance = Math.abs(caster.node.position.x - view.node.position.x); - if (distance <= range) { - targets.push(e); - } - }); - - return targets.slice(0, maxTargets); - } - - /** - * 根据位置查找实体 - */ - private findEntityAtPosition(pos: Vec3): ecs.Entity | null { - let foundEntity: ecs.Entity | null = null; - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { - const view = e.get(HeroViewComp); - if (!view || !view.node) return false; - const distance = Vec3.distance(pos, view.node.position); - if (distance < 50) { - foundEntity = e; - return true; - } - return false; - }); - return foundEntity; - } - -} \ No newline at end of file diff --git a/assets/script/game/hero/SCDSystem.ts b/assets/script/game/hero/SCDSystem.ts deleted file mode 100644 index d65d2e33..00000000 --- a/assets/script/game/hero/SCDSystem.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { smc } from "../common/SingletonModuleComp"; -import { HeroAttrsComp } from "./HeroAttrsComp"; -import { HeroSkillsComp } from "./HeroSkills"; - -/** - * ==================== 技能CD更新系统 ==================== - * - * 职责: - * 1. 每帧更新所有角色的技能CD - * 2. 自动递减CD时间 - * 3. 管理技能冷却状态 - * 4. 优化CD计算性能 - * - * 设计理念: - * - 独立的CD管理系统 - * - 只负责时间递减,不处理施法逻辑 - * - 支持CD加速和减免效果 - */ -@ecs.register('SkillCDSystem') -export class SkillCDSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { - - filter(): ecs.IMatcher { - return ecs.allOf(HeroSkillsComp); - } - - update(e: ecs.Entity): void { - if(!smc.mission.play ) return; - if(smc.mission.pause) return - const skills = e.get(HeroSkillsComp); - if (!skills) return; - const attrsCom = e.get(HeroAttrsComp); - if (!attrsCom) return; - if(smc.mission.stop_mon_action) return; - if (attrsCom.isStun() || attrsCom.isFrost()) { // 眩晕和冰冻状态不更新CD - return; - } - // 更新所有技能CD - skills.updateCDs(this.dt); - } - - /** - * 计算CD减免效果 - */ - - - /** - * 更新技能就绪状态 - */ - -} diff --git a/assets/script/game/hero/TalComp.ts b/assets/script/game/hero/TalComp.ts deleted file mode 100644 index 58280aac..00000000 --- a/assets/script/game/hero/TalComp.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { _decorator } from "cc"; -import { mLogger } from "../common/Logger"; -import { basename } from "path/win32"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; -import { GameEvent } from "../common/config/GameEvent"; -import { Attrs, BType } from "../common/config/HeroAttrs"; -import { BuffConf } from "../common/config/SkillSet"; -import { TalAttrs, talConf, TalEffet, TalTarget, TriType} from "../common/config/TalSet"; -import { HeroAttrsComp } from "./HeroAttrsComp"; -import { HeroViewComp } from "./HeroViewComp"; -import { ITalPts } from "../common/config/heroSet"; - -const { property } = _decorator; - -/** - * 天赋槽位接口定义 - * 描述单个天赋的数据结构 - */ -export interface TalSlot { - uuid: number; // 天赋唯一标识符 - name: string; // 天赋名称 - triType: TriType; // 天赋触发类型 - target: TalTarget; - effet: TalEffet; - attrs?:TalAttrs //触发的attrs效果的对应attrs value: number; // 触发的效果数值 - vType:BType; // 数值型还是百分比型 - value: number; // 触发的效果数值 - value_add: number; // 触发的效果数值增量 - count: number; // 执行次数,及可以触发的次数 - count_add: number; // 执行次数增量 - Trigger: number; // 天赋触发阈值 - Trigger_add: number; // 天赋触发阈值减值 - desc: string; // 天赋描述(说明触发条件和效果) - cur: number; // 当前累积值 -} -/** - * 天赋系统组件类 - * 作为ECS架构中的组件,负责管理英雄的天赋系统 - * - * 核心功能: - * - 初始化英雄天赋系统 - * - 添加新天赋到英雄 - * - 累积天赋触发进度 - * - 检查并触发满足条件的天赋 - * - 管理天赋效果数值 - */ -@ecs.register('TalComp', true) -export class TalComp extends ecs.Comp { - @property({ tooltip: "是否启用调试日志" }) - private debugMode: boolean = false; - - /** 天赋集合,以天赋ID为键,存储所有已获得的天赋 */ - Tals: Record = {}; - TalPts:Record = {}; - init(heroUuid: number) { - // 初始化天赋集合 - this.Tals = {}; - this.TalPts = {}; - // 监听升级事件 - oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this); - // 监听天赋选择事件 - oops.message.on(GameEvent.UseTalentCard, this.onUseTalentCard, this); - } - - onDestroy() { - oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this); - oops.message.off(GameEvent.UseTalentCard, this.onUseTalentCard, this); - } - - /** - * 处理天赋选择事件 - * @param event 事件名 - * @param args 天赋UUID - */ - private onUseTalentCard(event: string, args: any) { - const uuid = args as number; - mLogger.log(this.debugMode, 'TalComp', `[TalComp] 收到天赋选择事件,添加天赋 ID: ${uuid}`); - this.addTal(uuid); - } - - /** - * 处理英雄升级事件,触发升级类型的天赋 - */ - private onLevelUp(event: string, args: any) { - // 只有当前实体是主角时才处理(虽然TalComp只挂载在主角上,但为了安全起见可以再确认,或者直接处理) - // GameEvent.CanUpdateLv 事件参数 { lv: number } - - mLogger.log(this.debugMode, 'TalComp', `[TalComp] 监听到升级事件,当前等级: ${args.lv}`); - - } - - /** - * 为英雄添加一个新天赋 - * @param uuid 要添加的天赋ID - * - * 添加流程: - * 1. 检查天赋是否已存在 - * 2. 检查天赋配置是否存在 - * 3. 创建并初始化天赋数据 - */ - addTal(uuid: number,v_add:number = 0,c_add:number = 0,t_add:number = 0) { - // 检查天赋是否已存在 - if (this.Tals[uuid]) { - mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋已存在,执行叠加逻辑 ID:${uuid}`); - const tConf = talConf[uuid]; - if (tConf) { - // 叠加效果数值 - this.Tals[uuid].value_add += tConf.value; - } - return; - } - - // 获取天赋配置 - const tConf = talConf[uuid]; - if (!tConf) { - mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋配置不存在,天赋ID:${uuid}`); - return; - } - - // 创建并初始化天赋数据 - this.Tals[uuid] = { - uuid: uuid, - name: tConf.name, - triType: tConf.triType, - target: tConf.target, - effet: tConf.effet, - attrs: tConf.attrs, - vType: tConf.vType, - value: tConf.value, // 效果数值初始为配置值 - value_add: v_add, // 效果数值增量初始为0 - count: tConf.count, // 执行次数,及可以触发的次数 - count_add: c_add, // 执行次数增量初始为0 - Trigger: tConf.Trigger, // 触发阈值(后续可从配置中读取) - Trigger_add: t_add, // 触发阈值增量初始为0 - desc: tConf.desc, - cur: 0, // 当前累积值初始为0 - }; - mLogger.log(this.debugMode, 'TalComp', `[TalComp]添加天赋成功,天赋ID:${uuid}`); - } - - checkTal() { - return Object.keys(this.Tals).length > 0; - } - - getTriggers() { - // 存储所有触发的天赋 - let Triggers: Record = {}; - // 遍历所有天赋 - for (let uuid in this.Tals) { - const talent = this.Tals[uuid]; - if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发 - mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋触发,天赋ID:${uuid}`); - // 重置累积值 - talent.cur = 0; - // 添加到触发列表 - Triggers[uuid] = talent; - } - } - // 判断是否有天赋被触发 - return Triggers; - } - - /** - * 更新天赋的效果数值 - * @param uuid 天赋ID - * @param val 要增减的数值 - * - * 功能: - * - 用于调整天赋的实际效果数值 - * - 可通过正负数来增加或减少效果 - */ - updateVal(uuid: number, val: number) { - // 检查天赋是否存在 - if (!this.Tals[uuid]) { - mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`); - return; - } - - // 更新天赋效果数值 - this.Tals[uuid].value_add += val; - } - - updateTrigger(uuid: number, val: number) { - // 检查天赋是否存在 - if (!this.Tals[uuid]) { - mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`); - return; - } - - // 更新天赋触发阈值 - this.Tals[uuid].Trigger_add += val; - if (this.Tals[uuid].Trigger-this.Tals[uuid].Trigger_add <= 1) { - this.Tals[uuid].Trigger_add = this.Tals[uuid].Trigger-1; - } - } - /** - * 更新指定类型天赋的累积值 - * @param triType 天赋触发类型 - * @param val 要增加的累积值,默认值为1 - * - * 设计注意: - * - 当前实现只会更新第一个匹配类型的天赋 - * - 累积值用于后续判断是否触发天赋效果 - */ - updateCur(triType: TriType, val: number = 1) { - // 遍历所有天赋 - for (let uuid in this.Tals) { - const talent = this.Tals[uuid]; - - // 找到所有匹配类型的天赋并更新 - if (talent.triType == triType) { - talent.cur += val; - this.checkTrigger(talent.uuid); - } - } - } - checkTrigger(uuid:number){ - const talent = this.Tals[uuid]; - if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发 - mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋触发,天赋ID:${uuid}`); - for(let i=0;i<(talent.count+talent.count_add);i++){ - this.doTriggerTal(talent.uuid); - } - // 重置累积值 - talent.cur = 0; - - } - } - //执行天赋触发效果 - // 功能: - // - 根据天赋类型执行相应的效果 - // - 支持计数型和数值型天赋 - // --heroAttrs.addTalent 是计数型天赋buff heroAttrs.addTalBuff 是数值型天赋buff - doTriggerTal(uuid: number) { - // 检查天赋是否存在 - if (!this.Tals[uuid]) { - mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`); - return; - } - const talent = this.Tals[uuid]; - const heroAttrs=this.ent.get(HeroAttrsComp); - switch(talent.effet){ - case TalEffet.ATK_DMG: - heroAttrs.addCountTal(TalEffet.ATK_DMG, talent.value + talent.value_add); - break; - case TalEffet.SKILL_DMG: - heroAttrs.addCountTal(TalEffet.SKILL_DMG, talent.value + talent.value_add); - break; - case TalEffet.DEF: - heroAttrs.addCountTal(TalEffet.DEF, talent.value + talent.value_add); - break; - case TalEffet.HP: - heroAttrs.add_hp(talent.value + talent.value_add,talent.vType == BType.VALUE); - break; - case TalEffet.WFUNY: - heroAttrs.addCountTal(TalEffet.WFUNY, talent.value + talent.value_add); - break; - case TalEffet.D_SKILL: - heroAttrs.addCountTal(TalEffet.D_SKILL, talent.value + talent.value_add); - break; - case TalEffet.C_ATK: - heroAttrs.addCountTal(TalEffet.C_ATK, talent.value + talent.value_add); - break; - case TalEffet.C_SKILL: - heroAttrs.addCountTal(TalEffet.C_SKILL, talent.value + talent.value_add); - break; - case TalEffet.C_MSKILL: - heroAttrs.addCountTal(TalEffet.C_MSKILL, talent.value + talent.value_add); - break; - case TalEffet.BUFF: //临时buff - heroAttrs.addValueTal(talent.uuid, talent.attrs, talent.vType, talent.value + talent.value_add); - break; - case TalEffet.ATTR: //永久属性 - // 修正:强制类型转换为 number (Attrs 是数字枚举) - let attrIndex = talent.attrs as unknown as number; - // 如果 TalAttrs 存在且需要映射,请取消注释下一行 - // attrIndex = Attrs[TalAttrs[talent.attrs]]; - - let b:BuffConf={buff:attrIndex, BType:talent.vType, value:talent.value + talent.value_add, time:0, chance:100 } - heroAttrs.addBuff(b); - break; - } - } - /** - * 重置组件状态 - */ - reset() { - oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this); - oops.message.off(GameEvent.UseTalentCard, this.onUseTalentCard, this); - this.Tals = {}; - } - - - -} \ No newline at end of file