# Lucky Dice 核心流程需求

## 目标

本文档定义 FishDice 中普通骰子流程与 Lucky Dice 特殊分支的最小核心逻辑。当前阶段忽略复杂动画表现，只保留玩法闭环、规则扩展口、随机筛选口和目标玩法模式解析口。

核心目标：

- 普通骰子流程可以通过不同组合触发不同业务行为。
- 双四叶草组合可以触发 Lucky Dice 特殊流程。
- Lucky Dice 内部使用独立的特殊骰子结果池，不与普通数字骰混用。
- 骰子数量和结果槽数量需要可配置，第一版可以使用 2 颗普通骰和 3 个 Lucky Dice 结果槽，但规则系统不能写死这个数量。
- Lucky Dice 结果进入目标玩法前，需要保留筛选、随机和模式解析扩展点。
- 执行层避免维护巨大的“组合 key 到方法”的硬编码映射。

## 概念边界

### 普通骰子

普通流程使用一套主循环骰子面：

```text
2 / 3 / 4 / 5 / 6 / Clover
```

其中 `1` 被 `Clover` 替代。普通骰子负责主循环奖励、倍率、特殊触发等常规行为。

普通骰子的数量需要由骰子集合配置决定。第一版默认使用 2 颗普通骰，但系统需要支持后续扩展到 3 颗、4 颗或特殊关卡自定义数量。

最小组合语义：

- 数字 + 数字：普通奖励。
- 数字 + Clover：普通奖励加小额 bonus 或倍率反馈。
- Clover + Clover：触发 Lucky Dice。

后续可扩展更多组合含义，例如对子、三连、指定数量命中、点数和区间、指定数字组合、顺序组合等。

### Lucky Dice 特殊骰子

Lucky Dice 进入后使用另一套特殊结果骰子，不再使用普通数字骰。

示例特殊结果：

```text
Rocket / Thief / Chest / Bomb / Key
```

这套结果的职责是决定后续玩法入口，而不是做普通点数结算。

Lucky Dice 的结果槽数量也需要可配置。竞品拆解中表现为 3 格相同特殊结果，第一版可以固定为 3；但数据结构和播放流程需要允许后续扩展为 2 格、4 格或按玩法目标定义槽数量。

最小语义：

- Rocket：进入 Slap Down。
- Thief：进入 Treasure Heist。

## 总体流程

```text
玩家触发普通 Roll
→ 产出普通骰子结果
→ 提取组合事实 ComboFacts
→ 按优先级匹配普通组合规则
→ 执行规则配置的行为列表
    → 普通奖励：发放奖励并结束
    → Lucky Dice：进入 Lucky Dice 流程

Lucky Dice 流程
→ 构建特殊结果候选池
→ 按上下文筛选候选结果
→ 按权重随机一个结果
→ 按结果槽数量显示相同或配置指定的特殊结果
→ 解析目标玩法与进入模式
→ 启动目标玩法
→ 目标玩法结束后回到主循环
```

## 普通组合规则需求

### 组合 key

组合规则允许使用字符串 key 作为数据 ID，例如：

```text
clover_clover
number_number
number_clover
```

使用字符串 key 的目的：

- 便于配置表、JSON、远端配置和日志使用。
- 新增组合时不一定需要新增枚举或改代码。
- 规则识别与执行逻辑可以解耦。

约束：

- 不允许在业务代码中到处裸写字符串。
- 组合 key 只作为规则索引或配置 ID。
- 原始骰子结果、数量统计、是否有序等信息必须保留在结构化数据中。

### 组合事实

普通 Roll 产出后，需要生成组合事实，供规则匹配器使用。

至少包含：

```text
DiceSetType         骰子集合类型，普通骰子或 Lucky Dice
DiceCount           本次 Roll 实际骰子数量
Faces               原始骰子面列表
FaceCounts          每个骰子面的数量
NumberSum           数字骰点数和
NumberValues        本次出现的数字点数列表
CloverCount         四叶草数量
HasClover           是否包含四叶草
NormalizedKey       无序归一化 key
OrderedKey          有序 key
```

组合事实不能假设只有 2 颗骰子。`Faces` 和 `FaceCounts` 必须支持任意数量，规则匹配器应基于数量统计和条件表达，而不是只读取左骰、右骰两个固定位置。

普通组合默认按无序处理，例如：

```text
clover + 2
2 + clover
```

都归一为：

```text
2_clover
```

如果后续需要区分左骰、右骰或先后顺序，可以在规则中显式声明使用有序 key，例如：

```text
clover_then_rocket
rocket_then_clover
```

### 规则匹配

组合系统不应为每个组合写独立方法，而应使用少量通用匹配器。

首批匹配器需求：

- ExactCombo：精确匹配组合 key，例如 `clover_clover`。
- AllNumbers：全部为数字骰。
- ContainsFace：包含指定面，例如包含 1 个 Clover。
- FaceCount：指定面数量达到要求。
- FaceCountRange：指定面数量落在区间内，例如至少 2 个 Clover。
- DiceCount：本次骰子数量满足要求，例如只匹配 2 骰或 3 骰规则。
- NumberPair：数字对子。
- NumberOfAKind：N 个相同数字，例如三连、四连。
- NumberSumRange：点数和落在区间内。

规则需要支持优先级，优先级高的规则先匹配。

最小规则配置：

```text
优先级 100：clover_clover → trigger_lucky_dice
优先级 50：contains Clover count 1 → grant_reward + clover_bonus
优先级 10：all_numbers → grant_reward
```

当后续加入更多骰子数量时，应优先使用统计型规则，例如：

```text
Clover count >= 2 → trigger_lucky_dice
NumberOfAKind count 3 → grant_reward + combo_bonus
DiceCount 4 + NumberSumRange 18-24 → grant_reward + high_sum_bonus
```

## 行为执行需求

执行层只注册少量通用行为执行器，不维护“所有组合 key 到方法”的巨大 map。

规则配置只描述要执行哪些行为，行为执行器按行为类型处理。

首批行为类型：

- grant_reward：发放普通奖励。
- add_multiplier：调整倍率或临时倍率。
- trigger_lucky_dice：进入 Lucky Dice。
- enter_mode：进入指定玩法模式。
- show_popup：显示提示或轻量弹窗。

执行器注册表只随行为类型增长，不随组合数量增长。

示例：

```text
grant_reward        → GrantRewardExecutor
trigger_lucky_dice  → TriggerLuckyDiceExecutor
enter_mode          → EnterModeExecutor
```

组合扩展优先通过新增规则配置完成；只有出现新的通用行为类型时，才新增执行器。

## Lucky Dice 筛选与随机需求

Lucky Dice 结果不能直接从全部特殊结果中随机，必须经过候选池构建、筛选和权重随机。

### 候选结果

候选结果至少包含：

```text
ResultKey       特殊结果 ID，例如 rocket / thief
TargetKey       目标玩法 ID，例如 slap_down / treasure_heist
Weight          随机权重
Enabled         是否启用
MinLevel        最低等级或进度要求
SourceFilter    允许的触发来源
CooldownRule    冷却或次数限制
```

### 筛选器

首批筛选器需求：

- EnabledFilter：过滤未开启结果。
- ProgressFilter：过滤玩家进度不满足的结果。
- SourceFilter：过滤当前触发来源不允许的结果。
- CooldownFilter：过滤处于冷却或次数已满的玩法。
- TutorialFilter：新手期可强制或限制候选结果。

筛选器应可组合，筛选后如果候选池为空，需要有兜底策略。

兜底策略：

- 优先使用配置的 default result。
- 如果 default result 不可用，走普通奖励兜底。
- 兜底发生时需要打日志，方便排查配置问题。

### 随机选择

筛选后的候选结果按权重随机。

随机需求：

- 支持普通权重随机。
- 支持按上下文调整权重，例如活动期间提高某结果权重。
- 支持新手期固定结果或半随机结果。
- 随机结果需要可记录，方便回放、埋点和问题排查。

## 目标玩法与模式解析

Lucky Dice 的 `ResultKey` 不直接等于最终进入模式。需要分为两层：

```text
ResultKey → TargetKey → ModeKey
```

含义：

- ResultKey：Lucky Dice 抽中的特殊结果，例如 `rocket`。
- TargetKey：目标玩法，例如 `slap_down`。
- ModeKey：目标玩法的具体进入模式，例如 `slap_down_normal`。

示例：

```text
rocket → slap_down
slap_down + 新手期 → slap_down_tutorial
slap_down + 普通状态 → slap_down_normal
slap_down + 高倍率 → slap_down_bonus
```

首批模式解析规则：

- TutorialModeRule：新手期进入教程模式。
- BonusModeRule：高倍率或特殊上下文进入 bonus 模式。
- DefaultModeRule：默认进入普通模式。

目标玩法启动时，需要携带：

```text
TargetKey
ModeKey
ResultKey
Multiplier
TriggerSource
RollSessionId
```

## 最小可交付范围

第一版只需要实现以下玩法闭环：

### 普通骰子

```text
骰子面：2 / 3 / 4 / 5 / 6 / Clover
默认骰子数量：2
骰子数量来源：DiceSet 配置
```

组合行为：

```text
数字 + 数字 → 普通奖励
数字 + Clover → 普通奖励 + Clover bonus
Clover + Clover → 触发 Lucky Dice
```

### Lucky Dice

特殊结果：

```text
Rocket → SlapDownNormal
Thief → TreasureHeistNormal
默认结果槽数量：3
结果槽数量来源：Lucky Dice 结果或玩法配置
```

表现最小化：

```text
显示 Lucky Dice 标题
→ 显示倍率
→ 按结果槽数量显示特殊图标
→ 进入目标玩法
```

复杂动画如托盘、骰子飞入、粒子爆发、白烟转场等不进入第一版核心逻辑要求。

## 非目标

第一版不要求：

- 完整复刻竞品动画时长和粒子效果。
- 实现所有特殊结果类型。
- 实现复杂运营活动权重策略。
- 实现完整短玩法内容。
- 实现远端配置热更新。

## 验收标准

- 普通骰子结果能被转换为结构化组合事实。
- 普通骰子数量和 Lucky Dice 结果槽数量来自配置，核心规则不写死为 2 骰或 3 格。
- 规则系统能通过少量通用匹配器命中普通组合。
- 双四叶草能触发 Lucky Dice，而不是直接发普通奖励。
- 行为执行层只依赖少量通用执行器，不存在按组合数量增长的大型方法 map。
- Lucky Dice 能先筛选候选结果，再按权重随机。
- Lucky Dice 结果能解析到目标玩法和具体模式。
- Rocket 能进入 Slap Down 普通模式。
- Thief 能进入 Treasure Heist 普通模式。
- 候选池为空时存在可观测兜底。
- 日志或调试信息能追踪一次 Roll 从普通结果到最终行为的关键决策。
