Guard against MyPlayer being nullptr in IsPlayerDead(),
CycleSpellHotkeys(), RefreshTownNpcOrder(), SpeakSelectedTownNpc(), and
ListTownNpcsKeyPressed() to prevent crashes during early init or after
disconnect. Also reset AutoWalkTrackerTargetId when MyPlayer is null in
the auto-walk tracker to prevent the walk loop from retrying endlessly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The variable is only used within tracker.cpp, so remove the unnecessary
extern declaration from the header and place it in the anonymous
namespace alongside the other file-local tracker state.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix copy-paste comment errors in SpellBookKeyPressed() that referred to
"inventory" instead of "spellbook", and QuestLogKeyPressed() that said
"character quest log" instead of "quest log". Correct a misleading
FindPath comment in town NPC auto-walk, and update a stale SourceX path
reference in diablo.cpp.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move ~4,100 lines of accessibility code from diablo.cpp into 6 new
modules, reducing diablo.cpp from ~7,700 to ~3,660 lines.
New modules:
- controls/accessibility_keys: UI key handlers and guard functions
(IsPlayerDead, IsGameRunning, CanPlayerTakeAction, etc.)
- utils/walk_path_speech: BFS pathfinding, PosOk variants, walk
direction helpers, and path-to-speech formatting
- utils/accessibility_announcements: periodic announcements for low
HP warning sound, durability, boss health, monsters, doors
- controls/town_npc_nav: town NPC selection cycling and auto-walk
- utils/navigation_speech: exit/stairs/portal/unexplored speech and
keyboard walk key handlers
- controls/tracker: target category cycling, candidate finding,
pathfinding navigation, and auto-walk tracker
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove slot tracking when entering/exiting the belt. Now consistently
returns to row 4 column 1 when navigating up from the belt.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always enter belt at slot 1 when navigating down from inventory
- Return to exact inventory position when navigating up from belt
- Keep left/right navigation within belt area only
- Track last inventory slot before entering belt with SlotBeforeBelt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix inconsistent keyboard navigation when moving through multi-tile items
in the inventory. Previously, navigating into a large item (e.g., a 3x2 axe)
and then back out would exit from a different row than you entered from.
Changes:
- Add entry point tracking to remember which row/column you entered an item from
- Use tracked entry points when exiting items to maintain navigation consistency
- Add row and column position to accessibility speech (e.g., "Row 1, Column 3: Short Sword")
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CancelAutoWalk() now sends a walk-to-current-position command to
immediately clear the walk path buffer, instead of only preventing new
segments. Move the M key cancellation check above the CanPlayerTakeAction
guard so it works mid-walk. Add CancelAutoWalk() calls to secondary
action (D), spell action (W), and arrow-key walk so all player inputs
properly cancel an in-progress auto-walk.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix OBJ_SIGNCHEST validation mismatch (Chests case now uses
ValidateAutoWalkObjectTarget matching IsTrackedChestObject)
- Add spoken feedback for all silent early returns (bounds checks,
MyPlayer nullptr)
- M key now toggles: press again to cancel in-progress auto-walk
- A/Shift+A cancels auto-walk silently before attacking
- Auto-walk cancels when in-game menu opens
- Extract IsTrackedMonster() predicate (replaces 3 inline checks)
- Remove default: from Monsters switch cases to enable -Wswitch
exhaustiveness checking
- Add defensive re-validation in ResolveObjectTrackerTarget
- Add documentation comments
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These files had mixed CRLF/LF line endings. Normalize to CRLF to
match the .editorconfig convention for C++ source files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed an issue with the inventory when using a controller that was making 1x1 items clip to an invalid -1 location when picking them up if they are in the last inventory slot.
Gets rid of `orig_palette`, we now always have only 2 palettes:
1. `logical_palette`
This palette has color cycling / swapping applied but no global
effects such as brightness / fade-in.
2. `system_palette`
This palette is the actual palette used for rendering.
It is usually `logical_palette` with the global brightness setting
and fade-in/out applied.
Additionally, we now keep the k-d tree around and use it to
update single colors.
The colors that are color-cycled / swapped are never included
in the k-d tree, so the tree does not need updating on color
cycles/swaps.
The previous implementation didn't behave quite like A-* is supposed to.
After trying to figure out what's causing it and giving up,
I've reimplemented it in a straightforward manner.
Now it seems to work a lot better.
Also increases maximum player path length to 100 steps.
We still only store the first 25 steps in the save file for vanilla
compatibility.
In C++, globals initialization order accross translation units is not
defined. Accessing a global via a function ensures that it is initialized.
This will be needed for #7638, which will statically initialize change
handlers after the Options object has been initialized.
Untangles dependencies by splitting up `engine.{h,cpp}` into 3 files:
1. `primitive_render`
2. `ticks` -- only contains `GetAnimationFrame` for now.
3. `GetWidth2` renamed to `CalculateSpriteTileCenterX` and moved to `levels/dun_tile.hpp`.