@ -1976,16 +1976,16 @@ void UpdateAttackableMonsterAnnouncements()
SpeakText ( name , /*force=*/ true ) ;
}
// Door state values are defined in `Source/objects.cpp` (DOOR_CLOSED=0, DOOR_OPEN=1, DOOR_BLOCKED=2).
constexpr int DoorClosed = 0 ;
constexpr int DoorOpen = 1 ;
constexpr int DoorBlocked = 2 ;
[[nodiscard]] StringOrView DoorLabelForSpeech ( const Object & door )
{
if ( ! door . isDoor ( ) )
return door . name ( ) ;
// Door state values are defined in `Source/objects.cpp` (DOOR_CLOSED=0, DOOR_OPEN=1, DOOR_BLOCKED=2).
constexpr int DoorClosed = 0 ;
constexpr int DoorOpen = 1 ;
constexpr int DoorBlocked = 2 ;
// Catacombs doors are grates, so differentiate them for the screen reader / tracker.
if ( IsAnyOf ( door . _otype , _object_id : : OBJ_L2LDOOR , _object_id : : OBJ_L2RDOOR ) ) {
if ( door . _oVar4 = = DoorOpen )
@ -2101,10 +2101,10 @@ void GameLogic()
UpdateAutoWalkTracker ( ) ;
UpdateLowDurabilityWarnings ( ) ;
}
if ( leveltype ! = DTYPE_TOWN ) {
gGameLogicStep = GameLogicStep : : ProcessMonsters ;
# ifdef _DEBUG
if ( ! DebugInvisible )
if ( leveltype ! = DTYPE_TOWN ) {
gGameLogicStep = GameLogicStep : : ProcessMonsters ;
# ifdef _DEBUG
if ( ! DebugInvisible )
# endif
ProcessMonsters ( ) ;
gGameLogicStep = GameLogicStep : : ProcessObjects ;
@ -2115,19 +2115,19 @@ void GameLogic()
ProcessItems ( ) ;
ProcessLightList ( ) ;
ProcessVisionList ( ) ;
UpdateBossHealthAnnouncements ( ) ;
UpdateProximityAudioCues ( ) ;
UpdateAttackableMonsterAnnouncements ( ) ;
UpdateInteractableDoorAnnouncements ( ) ;
} else {
gGameLogicStep = GameLogicStep : : ProcessTowners ;
ProcessTowners ( ) ;
gGameLogicStep = GameLogicStep : : ProcessItemsTown ;
ProcessItems ( ) ;
gGameLogicStep = GameLogicStep : : ProcessMissilesTown ;
ProcessMissiles ( ) ;
UpdateProximityAudioCues ( ) ;
}
UpdateBossHealthAnnouncements ( ) ;
UpdateProximityAudioCues ( ) ;
UpdateAttackableMonsterAnnouncements ( ) ;
UpdateInteractableDoorAnnouncements ( ) ;
} else {
gGameLogicStep = GameLogicStep : : ProcessTowners ;
ProcessTowners ( ) ;
gGameLogicStep = GameLogicStep : : ProcessItemsTown ;
ProcessItems ( ) ;
gGameLogicStep = GameLogicStep : : ProcessMissilesTown ;
ProcessMissiles ( ) ;
UpdateProximityAudioCues ( ) ;
}
UpdatePlayerLowHpWarningSound ( ) ;
@ -2227,16 +2227,16 @@ std::vector<int> TownNpcOrder;
int SelectedTownNpc = - 1 ;
int AutoWalkTownNpcTarget = - 1 ;
enum class TrackerTargetCategory : uint8_t {
Items ,
Chests ,
Doors ,
Shrines ,
Objects ,
Breakables ,
Monsters ,
DeadBodies ,
} ;
enum class TrackerTargetCategory : uint8_t {
Items ,
Chests ,
Doors ,
Shrines ,
Objects ,
Breakables ,
Monsters ,
DeadBodies ,
} ;
TrackerTargetCategory SelectedTrackerTargetCategory = TrackerTargetCategory : : Items ;
TrackerTargetCategory AutoWalkTrackerTargetCategory = TrackerTargetCategory : : Items ; ///< Category of the active auto-walk target.
@ -2522,14 +2522,14 @@ namespace {
constexpr int TrackerInteractDistanceTiles = 1 ;
constexpr int TrackerCycleDistanceTiles = 12 ;
int LockedTrackerItemId = - 1 ;
int LockedTrackerChestId = - 1 ;
int LockedTrackerDoorId = - 1 ;
int LockedTrackerShrineId = - 1 ;
int LockedTrackerObjectId = - 1 ;
int LockedTrackerBreakableId = - 1 ;
int LockedTrackerMonsterId = - 1 ;
int LockedTrackerDeadBodyId = - 1 ;
int LockedTrackerItemId = - 1 ;
int LockedTrackerChestId = - 1 ;
int LockedTrackerDoorId = - 1 ;
int LockedTrackerShrineId = - 1 ;
int LockedTrackerObjectId = - 1 ;
int LockedTrackerBreakableId = - 1 ;
int LockedTrackerMonsterId = - 1 ;
int LockedTrackerDeadBodyId = - 1 ;
struct TrackerLevelKey {
dungeon_type levelType ;
@ -2540,17 +2540,17 @@ struct TrackerLevelKey {
std : : optional < TrackerLevelKey > LockedTrackerLevelKey ;
void ClearTrackerLocks ( )
{
LockedTrackerItemId = - 1 ;
LockedTrackerChestId = - 1 ;
LockedTrackerDoorId = - 1 ;
LockedTrackerShrineId = - 1 ;
LockedTrackerObjectId = - 1 ;
LockedTrackerBreakableId = - 1 ;
LockedTrackerMonsterId = - 1 ;
LockedTrackerDeadBodyId = - 1 ;
}
void ClearTrackerLocks ( )
{
LockedTrackerItemId = - 1 ;
LockedTrackerChestId = - 1 ;
LockedTrackerDoorId = - 1 ;
LockedTrackerShrineId = - 1 ;
LockedTrackerObjectId = - 1 ;
LockedTrackerBreakableId = - 1 ;
LockedTrackerMonsterId = - 1 ;
LockedTrackerDeadBodyId = - 1 ;
}
void EnsureTrackerLocksMatchCurrentLevel ( )
{
@ -2583,13 +2583,13 @@ int &LockedTrackerTargetId(TrackerTargetCategory category)
return LockedTrackerObjectId ;
case TrackerTargetCategory : : Breakables :
return LockedTrackerBreakableId ;
case TrackerTargetCategory : : Monsters :
return LockedTrackerMonsterId ;
case TrackerTargetCategory : : DeadBodies :
return LockedTrackerDeadBodyId ;
}
app_fatal ( " Invalid TrackerTargetCategory " ) ;
}
case TrackerTargetCategory : : Monsters :
return LockedTrackerMonsterId ;
case TrackerTargetCategory : : DeadBodies :
return LockedTrackerDeadBodyId ;
}
app_fatal ( " Invalid TrackerTargetCategory " ) ;
}
std : : string_view TrackerTargetCategoryLabel ( TrackerTargetCategory category )
{
@ -2606,14 +2606,14 @@ std::string_view TrackerTargetCategoryLabel(TrackerTargetCategory category)
return _ ( " objects " ) ;
case TrackerTargetCategory : : Breakables :
return _ ( " breakables " ) ;
case TrackerTargetCategory : : Monsters :
return _ ( " monsters " ) ;
case TrackerTargetCategory : : DeadBodies :
return _ ( " dead bodies " ) ;
default :
return _ ( " items " ) ;
}
}
case TrackerTargetCategory : : Monsters :
return _ ( " monsters " ) ;
case TrackerTargetCategory : : DeadBodies :
return _ ( " dead bodies " ) ;
default :
return _ ( " items " ) ;
}
}
void SpeakTrackerTargetCategory ( )
{
@ -2632,14 +2632,14 @@ void CycleTrackerTargetKeyPressed()
const SDL_Keymod modState = SDL_GetModState ( ) ;
const bool cyclePrevious = ( modState & SDL_KMOD_SHIFT ) ! = 0 ;
if ( cyclePrevious ) {
switch ( SelectedTrackerTargetCategory ) {
case TrackerTargetCategory : : Items :
SelectedTrackerTargetCategory = TrackerTargetCategory : : DeadBodies ;
break ;
case TrackerTargetCategory : : Chests :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Items ;
break ;
if ( cyclePrevious ) {
switch ( SelectedTrackerTargetCategory ) {
case TrackerTargetCategory : : Items :
SelectedTrackerTargetCategory = TrackerTargetCategory : : DeadBodies ;
break ;
case TrackerTargetCategory : : Chests :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Items ;
break ;
case TrackerTargetCategory : : Doors :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Chests ;
break ;
@ -2652,17 +2652,17 @@ void CycleTrackerTargetKeyPressed()
case TrackerTargetCategory : : Breakables :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Objects ;
break ;
case TrackerTargetCategory : : Monsters :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Breakables ;
break ;
case TrackerTargetCategory : : DeadBodies :
default :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Monsters ;
break ;
}
} else {
switch ( SelectedTrackerTargetCategory ) {
case TrackerTargetCategory : : Items :
case TrackerTargetCategory : : Monsters :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Breakables ;
break ;
case TrackerTargetCategory : : DeadBodies :
default :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Monsters ;
break ;
}
} else {
switch ( SelectedTrackerTargetCategory ) {
case TrackerTargetCategory : : Items :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Chests ;
break ;
case TrackerTargetCategory : : Chests :
@ -2677,26 +2677,26 @@ void CycleTrackerTargetKeyPressed()
case TrackerTargetCategory : : Objects :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Breakables ;
break ;
case TrackerTargetCategory : : Breakables :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Monsters ;
break ;
case TrackerTargetCategory : : Monsters :
SelectedTrackerTargetCategory = TrackerTargetCategory : : DeadBodies ;
break ;
case TrackerTargetCategory : : DeadBodies :
default :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Items ;
break ;
}
}
case TrackerTargetCategory : : Breakables :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Monsters ;
break ;
case TrackerTargetCategory : : Monsters :
SelectedTrackerTargetCategory = TrackerTargetCategory : : DeadBodies ;
break ;
case TrackerTargetCategory : : DeadBodies :
default :
SelectedTrackerTargetCategory = TrackerTargetCategory : : Items ;
break ;
}
}
SpeakTrackerTargetCategory ( ) ;
}
std : : optional < int > FindNearestGroundItemId ( Point playerPosition )
{
std : : optional < int > bestId ;
int bestDistance = 0 ;
std : : optional < int > FindNearestGroundItemId ( Point playerPosition )
{
std : : optional < int > bestId ;
int bestDistance = 0 ;
for ( int y = 0 ; y < MAXDUNY ; + + y ) {
for ( int x = 0 ; x < MAXDUNX ; + + x ) {
@ -2715,47 +2715,47 @@ std::optional<int> FindNearestGroundItemId(Point playerPosition)
}
}
}
return bestId ;
}
[[nodiscard]] constexpr int CorpseTrackerIdForPosition ( Point position )
{
return position . x + position . y * MAXDUNX ;
}
[[nodiscard]] constexpr Point CorpsePositionForTrackerId ( int corpseId )
{
return { corpseId % MAXDUNX , corpseId / MAXDUNX } ;
}
std : : optional < int > FindNearestCorpseId ( Point playerPosition )
{
std : : optional < int > bestId ;
int bestDistance = 0 ;
for ( int y = 0 ; y < MAXDUNY ; + + y ) {
for ( int x = 0 ; x < MAXDUNX ; + + x ) {
if ( dCorpse [ x ] [ y ] = = 0 )
continue ;
const Point position { x , y } ;
const int distance = playerPosition . WalkingDistance ( position ) ;
if ( ! bestId | | distance < bestDistance ) {
bestId = CorpseTrackerIdForPosition ( position ) ;
bestDistance = distance ;
}
}
}
return bestId ;
}
struct TrackerCandidate {
int id ;
int distance ;
StringOrView name ;
} ;
return bestId ;
}
[[nodiscard]] constexpr int CorpseTrackerIdForPosition ( Point position )
{
return position . x + position . y * MAXDUNX ;
}
[[nodiscard]] constexpr Point CorpsePositionForTrackerId ( int corpseId )
{
return { corpseId % MAXDUNX , corpseId / MAXDUNX } ;
}
std : : optional < int > FindNearestCorpseId ( Point playerPosition )
{
std : : optional < int > bestId ;
int bestDistance = 0 ;
for ( int y = 0 ; y < MAXDUNY ; + + y ) {
for ( int x = 0 ; x < MAXDUNX ; + + x ) {
if ( dCorpse [ x ] [ y ] = = 0 )
continue ;
const Point position { x , y } ;
const int distance = playerPosition . WalkingDistance ( position ) ;
if ( ! bestId | | distance < bestDistance ) {
bestId = CorpseTrackerIdForPosition ( position ) ;
bestDistance = distance ;
}
}
}
return bestId ;
}
struct TrackerCandidate {
int id ;
int distance ;
StringOrView name ;
} ;
[[nodiscard]] bool IsBetterTrackerCandidate ( const TrackerCandidate & a , const TrackerCandidate & b )
{
@ -2801,45 +2801,45 @@ struct TrackerCandidate {
}
}
std : : sort ( result . begin ( ) , result . end ( ) , [ ] ( const TrackerCandidate & a , const TrackerCandidate & b ) { return IsBetterTrackerCandidate ( a , b ) ; } ) ;
return result ;
}
[[nodiscard]] std : : vector < TrackerCandidate > CollectNearbyCorpseTrackerCandidates ( Point playerPosition , int maxDistance )
{
std : : vector < TrackerCandidate > result ;
const int minX = std : : max ( 0 , playerPosition . x - maxDistance ) ;
const int minY = std : : max ( 0 , playerPosition . y - maxDistance ) ;
const int maxX = std : : min ( MAXDUNX - 1 , playerPosition . x + maxDistance ) ;
const int maxY = std : : min ( MAXDUNY - 1 , playerPosition . y + maxDistance ) ;
for ( int y = minY ; y < = maxY ; + + y ) {
for ( int x = minX ; x < = maxX ; + + x ) {
if ( dCorpse [ x ] [ y ] = = 0 )
continue ;
const Point position { x , y } ;
const int distance = playerPosition . WalkingDistance ( position ) ;
if ( distance > maxDistance )
continue ;
result . push_back ( TrackerCandidate {
. id = CorpseTrackerIdForPosition ( position ) ,
. distance = distance ,
. name = _ ( " Dead body " ) ,
} ) ;
}
}
std : : sort ( result . begin ( ) , result . end ( ) , [ ] ( const TrackerCandidate & a , const TrackerCandidate & b ) { return IsBetterTrackerCandidate ( a , b ) ; } ) ;
return result ;
}
[[nodiscard]] constexpr bool IsTrackedChestObject ( const Object & object )
{
return object . canInteractWith ( ) & & ( object . IsChest ( ) | | object . _otype = = _object_id : : OBJ_SIGNCHEST ) ;
}
std : : sort ( result . begin ( ) , result . end ( ) , [ ] ( const TrackerCandidate & a , const TrackerCandidate & b ) { return IsBetterTrackerCandidate ( a , b ) ; } ) ;
return result ;
}
[[nodiscard]] std : : vector < TrackerCandidate > CollectNearbyCorpseTrackerCandidates ( Point playerPosition , int maxDistance )
{
std : : vector < TrackerCandidate > result ;
const int minX = std : : max ( 0 , playerPosition . x - maxDistance ) ;
const int minY = std : : max ( 0 , playerPosition . y - maxDistance ) ;
const int maxX = std : : min ( MAXDUNX - 1 , playerPosition . x + maxDistance ) ;
const int maxY = std : : min ( MAXDUNY - 1 , playerPosition . y + maxDistance ) ;
for ( int y = minY ; y < = maxY ; + + y ) {
for ( int x = minX ; x < = maxX ; + + x ) {
if ( dCorpse [ x ] [ y ] = = 0 )
continue ;
const Point position { x , y } ;
const int distance = playerPosition . WalkingDistance ( position ) ;
if ( distance > maxDistance )
continue ;
result . push_back ( TrackerCandidate {
. id = CorpseTrackerIdForPosition ( position ) ,
. distance = distance ,
. name = _ ( " Dead body " ) ,
} ) ;
}
}
std : : sort ( result . begin ( ) , result . end ( ) , [ ] ( const TrackerCandidate & a , const TrackerCandidate & b ) { return IsBetterTrackerCandidate ( a , b ) ; } ) ;
return result ;
}
[[nodiscard]] constexpr bool IsTrackedChestObject ( const Object & object )
{
return object . canInteractWith ( ) & & ( object . IsChest ( ) | | object . _otype = = _object_id : : OBJ_SIGNCHEST ) ;
}
[[nodiscard]] constexpr bool IsTrackedDoorObject ( const Object & object )
{
@ -3085,32 +3085,32 @@ void DecorateTrackerTargetNameWithOrdinalIfNeeded(int targetId, StringOrView &ta
targetName = std : : move ( decorated ) ;
}
[[nodiscard]] bool IsGroundItemPresent ( int itemId )
{
if ( itemId < 0 | | itemId > MAXITEMS )
return false ;
[[nodiscard]] bool IsGroundItemPresent ( int itemId )
{
if ( itemId < 0 | | itemId > MAXITEMS )
return false ;
for ( uint8_t i = 0 ; i < ActiveItemCount ; + + i ) {
if ( ActiveItems [ i ] = = itemId )
return true ;
}
return false ;
}
[[nodiscard]] bool IsCorpsePresent ( int corpseId )
{
if ( corpseId < 0 | | corpseId > = MAXDUNX * MAXDUNY )
return false ;
const Point position = CorpsePositionForTrackerId ( corpseId ) ;
return InDungeonBounds ( position ) & & dCorpse [ position . x ] [ position . y ] ! = 0 ;
}
std : : optional < int > FindNearestUnopenedChestObjectId ( Point playerPosition )
{
return FindNearestObjectId ( playerPosition , IsTrackedChestObject ) ;
}
return false ;
}
[[nodiscard]] bool IsCorpsePresent ( int corpseId )
{
if ( corpseId < 0 | | corpseId > = MAXDUNX * MAXDUNY )
return false ;
const Point position = CorpsePositionForTrackerId ( corpseId ) ;
return InDungeonBounds ( position ) & & dCorpse [ position . x ] [ position . y ] ! = 0 ;
}
std : : optional < int > FindNearestUnopenedChestObjectId ( Point playerPosition )
{
return FindNearestObjectId ( playerPosition , IsTrackedChestObject ) ;
}
std : : optional < int > FindNearestDoorObjectId ( Point playerPosition )
{
@ -3353,7 +3353,7 @@ std::optional<DoorBlockInfo> FindFirstClosedDoorOnWalkPath(Point startPosition,
for ( int i = 0 ; i < steps ; + + i ) {
const Point next = NextPositionForWalkDirection ( position , path [ i ] ) ;
Object * object = FindObjectAtPosition ( next ) ;
if ( object ! = nullptr & & object - > isDoor ( ) & & object - > _oSolidFlag ) {
if ( object ! = nullptr & & object - > isDoor ( ) & & object - > _oVar4 = = DoorClosed ) {
return DoorBlockInfo { . beforeDoor = position , . doorPosition = next } ;
}
position = next ;
@ -3385,7 +3385,7 @@ struct TrackerPathBlockInfo {
}
Object * object = FindObjectAtPosition ( next ) ;
if ( considerDoors & & object ! = nullptr & & object - > isDoor ( ) & & object - > _oSolidFlag ) {
if ( considerDoors & & object ! = nullptr & & object - > isDoor ( ) & & object - > _oVar4 = = DoorClosed ) {
return TrackerPathBlockInfo {
. type = TrackerPathBlockType : : Door ,
. stepIndex = i ,
@ -3422,14 +3422,14 @@ struct TrackerPathBlockInfo {
return std : : nullopt ;
}
void NavigateToTrackerTargetKeyPressed ( )
{
if ( ! CanPlayerTakeAction ( ) | | InGameMenu ( ) )
return ;
if ( leveltype = = DTYPE_TOWN & & IsNoneOf ( SelectedTrackerTargetCategory , TrackerTargetCategory : : Items , TrackerTargetCategory : : DeadBodies ) ) {
SpeakText ( _ ( " Not in a dungeon. " ) , true ) ;
return ;
}
void NavigateToTrackerTargetKeyPressed ( )
{
if ( ! CanPlayerTakeAction ( ) | | InGameMenu ( ) )
return ;
if ( leveltype = = DTYPE_TOWN & & IsNoneOf ( SelectedTrackerTargetCategory , TrackerTargetCategory : : Items , TrackerTargetCategory : : DeadBodies ) ) {
SpeakText ( _ ( " Not in a dungeon. " ) , true ) ;
return ;
}
if ( AutomapActive ) {
SpeakText ( _ ( " Close the map first. " ) , true ) ;
return ;
@ -3714,10 +3714,10 @@ void NavigateToTrackerTargetKeyPressed()
}
break ;
}
case TrackerTargetCategory : : Monsters : {
const std : : vector < TrackerCandidate > nearbyCandidates = CollectNearbyMonsterTrackerCandidates ( playerPosition , TrackerCycleDistanceTiles ) ;
if ( cycleTarget ) {
targetId = FindNextTrackerCandidateId ( nearbyCandidates , lockedTargetId ) ;
case TrackerTargetCategory : : Monsters : {
const std : : vector < TrackerCandidate > nearbyCandidates = CollectNearbyMonsterTrackerCandidates ( playerPosition , TrackerCycleDistanceTiles ) ;
if ( cycleTarget ) {
targetId = FindNextTrackerCandidateId ( nearbyCandidates , lockedTargetId ) ;
if ( ! targetId ) {
if ( nearbyCandidates . empty ( ) )
SpeakText ( _ ( " No monsters found. " ) , true ) ;
@ -3750,51 +3750,51 @@ void NavigateToTrackerTargetKeyPressed()
targetName = tracked . name ( ) ;
DecorateTrackerTargetNameWithOrdinalIfNeeded ( * targetId , targetName , nearbyCandidates ) ;
if ( ! cycleTarget ) {
targetPosition = tracked . position . tile ;
}
break ;
}
case TrackerTargetCategory : : DeadBodies : {
const std : : vector < TrackerCandidate > nearbyCandidates = CollectNearbyCorpseTrackerCandidates ( playerPosition , TrackerCycleDistanceTiles ) ;
if ( cycleTarget ) {
targetId = FindNextTrackerCandidateId ( nearbyCandidates , lockedTargetId ) ;
if ( ! targetId ) {
if ( nearbyCandidates . empty ( ) )
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
else
SpeakText ( _ ( " No next dead body. " ) , true ) ;
return ;
}
} else if ( IsCorpsePresent ( lockedTargetId ) ) {
targetId = lockedTargetId ;
} else {
targetId = FindNearestCorpseId ( playerPosition ) ;
}
if ( ! targetId ) {
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
if ( ! IsCorpsePresent ( * targetId ) ) {
lockedTargetId = - 1 ;
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
lockedTargetId = * targetId ;
targetName = _ ( " Dead body " ) ;
DecorateTrackerTargetNameWithOrdinalIfNeeded ( * targetId , targetName , nearbyCandidates ) ;
if ( ! cycleTarget ) {
targetPosition = CorpsePositionForTrackerId ( * targetId ) ;
}
break ;
}
}
if ( cycleTarget ) {
SpeakText ( targetName . str ( ) , /*force=*/ true ) ;
return ;
if ( ! cycleTarget ) {
targetPosition = tracked . position . tile ;
}
break ;
}
case TrackerTargetCategory : : DeadBodies : {
const std : : vector < TrackerCandidate > nearbyCandidates = CollectNearbyCorpseTrackerCandidates ( playerPosition , TrackerCycleDistanceTiles ) ;
if ( cycleTarget ) {
targetId = FindNextTrackerCandidateId ( nearbyCandidates , lockedTargetId ) ;
if ( ! targetId ) {
if ( nearbyCandidates . empty ( ) )
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
else
SpeakText ( _ ( " No next dead body. " ) , true ) ;
return ;
}
} else if ( IsCorpsePresent ( lockedTargetId ) ) {
targetId = lockedTargetId ;
} else {
targetId = FindNearestCorpseId ( playerPosition ) ;
}
if ( ! targetId ) {
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
if ( ! IsCorpsePresent ( * targetId ) ) {
lockedTargetId = - 1 ;
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
lockedTargetId = * targetId ;
targetName = _ ( " Dead body " ) ;
DecorateTrackerTargetNameWithOrdinalIfNeeded ( * targetId , targetName , nearbyCandidates ) ;
if ( ! cycleTarget ) {
targetPosition = CorpsePositionForTrackerId ( * targetId ) ;
}
break ;
}
}
if ( cycleTarget ) {
SpeakText ( targetName . str ( ) , /*force=*/ true ) ;
return ;
}
if ( ! targetPosition ) {
@ -4087,10 +4087,10 @@ void UpdateAutoWalkTracker()
if ( ! ValidateAutoWalkObjectTarget ( myPlayer , playerPosition , IsTrackedBreakableObject , N_ ( " Target breakable is gone. " ) , N_ ( " Breakable in range. " ) , destination ) )
return ;
break ;
case TrackerTargetCategory : : Monsters : {
const int monsterId = AutoWalkTrackerTargetId ;
if ( monsterId < 0 | | monsterId > = static_cast < int > ( MaxMonsters ) ) {
AutoWalkTrackerTargetId = - 1 ;
case TrackerTargetCategory : : Monsters : {
const int monsterId = AutoWalkTrackerTargetId ;
if ( monsterId < 0 | | monsterId > = static_cast < int > ( MaxMonsters ) ) {
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Target monster is gone. " ) , true ) ;
return ;
}
@ -4105,29 +4105,29 @@ void UpdateAutoWalkTracker()
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Monster in range. " ) , true ) ;
return ;
}
destination = FindBestAdjacentApproachTile ( myPlayer , playerPosition , monsterPosition ) ;
break ;
}
case TrackerTargetCategory : : DeadBodies : {
const int corpseId = AutoWalkTrackerTargetId ;
if ( ! IsCorpsePresent ( corpseId ) ) {
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Target dead body is gone. " ) , true ) ;
return ;
}
const Point corpsePosition = CorpsePositionForTrackerId ( corpseId ) ;
if ( playerPosition . WalkingDistance ( corpsePosition ) < = TrackerInteractDistanceTiles ) {
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Dead body in range. " ) , true ) ;
return ;
}
destination = corpsePosition ;
break ;
}
}
}
destination = FindBestAdjacentApproachTile ( myPlayer , playerPosition , monsterPosition ) ;
break ;
}
case TrackerTargetCategory : : DeadBodies : {
const int corpseId = AutoWalkTrackerTargetId ;
if ( ! IsCorpsePresent ( corpseId ) ) {
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Target dead body is gone. " ) , true ) ;
return ;
}
const Point corpsePosition = CorpsePositionForTrackerId ( corpseId ) ;
if ( playerPosition . WalkingDistance ( corpsePosition ) < = TrackerInteractDistanceTiles ) {
AutoWalkTrackerTargetId = - 1 ;
SpeakText ( _ ( " Dead body in range. " ) , true ) ;
return ;
}
destination = corpsePosition ;
break ;
}
}
if ( ! destination ) {
AutoWalkTrackerTargetId = - 1 ;
@ -4285,10 +4285,10 @@ void AutoWalkToTrackerTargetKeyPressed()
if ( ! targetId )
return ;
break ;
case TrackerTargetCategory : : Monsters : {
if ( lockedTargetId > = 0 & & lockedTargetId < static_cast < int > ( MaxMonsters ) ) {
targetId = lockedTargetId ;
} else {
case TrackerTargetCategory : : Monsters : {
if ( lockedTargetId > = 0 & & lockedTargetId < static_cast < int > ( MaxMonsters ) ) {
targetId = lockedTargetId ;
} else {
targetId = FindNearestMonsterId ( playerPosition ) ;
}
if ( ! targetId ) {
@ -4304,30 +4304,30 @@ void AutoWalkToTrackerTargetKeyPressed()
return ;
}
}
lockedTargetId = * targetId ;
targetName = Monsters [ * targetId ] . name ( ) ;
break ;
}
case TrackerTargetCategory : : DeadBodies : {
if ( IsCorpsePresent ( lockedTargetId ) ) {
targetId = lockedTargetId ;
} else {
targetId = FindNearestCorpseId ( playerPosition ) ;
}
if ( ! targetId ) {
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
if ( ! IsCorpsePresent ( * targetId ) ) {
lockedTargetId = - 1 ;
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
lockedTargetId = * targetId ;
targetName = _ ( " Dead body " ) ;
break ;
}
}
lockedTargetId = * targetId ;
targetName = Monsters [ * targetId ] . name ( ) ;
break ;
}
case TrackerTargetCategory : : DeadBodies : {
if ( IsCorpsePresent ( lockedTargetId ) ) {
targetId = lockedTargetId ;
} else {
targetId = FindNearestCorpseId ( playerPosition ) ;
}
if ( ! targetId ) {
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
if ( ! IsCorpsePresent ( * targetId ) ) {
lockedTargetId = - 1 ;
SpeakText ( _ ( " No dead bodies found. " ) , true ) ;
return ;
}
lockedTargetId = * targetId ;
targetName = _ ( " Dead body " ) ;
break ;
}
}
std : : string msg ;
StrAppend ( msg , _ ( " Going to: " ) , targetName ) ;
@ -6062,14 +6062,14 @@ void InitKeymapActions()
SpeakNearestStairsUpKeyPressed ,
nullptr ,
[ ] ( ) { return CanPlayerTakeAction ( ) & & leveltype ! = DTYPE_TOWN ; } ) ;
options . Keymapper . AddAction (
" CycleTrackerTarget " ,
N_ ( " Cycle tracker target " ) ,
N_ ( " Cycles what the tracker looks for (items, chests, doors, shrines, objects, breakables, monsters, dead bodies). Hold Shift to cycle backwards. " ) ,
' T ' ,
CycleTrackerTargetKeyPressed ,
nullptr ,
[ ] ( ) { return CanPlayerTakeAction ( ) & & ! InGameMenu ( ) ; } ) ;
options . Keymapper . AddAction (
" CycleTrackerTarget " ,
N_ ( " Cycle tracker target " ) ,
N_ ( " Cycles what the tracker looks for (items, chests, doors, shrines, objects, breakables, monsters, dead bodies). Hold Shift to cycle backwards. " ) ,
' T ' ,
CycleTrackerTargetKeyPressed ,
nullptr ,
[ ] ( ) { return CanPlayerTakeAction ( ) & & ! InGameMenu ( ) ; } ) ;
options . Keymapper . AddAction (
" NavigateToTrackerTarget " ,
N_ ( " Tracker directions " ) ,