@ -442,10 +442,11 @@ void ClrAllMonsters()
monster . position . old = { 0 , 0 } ;
monster . direction = static_cast < Direction > ( GenerateRnd ( 8 ) ) ;
monster . animInfo = { } ;
monster . flags = 0 ;
monster . flags = MFLAG_NO_ENEMY ;
monster . isInvalid = false ;
monster . enemy = GenerateRnd ( gbActivePlayers ) ;
monster . enemyPosition = Players [ monster . enemy ] . position . future ;
monster . enemy = 0 ;
monster . enemyPosition = { } ;
DiscardRandomValues ( 1 ) ;
}
}
@ -581,13 +582,21 @@ tl::expected<void, std::string> LoadDiabMonsts()
void DeleteMonster ( size_t activeIndex )
{
const Monster & monster = Monsters [ ActiveMonsters [ activeIndex ] ] ;
const unsigned monsterId = ActiveMonsters [ activeIndex ] ;
const Monster & monster = Monsters [ monsterId ] ;
if ( ( monster . flags & MFLAG_BERSERK ) ! = 0 ) {
AddUnLight ( monster . lightId ) ;
}
ActiveMonsterCount - - ;
std : : swap ( ActiveMonsters [ activeIndex ] , ActiveMonsters [ ActiveMonsterCount ] ) ; // This ensures alive monsters are before ActiveMonsterCount in the array and any deleted monster after
for ( size_t i = 0 ; i < ActiveMonsterCount ; i + + ) {
Monster & activeMonster = Monsters [ ActiveMonsters [ i ] ] ;
if ( ( activeMonster . flags & MFLAG_TARGETS_MONSTER ) ! = 0 & & activeMonster . enemy = = monsterId ) {
activeMonster . flags | = MFLAG_NO_ENEMY ;
}
}
}
void NewMonsterAnim ( Monster & monster , MonsterGraphic graphic , Direction md , AnimationDistributionFlags flags = AnimationDistributionFlags : : None , int8_t numSkippedFrames = 0 , int8_t distributeFramesBeforeFrame = 0 )
@ -1212,10 +1221,12 @@ void MonsterAttackPlayer(Monster &monster, Player &player, int hit, int minDam,
void MonsterAttackEnemy ( Monster & monster , int hit , int minDam , int maxDam )
{
if ( ( monster . flags & MFLAG_TARGETS_MONSTER ) ! = 0 )
MonsterAttackMonster ( monster , Monsters [ monster . enemy ] , hit , minDam , maxDam ) ;
else
MonsterAttackPlayer ( monster , Players [ monster . enemy ] , hit , minDam , maxDam ) ;
if ( ( monster . flags & MFLAG_NO_ENEMY ) = = 0 ) {
if ( ( monster . flags & MFLAG_TARGETS_MONSTER ) ! = 0 )
MonsterAttackMonster ( monster , Monsters [ monster . enemy ] , hit , minDam , maxDam ) ;
else
MonsterAttackPlayer ( monster , Players [ monster . enemy ] , hit , minDam , maxDam ) ;
}
}
bool MonsterAttack ( Monster & monster )
@ -4056,6 +4067,20 @@ void DeleteMonsterList()
}
}
void RemoveEnemyReferences ( const Player & player )
{
if ( & player = = MyPlayer | | ! player . isOnActiveLevel ( ) )
return ;
const size_t playerId = player . getId ( ) ;
for ( size_t i = 0 ; i < ActiveMonsterCount ; i + + ) {
Monster & activeMonster = Monsters [ ActiveMonsters [ i ] ] ;
if ( ( activeMonster . flags & MFLAG_TARGETS_MONSTER ) = = 0 & & activeMonster . enemy = = playerId ) {
activeMonster . flags | = MFLAG_NO_ENEMY ;
}
}
}
void ProcessMonsters ( )
{
DeleteMonsterList ( ) ;
@ -4096,20 +4121,21 @@ void ProcessMonsters()
UpdateEnemy ( monster ) ;
}
if ( ( monster . flags & MFLAG_TARGETS_MONSTER ) ! = 0 ) {
assert ( monster . enemy > = 0 & & monster . enemy < MaxMonsters ) ;
// BUGFIX: enemy target may be dead at time of access, thus reading garbage data from `Monsters[monster.enemy].position.future`.
monster . position . last = Monsters [ monster . enemy ] . position . future ;
monster . enemyPosition = monster . position . last ;
} else {
assert ( monster . enemy > = 0 & & monster . enemy < MAX_PLRS ) ;
Player & player = Players [ monster . enemy ] ;
monster . enemyPosition = player . position . future ;
if ( IsTileVisible ( monster . position . tile ) ) {
monster . activeForTicks = UINT8_MAX ;
monster . position . last = player . position . future ;
} else if ( monster . activeForTicks ! = 0 & & monster . type ( ) . type ! = MT_DIABLO ) {
monster . activeForTicks - - ;
if ( ( monster . flags & MFLAG_NO_ENEMY ) = = 0 ) {
if ( ( monster . flags & MFLAG_TARGETS_MONSTER ) ! = 0 ) {
assert ( monster . enemy > = 0 & & monster . enemy < MaxMonsters ) ;
monster . position . last = Monsters [ monster . enemy ] . position . future ;
monster . enemyPosition = monster . position . last ;
} else {
assert ( monster . enemy > = 0 & & monster . enemy < MAX_PLRS ) ;
Player & player = Players [ monster . enemy ] ;
monster . enemyPosition = player . position . future ;
if ( IsTileVisible ( monster . position . tile ) ) {
monster . activeForTicks = UINT8_MAX ;
monster . position . last = player . position . future ;
} else if ( monster . activeForTicks ! = 0 & & monster . type ( ) . type ! = MT_DIABLO ) {
monster . activeForTicks - - ;
}
}
}
while ( true ) {