Files
pixelheros/assets/script/game/map/TalentItemComp.ts
panFD 707e25e73f refactor: 重构天赋系统与技能触发逻辑
1.  重构天赋系统架构:将天赋加成与触发修正统一收敛到 HeroAttrsComp.applyTalent
2.  新增天赋触发修正字段:talent_t_num_reduce 与 talent_extra_trigger_chance
3.  重构天赋加点逻辑:统一 1 点/级,新增软前置校验
4.  优化天赋UI组件:改为编辑器静态配置驱动,重构层位展示逻辑
5.  修复技能触发判定:在 SkillTriggerHelper 中应用天赋触发修正
6.  调整天赋配置结构:改为 5 层递进解锁,新增 L4/L5 专属触发修正配置
2026-09-19 11:20:55 +08:00

132 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file TalentItemComp.ts
* @description 天赋迷你升级卡组件(UI 视图层,编辑器静态摆放)
*
* 职责:
* 1. 通过编辑器配置的 uuid 自查询天赋配置 + 当前等级 + 层位解锁态,渲染迷你点选卡。
* 2. 卡面自包含:图标 / 名称 / 当前已生效数值(Lv0 显示每级数值引导)/ 右下「当前/满级」角标。
* 3. 层位背景:普通背景节点下挂 blue / red / yellow 三个颜色子节点,按层位映射激活其一(L1蓝 / L2红 / L3金,L4/L5 复用金)。
* 4. 状态机:满级(MAX 金角标)/ 未激活(左上锁角标:未加点 / 层位未解锁 / 前置未满足,不做灰阶处理)。
* 5. 点击回调上抛卡体点击,加点确认弹窗与升级校验统一由 TalentsComp 处理(单一决策点)。
*
* 依赖:
* - TalentSet(TalentConfig/TalentTier/getTalentDisplayText/isTalentTierUnlocked/isTalentPrereqMet)—— 配置与校验
* - 背景三颜色子节点(blue / red / yellow,编辑器侧搭建)
* - smc —— 天赋等级表与图标图集(缺省回退资源目录)
*/
import { _decorator, CCInteger, Label, Node, NodeEventType, Sprite, SpriteFrame } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { TalentSet, TalentTier, getTalentDisplayText, isTalentPrereqMet, isTalentTierUnlocked } from "../common/config/TalentSet";
import { smc } from "../common/SingletonModuleComp";
import { oops } from "db://oops-framework/core/Oops";
const { ccclass, property } = _decorator;
/** 层位 → 背景节点下的颜色子节点名(L1蓝 / L2红 / L3金;L4/L5 复用金) */
const TIER_BG_CHILD_NAMES: Record<number, string> = {
[TalentTier.L1]: "blue",
[TalentTier.L2]: "red",
[TalentTier.L3]: "yellow",
[TalentTier.L4]: "yellow",
[TalentTier.L5]: "yellow",
};
/** TalentItemComp —— 天赋迷你升级卡组件(编辑器静态摆放,按 uuid 自驱动渲染) */
@ccclass('TalentItemComp')
@ecs.register('TalentItem', false)
export class TalentItemComp extends CCComp {
@property({ type: CCInteger, tooltip: "天赋 uuid(TalentSet key,编辑器侧配置)" })
talent_uuid: number = 0;
@property({ type: Label, tooltip: "天赋名称" })
lbl_name: Label = null!;
@property({ type: Label, tooltip: "当前已生效数值(Lv0 显示每级引导)" })
lbl_info: Label = null!;
@property({ type: Label, tooltip: "等级角标(当前/满级)" })
lbl_lv: Label = null!;
@property({ type: Sprite, tooltip: "天赋图标" })
icon: Sprite = null!;
@property({ type: Node, tooltip: "卡牌背景节点(下挂 blue / red / yellow 三颜色子节点,按层位激活其一)" })
bg: Node = null!;
@property({ type: Node, tooltip: "MAX 满级角标" })
node_max: Node = null!;
@property({ type: Node, tooltip: "未激活锁遮罩/锁图标(未加点、层位未解锁或前置未满足)" })
node_lock: Node = null!;
/** 点击回调(卡体点击上抛),由 TalentsComp 统一校验升级 */
public onTalentTap: ((uuid: number) => void) | null = null;
protected onLoad(): void {
this.node.on(NodeEventType.TOUCH_END, this.onTap, this);
}
protected onDestroy(): void {
this.node.off(NodeEventType.TOUCH_END, this.onTap, this);
}
/** 刷新迷你卡展示:按编辑器配置的 uuid 自查询配置与等级,层位/前置校验内部完成 */
public updateItem(): void {
const cfg = TalentSet[this.talent_uuid];
if (!cfg) return;
const levels = smc.getTalentLevels();
const lv = levels[this.talent_uuid] ?? 0;
const tierUnlocked = isTalentTierUnlocked(levels, cfg.tier);
const prereqMet = isTalentPrereqMet(levels, cfg);
if (this.lbl_name) this.lbl_name.string = cfg.name;
// 卡面自包含:已加点显示当前生效数值,未加点显示每级数值引导
if (this.lbl_info) this.lbl_info.string = getTalentDisplayText(cfg, lv);
if (this.lbl_lv) this.lbl_lv.string = `${lv}/${cfg.max_lv}`;
// 未激活(Lv0 / 层位未解锁 / 前置未满足):仅显示 node_lock 锁遮罩,不做灰阶处理
const inactive = lv <= 0 || !tierUnlocked || !prereqMet;
// 层位背景:激活对应颜色子节点(L1蓝 / L2红 / L3金)
if (this.bg) this.applyTierBg(cfg.tier);
// 图标:技能图标图集(gui/ui7)优先,资源目录回退(与 SCardComp 口径一致)
if (this.icon && cfg.icon) {
let frame: SpriteFrame | null = null;
if (smc.skillIconsAtlas) {
frame = smc.skillIconsAtlas.getSpriteFrame(cfg.icon);
}
if (!frame) {
frame = oops.res.get("game/heros/cards/" + cfg.icon, SpriteFrame) as SpriteFrame;
}
if (frame) this.icon.spriteFrame = frame;
}
// 状态角标:满级 MAX / 未激活锁角标(置于左上角)
if (this.node_max) this.node_max.active = lv >= cfg.max_lv;
if (this.node_lock) this.node_lock.active = inactive;
}
/** 按层位激活 bg 下对应颜色子节点,其余隐藏 */
private applyTierBg(tier: TalentTier): void {
const curName = TIER_BG_CHILD_NAMES[tier];
for (const [, name] of Object.entries(TIER_BG_CHILD_NAMES)) {
const child = this.bg.getChildByName(name);
if (!child) continue;
child.active = name === curName;
}
}
/** 卡体点击上抛 uuid,加点确认与升级校验由 TalentsComp 处理 */
private onTap(): void {
this.onTalentTap?.(this.talent_uuid);
}
/** ECS 组件移除时销毁节点(CCComp 抽象方法实现) */
reset() {
this.node.destroy();
}
}