## MODIFIED Requirements

### Requirement: 统一积分服务接入
系统 SHALL 在插件加载时声明对 `danding_points` 的依赖，并通过 `points_api` 完成所有积分相关操作。所有积分流水的 `source` 参数 MUST 固定为 `horse_race`。`points_api` 调用失败时系统 MUST 先区分失败类型：余额不足直接拒绝不重试，网络/服务异常则重试 1 次并间隔 1 秒；仍然失败则记录错误日志并向用户返回服务异常提示，不进行后续状态变更。

#### Scenario: 插件加载时声明积分依赖
- **WHEN** 群赛马插件初始化
- **THEN** 系统先执行 `require("danding_points")`，并从 `danding_bot.plugins.danding_points` 导入 `points_api`

#### Scenario: 下注扣款写入统一来源
- **WHEN** 用户成功下注 100 积分
- **THEN** 系统调用 `points_api.spend_points(user_id, 100, "horse_race", "赛马下注")`

#### Scenario: 积分服务余额不足时直接拒绝
- **WHEN** 系统调用 `points_api.spend_points` 首次返回 `(False, balance)` 且余额低于下注额
- **THEN** 系统直接向用户提示积分不足，不进行重试

#### Scenario: 积分服务网络异常时带延时重试
- **WHEN** 系统调用 `points_api.spend_points` 首次抛出网络异常或服务异常
- **THEN** 系统等待 1 秒后重试同一调用 1 次；若仍失败，则向用户返回"积分服务异常，请稍后重试"，不写入下注记录、不变更房间状态

### Requirement: 赔率计算与展示
系统 SHALL 使用标准池赔率公式计算每匹马的赔率：`odds = total_pool / horse_pool`，其中 `total_pool` 为当前比赛所有马匹的下注总额，`horse_pool` 为目标马匹的下注总额。当 `horse_pool = 0` 时（无人下注的马匹），赔率 MUST 设为 `None` 且不对外展示。系统 SHALL 在展示和结算时应用 `MIN_ODDS` 最低赔率保护，但仅当应用后总赔付不超过总池子时生效；若应用 `MIN_ODDS` 会导致该马赔付总额超过 `total_pool`，则 MUST 使用真实赔率。赔率展示 MUST 对当前房间内所有已下注马匹可用，精度保留到小数点后两位。结算金额 MUST 向下取整为整数积分。结算时 MUST 使用锁内快照赔率而非重新计算，确保与用户下注时看到的赔率一致。

#### Scenario: 标准赔率计算
- **WHEN** 总下注池为 800，某马下注额为 500
- **THEN** 该马赔率计算为 `800 / 500 = 1.6`

#### Scenario: 无人下注的马匹
- **WHEN** 某匹马没有收到任何下注（`horse_pool = 0`）
- **THEN** 该马赔率为 `None`，不在赔率列表中展示

#### Scenario: 热门马赔率触发下限保护且池子可承担
- **WHEN** 某匹马计算赔率为 `1.08`，`MIN_ODDS=1.2`，该马下注总额为 500，总池为 800
- **THEN** 应用保底赔率 1.2 后该马赔付总额为 600（≤800），系统对外展示和结算均使用 `1.2`

#### Scenario: 热门马赔率触发下限但池子不可承担
- **WHEN** 某匹马计算赔率为 `1.08`，`MIN_ODDS=1.2`，该马下注总额为 750，总池为 800
- **THEN** 应用保底赔率 1.2 后该马赔付总额为 900（>800），系统不应用保底，使用真实赔率 `1.08`

#### Scenario: 赔率精度与取整
- **WHEN** 赔率计算结果为 `1.5238...`
- **THEN** 展示为 `1.52`，结算时 `bet_amount × 1.52` 向下取整为整数积分

#### Scenario: 显示当前赔率
- **WHEN** 用户发送显示赔率命令
- **THEN** 系统返回当前房间所有已下注马匹的赔率明细，格式为"马匹名: 赔率值"

#### Scenario: 结算使用快照赔率
- **WHEN** 比赛结束进入结算流程
- **THEN** 系统在持锁状态下计算赔率快照并用于所有赔付计算，不依赖比赛开始前保存的可能已过时的赔率
