№ · BUFF 系统
CH.06.24
《同福客栈》Buff 系统实装与落地技术指南
1. 概述
在完成《客栈经营状态与核心数值体系设计文档》的框架搭建后,本指南旨在将“经营状态”、“势力合璧”以及“随机事件影响”统一抽象为代码层面的 Buff 系统,并给出具体的 TypeScript 数据结构、数值拦截计算逻辑以及状态管理的实装方案。
2. 数据结构定义 (TypeScript 规范)
为了兼容各种不同类型的 Buff(固定数值加减、百分比乘区、特定状态锁定等),我们需要设计一个高扩展性的接口。
2.1 核心配置模型
// Buff 作用目标枚举
export type BuffTarget = 'GLOBAL' | 'STAFF' | 'DIMENSION';
// Buff 效果修改器类型
export type ModifierType =
| 'ADD' // 固定值加成 (例如:客流量 +10)
| 'MULTIPLY' // 百分比乘区 (例如:营收 +50% -> 1.5)
| 'OVERRIDE' // 强制覆盖 (例如:强制营业状态为 'SUSPENDED')
| 'FREEZE'; // 冻结属性 (例如:心情锁定不掉);
// 具体的效果条目
export interface BuffEffect {
attribute: string; // 作用的属性键名 (如: 'reputation', 'customerFlow', 'revenue')
modifierType: ModifierType;
value: any; // 对应的值
targetId?: string; // 若作用于特定员工或维度,传入对应ID
}
// 静态 Buff 配置表结构
export interface BuffConfig {
id: string; // 唯一ID,如 'BUFF_PEAK_HOUR'
name: string; // 名称:如 '高峰营业'
desc: string; // 描述:如 '饭点时间,客流与营收增加,但损耗加剧。'
icon: string; // UI图标路径或 Icon 标识
isDebuff: boolean; // 是否为负面状态(决定边框颜色:红/绿)
effects: BuffEffect[]; // 包含的效果列表
}
2.2 运行时状态模型 (Active Buff)
存储在玩家当前存档或内存中的动态数据。
export interface ActiveBuff {
buffId: string; // 关联的静态 Buff ID
startTime: number; // 获得该 Buff 的游戏内时间戳
duration?: number; // 持续时间(毫秒/Tick数),若为 undefined 则代表永久或条件触发
source: string; // 来源记录(如:'EVENT_THIEF', 'FACTION_COMBO')
}
3. Buff 引擎与数值拦截机制 (核心实现)
Buff 系统的核心在于**“拦截器模式”**。底层的基础数值(Base Value)在内存中不变,所有获取最终数值(Final Value)的地方,都需要经过 Buff 引擎的计算。
3.1 数值计算流 (Value Pipeline)
export class BuffEngine {
// 获取当前生效的所有 Buff
private activeBuffs: ActiveBuff[] = [];
private buffConfigs: Record<string, BuffConfig> = {};
// 核心计算方法:传入基础值与属性名,返回计算后的最终值
public calculateFinalValue(attribute: string, baseValue: number, targetId?: string): number {
let finalValue = baseValue;
let multiplier = 1.0; // 乘区累加器
const relevantEffects = this.getRelevantEffects(attribute, targetId);
// 1. 先处理覆盖与冻结 (优先级最高)
const overrideEffect = relevantEffects.find(e => e.modifierType === 'OVERRIDE');
if (overrideEffect) return overrideEffect.value;
// 2. 处理固定值加减
relevantEffects.filter(e => e.modifierType === 'ADD').forEach(e => {
finalValue += e.value;
});
// 3. 处理百分比乘区 (同类乘区相加再相乘,防止指数级爆炸)
relevantEffects.filter(e => e.modifierType === 'MULTIPLY').forEach(e => {
multiplier += (e.value - 1); // e.value = 1.5 代表 +50%,此处累加 0.5
});
return finalValue * multiplier;
}
}
3.2 与现有系统的对接点
例如,在获取每日客流上限时,不再直接读取常量,而是通过引擎计算:
// 伪代码:计算今日客流上限
const baseFlow = 50; // 基础客流
const finalFlow = buffEngine.calculateFinalValue('customerFlowLimit', baseFlow);
4. 三类核心 Buff 的生命周期实装
根据《V2.0 优化落地版》文档,我们需要实装以下三类生命周期的 Buff:
4.1 临时时长类 Buff(Timer-based)
- 示例:【临时卫生整顿】(强制停业 2 小时)、【高峰营业】(饭点时段)。
- 实装方案:在游戏的全局
Tick循环中检测。每次Tick(比如游戏内推进了 10 分钟),遍历activeBuffs,将带有duration的 Buff 减去对应时间。当时间归零时,触发removeBuff事件,并重新计算客栈状态。
4.2 条件触发类 Buff(Conditional / Reactive)
- 示例:【势力合璧:官商一体】(衙门>=80 且 乡绅>=80)、【半营业状态】(清洁度<30)。
- 实装方案:不依赖定时器,而是采用事件监听(Event Bus)。当衙门好感度发生变化时,抛出
FACTION_CHANGED事件,Buff 管理器监听到后,重新评估条件。若满足,则addBuff('FACTION_COMBO_1'),不满足则移除。持续时间字段duration留空。
4.3 永久道具类 Buff(Legacy / Equipment)
- 示例:【佟家商会金卡】(所有食材采购成本永久降低 5%)。
- 实装方案:在玩家读档或开局初始化时,直接从
GlobalProfile(账号传承数据)中读取已解锁的特权,将对应的 Buff 注入到activeBuffs中,且不设过期时间。
5. UI 表现层对接 (React / Vue 组件建议)
为了让玩家清晰感知 Buff 的存在和效果,UI 层需做如下对接:
- 状态栏 (Buff Bar):在客栈主界面顶部或头像下方,渲染当前生效的 Buff 列表图标。
- 视觉区分:正面 Buff(
isDebuff: false)使用绿色或金色发光边框;负面 Buff(isDebuff: true)使用红色警示边框或毒气动画。 - Tooltip 提示:鼠标悬浮图标时,展示
BuffConfig中的名称、描述,以及动态计算的剩余时间(格式化为游戏内时辰或现实倒计时)。 - 飘字提示:当一个新 Buff 被添加或移除时(如进入“高峰营业”),在屏幕中央触发一次醒目的飘字动效通知玩家。
6. 开发落地的首要 Task 列表
- 建立
BuffConfigs.ts,将现有的“势力合璧”、“高峰营业”等 5-8 个基础状态配置为 JSON 格式。 - 在全局 Store (如 Redux/Zustand) 中引入
activeBuffs数组。 - 实现
BuffEngine工具类,完成ADD和MULTIPLY的拦截计算器。 - 在核心的“金币扣除”、“客流生成”函数中,接入
calculateFinalValue包装器。