The latest devlog update for the indie colony simulation game *Shogun Exodus* introduces Update #141, delivering a massive sweep of core system overhauls, gameplay refinements, and critical bug fixes. Key highlights of this patch include a brand-new UI and menu routing framework that streamlines menu navigation with Esc-key prioritization, alongside fully integrated custom keybindings. Additionally, newly implemented event-driven systems introduce corpse disposal mechanics, food decay and food poisoning hazards, and strict container item permissions to elevate the depth of base management.
This update also refines Servant AI behaviors, addressing hauling pathing restrictions, locked-room navigation, and task prioritization to prevent idle freezes. Visual and functional improvements—such as corrected camera zoom framing, enhanced lighting effects, and a robust rolling auto-save system—further polish the gameplay experience. Below is the comprehensive breakdown of the code refactors, balance tweaks, and optimization fixes implemented in this latest development cycle.
Raw Patch Notes
UPDATE 2026-07-04 #141 - Batch: UI/menu framework, corpses, food/needs, containers, visual & AI fixes (30 items)
- New autoloads: `UIMenus` (open-menu stack + Esc router), `DecaySystem` (rotten despawn sweep), `TimeEffectsSystem` (time-of-day status effects), `CorpseSystem` (dead-Servant disposal). All are event/tick-driven (no per-frame scans of hot paths) and registered in `project.godot`.
- Menus (tasks 8/9/24/30): `UIMenus` tracks open in-HUD menus; `PauseController` Esc now closes the topmost open menu first (ItemInfoPanel, JobsHUD, ContainerOverview, container filter) and only opens the game menu when nothing is open. `PauseMenu.reset_to_main()` runs on every open so the menu never resumes in a stale sub-panel. New bottom-bar `settings` main-UI button (new `autoload_method` handler type in `TimeHUD`) opens the game menu. ItemInfoPanel gained an outside-click backdrop + Esc close for its context/info/split popups.
- Keybindings (task 14): `SettingsManager` persists player rebindings (`keybindings` setting) and applies them to the InputMap; captures shipped defaults for Reset-to-Defaults. New Keybindings sub-panel in the pause Settings (built programmatically) with per-action rebind + capture; PauseController defers to it while capturing.
- Item interactions (tasks 1/2/4/18): right-click a stacked item -> Split (reusable slider dialog in ItemInfoPanel) to choose how many to carry/take; right-click the carrying player -> Add to Inventory / Drop / Split; clickable Parents links in the Info panel jump to the parent material; dropped items now fall to the floor (`PlacedItem.start_fall_to`) for both player and AI drops.
- Death & corpses (tasks 5/6): dead pawns show `Art/UI/DeathPortrait.png` in their portrait (frame+mask kept) and lie horizontally on the floor. `CorpseSystem` assigns a living Servant to haul the corpse (new `begin_corpse_haul` directive in BasicWanderAI) to the Castle entrance; on delivery the corpse despawns and every living Servant gets `discarded_the_dead` (-15, 24h). Corpses persist in the `corpses`/`dead` groups and re-register after load.
- Food & needs (tasks 10/11/21/22/28): rotten food is edible but lowest priority (per-food `eat_priority` minus condition `eat_priority_penalty`); eating rotten rolls data-driven `on_eat_effects` for Food Poisoning (25%) / Severe Food Poisoning (10%). Rotten items despawn 24h after rotting everywhere (`DecaySystem` + `ItemConditions.should_despawn` + condition `despawn_after_days`). AI hunger planner now eats ALL foods, preferring highest `eat_priority`. Shogun buff pins needs to max (`pin_stats_to_max`, enforced in Stats each tick) instead of slowing drain. `awake_during_the_night` (1am-4am, not sleeping) drains sleep 50% faster via `TimeEffectsSystem` + `apply_during_hours`.
- Containers (task 15): per-container AI allow-list on the storage component (`is_ai_allowed_item`, saved in component_state); AI (BasicWanderAI + JobManager) respects it, the player always bypasses. New reusable collapsible (+/-) tree `CategoryTreeView` + hybrid taxonomy `GameDB.get_item_category_path`; opened from the container's "Set Allowed Items" action. (Container Overview All Items tree grouping still pending.)
- Hauling AI (tasks 16/17/20/25): AI whose drop-off target became invalid now keeps the item in its bag (or drops it, falling to the floor, only if the bag can't fit it); a Servant that can't reach any job during work hours wanders instead of freezing and gains `a_bit_of_free_time` (+5); AI horizontal movement refuses to cross a room locked for it (e.g. under construction) even while hauling. (20 & 25 want in-engine verification.)
- Visual fixes (tasks 12/26/27/29): rust overlay picks a size-appropriate texture (small/medium/large) so large placeables no longer use the small texture scaled up; parallax shells self-snap on first frame and `LightingSystem.force_refresh()` runs before the loading screen reveals, killing the load-in snap; loading-screen prompt got its own darkened box and both boxes are darker; camera zoom now keeps the target's framing anchor (upper body) fixed instead of the bottom edge.
- Auto-save (task 7): `SaveGame` auto-saves on an in-game-hour interval (default 12, adjustable in Settings), rotating `Autosave_1..4` (oldest overwritten). New `autosave_enabled` / `autosave_interval_hours` settings + pause-menu controls.
- Materials (task 13): ingot stats derive once at load from parent ore(s) (`GameDB._compile_materials`) = sum across distinct parent-ore types (single-ore = ore value, fixing conductivity drift; alloy = sum). Steel/Bronze now reference ores; gold no longer rusts. Rust/rot thresholds now show in the Info panel ("Rusts After" / "Rots After") via condition `timer_threshold_label`.
- Data/misc (tasks 3/19/23): Work Hours tab widened so all 24 columns fit without scrolling; player-facing "base"->"Castle" and pawns->"Servants" (AGENTS.md convention + key UI strings + travel name); status effects gained grimdark `flavor_text` shown above the mechanical description in the character sheet Effects tooltip.
- Files (new): `Autoload/UIMenus.gd`, `Autoload/DecaySystem.gd`, `Autoload/TimeEffectsSystem.gd`, `Autoload/CorpseSystem.gd`, `Scripts/UI/CategoryTreeView.gd`, `implementation-brief.md`. Modified (partial): `project.godot`, `Autoload/GameDB.gd`, `Autoload/SettingsManager.gd`, `Autoload/SaveGame.gd`, `Autoload/PauseController.gd`, `Autoload/ItemConditions.gd`, `Autoload/ItemVisuals.gd`, `Autoload/LightingSystem.gd`, `Autoload/LoadingScreen.gd`, `Scripts/Player.gd`, `Scripts/BasicWanderAI.gd`, `Scripts/Stats.gd`, `Scripts/PlacedItem.gd`, `Scripts/FoodBowl.gd`, `Scripts/ItemInfoPanel.gd`, `Scripts/StatsPanel.gd`, `Scripts/CameraController.gd`, `Scripts/DeathHandler.gd`, `Scripts/TimeHUD.gd`, `Scripts/UI/PauseMenu.gd`, `Scripts/UI/JobsHUD.gd`, `Scripts/UI/ContainerOverviewHUD.gd`, `Scripts/UI/BuildingPortraitSlot.gd`, `Scripts/Buildings/BuildingParallaxController.gd`, `Scripts/Placeables/PlaceableBase.gd`, `Scripts/Placeables/Components/PlaceableStorageComponent.gd`, `Data/Items/materials.json`, `Data/Items/foods.json`, `Data/Items/condition_effects.json`, `Data/Stats/status_effects.json`, `Data/ui_config.json`, `Data/TravelLocations.json`, `Data/LoadingScreenText.json`, `AGENTS.md`.
- Fixes (#141 follow-up): (1) CRASH — `PlaceableBase.get_storage_entries`/`_with_keys` used a ternary with a bare `[]`, which infers an untyped Array and fails the `Array[Dictionary]` return when a non-storage placeable is queried (the DecaySystem sweep hit this); switched to explicit if/else with a typed empty return. (2) `GameDB._compile_materials` int/float ternary -> if/else (INCOMPATIBLE_TERNARY warning). (3) Renamed shadowing locals `name` -> `display_name` in `Player._resolve_type_item_display_name` and `GeneratedPlacementKnob._placeable_display_name`. (4) Prefixed the now-unused `_fallback_to_inventory` param in `BasicWanderAI._deposit_carried_to_container_or_continue`. (5) Dropped items now rest their sprite BOTTOM on the walk surface (via `PlacedItem._sprite_bottom_offset`) instead of sinking their center to it. (6) Esc now closes the player's Build/container/generator/travel/vendor/social/inventory menus (registered as one entry via `Player._sync_player_menu_registration` + `close_topmost_player_menu`) before opening the pause menu. (7) Pause-menu "Modding" button relabeled "Mods".
- Fixes (#141 follow-up 2, from playtest): (1) Corpses are now carried at the CarriedSprite height (like items) instead of dragged along the floor. (2) Pawns no longer carry items indefinitely — the task-25 room guard was too broad (`_can_enter_point_room` returns false for ANY point outside a room, so pawns stalled at ordinary boundaries/edges while carrying); replaced with a precise `_would_enter_locked_room` that only blocks crossing INTO a locked room the pawn isn't already in, and marks navigation failed so the job replans/drops. (3) Auto-save now actually fires — `_check_autosave()` was placed after the `_has_unsaved_changes` early-return in `SaveGame._process` (so it only ran when NOT dirty, i.e. never during play); moved it above the return. Slots renamed to `Auto_Save_1..4`. (4) Camera zoom framing fixed properly: the vertical anchor scaled with zoom (`(anchor-0.5)*world_size`), dropping the framed point toward the crotch as you zoomed in; set `vertical_screen_anchor = 0.5` and moved framing to a zoom-independent `target_focus_offset` (0,-90) so the face stays framed at every zoom. (5) Locked-room passthrough narrowed via the same precise guard (blocks entering a locked construction room from outside without stranding pawns or trapping evacuees). (6) Warmed the small_wall_lamp default light colour `#ffbc00` -> `#ffb04d` (less yellow-green; still slider-tunable in-game). (7) Generator fake-lights raised to `z_index: 18` (above the room darkness overlay at 17) so they punch through the night darkening like the lamp bloom instead of being dimmed. Files: `Autoload/SaveGame.gd`, `Scripts/BasicWanderAI.gd`, `Scripts/CameraController.gd`, `Scripts/PlacedItem.gd` (earlier), `Scripts/Placeables/PlaceableBase.gd` (earlier), `Data/Items/placeables.json`.
*This is an automated post, using Python and LLMs to summarize game updates. Mistakes, while rare, may happen.

Reply