| 3948 | } |
| 3949 | |
| 3950 | void ProcessMonsters() |
| 3951 | { |
| 3952 | DeleteMonsterList(); |
| 3953 | |
| 3954 | assert(ActiveMonsterCount <= MaxMonsters); |
| 3955 | for (size_t i = 0; i < ActiveMonsterCount; i++) { |
| 3956 | Monster &monster = Monsters[ActiveMonsters[i]]; |
| 3957 | FollowTheLeader(monster); |
| 3958 | if (gbIsMultiplayer) { |
| 3959 | SetRndSeed(monster.aiSeed); |
| 3960 | monster.aiSeed = AdvanceRndSeed(); |
| 3961 | } |
| 3962 | if (monster.hitPoints < monster.maxHitPoints && monster.hitPoints >> 6 > 0) { |
| 3963 | if (monster.level(sgGameInitInfo.nDifficulty) > 1) { |
| 3964 | monster.hitPoints += monster.level(sgGameInitInfo.nDifficulty) / 2; |
| 3965 | } else { |
| 3966 | monster.hitPoints += monster.level(sgGameInitInfo.nDifficulty); |
| 3967 | } |
| 3968 | monster.hitPoints = std::min(monster.hitPoints, monster.maxHitPoints); // prevent going over max HP with part of a single regen tick |
| 3969 | } |
| 3970 | |
| 3971 | if (IsTileVisible(monster.position.tile) && monster.activeForTicks == 0) { |
| 3972 | if (monster.type().type == MT_CLEAVER) { |
| 3973 | PlaySFX(USFX_CLEAVER); |
| 3974 | } |
| 3975 | if (monster.type().type == MT_NAKRUL) { |
| 3976 | if (sgGameInitInfo.bCowQuest != 0) { |
| 3977 | PlaySFX(USFX_NAKRUL6); |
| 3978 | } else { |
| 3979 | if (IsUberRoomOpened) |
| 3980 | PlaySFX(USFX_NAKRUL4); |
| 3981 | else |
| 3982 | PlaySFX(USFX_NAKRUL5); |
| 3983 | } |
| 3984 | } |
| 3985 | if (monster.type().type == MT_DEFILER) |
| 3986 | PlaySFX(USFX_DEFILER8); |
| 3987 | UpdateEnemy(monster); |
| 3988 | } |
| 3989 | |
| 3990 | if ((monster.flags & MFLAG_TARGETS_MONSTER) != 0) { |
| 3991 | assert(monster.enemy >= 0 && monster.enemy < MaxMonsters); |
| 3992 | // BUGFIX: enemy target may be dead at time of access, thus reading garbage data from `Monsters[monster.enemy].position.future`. |
| 3993 | monster.position.last = Monsters[monster.enemy].position.future; |
| 3994 | monster.enemyPosition = monster.position.last; |
| 3995 | } else { |
| 3996 | assert(monster.enemy >= 0 && monster.enemy < MAX_PLRS); |
| 3997 | Player &player = Players[monster.enemy]; |
| 3998 | monster.enemyPosition = player.position.future; |
| 3999 | if (IsTileVisible(monster.position.tile)) { |
| 4000 | monster.activeForTicks = UINT8_MAX; |
| 4001 | monster.position.last = player.position.future; |
| 4002 | } else if (monster.activeForTicks != 0 && monster.type().type != MT_DIABLO) { |
| 4003 | monster.activeForTicks--; |
| 4004 | } |
| 4005 | } |
| 4006 | while (true) { |
| 4007 | if ((monster.flags & MFLAG_SEARCH) == 0 || !AiPlanPath(monster)) { |
no test coverage detected