Diminishing Returns(递减收益)
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 食物修正机制 |
| 触发方式 | AppleCore FoodEvent.GetPlayerFoodValues 事件 |
| 引擎 | EvalEx 表达式解析器 |
功能
SpiceOfLife 的核心机制。当玩家重复食用相同或相似的食物时,食物的饱食度和饱和度会被动态降低,从而鼓励玩家多样化饮食。
修正系数通过表达式公式计算,应用于 AppleCore 的 FoodValues(饱食度和饱和度修正值)。
默认公式
MAX(0, (1 - count/12))^MIN(8, food_hunger_value)
含义:最近食用相同食物的次数越多,修正系数越低。基础历史长度为 12,超出后最旧的食物被移除(FixedSizeQueue 继承 LinkedList,super.remove() 弹出队首即最旧项,FixedSizeQueue.java:16-22)。
[!NOTE] 生效前置条件 递减收益需要同时满足:
food.modifier.enabled(默认 true)、食物不是黑名单食物组成员、玩家累计吃过 ≥new.player.food.eaten.threshold(默认 6)次(FoodModifier.java:45, 84-89)。不满足时系数恒为1f,即食物完全不被削弱。
可用变量
| 变量 | 说明 |
|---|---|
count |
该食物(或所属食物组)在历史中被食用的次数 |
hunger_count |
该食物(或所属食物组)在历史中恢复的饥饿值总和(1 饥饿 = 半格) |
saturation_count |
该食物(或所属食物组)在历史中提供的饱和度总和 |
max_history_length |
食物历史最大长度 |
cur_history_length |
当前食物历史长度 |
food_hunger_value |
食物的基础饥饿恢复值(1 = 半格) |
food_saturation_mod |
食物的基础饱和度修正值 |
cur_hunger |
玩家当前饥饿值(20 = 满) |
cur_saturation |
玩家当前饱和度 |
total_food_eaten |
玩家历史中所有食物的食用总次数 |
food_group_count |
该食物所属的食物组数量 |
distinct_food_groups_eaten |
当前食物历史中不同食物组的数量 |
total_food_groups |
已启用的食物组总数 |
exact_count |
不考虑食物组,该食物在历史中的精确食用次数 |
配置项
| 配置项 | 默认值 | 说明 |
|---|---|---|
food.modifier.enabled |
true |
总开关(ModConfig.java:39) |
food.history.length |
12 |
食物历史最大长度(ModConfig.java:86) |
food.modifier.formula |
见上方 | 修正公式(ModConfig.java:156) |
new.player.food.eaten.threshold |
12 / 2 = 6 |
新玩家累计吃过这么多次食物之前,递减收益完全不生效(ModConfig.java:204,FoodModifier.java:88-89)。默认值由历史长度推导,不是独立数字 |
affect.food.hunger.values |
true |
是否影响饥饿值(ModConfig.java:101) |
affect.food.saturation.modifiers |
false |
是否影响饱和度修正(ModConfig.java:113) |
affect.negative.food.hunger.values |
false |
是否让负饥饿值食物变得更负(ModConfig.java:103) |
affect.negative.food.saturation.modifiers |
false |
是否让负饱和度修正变得更负(ModConfig.java:125) |
food.hunger.rounding.mode |
round |
饥饿值取整方式,可选 round / floor / ceiling(ModConfig.java:96-99, 518-540) |
food.eating.speed.modifier |
1.0 |
大于 0 时按营养值拉长进食时间(ModConfig.java:131) |
food.eating.duration.max |
0 |
进食时长上限 tick,0 = 不限(ModConfig.java:136) |
use.hunger.restored.for.food.history.length |
false |
按饥饿值而非食物数量计算历史长度(ModConfig.java:145) |
food.history.persists.through.death |
false |
食物历史是否跨死亡保留(ModConfig.java:89) |
use.food.groups.as.whitelists |
false |
设为 true 时不属于任何食物组的食物被排除在递减收益之外(ModConfig.java:94) |
[!WARNING] 已订正(本轮源码审计)
- 原文列的 7 个配置项与默认值逐条核对无误,但漏了 6 个上表中的配置项,其中
new.player.food.eaten.threshold(默认 6)和food.hunger.rounding.mode(默认round)会直接改变玩家看到的数值,不可省略。- 补记一条语义容易写反的规则:负值食物不是乘以
modifier,而是乘以2 - modifier(即营养值越低、负得越狠),见下节(FoodModifier.java:69-77)。
数值如何落到饱食度/饱和度
修正系数 modifier 不是直接当饱食度用,而是作为乘数(FoodModifier.getModifiedFoodValues,FoodModifier.java:64-81):
| 情形 | 计算式 | 配置门槛 |
|---|---|---|
| 饥饿值 > 0 | hunger = round(hunger × modifier) |
需 affect.food.hunger.values |
| 饥饿值 < 0 | hunger = round(hunger × (2 − modifier)) |
需上述 且 affect.negative.food.hunger.values |
| 饱和度修正 > 0 | saturationModifier ×= modifier |
需 affect.food.saturation.modifiers |
| 饱和度修正 < 0 | saturationModifier ×= 2 − modifier |
需上述 且 affect.negative.food.saturation.modifiers |
取整用 food.hunger.rounding.mode(Math.round / Math.floor / Math.ceil,ModConfig.java:518-540)。默认 round 意味着结果会被取整到整数:例如饥饿 4、modifier 0.0625 → round(0.25) = 0,而不是 0.25。
饥饿值改为 0 时,客户端工具提示会额外用红色标出原始负值(TooltipHandler.java:88-92)。
进食速度联动
food.eating.speed.modifier > 0 时,进食时长按 duration / modifier^速度系数 拉长(营养值越低吃得越久),并受 food.eating.duration.max 截断;modifier 为 0 时时长被设为 Short.MAX_VALUE(近乎无限)除非设了上限(FoodModifier.java:152-172)。
食物组自定义公式
每个食物组可以在 JSON 配置中定义独立的公式,覆盖全局公式。实现是每个食物组各自持有一个 FoodModifier:formula != null ? new FoodModifier(formula) : FoodModifier.GLOBAL(FoodGroup.java:153)。一个食物属于 N 个组时,N 个系数分别计算后取算术平均(FoodModifier.java:91-104)。
相关条目
- Food Journal - 查看食物历史
- Lunch Box - 食物容器
- Extra Hearts - 里程碑额外心形