feat: 实现药水卡限时强化功能,支持自定义数值覆写

1. 新增Buff数值覆写机制,支持药水卡自定义buff效果数值
2. 重构属性计算逻辑,支持读取药水卡传递的覆写值
3. 新增多组限时强化Buff与药水卡配置
4. 优化UI数值显示,实时展示最终属性值
5. 新增多维度调试日志方便排查问题
This commit is contained in:
panFD
2026-07-23 23:00:49 +08:00
parent 2876108970
commit ac0891ccdd
12 changed files with 205 additions and 50 deletions

View File

@@ -74,4 +74,76 @@ export const BuffList: Record<number, BuffConfig> = {
is_control: true, control_kind: 'stun',
info: "击晕目标,无法行动",
},
// ==================== 玩家计时性强化(药水/技能用,默认 5s ====================
// 计时性回血HoT
7010: {
id: 7010, name: "再生", icon: "Stat_PotionBoost",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
tick: { interval: 0.5, damage_or_heal: 10, scale_by_ap_pct: 0 },
info: "每秒回复生命,持续 5 秒",
},
// 攻击强化(限时)
7011: {
id: 7011, name: "攻击爆发", icon: "Stat_Attack_03",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.ap, op: ModOp.PercentAdd, value: 50 }],
info: "攻击力提升 50%,持续 5 秒",
},
// 暴击强化(限时)
7012: {
id: 7012, name: "暴击爆发", icon: "Stat_CriticalChance_02",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.critical, op: ModOp.Flat, value: 30 }],
info: "暴击率提升 30%,持续 5 秒",
},
// 击退概率强化(限时)
7013: {
id: 7013, name: "击退爆发", icon: "Stat_Stun_01",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.knockback_chance, op: ModOp.Flat, value: 30 }],
info: "击退概率提升 30%,持续 5 秒",
},
// 穿透强化(限时)
7014: {
id: 7014, name: "穿透爆发", icon: "Stat_Tripleshot",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.puncture_chance, op: ModOp.Flat, value: 30 }],
info: "穿透概率提升 30%,持续 5 秒",
},
// 攻速强化(限时,走 getEffectiveSkillCd 计时修饰)
7015: {
id: 7015, name: "攻速爆发", icon: "Stat_AttackSpeed_02",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.speed, op: ModOp.Flat, value: 40 }],
info: "攻击速度提升 40%,持续 5 秒",
},
// 风怒强化(限时,按概率百分点)
7016: {
id: 7016, name: "风怒爆发", icon: "Stat_CriticalComboChance",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.wfuny, op: ModOp.Flat, value: 20 }],
info: "风怒概率提升 20%,持续 5 秒",
},
// 击晕概率强化(限时)
7017: {
id: 7017, name: "击晕爆发", icon: "Stat_Stun_01",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.stun_chance, op: ModOp.Flat, value: 30 }],
info: "击晕概率提升 30%,持续 5 秒",
},
// 击晕抗性强化(限时)
7018: {
id: 7018, name: "击晕抗性", icon: "Stat_Armor_01",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.stun_res, op: ModOp.Flat, value: 50 }],
info: "击晕抗性提升 50%,持续 5 秒",
},
// 冰冻抗性强化(限时)
7019: {
id: 7019, name: "冰冻抗性", icon: "Stat_Freeze",
category: BuffCategory.Buff, duration: 5, max_stack: 1,
modifiers: [{ attr: Attrs.freeze_res, op: ModOp.Flat, value: 50 }],
info: "冰冻抗性提升 50%,持续 5 秒",
},
};

View File

@@ -31,30 +31,25 @@ interface ItemCardRaw {
}
const ItemCardData: ItemCardRaw[] = [
// ==================== 基础恢复类 ====================
{ uuid: 9101, skill: 6302, name: "治疗药水", info: "恢复全体友方 300 点生命", cost: 3, weight: 20 },
{ uuid: 9102, skill: 6301, name: "护盾药水", info: "为全体友方添加护盾,可抵挡 3 次伤害", cost: 4, weight: 15 },
{ uuid: 9103, skill: 6303, name: "金币袋", info: "立即获得 5 金币", cost: 2, weight: 15, overrides: { gold: 5 } },
// ==================== 一次性回血(计时性 HoT5s ====================
{ uuid: 9101, skill: 6502, name: "再生药水", info: "全体友方每秒回复生命,持续 5 秒", cost: 0, weight: 20 },
// ==================== 性强化类(单次触发 ====================
{ uuid: 9111, skill: 6401, name: "攻击药", info: "全体友方攻击力提升 5", cost: 3, weight: 12 },
{ uuid: 9112, skill: 6402, name: "生命药剂", info: "全体友方最大生命值提升 20 点", cost: 3, weight: 12 },
{ uuid: 9113, skill: 6403, name: "暴击药剂", info: "全体友方击率提升 10%", cost: 3, weight: 12 },
{ uuid: 9114, skill: 6404, name: "暴伤药剂", info: "全体友方暴击伤害提升 20%", cost: 3, weight: 12 },
{ uuid: 9115, skill: 6405, name: "击晕药剂", info: "全体友方击晕概率提升 10%", cost: 3, weight: 12 },
{ uuid: 9116, skill: 6408, name: "穿刺药剂", info: "全体友方穿透概率提升 20%", cost: 3, weight: 12 },
{ uuid: 9117, skill: 6409, name: "风怒药剂", info: "全体友方风怒次数提升 1 次", cost: 3, weight: 12 },
// ==================== 计时性强化(统一 5s ====================
{ uuid: 9102, skill: 6503, name: "攻击药", info: "全体友方攻击力提升 50%,持续 5 秒", cost: 0, weight: 15 },
{ uuid: 9103, skill: 6504, name: "暴击药水", info: "全体友方暴击率提升 30%,持续 5 秒", cost: 0, weight: 15 },
{ uuid: 9104, skill: 6505, name: "击退药水", info: "全体友方击退概率提升 30%,持续 5 秒", cost: 0, weight: 12 },
{ uuid: 9105, skill: 6506, name: "穿透药水", info: "全体友方穿透概率提升 30%,持续 5 秒", cost: 0, weight: 12 },
{ uuid: 9106, skill: 6507, name: "攻速药水", info: "全体友方攻击速度提升 40%,持续 5 秒", cost: 0, weight: 15 },
{ uuid: 9107, skill: 6508, name: "风怒药水", info: "全体友方风怒概率提升 20%,持续 5 秒", cost: 0, weight: 12 },
{ uuid: 9108, skill: 6509, name: "击晕药水", info: "全体友方击晕概率提升 30%,持续 5 秒", cost: 0, weight: 12 },
{ uuid: 9109, skill: 6510, name: "击晕抗性药水", info: "全体友方击晕抗性提升 50%,持续 5 秒", cost: 4, weight: 10 },
{ uuid: 9110, skill: 6511, name: "冰冻抗性药水", info: "全体友方冰冻抗性提升 50%,持续 5 秒", cost: 4, weight: 10 },
// ==================== 高级恢复类 ====================
{ uuid: 9201, skill: 6302, name: "高级治疗药水", info: "恢复全体友方 600 点生命", cost: 6, weight: 8, overrides: { ap: 600 } },
{ uuid: 9202, skill: 6301, name: "高级护盾药水", info: "全体友方添加护盾,可抵挡 6 次伤害", cost: 8, weight: 6, overrides: { ap: 6 } },
{ uuid: 9203, skill: 6303, name: "大金币袋", info: "立即获得 12 金币", cost: 5, weight: 6, overrides: { gold: 12 } },
// ==================== 高级属性强化类 ====================
{ uuid: 9211, skill: 6401, name: "高级攻击药剂", info: "全体友方攻击力提升 10 点", cost: 6, weight: 5, overrides: { ap: 10 } },
{ uuid: 9212, skill: 6402, name: "高级生命药剂", info: "全体友方最大生命值提升 40 点", cost: 6, weight: 5, overrides: { ap: 40 } },
{ uuid: 9213, skill: 6403, name: "高级暴击药剂", info: "全体友方暴击率提升 20%", cost: 6, weight: 5, overrides: { ap: 2 } },
{ uuid: 9214, skill: 6404, name: "高级暴伤药剂", info: "全体友方暴击伤害提升 40%", cost: 6, weight: 5, overrides: { ap: 2 } },
// ==================== 高级buff_value 覆写,复用同一技能底座) ====================
{ uuid: 9201, skill: 6502, name: "高级再生药水", info: "全体友方每秒回复 25 生命,持续 5 秒", cost: 0, weight: 8, overrides: { buff_value: 25 } },
{ uuid: 9202, skill: 6503, name: "高级攻击药水", info: "全体友方攻击力提升 80%,持续 5 秒", cost: 0, weight: 8, overrides: { buff_value: 80 } },
{ uuid: 9203, skill: 6504, name: "高级暴击药水", info: "全体友方暴击率提升 50%,持续 5 秒", cost: 0, weight: 8, overrides: { buff_value: 50 } },
{ uuid: 9206, skill: 6507, name: "高级攻速药水", info: "全体友方攻击速度提升 70%,持续 5 秒", cost: 0, weight: 8, overrides: { buff_value: 70 } },
];
/**

View File

@@ -155,6 +155,7 @@ export interface SkillConfig {
bck?: number, // 额外击退概率
buff_type?: Attrs, // Buff 类型 (单一职责)
timed_buff_id?: number, // 计时性 buff 配置 id指向 BuffList存在时走 buffManager 而非永久 add_*
buff_value?: number, // 覆写计时 buff 的修饰数值modifiers.value / tick.damage_or_heal由药水卡自定义档位
call_hero?: number, // 召唤技能召唤英雄id(可选)
is_accel?: boolean, // 是否逐渐加速飞行
info: string, // 技能描述
@@ -172,6 +173,7 @@ export interface SkillOverrides {
bck?: number;
buff_type?: Attrs;
timed_buff_id?: number;
buff_value?: number;
call_hero?: number;
is_accel?: boolean;
}
@@ -377,6 +379,59 @@ export const SkillSet: Record<number, SkillConfig> = {
uuid: 6501, name: "复活", sp_name: "buff_wind", icon: "Stat_HolyDamage", TGroup: TGroup.Self, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 50, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, info: "ap 代表复活的生命值百分比",
},
// ==================== 计时性强化技能(药水底座,统一 5s走 timed_buff_id ====================
// 注ap 字段在此类技能中无意义,修饰数值由 BuffList 配置hit_count=99 确保覆盖全队。
6502: {
uuid: 6502, name: "计时回血", sp_name: "buff_wind", icon: "Stat_PotionBoost", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp, timed_buff_id: 7010, info: "全体友方每秒回复生命持续5秒",
},
6503: {
uuid: 6503, name: "攻击爆发", sp_name: "buff_wind", icon: "Stat_Attack_03", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.ap, timed_buff_id: 7011, info: "全体友方攻击力提升50%持续5秒",
},
6504: {
uuid: 6504, name: "暴击爆发", sp_name: "buff_wind", icon: "Stat_CriticalChance_02", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.critical, timed_buff_id: 7012, info: "全体友方暴击率提升30%持续5秒",
},
6505: {
uuid: 6505, name: "击退爆发", sp_name: "buff_wind", icon: "Stat_Stun_01", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.knockback_chance, timed_buff_id: 7013, info: "全体友方击退概率提升30%持续5秒",
},
6506: {
uuid: 6506, name: "穿透爆发", sp_name: "buff_wind", icon: "Stat_Tripleshot", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.puncture_chance, timed_buff_id: 7014, info: "全体友方穿透概率提升30%持续5秒",
},
6507: {
uuid: 6507, name: "攻速爆发", sp_name: "buff_wind", icon: "Stat_AttackSpeed_02", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.speed, timed_buff_id: 7015, info: "全体友方攻击速度提升40%持续5秒",
},
6508: {
uuid: 6508, name: "风怒爆发", sp_name: "buff_wind", icon: "Stat_CriticalComboChance", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.wfuny, timed_buff_id: 7016, info: "全体友方风怒概率提升20%持续5秒",
},
6509: {
uuid: 6509, name: "击晕爆发", sp_name: "buff_wind", icon: "Stat_Stun_01", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.stun_chance, timed_buff_id: 7017, info: "全体友方击晕概率提升30%持续5秒",
},
6510: {
uuid: 6510, name: "击晕抗性", sp_name: "buff_wind", icon: "Stat_Armor_01", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.stun_res, timed_buff_id: 7018, info: "全体友方击晕抗性提升50%持续5秒",
},
6511: {
uuid: 6511, name: "冰冻抗性", sp_name: "buff_wind", icon: "Stat_Freeze", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 99, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.freeze_res, timed_buff_id: 7019, info: "全体友方冰冻抗性提升50%持续5秒",
}
};

View File

@@ -15,12 +15,15 @@ export class ActiveBuff {
source_ap_snapshot: number;
/** 周期效果累计时间(秒) */
tick_acc: number = 0;
/** 修饰数值覆写(来自药水卡 buff_value优先于 BuffList 配置值undefined 表示用配置值 */
value_override?: number;
constructor(cfg_id: number, dur: number, src_uuid: number, src_ap: number) {
constructor(cfg_id: number, dur: number, src_uuid: number, src_ap: number, value_override?: number) {
this.config_id = cfg_id;
this.remaining = dur;
this.source_uuid = src_uuid;
this.source_ap_snapshot = src_ap;
this.value_override = value_override;
}
}

View File

@@ -12,9 +12,11 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
import { BuffCategory, BuffList } from "../common/config/BuffSet";
import { BuffComp, ActiveBuff } from "./BuffComp";
/** applyBuff 的覆盖参数(预留按需覆写持续时间) */
/** applyBuff 的覆盖参数(预留按需覆写持续时间 / 修饰数值 */
export interface BuffApplyOverrides {
duration?: number;
/** 覆写计时 buff 的修饰数值modifiers.value / tick.damage_or_heal由药水卡 buff_value 自定义档位 */
value?: number;
}
class BuffManagerImpl {
@@ -34,7 +36,11 @@ class BuffManagerImpl {
*/
applyBuff(target: ecs.Entity, buffId: number, sourceUuid: number = 0, sourceAp: number = 0, overrides?: BuffApplyOverrides): void {
const cfg = BuffList[buffId];
if (!cfg) return;
if (!cfg) {
console.log(`[BuffManager] applyBuff: buffId=${buffId} 配置不存在,跳过`);
return;
}
console.log(`[BuffManager] applyBuff: buff=${cfg.name}(${buffId}) target_eid=${target.eid} duration=${overrides?.duration ?? cfg.duration} value_override=${overrides?.value} source_ap=${sourceAp}`);
const buffComp = this.ensureBuffComp(target);
const duration = overrides?.duration ?? cfg.duration;
@@ -45,7 +51,7 @@ class BuffManagerImpl {
buffComp.buffs.set(buffId, layers);
}
const newLayer = new ActiveBuff(buffId, duration, sourceUuid, sourceAp);
const newLayer = new ActiveBuff(buffId, duration, sourceUuid, sourceAp, overrides?.value);
if (cfg.max_stack === 0 || layers.length < cfg.max_stack) {
layers.push(newLayer);

View File

@@ -60,6 +60,7 @@ export class BuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (cfg.duration > 0 && layer.remaining <= 0) {
layers.splice(i, 1);
anyChanged = true;
console.log(`[BuffSystem] buff 到期移除: ${cfg.name}(${buffId}) eid=${e.eid} 剩余层数=${layers.length}`);
}
}
@@ -90,8 +91,10 @@ export class BuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
while (layer.tick_acc >= tick.interval) {
layer.tick_acc -= tick.interval;
// 按 ap 缩放后取整floor(dmg * (1 + ap_snapshot * scale_pct / 10000))
// damage_or_heal 优先取药水卡覆写值
const baseAmount = layer.value_override !== undefined ? layer.value_override : tick.damage_or_heal;
const scale = 1 + layer.source_ap_snapshot * tick.scale_by_ap_pct / 10000;
const amount = Math.floor(tick.damage_or_heal * scale);
const amount = Math.floor(baseAmount * scale);
attrs.add_hp(amount);
}
}

View File

@@ -351,14 +351,17 @@ export class HeroAttrsComp extends ecs.Comp {
if (!cfg || !cfg.modifiers) return;
// 每层独立贡献,模拟叠层放大效果
for (let i = 0; i < layers.length; i++) {
const layerVal = layers[i].value_override; // 药水卡覆写值优先
for (const mod of cfg.modifiers) {
if (mod.attr !== attr) continue;
const value = layerVal !== undefined ? layerVal : mod.value;
console.log(`[HeroAttrs] aggregateTimedMods 命中: ${this.hero_name} buff=${cfg.name} attr=${attr} op=${mod.op} value=${value} remaining=${layers[i].remaining.toFixed(1)}`);
if (mod.op === ModOp.Flat) {
result.flatSum += mod.value;
result.flatSum += value;
} else {
// PercentAdd 与 PercentMul 暂统一按加法百分比聚合;
// PercentMul 真正的独立乘区尚未启用TODO: 启用时需改造为多乘区连乘
result.pctSum += mod.value;
result.pctSum += value;
}
}
}
@@ -373,7 +376,11 @@ export class HeroAttrsComp extends ecs.Comp {
public getFinalAp(): number {
const runtimeAp = this.getRuntimeAp(this.ap);
const mods = this.aggregateTimedMods(Attrs.ap);
return (runtimeAp + mods.flatSum) * (1 + mods.pctSum / 100);
const final = (runtimeAp + mods.flatSum) * (1 + mods.pctSum / 100);
if (mods.flatSum !== 0 || mods.pctSum !== 0) {
console.log(`[HeroAttrs] getFinalAp: ${this.hero_name} base=${this.ap} runtime=${runtimeAp.toFixed(1)} flat=${mods.flatSum} pct=${mods.pctSum} final=${final.toFixed(1)}`);
}
return final;
}
/**
@@ -472,7 +479,9 @@ export class HeroAttrsComp extends ecs.Comp {
const skill = this.skills[skillId];
if (!skill) return 0;
if (skill.cd <= 0) return 0;
const speedBonus = this.getRuntimeAttackSpeedBonus();
// 攻速 = 驻场加成 + 计时性 buff 修饰speed 属性的 flat/pct 均按攻速百分点处理)
const timedMods = this.aggregateTimedMods(Attrs.speed);
const speedBonus = this.getRuntimeAttackSpeedBonus() + timedMods.flatSum + timedMods.pctSum;
if (speedBonus <= 0) return skill.cd;
const speedRate = 1 + speedBonus / 100;
return Math.max(HeroAttrsComp.minAttackCd, skill.cd / speedRate);

View File

@@ -142,10 +142,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
}
}
console.log("[SCastSystem] forceCastCardSkill: casting skill", s_uuid, "castTimes", castTimes, "targetPos", targetPos);
console.log("[SCastSystem] forceCastCardSkill: casting skill", s_uuid, "castTimes", castTimes, "targetPos", targetPos, "isFriendly", isFriendly, "buff_value", config.buff_value, "timed_buff_id", config.timed_buff_id);
for (let i = 0; i < castTimes; i++) {
if (isFriendly) {
const friendlyTargets = this.resolveFriendlyTargets(targetEids, FacSet.HERO);
console.log("[SCastSystem] friendlyTargets count =", friendlyTargets.length);
if (friendlyTargets.length === 0) continue;
this.applyFriendlySkillEffects(s_uuid, cardLv, config, null as any, mockAttrs, friendlyTargets, spawnPos);
} else {
@@ -455,12 +456,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
}
}
private applyActualFriendlyEffect(target: HeroViewComp, kind: SkillKind, sAp: number, _cAttrsComp: HeroAttrsComp, config: SkillConfig, sUp: any, _skillLv: number = 1) {
if (!target.ent) return;
const model = target.ent.get(HeroAttrsComp);
if (!model || model.is_dead) return;
console.log(`[SCastSystem] applyActualFriendlyEffect: skill=${config.uuid} kind=${kind} buff_type=${config.buff_type} timed_buff_id=${config.timed_buff_id} buff_value=${config.buff_value} target=${model.hero_name}`);
if (config.endAnm && config.endAnm !== "") {
target.playEnd(config.endAnm);
@@ -493,7 +493,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
target.ent,
config.timed_buff_id,
_cAttrsComp.hero_uuid,
_cAttrsComp.ap
_cAttrsComp.ap,
config.buff_value !== undefined ? { value: config.buff_value } : undefined
);
return;
}

View File

@@ -355,8 +355,9 @@ export class HInfoComp extends CCComp {
}
// ---- 数值标签 ----
// 攻击力显示最终值(含计时 buff 修饰),实时反映药水等限时强化
if (this.apLabel) {
const currentAp = Math.max(0, Math.floor(this.model.ap ?? 0));
const currentAp = Math.max(0, Math.floor(this.model.getFinalAp()));
const baseAp = Math.max(0, Math.floor(this.model.base_ap ?? 0));
this.apLabel.string = `${currentAp}`;
if (this.apPlusLabel) {
@@ -370,7 +371,7 @@ export class HInfoComp extends CCComp {
}
}
if (this.hpLabel) {
const currentHp = Math.max(0, Math.floor(this.model.hp_max ?? 0));
const currentHp = Math.max(0, Math.floor(this.model.getFinalHpMax()));
const baseHp = Math.max(0, Math.floor(this.model.base_hp ?? 0));
this.hpLabel.string = `${currentHp}`;
if (this.hpPlusLabel) {

View File

@@ -28,6 +28,7 @@ import { SBox } from "./SBox";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { BoxSet } from "../common/config/GameSet";
import { SkillOverrides } from "../common/config/SkillSet";
const { ccclass, property } = _decorator;
/** 技能槽位数据结构 */
@@ -73,6 +74,7 @@ export class MissSkillsComp extends CCComp {
/** 注册事件监听 */
onLoad() {
oops.message.on(GameEvent.UseSkillCard, this.onUseSkillCard, this);
oops.message.on(GameEvent.UseItemCard, this.onUseSkillCard, this);
oops.message.on(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this);
}
@@ -80,6 +82,7 @@ export class MissSkillsComp extends CCComp {
onDestroy() {
super.onDestroy();
oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this);
oops.message.off(GameEvent.UseItemCard, this.onUseSkillCard, this);
oops.message.off(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this);
}
@@ -138,10 +141,12 @@ export class MissSkillsComp extends CCComp {
*/
private onUseSkillCard(event: string, args: any) {
const payload = args ?? event;
const uuid = Number(payload?.uuid ?? 0);
// 卡 uuid 仅用于查配置;真正施法用技能 idpayload.skill缺省时退回 uuid兼容技能卡直接用技能 id 的场景)
const skillUuid = Number(payload?.skill ?? payload?.uuid ?? 0);
const card_lv = Math.max(1, Math.floor(Number(payload?.card_lv ?? 1)));
if (!uuid) return;
this.addSkill(uuid, card_lv);
if (!skillUuid) return;
// 药水/技能卡的 overrides含 buff_value需透传到技能实体
this.addSkill(skillUuid, card_lv, payload?.overrides);
}
start() {
@@ -157,7 +162,7 @@ export class MissSkillsComp extends CCComp {
* @param uuid 技能 UUID
* @param card_lv 技能卡等级
*/
addSkill(uuid: number, card_lv: number) {
addSkill(uuid: number, card_lv: number, overrides?: SkillOverrides) {
if (!this.skill_box) {
mLogger.error(this.debugMode, "MissSkillsComp", "skill_box prefab not set");
return;
@@ -174,7 +179,7 @@ export class MissSkillsComp extends CCComp {
// 使用 ECS 实体创建技能节点
let sbox = ecs.getEntity<SBox>(SBox);
let pos = new Vec3(this.slots[emptyIndex].x, this.slots[emptyIndex].y, 0);
let node = sbox.load(uuid, card_lv, pos, this.skill_box);
let node = sbox.load(uuid, card_lv, pos, this.skill_box, overrides);
this.slots[emptyIndex].used = true;
this.slots[emptyIndex].node = node;

View File

@@ -2,6 +2,7 @@ import { instantiate, Prefab, Vec3, Node } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { smc } from "../common/SingletonModuleComp";
import { SkillBoxComp } from "./SkillBoxComp";
import { SkillOverrides } from "../common/config/SkillSet";
/** SBox 实体:负责技能卡效果节点创建、初始化与销毁流程 */
@ecs.register(`SBox`)
@@ -29,10 +30,10 @@ export class SBox extends ecs.Entity {
* 1) 创建节点并挂到 SKILL 层
* 2) 初始化表现与属性数据
*/
load(uuid: number, card_lv: number, pos: Vec3, prefab: Prefab): Node {
load(uuid: number, card_lv: number, pos: Vec3, prefab: Prefab, overrides?: SkillOverrides): Node {
let node = instantiate(prefab);
let scene = smc.map.MapView.scene;
// 统一挂到实体显示层 SKILL 节点下
let parent = scene.entityLayer!.node!.getChildByName("SKILL");
if (parent) {
@@ -43,9 +44,9 @@ export class SBox extends ecs.Entity {
// 获取并注册组件
let sboxComp = node.getComponent(SkillBoxComp) || node.addComponent(SkillBoxComp);
this.add(sboxComp);
// 初始化业务逻辑
sboxComp.init(uuid, card_lv);
// 初始化业务逻辑(透传药水卡 overrides含 buff_value
sboxComp.init(uuid, card_lv, overrides);
return node;
}

View File

@@ -166,10 +166,10 @@ export class SkillBoxComp extends CCComp {
* @param uuid 卡牌 UUID
* @param card_lv 技能卡等级
*/
init(uuid: number, card_lv: number) {
init(uuid: number, card_lv: number, overrides?: SkillOverrides) {
this.card_lv = card_lv;
// 查询触发配置
// 查询触发配置(药水卡不在 SkillCardList会走 else 分支)
const config = SkillCardList.find(c => c.uuid === uuid);
if (config) {
this.s_uuid = config.skill ?? uuid; // 获取实际的技能 UUID
@@ -177,14 +177,18 @@ export class SkillBoxComp extends CCComp {
this.trigger_times = config.t_times ?? 1;
this.trigger_interval = config.t_inv ?? 0;
this.keep_waves = config.keep_waves ?? 0;
this.overrides = config.overrides;
this.overrides = overrides ?? config.overrides; // 外部透传(药水卡)优先
this.field = config.field || [];
this.card_icon = config.icon; // 保存卡牌自定义图标(优先级最高)
// 读取触发类型与上限(兜底默认值,避免 undefined
this.trigger_type = config.trigger_type ?? CardTriggerType.Instant;
this.trigger_limit = config.trigger_limit ?? Infinity;
} else {
// 药水卡等uuid 即技能 id触发类型默认 Instant即时生效一次
this.s_uuid = uuid;
this.overrides = overrides;
this.trigger_type = CardTriggerType.Instant;
this.trigger_times = 1;
}
this.current_trigger_times = 0;