PPP commited on
Commit
07f6446
·
1 Parent(s): 40c24a7

feat(rest): fill missing recovery effects for valid rest actions

Browse files
Files changed (2) hide show
  1. state_manager.py +32 -0
  2. story_engine.py +36 -4
state_manager.py CHANGED
@@ -1882,3 +1882,35 @@ class GameState:
1882
  changes["status_effects_removed"] = ["中毒"]
1883
 
1884
  return changes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1882
  changes["status_effects_removed"] = ["中毒"]
1883
 
1884
  return changes
1885
+
1886
+ def get_rest_rule_effects(self) -> dict[str, int]:
1887
+ """Return conservative default recovery when resting at a valid location."""
1888
+ loc = self.world.locations.get(self.player.location)
1889
+ if loc is None or not loc.rest_available:
1890
+ return {}
1891
+
1892
+ if loc.shop_available:
1893
+ base_recovery = {
1894
+ "hp_change": 20,
1895
+ "mp_change": 10,
1896
+ "morale_change": 10,
1897
+ "sanity_change": 6,
1898
+ }
1899
+ else:
1900
+ base_recovery = {
1901
+ "hp_change": 12,
1902
+ "mp_change": 6,
1903
+ "morale_change": 6,
1904
+ "sanity_change": 4,
1905
+ }
1906
+
1907
+ filtered: dict[str, int] = {}
1908
+ if self.player.hp < self.player.max_hp:
1909
+ filtered["hp_change"] = base_recovery["hp_change"]
1910
+ if self.player.mp < self.player.max_mp:
1911
+ filtered["mp_change"] = base_recovery["mp_change"]
1912
+ if self.player.morale < 100:
1913
+ filtered["morale_change"] = base_recovery["morale_change"]
1914
+ if self.player.sanity < 100:
1915
+ filtered["sanity_change"] = base_recovery["sanity_change"]
1916
+ return filtered
story_engine.py CHANGED
@@ -582,6 +582,7 @@ class StoryEngine:
582
  event_type = outline.get("event_type", "")
583
  state_changes, sanitize_warnings = self._sanitize_state_changes(state_changes, event_type)
584
  state_changes, item_rule_notes = self._fill_missing_consumable_effects(state_changes, player_intent)
 
585
  if sanitize_warnings:
586
  logger.info(f"状态变更清理: {sanitize_warnings}")
587
 
@@ -622,7 +623,7 @@ class StoryEngine:
622
  # 合并 tick_log 和 change_log 中的重复属性条目
623
  merged_log = _merge_change_logs(
624
  tick_log,
625
- change_log + validation_issues + item_rule_notes,
626
  )
627
 
628
  return {
@@ -1115,9 +1116,39 @@ class StoryEngine:
1115
 
1116
  return merged_changes, applied_notes
1117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1118
  def _strip_invalid_item_effects(self, state_changes: dict) -> dict:
1119
- """
1120
- 当 LLM 生成了涉及不存在物品的状态变更时,移除相关效果(安全网)。
1121
 
1122
  例如:LLM 生成了"吃了包子" → hunger_change: +10, items_lost: ["包子"],
1123
  但包子不在背包中。此方法移除 items_lost 和相关的属性效果。
@@ -1496,6 +1527,7 @@ class StoryEngine:
1496
  event_type = outline.get("event_type", "")
1497
  state_changes, sanitize_warnings = self._sanitize_state_changes(state_changes, event_type)
1498
  state_changes, item_rule_notes = self._fill_missing_consumable_effects(state_changes, player_intent)
 
1499
 
1500
  # 应用状态变更
1501
  change_log = self.game_state.apply_changes(state_changes)
@@ -1529,7 +1561,7 @@ class StoryEngine:
1529
  # 合并日志
1530
  merged_log = _merge_change_logs(
1531
  tick_log,
1532
- change_log + validation_issues + item_rule_notes,
1533
  )
1534
 
1535
  yield {
 
582
  event_type = outline.get("event_type", "")
583
  state_changes, sanitize_warnings = self._sanitize_state_changes(state_changes, event_type)
584
  state_changes, item_rule_notes = self._fill_missing_consumable_effects(state_changes, player_intent)
585
+ state_changes, rest_rule_notes = self._fill_missing_rest_effects(state_changes, player_intent)
586
  if sanitize_warnings:
587
  logger.info(f"状态变更清理: {sanitize_warnings}")
588
 
 
623
  # 合并 tick_log 和 change_log 中的重复属性条目
624
  merged_log = _merge_change_logs(
625
  tick_log,
626
+ change_log + validation_issues + item_rule_notes + rest_rule_notes,
627
  )
628
 
629
  return {
 
1116
 
1117
  return merged_changes, applied_notes
1118
 
1119
+ def _fill_missing_rest_effects(
1120
+ self,
1121
+ state_changes: dict,
1122
+ player_intent: dict,
1123
+ ) -> tuple[dict, list[str]]:
1124
+ """
1125
+ Fill missing rest recovery with conservative defaults at rest-enabled locations.
1126
+ """
1127
+ if str(player_intent.get("intent", "")).upper() != "REST":
1128
+ return state_changes, []
1129
+
1130
+ recovery_keys = (
1131
+ "hp_change",
1132
+ "mp_change",
1133
+ "morale_change",
1134
+ "sanity_change",
1135
+ "hunger_change",
1136
+ )
1137
+ if any(key in state_changes for key in recovery_keys):
1138
+ return state_changes, []
1139
+
1140
+ inferred = self.game_state.get_rest_rule_effects()
1141
+ if not inferred:
1142
+ return state_changes, []
1143
+
1144
+ merged_changes = dict(state_changes)
1145
+ merged_changes.update(inferred)
1146
+ logger.info("按休息规则补全缺失效果: %s", inferred)
1147
+ return merged_changes, ["休息规则补全"]
1148
+
1149
  def _strip_invalid_item_effects(self, state_changes: dict) -> dict:
1150
+ """
1151
+ 当 LLM 生成了涉及不存在物品的状态变更时,移除相关效果(安全网)。
1152
 
1153
  例如:LLM 生成了"吃了包子" → hunger_change: +10, items_lost: ["包子"],
1154
  但包子不在背包中。此方法移除 items_lost 和相关的属性效果。
 
1527
  event_type = outline.get("event_type", "")
1528
  state_changes, sanitize_warnings = self._sanitize_state_changes(state_changes, event_type)
1529
  state_changes, item_rule_notes = self._fill_missing_consumable_effects(state_changes, player_intent)
1530
+ state_changes, rest_rule_notes = self._fill_missing_rest_effects(state_changes, player_intent)
1531
 
1532
  # 应用状态变更
1533
  change_log = self.game_state.apply_changes(state_changes)
 
1561
  # 合并日志
1562
  merged_log = _merge_change_logs(
1563
  tick_log,
1564
+ change_log + validation_issues + item_rule_notes + rest_rule_notes,
1565
  )
1566
 
1567
  yield {