feat: 实现药水卡限时强化功能,支持自定义数值覆写
1. 新增Buff数值覆写机制,支持药水卡自定义buff效果数值 2. 重构属性计算逻辑,支持读取药水卡传递的覆写值 3. 新增多组限时强化Buff与药水卡配置 4. 优化UI数值显示,实时展示最终属性值 5. 新增多维度调试日志方便排查问题
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user