№ · BUFF 系统 CH.06.24
主页 · ⚡ Buff 系统 · 《同福客栈》Buff 系统实装与落地技术指南

《同福客栈》Buff 系统实装与落地技术指南

📅 2026-06-24 · 📦 6.6 KB · ⚡ Buff 系统 · 📝 MD 文档 🏷️ 时间🏷️ 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 层需做如下对接:

  1. 状态栏 (Buff Bar):在客栈主界面顶部或头像下方,渲染当前生效的 Buff 列表图标。
  2. 视觉区分:正面 Buff(isDebuff: false)使用绿色或金色发光边框;负面 Buff(isDebuff: true)使用红色警示边框或毒气动画。
  3. Tooltip 提示:鼠标悬浮图标时,展示 BuffConfig 中的名称、描述,以及动态计算的剩余时间(格式化为游戏内时辰或现实倒计时)。
  4. 飘字提示:当一个新 Buff 被添加或移除时(如进入“高峰营业”),在屏幕中央触发一次醒目的飘字动效通知玩家。

6. 开发落地的首要 Task 列表

  1. 建立 BuffConfigs.ts,将现有的“势力合璧”、“高峰营业”等 5-8 个基础状态配置为 JSON 格式。
  2. 在全局 Store (如 Redux/Zustand) 中引入 activeBuffs 数组。
  3. 实现 BuffEngine 工具类,完成 ADDMULTIPLY 的拦截计算器。
  4. 在核心的“金币扣除”、“客流生成”函数中,接入 calculateFinalValue 包装器。