From 77b72da27663cff2f6703e39d5a0db35c2a978eb Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Tue, 13 Jul 2021 03:00:03 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8FUse=20monster=20by=20referenc?= =?UTF-8?q?e=20when=20possible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/control.cpp | 7 +- Source/controls/plrctrls.cpp | 29 +- Source/dead.cpp | 18 +- Source/debug.cpp | 12 +- Source/diablo.cpp | 18 +- Source/effects.cpp | 58 +- Source/effects.h | 5 +- Source/effects_stubs.cpp | 2 +- Source/inv.cpp | 3 +- Source/items.cpp | 38 +- Source/items.h | 5 +- Source/loadsave.cpp | 278 ++- Source/missiles.cpp | 280 +-- Source/missiles.h | 3 +- Source/monster.cpp | 3444 +++++++++++++++++----------------- Source/monster.h | 21 +- Source/msg.cpp | 61 +- Source/objects.cpp | 36 +- Source/objects.h | 3 +- Source/player.cpp | 70 +- Source/qol/monhealthbar.cpp | 22 +- Source/quests.cpp | 17 +- Source/quests.h | 3 +- Source/scrollrt.cpp | 51 +- Source/sync.cpp | 46 +- test/effects_test.cpp | 20 +- 26 files changed, 2282 insertions(+), 2268 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index 1a9a8ec35..7230b25f7 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -1284,15 +1284,16 @@ void DrawInfoBox(const Surface &out) else if (pcursobj != -1) GetObjectStr(pcursobj); if (pcursmonst != -1) { + const auto &monster = Monsters[pcursmonst]; if (leveltype != DTYPE_TOWN) { infoclr = UIS_SILVER; - strcpy(infostr, _(Monsters[pcursmonst].mName)); + strcpy(infostr, _(monster.mName)); ClearPanel(); - if (Monsters[pcursmonst]._uniqtype != 0) { + if (monster._uniqtype != 0) { infoclr = UIS_GOLD; PrintUniqueHistory(); } else { - PrintMonstHistory(Monsters[pcursmonst].MType->mtype); + PrintMonstHistory(monster.MType->mtype); } } else if (pcursitem == -1) { string_view townerName = Towners[pcursmonst]._tName; diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 6d178d5ab..f54860b91 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -185,17 +185,15 @@ bool HasRangedSpell() && !spelldata[spl].sTownSpell; } -bool CanTargetMonster(int mi) +bool CanTargetMonster(const MonsterStruct &monster) { - const MonsterStruct &monst = Monsters[mi]; - - if ((monst._mFlags & (MFLAG_HIDDEN | MFLAG_GOLEM)) != 0) + if ((monster._mFlags & (MFLAG_HIDDEN | MFLAG_GOLEM)) != 0) return false; - if (monst._mhitpoints >> 6 <= 0) // dead + if (monster._mhitpoints >> 6 <= 0) // dead return false; - const int mx = monst.position.tile.x; - const int my = monst.position.tile.y; + const int mx = monster.position.tile.x; + const int my = monster.position.tile.y; if ((dFlags[mx][my] & BFLAG_LIT) == 0) // not visible return false; if (dMonster[mx][my] == 0) @@ -212,14 +210,16 @@ void FindRangedTarget() // The first MAX_PLRS monsters are reserved for players' golems. for (int mi = MAX_PLRS; mi < MAXMONSTERS; mi++) { - if (!CanTargetMonster(mi)) + const auto &monster = Monsters[mi]; + + if (!CanTargetMonster(monster)) continue; - const bool newCanTalk = CanTalkToMonst(mi); + const bool newCanTalk = CanTalkToMonst(monster); if (pcursmonst != -1 && !canTalk && newCanTalk) continue; - const int newDdistance = GetDistanceRanged(Monsters[mi].position.future); - const int newRotations = GetRotaryDistance(Monsters[mi].position.future); + const int newDdistance = GetDistanceRanged(monster.position.future); + const int newRotations = GetRotaryDistance(monster.position.future); if (pcursmonst != -1 && canTalk == newCanTalk) { if (distance < newDdistance) continue; @@ -274,8 +274,9 @@ void FindMeleeTarget() if (dMonster[dx][dy] != 0) { const int mi = dMonster[dx][dy] > 0 ? dMonster[dx][dy] - 1 : -(dMonster[dx][dy] + 1); - if (CanTargetMonster(mi)) { - const bool newCanTalk = CanTalkToMonst(mi); + const auto &monster = Monsters[mi]; + if (CanTargetMonster(monster)) { + const bool newCanTalk = CanTalkToMonst(monster); if (pcursmonst != -1 && !canTalk && newCanTalk) continue; const int newRotations = GetRotaryDistance({ dx, dy }); @@ -442,7 +443,7 @@ void Interact() if (leveltype == DTYPE_TOWN && pcursmonst != -1) { NetSendCmdLocParam1(true, CMD_TALKXY, Towners[pcursmonst].position, pcursmonst); } else if (pcursmonst != -1) { - if (Players[MyPlayerId]._pwtype != WT_RANGED || CanTalkToMonst(pcursmonst)) { + if (Players[MyPlayerId]._pwtype != WT_RANGED || CanTalkToMonst(Monsters[pcursmonst])) { NetSendCmdParam1(true, CMD_ATTACKID, pcursmonst); } else { NetSendCmdParam1(true, CMD_RATTACKID, pcursmonst); diff --git a/Source/dead.cpp b/Source/dead.cpp index d7253d8ce..50f447c2d 100644 --- a/Source/dead.cpp +++ b/Source/dead.cpp @@ -63,13 +63,13 @@ void InitDead() stonendx = nd; for (int i = 0; i < ActiveMonsterCount; i++) { - int mi = ActiveMonsters[i]; - if (Monsters[mi]._uniqtype != 0) { - InitDeadAnimationFromMonster(Dead[nd], *Monsters[mi].MType); - Dead[nd].translationPaletteIndex = Monsters[mi]._uniqtrans + 4; + auto &monster = Monsters[ActiveMonsters[i]]; + if (monster._uniqtype != 0) { + InitDeadAnimationFromMonster(Dead[nd], *monster.MType); + Dead[nd].translationPaletteIndex = monster._uniqtrans + 4; nd++; - Monsters[mi]._udeadval = nd; + monster._udeadval = nd; } } @@ -84,13 +84,13 @@ void AddDead(Point tilePosition, int8_t dv, Direction ddir) void SetDead() { for (int i = 0; i < ActiveMonsterCount; i++) { - int mi = ActiveMonsters[i]; - if (Monsters[mi]._uniqtype == 0) + auto &monster = Monsters[ActiveMonsters[i]]; + if (monster._uniqtype == 0) continue; for (int dx = 0; dx < MAXDUNX; dx++) { for (int dy = 0; dy < MAXDUNY; dy++) { - if ((dDead[dx][dy] & 0x1F) == Monsters[mi]._udeadval) - ChangeLightXY(Monsters[mi].mlid, { dx, dy }); + if ((dDead[dx][dy] & 0x1F) == monster._udeadval) + ChangeLightXY(monster.mlid, { dx, dy }); } } } diff --git a/Source/debug.cpp b/Source/debug.cpp index d89f6018e..46547f0bc 100644 --- a/Source/debug.cpp +++ b/Source/debug.cpp @@ -39,13 +39,15 @@ void PrintDebugMonster(int m) { char dstr[128]; - sprintf(dstr, "Monster %i = %s", m, _(Monsters[m].mName)); + auto &monster = Monsters[m]; + + sprintf(dstr, "Monster %i = %s", m, _(monster.mName)); NetSendCmdString(1 << MyPlayerId, dstr); - sprintf(dstr, "X = %i, Y = %i", Monsters[m].position.tile.x, Monsters[m].position.tile.y); + sprintf(dstr, "X = %i, Y = %i", monster.position.tile.x, monster.position.tile.y); NetSendCmdString(1 << MyPlayerId, dstr); - sprintf(dstr, "Enemy = %i, HP = %i", Monsters[m]._menemy, Monsters[m]._mhitpoints); + sprintf(dstr, "Enemy = %i, HP = %i", monster._menemy, monster._mhitpoints); NetSendCmdString(1 << MyPlayerId, dstr); - sprintf(dstr, "Mode = %i, Var1 = %i", Monsters[m]._mmode, Monsters[m]._mVar1); + sprintf(dstr, "Mode = %i, Var1 = %i", monster._mmode, monster._mVar1); NetSendCmdString(1 << MyPlayerId, dstr); bool bActive = false; @@ -55,7 +57,7 @@ void PrintDebugMonster(int m) bActive = true; } - sprintf(dstr, "Active List = %i, Squelch = %i", bActive ? 1 : 0, Monsters[m]._msquelch); + sprintf(dstr, "Active List = %i, Squelch = %i", bActive ? 1 : 0, monster._msquelch); NetSendCmdString(1 << MyPlayerId, dstr); } diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 237c04120..b0b3b71da 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -250,7 +250,7 @@ bool LeftMouseCmd(bool bShift) if (bShift) { NetSendCmdLoc(MyPlayerId, true, CMD_RATTACKXY, { cursmx, cursmy }); } else if (pcursmonst != -1) { - if (CanTalkToMonst(pcursmonst)) { + if (CanTalkToMonst(Monsters[pcursmonst])) { NetSendCmdParam1(true, CMD_ATTACKID, pcursmonst); } else { NetSendCmdParam1(true, CMD_RATTACKID, pcursmonst); @@ -261,7 +261,7 @@ bool LeftMouseCmd(bool bShift) } else { if (bShift) { if (pcursmonst != -1) { - if (CanTalkToMonst(pcursmonst)) { + if (CanTalkToMonst(Monsters[pcursmonst])) { NetSendCmdParam1(true, CMD_ATTACKID, pcursmonst); } else { NetSendCmdLoc(MyPlayerId, true, CMD_SATTACKXY, { cursmx, cursmy }); @@ -1188,16 +1188,16 @@ void CreateLevel(lvl_entry lvldir) void UpdateMonsterLights() { for (int i = 0; i < ActiveMonsterCount; i++) { - MonsterStruct *mon = &Monsters[ActiveMonsters[i]]; - if (mon->mlid != NO_LIGHT) { - if (mon->mlid == Players[MyPlayerId]._plid) { // Fix old saves where some monsters had 0 instead of NO_LIGHT - mon->mlid = NO_LIGHT; + auto &monster = Monsters[ActiveMonsters[i]]; + if (monster.mlid != NO_LIGHT) { + if (monster.mlid == Players[MyPlayerId]._plid) { // Fix old saves where some monsters had 0 instead of NO_LIGHT + monster.mlid = NO_LIGHT; continue; } - LightStruct *lid = &Lights[mon->mlid]; - if (mon->position.tile != lid->position.tile) { - ChangeLightXY(mon->mlid, mon->position.tile); + LightStruct *lid = &Lights[monster.mlid]; + if (monster.position.tile != lid->position.tile) { + ChangeLightXY(monster.mlid, monster.position.tile); } } } diff --git a/Source/effects.cpp b/Source/effects.cpp index e938b0c5b..961ac5cf4 100644 --- a/Source/effects.cpp +++ b/Source/effects.cpp @@ -1095,25 +1095,6 @@ void StreamUpdate() } } -bool CalculatePosition(Point soundPosition, int *plVolume, int *plPan) -{ - const auto &playerPosition = Players[MyPlayerId].position.tile; - const auto delta = soundPosition - playerPosition; - - int pan = (delta.deltaX - delta.deltaY) * 256; - *plPan = clamp(pan, PAN_MIN, PAN_MAX); - - int volume = playerPosition.ApproxDistance(soundPosition); - volume *= -64; - - if (volume <= ATTENUATION_MIN) - return false; - - *plVolume = volume; - - return true; -} - void PlaySfxPriv(TSFX *pSFX, bool loc, Point position) { if (Players[MyPlayerId].pLvlLoad != 0 && gbIsMultiplayer) { @@ -1129,7 +1110,7 @@ void PlaySfxPriv(TSFX *pSFX, bool loc, Point position) int lVolume = 0; int lPan = 0; - if (loc && !CalculatePosition(position, &lVolume, &lPan)) { + if (loc && !CalculateSoundPosition(position, &lVolume, &lPan)) { return; } @@ -1255,29 +1236,23 @@ void FreeMonsterSnd() } } -void PlayEffect(int i, int mode) +bool CalculateSoundPosition(Point soundPosition, int *plVolume, int *plPan) { - if (Players[MyPlayerId].pLvlLoad != 0) { - return; - } + const auto &playerPosition = Players[MyPlayerId].position.tile; + const auto delta = soundPosition - playerPosition; - int sndIdx = GenerateRnd(2); - if (!gbSndInited || !gbSoundOn || gbBufferMsgs != 0) { - return; - } + int pan = (delta.deltaX - delta.deltaY) * 256; + *plPan = clamp(pan, PAN_MIN, PAN_MAX); - int mi = Monsters[i]._mMTidx; - TSnd *snd = LevelMonsterTypes[mi].Snds[mode][sndIdx].get(); - if (snd == nullptr || snd->isPlaying()) { - return; - } + int volume = playerPosition.ApproxDistance(soundPosition); + volume *= -64; - int lVolume = 0; - int lPan = 0; - if (!CalculatePosition(Monsters[i].position.tile, &lVolume, &lPan)) - return; + if (volume <= ATTENUATION_MIN) + return false; + + *plVolume = volume; - snd_play_snd(snd, lVolume, lPan); + return true; } void PlaySFX(_sfx_id psfx) @@ -1391,11 +1366,4 @@ int GetSFXLength(int nSFX) return sgSFX[nSFX].pSnd->DSB.GetLength(); } -#ifdef RUN_TESTS -bool TestCalculatePosition(Point soundPosition, int *plVolume, int *plPan) -{ - return CalculatePosition(soundPosition, plVolume, plPan); -} -#endif - } // namespace devilution diff --git a/Source/effects.h b/Source/effects.h index 6da6b488f..c7d724f22 100644 --- a/Source/effects.h +++ b/Source/effects.h @@ -1177,7 +1177,7 @@ bool effect_is_playing(int nSFX); void stream_stop(); void InitMonsterSND(int monst); void FreeMonsterSnd(); -void PlayEffect(int i, int mode); +bool CalculateSoundPosition(Point soundPosition, int *plVolume, int *plPan); void PlaySFX(_sfx_id psfx); void PlaySfxLoc(_sfx_id psfx, Point position, bool randomizeByCategory = true); void sound_stop(); @@ -1188,9 +1188,6 @@ void ui_sound_init(); void effects_play_sound(const char *sndFile); #ifndef NOSOUND -#ifdef RUN_TESTS -bool TestCalculatePosition(Point soundPosition, int *plVolume, int *plPan); -#endif int GetSFXLength(int nSFX); #endif diff --git a/Source/effects_stubs.cpp b/Source/effects_stubs.cpp index 1e71a83e8..18837ae89 100644 --- a/Source/effects_stubs.cpp +++ b/Source/effects_stubs.cpp @@ -12,7 +12,7 @@ bool effect_is_playing(int nSFX) { return false; } void stream_stop() { } void InitMonsterSND(int monst) { } void FreeMonsterSnd() { } -void PlayEffect(int i, int mode) { } +bool CalculateSoundPosition(Point soundPosition, int *plVolume, int *plPan) { } void PlaySFX(_sfx_id psfx) { } void PlaySfxLoc(_sfx_id psfx, Point position, bool randomizeByCategory) { } void sound_stop() { } diff --git a/Source/inv.cpp b/Source/inv.cpp index 76ff647a7..331bd84dd 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -2145,7 +2145,8 @@ void DoTelekinesis() NetSendCmdParam1(true, CMD_OPOBJT, pcursobj); if (pcursitem != -1) NetSendCmdGItem(true, CMD_REQUESTAGITEM, MyPlayerId, MyPlayerId, pcursitem); - if (pcursmonst != -1 && !M_Talker(pcursmonst) && Monsters[pcursmonst].mtalkmsg == TEXT_NONE) + auto &monter = Monsters[pcursmonst]; + if (pcursmonst != -1 && !M_Talker(monter) && monter.mtalkmsg == TEXT_NONE) NetSendCmdParam1(true, CMD_KNOCKBACK, pcursmonst); NewCursor(CURSOR_HAND); } diff --git a/Source/items.cpp b/Source/items.cpp index 2969fea05..4ab1e4f53 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1394,10 +1394,10 @@ void GetItemBonus(int i, int minlvl, int maxlvl, bool onlygood, bool allowspells } } -int RndUItem(int m) +int RndUItem(MonsterStruct *monster) { - if (m != -1 && (Monsters[m].MData->mTreasure & 0x8000) != 0 && !gbIsMultiplayer) - return -((Monsters[m].MData->mTreasure & 0xFFF) + 1); + if (monster != nullptr && (monster->MData->mTreasure & 0x8000) != 0 && !gbIsMultiplayer) + return -((monster->MData->mTreasure & 0xFFF) + 1); int ril[512]; @@ -1410,8 +1410,8 @@ int RndUItem(int m) bool okflag = true; if (AllItemsList[i].iRnd == IDROP_NEVER) okflag = false; - if (m != -1) { - if (Monsters[m].mLevel < AllItemsList[i].iMinMLvl) + if (monster != nullptr) { + if (monster->mLevel < AllItemsList[i].iMinMLvl) okflag = false; } else { if (2 * curlv < AllItemsList[i].iMinMLvl) @@ -3342,12 +3342,12 @@ void SetupItem(int i) Items[i]._iIdentified = false; } -int RndItem(int m) +int RndItem(const MonsterStruct &monster) { - if ((Monsters[m].MData->mTreasure & 0x8000) != 0) - return -((Monsters[m].MData->mTreasure & 0xFFF) + 1); + if ((monster.MData->mTreasure & 0x8000) != 0) + return -((monster.MData->mTreasure & 0xFFF) + 1); - if ((Monsters[m].MData->mTreasure & 0x4000) != 0) + if ((monster.MData->mTreasure & 0x4000) != 0) return 0; if (GenerateRnd(100) > 40) @@ -3363,12 +3363,12 @@ int RndItem(int m) if (!IsItemAvailable(i)) continue; - if (AllItemsList[i].iRnd == IDROP_DOUBLE && Monsters[m].mLevel >= AllItemsList[i].iMinMLvl + if (AllItemsList[i].iRnd == IDROP_DOUBLE && monster.mLevel >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; ri++; } - if (AllItemsList[i].iRnd != IDROP_NEVER && Monsters[m].mLevel >= AllItemsList[i].iMinMLvl + if (AllItemsList[i].iRnd != IDROP_NEVER && monster.mLevel >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; ri++; @@ -3401,20 +3401,20 @@ void SpawnUnique(_unique_items uid, Point position) SetupItem(ii); } -void SpawnItem(int m, Point position, bool sendmsg) +void SpawnItem(MonsterStruct &monster, Point position, bool sendmsg) { int idx; bool onlygood = true; - if (Monsters[m]._uniqtype != 0 || ((Monsters[m].MData->mTreasure & 0x8000) != 0 && gbIsMultiplayer)) { - idx = RndUItem(m); + if (monster._uniqtype != 0 || ((monster.MData->mTreasure & 0x8000) != 0 && gbIsMultiplayer)) { + idx = RndUItem(&monster); if (idx < 0) { SpawnUnique((_unique_items) - (idx + 1), position); return; } onlygood = true; } else if (Quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || Quests[Q_MUSHROOM]._qvar1 != QS_MUSHGIVEN) { - idx = RndItem(m); + idx = RndItem(monster); if (idx == 0) return; if (idx > 0) { @@ -3434,10 +3434,10 @@ void SpawnItem(int m, Point position, bool sendmsg) int ii = AllocateItem(); GetSuperItemSpace(position, ii); - int uper = Monsters[m]._uniqtype != 0 ? 15 : 1; + int uper = monster._uniqtype != 0 ? 15 : 1; - int8_t mLevel = Monsters[m].MData->mLevel; - if (!gbIsHellfire && Monsters[m].MType->mtype == MT_DIABLO) + int8_t mLevel = monster.MData->mLevel; + if (!gbIsHellfire && monster.MType->mtype == MT_DIABLO) mLevel -= 15; SetupAllItems(ii, idx, AdvanceRndSeed(), mLevel, uper, onlygood, false, false); @@ -3448,7 +3448,7 @@ void SpawnItem(int m, Point position, bool sendmsg) void CreateRndItem(Point position, bool onlygood, bool sendmsg, bool delta) { - int idx = onlygood ? RndUItem(-1) : RndAllItems(); + int idx = onlygood ? RndUItem(nullptr) : RndAllItems(); SetupBaseItem(position, idx, onlygood, sendmsg, delta); } diff --git a/Source/items.h b/Source/items.h index 84b934033..ce37b55cb 100644 --- a/Source/items.h +++ b/Source/items.h @@ -12,6 +12,7 @@ #include "engine/point.hpp" #include "engine.h" #include "itemdat.h" +#include "monster.h" #include "utils/stdcompat/optional.hpp" namespace devilution { @@ -421,9 +422,9 @@ int AllocateItem(); Point GetSuperItemLoc(Point position); void GetItemAttrs(int i, int idata, int lvl); void SetupItem(int i); -int RndItem(int m); +int RndItem(const MonsterStruct &monster); void SpawnUnique(_unique_items uid, Point position); -void SpawnItem(int m, Point position, bool sendmsg); +void SpawnItem(MonsterStruct &monster, Point position, bool sendmsg); void CreateRndItem(Point position, bool onlygood, bool sendmsg, bool delta); void CreateRndUseful(Point position, bool sendmsg); void CreateTypeItem(Point position, bool onlygood, int itype, int imisc, bool sendmsg, bool delta); diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 2c5b29f6c..0c44a4edb 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -532,100 +532,98 @@ void LoadPlayer(LoadHelper *file, int p) bool gbSkipSync = false; -void LoadMonster(LoadHelper *file, int i) +void LoadMonster(LoadHelper *file, MonsterStruct &monster) { - MonsterStruct *pMonster = &Monsters[i]; - - pMonster->_mMTidx = file->NextLE(); - pMonster->_mmode = static_cast(file->NextLE()); - pMonster->_mgoal = static_cast(file->NextLE()); + monster._mMTidx = file->NextLE(); + monster._mmode = static_cast(file->NextLE()); + monster._mgoal = static_cast(file->NextLE()); file->Skip(3); // Alignment - pMonster->_mgoalvar1 = file->NextLE(); - pMonster->_mgoalvar2 = file->NextLE(); - pMonster->_mgoalvar3 = file->NextLE(); + monster._mgoalvar1 = file->NextLE(); + monster._mgoalvar2 = file->NextLE(); + monster._mgoalvar3 = file->NextLE(); file->Skip(4); // Unused - pMonster->_pathcount = file->NextLE(); + monster._pathcount = file->NextLE(); file->Skip(3); // Alignment - pMonster->position.tile.x = file->NextLE(); - pMonster->position.tile.y = file->NextLE(); - pMonster->position.future.x = file->NextLE(); - pMonster->position.future.y = file->NextLE(); - pMonster->position.old.x = file->NextLE(); - pMonster->position.old.y = file->NextLE(); - pMonster->position.offset.deltaX = file->NextLE(); - pMonster->position.offset.deltaY = file->NextLE(); - pMonster->position.velocity.deltaX = file->NextLE(); - pMonster->position.velocity.deltaY = file->NextLE(); - pMonster->_mdir = static_cast(file->NextLE()); - pMonster->_menemy = file->NextLE(); - pMonster->enemyPosition.x = file->NextLE(); - pMonster->enemyPosition.y = file->NextLE(); + monster.position.tile.x = file->NextLE(); + monster.position.tile.y = file->NextLE(); + monster.position.future.x = file->NextLE(); + monster.position.future.y = file->NextLE(); + monster.position.old.x = file->NextLE(); + monster.position.old.y = file->NextLE(); + monster.position.offset.deltaX = file->NextLE(); + monster.position.offset.deltaY = file->NextLE(); + monster.position.velocity.deltaX = file->NextLE(); + monster.position.velocity.deltaY = file->NextLE(); + monster._mdir = static_cast(file->NextLE()); + monster._menemy = file->NextLE(); + monster.enemyPosition.x = file->NextLE(); + monster.enemyPosition.y = file->NextLE(); file->Skip(2); // Unused file->Skip(4); // Skip pointer _mAnimData - pMonster->AnimInfo = {}; - pMonster->AnimInfo.TicksPerFrame = file->NextLE(); - pMonster->AnimInfo.TickCounterOfCurrentFrame = file->NextLE(); - pMonster->AnimInfo.NumberOfFrames = file->NextLE(); - pMonster->AnimInfo.CurrentFrame = file->NextLE(); + monster.AnimInfo = {}; + monster.AnimInfo.TicksPerFrame = file->NextLE(); + monster.AnimInfo.TickCounterOfCurrentFrame = file->NextLE(); + monster.AnimInfo.NumberOfFrames = file->NextLE(); + monster.AnimInfo.CurrentFrame = file->NextLE(); file->Skip(4); // Skip _meflag - pMonster->_mDelFlag = file->NextBool32(); - pMonster->_mVar1 = file->NextLE(); - pMonster->_mVar2 = file->NextLE(); - pMonster->_mVar3 = file->NextLE(); - pMonster->position.temp.x = file->NextLE(); - pMonster->position.temp.y = file->NextLE(); - pMonster->position.offset2.deltaX = file->NextLE(); - pMonster->position.offset2.deltaY = file->NextLE(); + monster._mDelFlag = file->NextBool32(); + monster._mVar1 = file->NextLE(); + monster._mVar2 = file->NextLE(); + monster._mVar3 = file->NextLE(); + monster.position.temp.x = file->NextLE(); + monster.position.temp.y = file->NextLE(); + monster.position.offset2.deltaX = file->NextLE(); + monster.position.offset2.deltaY = file->NextLE(); file->Skip(4); // Skip actionFrame - pMonster->_mmaxhp = file->NextLE(); - pMonster->_mhitpoints = file->NextLE(); + monster._mmaxhp = file->NextLE(); + monster._mhitpoints = file->NextLE(); - pMonster->_mAi = static_cast<_mai_id>(file->NextLE()); - pMonster->_mint = file->NextLE(); + monster._mAi = static_cast<_mai_id>(file->NextLE()); + monster._mint = file->NextLE(); file->Skip(2); // Alignment - pMonster->_mFlags = file->NextLE(); - pMonster->_msquelch = file->NextLE(); + monster._mFlags = file->NextLE(); + monster._msquelch = file->NextLE(); file->Skip(3); // Alignment file->Skip(4); // Unused - pMonster->position.last.x = file->NextLE(); - pMonster->position.last.y = file->NextLE(); - pMonster->_mRndSeed = file->NextLE(); - pMonster->_mAISeed = file->NextLE(); + monster.position.last.x = file->NextLE(); + monster.position.last.y = file->NextLE(); + monster._mRndSeed = file->NextLE(); + monster._mAISeed = file->NextLE(); file->Skip(4); // Unused - pMonster->_uniqtype = file->NextLE(); - pMonster->_uniqtrans = file->NextLE(); - pMonster->_udeadval = file->NextLE(); + monster._uniqtype = file->NextLE(); + monster._uniqtrans = file->NextLE(); + monster._udeadval = file->NextLE(); - pMonster->mWhoHit = file->NextLE(); - pMonster->mLevel = file->NextLE(); + monster.mWhoHit = file->NextLE(); + monster.mLevel = file->NextLE(); file->Skip(1); // Alignment - pMonster->mExp = file->NextLE(); + monster.mExp = file->NextLE(); - if (i < MAX_PLRS) // Don't skip for golems - pMonster->mHit = file->NextLE(); + if ((monster._mFlags & MFLAG_GOLEM) != 0) // Don't skip for golems + monster.mHit = file->NextLE(); else file->Skip(1); // Skip mHit as it's already initialized - pMonster->mMinDamage = file->NextLE(); - pMonster->mMaxDamage = file->NextLE(); + monster.mMinDamage = file->NextLE(); + monster.mMaxDamage = file->NextLE(); file->Skip(1); // Skip mHit2 as it's already initialized - pMonster->mMinDamage2 = file->NextLE(); - pMonster->mMaxDamage2 = file->NextLE(); - pMonster->mArmorClass = file->NextLE(); + monster.mMinDamage2 = file->NextLE(); + monster.mMaxDamage2 = file->NextLE(); + monster.mArmorClass = file->NextLE(); file->Skip(1); // Alignment - pMonster->mMagicRes = file->NextLE(); + monster.mMagicRes = file->NextLE(); file->Skip(2); // Alignment - pMonster->mtalkmsg = static_cast<_speech_id>(file->NextLE()); - if (pMonster->mtalkmsg == TEXT_KING1) // Fix original bad mapping of NONE for monsters - pMonster->mtalkmsg = TEXT_NONE; - pMonster->leader = file->NextLE(); - pMonster->leaderflag = file->NextLE(); - pMonster->packsize = file->NextLE(); - pMonster->mlid = file->NextLE(); - if (pMonster->mlid == Players[MyPlayerId]._plid) - pMonster->mlid = NO_LIGHT; // Correct incorect values in old saves + monster.mtalkmsg = static_cast<_speech_id>(file->NextLE()); + if (monster.mtalkmsg == TEXT_KING1) // Fix original bad mapping of NONE for monsters + monster.mtalkmsg = TEXT_NONE; + monster.leader = file->NextLE(); + monster.leaderflag = file->NextLE(); + monster.packsize = file->NextLE(); + monster.mlid = file->NextLE(); + if (monster.mlid == Players[MyPlayerId]._plid) + monster.mlid = NO_LIGHT; // Correct incorect values in old saves // Omit pointer mName; // Omit pointer MType; @@ -634,7 +632,7 @@ void LoadMonster(LoadHelper *file, int i) if (gbSkipSync) return; - SyncMonsterAnim(i); + SyncMonsterAnim(monster); } void LoadMissile(LoadHelper *file, int i) @@ -1196,92 +1194,90 @@ void SavePlayer(SaveHelper *file, int p) // Omit pointer pReserved } -void SaveMonster(SaveHelper *file, int i) +void SaveMonster(SaveHelper *file, MonsterStruct &monster) { - MonsterStruct *pMonster = &Monsters[i]; - - file->WriteLE(pMonster->_mMTidx); - file->WriteLE(pMonster->_mmode); - file->WriteLE(pMonster->_mgoal); + file->WriteLE(monster._mMTidx); + file->WriteLE(monster._mmode); + file->WriteLE(monster._mgoal); file->Skip(3); // Alignment - file->WriteLE(pMonster->_mgoalvar1); - file->WriteLE(pMonster->_mgoalvar2); - file->WriteLE(pMonster->_mgoalvar3); + file->WriteLE(monster._mgoalvar1); + file->WriteLE(monster._mgoalvar2); + file->WriteLE(monster._mgoalvar3); file->Skip(4); // Unused - file->WriteLE(pMonster->_pathcount); + file->WriteLE(monster._pathcount); file->Skip(3); // Alignment - file->WriteLE(pMonster->position.tile.x); - file->WriteLE(pMonster->position.tile.y); - file->WriteLE(pMonster->position.future.x); - file->WriteLE(pMonster->position.future.y); - file->WriteLE(pMonster->position.old.x); - file->WriteLE(pMonster->position.old.y); - file->WriteLE(pMonster->position.offset.deltaX); - file->WriteLE(pMonster->position.offset.deltaY); - file->WriteLE(pMonster->position.velocity.deltaX); - file->WriteLE(pMonster->position.velocity.deltaY); - file->WriteLE(pMonster->_mdir); - file->WriteLE(pMonster->_menemy); - file->WriteLE(pMonster->enemyPosition.x); - file->WriteLE(pMonster->enemyPosition.y); + file->WriteLE(monster.position.tile.x); + file->WriteLE(monster.position.tile.y); + file->WriteLE(monster.position.future.x); + file->WriteLE(monster.position.future.y); + file->WriteLE(monster.position.old.x); + file->WriteLE(monster.position.old.y); + file->WriteLE(monster.position.offset.deltaX); + file->WriteLE(monster.position.offset.deltaY); + file->WriteLE(monster.position.velocity.deltaX); + file->WriteLE(monster.position.velocity.deltaY); + file->WriteLE(monster._mdir); + file->WriteLE(monster._menemy); + file->WriteLE(monster.enemyPosition.x); + file->WriteLE(monster.enemyPosition.y); file->Skip(2); // Unused file->Skip(4); // Skip pointer _mAnimData - file->WriteLE(pMonster->AnimInfo.TicksPerFrame); - file->WriteLE(pMonster->AnimInfo.TickCounterOfCurrentFrame); - file->WriteLE(pMonster->AnimInfo.NumberOfFrames); - file->WriteLE(pMonster->AnimInfo.CurrentFrame); + file->WriteLE(monster.AnimInfo.TicksPerFrame); + file->WriteLE(monster.AnimInfo.TickCounterOfCurrentFrame); + file->WriteLE(monster.AnimInfo.NumberOfFrames); + file->WriteLE(monster.AnimInfo.CurrentFrame); file->Skip(); // Skip _meflag - file->WriteLE(pMonster->_mDelFlag ? 1 : 0); - file->WriteLE(pMonster->_mVar1); - file->WriteLE(pMonster->_mVar2); - file->WriteLE(pMonster->_mVar3); - file->WriteLE(pMonster->position.temp.x); - file->WriteLE(pMonster->position.temp.y); - file->WriteLE(pMonster->position.offset2.deltaX); - file->WriteLE(pMonster->position.offset2.deltaY); + file->WriteLE(monster._mDelFlag ? 1 : 0); + file->WriteLE(monster._mVar1); + file->WriteLE(monster._mVar2); + file->WriteLE(monster._mVar3); + file->WriteLE(monster.position.temp.x); + file->WriteLE(monster.position.temp.y); + file->WriteLE(monster.position.offset2.deltaX); + file->WriteLE(monster.position.offset2.deltaY); file->Skip(); // Skip _mVar8 - file->WriteLE(pMonster->_mmaxhp); - file->WriteLE(pMonster->_mhitpoints); + file->WriteLE(monster._mmaxhp); + file->WriteLE(monster._mhitpoints); - file->WriteLE(pMonster->_mAi); - file->WriteLE(pMonster->_mint); + file->WriteLE(monster._mAi); + file->WriteLE(monster._mint); file->Skip(2); // Alignment - file->WriteLE(pMonster->_mFlags); - file->WriteLE(pMonster->_msquelch); + file->WriteLE(monster._mFlags); + file->WriteLE(monster._msquelch); file->Skip(3); // Alignment file->Skip(4); // Unused - file->WriteLE(pMonster->position.last.x); - file->WriteLE(pMonster->position.last.y); - file->WriteLE(pMonster->_mRndSeed); - file->WriteLE(pMonster->_mAISeed); + file->WriteLE(monster.position.last.x); + file->WriteLE(monster.position.last.y); + file->WriteLE(monster._mRndSeed); + file->WriteLE(monster._mAISeed); file->Skip(4); // Unused - file->WriteLE(pMonster->_uniqtype); - file->WriteLE(pMonster->_uniqtrans); - file->WriteLE(pMonster->_udeadval); + file->WriteLE(monster._uniqtype); + file->WriteLE(monster._uniqtrans); + file->WriteLE(monster._udeadval); - file->WriteLE(pMonster->mWhoHit); - file->WriteLE(pMonster->mLevel); + file->WriteLE(monster.mWhoHit); + file->WriteLE(monster.mLevel); file->Skip(1); // Alignment - file->WriteLE(pMonster->mExp); - - file->WriteLE(std::min(pMonster->mHit, std::numeric_limits::max())); // For backwards compatibility - file->WriteLE(pMonster->mMinDamage); - file->WriteLE(pMonster->mMaxDamage); - file->WriteLE(std::min(pMonster->mHit2, std::numeric_limits::max())); // For backwards compatibility - file->WriteLE(pMonster->mMinDamage2); - file->WriteLE(pMonster->mMaxDamage2); - file->WriteLE(pMonster->mArmorClass); + file->WriteLE(monster.mExp); + + file->WriteLE(std::min(monster.mHit, std::numeric_limits::max())); // For backwards compatibility + file->WriteLE(monster.mMinDamage); + file->WriteLE(monster.mMaxDamage); + file->WriteLE(std::min(monster.mHit2, std::numeric_limits::max())); // For backwards compatibility + file->WriteLE(monster.mMinDamage2); + file->WriteLE(monster.mMaxDamage2); + file->WriteLE(monster.mArmorClass); file->Skip(1); // Alignment - file->WriteLE(pMonster->mMagicRes); + file->WriteLE(monster.mMagicRes); file->Skip(2); // Alignment - file->WriteLE(pMonster->mtalkmsg == TEXT_NONE ? 0 : pMonster->mtalkmsg); // Replicate original bad mapping of none for monsters - file->WriteLE(pMonster->leader); - file->WriteLE(pMonster->leaderflag); - file->WriteLE(pMonster->packsize); - file->WriteLE(pMonster->mlid); + file->WriteLE(monster.mtalkmsg == TEXT_NONE ? 0 : monster.mtalkmsg); // Replicate original bad mapping of none for monsters + file->WriteLE(monster.leader); + file->WriteLE(monster.leaderflag); + file->WriteLE(monster.packsize); + file->WriteLE(monster.mlid); // Omit pointer mName; // Omit pointer MType; @@ -1739,7 +1735,7 @@ void LoadGame(bool firstflag) for (int &monsterId : ActiveMonsters) monsterId = file.NextBE(); for (int i = 0; i < ActiveMonsterCount; i++) - LoadMonster(&file, ActiveMonsters[i]); + LoadMonster(&file, Monsters[ActiveMonsters[i]]); for (int &missileId : ActiveMissiles) missileId = file.NextLE(); for (int &missileId : AvailableMissiles) @@ -1930,7 +1926,7 @@ void SaveGameData() for (int monsterId : ActiveMonsters) file.WriteBE(monsterId); for (int i = 0; i < ActiveMonsterCount; i++) - SaveMonster(&file, ActiveMonsters[i]); + SaveMonster(&file, Monsters[ActiveMonsters[i]]); for (int missileId : ActiveMissiles) file.WriteLE(missileId); for (int missileId : AvailableMissiles) @@ -2059,7 +2055,7 @@ void SaveLevel() for (int monsterId : ActiveMonsters) file.WriteBE(monsterId); for (int i = 0; i < ActiveMonsterCount; i++) - SaveMonster(&file, ActiveMonsters[i]); + SaveMonster(&file, Monsters[ActiveMonsters[i]]); for (int objectId : ActiveObjects) file.WriteLE(objectId); for (int objectId : AvailableObjects) @@ -2142,7 +2138,7 @@ void LoadLevel() for (int &monsterId : ActiveMonsters) monsterId = file.NextBE(); for (int i = 0; i < ActiveMonsterCount; i++) - LoadMonster(&file, ActiveMonsters[i]); + LoadMonster(&file, Monsters[ActiveMonsters[i]]); for (int &objectId : ActiveObjects) objectId = file.NextLE(); for (int &objectId : AvailableObjects) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 847fa4fc4..1b2c493c4 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -16,6 +16,7 @@ #include "init.h" #include "inv.h" #include "lighting.h" +#include "monster.h" #include "spells.h" #include "trigs.h" @@ -84,7 +85,7 @@ inline bool InDungeonBounds(Point position) return position.x > 0 && position.x < MAXDUNX && position.y > 0 && position.y < MAXDUNY; } -int FindClosest(Point source, int rad) +MonsterStruct *FindClosest(Point source, int rad) { if (rad > 19) rad = 19; @@ -98,11 +99,11 @@ int FindClosest(Point source, int rad) if (InDungeonBounds({ tx, ty })) { int mid = dMonster[tx][ty]; if (mid > 0 && !CheckBlock(source, { tx, ty })) - return mid - 1; + return &Monsters[mid - 1]; } } } - return -1; + return nullptr; } constexpr Direction16 Direction16Flip(Direction16 x, Direction16 pivot) @@ -197,7 +198,7 @@ void MoveMissilePos(int i) } int x = Missiles[i].position.tile.x + dx; int y = Missiles[i].position.tile.y + dy; - if (PosOkMonst(Missiles[i]._misource, { x, y })) { + if (MonsterIsTileAvalible(Missiles[i]._misource, { x, y })) { Missiles[i].position.tile.x += dx; Missiles[i].position.tile.y += dy; Missiles[i].position.offset.deltaX += (dy * 32) - (dx * 32); @@ -207,18 +208,20 @@ void MoveMissilePos(int i) bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool shift) { + auto &monster = Monsters[m]; + bool resist = false; - if (Monsters[m].mtalkmsg != TEXT_NONE - || Monsters[m]._mhitpoints >> 6 <= 0 - || (t == MIS_HBOLT && Monsters[m].MType->mtype != MT_DIABLO && Monsters[m].MData->mMonstClass != MC_UNDEAD)) { + if (monster.mtalkmsg != TEXT_NONE + || monster._mhitpoints >> 6 <= 0 + || (t == MIS_HBOLT && monster.MType->mtype != MT_DIABLO && monster.MData->mMonstClass != MC_UNDEAD)) { return false; } - if (Monsters[m].MType->mtype == MT_ILLWEAV && Monsters[m]._mgoal == MGOAL_RETREAT) + if (monster.MType->mtype == MT_ILLWEAV && monster._mgoal == MGOAL_RETREAT) return false; - if (Monsters[m]._mmode == MM_CHARGE) + if (monster._mmode == MM_CHARGE) return false; - uint8_t mor = Monsters[m].mMagicRes; + uint8_t mor = monster.mMagicRes; missile_resistance mir = MissileData[t].mResist; if (((mor & IMMUNE_MAGIC) != 0 && mir == MISR_MAGIC) @@ -232,7 +235,7 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool || ((mor & RESIST_LIGHTNING) != 0 && mir == MISR_LIGHTNING)) resist = true; - if (gbIsHellfire && t == MIS_HBOLT && (Monsters[m].MType->mtype == MT_DIABLO || Monsters[m].MType->mtype == MT_BONEDEMN)) + if (gbIsHellfire && t == MIS_HBOLT && (monster.MType->mtype == MT_DIABLO || monster.MType->mtype == MT_BONEDEMN)) resist = true; int hit = GenerateRnd(100); @@ -243,7 +246,7 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool hper = player._pDexterity; hper += player._pIBonusToHit; hper += player._pLevel; - hper -= Monsters[m].mArmorClass; + hper -= monster.mArmorClass; hper -= (dist * dist) / 2; hper += player._pIEnAc; hper += 50; @@ -252,23 +255,23 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool if (player._pClass == HeroClass::Warrior || player._pClass == HeroClass::Bard) hper += 10; } else { - hper = player._pMagic - (Monsters[m].mLevel * 2) - dist + 50; + hper = player._pMagic - (monster.mLevel * 2) - dist + 50; if (player._pClass == HeroClass::Sorcerer) hper += 20; else if (player._pClass == HeroClass::Bard) hper += 10; } } else { - hper = GenerateRnd(75) - Monsters[m].mLevel * 2; + hper = GenerateRnd(75) - monster.mLevel * 2; } hper = clamp(hper, 5, 95); - if (Monsters[m]._mmode == MM_STONE) + if (monster._mmode == MM_STONE) hit = 0; bool ret = false; - if (CheckMonsterHit(m, &ret)) + if (CheckMonsterHit(monster, &ret)) return ret; #ifdef _DEBUG @@ -281,7 +284,7 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool int dam; if (t == MIS_BONESPIRIT) { - dam = Monsters[m]._mhitpoints / 3 >> 6; + dam = monster._mhitpoints / 3 >> 6; } else { dam = mindam + GenerateRnd(maxdam - mindam + 1); } @@ -301,25 +304,25 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool dam >>= 2; if (pnum == MyPlayerId) - Monsters[m]._mhitpoints -= dam; + monster._mhitpoints -= dam; if ((gbIsHellfire && (Players[pnum]._pIFlags & ISPL_NOHEALMON) != 0) || (!gbIsHellfire && (Players[pnum]._pIFlags & ISPL_FIRE_ARROWS) != 0)) - Monsters[m]._mFlags |= MFLAG_NOHEAL; + monster._mFlags |= MFLAG_NOHEAL; - if (Monsters[m]._mhitpoints >> 6 <= 0) { - if (Monsters[m]._mmode == MM_STONE) { + if (monster._mhitpoints >> 6 <= 0) { + if (monster._mmode == MM_STONE) { M_StartKill(m, pnum); - Monsters[m].Petrify(); + monster.Petrify(); } else { M_StartKill(m, pnum); } } else { if (resist) { - PlayEffect(m, 1); - } else if (Monsters[m]._mmode == MM_STONE) { + PlayEffect(monster, 1); + } else if (monster._mmode == MM_STONE) { if (m > MAX_PLRS - 1) M_StartHit(m, pnum, dam); - Monsters[m].Petrify(); + monster.Petrify(); } else { if (MissileData[t].mType == 0 && (Players[pnum]._pIFlags & ISPL_KNOCKBACK) != 0) { M_GetKnockback(m); @@ -329,9 +332,9 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, bool } } - if (Monsters[m]._msquelch == 0) { - Monsters[m]._msquelch = UINT8_MAX; - Monsters[m].position.last = Players[pnum].position.tile; + if (monster._msquelch == 0) { + monster._msquelch = UINT8_MAX; + monster.position.last = Players[pnum].position.tile; } return true; @@ -518,7 +521,8 @@ void CheckMissileCol(int i, int mindam, int maxdam, bool shift, Point position, Missiles[i]._miHitFlag = true; } } else { - if ((Monsters[Missiles[i]._misource]._mFlags & MFLAG_TARGETS_MONSTER) != 0 + auto &monster = Monsters[Missiles[i]._misource]; + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0 && dMonster[mx][my] > 0 && (Monsters[dMonster[mx][my] - 1]._mFlags & MFLAG_GOLEM) != 0 && MonsterTrapHit(dMonster[mx][my] - 1, mindam, maxdam, Missiles[i]._midist, Missiles[i]._mitype, shift)) { @@ -529,7 +533,7 @@ void CheckMissileCol(int i, int mindam, int maxdam, bool shift, Point position, if (dPlayer[mx][my] > 0 && PlayerMHit( dPlayer[mx][my] - 1, - Missiles[i]._misource, + &monster, Missiles[i]._midist, mindam, maxdam, @@ -576,7 +580,7 @@ void CheckMissileCol(int i, int mindam, int maxdam, bool shift, Point position, if (dPlayer[mx][my] > 0) { if (PlayerMHit( dPlayer[mx][my] - 1, - -1, + nullptr, Missiles[i]._midist, mindam, maxdam, @@ -1022,20 +1026,22 @@ void DeleteMissile(int mi, int i) bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, bool shift) { + auto &monster = Monsters[m]; + bool resist = false; - if (Monsters[m].mtalkmsg != TEXT_NONE) { + if (monster.mtalkmsg != TEXT_NONE) { return false; } - if (Monsters[m]._mhitpoints >> 6 <= 0) { + if (monster._mhitpoints >> 6 <= 0) { return false; } - if (Monsters[m].MType->mtype == MT_ILLWEAV && Monsters[m]._mgoal == MGOAL_RETREAT) + if (monster.MType->mtype == MT_ILLWEAV && monster._mgoal == MGOAL_RETREAT) return false; - if (Monsters[m]._mmode == MM_CHARGE) + if (monster._mmode == MM_CHARGE) return false; missile_resistance mir = MissileData[t].mResist; - int mor = Monsters[m].mMagicRes; + int mor = monster.mMagicRes; if (((mor & IMMUNE_MAGIC) != 0 && mir == MISR_MAGIC) || ((mor & IMMUNE_FIRE) != 0 && mir == MISR_FIRE) || ((mor & IMMUNE_LIGHTNING) != 0 && mir == MISR_LIGHTNING)) { @@ -1049,45 +1055,45 @@ bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, bool shift) } int hit = GenerateRnd(100); - int hper = 90 - (BYTE)Monsters[m].mArmorClass - dist; + int hper = 90 - (BYTE)monster.mArmorClass - dist; if (hper < 5) hper = 5; if (hper > 95) hper = 95; bool ret; - if (CheckMonsterHit(m, &ret)) { + if (CheckMonsterHit(monster, &ret)) { return ret; } #ifdef _DEBUG - if (hit < hper || debug_mode_dollar_sign || debug_mode_key_inverted_v || Monsters[m]._mmode == MM_STONE) { + if (hit < hper || debug_mode_dollar_sign || debug_mode_key_inverted_v || monster._mmode == MM_STONE) { #else - if (hit < hper || Monsters[m]._mmode == MM_STONE) { + if (hit < hper || monster._mmode == MM_STONE) { #endif int dam = mindam + GenerateRnd(maxdam - mindam + 1); if (!shift) dam <<= 6; if (resist) - Monsters[m]._mhitpoints -= dam / 4; + monster._mhitpoints -= dam / 4; else - Monsters[m]._mhitpoints -= dam; + monster._mhitpoints -= dam; #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) - Monsters[m]._mhitpoints = 0; + monster._mhitpoints = 0; #endif - if (Monsters[m]._mhitpoints >> 6 <= 0) { - if (Monsters[m]._mmode == MM_STONE) { + if (monster._mhitpoints >> 6 <= 0) { + if (monster._mmode == MM_STONE) { M_StartKill(m, -1); - Monsters[m].Petrify(); + monster.Petrify(); } else { M_StartKill(m, -1); } } else { if (resist) { - PlayEffect(m, 1); - } else if (Monsters[m]._mmode == MM_STONE) { + PlayEffect(monster, 1); + } else if (monster._mmode == MM_STONE) { if (m > MAX_PLRS - 1) M_StartHit(m, -1, dam); - Monsters[m].Petrify(); + monster.Petrify(); } else { if (m > MAX_PLRS - 1) M_StartHit(m, -1, dam); @@ -1098,7 +1104,7 @@ bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, bool shift) return false; } -bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool shift, int earflag, bool *blocked) +bool PlayerMHit(int pnum, MonsterStruct *monster, int dist, int mind, int maxd, int mtype, bool shift, int earflag, bool *blocked) { *blocked = false; @@ -1124,16 +1130,16 @@ bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool s int hper = 40; if (MissileData[mtype].mType == 0) { int tac = player._pIAC + player._pIBonusAC + player._pDexterity / 5; - if (m != -1) { - hper = Monsters[m].mHit - + ((Monsters[m].mLevel - player._pLevel) * 2) + if (monster != nullptr) { + hper = monster->mHit + + ((monster->mLevel - player._pLevel) * 2) + 30 - (dist * 2) - tac; } else { hper = 100 - (tac / 2) - (dist * 2); } - } else if (m != -1) { - hper += (Monsters[m].mLevel * 2) - (player._pLevel * 2) - (dist * 2); + } else if (monster != nullptr) { + hper += (monster->mLevel * 2) - (player._pLevel * 2) - (dist * 2); } if (hper < 10) @@ -1159,8 +1165,8 @@ bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool s blk = 100; int blkper = player._pBaseToBlk + player._pDexterity; - if (m != -1) - blkper -= (Monsters[m].mLevel - player._pLevel) * 2; + if (monster != nullptr) + blkper -= (monster->mLevel - player._pLevel) * 2; if (blkper < 0) blkper = 0; @@ -1194,13 +1200,13 @@ bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool s } else { if (!shift) { dam = (mind << 6) + GenerateRnd((maxd - mind + 1) << 6); - if (m == -1) + if (monster == nullptr) if ((player._pIFlags & ISPL_ABSHALFTRAP) != 0) dam /= 2; dam += (player._pIGetHit << 6); } else { dam = mind + GenerateRnd(maxd - mind + 1); - if (m == -1) + if (monster == nullptr) if ((player._pIFlags & ISPL_ABSHALFTRAP) != 0) dam /= 2; dam += player._pIGetHit; @@ -1211,8 +1217,8 @@ bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool s if ((resper <= 0 || gbIsHellfire) && blk < blkper) { Direction dir = player._pdir; - if (m != -1) { - dir = GetDirection(player.position.tile, Monsters[m].position.tile); + if (monster != nullptr) { + dir = GetDirection(player.position.tile, monster->position.tile); } *blocked = true; StartPlrBlock(pnum, dir); @@ -1481,27 +1487,28 @@ void AddBerserk(int mi, Point /*src*/, Point dst, int /*midir*/, int8_t /*mienem dm = dm > 0 ? dm - 1 : -(dm + 1); if (dm <= 3) continue; + auto &monster = Monsters[dm]; - if (Monsters[dm]._uniqtype != 0 || Monsters[dm]._mAi == AI_DIABLO) + if (monster._uniqtype != 0 || monster._mAi == AI_DIABLO) continue; - if (Monsters[dm]._mmode == MM_FADEIN || Monsters[dm]._mmode == MM_FADEOUT) + if (monster._mmode == MM_FADEIN || monster._mmode == MM_FADEOUT) continue; - if ((Monsters[dm].mMagicRes & IMMUNE_MAGIC) != 0) + if ((monster.mMagicRes & IMMUNE_MAGIC) != 0) continue; - if ((Monsters[dm].mMagicRes & RESIST_MAGIC) != 0 && ((Monsters[dm].mMagicRes & RESIST_MAGIC) != 1 || GenerateRnd(2) != 0)) + if ((monster.mMagicRes & RESIST_MAGIC) != 0 && ((monster.mMagicRes & RESIST_MAGIC) != 1 || GenerateRnd(2) != 0)) continue; - if (Monsters[dm]._mmode == MM_CHARGE) + if (monster._mmode == MM_CHARGE) continue; i = 6; auto slvl = GetSpellLevel(id, SPL_BERSERK); - Monsters[dm]._mFlags |= MFLAG_BERSERK | MFLAG_GOLEM; - Monsters[dm].mMinDamage = (GenerateRnd(10) + 120) * Monsters[dm].mMinDamage / 100 + slvl; - Monsters[dm].mMaxDamage = (GenerateRnd(10) + 120) * Monsters[dm].mMaxDamage / 100 + slvl; - Monsters[dm].mMinDamage2 = (GenerateRnd(10) + 120) * Monsters[dm].mMinDamage2 / 100 + slvl; - Monsters[dm].mMaxDamage2 = (GenerateRnd(10) + 120) * Monsters[dm].mMaxDamage2 / 100 + slvl; + monster._mFlags |= MFLAG_BERSERK | MFLAG_GOLEM; + monster.mMinDamage = (GenerateRnd(10) + 120) * monster.mMinDamage / 100 + slvl; + monster.mMaxDamage = (GenerateRnd(10) + 120) * monster.mMaxDamage / 100 + slvl; + monster.mMinDamage2 = (GenerateRnd(10) + 120) * monster.mMinDamage2 / 100 + slvl; + monster.mMaxDamage2 = (GenerateRnd(10) + 120) * monster.mMaxDamage2 / 100 + slvl; int r = (currlevel < 17 || currlevel > 20) ? 3 : 9; - Monsters[dm].mlid = AddLight(Monsters[dm].position.tile, r); + monster.mlid = AddLight(monster.position.tile, r); UseMana(id, SPL_BERSERK); break; } @@ -2479,33 +2486,36 @@ void InitMissileAnimationFromMonster(MissileStruct &mis, int midir, const Monste void AddRhino(int mi, Point src, Point dst, int midir, int8_t /*mienemy*/, int id, int /*dam*/) { + auto &monster = Monsters[id]; + MonsterGraphic graphic = MonsterGraphic::Special; - if (Monsters[id].MType->mtype < MT_HORNED || Monsters[id].MType->mtype > MT_OBLORD) { - if (Monsters[id].MType->mtype < MT_NSNAKE || Monsters[id].MType->mtype > MT_GSNAKE) { + if (monster.MType->mtype < MT_HORNED || monster.MType->mtype > MT_OBLORD) { + if (monster.MType->mtype < MT_NSNAKE || monster.MType->mtype > MT_GSNAKE) { graphic = MonsterGraphic::Walk; } else { graphic = MonsterGraphic::Attack; } } UpdateMissileVelocity(mi, src, dst, 18); - InitMissileAnimationFromMonster(Missiles[mi], midir, Monsters[id], graphic); - if (Monsters[id].MType->mtype >= MT_NSNAKE && Monsters[id].MType->mtype <= MT_GSNAKE) + InitMissileAnimationFromMonster(Missiles[mi], midir, monster, graphic); + if (monster.MType->mtype >= MT_NSNAKE && monster.MType->mtype <= MT_GSNAKE) Missiles[mi]._miAnimFrame = 7; - if (Monsters[id]._uniqtype != 0) { - Missiles[mi]._miUniqTrans = Monsters[id]._uniqtrans + 1; - Missiles[mi]._mlid = Monsters[id].mlid; + if (monster._uniqtype != 0) { + Missiles[mi]._miUniqTrans = monster._uniqtrans + 1; + Missiles[mi]._mlid = monster.mlid; } PutMissile(mi); } void AddFireman(int mi, Point src, Point dst, int midir, int8_t /*mienemy*/, int id, int /*dam*/) { + auto &monster = Monsters[id]; + UpdateMissileVelocity(mi, src, dst, 16); - auto &mon = Monsters[id]; - InitMissileAnimationFromMonster(Missiles[mi], midir, mon, MonsterGraphic::Walk); - if (mon._uniqtype != 0) - Missiles[mi]._miUniqTrans = mon._uniqtrans + 1; - dMonster[mon.position.tile.x][mon.position.tile.y] = 0; + InitMissileAnimationFromMonster(Missiles[mi], midir, monster, MonsterGraphic::Walk); + if (monster._uniqtype != 0) + Missiles[mi]._miUniqTrans = monster._uniqtrans + 1; + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; PutMissile(mi); } @@ -2522,17 +2532,16 @@ void AddFlare(int mi, Point src, Point dst, int midir, int8_t mienemy, int id, i if (mienemy == TARGET_MONSTERS) { UseMana(id, SPL_FLARE); ApplyPlrDamage(id, 5); - } else { - if (id > 0) { - if (Monsters[id].MType->mtype == MT_SUCCUBUS) - SetMissAnim(mi, MFILE_FLARE); - if (Monsters[id].MType->mtype == MT_SNOWWICH) - SetMissAnim(mi, MFILE_SCUBMISB); - if (Monsters[id].MType->mtype == MT_HLSPWN) - SetMissAnim(mi, MFILE_SCUBMISD); - if (Monsters[id].MType->mtype == MT_SOLBRNR) - SetMissAnim(mi, MFILE_SCUBMISC); - } + } else if (id > 0) { + auto &monster = Monsters[id]; + if (monster.MType->mtype == MT_SUCCUBUS) + SetMissAnim(mi, MFILE_FLARE); + if (monster.MType->mtype == MT_SNOWWICH) + SetMissAnim(mi, MFILE_SCUBMISB); + if (monster.MType->mtype == MT_HLSPWN) + SetMissAnim(mi, MFILE_SCUBMISD); + if (monster.MType->mtype == MT_SOLBRNR) + SetMissAnim(mi, MFILE_SCUBMISC); } if (MissileSpriteData[Missiles[mi]._miAnimType].mAnimFAmt == 16) { @@ -2589,13 +2598,14 @@ void AddStone(int mi, Point /*src*/, Point dst, int /*midir*/, int8_t /*mienemy* if (InDungeonBounds({ tx, ty })) { int mid = dMonster[tx][ty]; mid = mid > 0 ? mid - 1 : -(mid + 1); - if (mid > MAX_PLRS - 1 && Monsters[mid]._mAi != AI_DIABLO && Monsters[mid].MType->mtype != MT_NAKRUL) { - if (Monsters[mid]._mmode != MM_FADEIN && Monsters[mid]._mmode != MM_FADEOUT && Monsters[mid]._mmode != MM_CHARGE) { + auto &monster = Monsters[mid]; + if (mid > MAX_PLRS - 1 && monster._mAi != AI_DIABLO && monster.MType->mtype != MT_NAKRUL) { + if (monster._mmode != MM_FADEIN && monster._mmode != MM_FADEOUT && monster._mmode != MM_CHARGE) { faded = true; i = 6; - Missiles[mi]._miVar1 = Monsters[mid]._mmode; + Missiles[mi]._miVar1 = monster._mmode; Missiles[mi]._miVar2 = mid; - Monsters[mid].Petrify(); + monster.Petrify(); break; } } @@ -2936,7 +2946,8 @@ void AddFlame(int mi, Point src, Point dst, int midir, int8_t mienemy, int id, i int i = GenerateRnd(Players[id]._pLevel) + GenerateRnd(2); Missiles[mi]._midam = 8 * i + 16 + ((8 * i + 16) / 2); } else { - Missiles[mi]._midam = Monsters[id].mMinDamage + GenerateRnd(Monsters[id].mMaxDamage - Monsters[id].mMinDamage + 1); + auto &monster = Monsters[id]; + Missiles[mi]._midam = monster.mMinDamage + GenerateRnd(monster.mMaxDamage - monster.mMinDamage + 1); } } @@ -3300,7 +3311,8 @@ void MI_Firebolt(int i) break; } } else { - d = Monsters[p].mMinDamage + GenerateRnd(Monsters[p].mMaxDamage - Monsters[p].mMinDamage + 1); + auto &monster = Monsters[p]; + d = monster.mMinDamage + GenerateRnd(monster.mMaxDamage - monster.mMinDamage + 1); } } else { d = currlevel + GenerateRnd(2 * currlevel); @@ -3468,8 +3480,8 @@ void MI_HorkSpawn(int mi) if (!nSolidTable[dp] && dMonster[tx][ty] == 0 && dPlayer[tx][ty] == 0 && dObject[tx][ty] == 0) { i = 6; auto md = static_cast(Missiles[mi]._miVar1); - int mon = AddMonster({ tx, ty }, md, 1, true); - M_StartStand(mon, md); + int monsterId = AddMonster({ tx, ty }, md, 1, true); + M_StartStand(Monsters[monsterId], md); break; } } @@ -3771,7 +3783,8 @@ void MI_Lightctrl(int i) if (Missiles[i]._micaster == TARGET_MONSTERS) { dam = (GenerateRnd(2) + GenerateRnd(Players[id]._pLevel) + 2) << 6; } else { - dam = 2 * (Monsters[id].mMinDamage + GenerateRnd(Monsters[id].mMaxDamage - Monsters[id].mMinDamage + 1)); + auto &monster = Monsters[id]; + dam = 2 * (monster.mMinDamage + GenerateRnd(monster.mMaxDamage - monster.mMinDamage + 1)); } } else { dam = GenerateRnd(currlevel) + 2 * currlevel; @@ -4215,25 +4228,25 @@ void MI_Teleport(int i) void MI_Stone(int i) { Missiles[i]._mirange--; - int m = Missiles[i]._miVar2; - if (Monsters[m]._mhitpoints == 0 && Missiles[i]._miAnimType != MFILE_SHATTER1) { + auto &monster = Monsters[Missiles[i]._miVar2]; + if (monster._mhitpoints == 0 && Missiles[i]._miAnimType != MFILE_SHATTER1) { Missiles[i]._mimfnum = 0; Missiles[i]._miDrawFlag = true; SetMissAnim(i, MFILE_SHATTER1); Missiles[i]._mirange = 11; } - if (Monsters[m]._mmode != MM_STONE) { + if (monster._mmode != MM_STONE) { Missiles[i]._miDelFlag = true; return; } if (Missiles[i]._mirange == 0) { Missiles[i]._miDelFlag = true; - if (Monsters[m]._mhitpoints > 0) { - Monsters[m]._mmode = (MON_MODE)Missiles[i]._miVar1; - Monsters[m].AnimInfo.IsPetrified = false; + if (monster._mhitpoints > 0) { + monster._mmode = (MON_MODE)Missiles[i]._miVar1; + monster.AnimInfo.IsPetrified = false; } else { - AddDead(Monsters[m].position.tile, stonendx, Monsters[m]._mdir); + AddDead(monster.position.tile, stonendx, monster._mdir); } } if (Missiles[i]._miAnimType == MFILE_SHATTER1) @@ -4255,7 +4268,8 @@ void MI_Boom(int i) void MI_Rhino(int i) { int monst = Missiles[i]._misource; - if (Monsters[monst]._mmode != MM_CHARGE) { + auto &monster = Monsters[monst]; + if (monster._mmode != MM_CHARGE) { Missiles[i]._miDelFlag = true; return; } @@ -4263,7 +4277,7 @@ void MI_Rhino(int i) Point prevPos = Missiles[i].position.tile; Point newPosSnake; dMonster[prevPos.x][prevPos.y] = 0; - if (Monsters[monst]._mAi == AI_SNAKE) { + if (monster._mAi == AI_SNAKE) { Missiles[i].position.traveled += Missiles[i].position.velocity * 2; UpdateMissilePos(i); newPosSnake = Missiles[i].position.tile; @@ -4273,16 +4287,16 @@ void MI_Rhino(int i) } UpdateMissilePos(i); Point newPos = Missiles[i].position.tile; - if (!PosOkMonst(monst, newPos) || (Monsters[monst]._mAi == AI_SNAKE && !PosOkMonst(monst, newPosSnake))) { + if (!MonsterIsTileAvalible(monst, newPos) || (monster._mAi == AI_SNAKE && !MonsterIsTileAvalible(monst, newPosSnake))) { MissToMonst(i, prevPos); Missiles[i]._miDelFlag = true; return; } - Monsters[monst].position.future = newPos; - Monsters[monst].position.old = newPos; - Monsters[monst].position.tile = newPos; + monster.position.future = newPos; + monster.position.old = newPos; + monster.position.tile = newPos; dMonster[newPos.x][newPos.y] = -(monst + 1); - if (Monsters[monst]._uniqtype != 0) + if (monster._uniqtype != 0) ChangeLightXY(Missiles[i]._mlid, newPos); MoveMissilePos(i); PutMissile(i); @@ -4294,16 +4308,16 @@ void MI_Fireman(int i) Point a = Missiles[i].position.tile; Missiles[i].position.traveled += Missiles[i].position.velocity; UpdateMissilePos(i); - int src = Missiles[i]._misource; + auto &monster = Monsters[Missiles[i]._misource]; Point b = Missiles[i].position.tile; - int enemy = Monsters[src]._menemy; - Point c = (Monsters[src]._mFlags & MFLAG_TARGETS_MONSTER) == 0 ? Players[enemy].position.tile : Monsters[enemy].position.tile; + int enemy = monster._menemy; + Point c = (monster._mFlags & MFLAG_TARGETS_MONSTER) == 0 ? Players[enemy].position.tile : Monsters[enemy].position.tile; int j = 0; - if (b != a && (((Missiles[i]._miVar1 & 1) != 0 && a.WalkingDistance(c) >= 4) || Missiles[i]._miVar2 > 1) && PosOkMonst(Missiles[i]._misource, a)) { + if (b != a && (((Missiles[i]._miVar1 & 1) != 0 && a.WalkingDistance(c) >= 4) || Missiles[i]._miVar2 > 1) && MonsterIsTileAvalible(Missiles[i]._misource, a)) { MissToMonst(i, a); Missiles[i]._miDelFlag = true; - } else if ((Monsters[src]._mFlags & MFLAG_TARGETS_MONSTER) == 0) { + } else if ((monster._mFlags & MFLAG_TARGETS_MONSTER) == 0) { j = dPlayer[b.x][b.y]; } else { j = dMonster[b.x][b.y]; @@ -4311,7 +4325,7 @@ void MI_Fireman(int i) if (!PosOkMissile(0, b) || (j > 0 && (Missiles[i]._miVar1 & 1) == 0)) { Missiles[i].position.velocity *= -1; Missiles[i]._mimfnum = opposite[Missiles[i]._mimfnum]; - Missiles[i]._miAnimData = Monsters[src].MType->GetAnimData(MonsterGraphic::Walk).CelSpritesForDirections[Missiles[i]._mimfnum]->Data(); + Missiles[i]._miAnimData = monster.MType->GetAnimData(MonsterGraphic::Walk).CelSpritesForDirections[Missiles[i]._mimfnum]->Data(); Missiles[i]._miVar2++; if (j > 0) Missiles[i]._miVar1 |= 1; @@ -4658,11 +4672,11 @@ void MI_Element(int i) if (Missiles[i]._miVar3 == 1) { Missiles[i]._miVar3 = 2; Missiles[i]._mirange = 255; - int mid = FindClosest(c, 19); - if (mid > 0) { - Direction sd = GetDirection(c, Monsters[mid].position.tile); + auto *monster = FindClosest(c, 19); + if (monster != nullptr) { + Direction sd = GetDirection(c, monster->position.tile); SetMissDir(i, sd); - UpdateMissileVelocity(i, c, Monsters[mid].position.tile, 16); + UpdateMissileVelocity(i, c, monster->position.tile, 16); } else { Direction sd = Players[id]._pdir; SetMissDir(i, sd); @@ -4705,11 +4719,11 @@ void MI_Bonespirit(int i) if (Missiles[i]._miVar3 == 1) { Missiles[i]._miVar3 = 2; Missiles[i]._mirange = 255; - int mid = FindClosest(c, 19); - if (mid > 0) { - Missiles[i]._midam = Monsters[mid]._mhitpoints >> 7; - SetMissDir(i, GetDirection(c, Monsters[mid].position.tile)); - UpdateMissileVelocity(i, c, Monsters[mid].position.tile, 16); + auto *monster = FindClosest(c, 19); + if (monster != nullptr) { + Missiles[i]._midam = monster->_mhitpoints >> 7; + SetMissDir(i, GetDirection(c, monster->position.tile)); + UpdateMissileVelocity(i, c, monster->position.tile, 16); } else { Direction sd = Players[id]._pdir; SetMissDir(i, sd); diff --git a/Source/missiles.h b/Source/missiles.h index c050e8c1f..851b1aa3e 100644 --- a/Source/missiles.h +++ b/Source/missiles.h @@ -11,6 +11,7 @@ #include "engine.h" #include "engine/point.hpp" #include "misdat.h" +#include "monster.h" #include "spelldat.h" namespace devilution { @@ -128,7 +129,7 @@ int GetSpellLevel(int playerId, spell_id sn); Direction16 GetDirection16(Point p1, Point p2); void DeleteMissile(int mi, int i); bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, bool shift); -bool PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, bool shift, int earflag, bool *blocked); +bool PlayerMHit(int pnum, MonsterStruct *monster, int dist, int mind, int maxd, int mtype, bool shift, int earflag, bool *blocked); void SetMissDir(int mi, int dir); void LoadMissileGFX(BYTE mi); void InitMissileGFX(); diff --git a/Source/monster.cpp b/Source/monster.cpp index 15612ced7..c090747bb 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -159,111 +159,111 @@ void InitMonsterTRN(CMonster &monst) } } -void InitMonster(int i, Direction rd, int mtype, Point position) -{ - CMonster *monst = &LevelMonsterTypes[mtype]; - - const auto &animData = monst->GetAnimData(MonsterGraphic::Stand); - - Monsters[i]._mdir = rd; - Monsters[i].position.tile = position; - Monsters[i].position.future = position; - Monsters[i].position.old = position; - Monsters[i]._mMTidx = mtype; - Monsters[i]._mmode = MM_STAND; - Monsters[i].mName = _(monst->MData->mName); - Monsters[i].MType = monst; - Monsters[i].MData = monst->MData; - Monsters[i].AnimInfo = {}; - Monsters[i].AnimInfo.pCelSprite = animData.CelSpritesForDirections[rd] ? &*animData.CelSpritesForDirections[rd] : nullptr; - Monsters[i].AnimInfo.TicksPerFrame = animData.Rate; - Monsters[i].AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(Monsters[i].AnimInfo.TicksPerFrame - 1); - Monsters[i].AnimInfo.NumberOfFrames = animData.Frames; - Monsters[i].AnimInfo.CurrentFrame = GenerateRnd(Monsters[i].AnimInfo.NumberOfFrames - 1) + 1; - - Monsters[i].mLevel = monst->MData->mLevel; - Monsters[i]._mmaxhp = (monst->mMinHP + GenerateRnd(monst->mMaxHP - monst->mMinHP + 1)) << 6; - if (monst->mtype == MT_DIABLO && !gbIsHellfire) { - Monsters[i]._mmaxhp /= 2; - Monsters[i].mLevel -= 15; +void InitMonster(MonsterStruct &monster, Direction rd, int mtype, Point position) +{ + auto &monsterType = LevelMonsterTypes[mtype]; + + const auto &animData = monsterType.GetAnimData(MonsterGraphic::Stand); + + monster._mdir = rd; + monster.position.tile = position; + monster.position.future = position; + monster.position.old = position; + monster._mMTidx = mtype; + monster._mmode = MM_STAND; + monster.mName = _(monsterType.MData->mName); + monster.MType = &monsterType; + monster.MData = monsterType.MData; + monster.AnimInfo = {}; + monster.AnimInfo.pCelSprite = animData.CelSpritesForDirections[rd] ? &*animData.CelSpritesForDirections[rd] : nullptr; + monster.AnimInfo.TicksPerFrame = animData.Rate; + monster.AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(monster.AnimInfo.TicksPerFrame - 1); + monster.AnimInfo.NumberOfFrames = animData.Frames; + monster.AnimInfo.CurrentFrame = GenerateRnd(monster.AnimInfo.NumberOfFrames - 1) + 1; + + monster.mLevel = monsterType.MData->mLevel; + monster._mmaxhp = (monsterType.mMinHP + GenerateRnd(monsterType.mMaxHP - monsterType.mMinHP + 1)) << 6; + if (monsterType.mtype == MT_DIABLO && !gbIsHellfire) { + monster._mmaxhp /= 2; + monster.mLevel -= 15; } if (!gbIsMultiplayer) { - Monsters[i]._mmaxhp /= 2; - if (Monsters[i]._mmaxhp < 64) { - Monsters[i]._mmaxhp = 64; - } - } - - Monsters[i]._mhitpoints = Monsters[i]._mmaxhp; - Monsters[i]._mAi = monst->MData->mAi; - Monsters[i]._mint = monst->MData->mInt; - Monsters[i]._mgoal = MGOAL_NORMAL; - Monsters[i]._mgoalvar1 = 0; - Monsters[i]._mgoalvar2 = 0; - Monsters[i]._mgoalvar3 = 0; - Monsters[i]._pathcount = 0; - Monsters[i]._mDelFlag = false; - Monsters[i]._uniqtype = 0; - Monsters[i]._msquelch = 0; - Monsters[i].mlid = NO_LIGHT; // BUGFIX monsters initial light id should be -1 (fixed) - Monsters[i]._mRndSeed = AdvanceRndSeed(); - Monsters[i]._mAISeed = AdvanceRndSeed(); - Monsters[i].mWhoHit = 0; - Monsters[i].mExp = monst->MData->mExp; - Monsters[i].mHit = monst->MData->mHit; - Monsters[i].mMinDamage = monst->MData->mMinDamage; - Monsters[i].mMaxDamage = monst->MData->mMaxDamage; - Monsters[i].mHit2 = monst->MData->mHit2; - Monsters[i].mMinDamage2 = monst->MData->mMinDamage2; - Monsters[i].mMaxDamage2 = monst->MData->mMaxDamage2; - Monsters[i].mArmorClass = monst->MData->mArmorClass; - Monsters[i].mMagicRes = monst->MData->mMagicRes; - Monsters[i].leader = 0; - Monsters[i].leaderflag = 0; - Monsters[i]._mFlags = monst->MData->mFlags; - Monsters[i].mtalkmsg = TEXT_NONE; - - if (Monsters[i]._mAi == AI_GARG) { - Monsters[i].AnimInfo.pCelSprite = &*monst->GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[rd]; - Monsters[i].AnimInfo.CurrentFrame = 1; - Monsters[i]._mFlags |= MFLAG_ALLOW_SPECIAL; - Monsters[i]._mmode = MM_SATTACK; + monster._mmaxhp /= 2; + if (monster._mmaxhp < 64) { + monster._mmaxhp = 64; + } + } + + monster._mhitpoints = monster._mmaxhp; + monster._mAi = monsterType.MData->mAi; + monster._mint = monsterType.MData->mInt; + monster._mgoal = MGOAL_NORMAL; + monster._mgoalvar1 = 0; + monster._mgoalvar2 = 0; + monster._mgoalvar3 = 0; + monster._pathcount = 0; + monster._mDelFlag = false; + monster._uniqtype = 0; + monster._msquelch = 0; + monster.mlid = NO_LIGHT; // BUGFIX monsters initial light id should be -1 (fixed) + monster._mRndSeed = AdvanceRndSeed(); + monster._mAISeed = AdvanceRndSeed(); + monster.mWhoHit = 0; + monster.mExp = monsterType.MData->mExp; + monster.mHit = monsterType.MData->mHit; + monster.mMinDamage = monsterType.MData->mMinDamage; + monster.mMaxDamage = monsterType.MData->mMaxDamage; + monster.mHit2 = monsterType.MData->mHit2; + monster.mMinDamage2 = monsterType.MData->mMinDamage2; + monster.mMaxDamage2 = monsterType.MData->mMaxDamage2; + monster.mArmorClass = monsterType.MData->mArmorClass; + monster.mMagicRes = monsterType.MData->mMagicRes; + monster.leader = 0; + monster.leaderflag = 0; + monster._mFlags = monsterType.MData->mFlags; + monster.mtalkmsg = TEXT_NONE; + + if (monster._mAi == AI_GARG) { + monster.AnimInfo.pCelSprite = &*monsterType.GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[rd]; + monster.AnimInfo.CurrentFrame = 1; + monster._mFlags |= MFLAG_ALLOW_SPECIAL; + monster._mmode = MM_SATTACK; } if (sgGameInitInfo.nDifficulty == DIFF_NIGHTMARE) { - Monsters[i]._mmaxhp = 3 * Monsters[i]._mmaxhp; + monster._mmaxhp = 3 * monster._mmaxhp; if (gbIsHellfire) - Monsters[i]._mmaxhp += (gbIsMultiplayer ? 100 : 50) << 6; + monster._mmaxhp += (gbIsMultiplayer ? 100 : 50) << 6; else - Monsters[i]._mmaxhp += 64; - Monsters[i]._mhitpoints = Monsters[i]._mmaxhp; - Monsters[i].mLevel += 15; - Monsters[i].mExp = 2 * (Monsters[i].mExp + 1000); - Monsters[i].mHit += NIGHTMARE_TO_HIT_BONUS; - Monsters[i].mMinDamage = 2 * (Monsters[i].mMinDamage + 2); - Monsters[i].mMaxDamage = 2 * (Monsters[i].mMaxDamage + 2); - Monsters[i].mHit2 += NIGHTMARE_TO_HIT_BONUS; - Monsters[i].mMinDamage2 = 2 * (Monsters[i].mMinDamage2 + 2); - Monsters[i].mMaxDamage2 = 2 * (Monsters[i].mMaxDamage2 + 2); - Monsters[i].mArmorClass += NIGHTMARE_AC_BONUS; + monster._mmaxhp += 64; + monster._mhitpoints = monster._mmaxhp; + monster.mLevel += 15; + monster.mExp = 2 * (monster.mExp + 1000); + monster.mHit += NIGHTMARE_TO_HIT_BONUS; + monster.mMinDamage = 2 * (monster.mMinDamage + 2); + monster.mMaxDamage = 2 * (monster.mMaxDamage + 2); + monster.mHit2 += NIGHTMARE_TO_HIT_BONUS; + monster.mMinDamage2 = 2 * (monster.mMinDamage2 + 2); + monster.mMaxDamage2 = 2 * (monster.mMaxDamage2 + 2); + monster.mArmorClass += NIGHTMARE_AC_BONUS; } else if (sgGameInitInfo.nDifficulty == DIFF_HELL) { - Monsters[i]._mmaxhp = 4 * Monsters[i]._mmaxhp; + monster._mmaxhp = 4 * monster._mmaxhp; if (gbIsHellfire) - Monsters[i]._mmaxhp += (gbIsMultiplayer ? 200 : 100) << 6; + monster._mmaxhp += (gbIsMultiplayer ? 200 : 100) << 6; else - Monsters[i]._mmaxhp += 192; - Monsters[i]._mhitpoints = Monsters[i]._mmaxhp; - Monsters[i].mLevel += 30; - Monsters[i].mExp = 4 * (Monsters[i].mExp + 1000); - Monsters[i].mHit += HELL_TO_HIT_BONUS; - Monsters[i].mMinDamage = 4 * Monsters[i].mMinDamage + 6; - Monsters[i].mMaxDamage = 4 * Monsters[i].mMaxDamage + 6; - Monsters[i].mHit2 += HELL_TO_HIT_BONUS; - Monsters[i].mMinDamage2 = 4 * Monsters[i].mMinDamage2 + 6; - Monsters[i].mMaxDamage2 = 4 * Monsters[i].mMaxDamage2 + 6; - Monsters[i].mArmorClass += HELL_AC_BONUS; - Monsters[i].mMagicRes = monst->MData->mMagicRes2; + monster._mmaxhp += 192; + monster._mhitpoints = monster._mmaxhp; + monster.mLevel += 30; + monster.mExp = 4 * (monster.mExp + 1000); + monster.mHit += HELL_TO_HIT_BONUS; + monster.mMinDamage = 4 * monster.mMinDamage + 6; + monster.mMaxDamage = 4 * monster.mMaxDamage + 6; + monster.mHit2 += HELL_TO_HIT_BONUS; + monster.mMinDamage2 = 4 * monster.mMinDamage2 + 6; + monster.mMaxDamage2 = 4 * monster.mMaxDamage2 + 6; + monster.mArmorClass += HELL_AC_BONUS; + monster.mMagicRes = monsterType.MData->mMagicRes2; } } @@ -306,13 +306,15 @@ void PlaceMonster(int i, int mtype, int x, int y) dMonster[x][y] = i + 1; auto rd = static_cast(GenerateRnd(8)); - InitMonster(i, rd, mtype, { x, y }); + InitMonster(Monsters[i], rd, mtype, { x, y }); } -void PlaceGroup(int mtype, int num, int leaderf, int leader) +void PlaceGroup(int mtype, int num, int leaderAttributes, int leaderId) { int placed = 0; + auto &leader = Monsters[leaderId]; + for (int try1 = 0; try1 < 10; try1++) { while (placed != 0) { ActiveMonsterCount--; @@ -322,9 +324,9 @@ void PlaceGroup(int mtype, int num, int leaderf, int leader) int xp; int yp; - if ((leaderf & 1) != 0) { + if ((leaderAttributes & 1) != 0) { int offset = GenerateRnd(8); - auto position = Monsters[leader].position.tile + static_cast(offset); + auto position = leader.position.tile + static_cast(offset); xp = position.x; yp = position.y; } else { @@ -344,28 +346,29 @@ void PlaceGroup(int mtype, int num, int leaderf, int leader) for (int try2 = 0; j < num && try2 < 100; xp += Displacement::fromDirection(static_cast(GenerateRnd(8))).deltaX, yp += Displacement::fromDirection(static_cast(GenerateRnd(8))).deltaX) { /// BUGFIX: `yp += Point.y` if (!MonstPlace(xp, yp) || (dTransVal[xp][yp] != dTransVal[x1][y1]) - || ((leaderf & 2) != 0 && (abs(xp - x1) >= 4 || abs(yp - y1) >= 4))) { + || ((leaderAttributes & 2) != 0 && (abs(xp - x1) >= 4 || abs(yp - y1) >= 4))) { try2++; continue; } PlaceMonster(ActiveMonsterCount, mtype, xp, yp); - if ((leaderf & 1) != 0) { - Monsters[ActiveMonsterCount]._mmaxhp *= 2; - Monsters[ActiveMonsterCount]._mhitpoints = Monsters[ActiveMonsterCount]._mmaxhp; - Monsters[ActiveMonsterCount]._mint = Monsters[leader]._mint; - - if ((leaderf & 2) != 0) { - Monsters[ActiveMonsterCount].leader = leader; - Monsters[ActiveMonsterCount].leaderflag = 1; - Monsters[ActiveMonsterCount]._mAi = Monsters[leader]._mAi; + if ((leaderAttributes & 1) != 0) { + auto &minion = Monsters[ActiveMonsterCount]; + minion._mmaxhp *= 2; + minion._mhitpoints = minion._mmaxhp; + minion._mint = leader._mint; + + if ((leaderAttributes & 2) != 0) { + minion.leader = leaderId; + minion.leaderflag = 1; + minion._mAi = leader._mAi; } - if (Monsters[ActiveMonsterCount]._mAi != AI_GARG) { - Monsters[ActiveMonsterCount].AnimInfo.pCelSprite = &*Monsters[ActiveMonsterCount].MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[Monsters[ActiveMonsterCount]._mdir]; - Monsters[ActiveMonsterCount].AnimInfo.CurrentFrame = GenerateRnd(Monsters[ActiveMonsterCount].AnimInfo.NumberOfFrames - 1) + 1; - Monsters[ActiveMonsterCount]._mFlags &= ~MFLAG_ALLOW_SPECIAL; - Monsters[ActiveMonsterCount]._mmode = MM_STAND; + if (minion._mAi != AI_GARG) { + minion.AnimInfo.pCelSprite = &*minion.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[minion._mdir]; + minion.AnimInfo.CurrentFrame = GenerateRnd(minion.AnimInfo.NumberOfFrames - 1) + 1; + minion._mFlags &= ~MFLAG_ALLOW_SPECIAL; + minion._mmode = MM_STAND; } } ActiveMonsterCount++; @@ -378,15 +381,15 @@ void PlaceGroup(int mtype, int num, int leaderf, int leader) } } - if ((leaderf & 2) != 0) { - Monsters[leader].packsize = placed; + if ((leaderAttributes & 2) != 0) { + leader.packsize = placed; } } void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize) { - MonsterStruct *monst = &Monsters[ActiveMonsterCount]; - const UniqMonstStruct *uniq = &UniqMonst[uniqindex]; + auto &monster = Monsters[ActiveMonsterCount]; + const auto &uniqueData = UniqMonst[uniqindex]; if ((uniquetrans + 19) * 256 >= LIGHTSIZE) { return; @@ -394,7 +397,7 @@ void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize) int uniqtype; for (uniqtype = 0; uniqtype < LevelMonsterTypeCount; uniqtype++) { - if (LevelMonsterTypes[uniqtype].mtype == UniqMonst[uniqindex].mtype) { + if (LevelMonsterTypes[uniqtype].mtype == uniqueData.mtype) { break; } } @@ -493,118 +496,118 @@ void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize) UberDiabloMonsterIndex = ActiveMonsterCount; } PlaceMonster(ActiveMonsterCount, uniqtype, xp, yp); - monst->_uniqtype = uniqindex + 1; + monster._uniqtype = uniqindex + 1; - if (uniq->mlevel != 0) { - monst->mLevel = 2 * uniq->mlevel; + if (uniqueData.mlevel != 0) { + monster.mLevel = 2 * uniqueData.mlevel; } else { - monst->mLevel += 5; + monster.mLevel += 5; } - monst->mExp *= 2; - monst->mName = _(uniq->mName); - monst->_mmaxhp = uniq->mmaxhp << 6; + monster.mExp *= 2; + monster.mName = _(uniqueData.mName); + monster._mmaxhp = uniqueData.mmaxhp << 6; if (!gbIsMultiplayer) { - monst->_mmaxhp = monst->_mmaxhp / 2; - if (monst->_mmaxhp < 64) { - monst->_mmaxhp = 64; + monster._mmaxhp = monster._mmaxhp / 2; + if (monster._mmaxhp < 64) { + monster._mmaxhp = 64; } } - monst->_mhitpoints = monst->_mmaxhp; - monst->_mAi = uniq->mAi; - monst->_mint = uniq->mint; - monst->mMinDamage = uniq->mMinDamage; - monst->mMaxDamage = uniq->mMaxDamage; - monst->mMinDamage2 = uniq->mMinDamage; - monst->mMaxDamage2 = uniq->mMaxDamage; - monst->mMagicRes = uniq->mMagicRes; - monst->mtalkmsg = uniq->mtalkmsg; + monster._mhitpoints = monster._mmaxhp; + monster._mAi = uniqueData.mAi; + monster._mint = uniqueData.mint; + monster.mMinDamage = uniqueData.mMinDamage; + monster.mMaxDamage = uniqueData.mMaxDamage; + monster.mMinDamage2 = uniqueData.mMinDamage; + monster.mMaxDamage2 = uniqueData.mMaxDamage; + monster.mMagicRes = uniqueData.mMagicRes; + monster.mtalkmsg = uniqueData.mtalkmsg; if (uniqindex == UMT_HORKDMN) - monst->mlid = NO_LIGHT; // BUGFIX monsters initial light id should be -1 (fixed) + monster.mlid = NO_LIGHT; // BUGFIX monsters initial light id should be -1 (fixed) else - monst->mlid = AddLight(monst->position.tile, 3); + monster.mlid = AddLight(monster.position.tile, 3); if (gbIsMultiplayer) { - if (monst->_mAi == AI_LAZHELP) - monst->mtalkmsg = TEXT_NONE; - if (monst->_mAi == AI_LAZARUS && Quests[Q_BETRAYER]._qvar1 > 3) { - monst->_mgoal = MGOAL_NORMAL; - } else if (monst->mtalkmsg != TEXT_NONE) { - monst->_mgoal = MGOAL_INQUIRING; + if (monster._mAi == AI_LAZHELP) + monster.mtalkmsg = TEXT_NONE; + if (monster._mAi == AI_LAZARUS && Quests[Q_BETRAYER]._qvar1 > 3) { + monster._mgoal = MGOAL_NORMAL; + } else if (monster.mtalkmsg != TEXT_NONE) { + monster._mgoal = MGOAL_INQUIRING; } - } else if (monst->mtalkmsg != TEXT_NONE) { - monst->_mgoal = MGOAL_INQUIRING; + } else if (monster.mtalkmsg != TEXT_NONE) { + monster._mgoal = MGOAL_INQUIRING; } if (sgGameInitInfo.nDifficulty == DIFF_NIGHTMARE) { - monst->_mmaxhp = 3 * monst->_mmaxhp; + monster._mmaxhp = 3 * monster._mmaxhp; if (gbIsHellfire) - monst->_mmaxhp += (gbIsMultiplayer ? 100 : 50) << 6; + monster._mmaxhp += (gbIsMultiplayer ? 100 : 50) << 6; else - monst->_mmaxhp += 64; - monst->mLevel += 15; - monst->_mhitpoints = monst->_mmaxhp; - monst->mExp = 2 * (monst->mExp + 1000); - monst->mMinDamage = 2 * (monst->mMinDamage + 2); - monst->mMaxDamage = 2 * (monst->mMaxDamage + 2); - monst->mMinDamage2 = 2 * (monst->mMinDamage2 + 2); - monst->mMaxDamage2 = 2 * (monst->mMaxDamage2 + 2); + monster._mmaxhp += 64; + monster.mLevel += 15; + monster._mhitpoints = monster._mmaxhp; + monster.mExp = 2 * (monster.mExp + 1000); + monster.mMinDamage = 2 * (monster.mMinDamage + 2); + monster.mMaxDamage = 2 * (monster.mMaxDamage + 2); + monster.mMinDamage2 = 2 * (monster.mMinDamage2 + 2); + monster.mMaxDamage2 = 2 * (monster.mMaxDamage2 + 2); } else if (sgGameInitInfo.nDifficulty == DIFF_HELL) { - monst->_mmaxhp = 4 * monst->_mmaxhp; + monster._mmaxhp = 4 * monster._mmaxhp; if (gbIsHellfire) - monst->_mmaxhp += (gbIsMultiplayer ? 200 : 100) << 6; + monster._mmaxhp += (gbIsMultiplayer ? 200 : 100) << 6; else - monst->_mmaxhp += 192; - monst->mLevel += 30; - monst->_mhitpoints = monst->_mmaxhp; - monst->mExp = 4 * (monst->mExp + 1000); - monst->mMinDamage = 4 * monst->mMinDamage + 6; - monst->mMaxDamage = 4 * monst->mMaxDamage + 6; - monst->mMinDamage2 = 4 * monst->mMinDamage2 + 6; - monst->mMaxDamage2 = 4 * monst->mMaxDamage2 + 6; + monster._mmaxhp += 192; + monster.mLevel += 30; + monster._mhitpoints = monster._mmaxhp; + monster.mExp = 4 * (monster.mExp + 1000); + monster.mMinDamage = 4 * monster.mMinDamage + 6; + monster.mMaxDamage = 4 * monster.mMaxDamage + 6; + monster.mMinDamage2 = 4 * monster.mMinDamage2 + 6; + monster.mMaxDamage2 = 4 * monster.mMaxDamage2 + 6; } char filestr[64]; - sprintf(filestr, "Monsters\\Monsters\\%s.TRN", uniq->mTrnName); + sprintf(filestr, "Monsters\\Monsters\\%s.TRN", uniqueData.mTrnName); LoadFileInMem(filestr, &LightTables[256 * (uniquetrans + 19)], 256); - monst->_uniqtrans = uniquetrans++; + monster._uniqtrans = uniquetrans++; - if ((uniq->mUnqAttr & 4) != 0) { - monst->mHit = uniq->mUnqVar1; - monst->mHit2 = uniq->mUnqVar1; + if ((uniqueData.mUnqAttr & 4) != 0) { + monster.mHit = uniqueData.mUnqVar1; + monster.mHit2 = uniqueData.mUnqVar1; if (sgGameInitInfo.nDifficulty == DIFF_NIGHTMARE) { - monst->mHit += NIGHTMARE_TO_HIT_BONUS; - monst->mHit2 += NIGHTMARE_TO_HIT_BONUS; + monster.mHit += NIGHTMARE_TO_HIT_BONUS; + monster.mHit2 += NIGHTMARE_TO_HIT_BONUS; } else if (sgGameInitInfo.nDifficulty == DIFF_HELL) { - monst->mHit += HELL_TO_HIT_BONUS; - monst->mHit2 += HELL_TO_HIT_BONUS; + monster.mHit += HELL_TO_HIT_BONUS; + monster.mHit2 += HELL_TO_HIT_BONUS; } } - if ((uniq->mUnqAttr & 8) != 0) { - monst->mArmorClass = uniq->mUnqVar1; + if ((uniqueData.mUnqAttr & 8) != 0) { + monster.mArmorClass = uniqueData.mUnqVar1; if (sgGameInitInfo.nDifficulty == DIFF_NIGHTMARE) { - monst->mArmorClass += NIGHTMARE_AC_BONUS; + monster.mArmorClass += NIGHTMARE_AC_BONUS; } else if (sgGameInitInfo.nDifficulty == DIFF_HELL) { - monst->mArmorClass += HELL_AC_BONUS; + monster.mArmorClass += HELL_AC_BONUS; } } ActiveMonsterCount++; - if ((uniq->mUnqAttr & 1) != 0) { - PlaceGroup(miniontype, bosspacksize, uniq->mUnqAttr, ActiveMonsterCount - 1); + if ((uniqueData.mUnqAttr & 1) != 0) { + PlaceGroup(miniontype, bosspacksize, uniqueData.mUnqAttr, ActiveMonsterCount - 1); } - if (monst->_mAi != AI_GARG) { - monst->AnimInfo.pCelSprite = &*monst->MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monst->_mdir]; - monst->AnimInfo.CurrentFrame = GenerateRnd(monst->AnimInfo.NumberOfFrames - 1) + 1; - monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; - monst->_mmode = MM_STAND; + if (monster._mAi != AI_GARG) { + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monster._mdir]; + monster.AnimInfo.CurrentFrame = GenerateRnd(monster.AnimInfo.NumberOfFrames - 1) + 1; + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; + monster._mmode = MM_STAND; } } @@ -632,35 +635,34 @@ int AddMonsterType(_monster_id type, placeflag placeflag) return i; } -void ClearMVars(int i) +void ClearMVars(MonsterStruct &monster) { - Monsters[i]._mVar1 = 0; - Monsters[i]._mVar2 = 0; - Monsters[i]._mVar3 = 0; - Monsters[i].position.temp = { 0, 0 }; - Monsters[i].position.offset2 = { 0, 0 }; + monster._mVar1 = 0; + monster._mVar2 = 0; + monster._mVar3 = 0; + monster.position.temp = { 0, 0 }; + monster.position.offset2 = { 0, 0 }; } void ClrAllMonsters() { - for (int i = 0; i < MAXMONSTERS; i++) { - MonsterStruct *monst = &Monsters[i]; - ClearMVars(i); - monst->mName = "Invalid Monster"; - monst->_mgoal = MGOAL_NONE; - monst->_mmode = MM_STAND; - monst->_mVar1 = 0; - monst->_mVar2 = 0; - monst->position.tile = { 0, 0 }; - monst->position.future = { 0, 0 }; - monst->position.old = { 0, 0 }; - monst->_mdir = static_cast(GenerateRnd(8)); - monst->position.velocity = { 0, 0 }; - monst->AnimInfo = {}; - monst->_mFlags = 0; - monst->_mDelFlag = false; - monst->_menemy = GenerateRnd(gbActivePlayers); - monst->enemyPosition = Players[monst->_menemy].position.future; + for (auto &monster : Monsters) { + ClearMVars(monster); + monster.mName = "Invalid Monster"; + monster._mgoal = MGOAL_NONE; + monster._mmode = MM_STAND; + monster._mVar1 = 0; + monster._mVar2 = 0; + monster.position.tile = { 0, 0 }; + monster.position.future = { 0, 0 }; + monster.position.old = { 0, 0 }; + monster._mdir = static_cast(GenerateRnd(8)); + monster.position.velocity = { 0, 0 }; + monster.AnimInfo = {}; + monster._mFlags = 0; + monster._mDelFlag = false; + monster._menemy = GenerateRnd(gbActivePlayers); + monster.enemyPosition = Players[monster._menemy].position.future; } } @@ -760,7 +762,8 @@ void PlaceQuestMonsters() if (i1 < LevelMonsterTypeCount) { for (int i2 = 0; i2 < ActiveMonsterCount; i2++) { - if (Monsters[i2]._uniqtype != 0 || Monsters[i2]._mMTidx == i1) { + auto &monster = Monsters[i2]; + if (monster._uniqtype != 0 || monster._mMTidx == i1) { UberDiabloMonsterIndex = i2; break; } @@ -825,31 +828,31 @@ void StartMonsterGotHit(int monsterId) dMonster[monster.position.tile.x][monster.position.tile.y] = monsterId + 1; } -bool IsRanged(int i) +bool IsRanged(MonsterStruct &monster) { - return IsAnyOf(Monsters[i]._mAi, AI_SKELBOW, AI_GOATBOW, AI_SUCC, AI_LAZHELP); + return IsAnyOf(monster._mAi, AI_SKELBOW, AI_GOATBOW, AI_SUCC, AI_LAZHELP); } -void UpdateEnemy(int i) +void UpdateEnemy(MonsterStruct &monster) { Point target; int menemy = -1; int bestDist = -1; bool bestsameroom = false; - MonsterStruct *monst = &Monsters[i]; - if ((monst->_mFlags & MFLAG_BERSERK) != 0 || (monst->_mFlags & MFLAG_GOLEM) == 0) { + if ((monster._mFlags & MFLAG_BERSERK) != 0 || (monster._mFlags & MFLAG_GOLEM) == 0) { for (int pnum = 0; pnum < MAX_PLRS; pnum++) { - if (!Players[pnum].plractive || currlevel != Players[pnum].plrlevel || Players[pnum]._pLvlChanging - || (((Players[pnum]._pHitPoints >> 6) == 0) && gbIsMultiplayer)) + auto &player = Players[pnum]; + if (!player.plractive || currlevel != player.plrlevel || player._pLvlChanging + || (((player._pHitPoints >> 6) == 0) && gbIsMultiplayer)) continue; - bool sameroom = (dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[Players[pnum].position.tile.x][Players[pnum].position.tile.y]); - int dist = monst->position.tile.WalkingDistance(Players[pnum].position.tile); + bool sameroom = (dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[player.position.tile.x][player.position.tile.y]); + int dist = monster.position.tile.WalkingDistance(player.position.tile); if ((sameroom && !bestsameroom) || ((sameroom || !bestsameroom) && dist < bestDist) || (menemy == -1)) { - monst->_mFlags &= ~MFLAG_TARGETS_MONSTER; + monster._mFlags &= ~MFLAG_TARGETS_MONSTER; menemy = pnum; - target = Players[pnum].position.future; + target = player.position.future; bestDist = dist; bestsameroom = sameroom; } @@ -857,44 +860,45 @@ void UpdateEnemy(int i) } for (int j = 0; j < ActiveMonsterCount; j++) { int mi = ActiveMonsters[j]; - if (mi == i) + auto &otherMonster = Monsters[mi]; + if (&otherMonster == &monster) continue; - if ((Monsters[mi]._mhitpoints >> 6) <= 0) + if ((otherMonster._mhitpoints >> 6) <= 0) continue; - if (Monsters[mi].position.tile.x == 1 && Monsters[mi].position.tile.y == 0) + if (otherMonster.position.tile.x == 1 && otherMonster.position.tile.y == 0) continue; - if (M_Talker(mi) && Monsters[mi].mtalkmsg != TEXT_NONE) + if (M_Talker(otherMonster) && otherMonster.mtalkmsg != TEXT_NONE) continue; - if ((monst->_mFlags & MFLAG_GOLEM) != 0 && (Monsters[mi]._mFlags & MFLAG_GOLEM) != 0) // prevent golems from fighting each other + if ((monster._mFlags & MFLAG_GOLEM) != 0 && (otherMonster._mFlags & MFLAG_GOLEM) != 0) // prevent golems from fighting each other continue; - int dist = Monsters[mi].position.tile.WalkingDistance(monst->position.tile); - if (((monst->_mFlags & MFLAG_GOLEM) == 0 - && (monst->_mFlags & MFLAG_BERSERK) == 0 + int dist = otherMonster.position.tile.WalkingDistance(monster.position.tile); + if (((monster._mFlags & MFLAG_GOLEM) == 0 + && (monster._mFlags & MFLAG_BERSERK) == 0 && dist >= 2 - && !IsRanged(i)) - || ((monst->_mFlags & MFLAG_GOLEM) == 0 - && (monst->_mFlags & MFLAG_BERSERK) == 0 - && (Monsters[mi]._mFlags & MFLAG_GOLEM) == 0)) { + && !IsRanged(monster)) + || ((monster._mFlags & MFLAG_GOLEM) == 0 + && (monster._mFlags & MFLAG_BERSERK) == 0 + && (otherMonster._mFlags & MFLAG_GOLEM) == 0)) { continue; } - bool sameroom = dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[Monsters[mi].position.tile.x][Monsters[mi].position.tile.y]; + bool sameroom = dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[otherMonster.position.tile.x][otherMonster.position.tile.y]; if ((sameroom && !bestsameroom) || ((sameroom || !bestsameroom) && dist < bestDist) || (menemy == -1)) { - monst->_mFlags |= MFLAG_TARGETS_MONSTER; + monster._mFlags |= MFLAG_TARGETS_MONSTER; menemy = mi; - target = Monsters[mi].position.future; + target = otherMonster.position.future; bestDist = dist; bestsameroom = sameroom; } } if (menemy != -1) { - monst->_mFlags &= ~MFLAG_NO_ENEMY; - monst->_menemy = menemy; - monst->enemyPosition = target; + monster._mFlags &= ~MFLAG_NO_ENEMY; + monster._menemy = menemy; + monster.enemyPosition = target; } else { - monst->_mFlags |= MFLAG_NO_ENEMY; + monster._mFlags |= MFLAG_NO_ENEMY; } } @@ -902,162 +906,168 @@ void UpdateEnemy(int i) * @brief Make the AI wait a bit before thinking again * @param len */ -void AiDelay(int i, int len) +void AiDelay(MonsterStruct &monster, int len) { if (len <= 0) { return; } - if (Monsters[i]._mAi == AI_LAZARUS) { + if (monster._mAi == AI_LAZARUS) { return; } - Monsters[i]._mVar2 = len; - Monsters[i]._mmode = MM_DELAY; + monster._mVar2 = len; + monster._mmode = MM_DELAY; } /** * @brief Get the direction from the monster to its current enemy */ -Direction GetMonsterDirection(int i) +Direction GetMonsterDirection(MonsterStruct &monster) { - return GetDirection(Monsters[i].position.tile, Monsters[i].enemyPosition); + return GetDirection(monster.position.tile, monster.enemyPosition); } -void StartSpecialStand(int i, Direction md) +void StartSpecialStand(MonsterStruct &monster, Direction md) { - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, md); - Monsters[i]._mmode = MM_SPSTAND; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + NewMonsterAnim(monster, MonsterGraphic::Special, md); + monster._mmode = MM_SPSTAND; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } void StartWalk(int i, int xvel, int yvel, int xadd, int yadd, Direction endDir) { - int fx = xadd + Monsters[i].position.tile.x; - int fy = yadd + Monsters[i].position.tile.y; + auto &monster = Monsters[i]; + + int fx = xadd + monster.position.tile.x; + int fy = yadd + monster.position.tile.y; dMonster[fx][fy] = -(i + 1); - Monsters[i]._mmode = MM_WALK; - Monsters[i].position.old = Monsters[i].position.tile; - Monsters[i].position.future = { fx, fy }; - Monsters[i].position.velocity = { xvel, yvel }; - Monsters[i]._mVar1 = xadd; - Monsters[i]._mVar2 = yadd; - Monsters[i]._mVar3 = endDir; - NewMonsterAnim(Monsters[i], MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); - Monsters[i].position.offset2 = { 0, 0 }; + monster._mmode = MM_WALK; + monster.position.old = monster.position.tile; + monster.position.future = { fx, fy }; + monster.position.velocity = { xvel, yvel }; + monster._mVar1 = xadd; + monster._mVar2 = yadd; + monster._mVar3 = endDir; + NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); + monster.position.offset2 = { 0, 0 }; } void StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, Direction endDir) { - int fx = xadd + Monsters[i].position.tile.x; - int fy = yadd + Monsters[i].position.tile.y; + auto &monster = Monsters[i]; - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = -(i + 1); - Monsters[i]._mVar1 = Monsters[i].position.tile.x; - Monsters[i]._mVar2 = Monsters[i].position.tile.y; - Monsters[i].position.old = Monsters[i].position.tile; - Monsters[i].position.tile = { fx, fy }; - Monsters[i].position.future = { fx, fy }; + int fx = xadd + monster.position.tile.x; + int fy = yadd + monster.position.tile.y; + + dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); + monster._mVar1 = monster.position.tile.x; + monster._mVar2 = monster.position.tile.y; + monster.position.old = monster.position.tile; + monster.position.tile = { fx, fy }; + monster.position.future = { fx, fy }; dMonster[fx][fy] = i + 1; - if (Monsters[i].mlid != NO_LIGHT) - ChangeLightXY(Monsters[i].mlid, Monsters[i].position.tile); - Monsters[i].position.offset = { xoff, yoff }; - Monsters[i]._mmode = MM_WALK2; - Monsters[i].position.velocity = { xvel, yvel }; - Monsters[i]._mVar3 = endDir; - NewMonsterAnim(Monsters[i], MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); - Monsters[i].position.offset2 = { 16 * xoff, 16 * yoff }; + if (monster.mlid != NO_LIGHT) + ChangeLightXY(monster.mlid, monster.position.tile); + monster.position.offset = { xoff, yoff }; + monster._mmode = MM_WALK2; + monster.position.velocity = { xvel, yvel }; + monster._mVar3 = endDir; + NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); + monster.position.offset2 = { 16 * xoff, 16 * yoff }; } void StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, Direction endDir) { - int fx = xadd + Monsters[i].position.tile.x; - int fy = yadd + Monsters[i].position.tile.y; - int x = mapx + Monsters[i].position.tile.x; - int y = mapy + Monsters[i].position.tile.y; + auto &monster = Monsters[i]; + + int fx = xadd + monster.position.tile.x; + int fy = yadd + monster.position.tile.y; + int x = mapx + monster.position.tile.x; + int y = mapy + monster.position.tile.y; - if (Monsters[i].mlid != NO_LIGHT) - ChangeLightXY(Monsters[i].mlid, { x, y }); + if (monster.mlid != NO_LIGHT) + ChangeLightXY(monster.mlid, { x, y }); - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = -(i + 1); + dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); dMonster[fx][fy] = -(i + 1); - Monsters[i].position.temp = { x, y }; + monster.position.temp = { x, y }; dFlags[x][y] |= BFLAG_MONSTLR; - Monsters[i].position.old = Monsters[i].position.tile; - Monsters[i].position.future = { fx, fy }; - Monsters[i].position.offset = { xoff, yoff }; - Monsters[i]._mmode = MM_WALK3; - Monsters[i].position.velocity = { xvel, yvel }; - Monsters[i]._mVar1 = fx; - Monsters[i]._mVar2 = fy; - Monsters[i]._mVar3 = endDir; - NewMonsterAnim(Monsters[i], MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); - Monsters[i].position.offset2 = { 16 * xoff, 16 * yoff }; -} - -void StartAttack(int i) -{ - Direction md = GetMonsterDirection(i); - NewMonsterAnim(Monsters[i], MonsterGraphic::Attack, md, AnimationDistributionFlags::ProcessAnimationPending); - Monsters[i]._mmode = MM_ATTACK; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + monster.position.old = monster.position.tile; + monster.position.future = { fx, fy }; + monster.position.offset = { xoff, yoff }; + monster._mmode = MM_WALK3; + monster.position.velocity = { xvel, yvel }; + monster._mVar1 = fx; + monster._mVar2 = fy; + monster._mVar3 = endDir; + NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1); + monster.position.offset2 = { 16 * xoff, 16 * yoff }; +} + +void StartAttack(MonsterStruct &monster) +{ + Direction md = GetMonsterDirection(monster); + NewMonsterAnim(monster, MonsterGraphic::Attack, md, AnimationDistributionFlags::ProcessAnimationPending); + monster._mmode = MM_ATTACK; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } -void StartRangedAttack(int i, missile_id missileType, int dam) +void StartRangedAttack(MonsterStruct &monster, missile_id missileType, int dam) { - Direction md = GetMonsterDirection(i); - NewMonsterAnim(Monsters[i], MonsterGraphic::Attack, md, AnimationDistributionFlags::ProcessAnimationPending); - Monsters[i]._mmode = MM_RATTACK; - Monsters[i]._mVar1 = missileType; - Monsters[i]._mVar2 = dam; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + Direction md = GetMonsterDirection(monster); + NewMonsterAnim(monster, MonsterGraphic::Attack, md, AnimationDistributionFlags::ProcessAnimationPending); + monster._mmode = MM_RATTACK; + monster._mVar1 = missileType; + monster._mVar2 = dam; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } -void StartRangedSpecialAttack(int i, missile_id missileType, int dam) +void StartRangedSpecialAttack(MonsterStruct &monster, missile_id missileType, int dam) { - Direction md = GetMonsterDirection(i); + Direction md = GetMonsterDirection(monster); int distributeFramesBeforeFrame = 0; - if (Monsters[i]._mAi == AI_MEGA) - distributeFramesBeforeFrame = Monsters[i].MData->mAFNum2; - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, md, AnimationDistributionFlags::ProcessAnimationPending, 0, distributeFramesBeforeFrame); - Monsters[i]._mmode = MM_RSPATTACK; - Monsters[i]._mVar1 = missileType; - Monsters[i]._mVar2 = 0; - Monsters[i]._mVar3 = dam; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + if (monster._mAi == AI_MEGA) + distributeFramesBeforeFrame = monster.MData->mAFNum2; + NewMonsterAnim(monster, MonsterGraphic::Special, md, AnimationDistributionFlags::ProcessAnimationPending, 0, distributeFramesBeforeFrame); + monster._mmode = MM_RSPATTACK; + monster._mVar1 = missileType; + monster._mVar2 = 0; + monster._mVar3 = dam; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } -void StartSpecialAttack(int i) +void StartSpecialAttack(MonsterStruct &monster) { - Direction md = GetMonsterDirection(i); - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, md); - Monsters[i]._mmode = MM_SATTACK; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + Direction md = GetMonsterDirection(monster); + NewMonsterAnim(monster, MonsterGraphic::Special, md); + monster._mmode = MM_SATTACK; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } -void StartEating(int i) +void StartEating(MonsterStruct &monster) { - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, Monsters[i]._mdir); - Monsters[i]._mmode = MM_SATTACK; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + NewMonsterAnim(monster, MonsterGraphic::Special, monster._mdir); + monster._mmode = MM_SATTACK; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; } void DiabloDeath(int i, bool sendmsg) { - MonsterStruct *monst = &Monsters[i]; + auto &diablo = Monsters[i]; PlaySFX(USFX_DIABLOD); Quests[Q_DIABLO]._qactive = QUEST_DONE; if (sendmsg) @@ -1066,47 +1076,48 @@ void DiabloDeath(int i, bool sendmsg) gbProcessPlayers = false; for (int j = 0; j < ActiveMonsterCount; j++) { int k = ActiveMonsters[j]; - if (k == i || monst->_msquelch == 0) + auto &monster = Monsters[k]; + if (k == i || diablo._msquelch == 0) continue; - NewMonsterAnim(Monsters[k], MonsterGraphic::Death, Monsters[k]._mdir); - Monsters[k]._mmode = MM_DEATH; - Monsters[k].position.offset = { 0, 0 }; - Monsters[k]._mVar1 = 0; - Monsters[k].position.tile = Monsters[k].position.old; - Monsters[k].position.future = Monsters[k].position.tile; + NewMonsterAnim(monster, MonsterGraphic::Death, monster._mdir); + monster._mmode = MM_DEATH; + monster.position.offset = { 0, 0 }; + monster._mVar1 = 0; + monster.position.tile = monster.position.old; + monster.position.future = monster.position.tile; M_ClearSquares(k); - dMonster[Monsters[k].position.tile.x][Monsters[k].position.tile.y] = k + 1; + dMonster[monster.position.tile.x][monster.position.tile.y] = k + 1; } - AddLight(monst->position.tile, 8); - DoVision(monst->position.tile, 8, false, true); - int dist = monst->position.tile.WalkingDistance({ ViewX, ViewY }); + AddLight(diablo.position.tile, 8); + DoVision(diablo.position.tile, 8, false, true); + int dist = diablo.position.tile.WalkingDistance({ ViewX, ViewY }); if (dist > 20) dist = 20; - monst->_mVar3 = ViewX << 16; - monst->position.temp.x = ViewY << 16; - monst->position.temp.y = (int)((monst->_mVar3 - (monst->position.tile.x << 16)) / (double)dist); - monst->position.offset2.deltaX = (int)((monst->position.temp.x - (monst->position.tile.y << 16)) / (double)dist); + diablo._mVar3 = ViewX << 16; + diablo.position.temp.x = ViewY << 16; + diablo.position.temp.y = (int)((diablo._mVar3 - (diablo.position.tile.x << 16)) / (double)dist); + diablo.position.offset2.deltaX = (int)((diablo.position.temp.x - (diablo.position.tile.y << 16)) / (double)dist); } void SpawnLoot(int i, bool sendmsg) { - MonsterStruct *monst = &Monsters[i]; - if (QuestStatus(Q_GARBUD) && monst->_uniqtype - 1 == UMT_GARBUD) { - CreateTypeItem(monst->position.tile + Displacement { 1, 1 }, true, ITYPE_MACE, IMISC_NONE, true, false); - } else if (monst->_uniqtype - 1 == UMT_DEFILER) { + auto &monster = Monsters[i]; + if (QuestStatus(Q_GARBUD) && monster._uniqtype - 1 == UMT_GARBUD) { + CreateTypeItem(monster.position.tile + Displacement { 1, 1 }, true, ITYPE_MACE, IMISC_NONE, true, false); + } else if (monster._uniqtype - 1 == UMT_DEFILER) { if (effect_is_playing(USFX_DEFILER8)) stream_stop(); Quests[Q_DEFILER]._qlog = false; - SpawnMapOfDoom(monst->position.tile); - } else if (monst->_uniqtype - 1 == UMT_HORKDMN) { + SpawnMapOfDoom(monster.position.tile); + } else if (monster._uniqtype - 1 == UMT_HORKDMN) { if (sgGameInitInfo.bTheoQuest != 0) { - SpawnTheodore(monst->position.tile); + SpawnTheodore(monster.position.tile); } else { - CreateAmulet(monst->position.tile, 13, false, true); + CreateAmulet(monster.position.tile, 13, false, true); } - } else if (monst->MType->mtype == MT_HORKSPWN) { - } else if (monst->MType->mtype == MT_NAKRUL) { + } else if (monster.MType->mtype == MT_HORKSPWN) { + } else if (monster.MType->mtype == MT_NAKRUL) { int nSFX = IsUberRoomOpened ? USFX_NAKRUL4 : USFX_NAKRUL5; if (sgGameInitInfo.bCowQuest != 0) nSFX = USFX_NAKRUL6; @@ -1114,25 +1125,25 @@ void SpawnLoot(int i, bool sendmsg) stream_stop(); Quests[Q_NAKRUL]._qlog = false; UberDiabloMonsterIndex = -2; - CreateMagicWeapon(monst->position.tile, ITYPE_SWORD, ICURS_GREAT_SWORD, false, true); - CreateMagicWeapon(monst->position.tile, ITYPE_STAFF, ICURS_WAR_STAFF, false, true); - CreateMagicWeapon(monst->position.tile, ITYPE_BOW, ICURS_LONG_WAR_BOW, false, true); - CreateSpellBook(monst->position.tile, SPL_APOCA, false, true); + CreateMagicWeapon(monster.position.tile, ITYPE_SWORD, ICURS_GREAT_SWORD, false, true); + CreateMagicWeapon(monster.position.tile, ITYPE_STAFF, ICURS_WAR_STAFF, false, true); + CreateMagicWeapon(monster.position.tile, ITYPE_BOW, ICURS_LONG_WAR_BOW, false, true); + CreateSpellBook(monster.position.tile, SPL_APOCA, false, true); } else if (i > MAX_PLRS - 1) { // Golems should not spawn loot - SpawnItem(i, monst->position.tile, sendmsg); + SpawnItem(monster, monster.position.tile, sendmsg); } } void Teleport(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode == MM_STONE) + if (monster._mmode == MM_STONE) return; - int mx = monst->enemyPosition.x; - int my = monst->enemyPosition.y; + int mx = monster.enemyPosition.x; + int my = monster.enemyPosition.y; int rx = 2 * GenerateRnd(2) - 1; int ry = 2 * GenerateRnd(2) - 1; @@ -1145,8 +1156,8 @@ void Teleport(int i) if (j != 0 || k != 0) { x = mx + rx * j; y = my + ry * k; - if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && x != monst->position.tile.x && y != monst->position.tile.y) { - if (PosOkMonst(i, { x, y })) + if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && x != monster.position.tile.x && y != monster.position.tile.y) { + if (MonsterIsTileAvalible(i, { x, y })) done = true; } } @@ -1155,199 +1166,185 @@ void Teleport(int i) if (done) { M_ClearSquares(i); - dMonster[monst->position.tile.x][monst->position.tile.y] = 0; + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; dMonster[x][y] = i + 1; - monst->position.old = { x, y }; - monst->_mdir = GetMonsterDirection(i); + monster.position.old = { x, y }; + monster._mdir = GetMonsterDirection(monster); } } void MonsterHitMonster(int mid, int i, int dam) { - assurance((DWORD)mid < MAXMONSTERS, mid); - assurance(Monsters[mid].MType != nullptr, mid); + assert((DWORD)mid < MAXMONSTERS); + auto &monster = Monsters[mid]; + assurance(monster.MType != nullptr, mid); if (i >= 0 && i < MAX_PLRS) - Monsters[mid].mWhoHit |= 1 << i; + monster.mWhoHit |= 1 << i; - delta_monster_hp(mid, Monsters[mid]._mhitpoints, currlevel); + delta_monster_hp(mid, monster._mhitpoints, currlevel); NetSendCmdMonDmg(false, mid, dam); - PlayEffect(mid, 1); + PlayEffect(monster, 1); - if ((Monsters[mid].MType->mtype >= MT_SNEAK && Monsters[mid].MType->mtype <= MT_ILLWEAV) || dam >> 6 >= Monsters[mid].mLevel + 3) { + if ((monster.MType->mtype >= MT_SNEAK && monster.MType->mtype <= MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { if (i >= 0) - Monsters[mid]._mdir = opposite[Monsters[i]._mdir]; + monster._mdir = opposite[Monsters[i]._mdir]; - if (Monsters[mid].MType->mtype == MT_BLINK) { + if (monster.MType->mtype == MT_BLINK) { Teleport(mid); - } else if ((Monsters[mid].MType->mtype >= MT_NSCAV && Monsters[mid].MType->mtype <= MT_YSCAV) - || Monsters[mid].MType->mtype == MT_GRAVEDIG) { - Monsters[mid]._mgoal = MGOAL_NORMAL; - Monsters[mid]._mgoalvar1 = 0; - Monsters[mid]._mgoalvar2 = 0; + } else if ((monster.MType->mtype >= MT_NSCAV && monster.MType->mtype <= MT_YSCAV) + || monster.MType->mtype == MT_GRAVEDIG) { + monster._mgoal = MGOAL_NORMAL; + monster._mgoalvar1 = 0; + monster._mgoalvar2 = 0; } - if (Monsters[mid]._mmode != MM_STONE) { + if (monster._mmode != MM_STONE) { StartMonsterGotHit(mid); } } } -void MonsterDeath(int i, int pnum, bool sendmsg) +void StartMonsterDeath(int i, int pnum, bool sendmsg) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - assurance(monst->MType != nullptr, i); + assurance(monster.MType != nullptr, i); if (pnum >= 0) - monst->mWhoHit |= 1 << pnum; + monster.mWhoHit |= 1 << pnum; if (pnum < MAX_PLRS && i >= MAX_PLRS) /// BUGFIX: i >= MAX_PLRS (fixed) - AddPlrMonstExper(monst->mLevel, monst->mExp, monst->mWhoHit); - MonsterKillCounts[monst->MType->mtype]++; - monst->_mhitpoints = 0; - SetRndSeed(monst->_mRndSeed); + AddPlrMonstExper(monster.mLevel, monster.mExp, monster.mWhoHit); + MonsterKillCounts[monster.MType->mtype]++; + monster._mhitpoints = 0; + SetRndSeed(monster._mRndSeed); SpawnLoot(i, sendmsg); - if (monst->MType->mtype == MT_DIABLO) + if (monster.MType->mtype == MT_DIABLO) DiabloDeath(i, true); else - PlayEffect(i, 2); - - Direction md = pnum >= 0 ? GetMonsterDirection(i) : monst->_mdir; - NewMonsterAnim(*monst, MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None); - monst->_mmode = MM_DEATH; - monst->_mgoal = MGOAL_NONE; - monst->position.offset = { 0, 0 }; - monst->_mVar1 = 0; - monst->position.tile = monst->position.old; - monst->position.future = monst->position.old; + PlayEffect(monster, 2); + + Direction md = pnum >= 0 ? GetMonsterDirection(monster) : monster._mdir; + NewMonsterAnim(monster, MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None); + monster._mmode = MM_DEATH; + monster._mgoal = MGOAL_NONE; + monster.position.offset = { 0, 0 }; + monster._mVar1 = 0; + monster.position.tile = monster.position.old; + monster.position.future = monster.position.old; M_ClearSquares(i); - dMonster[monst->position.tile.x][monst->position.tile.y] = i + 1; - CheckQuestKill(i, sendmsg); - M_FallenFear(monst->position.tile); - if ((monst->MType->mtype >= MT_NACID && monst->MType->mtype <= MT_XACID) || monst->MType->mtype == MT_SPIDLORD) - AddMissile(monst->position.tile, { 0, 0 }, 0, MIS_ACIDPUD, TARGET_PLAYERS, i, monst->_mint + 1, 0); + dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; + CheckQuestKill(monster, sendmsg); + M_FallenFear(monster.position.tile); + if ((monster.MType->mtype >= MT_NACID && monster.MType->mtype <= MT_XACID) || monster.MType->mtype == MT_SPIDLORD) + AddMissile(monster.position.tile, { 0, 0 }, 0, MIS_ACIDPUD, TARGET_PLAYERS, i, monster._mint + 1, 0); } void StartDeathFromMonster(int i, int mid) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &killer = Monsters[i]; assurance((DWORD)mid < MAXMONSTERS, mid); - assurance(Monsters[mid].MType != nullptr, mid); /// BUGFIX: should check `mid` (fixed) + auto &monster = Monsters[mid]; + assurance(monster.MType != nullptr, mid); /// BUGFIX: should check `mid` (fixed) - delta_kill_monster(mid, Monsters[mid].position.tile, currlevel); - NetSendCmdLocParam1(false, CMD_MONSTDEATH, Monsters[mid].position.tile, mid); + delta_kill_monster(mid, monster.position.tile, currlevel); + NetSendCmdLocParam1(false, CMD_MONSTDEATH, monster.position.tile, mid); if (i < MAX_PLRS) { - Monsters[mid].mWhoHit |= 1 << i; + monster.mWhoHit |= 1 << i; if (mid >= MAX_PLRS) - AddPlrMonstExper(Monsters[mid].mLevel, Monsters[mid].mExp, Monsters[mid].mWhoHit); + AddPlrMonstExper(monster.mLevel, monster.mExp, monster.mWhoHit); } - MonsterKillCounts[Monsters[mid].MType->mtype]++; - Monsters[mid]._mhitpoints = 0; - SetRndSeed(Monsters[mid]._mRndSeed); + MonsterKillCounts[monster.MType->mtype]++; + monster._mhitpoints = 0; + SetRndSeed(monster._mRndSeed); - SpawnLoot(mid, true); + SpawnLoot(i, true); - if (Monsters[mid].MType->mtype == MT_DIABLO) - DiabloDeath(mid, true); + if (monster.MType->mtype == MT_DIABLO) + DiabloDeath(i, true); else - PlayEffect(mid, 2); + PlayEffect(monster, 2); - Direction md = opposite[Monsters[i]._mdir]; - if (Monsters[mid].MType->mtype == MT_GOLEM) + Direction md = opposite[killer._mdir]; + if (monster.MType->mtype == MT_GOLEM) md = DIR_S; - NewMonsterAnim(Monsters[mid], MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None); - Monsters[mid]._mmode = MM_DEATH; - Monsters[mid].position.offset = { 0, 0 }; - Monsters[mid].position.tile = Monsters[mid].position.old; - Monsters[mid].position.future = Monsters[mid].position.old; + NewMonsterAnim(monster, MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None); + monster._mmode = MM_DEATH; + monster.position.offset = { 0, 0 }; + monster.position.tile = monster.position.old; + monster.position.future = monster.position.old; M_ClearSquares(mid); - dMonster[Monsters[mid].position.tile.x][Monsters[mid].position.tile.y] = mid + 1; - CheckQuestKill(mid, true); - M_FallenFear(Monsters[mid].position.tile); - if (Monsters[mid].MType->mtype >= MT_NACID && Monsters[mid].MType->mtype <= MT_XACID) - AddMissile(Monsters[mid].position.tile, { 0, 0 }, 0, MIS_ACIDPUD, TARGET_PLAYERS, mid, Monsters[mid]._mint + 1, 0); + dMonster[monster.position.tile.x][monster.position.tile.y] = mid + 1; + CheckQuestKill(monster, true); + M_FallenFear(monster.position.tile); + if (monster.MType->mtype >= MT_NACID && monster.MType->mtype <= MT_XACID) + AddMissile(monster.position.tile, { 0, 0 }, 0, MIS_ACIDPUD, TARGET_PLAYERS, mid, monster._mint + 1, 0); if (gbIsHellfire) - M_StartStand(i, Monsters[i]._mdir); + M_StartStand(killer, killer._mdir); } -void StartFadein(int i, Direction md, bool backwards) +void StartFadein(MonsterStruct &monster, Direction md, bool backwards) { - assurance((DWORD)i < MAXMONSTERS, i); - assurance(Monsters[i].MType != nullptr, i); - - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, md); - Monsters[i]._mmode = MM_FADEIN; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; - Monsters[i]._mFlags &= ~MFLAG_HIDDEN; + NewMonsterAnim(monster, MonsterGraphic::Special, md); + monster._mmode = MM_FADEIN; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; + monster._mFlags &= ~MFLAG_HIDDEN; if (backwards) { - Monsters[i]._mFlags |= MFLAG_LOCK_ANIMATION; - Monsters[i].AnimInfo.CurrentFrame = Monsters[i].AnimInfo.NumberOfFrames; + monster._mFlags |= MFLAG_LOCK_ANIMATION; + monster.AnimInfo.CurrentFrame = monster.AnimInfo.NumberOfFrames; } } -void StartFadeout(int i, Direction md, bool backwards) +void StartFadeout(MonsterStruct &monster, Direction md, bool backwards) { - assurance((DWORD)i < MAXMONSTERS, i); - assurance(Monsters[i].MType != nullptr, i); - assurance(Monsters[i].MType != nullptr, i); - - NewMonsterAnim(Monsters[i], MonsterGraphic::Special, md); - Monsters[i]._mmode = MM_FADEOUT; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; + NewMonsterAnim(monster, MonsterGraphic::Special, md); + monster._mmode = MM_FADEOUT; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; if (backwards) { - Monsters[i]._mFlags |= MFLAG_LOCK_ANIMATION; - Monsters[i].AnimInfo.CurrentFrame = Monsters[i].AnimInfo.NumberOfFrames; + monster._mFlags |= MFLAG_LOCK_ANIMATION; + monster.AnimInfo.CurrentFrame = monster.AnimInfo.NumberOfFrames; } } -void StartHeal(int i) +void StartHeal(MonsterStruct &monster) { - assurance((DWORD)i < MAXMONSTERS, i); - assurance(Monsters[i].MType != nullptr, i); - - MonsterStruct *monst = &Monsters[i]; - monst->AnimInfo.pCelSprite = &*monst->MType->GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[monst->_mdir]; - monst->AnimInfo.CurrentFrame = monst->MType->GetAnimData(MonsterGraphic::Special).Frames; - monst->_mFlags |= MFLAG_LOCK_ANIMATION; - monst->_mmode = MM_HEAL; - monst->_mVar1 = monst->_mmaxhp / (16 * (GenerateRnd(5) + 4)); + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[monster._mdir]; + monster.AnimInfo.CurrentFrame = monster.MType->GetAnimData(MonsterGraphic::Special).Frames; + monster._mFlags |= MFLAG_LOCK_ANIMATION; + monster._mmode = MM_HEAL; + monster._mVar1 = monster._mmaxhp / (16 * (GenerateRnd(5) + 4)); } -void SyncLightPosition(int monst) +void SyncLightPosition(MonsterStruct &monster) { - assurance((DWORD)monst < MAXMONSTERS, monst); - - int lx = (Monsters[monst].position.offset.deltaX + 2 * Monsters[monst].position.offset.deltaY) / 8; - int ly = (2 * Monsters[monst].position.offset.deltaY - Monsters[monst].position.offset.deltaX) / 8; + int lx = (monster.position.offset.deltaX + 2 * monster.position.offset.deltaY) / 8; + int ly = (2 * monster.position.offset.deltaY - monster.position.offset.deltaX) / 8; - if (Monsters[monst].mlid != NO_LIGHT) - ChangeLightOffset(Monsters[monst].mlid, { lx, ly }); + if (monster.mlid != NO_LIGHT) + ChangeLightOffset(monster.mlid, { lx, ly }); } -bool MonsterIdle(int i) +bool MonsterIdle(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - - MonsterStruct *monst = &Monsters[i]; - if (monst->MType->mtype == MT_GOLEM) - monst->AnimInfo.pCelSprite = &*monst->MType->GetAnimData(MonsterGraphic::Walk).CelSpritesForDirections[monst->_mdir]; + if (monster.MType->mtype == MT_GOLEM) + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Walk).CelSpritesForDirections[monster._mdir]; else - monst->AnimInfo.pCelSprite = &*monst->MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monst->_mdir]; + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monster._mdir]; - if (monst->AnimInfo.CurrentFrame == monst->AnimInfo.NumberOfFrames) - UpdateEnemy(i); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) + UpdateEnemy(monster); - monst->_mVar2++; + monster._mVar2++; return false; } @@ -1357,72 +1354,74 @@ bool MonsterIdle(int i) */ bool MonsterWalk(int i, int variant) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); //Check if we reached new tile - bool isAnimationEnd = Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames; + bool isAnimationEnd = monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames; if (isAnimationEnd) { switch (variant) { case MM_WALK: - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = 0; - Monsters[i].position.tile.x += Monsters[i]._mVar1; - Monsters[i].position.tile.y += Monsters[i]._mVar2; - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = i + 1; + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; + monster.position.tile.x += monster._mVar1; + monster.position.tile.y += monster._mVar2; + dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; break; case MM_WALK2: - dMonster[Monsters[i]._mVar1][Monsters[i]._mVar2] = 0; + dMonster[monster._mVar1][monster._mVar2] = 0; break; case MM_WALK3: - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = 0; - Monsters[i].position.tile = { Monsters[i]._mVar1, Monsters[i]._mVar2 }; - dFlags[Monsters[i].position.temp.x][Monsters[i].position.temp.y] &= ~BFLAG_MONSTLR; - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = i + 1; + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; + monster.position.tile = { monster._mVar1, monster._mVar2 }; + dFlags[monster.position.temp.x][monster.position.temp.y] &= ~BFLAG_MONSTLR; + dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; break; } - if (Monsters[i].mlid != NO_LIGHT) - ChangeLightXY(Monsters[i].mlid, Monsters[i].position.tile); - M_StartStand(i, Monsters[i]._mdir); + if (monster.mlid != NO_LIGHT) + ChangeLightXY(monster.mlid, monster.position.tile); + M_StartStand(monster, monster._mdir); } else { //We didn't reach new tile so update monster's "sub-tile" position - if (Monsters[i].AnimInfo.TickCounterOfCurrentFrame == 0) { - if (Monsters[i].AnimInfo.CurrentFrame == 0 && Monsters[i].MType->mtype == MT_FLESTHNG) - PlayEffect(i, 3); - Monsters[i].position.offset2 += Monsters[i].position.velocity; - Monsters[i].position.offset.deltaX = Monsters[i].position.offset2.deltaX >> 4; - Monsters[i].position.offset.deltaY = Monsters[i].position.offset2.deltaY >> 4; + if (monster.AnimInfo.TickCounterOfCurrentFrame == 0) { + if (monster.AnimInfo.CurrentFrame == 0 && monster.MType->mtype == MT_FLESTHNG) + PlayEffect(monster, 3); + monster.position.offset2 += monster.position.velocity; + monster.position.offset.deltaX = monster.position.offset2.deltaX >> 4; + monster.position.offset.deltaY = monster.position.offset2.deltaY >> 4; } } - if (Monsters[i].mlid != NO_LIGHT) // BUGFIX: change uniqtype check to mlid check like it is in all other places (fixed) - SyncLightPosition(i); + if (monster.mlid != NO_LIGHT) // BUGFIX: change uniqtype check to mlid check like it is in all other places (fixed) + SyncLightPosition(monster); return isAnimationEnd; } void MonsterAttackMonster(int i, int mid, int hper, int mind, int maxd) { - assurance((DWORD)mid < MAXMONSTERS, mid); - assurance(Monsters[mid].MType != nullptr, mid); + assert((DWORD)mid < MAXMONSTERS); + auto &monster = Monsters[mid]; + assurance(monster.MType != nullptr, mid); - if (Monsters[mid]._mhitpoints >> 6 > 0 && (Monsters[mid].MType->mtype != MT_ILLWEAV || Monsters[mid]._mgoal != MGOAL_RETREAT)) { + if (monster._mhitpoints >> 6 > 0 && (monster.MType->mtype != MT_ILLWEAV || monster._mgoal != MGOAL_RETREAT)) { int hit = GenerateRnd(100); - if (Monsters[mid]._mmode == MM_STONE) + if (monster._mmode == MM_STONE) hit = 0; bool unused; - if (!CheckMonsterHit(mid, &unused) && hit < hper) { + if (!CheckMonsterHit(monster, &unused) && hit < hper) { int dam = (mind + GenerateRnd(maxd - mind + 1)) << 6; - Monsters[mid]._mhitpoints -= dam; - if (Monsters[mid]._mhitpoints >> 6 <= 0) { - if (Monsters[mid]._mmode == MM_STONE) { + monster._mhitpoints -= dam; + if (monster._mhitpoints >> 6 <= 0) { + if (monster._mmode == MM_STONE) { StartDeathFromMonster(i, mid); - Monsters[mid].Petrify(); + monster.Petrify(); } else { StartDeathFromMonster(i, mid); } } else { - if (Monsters[mid]._mmode == MM_STONE) { + if (monster._mmode == MM_STONE) { MonsterHitMonster(mid, i, dam); - Monsters[mid].Petrify(); + monster.Petrify(); } else { MonsterHitMonster(mid, i, dam); } @@ -1433,16 +1432,17 @@ void MonsterAttackMonster(int i, int mid, int hper, int mind, int maxd) void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) { - assurance((DWORD)i < MAXMONSTERS, i); - assurance(Monsters[i].MType != nullptr, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + assurance(monster.MType != nullptr, i); - if ((Monsters[i]._mFlags & MFLAG_TARGETS_MONSTER) != 0) { + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) { MonsterAttackMonster(i, pnum, hit, minDam, maxDam); return; } if (Players[pnum]._pHitPoints >> 6 <= 0 || Players[pnum]._pInvincible || (Players[pnum]._pSpellFlags & 1) != 0) return; - if (Monsters[i].position.tile.WalkingDistance(Players[pnum].position.tile) >= 2) + if (monster.position.tile.WalkingDistance(Players[pnum].position.tile) >= 2) return; int hper = GenerateRnd(100); @@ -1451,11 +1451,11 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) hper = 1000; #endif int ac = Players[pnum]._pIBonusAC + Players[pnum]._pIAC; - if ((Players[pnum].pDamAcFlags & ISPLHF_ACDEMON) != 0 && Monsters[i].MData->mMonstClass == MC_DEMON) + if ((Players[pnum].pDamAcFlags & ISPLHF_ACDEMON) != 0 && monster.MData->mMonstClass == MC_DEMON) ac += 40; - if ((Players[pnum].pDamAcFlags & ISPLHF_ACUNDEAD) != 0 && Monsters[i].MData->mMonstClass == MC_UNDEAD) + if ((Players[pnum].pDamAcFlags & ISPLHF_ACUNDEAD) != 0 && monster.MData->mMonstClass == MC_UNDEAD) ac += 20; - hit += 2 * (Monsters[i].mLevel - Players[pnum]._pLevel) + hit += 2 * (monster.mLevel - Players[pnum]._pLevel) + 30 - ac - Players[pnum]._pDexterity / 5; @@ -1473,7 +1473,7 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) } int blk = Players[pnum]._pDexterity + Players[pnum]._pBaseToBlk - - (Monsters[i].mLevel * 2) + - (monster.mLevel * 2) + (Players[pnum]._pLevel * 2); if (blk < 0) blk = 0; @@ -1482,7 +1482,7 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) if (hper >= hit) return; if (blkper < blk) { - Direction dir = GetDirection(Players[pnum].position.tile, Monsters[i].position.tile); + Direction dir = GetDirection(Players[pnum].position.tile, monster.position.tile); StartPlrBlock(pnum, dir); if (pnum == MyPlayerId && Players[pnum].wReflections > 0) { Players[pnum].wReflections--; @@ -1491,18 +1491,18 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) if (dam < 64) dam = 64; int mdam = dam * (GenerateRnd(10) + 20L) / 100; - Monsters[i]._mhitpoints -= mdam; + monster._mhitpoints -= mdam; dam -= mdam; if (dam < 0) dam = 0; - if (Monsters[i]._mhitpoints >> 6 <= 0) + if (monster._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); } return; } - if (Monsters[i].MType->mtype == MT_YZOMBIE && pnum == MyPlayerId) { + if (monster.MType->mtype == MT_YZOMBIE && pnum == MyPlayerId) { int currentMissileId = -1; for (int j = 0; j < ActiveMissileCount; j++) { int mi = ActiveMissiles[j]; @@ -1536,11 +1536,11 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) if (Players[pnum].wReflections > 0) { Players[pnum].wReflections--; int mdam = dam * (GenerateRnd(10) + 20L) / 100; - Monsters[i]._mhitpoints -= mdam; + monster._mhitpoints -= mdam; dam -= mdam; if (dam < 0) dam = 0; - if (Monsters[i]._mhitpoints >> 6 <= 0) + if (monster._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); @@ -1549,25 +1549,25 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) } if ((Players[pnum]._pIFlags & ISPL_THORNS) != 0) { int mdam = (GenerateRnd(3) + 1) << 6; - Monsters[i]._mhitpoints -= mdam; - if (Monsters[i]._mhitpoints >> 6 <= 0) + monster._mhitpoints -= mdam; + if (monster._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); } - if ((Monsters[i]._mFlags & MFLAG_NOLIFESTEAL) == 0 && Monsters[i].MType->mtype == MT_SKING && gbIsMultiplayer) - Monsters[i]._mhitpoints += dam; + if ((monster._mFlags & MFLAG_NOLIFESTEAL) == 0 && monster.MType->mtype == MT_SKING && gbIsMultiplayer) + monster._mhitpoints += dam; if (Players[pnum]._pHitPoints >> 6 <= 0) { if (gbIsHellfire) - M_StartStand(i, Monsters[i]._mdir); + M_StartStand(monster, monster._mdir); return; } StartPlrHit(pnum, dam, false); - if ((Monsters[i]._mFlags & MFLAG_KNOCKBACK) != 0) { + if ((monster._mFlags & MFLAG_KNOCKBACK) != 0) { if (Players[pnum]._pmode != PM_GOTHIT) StartPlrHit(pnum, 0, true); - Point newPosition = Players[pnum].position.tile + Monsters[i]._mdir; + Point newPosition = Players[pnum].position.tile + monster._mdir; if (PosOkPlayer(pnum, newPosition)) { Players[pnum].position.tile = newPosition; FixPlayerLocation(pnum, Players[pnum]._pdir); @@ -1580,28 +1580,28 @@ void MonsterAttackPlayer(int i, int pnum, int hit, int minDam, int maxDam) bool MonsterAttack(int i) { - commitment((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - commitment(monst->MType != nullptr, i); - commitment(monst->MData != nullptr, i); // BUGFIX: should check MData (fixed) + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); + commitment(monster.MData != nullptr, i); // BUGFIX: should check MData (fixed) - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum) { - MonsterAttackPlayer(i, Monsters[i]._menemy, Monsters[i].mHit, Monsters[i].mMinDamage, Monsters[i].mMaxDamage); - if (Monsters[i]._mAi != AI_SNAKE) - PlayEffect(i, 0); + if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum) { + MonsterAttackPlayer(i, monster._menemy, monster.mHit, monster.mMinDamage, monster.mMaxDamage); + if (monster._mAi != AI_SNAKE) + PlayEffect(monster, 0); } - if (Monsters[i].MType->mtype >= MT_NMAGMA && Monsters[i].MType->mtype <= MT_WMAGMA && Monsters[i].AnimInfo.CurrentFrame == 9) { - MonsterAttackPlayer(i, Monsters[i]._menemy, Monsters[i].mHit + 10, Monsters[i].mMinDamage - 2, Monsters[i].mMaxDamage - 2); - PlayEffect(i, 0); + if (monster.MType->mtype >= MT_NMAGMA && monster.MType->mtype <= MT_WMAGMA && monster.AnimInfo.CurrentFrame == 9) { + MonsterAttackPlayer(i, monster._menemy, monster.mHit + 10, monster.mMinDamage - 2, monster.mMaxDamage - 2); + PlayEffect(monster, 0); } - if (Monsters[i].MType->mtype >= MT_STORM && Monsters[i].MType->mtype <= MT_MAEL && Monsters[i].AnimInfo.CurrentFrame == 13) { - MonsterAttackPlayer(i, Monsters[i]._menemy, Monsters[i].mHit - 20, Monsters[i].mMinDamage + 4, Monsters[i].mMaxDamage + 4); - PlayEffect(i, 0); + if (monster.MType->mtype >= MT_STORM && monster.MType->mtype <= MT_MAEL && monster.AnimInfo.CurrentFrame == 13) { + MonsterAttackPlayer(i, monster._menemy, monster.mHit - 20, monster.mMinDamage + 4, monster.mMaxDamage + 4); + PlayEffect(monster, 0); } - if (Monsters[i]._mAi == AI_SNAKE && Monsters[i].AnimInfo.CurrentFrame == 1) - PlayEffect(i, 0); - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster._mAi == AI_SNAKE && monster.AnimInfo.CurrentFrame == 1) + PlayEffect(monster, 0); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } @@ -1610,37 +1610,38 @@ bool MonsterAttack(int i) bool MonaterRangedAttack(int i) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - commitment(Monsters[i].MData != nullptr, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); + commitment(monster.MData != nullptr, i); - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum) { - if (Monsters[i]._mVar1 != -1) { + if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum) { + if (monster._mVar1 != -1) { int multimissiles = 1; - if (Monsters[i]._mVar1 == MIS_CBOLT) + if (monster._mVar1 == MIS_CBOLT) multimissiles = 3; for (int mi = 0; mi < multimissiles; mi++) { - Point sourcePosition = Monsters[i].position.tile; + Point sourcePosition = monster.position.tile; if (gbIsHellfire) { - sourcePosition += Monsters[i]._mdir; + sourcePosition += monster._mdir; } AddMissile( sourcePosition, - Monsters[i].enemyPosition, - Monsters[i]._mdir, - Monsters[i]._mVar1, + monster.enemyPosition, + monster._mdir, + monster._mVar1, TARGET_PLAYERS, i, - Monsters[i]._mVar2, + monster._mVar2, 0); } } - PlayEffect(i, 0); + PlayEffect(monster, 0); } - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } @@ -1649,38 +1650,39 @@ bool MonaterRangedAttack(int i) bool MonsterRangedSpecialAttack(int i) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - commitment(Monsters[i].MData != nullptr, i); // BUGFIX: should check MData (fixed) + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); + commitment(monster.MData != nullptr, i); // BUGFIX: should check MData (fixed) - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum2 && Monsters[i].AnimInfo.TickCounterOfCurrentFrame == 0) { - Point sourcePosition = Monsters[i].position.tile; + if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2 && monster.AnimInfo.TickCounterOfCurrentFrame == 0) { + Point sourcePosition = monster.position.tile; if (gbIsHellfire) { - sourcePosition += Monsters[i]._mdir; + sourcePosition += monster._mdir; } AddMissile( sourcePosition, - Monsters[i].enemyPosition, - Monsters[i]._mdir, - Monsters[i]._mVar1, + monster.enemyPosition, + monster._mdir, + monster._mVar1, TARGET_PLAYERS, i, - Monsters[i]._mVar3, + monster._mVar3, 0); - PlayEffect(i, 3); + PlayEffect(monster, 3); } - if (Monsters[i]._mAi == AI_MEGA && Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum2) { - if (Monsters[i]._mVar2++ == 0) { - Monsters[i]._mFlags |= MFLAG_ALLOW_SPECIAL; - } else if (Monsters[i]._mVar2 == 15) { - Monsters[i]._mFlags &= ~MFLAG_ALLOW_SPECIAL; + if (monster._mAi == AI_MEGA && monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2) { + if (monster._mVar2++ == 0) { + monster._mFlags |= MFLAG_ALLOW_SPECIAL; + } else if (monster._mVar2 == 15) { + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; } } - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } @@ -1689,112 +1691,104 @@ bool MonsterRangedSpecialAttack(int i) bool MonsterSpecialAttack(int i) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - commitment(Monsters[i].MData != nullptr, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); + commitment(monster.MData != nullptr, i); - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum2) - MonsterAttackPlayer(i, Monsters[i]._menemy, Monsters[i].mHit2, Monsters[i].mMinDamage2, Monsters[i].mMaxDamage2); + if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2) + MonsterAttackPlayer(i, monster._menemy, monster.mHit2, monster.mMinDamage2, monster.mMaxDamage2); - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } return false; } -bool MonsterFadein(int i) +bool MonsterFadein(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - - if (((Monsters[i]._mFlags & MFLAG_LOCK_ANIMATION) == 0 || Monsters[i].AnimInfo.CurrentFrame != 1) - && ((Monsters[i]._mFlags & MFLAG_LOCK_ANIMATION) != 0 || Monsters[i].AnimInfo.CurrentFrame != Monsters[i].AnimInfo.NumberOfFrames)) { + if (((monster._mFlags & MFLAG_LOCK_ANIMATION) == 0 || monster.AnimInfo.CurrentFrame != 1) + && ((monster._mFlags & MFLAG_LOCK_ANIMATION) != 0 || monster.AnimInfo.CurrentFrame != monster.AnimInfo.NumberOfFrames)) { return false; } - M_StartStand(i, Monsters[i]._mdir); - Monsters[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; + M_StartStand(monster, monster._mdir); + monster._mFlags &= ~MFLAG_LOCK_ANIMATION; return true; } -bool MonsterFadeout(int i) +bool MonsterFadeout(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - - if (((Monsters[i]._mFlags & MFLAG_LOCK_ANIMATION) == 0 || Monsters[i].AnimInfo.CurrentFrame != 1) - && ((Monsters[i]._mFlags & MFLAG_LOCK_ANIMATION) != 0 || Monsters[i].AnimInfo.CurrentFrame != Monsters[i].AnimInfo.NumberOfFrames)) { + if (((monster._mFlags & MFLAG_LOCK_ANIMATION) == 0 || monster.AnimInfo.CurrentFrame != 1) + && ((monster._mFlags & MFLAG_LOCK_ANIMATION) != 0 || monster.AnimInfo.CurrentFrame != monster.AnimInfo.NumberOfFrames)) { return false; } - int mt = Monsters[i].MType->mtype; + int mt = monster.MType->mtype; if (mt < MT_INCIN || mt > MT_HELLBURN) { - Monsters[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; - Monsters[i]._mFlags |= MFLAG_HIDDEN; + monster._mFlags &= ~MFLAG_LOCK_ANIMATION; + monster._mFlags |= MFLAG_HIDDEN; } else { - Monsters[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; + monster._mFlags &= ~MFLAG_LOCK_ANIMATION; } - M_StartStand(i, Monsters[i]._mdir); + M_StartStand(monster, monster._mdir); return true; } -bool MonsterHeal(int i) +bool MonsterHeal(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - if ((Monsters[i]._mFlags & MFLAG_NOHEAL) != 0) { - monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; - monst->_mmode = MM_SATTACK; + if ((monster._mFlags & MFLAG_NOHEAL) != 0) { + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; + monster._mmode = MM_SATTACK; return false; } - if (monst->AnimInfo.CurrentFrame == 1) { - monst->_mFlags &= ~MFLAG_LOCK_ANIMATION; - monst->_mFlags |= MFLAG_ALLOW_SPECIAL; - if (monst->_mVar1 + monst->_mhitpoints < monst->_mmaxhp) { - monst->_mhitpoints = monst->_mVar1 + monst->_mhitpoints; + if (monster.AnimInfo.CurrentFrame == 1) { + monster._mFlags &= ~MFLAG_LOCK_ANIMATION; + monster._mFlags |= MFLAG_ALLOW_SPECIAL; + if (monster._mVar1 + monster._mhitpoints < monster._mmaxhp) { + monster._mhitpoints = monster._mVar1 + monster._mhitpoints; } else { - monst->_mhitpoints = monst->_mmaxhp; - monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; - monst->_mmode = MM_SATTACK; + monster._mhitpoints = monster._mmaxhp; + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; + monster._mmode = MM_SATTACK; } } return false; } -bool MonsterTalk(int i) +bool MonsterTalk(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - - MonsterStruct *monst = &Monsters[i]; - M_StartStand(i, Monsters[i]._mdir); - monst->_mgoal = MGOAL_TALKING; // CODEFIX: apply Monst instead of monster[i] in the rest of the function - if (effect_is_playing(Texts[Monsters[i].mtalkmsg].sfxnr)) + M_StartStand(monster, monster._mdir); + monster._mgoal = MGOAL_TALKING; + if (effect_is_playing(Texts[monster.mtalkmsg].sfxnr)) return false; - InitQTextMsg(Monsters[i].mtalkmsg); - if (Monsters[i]._uniqtype - 1 == UMT_GARBUD) { - if (Monsters[i].mtalkmsg == TEXT_GARBUD1) { + InitQTextMsg(monster.mtalkmsg); + if (monster._uniqtype - 1 == UMT_GARBUD) { + if (monster.mtalkmsg == TEXT_GARBUD1) { Quests[Q_GARBUD]._qactive = QUEST_ACTIVE; Quests[Q_GARBUD]._qlog = true; // BUGFIX: (?) for other quests qactive and qlog go together, maybe this should actually go into the if above (fixed) } - if (Monsters[i].mtalkmsg == TEXT_GARBUD2 && (Monsters[i]._mFlags & MFLAG_QUEST_COMPLETE) == 0) { - SpawnItem(i, Monsters[i].position.tile + Displacement { 1, 1 }, true); - Monsters[i]._mFlags |= MFLAG_QUEST_COMPLETE; + if (monster.mtalkmsg == TEXT_GARBUD2 && (monster._mFlags & MFLAG_QUEST_COMPLETE) == 0) { + SpawnItem(monster, monster.position.tile + Displacement { 1, 1 }, true); + monster._mFlags |= MFLAG_QUEST_COMPLETE; } } - if (Monsters[i]._uniqtype - 1 == UMT_ZHAR - && Monsters[i].mtalkmsg == TEXT_ZHAR1 - && (Monsters[i]._mFlags & MFLAG_QUEST_COMPLETE) == 0) { + if (monster._uniqtype - 1 == UMT_ZHAR + && monster.mtalkmsg == TEXT_ZHAR1 + && (monster._mFlags & MFLAG_QUEST_COMPLETE) == 0) { Quests[Q_ZHAR]._qactive = QUEST_ACTIVE; Quests[Q_ZHAR]._qlog = true; - CreateTypeItem(Monsters[i].position.tile + Displacement { 1, 1 }, false, ITYPE_MISC, IMISC_BOOK, true, false); - Monsters[i]._mFlags |= MFLAG_QUEST_COMPLETE; + CreateTypeItem(monster.position.tile + Displacement { 1, 1 }, false, ITYPE_MISC, IMISC_BOOK, true, false); + monster._mFlags |= MFLAG_QUEST_COMPLETE; } - if (Monsters[i]._uniqtype - 1 == UMT_SNOTSPIL) { - if (Monsters[i].mtalkmsg == TEXT_BANNER10 && (Monsters[i]._mFlags & MFLAG_QUEST_COMPLETE) == 0) { + if (monster._uniqtype - 1 == UMT_SNOTSPIL) { + if (monster.mtalkmsg == TEXT_BANNER10 && (monster._mFlags & MFLAG_QUEST_COMPLETE) == 0) { ObjChangeMap(setpc_x, setpc_y, (setpc_w / 2) + setpc_x + 2, (setpc_h / 2) + setpc_y - 2); auto tren = TransVal; TransVal = 9; @@ -1803,40 +1797,37 @@ bool MonsterTalk(int i) Quests[Q_LTBANNER]._qvar1 = 2; if (Quests[Q_LTBANNER]._qactive == QUEST_INIT) Quests[Q_LTBANNER]._qactive = QUEST_ACTIVE; - Monsters[i]._mFlags |= MFLAG_QUEST_COMPLETE; + monster._mFlags |= MFLAG_QUEST_COMPLETE; } if (Quests[Q_LTBANNER]._qvar1 < 2) { - app_fatal("SS Talk = %i, Flags = %i", Monsters[i].mtalkmsg, Monsters[i]._mFlags); + app_fatal("SS Talk = %i, Flags = %i", monster.mtalkmsg, monster._mFlags); } } - if (Monsters[i]._uniqtype - 1 == UMT_LACHDAN) { - if (Monsters[i].mtalkmsg == TEXT_VEIL9) { + if (monster._uniqtype - 1 == UMT_LACHDAN) { + if (monster.mtalkmsg == TEXT_VEIL9) { Quests[Q_VEIL]._qactive = QUEST_ACTIVE; Quests[Q_VEIL]._qlog = true; } - if (Monsters[i].mtalkmsg == TEXT_VEIL11 && (Monsters[i]._mFlags & MFLAG_QUEST_COMPLETE) == 0) { - SpawnUnique(UITEM_STEELVEIL, Monsters[i].position.tile + DIR_S); - Monsters[i]._mFlags |= MFLAG_QUEST_COMPLETE; + if (monster.mtalkmsg == TEXT_VEIL11 && (monster._mFlags & MFLAG_QUEST_COMPLETE) == 0) { + SpawnUnique(UITEM_STEELVEIL, monster.position.tile + DIR_S); + monster._mFlags |= MFLAG_QUEST_COMPLETE; } } - if (Monsters[i]._uniqtype - 1 == UMT_WARLORD) + if (monster._uniqtype - 1 == UMT_WARLORD) Quests[Q_WARLORD]._qvar1 = 2; - if (Monsters[i]._uniqtype - 1 == UMT_LAZARUS && gbIsMultiplayer) { + if (monster._uniqtype - 1 == UMT_LAZARUS && gbIsMultiplayer) { Quests[Q_BETRAYER]._qvar1 = 6; - Monsters[i]._mgoal = MGOAL_NORMAL; - Monsters[i]._msquelch = UINT8_MAX; - Monsters[i].mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; } return false; } -bool MonsterGotHit(int i) +bool MonsterGotHit(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } @@ -1846,83 +1837,76 @@ bool MonsterGotHit(int i) bool MonsterDeath(int i) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + commitment(monster.MType != nullptr, i); - Monsters[i]._mVar1++; - if (Monsters[i].MType->mtype == MT_DIABLO) { - if (Monsters[i].position.tile.x < ViewX) { + monster._mVar1++; + if (monster.MType->mtype == MT_DIABLO) { + if (monster.position.tile.x < ViewX) { ViewX--; - } else if (Monsters[i].position.tile.x > ViewX) { + } else if (monster.position.tile.x > ViewX) { ViewX++; } - if (Monsters[i].position.tile.y < ViewY) { + if (monster.position.tile.y < ViewY) { ViewY--; - } else if (Monsters[i].position.tile.y > ViewY) { + } else if (monster.position.tile.y > ViewY) { ViewY++; } - if (Monsters[i]._mVar1 == 140) + if (monster._mVar1 == 140) PrepDoEnding(); - } else if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - if (Monsters[i]._uniqtype == 0) - AddDead(Monsters[i].position.tile, Monsters[i].MType->mdeadval, Monsters[i]._mdir); + } else if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + if (monster._uniqtype == 0) + AddDead(monster.position.tile, monster.MType->mdeadval, monster._mdir); else - AddDead(Monsters[i].position.tile, Monsters[i]._udeadval, Monsters[i]._mdir); + AddDead(monster.position.tile, monster._udeadval, monster._mdir); - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = 0; - Monsters[i]._mDelFlag = true; + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; + monster._mDelFlag = true; M_UpdateLeader(i); } return false; } -bool MonsterSpecialStand(int i) +bool MonsterSpecialStand(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); + if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2) + PlayEffect(monster, 3); - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].MData->mAFNum2) - PlayEffect(i, 3); - - if (Monsters[i].AnimInfo.CurrentFrame == Monsters[i].AnimInfo.NumberOfFrames) { - M_StartStand(i, Monsters[i]._mdir); + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { + M_StartStand(monster, monster._mdir); return true; } return false; } -bool MonsterDelay(int i) +bool MonsterDelay(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - commitment(Monsters[i].MType != nullptr, i); - - Monsters[i].AnimInfo.pCelSprite = &*Monsters[i].MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[GetMonsterDirection(i)]; - if (Monsters[i]._mAi == AI_LAZARUS) { - if (Monsters[i]._mVar2 > 8 || Monsters[i]._mVar2 < 0) - Monsters[i]._mVar2 = 8; + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[GetMonsterDirection(monster)]; + if (monster._mAi == AI_LAZARUS) { + if (monster._mVar2 > 8 || monster._mVar2 < 0) + monster._mVar2 = 8; } - if (Monsters[i]._mVar2-- == 0) { - int oFrame = Monsters[i].AnimInfo.CurrentFrame; - M_StartStand(i, Monsters[i]._mdir); - Monsters[i].AnimInfo.CurrentFrame = oFrame; + if (monster._mVar2-- == 0) { + int oFrame = monster.AnimInfo.CurrentFrame; + M_StartStand(monster, monster._mdir); + monster.AnimInfo.CurrentFrame = oFrame; return true; } return false; } -bool MonsterPetrified(int i) +bool MonsterPetrified(MonsterStruct &monster) { - commitment((DWORD)i < MAXMONSTERS, i); - - if (Monsters[i]._mhitpoints <= 0) { - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = 0; - Monsters[i]._mDelFlag = true; + if (monster._mhitpoints <= 0) { + dMonster[monster.position.tile.x][monster.position.tile.y] = 0; + monster._mDelFlag = true; } return false; @@ -1953,7 +1937,7 @@ int SpawnSkeleton(Point position, Direction dir) { int skel = AddSkeleton(position, dir, true); if (skel != -1) - StartSpecialStand(skel, dir); + StartSpecialStand(Monsters[skel], dir); return skel; } @@ -1970,49 +1954,49 @@ bool IsLineNotSolid(Point startPoint, Point endPoint) void GroupUnity(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - int leader; - if (Monsters[i].leaderflag != 0) { - leader = Monsters[i].leader; - bool clear = IsLineNotSolid(Monsters[i].position.tile, Monsters[leader].position.future); - if (clear || Monsters[i].leaderflag != 1) { + auto &leader = Monsters[monster.leader]; + if (monster.leaderflag != 0) { + bool clear = IsLineNotSolid(monster.position.tile, leader.position.future); + if (clear || monster.leaderflag != 1) { if (clear - && Monsters[i].leaderflag == 2 - && Monsters[i].position.tile.WalkingDistance(Monsters[leader].position.future) < 4) { - Monsters[leader].packsize++; - Monsters[i].leaderflag = 1; + && monster.leaderflag == 2 + && monster.position.tile.WalkingDistance(leader.position.future) < 4) { + leader.packsize++; + monster.leaderflag = 1; } } else { - Monsters[leader].packsize--; - Monsters[i].leaderflag = 2; + leader.packsize--; + monster.leaderflag = 2; } } - if (Monsters[i].leaderflag == 1) { - if (Monsters[i]._msquelch > Monsters[leader]._msquelch) { - Monsters[leader].position.last = Monsters[i].position.tile; - Monsters[leader]._msquelch = Monsters[i]._msquelch - 1; + if (monster.leaderflag == 1) { + if (monster._msquelch > leader._msquelch) { + leader.position.last = monster.position.tile; + leader._msquelch = monster._msquelch - 1; } - if (Monsters[leader]._mAi == AI_GARG) { - if ((Monsters[leader]._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { - Monsters[leader]._mFlags &= ~MFLAG_ALLOW_SPECIAL; - Monsters[leader]._mmode = MM_SATTACK; + if (leader._mAi == AI_GARG) { + if ((leader._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { + leader._mFlags &= ~MFLAG_ALLOW_SPECIAL; + leader._mmode = MM_SATTACK; } } - } else if (Monsters[i]._uniqtype != 0) { - if ((UniqMonst[Monsters[i]._uniqtype - 1].mUnqAttr & 2) != 0) { + } else if (monster._uniqtype != 0) { + if ((UniqMonst[monster._uniqtype - 1].mUnqAttr & 2) != 0) { for (int j = 0; j < ActiveMonsterCount; j++) { - int m = ActiveMonsters[j]; - if (Monsters[m].leaderflag == 1 && Monsters[m].leader == i) { - if (Monsters[i]._msquelch > Monsters[m]._msquelch) { - Monsters[m].position.last = Monsters[i].position.tile; - Monsters[m]._msquelch = Monsters[i]._msquelch - 1; + auto &minion = Monsters[ActiveMonsters[j]]; + if (minion.leaderflag == 1 && minion.leader == i) { + if (monster._msquelch > minion._msquelch) { + minion.position.last = monster.position.tile; + minion._msquelch = monster._msquelch - 1; } - if (Monsters[m]._mAi == AI_GARG) { - if ((Monsters[m]._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { - Monsters[m]._mFlags &= ~MFLAG_ALLOW_SPECIAL; - Monsters[m]._mmode = MM_SATTACK; + if (minion._mAi == AI_GARG) { + if ((minion._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { + minion._mFlags &= ~MFLAG_ALLOW_SPECIAL; + minion._mmode = MM_SATTACK; } } } @@ -2120,7 +2104,7 @@ bool MonsterIsTileClear(int i, Point position) /** * @brief Check that the amonster that can open doors can stand on the tile */ -bool MonsterIsTileClearOrDoor(int i, Point position) +bool MonsterIsTileAccessible(int i, Point position) { bool isdoor = false; if (dObject[position.x][position.y] != 0) { @@ -2144,13 +2128,14 @@ bool AiPlanWalk(int i) /** Maps from walking path step to facing direction. */ const Direction plr2monst[9] = { DIR_S, DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; - commitment((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - check = MonsterIsTileClearOrDoor; + check = MonsterIsTileAccessible; if ((Monsters[i]._mFlags & MFLAG_CAN_OPEN_DOOR) == 0) - check = PosOkMonst; + check = MonsterIsTileAvalible; - if (FindPath(check, i, Monsters[i].position.tile.x, Monsters[i].position.tile.y, Monsters[i].enemyPosition.x, Monsters[i].enemyPosition.y, path) == 0) { + if (FindPath(check, i, monster.position.tile.x, monster.position.tile.y, monster.enemyPosition.x, monster.enemyPosition.y, path) == 0) { return false; } @@ -2202,369 +2187,371 @@ bool RoundWalk(int i, Direction direction, int *dir) bool AiPlanPath(int i) { - commitment((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->MType->mtype != MT_GOLEM) { - if (monst->_msquelch == 0) + if (monster.MType->mtype != MT_GOLEM) { + if (monster._msquelch == 0) return false; - if (monst->_mmode != MM_STAND) + if (monster._mmode != MM_STAND) return false; - if (monst->_mgoal != MGOAL_NORMAL && monst->_mgoal != MGOAL_MOVE && monst->_mgoal != MGOAL_ATTACK2) + if (monster._mgoal != MGOAL_NORMAL && monster._mgoal != MGOAL_MOVE && monster._mgoal != MGOAL_ATTACK2) return false; - if (monst->position.tile.x == 1 && monst->position.tile.y == 0) + if (monster.position.tile.x == 1 && monster.position.tile.y == 0) return false; } bool clear = LineClear( MonsterIsTileClear, i, - monst->position.tile, - monst->enemyPosition); - if (!clear || (monst->_pathcount >= 5 && monst->_pathcount < 8)) { - if ((monst->_mFlags & MFLAG_CAN_OPEN_DOOR) != 0) - MonstCheckDoors(i); - monst->_pathcount++; - if (monst->_pathcount < 5) + monster.position.tile, + monster.enemyPosition); + if (!clear || (monster._pathcount >= 5 && monster._pathcount < 8)) { + if ((monster._mFlags & MFLAG_CAN_OPEN_DOOR) != 0) + MonstCheckDoors(monster); + monster._pathcount++; + if (monster._pathcount < 5) return false; if (AiPlanWalk(i)) return true; } - if (monst->MType->mtype != MT_GOLEM) - monst->_pathcount = 0; + if (monster.MType->mtype != MT_GOLEM) + monster._pathcount = 0; return false; } void AiAvoidance(int i, bool special) { - assurance((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(100); - if ((abs(mx) >= 2 || abs(my) >= 2) && monst->_msquelch == UINT8_MAX && dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[fx][fy]) { - if (monst->_mgoal == MGOAL_MOVE || ((abs(mx) >= 4 || abs(my) >= 4) && GenerateRnd(4) == 0)) { - if (monst->_mgoal != MGOAL_MOVE) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + if ((abs(mx) >= 2 || abs(my) >= 2) && monster._msquelch == UINT8_MAX && dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[fx][fy]) { + if (monster._mgoal == MGOAL_MOVE || ((abs(mx) >= 4 || abs(my) >= 4) && GenerateRnd(4) == 0)) { + if (monster._mgoal != MGOAL_MOVE) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; + monster._mgoal = MGOAL_MOVE; int dist = std::max(abs(mx), abs(my)); - if ((monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md)) || dTransVal[monst->position.tile.x][monst->position.tile.y] != dTransVal[fx][fy]) { - monst->_mgoal = MGOAL_NORMAL; - } else if (!RoundWalk(i, md, &monst->_mgoalvar2)) { - AiDelay(i, GenerateRnd(10) + 10); + if ((monster._mgoalvar1++ >= 2 * dist && DirOK(i, md)) || dTransVal[monster.position.tile.x][monster.position.tile.y] != dTransVal[fx][fy]) { + monster._mgoal = MGOAL_NORMAL; + } else if (!RoundWalk(i, md, &monster._mgoalvar2)) { + AiDelay(monster, GenerateRnd(10) + 10); } } } else { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) { + if (monster._mgoal == MGOAL_NORMAL) { if (abs(mx) >= 2 || abs(my) >= 2) { - if ((monst->_mVar2 > 20 && v < 2 * monst->_mint + 28) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) - && monst->_mVar2 == 0 - && v < 2 * monst->_mint + 78)) { + if ((monster._mVar2 > 20 && v < 2 * monster._mint + 28) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) + && monster._mVar2 == 0 + && v < 2 * monster._mint + 78)) { RandomWalk(i, md); } - } else if (v < 2 * monst->_mint + 23) { - monst->_mdir = md; - if (special && monst->_mhitpoints < (monst->_mmaxhp / 2) && GenerateRnd(2) != 0) - StartSpecialAttack(i); + } else if (v < 2 * monster._mint + 23) { + monster._mdir = md; + if (special && monster._mhitpoints < (monster._mmaxhp / 2) && GenerateRnd(2) != 0) + StartSpecialAttack(monster); else - StartAttack(i); + StartAttack(monster); } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void AiRanged(int i, missile_id missileType, bool special) { assurance((DWORD)i < MAXMONSTERS, i); + auto &monster = Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - MonsterStruct *monst = &Monsters[i]; - if (monst->_msquelch == UINT8_MAX || (monst->_mFlags & MFLAG_TARGETS_MONSTER) != 0) { - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetMonsterDirection(i); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); - monst->_mdir = md; - if (monst->_mVar1 == MM_RATTACK) { - AiDelay(i, GenerateRnd(20)); + if (monster._msquelch == UINT8_MAX || (monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) { + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetMonsterDirection(monster); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); + monster._mdir = md; + if (monster._mVar1 == MM_RATTACK) { + AiDelay(monster, GenerateRnd(20)); } else if (abs(mx) < 4 && abs(my) < 4) { - if (GenerateRnd(100) < 10 * (monst->_mint + 7)) + if (GenerateRnd(100) < 10 * (monster._mint + 7)) RandomWalk(i, opposite[md]); } - if (monst->_mmode == MM_STAND) { - if (LineClearMissile(monst->position.tile, { fx, fy })) { + if (monster._mmode == MM_STAND) { + if (LineClearMissile(monster.position.tile, { fx, fy })) { if (special) - StartRangedSpecialAttack(i, missileType, 4); + StartRangedSpecialAttack(monster, missileType, 4); else - StartRangedAttack(i, missileType, 4); + StartRangedAttack(monster, missileType, 4); } else { - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } } return; } - if (monst->_msquelch != 0) { - int fx = monst->position.last.x; - int fy = monst->position.last.y; - Direction md = GetDirection(monst->position.tile, { fx, fy }); + if (monster._msquelch != 0) { + int fx = monster.position.last.x; + int fy = monster.position.last.y; + Direction md = GetDirection(monster.position.tile, { fx, fy }); RandomWalk(i, md); } } void AiRangedAvoidance(int i, missile_id missileType, bool checkdoors, int dam, int lessmissiles) { - assurance((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (checkdoors && monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (checkdoors && monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(10000); int dist = std::max(abs(mx), abs(my)); - if (dist >= 2 && monst->_msquelch == UINT8_MAX && dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[fx][fy]) { - if (monst->_mgoal == MGOAL_MOVE || (dist >= 3 && GenerateRnd(4 << lessmissiles) == 0)) { - if (monst->_mgoal != MGOAL_MOVE) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + if (dist >= 2 && monster._msquelch == UINT8_MAX && dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[fx][fy]) { + if (monster._mgoal == MGOAL_MOVE || (dist >= 3 && GenerateRnd(4 << lessmissiles) == 0)) { + if (monster._mgoal != MGOAL_MOVE) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; - if (monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md)) { - monst->_mgoal = MGOAL_NORMAL; - } else if (v < (500 * (monst->_mint + 1) >> lessmissiles) - && (LineClearMissile(monst->position.tile, { fx, fy }))) { - StartRangedSpecialAttack(i, missileType, dam); + monster._mgoal = MGOAL_MOVE; + if (monster._mgoalvar1++ >= 2 * dist && DirOK(i, md)) { + monster._mgoal = MGOAL_NORMAL; + } else if (v < (500 * (monster._mint + 1) >> lessmissiles) + && (LineClearMissile(monster.position.tile, { fx, fy }))) { + StartRangedSpecialAttack(monster, missileType, dam); } else { - RoundWalk(i, md, &monst->_mgoalvar2); + RoundWalk(i, md, &monster._mgoalvar2); } } } else { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) { - if (((dist >= 3 && v < ((500 * (monst->_mint + 2)) >> lessmissiles)) - || v < ((500 * (monst->_mint + 1)) >> lessmissiles)) - && LineClearMissile(monst->position.tile, { fx, fy })) { - StartRangedSpecialAttack(i, missileType, dam); + if (monster._mgoal == MGOAL_NORMAL) { + if (((dist >= 3 && v < ((500 * (monster._mint + 2)) >> lessmissiles)) + || v < ((500 * (monster._mint + 1)) >> lessmissiles)) + && LineClearMissile(monster.position.tile, { fx, fy })) { + StartRangedSpecialAttack(monster, missileType, dam); } else if (dist >= 2) { v = GenerateRnd(100); - if (v < 1000 * (monst->_mint + 5) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) && monst->_mVar2 == 0 && v < 1000 * (monst->_mint + 8))) { + if (v < 1000 * (monster._mint + 5) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) && monster._mVar2 == 0 && v < 1000 * (monster._mint + 8))) { RandomWalk(i, md); } - } else if (v < 1000 * (monst->_mint + 6)) { - monst->_mdir = md; - StartAttack(i); + } else if (v < 1000 * (monster._mint + 6)) { + monster._mdir = md; + StartAttack(monster); } } - if (monst->_mmode == MM_STAND) { - AiDelay(i, GenerateRnd(10) + 5); + if (monster._mmode == MM_STAND) { + AiDelay(monster, GenerateRnd(10) + 5); } } void ZombieAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; if ((dFlags[mx][my] & BFLAG_VISIBLE) == 0) { return; } - if (GenerateRnd(100) < 2 * monst->_mint + 10) { - int dist = monst->enemyPosition.WalkingDistance({ mx, my }); + if (GenerateRnd(100) < 2 * monster._mint + 10) { + int dist = monster.enemyPosition.WalkingDistance({ mx, my }); if (dist >= 2) { - if (dist >= 2 * monst->_mint + 4) { - Direction md = monst->_mdir; - if (GenerateRnd(100) < 2 * monst->_mint + 20) { + if (dist >= 2 * monster._mint + 4) { + Direction md = monster._mdir; + if (GenerateRnd(100) < 2 * monster._mint + 20) { md = static_cast(GenerateRnd(8)); } DumbWalk(i, md); } else { - RandomWalk(i, GetMonsterDirection(i)); + RandomWalk(i, GetMonsterDirection(monster)); } } else { - StartAttack(i); + StartAttack(monster); } } - monst->CheckStandAnimationIsLoaded(monst->_mdir); + monster.CheckStandAnimationIsLoaded(monster._mdir); } void OverlordAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int mx = monst->position.tile.x - monst->enemyPosition.x; - int my = monst->position.tile.y - monst->enemyPosition.y; - Direction md = GetMonsterDirection(i); - monst->_mdir = md; + int mx = monster.position.tile.x - monster.enemyPosition.x; + int my = monster.position.tile.y - monster.enemyPosition.y; + Direction md = GetMonsterDirection(monster); + monster._mdir = md; int v = GenerateRnd(100); if (abs(mx) >= 2 || abs(my) >= 2) { - if ((monst->_mVar2 > 20 && v < 4 * monst->_mint + 20) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) - && monst->_mVar2 == 0 - && v < 4 * monst->_mint + 70)) { + if ((monster._mVar2 > 20 && v < 4 * monster._mint + 20) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) + && monster._mVar2 == 0 + && v < 4 * monster._mint + 70)) { RandomWalk(i, md); } - } else if (v < 4 * monst->_mint + 15) { - StartAttack(i); - } else if (v < 4 * monst->_mint + 20) { - StartSpecialAttack(i); + } else if (v < 4 * monster._mint + 15) { + StartAttack(monster); + } else if (v < 4 * monster._mint + 20) { + StartSpecialAttack(monster); } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void SkeletonAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int x = monst->position.tile.x - monst->enemyPosition.x; - int y = monst->position.tile.y - monst->enemyPosition.y; - Direction md = GetDirection(monst->position.tile, monst->position.last); - monst->_mdir = md; + int x = monster.position.tile.x - monster.enemyPosition.x; + int y = monster.position.tile.y - monster.enemyPosition.y; + Direction md = GetDirection(monster.position.tile, monster.position.last); + monster._mdir = md; if (abs(x) >= 2 || abs(y) >= 2) { - if (monst->_mVar1 == MM_DELAY || (GenerateRnd(100) >= 35 - 4 * monst->_mint)) { + if (monster._mVar1 == MM_DELAY || (GenerateRnd(100) >= 35 - 4 * monster._mint)) { RandomWalk(i, md); } else { - AiDelay(i, 15 - 2 * monst->_mint + GenerateRnd(10)); + AiDelay(monster, 15 - 2 * monster._mint + GenerateRnd(10)); } } else { - if (monst->_mVar1 == MM_DELAY || (GenerateRnd(100) < 2 * monst->_mint + 20)) { - StartAttack(i); + if (monster._mVar1 == MM_DELAY || (GenerateRnd(100) < 2 * monster._mint + 20)) { + StartAttack(monster); } else { - AiDelay(i, 2 * (5 - monst->_mint) + GenerateRnd(10)); + AiDelay(monster, 2 * (5 - monster._mint) + GenerateRnd(10)); } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void SkeletonBowAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int mx = monst->position.tile.x - monst->enemyPosition.x; - int my = monst->position.tile.y - monst->enemyPosition.y; + int mx = monster.position.tile.x - monster.enemyPosition.x; + int my = monster.position.tile.y - monster.enemyPosition.y; - Direction md = GetMonsterDirection(i); - monst->_mdir = md; + Direction md = GetMonsterDirection(monster); + monster._mdir = md; int v = GenerateRnd(100); bool walking = false; if (abs(mx) < 4 && abs(my) < 4) { - if ((monst->_mVar2 > 20 && v < 2 * monst->_mint + 13) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) - && monst->_mVar2 == 0 - && v < 2 * monst->_mint + 63)) { + if ((monster._mVar2 > 20 && v < 2 * monster._mint + 13) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) + && monster._mVar2 == 0 + && v < 2 * monster._mint + 63)) { walking = DumbWalk(i, opposite[md]); } } if (!walking) { - if (GenerateRnd(100) < 2 * monst->_mint + 3) { - if (LineClearMissile(monst->position.tile, monst->enemyPosition)) - StartRangedAttack(i, MIS_ARROW, 4); + if (GenerateRnd(100) < 2 * monster._mint + 3) { + if (LineClearMissile(monster.position.tile, monster.enemyPosition)) + StartRangedAttack(monster, MIS_ARROW, 4); } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void ScavengerAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) + if (monster._mmode != MM_STAND) return; - if (monst->_mhitpoints < (monst->_mmaxhp / 2) && monst->_mgoal != MGOAL_HEALING) { - if (monst->leaderflag != 0) { - Monsters[monst->leader].packsize--; - monst->leaderflag = 0; - } - monst->_mgoal = MGOAL_HEALING; - monst->_mgoalvar3 = 10; - } - if (monst->_mgoal == MGOAL_HEALING && monst->_mgoalvar3 != 0) { - monst->_mgoalvar3--; - if (dDead[monst->position.tile.x][monst->position.tile.y] != 0) { - StartEating(i); - if ((monst->_mFlags & MFLAG_NOHEAL) == 0) { + if (monster._mhitpoints < (monster._mmaxhp / 2) && monster._mgoal != MGOAL_HEALING) { + if (monster.leaderflag != 0) { + Monsters[monster.leader].packsize--; + monster.leaderflag = 0; + } + monster._mgoal = MGOAL_HEALING; + monster._mgoalvar3 = 10; + } + if (monster._mgoal == MGOAL_HEALING && monster._mgoalvar3 != 0) { + monster._mgoalvar3--; + if (dDead[monster.position.tile.x][monster.position.tile.y] != 0) { + StartEating(monster); + if ((monster._mFlags & MFLAG_NOHEAL) == 0) { if (gbIsHellfire) { - int mMaxHP = monst->_mmaxhp; // BUGFIX use _mmaxhp or we loose health when difficulty isn't normal (fixed) - monst->_mhitpoints += mMaxHP / 8; - if (monst->_mhitpoints > monst->_mmaxhp) - monst->_mhitpoints = monst->_mmaxhp; - if (monst->_mgoalvar3 <= 0 || monst->_mhitpoints == monst->_mmaxhp) - dDead[monst->position.tile.x][monst->position.tile.y] = 0; + int mMaxHP = monster._mmaxhp; // BUGFIX use _mmaxhp or we loose health when difficulty isn't normal (fixed) + monster._mhitpoints += mMaxHP / 8; + if (monster._mhitpoints > monster._mmaxhp) + monster._mhitpoints = monster._mmaxhp; + if (monster._mgoalvar3 <= 0 || monster._mhitpoints == monster._mmaxhp) + dDead[monster.position.tile.x][monster.position.tile.y] = 0; } else { - monst->_mhitpoints += 64; + monster._mhitpoints += 64; } } - int targetHealth = monst->_mmaxhp; + int targetHealth = monster._mmaxhp; if (!gbIsHellfire) - targetHealth = (monst->_mmaxhp / 2) + (monst->_mmaxhp / 4); - if (monst->_mhitpoints >= targetHealth) { - monst->_mgoal = MGOAL_NORMAL; - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = 0; + targetHealth = (monster._mmaxhp / 2) + (monster._mmaxhp / 4); + if (monster._mhitpoints >= targetHealth) { + monster._mgoal = MGOAL_NORMAL; + monster._mgoalvar1 = 0; + monster._mgoalvar2 = 0; } } else { - if (monst->_mgoalvar1 == 0) { + if (monster._mgoalvar1 == 0) { bool done = false; int x; int y; @@ -2574,10 +2561,10 @@ void ScavengerAi(int i) // BUGFIX: incorrect check of offset against limits of the dungeon if (y < 0 || y >= MAXDUNY || x < 0 || x >= MAXDUNX) continue; - done = dDead[monst->position.tile.x + x][monst->position.tile.y + y] != 0 + done = dDead[monster.position.tile.x + x][monster.position.tile.y + y] != 0 && IsLineNotSolid( - monst->position.tile, - monst->position.tile + Displacement { x, y }); + monster.position.tile, + monster.position.tile + Displacement { x, y }); } } x--; @@ -2588,95 +2575,96 @@ void ScavengerAi(int i) // BUGFIX: incorrect check of offset against limits of the dungeon if (y < 0 || y >= MAXDUNY || x < 0 || x >= MAXDUNX) continue; - done = dDead[monst->position.tile.x + x][monst->position.tile.y + y] != 0 + done = dDead[monster.position.tile.x + x][monster.position.tile.y + y] != 0 && IsLineNotSolid( - monst->position.tile, - monst->position.tile + Displacement { x, y }); + monster.position.tile, + monster.position.tile + Displacement { x, y }); } } x++; y++; } if (done) { - monst->_mgoalvar1 = x + monst->position.tile.x + 1; - monst->_mgoalvar2 = y + monst->position.tile.y + 1; + monster._mgoalvar1 = x + monster.position.tile.x + 1; + monster._mgoalvar2 = y + monster.position.tile.y + 1; } } - if (monst->_mgoalvar1 != 0) { - int x = monst->_mgoalvar1 - 1; - int y = monst->_mgoalvar2 - 1; - monst->_mdir = GetDirection(monst->position.tile, { x, y }); - RandomWalk(i, monst->_mdir); + if (monster._mgoalvar1 != 0) { + int x = monster._mgoalvar1 - 1; + int y = monster._mgoalvar2 - 1; + monster._mdir = GetDirection(monster.position.tile, { x, y }); + RandomWalk(i, monster._mdir); } } } - if (monst->_mmode == MM_STAND) + if (monster._mmode == MM_STAND) SkeletonAi(i); } void RhinoAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(100); int dist = std::max(abs(mx), abs(my)); if (dist >= 2) { - if (monst->_mgoal == MGOAL_MOVE || (dist >= 5 && GenerateRnd(4) != 0)) { - if (monst->_mgoal != MGOAL_MOVE) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + if (monster._mgoal == MGOAL_MOVE || (dist >= 5 && GenerateRnd(4) != 0)) { + if (monster._mgoal != MGOAL_MOVE) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; - if (monst->_mgoalvar1++ >= 2 * dist || dTransVal[monst->position.tile.x][monst->position.tile.y] != dTransVal[fx][fy]) { - monst->_mgoal = MGOAL_NORMAL; - } else if (!RoundWalk(i, md, &monst->_mgoalvar2)) { - AiDelay(i, GenerateRnd(10) + 10); + monster._mgoal = MGOAL_MOVE; + if (monster._mgoalvar1++ >= 2 * dist || dTransVal[monster.position.tile.x][monster.position.tile.y] != dTransVal[fx][fy]) { + monster._mgoal = MGOAL_NORMAL; + } else if (!RoundWalk(i, md, &monster._mgoalvar2)) { + AiDelay(monster, GenerateRnd(10) + 10); } } } else { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) { + if (monster._mgoal == MGOAL_NORMAL) { if (dist >= 5 - && v < 2 * monst->_mint + 43 - && LineClear(PosOkMonst, i, monst->position.tile, { fx, fy })) { - if (AddMissile(monst->position.tile, { fx, fy }, md, MIS_RHINO, monst->_menemy, i, 0, 0) != -1) { - if (monst->MData->snd_special) - PlayEffect(i, 3); - dMonster[monst->position.tile.x][monst->position.tile.y] = -(i + 1); - monst->_mmode = MM_CHARGE; + && v < 2 * monster._mint + 43 + && LineClear(MonsterIsTileAvalible, i, monster.position.tile, { fx, fy })) { + if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, monster._menemy, i, 0, 0) != -1) { + if (monster.MData->snd_special) + PlayEffect(monster, 3); + dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); + monster._mmode = MM_CHARGE; } } else { if (dist >= 2) { v = GenerateRnd(100); - if (v >= 2 * monst->_mint + 33 - && ((monst->_mVar1 != MM_WALK && monst->_mVar1 != MM_WALK2 && monst->_mVar1 != MM_WALK3) - || monst->_mVar2 != 0 - || v >= 2 * monst->_mint + 83)) { - AiDelay(i, GenerateRnd(10) + 10); + if (v >= 2 * monster._mint + 33 + && ((monster._mVar1 != MM_WALK && monster._mVar1 != MM_WALK2 && monster._mVar1 != MM_WALK3) + || monster._mVar2 != 0 + || v >= 2 * monster._mint + 83)) { + AiDelay(monster, GenerateRnd(10) + 10); } else { RandomWalk(i, md); } - } else if (v < 2 * monst->_mint + 28) { - monst->_mdir = md; - StartAttack(i); + } else if (v < 2 * monster._mint + 28) { + monster._mdir = md; + StartAttack(monster); } } } - monst->CheckStandAnimationIsLoaded(monst->_mdir); + monster.CheckStandAnimationIsLoaded(monster._mdir); } void GoatAi(int i) @@ -2691,63 +2679,64 @@ void GoatBowAi(int i) void FallenAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mgoal == MGOAL_ATTACK2) { - if (monst->_mgoalvar1 != 0) - monst->_mgoalvar1--; + if (monster._mgoal == MGOAL_ATTACK2) { + if (monster._mgoalvar1 != 0) + monster._mgoalvar1--; else - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - if (monst->_mgoal == MGOAL_RETREAT) { - if (monst->_mgoalvar1-- == 0) { - monst->_mgoal = MGOAL_NORMAL; - M_StartStand(i, opposite[monst->_mgoalvar2]); + if (monster._mgoal == MGOAL_RETREAT) { + if (monster._mgoalvar1-- == 0) { + monster._mgoal = MGOAL_NORMAL; + M_StartStand(monster, opposite[monster._mgoalvar2]); } } - if (monst->AnimInfo.CurrentFrame == monst->AnimInfo.NumberOfFrames) { + if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames) { if (GenerateRnd(4) != 0) { return; } - if ((Monsters[i]._mFlags & MFLAG_NOHEAL) == 0) { // CODEFIX: - change to Monst-> in devilutionx - StartSpecialStand(i, monst->_mdir); - if (monst->_mmaxhp - (2 * monst->_mint + 2) >= monst->_mhitpoints) - monst->_mhitpoints += 2 * monst->_mint + 2; + if ((monster._mFlags & MFLAG_NOHEAL) == 0) { + StartSpecialStand(monster, monster._mdir); + if (monster._mmaxhp - (2 * monster._mint + 2) >= monster._mhitpoints) + monster._mhitpoints += 2 * monster._mint + 2; else - monst->_mhitpoints = monst->_mmaxhp; + monster._mhitpoints = monster._mmaxhp; } - int rad = 2 * monst->_mint + 4; + int rad = 2 * monster._mint + 4; for (int y = -rad; y <= rad; y++) { for (int x = -rad; x <= rad; x++) { - int xpos = monst->position.tile.x + x; - int ypos = monst->position.tile.y + y; + int xpos = monster.position.tile.x + x; + int ypos = monster.position.tile.y + y; if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { int m = dMonster[xpos][ypos]; if (m > 0) { m--; - if (Monsters[m]._mAi == AI_FALLEN) { - Monsters[m]._mgoal = MGOAL_ATTACK2; - Monsters[m]._mgoalvar1 = 30 * monst->_mint + 105; + auto &otherMonster = Monsters[m]; + if (otherMonster._mAi == AI_FALLEN) { + otherMonster._mgoal = MGOAL_ATTACK2; + otherMonster._mgoalvar1 = 30 * monster._mint + 105; } } } } } - } else if (monst->_mgoal == MGOAL_RETREAT) { - RandomWalk(i, monst->_mdir); - } else if (monst->_mgoal == MGOAL_ATTACK2) { - int xpos = monst->position.tile.x - monst->enemyPosition.x; - int ypos = monst->position.tile.y - monst->enemyPosition.y; + } else if (monster._mgoal == MGOAL_RETREAT) { + RandomWalk(i, monster._mdir); + } else if (monster._mgoal == MGOAL_ATTACK2) { + int xpos = monster.position.tile.x - monster.enemyPosition.x; + int ypos = monster.position.tile.y - monster.enemyPosition.y; if (abs(xpos) < 2 && abs(ypos) < 2) - StartAttack(i); + StartAttack(monster); else - RandomWalk(i, GetMonsterDirection(i)); + RandomWalk(i, GetMonsterDirection(monster)); } else SkeletonAi(i); } @@ -2759,154 +2748,155 @@ void MagmaAi(int i) void LeoricAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(100); int dist = std::max(abs(mx), abs(my)); - if (dist >= 2 && monst->_msquelch == UINT8_MAX && dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[fx][fy]) { - if (monst->_mgoal == MGOAL_MOVE || ((abs(mx) >= 3 || abs(my) >= 3) && GenerateRnd(4) == 0)) { - if (monst->_mgoal != MGOAL_MOVE) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + if (dist >= 2 && monster._msquelch == UINT8_MAX && dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[fx][fy]) { + if (monster._mgoal == MGOAL_MOVE || ((abs(mx) >= 3 || abs(my) >= 3) && GenerateRnd(4) == 0)) { + if (monster._mgoal != MGOAL_MOVE) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; - if ((monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md)) || dTransVal[monst->position.tile.x][monst->position.tile.y] != dTransVal[fx][fy]) { - monst->_mgoal = MGOAL_NORMAL; - } else if (!RoundWalk(i, md, &monst->_mgoalvar2)) { - AiDelay(i, GenerateRnd(10) + 10); + monster._mgoal = MGOAL_MOVE; + if ((monster._mgoalvar1++ >= 2 * dist && DirOK(i, md)) || dTransVal[monster.position.tile.x][monster.position.tile.y] != dTransVal[fx][fy]) { + monster._mgoal = MGOAL_NORMAL; + } else if (!RoundWalk(i, md, &monster._mgoalvar2)) { + AiDelay(monster, GenerateRnd(10) + 10); } } } else { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) { + if (monster._mgoal == MGOAL_NORMAL) { if (!gbIsMultiplayer - && ((dist >= 3 && v < 4 * monst->_mint + 35) || v < 6) - && LineClearMissile(monst->position.tile, { fx, fy })) { - Point newPosition = monst->position.tile + md; - if (PosOkMonst(i, newPosition) && ActiveMonsterCount < MAXMONSTERS) { + && ((dist >= 3 && v < 4 * monster._mint + 35) || v < 6) + && LineClearMissile(monster.position.tile, { fx, fy })) { + Point newPosition = monster.position.tile + md; + if (MonsterIsTileAvalible(i, newPosition) && ActiveMonsterCount < MAXMONSTERS) { SpawnSkeleton(newPosition, md); - StartSpecialStand(i, md); + StartSpecialStand(monster, md); } } else { if (dist >= 2) { v = GenerateRnd(100); - if (v >= monst->_mint + 25 - && ((monst->_mVar1 != MM_WALK && monst->_mVar1 != MM_WALK2 && monst->_mVar1 != MM_WALK3) || monst->_mVar2 != 0 || (v >= monst->_mint + 75))) { - AiDelay(i, GenerateRnd(10) + 10); + if (v >= monster._mint + 25 + && ((monster._mVar1 != MM_WALK && monster._mVar1 != MM_WALK2 && monster._mVar1 != MM_WALK3) || monster._mVar2 != 0 || (v >= monster._mint + 75))) { + AiDelay(monster, GenerateRnd(10) + 10); } else { RandomWalk(i, md); } - } else if (v < monst->_mint + 20) { - monst->_mdir = md; - StartAttack(i); + } else if (v < monster._mint + 20) { + monster._mdir = md; + StartAttack(monster); } } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void BatAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - int pnum = monst->_menemy; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + int pnum = monster._menemy; + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int xd = monst->position.tile.x - monst->enemyPosition.x; - int yd = monst->position.tile.y - monst->enemyPosition.y; - Direction md = GetDirection(monst->position.tile, monst->position.last); - monst->_mdir = md; + int xd = monster.position.tile.x - monster.enemyPosition.x; + int yd = monster.position.tile.y - monster.enemyPosition.y; + Direction md = GetDirection(monster.position.tile, monster.position.last); + monster._mdir = md; int v = GenerateRnd(100); - if (monst->_mgoal == MGOAL_RETREAT) { - if (monst->_mgoalvar1 == 0) { + if (monster._mgoal == MGOAL_RETREAT) { + if (monster._mgoalvar1 == 0) { RandomWalk(i, opposite[md]); - monst->_mgoalvar1++; + monster._mgoalvar1++; } else { if (GenerateRnd(2) != 0) RandomWalk(i, left[md]); else RandomWalk(i, right[md]); - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - if (monst->MType->mtype == MT_GLOOM + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + if (monster.MType->mtype == MT_GLOOM && (abs(xd) >= 5 || abs(yd) >= 5) - && v < 4 * monst->_mint + 33 - && LineClear(PosOkMonst, i, monst->position.tile, { fx, fy })) { - if (AddMissile(monst->position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { - dMonster[monst->position.tile.x][monst->position.tile.y] = -(i + 1); - monst->_mmode = MM_CHARGE; + && v < 4 * monster._mint + 33 + && LineClear(MonsterIsTileAvalible, i, monster.position.tile, { fx, fy })) { + if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { + dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); + monster._mmode = MM_CHARGE; } } else if (abs(xd) >= 2 || abs(yd) >= 2) { - if ((monst->_mVar2 > 20 && v < monst->_mint + 13) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) - && monst->_mVar2 == 0 - && v < monst->_mint + 63)) { + if ((monster._mVar2 > 20 && v < monster._mint + 13) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) + && monster._mVar2 == 0 + && v < monster._mint + 63)) { RandomWalk(i, md); } - } else if (v < 4 * monst->_mint + 8) { - StartAttack(i); - monst->_mgoal = MGOAL_RETREAT; - monst->_mgoalvar1 = 0; - if (monst->MType->mtype == MT_FAMILIAR) { - AddMissile(monst->enemyPosition, { monst->enemyPosition.x + 1, 0 }, -1, MIS_LIGHTNING, TARGET_PLAYERS, i, GenerateRnd(10) + 1, 0); + } else if (v < 4 * monster._mint + 8) { + StartAttack(monster); + monster._mgoal = MGOAL_RETREAT; + monster._mgoalvar1 = 0; + if (monster.MType->mtype == MT_FAMILIAR) { + AddMissile(monster.enemyPosition, { monster.enemyPosition.x + 1, 0 }, -1, MIS_LIGHTNING, TARGET_PLAYERS, i, GenerateRnd(10) + 1, 0); } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void GargoyleAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - int dx = monst->position.tile.x - monst->position.last.x; - int dy = monst->position.tile.y - monst->position.last.y; - Direction md = GetMonsterDirection(i); - if (monst->_msquelch != 0 && (monst->_mFlags & MFLAG_ALLOW_SPECIAL) != 0) { - UpdateEnemy(i); - int mx = monst->position.tile.x - monst->enemyPosition.x; - int my = monst->position.tile.y - monst->enemyPosition.y; - if (abs(mx) < monst->_mint + 2 && abs(my) < monst->_mint + 2) { - monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; + int dx = monster.position.tile.x - monster.position.last.x; + int dy = monster.position.tile.y - monster.position.last.y; + Direction md = GetMonsterDirection(monster); + if (monster._msquelch != 0 && (monster._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { + UpdateEnemy(monster); + int mx = monster.position.tile.x - monster.enemyPosition.x; + int my = monster.position.tile.y - monster.enemyPosition.y; + if (abs(mx) < monster._mint + 2 && abs(my) < monster._mint + 2) { + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; } return; } - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - if (monst->_mhitpoints < (monst->_mmaxhp / 2)) - if ((monst->_mFlags & MFLAG_NOHEAL) == 0) - monst->_mgoal = MGOAL_RETREAT; - if (monst->_mgoal == MGOAL_RETREAT) { - if (abs(dx) >= monst->_mint + 2 || abs(dy) >= monst->_mint + 2) { - monst->_mgoal = MGOAL_NORMAL; - StartHeal(i); + if (monster._mhitpoints < (monster._mmaxhp / 2)) + if ((monster._mFlags & MFLAG_NOHEAL) == 0) + monster._mgoal = MGOAL_RETREAT; + if (monster._mgoal == MGOAL_RETREAT) { + if (abs(dx) >= monster._mint + 2 || abs(dy) >= monster._mint + 2) { + monster._mgoal = MGOAL_NORMAL; + StartHeal(monster); } else if (!RandomWalk(i, opposite[md])) { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } } AiAvoidance(i, false); @@ -2914,27 +2904,27 @@ void GargoyleAi(int i) void ButcherAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - int x = mx - monst->enemyPosition.x; - int y = my - monst->enemyPosition.y; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + int x = mx - monster.enemyPosition.x; + int y = my - monster.enemyPosition.y; - Direction md = GetDirection({ mx, my }, monst->position.last); - monst->_mdir = md; + Direction md = GetDirection({ mx, my }, monster.position.last); + monster._mdir = md; if (abs(x) >= 2 || abs(y) >= 2) RandomWalk(i, md); else - StartAttack(i); + StartAttack(monster); - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void SuccubusAi(int i) @@ -2944,62 +2934,62 @@ void SuccubusAi(int i) void SneakAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; if (dLight[mx][my] == LightsMax) { return; } - mx -= monst->enemyPosition.x; - my -= monst->enemyPosition.y; - - int dist = 5 - monst->_mint; - if (monst->_mVar1 == MM_GOTHIT) { - monst->_mgoal = MGOAL_RETREAT; - monst->_mgoalvar1 = 0; - } else if (abs(mx) >= dist + 3 || abs(my) >= dist + 3 || monst->_mgoalvar1 > 8) { - monst->_mgoal = MGOAL_NORMAL; - monst->_mgoalvar1 = 0; - } - Direction md = GetMonsterDirection(i); - if (monst->_mgoal == MGOAL_RETREAT && (monst->_mFlags & MFLAG_NO_ENEMY) == 0) { - if ((monst->_mFlags & MFLAG_TARGETS_MONSTER) != 0) - md = GetDirection(monst->position.tile, Monsters[monst->_menemy].position.tile); + mx -= monster.enemyPosition.x; + my -= monster.enemyPosition.y; + + int dist = 5 - monster._mint; + if (monster._mVar1 == MM_GOTHIT) { + monster._mgoal = MGOAL_RETREAT; + monster._mgoalvar1 = 0; + } else if (abs(mx) >= dist + 3 || abs(my) >= dist + 3 || monster._mgoalvar1 > 8) { + monster._mgoal = MGOAL_NORMAL; + monster._mgoalvar1 = 0; + } + Direction md = GetMonsterDirection(monster); + if (monster._mgoal == MGOAL_RETREAT && (monster._mFlags & MFLAG_NO_ENEMY) == 0) { + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) + md = GetDirection(monster.position.tile, Monsters[monster._menemy].position.tile); else - md = GetDirection(monst->position.tile, Players[monst->_menemy].position.last); + md = GetDirection(monster.position.tile, Players[monster._menemy].position.last); md = opposite[md]; - if (monst->MType->mtype == MT_UNSEEN) { + if (monster.MType->mtype == MT_UNSEEN) { if (GenerateRnd(2) != 0) md = left[md]; else md = right[md]; } } - monst->_mdir = md; + monster._mdir = md; int v = GenerateRnd(100); - if (abs(mx) < dist && abs(my) < dist && (monst->_mFlags & MFLAG_HIDDEN) != 0) { - StartFadein(i, md, false); + if (abs(mx) < dist && abs(my) < dist && (monster._mFlags & MFLAG_HIDDEN) != 0) { + StartFadein(monster, md, false); } else { - if ((abs(mx) >= dist + 1 || abs(my) >= dist + 1) && (monst->_mFlags & MFLAG_HIDDEN) == 0) { - StartFadeout(i, md, true); + if ((abs(mx) >= dist + 1 || abs(my) >= dist + 1) && (monster._mFlags & MFLAG_HIDDEN) == 0) { + StartFadeout(monster, md, true); } else { - if (monst->_mgoal == MGOAL_RETREAT - || ((abs(mx) >= 2 || abs(my) >= 2) && ((monst->_mVar2 > 20 && v < 4 * monst->_mint + 14) || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) && monst->_mVar2 == 0 && v < 4 * monst->_mint + 64)))) { - monst->_mgoalvar1++; + if (monster._mgoal == MGOAL_RETREAT + || ((abs(mx) >= 2 || abs(my) >= 2) && ((monster._mVar2 > 20 && v < 4 * monster._mint + 14) || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) && monster._mVar2 == 0 && v < 4 * monster._mint + 64)))) { + monster._mgoalvar1++; RandomWalk(i, md); } } } - if (monst->_mmode == MM_STAND) { - if (abs(mx) >= 2 || abs(my) >= 2 || v >= 4 * monst->_mint + 10) - monst->AnimInfo.pCelSprite = &*monst->MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[md]; + if (monster._mmode == MM_STAND) { + if (abs(mx) >= 2 || abs(my) >= 2 || v >= 4 * monster._mint + 10) + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[md]; else - StartAttack(i); + StartAttack(monster); } } @@ -3010,86 +3000,86 @@ void StormAi(int i) void FiremanAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND || monst->_msquelch == 0) + if (monster._mmode != MM_STAND || monster._msquelch == 0) return; - int pnum = Monsters[i]._menemy; - int fx = Monsters[i].enemyPosition.x; - int fy = Monsters[i].enemyPosition.y; - int xd = Monsters[i].position.tile.x - fx; - int yd = Monsters[i].position.tile.y - fy; - - Direction md = GetMonsterDirection(i); - if (monst->_mgoal == MGOAL_NORMAL) { - if (LineClearMissile(monst->position.tile, { fx, fy }) - && AddMissile(monst->position.tile, { fx, fy }, md, MIS_FIREMAN, pnum, i, 0, 0) != -1) { - monst->_mmode = MM_CHARGE; - monst->_mgoal = MGOAL_ATTACK2; - monst->_mgoalvar1 = 0; - } - } else if (monst->_mgoal == MGOAL_ATTACK2) { - if (monst->_mgoalvar1 == 3) { - monst->_mgoal = MGOAL_NORMAL; - StartFadeout(i, md, true); - } else if (LineClearMissile(monst->position.tile, { fx, fy })) { - StartRangedAttack(i, MIS_KRULL, 4); - monst->_mgoalvar1++; + int pnum = monster._menemy; + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int xd = monster.position.tile.x - fx; + int yd = monster.position.tile.y - fy; + + Direction md = GetMonsterDirection(monster); + if (monster._mgoal == MGOAL_NORMAL) { + if (LineClearMissile(monster.position.tile, { fx, fy }) + && AddMissile(monster.position.tile, { fx, fy }, md, MIS_FIREMAN, pnum, i, 0, 0) != -1) { + monster._mmode = MM_CHARGE; + monster._mgoal = MGOAL_ATTACK2; + monster._mgoalvar1 = 0; + } + } else if (monster._mgoal == MGOAL_ATTACK2) { + if (monster._mgoalvar1 == 3) { + monster._mgoal = MGOAL_NORMAL; + StartFadeout(monster, md, true); + } else if (LineClearMissile(monster.position.tile, { fx, fy })) { + StartRangedAttack(monster, MIS_KRULL, 4); + monster._mgoalvar1++; } else { - AiDelay(i, GenerateRnd(10) + 5); - monst->_mgoalvar1++; + AiDelay(monster, GenerateRnd(10) + 5); + monster._mgoalvar1++; } - } else if (monst->_mgoal == MGOAL_RETREAT) { - StartFadein(i, md, false); - monst->_mgoal = MGOAL_ATTACK2; + } else if (monster._mgoal == MGOAL_RETREAT) { + StartFadein(monster, md, false); + monster._mgoal = MGOAL_ATTACK2; } - monst->_mdir = md; + monster._mdir = md; AdvanceRndSeed(); - if (monst->_mmode != MM_STAND) + if (monster._mmode != MM_STAND) return; - if (abs(xd) < 2 && abs(yd) < 2 && monst->_mgoal == MGOAL_NORMAL) { - MonsterAttackPlayer(i, Monsters[i]._menemy, Monsters[i].mHit, Monsters[i].mMinDamage, Monsters[i].mMaxDamage); - monst->_mgoal = MGOAL_RETREAT; + if (abs(xd) < 2 && abs(yd) < 2 && monster._mgoal == MGOAL_NORMAL) { + MonsterAttackPlayer(i, monster._menemy, monster.mHit, monster.mMinDamage, monster.mMaxDamage); + monster._mgoal = MGOAL_RETREAT; if (!RandomWalk(i, opposite[md])) { - StartFadein(i, md, false); - monst->_mgoal = MGOAL_ATTACK2; + StartFadein(monster, md, false); + monster._mgoal = MGOAL_ATTACK2; } - } else if (!RandomWalk(i, md) && (monst->_mgoal == MGOAL_NORMAL || monst->_mgoal == MGOAL_RETREAT)) { - StartFadein(i, md, false); - monst->_mgoal = MGOAL_ATTACK2; + } else if (!RandomWalk(i, md) && (monster._mgoal == MGOAL_NORMAL || monster._mgoal == MGOAL_RETREAT)) { + StartFadein(monster, md, false); + monster._mgoal = MGOAL_ATTACK2; } } void GharbadAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); - if (monst->mtalkmsg >= TEXT_GARBUD1 - && monst->mtalkmsg <= TEXT_GARBUD3 + if (monster.mtalkmsg >= TEXT_GARBUD1 + && monster.mtalkmsg <= TEXT_GARBUD3 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 - && monst->_mgoal == MGOAL_TALKING) { - monst->_mgoal = MGOAL_INQUIRING; - switch (monst->mtalkmsg) { + && monster._mgoal == MGOAL_TALKING) { + monster._mgoal = MGOAL_INQUIRING; + switch (monster.mtalkmsg) { case TEXT_GARBUD1: - monst->mtalkmsg = TEXT_GARBUD2; + monster.mtalkmsg = TEXT_GARBUD2; break; case TEXT_GARBUD2: - monst->mtalkmsg = TEXT_GARBUD3; + monster.mtalkmsg = TEXT_GARBUD3; break; case TEXT_GARBUD3: - monst->mtalkmsg = TEXT_GARBUD4; + monster.mtalkmsg = TEXT_GARBUD4; break; default: break; @@ -3097,19 +3087,19 @@ void GharbadAi(int i) } if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - if (monst->mtalkmsg == TEXT_GARBUD4) { - if (!effect_is_playing(USFX_GARBUD4) && monst->_mgoal == MGOAL_TALKING) { - monst->_mgoal = MGOAL_NORMAL; - monst->_msquelch = UINT8_MAX; - monst->mtalkmsg = TEXT_NONE; + if (monster.mtalkmsg == TEXT_GARBUD4) { + if (!effect_is_playing(USFX_GARBUD4) && monster._mgoal == MGOAL_TALKING) { + monster._mgoal = MGOAL_NORMAL; + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; } } } - if (monst->_mgoal == MGOAL_NORMAL || monst->_mgoal == MGOAL_MOVE) + if (monster._mgoal == MGOAL_NORMAL || monster._mgoal == MGOAL_MOVE) AiAvoidance(i, true); - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void AcidAvoidanceAi(int i) @@ -3124,270 +3114,271 @@ void AcidAi(int i) void SnotSpilAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); - if (monst->mtalkmsg == TEXT_BANNER10 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && monst->_mgoal == MGOAL_TALKING) { - monst->mtalkmsg = TEXT_BANNER11; - monst->_mgoal = MGOAL_INQUIRING; + if (monster.mtalkmsg == TEXT_BANNER10 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && monster._mgoal == MGOAL_TALKING) { + monster.mtalkmsg = TEXT_BANNER11; + monster._mgoal = MGOAL_INQUIRING; } - if (monst->mtalkmsg == TEXT_BANNER11 && Quests[Q_LTBANNER]._qvar1 == 3) { - monst->mtalkmsg = TEXT_NONE; - monst->_mgoal = MGOAL_NORMAL; + if (monster.mtalkmsg == TEXT_BANNER11 && Quests[Q_LTBANNER]._qvar1 == 3) { + monster.mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; } if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - if (monst->mtalkmsg == TEXT_BANNER12) { - if (!effect_is_playing(USFX_SNOT3) && monst->_mgoal == MGOAL_TALKING) { + if (monster.mtalkmsg == TEXT_BANNER12) { + if (!effect_is_playing(USFX_SNOT3) && monster._mgoal == MGOAL_TALKING) { ObjChangeMap(setpc_x, setpc_y, setpc_x + setpc_w + 1, setpc_y + setpc_h + 1); Quests[Q_LTBANNER]._qvar1 = 3; RedoPlayerVision(); - monst->_msquelch = UINT8_MAX; - monst->mtalkmsg = TEXT_NONE; - monst->_mgoal = MGOAL_NORMAL; + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; } } if (Quests[Q_LTBANNER]._qvar1 == 3) { - if (monst->_mgoal == MGOAL_NORMAL || monst->_mgoal == MGOAL_ATTACK2) + if (monster._mgoal == MGOAL_NORMAL || monster._mgoal == MGOAL_ATTACK2) FallenAi(i); } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void SnakeAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + char pattern[6] = { 1, 1, 0, -1, -1, 0 }; - MonsterStruct *monst = &Monsters[i]; - int pnum = monst->_menemy; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) + int pnum = monster._menemy; + if (monster._mmode != MM_STAND || monster._msquelch == 0) return; - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - monst->_mdir = md; + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + monster._mdir = md; if (abs(mx) >= 2 || abs(my) >= 2) { - if (abs(mx) < 3 && abs(my) < 3 && LineClear(PosOkMonst, i, monst->position.tile, { fx, fy }) && monst->_mVar1 != MM_CHARGE) { - if (AddMissile(monst->position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { - PlayEffect(i, 0); - dMonster[monst->position.tile.x][monst->position.tile.y] = -(i + 1); - monst->_mmode = MM_CHARGE; + if (abs(mx) < 3 && abs(my) < 3 && LineClear(MonsterIsTileAvalible, i, monster.position.tile, { fx, fy }) && monster._mVar1 != MM_CHARGE) { + if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { + PlayEffect(monster, 0); + dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); + monster._mmode = MM_CHARGE; } - } else if (monst->_mVar1 == MM_DELAY || GenerateRnd(100) >= 35 - 2 * monst->_mint) { - if (pattern[monst->_mgoalvar1] == -1) + } else if (monster._mVar1 == MM_DELAY || GenerateRnd(100) >= 35 - 2 * monster._mint) { + if (pattern[monster._mgoalvar1] == -1) md = left[md]; - else if (pattern[monst->_mgoalvar1] == 1) + else if (pattern[monster._mgoalvar1] == 1) md = right[md]; - monst->_mgoalvar1++; - if (monst->_mgoalvar1 > 5) - monst->_mgoalvar1 = 0; + monster._mgoalvar1++; + if (monster._mgoalvar1 > 5) + monster._mgoalvar1 = 0; - if (md != monst->_mgoalvar2) { - int drift = md - monst->_mgoalvar2; + if (md != monster._mgoalvar2) { + int drift = md - monster._mgoalvar2; if (drift < 0) drift += 8; if (drift < 4) - md = right[monst->_mgoalvar2]; + md = right[monster._mgoalvar2]; else if (drift > 4) - md = left[monst->_mgoalvar2]; - monst->_mgoalvar2 = md; + md = left[monster._mgoalvar2]; + monster._mgoalvar2 = md; } if (!DumbWalk(i, md)) - RandomWalk2(i, monst->_mdir); + RandomWalk2(i, monster._mdir); } else { - AiDelay(i, 15 - monst->_mint + GenerateRnd(10)); + AiDelay(monster, 15 - monster._mint + GenerateRnd(10)); } } else { - if (monst->_mVar1 == MM_DELAY - || monst->_mVar1 == MM_CHARGE - || (GenerateRnd(100) < monst->_mint + 20)) { - StartAttack(i); + if (monster._mVar1 == MM_DELAY + || monster._mVar1 == MM_CHARGE + || (GenerateRnd(100) < monster._mint + 20)) { + StartAttack(monster); } else - AiDelay(i, 10 - monst->_mint + GenerateRnd(10)); + AiDelay(monster, 10 - monster._mint + GenerateRnd(10)); } - monst->CheckStandAnimationIsLoaded(monst->_mdir); + monster.CheckStandAnimationIsLoaded(monster._mdir); } void CounselorAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(100); - if (monst->_mgoal == MGOAL_RETREAT) { - if (monst->_mgoalvar1++ <= 3) + if (monster._mgoal == MGOAL_RETREAT) { + if (monster._mgoalvar1++ <= 3) RandomWalk(i, opposite[md]); else { - monst->_mgoal = MGOAL_NORMAL; - StartFadein(i, md, true); + monster._mgoal = MGOAL_NORMAL; + StartFadein(monster, md, true); } - } else if (monst->_mgoal == MGOAL_MOVE) { + } else if (monster._mgoal == MGOAL_MOVE) { int dist = std::max(abs(mx), abs(my)); - if (dist >= 2 && monst->_msquelch == UINT8_MAX && dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[fx][fy]) { - if (monst->_mgoalvar1++ < 2 * dist || !DirOK(i, md)) { - RoundWalk(i, md, &monst->_mgoalvar2); + if (dist >= 2 && monster._msquelch == UINT8_MAX && dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[fx][fy]) { + if (monster._mgoalvar1++ < 2 * dist || !DirOK(i, md)) { + RoundWalk(i, md, &monster._mgoalvar2); } else { - monst->_mgoal = MGOAL_NORMAL; - StartFadein(i, md, true); + monster._mgoal = MGOAL_NORMAL; + StartFadein(monster, md, true); } } - } else if (monst->_mgoal == MGOAL_NORMAL) { + } else if (monster._mgoal == MGOAL_NORMAL) { if (abs(mx) >= 2 || abs(my) >= 2) { - if (v < 5 * (monst->_mint + 10) && LineClearMissile(monst->position.tile, { fx, fy })) { + if (v < 5 * (monster._mint + 10) && LineClearMissile(monster.position.tile, { fx, fy })) { constexpr missile_id MissileTypes[4] = { MIS_FIREBOLT, MIS_CBOLT, MIS_LIGHTCTRL, MIS_FIREBALL }; - StartRangedAttack(i, MissileTypes[monst->_mint], monst->mMinDamage + GenerateRnd(monst->mMaxDamage - monst->mMinDamage + 1)); + StartRangedAttack(monster, MissileTypes[monster._mint], monster.mMinDamage + GenerateRnd(monster.mMaxDamage - monster.mMinDamage + 1)); } else if (GenerateRnd(100) < 30) { - monst->_mgoal = MGOAL_MOVE; - monst->_mgoalvar1 = 0; - StartFadeout(i, md, false); + monster._mgoal = MGOAL_MOVE; + monster._mgoalvar1 = 0; + StartFadeout(monster, md, false); } else - AiDelay(i, GenerateRnd(10) + 2 * (5 - monst->_mint)); + AiDelay(monster, GenerateRnd(10) + 2 * (5 - monster._mint)); } else { - monst->_mdir = md; - if (monst->_mhitpoints < (monst->_mmaxhp / 2)) { - monst->_mgoal = MGOAL_RETREAT; - monst->_mgoalvar1 = 0; - StartFadeout(i, md, false); - } else if (monst->_mVar1 == MM_DELAY - || GenerateRnd(100) < 2 * monst->_mint + 20) { - StartRangedAttack(i, MIS_NULL, 0); - AddMissile(monst->position.tile, { 0, 0 }, monst->_mdir, MIS_FLASH, TARGET_PLAYERS, i, 4, 0); - AddMissile(monst->position.tile, { 0, 0 }, monst->_mdir, MIS_FLASH2, TARGET_PLAYERS, i, 4, 0); + monster._mdir = md; + if (monster._mhitpoints < (monster._mmaxhp / 2)) { + monster._mgoal = MGOAL_RETREAT; + monster._mgoalvar1 = 0; + StartFadeout(monster, md, false); + } else if (monster._mVar1 == MM_DELAY + || GenerateRnd(100) < 2 * monster._mint + 20) { + StartRangedAttack(monster, MIS_NULL, 0); + AddMissile(monster.position.tile, { 0, 0 }, monster._mdir, MIS_FLASH, TARGET_PLAYERS, i, 4, 0); + AddMissile(monster.position.tile, { 0, 0 }, monster._mdir, MIS_FLASH2, TARGET_PLAYERS, i, 4, 0); } else - AiDelay(i, GenerateRnd(10) + 2 * (5 - monst->_mint)); + AiDelay(monster, GenerateRnd(10) + 2 * (5 - monster._mint)); } } - if (monst->_mmode == MM_STAND) { - AiDelay(i, GenerateRnd(10) + 5); + if (monster._mmode == MM_STAND) { + AiDelay(monster, GenerateRnd(10) + 5); } } void ZharAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); - if (monst->mtalkmsg == TEXT_ZHAR1 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && monst->_mgoal == MGOAL_TALKING) { - monst->mtalkmsg = TEXT_ZHAR2; - monst->_mgoal = MGOAL_INQUIRING; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); + if (monster.mtalkmsg == TEXT_ZHAR1 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && monster._mgoal == MGOAL_TALKING) { + monster.mtalkmsg = TEXT_ZHAR2; + monster._mgoal = MGOAL_INQUIRING; } if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - if (monst->mtalkmsg == TEXT_ZHAR2) { - if (!effect_is_playing(USFX_ZHAR2) && monst->_mgoal == MGOAL_TALKING) { - monst->_msquelch = UINT8_MAX; - monst->mtalkmsg = TEXT_NONE; - monst->_mgoal = MGOAL_NORMAL; + if (monster.mtalkmsg == TEXT_ZHAR2) { + if (!effect_is_playing(USFX_ZHAR2) && monster._mgoal == MGOAL_TALKING) { + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; } } } - if (monst->_mgoal == MGOAL_NORMAL || monst->_mgoal == MGOAL_RETREAT || monst->_mgoal == MGOAL_MOVE) + if (monster._mgoal == MGOAL_NORMAL || monster._mgoal == MGOAL_RETREAT || monster._mgoal == MGOAL_MOVE) CounselorAi(i); - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void MegaAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - int mx = monst->position.tile.x - monst->enemyPosition.x; - int my = monst->position.tile.y - monst->enemyPosition.y; + int mx = monster.position.tile.x - monster.enemyPosition.x; + int my = monster.position.tile.y - monster.enemyPosition.y; if (abs(mx) >= 5 || abs(my) >= 5) { SkeletonAi(i); return; } - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - mx = monst->position.tile.x - fx; - my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); - if (monst->_msquelch < UINT8_MAX) - MonstCheckDoors(i); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + mx = monster.position.tile.x - fx; + my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); + if (monster._msquelch < UINT8_MAX) + MonstCheckDoors(monster); int v = GenerateRnd(100); int dist = std::max(abs(mx), abs(my)); - if (dist >= 2 && monst->_msquelch == UINT8_MAX && dTransVal[monst->position.tile.x][monst->position.tile.y] == dTransVal[fx][fy]) { - if (monst->_mgoal == MGOAL_MOVE || dist >= 3) { - if (monst->_mgoal != MGOAL_MOVE) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + if (dist >= 2 && monster._msquelch == UINT8_MAX && dTransVal[monster.position.tile.x][monster.position.tile.y] == dTransVal[fx][fy]) { + if (monster._mgoal == MGOAL_MOVE || dist >= 3) { + if (monster._mgoal != MGOAL_MOVE) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; - monst->_mgoalvar3 = 4; - if (monst->_mgoalvar1++ < 2 * dist || !DirOK(i, md)) { - if (v < 5 * (monst->_mint + 16)) - RoundWalk(i, md, &monst->_mgoalvar2); + monster._mgoal = MGOAL_MOVE; + monster._mgoalvar3 = 4; + if (monster._mgoalvar1++ < 2 * dist || !DirOK(i, md)) { + if (v < 5 * (monster._mint + 16)) + RoundWalk(i, md, &monster._mgoalvar2); } else - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } } else { - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) { - if (((dist >= 3 && v < 5 * (monst->_mint + 2)) || v < 5 * (monst->_mint + 1) || monst->_mgoalvar3 == 4) && LineClearMissile(monst->position.tile, { fx, fy })) { - StartRangedSpecialAttack(i, MIS_FLAMEC, 0); + if (monster._mgoal == MGOAL_NORMAL) { + if (((dist >= 3 && v < 5 * (monster._mint + 2)) || v < 5 * (monster._mint + 1) || monster._mgoalvar3 == 4) && LineClearMissile(monster.position.tile, { fx, fy })) { + StartRangedSpecialAttack(monster, MIS_FLAMEC, 0); } else if (dist >= 2) { v = GenerateRnd(100); - if (v < 2 * (5 * monst->_mint + 25) - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) - && monst->_mVar2 == 0 - && v < 2 * (5 * monst->_mint + 40))) { + if (v < 2 * (5 * monster._mint + 25) + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) + && monster._mVar2 == 0 + && v < 2 * (5 * monster._mint + 40))) { RandomWalk(i, md); } } else { - if (GenerateRnd(100) < 10 * (monst->_mint + 4)) { - monst->_mdir = md; + if (GenerateRnd(100) < 10 * (monster._mint + 4)) { + monster._mdir = md; if (GenerateRnd(2) != 0) - StartAttack(i); + StartAttack(monster); else - StartRangedSpecialAttack(i, MIS_FLAMEC, 0); + StartRangedSpecialAttack(monster, MIS_FLAMEC, 0); } } - monst->_mgoalvar3 = 1; + monster._mgoalvar3 = 1; } - if (monst->_mmode == MM_STAND) { - AiDelay(i, GenerateRnd(10) + 5); + if (monster._mmode == MM_STAND) { + AiDelay(monster, GenerateRnd(10) + 5); } } @@ -3398,137 +3389,138 @@ void DiabloAi(int i) void LazarusAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { if (!gbIsMultiplayer) { - if (monst->mtalkmsg == TEXT_VILE13 && monst->_mgoal == MGOAL_INQUIRING && Players[MyPlayerId].position.tile.x == 35 && Players[MyPlayerId].position.tile.y == 46) { + if (monster.mtalkmsg == TEXT_VILE13 && monster._mgoal == MGOAL_INQUIRING && Players[MyPlayerId].position.tile.x == 35 && Players[MyPlayerId].position.tile.y == 46) { PlayInGameMovie("gendata\\fprst3.smk"); - monst->_mmode = MM_TALK; + monster._mmode = MM_TALK; Quests[Q_BETRAYER]._qvar1 = 5; } - if (monst->mtalkmsg == TEXT_VILE13 && !effect_is_playing(USFX_LAZ1) && monst->_mgoal == MGOAL_TALKING) { + if (monster.mtalkmsg == TEXT_VILE13 && !effect_is_playing(USFX_LAZ1) && monster._mgoal == MGOAL_TALKING) { ObjChangeMapResync(1, 18, 20, 24); RedoPlayerVision(); Quests[Q_BETRAYER]._qvar1 = 6; - monst->_mgoal = MGOAL_NORMAL; - monst->_msquelch = UINT8_MAX; - monst->mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; } } - if (gbIsMultiplayer && monst->mtalkmsg == TEXT_VILE13 && monst->_mgoal == MGOAL_INQUIRING && Quests[Q_BETRAYER]._qvar1 <= 3) { - monst->_mmode = MM_TALK; + if (gbIsMultiplayer && monster.mtalkmsg == TEXT_VILE13 && monster._mgoal == MGOAL_INQUIRING && Quests[Q_BETRAYER]._qvar1 <= 3) { + monster._mmode = MM_TALK; } } - if (monst->_mgoal == MGOAL_NORMAL || monst->_mgoal == MGOAL_RETREAT || monst->_mgoal == MGOAL_MOVE) { - if (!gbIsMultiplayer && Quests[Q_BETRAYER]._qvar1 == 4 && monst->mtalkmsg == TEXT_NONE) { // Fix save games affected by teleport bug + if (monster._mgoal == MGOAL_NORMAL || monster._mgoal == MGOAL_RETREAT || monster._mgoal == MGOAL_MOVE) { + if (!gbIsMultiplayer && Quests[Q_BETRAYER]._qvar1 == 4 && monster.mtalkmsg == TEXT_NONE) { // Fix save games affected by teleport bug ObjChangeMapResync(1, 18, 20, 24); RedoPlayerVision(); Quests[Q_BETRAYER]._qvar1 = 6; } - monst->mtalkmsg = TEXT_NONE; + monster.mtalkmsg = TEXT_NONE; CounselorAi(i); } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void LazarusMinionAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); - if (Monsters[i]._mmode != MM_STAND) + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + + if (monster._mmode != MM_STAND) return; - MonsterStruct *monst = &Monsters[i]; - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { if (!gbIsMultiplayer) { if (Quests[Q_BETRAYER]._qvar1 <= 5) { - monst->_mgoal = MGOAL_INQUIRING; + monster._mgoal = MGOAL_INQUIRING; } else { - monst->_mgoal = MGOAL_NORMAL; - monst->mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; + monster.mtalkmsg = TEXT_NONE; } } else - monst->_mgoal = MGOAL_NORMAL; + monster._mgoal = MGOAL_NORMAL; } - if (monst->_mgoal == MGOAL_NORMAL) + if (monster._mgoal == MGOAL_NORMAL) SuccubusAi(i); - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void LachdananAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); - if (monst->mtalkmsg == TEXT_VEIL9 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && Monsters[i]._mgoal == MGOAL_TALKING) { - monst->mtalkmsg = TEXT_VEIL10; - Monsters[i]._mgoal = MGOAL_INQUIRING; + if (monster.mtalkmsg == TEXT_VEIL9 && (dFlags[mx][my] & BFLAG_VISIBLE) == 0 && monster._mgoal == MGOAL_TALKING) { + monster.mtalkmsg = TEXT_VEIL10; + monster._mgoal = MGOAL_INQUIRING; } if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - if (monst->mtalkmsg == TEXT_VEIL11) { - if (!effect_is_playing(USFX_LACH3) && monst->_mgoal == MGOAL_TALKING) { - monst->mtalkmsg = TEXT_NONE; + if (monster.mtalkmsg == TEXT_VEIL11) { + if (!effect_is_playing(USFX_LACH3) && monster._mgoal == MGOAL_TALKING) { + monster.mtalkmsg = TEXT_NONE; Quests[Q_VEIL]._qactive = QUEST_DONE; M_StartKill(i, -1); } } } - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void WarlordAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (Monsters[i]._mmode != MM_STAND) { + if (monster._mmode != MM_STAND) { return; } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; - Direction md = GetMonsterDirection(i); + int mx = monster.position.tile.x; + int my = monster.position.tile.y; + Direction md = GetMonsterDirection(monster); if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - if (monst->mtalkmsg == TEXT_WARLRD9 && monst->_mgoal == MGOAL_INQUIRING) - monst->_mmode = MM_TALK; - if (monst->mtalkmsg == TEXT_WARLRD9 && !effect_is_playing(USFX_WARLRD1) && monst->_mgoal == MGOAL_TALKING) { - monst->_msquelch = UINT8_MAX; - monst->mtalkmsg = TEXT_NONE; - monst->_mgoal = MGOAL_NORMAL; + if (monster.mtalkmsg == TEXT_WARLRD9 && monster._mgoal == MGOAL_INQUIRING) + monster._mmode = MM_TALK; + if (monster.mtalkmsg == TEXT_WARLRD9 && !effect_is_playing(USFX_WARLRD1) && monster._mgoal == MGOAL_TALKING) { + monster._msquelch = UINT8_MAX; + monster.mtalkmsg = TEXT_NONE; + monster._mgoal = MGOAL_NORMAL; } } - if (monst->_mgoal == MGOAL_NORMAL) + if (monster._mgoal == MGOAL_NORMAL) SkeletonAi(i); - monst->CheckStandAnimationIsLoaded(md); + monster.CheckStandAnimationIsLoaded(md); } void FirebatAi(int i) @@ -3543,66 +3535,64 @@ void TorchantAi(int i) void HorkDemonAi(int i) { - if ((DWORD)i >= MAXMONSTERS) { - return; - } + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->_mmode != MM_STAND || monst->_msquelch == 0) { + if (monster._mmode != MM_STAND || monster._msquelch == 0) { return; } - int fx = monst->enemyPosition.x; - int fy = monst->enemyPosition.y; - int mx = monst->position.tile.x - fx; - int my = monst->position.tile.y - fy; - Direction md = GetDirection(monst->position.tile, monst->position.last); + int fx = monster.enemyPosition.x; + int fy = monster.enemyPosition.y; + int mx = monster.position.tile.x - fx; + int my = monster.position.tile.y - fy; + Direction md = GetDirection(monster.position.tile, monster.position.last); - if (monst->_msquelch < 255) { - MonstCheckDoors(i); + if (monster._msquelch < 255) { + MonstCheckDoors(monster); } int v = GenerateRnd(100); if (abs(mx) < 2 && abs(my) < 2) { - monst->_mgoal = MGOAL_NORMAL; - } else if (monst->_mgoal == 4 || ((abs(mx) >= 5 || abs(my) >= 5) && GenerateRnd(4) != 0)) { - if (monst->_mgoal != 4) { - monst->_mgoalvar1 = 0; - monst->_mgoalvar2 = GenerateRnd(2); + monster._mgoal = MGOAL_NORMAL; + } else if (monster._mgoal == 4 || ((abs(mx) >= 5 || abs(my) >= 5) && GenerateRnd(4) != 0)) { + if (monster._mgoal != 4) { + monster._mgoalvar1 = 0; + monster._mgoalvar2 = GenerateRnd(2); } - monst->_mgoal = MGOAL_MOVE; + monster._mgoal = MGOAL_MOVE; int dist = std::max(abs(mx), abs(my)); - if (monst->_mgoalvar1++ >= 2 * dist || dTransVal[monst->position.tile.x][monst->position.tile.y] != dTransVal[fx][fy]) { - monst->_mgoal = MGOAL_NORMAL; - } else if (!RoundWalk(i, md, &monst->_mgoalvar2)) { - AiDelay(i, GenerateRnd(10) + 10); + if (monster._mgoalvar1++ >= 2 * dist || dTransVal[monster.position.tile.x][monster.position.tile.y] != dTransVal[fx][fy]) { + monster._mgoal = MGOAL_NORMAL; + } else if (!RoundWalk(i, md, &monster._mgoalvar2)) { + AiDelay(monster, GenerateRnd(10) + 10); } } - if (monst->_mgoal == 1) { - if ((abs(mx) >= 3 || abs(my) >= 3) && v < 2 * monst->_mint + 43) { - Point position = monst->position.tile + monst->_mdir; - if (PosOkMonst(i, position) && ActiveMonsterCount < MAXMONSTERS) { - StartRangedSpecialAttack(i, MIS_HORKDMN, 0); + if (monster._mgoal == 1) { + if ((abs(mx) >= 3 || abs(my) >= 3) && v < 2 * monster._mint + 43) { + Point position = monster.position.tile + monster._mdir; + if (MonsterIsTileAvalible(i, position) && ActiveMonsterCount < MAXMONSTERS) { + StartRangedSpecialAttack(monster, MIS_HORKDMN, 0); } } else if (abs(mx) < 2 && abs(my) < 2) { - if (v < 2 * monst->_mint + 28) { - monst->_mdir = md; - StartAttack(i); + if (v < 2 * monster._mint + 28) { + monster._mdir = md; + StartAttack(monster); } } else { v = GenerateRnd(100); - if (v < 2 * monst->_mint + 33 - || ((monst->_mVar1 == MM_WALK || monst->_mVar1 == MM_WALK2 || monst->_mVar1 == MM_WALK3) && monst->_mVar2 == 0 && v < 2 * monst->_mint + 83)) { + if (v < 2 * monster._mint + 33 + || ((monster._mVar1 == MM_WALK || monster._mVar1 == MM_WALK2 || monster._mVar1 == MM_WALK3) && monster._mVar2 == 0 && v < 2 * monster._mint + 83)) { RandomWalk(i, md); } else { - AiDelay(i, GenerateRnd(10) + 10); + AiDelay(monster, GenerateRnd(10) + 10); } } } - monst->CheckStandAnimationIsLoaded(monst->_mdir); + monster.CheckStandAnimationIsLoaded(monster._mdir); } void LichAi(int i) @@ -3646,11 +3636,12 @@ const char *GetMonsterTypeText(const MonsterDataStruct &monsterData) void ActivateSpawn(int i, int x, int y, Direction dir) { + auto &monster = Monsters[i]; dMonster[x][y] = i + 1; - Monsters[i].position.tile = { x, y }; - Monsters[i].position.future = { x, y }; - Monsters[i].position.old = { x, y }; - StartSpecialStand(i, dir); + monster.position.tile = { x, y }; + monster.position.future = { x, y }; + monster.position.old = { x, y }; + StartSpecialStand(monster, dir); } /** Maps from monster AI ID to monster AI function. */ @@ -3962,18 +3953,15 @@ void InitMonsterGFX(int monst) void monster_some_crypt() { - MonsterStruct *mon; - int hp; - if (currlevel == 24 && UberDiabloMonsterIndex >= 0 && UberDiabloMonsterIndex < ActiveMonsterCount) { - mon = &Monsters[UberDiabloMonsterIndex]; - PlayEffect(UberDiabloMonsterIndex, 2); + auto &monster = Monsters[UberDiabloMonsterIndex]; + PlayEffect(monster, 2); Quests[Q_NAKRUL]._qlog = false; - mon->mArmorClass -= 50; - hp = mon->_mmaxhp / 2; - mon->mMagicRes = 0; - mon->_mhitpoints = hp; - mon->_mmaxhp = hp; + monster.mArmorClass -= 50; + int hp = monster._mmaxhp / 2; + monster.mMagicRes = 0; + monster._mhitpoints = hp; + monster._mmaxhp = hp; } } @@ -4091,7 +4079,7 @@ int AddMonster(Point position, Direction dir, int mtype, bool inMap) int i = ActiveMonsters[ActiveMonsterCount++]; if (inMap) dMonster[position.x][position.y] = i + 1; - InitMonster(i, dir, mtype, position); + InitMonster(Monsters[i], dir, mtype, position); return i; } @@ -4131,31 +4119,33 @@ void AddDoppelganger(MonsterStruct &monster) } } -bool M_Talker(int i) +bool M_Talker(MonsterStruct &monster) { - return IsAnyOf(Monsters[i]._mAi, AI_LAZARUS, AI_WARLORD, AI_GARBUD, AI_ZHAR, AI_SNOTSPIL, AI_LACHDAN, AI_LAZHELP); + return IsAnyOf(monster._mAi, AI_LAZARUS, AI_WARLORD, AI_GARBUD, AI_ZHAR, AI_SNOTSPIL, AI_LACHDAN, AI_LAZHELP); } -void M_StartStand(int i, Direction md) +void M_StartStand(MonsterStruct &monster, Direction md) { - ClearMVars(i); - if (Monsters[i].MType->mtype == MT_GOLEM) - NewMonsterAnim(Monsters[i], MonsterGraphic::Walk, md); + ClearMVars(monster); + if (monster.MType->mtype == MT_GOLEM) + NewMonsterAnim(monster, MonsterGraphic::Walk, md); else - NewMonsterAnim(Monsters[i], MonsterGraphic::Stand, md); - Monsters[i]._mVar1 = Monsters[i]._mmode; - Monsters[i]._mVar2 = 0; - Monsters[i]._mmode = MM_STAND; - Monsters[i].position.offset = { 0, 0 }; - Monsters[i].position.future = Monsters[i].position.tile; - Monsters[i].position.old = Monsters[i].position.tile; - UpdateEnemy(i); + NewMonsterAnim(monster, MonsterGraphic::Stand, md); + monster._mVar1 = monster._mmode; + monster._mVar2 = 0; + monster._mmode = MM_STAND; + monster.position.offset = { 0, 0 }; + monster.position.future = monster.position.tile; + monster.position.old = monster.position.tile; + UpdateEnemy(monster); } void M_ClearSquares(int i) { - int mx = Monsters[i].position.old.x; - int my = Monsters[i].position.old.y; + auto &monster = Monsters[i]; + + int mx = monster.position.old.x; + int my = monster.position.old.y; int m1 = -(i + 1); int m2 = i + 1; @@ -4176,41 +4166,45 @@ void M_ClearSquares(int i) void M_GetKnockback(int i) { - Direction d = opposite[Monsters[i]._mdir]; + auto &monster = Monsters[i]; + + Direction d = opposite[monster._mdir]; if (!DirOK(i, d)) { return; } M_ClearSquares(i); - Monsters[i].position.old += d; + monster.position.old += d; StartMonsterGotHit(i); } void M_StartHit(int i, int pnum, int dam) { + auto &monster = Monsters[i]; + if (pnum >= 0) - Monsters[i].mWhoHit |= 1 << pnum; + monster.mWhoHit |= 1 << pnum; if (pnum == MyPlayerId) { - delta_monster_hp(i, Monsters[i]._mhitpoints, currlevel); + delta_monster_hp(i, monster._mhitpoints, currlevel); NetSendCmdMonDmg(false, i, dam); } - PlayEffect(i, 1); - if ((Monsters[i].MType->mtype >= MT_SNEAK && Monsters[i].MType->mtype <= MT_ILLWEAV) || dam >> 6 >= Monsters[i].mLevel + 3) { + PlayEffect(monster, 1); + if ((monster.MType->mtype >= MT_SNEAK && monster.MType->mtype <= MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { if (pnum >= 0) { - Monsters[i]._menemy = pnum; - Monsters[i].enemyPosition = Players[pnum].position.future; - Monsters[i]._mFlags &= ~MFLAG_TARGETS_MONSTER; - Monsters[i]._mdir = GetMonsterDirection(i); + monster._menemy = pnum; + monster.enemyPosition = Players[pnum].position.future; + monster._mFlags &= ~MFLAG_TARGETS_MONSTER; + monster._mdir = GetMonsterDirection(monster); } - if (Monsters[i].MType->mtype == MT_BLINK) { + if (monster.MType->mtype == MT_BLINK) { Teleport(i); - } else if ((Monsters[i].MType->mtype >= MT_NSCAV && Monsters[i].MType->mtype <= MT_YSCAV) - || Monsters[i].MType->mtype == MT_GRAVEDIG) { - Monsters[i]._mgoal = MGOAL_NORMAL; - Monsters[i]._mgoalvar1 = 0; - Monsters[i]._mgoalvar2 = 0; + } else if ((monster.MType->mtype >= MT_NSCAV && monster.MType->mtype <= MT_YSCAV) + || monster.MType->mtype == MT_GRAVEDIG) { + monster._mgoal = MGOAL_NORMAL; + monster._mgoalvar1 = 0; + monster._mgoalvar2 = 0; } - if (Monsters[i]._mmode != MM_STONE) { + if (monster._mmode != MM_STONE) { StartMonsterGotHit(i); } } @@ -4218,54 +4212,57 @@ void M_StartHit(int i, int pnum, int dam) void M_StartKill(int i, int pnum) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; if (MyPlayerId == pnum) { - delta_kill_monster(i, Monsters[i].position.tile, currlevel); + delta_kill_monster(i, monster.position.tile, currlevel); if (i != pnum) { - NetSendCmdLocParam1(false, CMD_MONSTDEATH, Monsters[i].position.tile, i); + NetSendCmdLocParam1(false, CMD_MONSTDEATH, monster.position.tile, i); } else { - NetSendCmdLocParam1(false, CMD_KILLGOLEM, Monsters[i].position.tile, currlevel); + NetSendCmdLocParam1(false, CMD_KILLGOLEM, monster.position.tile, currlevel); } } - MonsterDeath(i, pnum, true); + StartMonsterDeath(i, pnum, true); } void M_SyncStartKill(int i, Point position, int pnum) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; - if (Monsters[i]._mhitpoints > 0 || Monsters[i]._mmode == MM_DEATH) { + if (monster._mhitpoints > 0 || monster._mmode == MM_DEATH) { return; } if (dMonster[position.x][position.y] == 0) { M_ClearSquares(i); - Monsters[i].position.tile = position; - Monsters[i].position.old = position; + monster.position.tile = position; + monster.position.old = position; } - if (Monsters[i]._mmode == MM_STONE) { - MonsterDeath(i, pnum, false); - Monsters[i].Petrify(); + if (monster._mmode == MM_STONE) { + StartMonsterDeath(i, pnum, false); + monster.Petrify(); } else { - MonsterDeath(i, pnum, false); + StartMonsterDeath(i, pnum, false); } } void M_UpdateLeader(int i) { assurance((DWORD)i < MAXMONSTERS, i); + auto &monster = Monsters[i]; for (int j = 0; j < ActiveMonsterCount; j++) { - int ma = ActiveMonsters[j]; - if (Monsters[ma].leaderflag == 1 && Monsters[ma].leader == i) - Monsters[ma].leaderflag = 0; + auto &minion = Monsters[ActiveMonsters[j]]; + if (minion.leaderflag == 1 && minion.leader == i) + minion.leaderflag = 0; } - if (Monsters[i].leaderflag == 1) { - Monsters[Monsters[i].leader].packsize--; + if (monster.leaderflag == 1) { + Monsters[monster.leader].packsize--; } } @@ -4373,58 +4370,57 @@ void M_WalkDir(int i, Direction md) void GolumAi(int i) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &golem = Monsters[i]; - MonsterStruct *monst = &Monsters[i]; - if (monst->position.tile.x == 1 && monst->position.tile.y == 0) { + if (golem.position.tile.x == 1 && golem.position.tile.y == 0) { return; } - if (monst->_mmode == MM_DEATH - || monst->_mmode == MM_SPSTAND - || (monst->_mmode >= MM_WALK && monst->_mmode <= MM_WALK3)) { + if (golem._mmode == MM_DEATH + || golem._mmode == MM_SPSTAND + || (golem._mmode >= MM_WALK && golem._mmode <= MM_WALK3)) { return; } - if ((monst->_mFlags & MFLAG_TARGETS_MONSTER) == 0) - UpdateEnemy(i); + if ((golem._mFlags & MFLAG_TARGETS_MONSTER) == 0) + UpdateEnemy(golem); - bool haveEnemy = (Monsters[i]._mFlags & MFLAG_NO_ENEMY) == 0; + bool haveEnemy = (golem._mFlags & MFLAG_NO_ENEMY) == 0; - if (monst->_mmode == MM_ATTACK) { + if (golem._mmode == MM_ATTACK) { return; } - int menemy = Monsters[i]._menemy; + auto &enemy = Monsters[golem._menemy]; - int mex = Monsters[i].position.tile.x - Monsters[menemy].position.future.x; - int mey = Monsters[i].position.tile.y - Monsters[menemy].position.future.y; - Direction md = GetDirection(Monsters[i].position.tile, Monsters[menemy].position.tile); - Monsters[i]._mdir = md; + int mex = golem.position.tile.x - enemy.position.future.x; + int mey = golem.position.tile.y - enemy.position.future.y; + Direction md = GetDirection(golem.position.tile, enemy.position.tile); + golem._mdir = md; if (abs(mex) < 2 && abs(mey) < 2 && haveEnemy) { - menemy = Monsters[i]._menemy; - Monsters[i].enemyPosition = Monsters[menemy].position.tile; - if (Monsters[menemy]._msquelch == 0) { - Monsters[menemy]._msquelch = UINT8_MAX; - Monsters[Monsters[i]._menemy].position.last = Monsters[i].position.tile; + golem.enemyPosition = enemy.position.tile; + if (enemy._msquelch == 0) { + enemy._msquelch = UINT8_MAX; + enemy.position.last = golem.position.tile; for (int j = 0; j < 5; j++) { for (int k = 0; k < 5; k++) { - menemy = dMonster[Monsters[i].position.tile.x + k - 2][Monsters[i].position.tile.y + j - 2]; // BUGFIX: Check if indexes are between 0 and 112 + int menemy = dMonster[golem.position.tile.x + k - 2][golem.position.tile.y + j - 2]; // BUGFIX: Check if indexes are between 0 and 112 if (menemy > 0) Monsters[menemy - 1]._msquelch = UINT8_MAX; // BUGFIX: should be `Monsters[_menemy-1]`, not Monsters[_menemy]. (fixed) } } } - StartAttack(i); + StartAttack(golem); return; } if (haveEnemy && AiPlanPath(i)) return; - Monsters[i]._pathcount++; - if (Monsters[i]._pathcount > 8) - Monsters[i]._pathcount = 5; + golem._pathcount++; + if (golem._pathcount > 8) + golem._pathcount = 5; bool ok = RandomWalk(i, Players[i]._pdir); if (ok) @@ -4442,11 +4438,12 @@ void GolumAi(int i) void DeleteMonsterList() { for (int i = 0; i < MAX_PLRS; i++) { - if (Monsters[i]._mDelFlag) { - Monsters[i].position.tile = { 1, 0 }; - Monsters[i].position.future = { 0, 0 }; - Monsters[i].position.old = { 0, 0 }; - Monsters[i]._mDelFlag = false; + auto &golem = Monsters[i]; + if (golem._mDelFlag) { + golem.position.tile = { 1, 0 }; + golem.position.future = { 0, 0 }; + golem.position.old = { 0, 0 }; + golem._mDelFlag = false; } } @@ -4466,27 +4463,27 @@ void ProcessMonsters() assert((DWORD)ActiveMonsterCount <= MAXMONSTERS); for (int i = 0; i < ActiveMonsterCount; i++) { int mi = ActiveMonsters[i]; - MonsterStruct *monst = &Monsters[mi]; + auto &monster = Monsters[mi]; bool raflag = false; if (gbIsMultiplayer) { - SetRndSeed(monst->_mAISeed); - monst->_mAISeed = AdvanceRndSeed(); + SetRndSeed(monster._mAISeed); + monster._mAISeed = AdvanceRndSeed(); } - if ((Monsters[mi]._mFlags & MFLAG_NOHEAL) == 0 && monst->_mhitpoints < monst->_mmaxhp && monst->_mhitpoints >> 6 > 0) { - if (monst->mLevel > 1) { - monst->_mhitpoints += monst->mLevel / 2; + if ((monster._mFlags & MFLAG_NOHEAL) == 0 && monster._mhitpoints < monster._mmaxhp && monster._mhitpoints >> 6 > 0) { + if (monster.mLevel > 1) { + monster._mhitpoints += monster.mLevel / 2; } else { - monst->_mhitpoints += monst->mLevel; + monster._mhitpoints += monster.mLevel; } } - int mx = monst->position.tile.x; - int my = monst->position.tile.y; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; - if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0 && monst->_msquelch == 0) { - if (monst->MType->mtype == MT_CLEAVER) { + if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0 && monster._msquelch == 0) { + if (monster.MType->mtype == MT_CLEAVER) { PlaySFX(USFX_CLEAVER); } - if (monst->MType->mtype == MT_NAKRUL) { + if (monster.MType->mtype == MT_NAKRUL) { if (sgGameInitInfo.bCowQuest != 0) { PlaySFX(USFX_NAKRUL6); } else { @@ -4496,46 +4493,46 @@ void ProcessMonsters() PlaySFX(USFX_NAKRUL5); } } - if (monst->MType->mtype == MT_DEFILER) + if (monster.MType->mtype == MT_DEFILER) PlaySFX(USFX_DEFILER8); - UpdateEnemy(mi); + UpdateEnemy(monster); } int menemy; - if ((monst->_mFlags & MFLAG_TARGETS_MONSTER) != 0) { - menemy = monst->_menemy; + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) { + menemy = monster._menemy; assurance((DWORD)menemy < MAXMONSTERS, menemy); - monst->position.last = Monsters[monst->_menemy].position.future; - monst->enemyPosition = monst->position.last; + monster.position.last = Monsters[monster._menemy].position.future; + monster.enemyPosition = monster.position.last; } else { - menemy = monst->_menemy; + menemy = monster._menemy; assurance((DWORD)menemy < MAX_PLRS, menemy); - monst->enemyPosition = Players[monst->_menemy].position.future; + monster.enemyPosition = Players[monster._menemy].position.future; if ((dFlags[mx][my] & BFLAG_VISIBLE) != 0) { - monst->_msquelch = UINT8_MAX; - monst->position.last = Players[monst->_menemy].position.future; - } else if (monst->_msquelch != 0 && monst->MType->mtype != MT_DIABLO) { /// BUGFIX: change '_mAi' to 'MType->mtype' - monst->_msquelch--; + monster._msquelch = UINT8_MAX; + monster.position.last = Players[monster._menemy].position.future; + } else if (monster._msquelch != 0 && monster.MType->mtype != MT_DIABLO) { /// BUGFIX: change '_mAi' to 'MType->mtype' + monster._msquelch--; } } do { - if ((monst->_mFlags & MFLAG_SEARCH) == 0 || !AiPlanPath(mi)) { - AiProc[monst->_mAi](mi); + if ((monster._mFlags & MFLAG_SEARCH) == 0 || !AiPlanPath(mi)) { + AiProc[monster._mAi](mi); } - switch (monst->_mmode) { + switch (monster._mmode) { case MM_STAND: - raflag = MonsterIdle(mi); + raflag = MonsterIdle(monster); break; case MM_WALK: case MM_WALK2: case MM_WALK3: - raflag = MonsterWalk(mi, monst->_mmode); + raflag = MonsterWalk(mi, monster._mmode); break; case MM_ATTACK: raflag = MonsterAttack(mi); break; case MM_GOTHIT: - raflag = MonsterGotHit(mi); + raflag = MonsterGotHit(monster); break; case MM_DEATH: raflag = MonsterDeath(mi); @@ -4544,42 +4541,42 @@ void ProcessMonsters() raflag = MonsterSpecialAttack(mi); break; case MM_FADEIN: - raflag = MonsterFadein(mi); + raflag = MonsterFadein(monster); break; case MM_FADEOUT: - raflag = MonsterFadeout(mi); + raflag = MonsterFadeout(monster); break; case MM_RATTACK: raflag = MonaterRangedAttack(mi); break; case MM_SPSTAND: - raflag = MonsterSpecialStand(mi); + raflag = MonsterSpecialStand(monster); break; case MM_RSPATTACK: raflag = MonsterRangedSpecialAttack(mi); break; case MM_DELAY: - raflag = MonsterDelay(mi); + raflag = MonsterDelay(monster); break; case MM_CHARGE: raflag = false; break; case MM_STONE: - raflag = MonsterPetrified(mi); + raflag = MonsterPetrified(monster); break; case MM_HEAL: - raflag = MonsterHeal(mi); + raflag = MonsterHeal(monster); break; case MM_TALK: - raflag = MonsterTalk(mi); + raflag = MonsterTalk(monster); break; } if (raflag) { GroupUnity(mi); } } while (raflag); - if (monst->_mmode != MM_STONE) { - monst->AnimInfo.ProcessAnimation((monst->_mFlags & MFLAG_LOCK_ANIMATION) != 0, (monst->_mFlags & MFLAG_ALLOW_SPECIAL) != 0); + if (monster._mmode != MM_STONE) { + monster.AnimInfo.ProcessAnimation((monster._mFlags & MFLAG_LOCK_ANIMATION) != 0, (monster._mFlags & MFLAG_ALLOW_SPECIAL) != 0); } } @@ -4602,10 +4599,11 @@ void FreeMonsters() bool DirOK(int i, Direction mdir) { - commitment((DWORD)i < MAXMONSTERS, i); - Point position = Monsters[i].position.tile; + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; + Point position = monster.position.tile; Point futurePosition = position + mdir; - if (futurePosition.y < 0 || futurePosition.y >= MAXDUNY || futurePosition.x < 0 || futurePosition.x >= MAXDUNX || !PosOkMonst(i, futurePosition)) + if (futurePosition.y < 0 || futurePosition.y >= MAXDUNY || futurePosition.x < 0 || futurePosition.x >= MAXDUNX || !MonsterIsTileAvalible(i, futurePosition)) return false; if (mdir == DIR_E) { if (SolidLoc(position + DIR_SE) || (dFlags[position.x + 1][position.y] & BFLAG_MONSTLR) != 0) @@ -4619,10 +4617,10 @@ bool DirOK(int i, Direction mdir) } else if (mdir == DIR_S) if (SolidLoc(position + DIR_SW) || SolidLoc(position + DIR_SE)) return false; - if (Monsters[i].leaderflag == 1) { - return futurePosition.WalkingDistance(Monsters[Monsters[i].leader].position.future) < 4; + if (monster.leaderflag == 1) { + return futurePosition.WalkingDistance(Monsters[monster.leader].position.future) < 4; } - if (Monsters[i]._uniqtype == 0 || (UniqMonst[Monsters[i]._uniqtype - 1].mUnqAttr & 2) == 0) + if (monster._uniqtype == 0 || (UniqMonst[monster._uniqtype - 1].mUnqAttr & 2) == 0) return true; int mcount = 0; for (int x = futurePosition.x - 3; x <= futurePosition.x + 3; x++) { @@ -4635,14 +4633,15 @@ bool DirOK(int i, Direction mdir) if (mi != 0) mi--; // BUGFIX: should only run pack member check if mi was non-zero prior to executing the body of the above if-statement. - if (Monsters[mi].leaderflag == 1 - && Monsters[mi].leader == i - && Monsters[mi].position.future == Point { x, y }) { + auto &minion = Monsters[mi]; + if (minion.leaderflag == 1 + && minion.leader == i + && minion.position.future == Point { x, y }) { mcount++; } } } - return mcount == Monsters[i].packsize; + return mcount == monster.packsize; } bool PosOkMissile(int /*entity*/, Point position) @@ -4729,20 +4728,19 @@ bool LineClear(bool (*clear)(int, Point), int entity, Point startPoint, Point en return position == endPoint; } -void SyncMonsterAnim(int i) +void SyncMonsterAnim(MonsterStruct &monster) { - assurance((DWORD)i < MAXMONSTERS || i < 0, i); - Monsters[i].MType = &LevelMonsterTypes[Monsters[i]._mMTidx]; - Monsters[i].MData = LevelMonsterTypes[Monsters[i]._mMTidx].MData; - if (Monsters[i]._uniqtype != 0) - Monsters[i].mName = _(UniqMonst[Monsters[i]._uniqtype - 1].mName); + monster.MType = &LevelMonsterTypes[monster._mMTidx]; + monster.MData = LevelMonsterTypes[monster._mMTidx].MData; + if (monster._uniqtype != 0) + monster.mName = _(UniqMonst[monster._uniqtype - 1].mName); else - Monsters[i].mName = _(Monsters[i].MData->mName); - int mdir = Monsters[i]._mdir; + monster.mName = _(monster.MData->mName); + int mdir = monster._mdir; MonsterGraphic graphic = MonsterGraphic::Stand; - switch (Monsters[i]._mmode) { + switch (monster._mmode) { case MM_STAND: case MM_DELAY: case MM_TALK: @@ -4772,28 +4770,28 @@ void SyncMonsterAnim(int i) break; case MM_CHARGE: graphic = MonsterGraphic::Attack; - Monsters[i].AnimInfo.CurrentFrame = 1; - Monsters[i].AnimInfo.NumberOfFrames = Monsters[i].MType->GetAnimData(MonsterGraphic::Attack).Frames; + monster.AnimInfo.CurrentFrame = 1; + monster.AnimInfo.NumberOfFrames = monster.MType->GetAnimData(MonsterGraphic::Attack).Frames; break; default: - Monsters[i].AnimInfo.CurrentFrame = 1; - Monsters[i].AnimInfo.NumberOfFrames = Monsters[i].MType->GetAnimData(MonsterGraphic::Stand).Frames; + monster.AnimInfo.CurrentFrame = 1; + monster.AnimInfo.NumberOfFrames = monster.MType->GetAnimData(MonsterGraphic::Stand).Frames; break; } - if (Monsters[i].MType->GetAnimData(graphic).CelSpritesForDirections[mdir]) - Monsters[i].AnimInfo.pCelSprite = &*Monsters[i].MType->GetAnimData(graphic).CelSpritesForDirections[mdir]; + if (monster.MType->GetAnimData(graphic).CelSpritesForDirections[mdir]) + monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(graphic).CelSpritesForDirections[mdir]; else - Monsters[i].AnimInfo.pCelSprite = nullptr; + monster.AnimInfo.pCelSprite = nullptr; } void M_FallenFear(Point position) { for (int i = 0; i < ActiveMonsterCount; i++) { - MonsterStruct *m = &Monsters[ActiveMonsters[i]]; + auto &monster = Monsters[ActiveMonsters[i]]; int rundist; - switch (m->MType->mtype) { + switch (monster.MType->mtype) { case MT_RFALLSP: case MT_RFALLSD: rundist = 7; @@ -4813,12 +4811,12 @@ void M_FallenFear(Point position) default: continue; } - if (m->_mAi == AI_FALLEN - && position.WalkingDistance(m->position.tile) < 5 - && m->_mhitpoints >> 6 > 0) { - m->_mgoal = MGOAL_RETREAT; - m->_mgoalvar1 = rundist; - m->_mgoalvar2 = GetDirection(position, m->position.tile); + if (monster._mAi == AI_FALLEN + && position.WalkingDistance(monster.position.tile) < 5 + && monster._mhitpoints >> 6 > 0) { + monster._mgoal = MGOAL_RETREAT; + monster._mgoalvar1 = rundist; + monster._mgoalvar2 = GetDirection(position, monster.position.tile); } } } @@ -4899,12 +4897,13 @@ void PrintMonstHistory(int mt) void PrintUniqueHistory() { + auto &monster = Monsters[pcursmonst]; if (sgOptions.Gameplay.bShowMonsterType) { - strcpy(tempstr, fmt::format(_("Type: {:s}"), GetMonsterTypeText(*Monsters[pcursmonst].MData)).c_str()); + strcpy(tempstr, fmt::format(_("Type: {:s}"), GetMonsterTypeText(*monster.MData)).c_str()); AddPanelString(tempstr); } - int res = Monsters[pcursmonst].mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING); + int res = monster.mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING); if (res == 0) { strcpy(tempstr, _("No resistances")); AddPanelString(tempstr); @@ -4925,6 +4924,31 @@ void PrintUniqueHistory() pinfoflag = true; } +void PlayEffect(MonsterStruct &monster, int mode) +{ + if (Players[MyPlayerId].pLvlLoad != 0) { + return; + } + + int sndIdx = GenerateRnd(2); + if (!gbSndInited || !gbSoundOn || gbBufferMsgs != 0) { + return; + } + + int mi = monster._mMTidx; + TSnd *snd = LevelMonsterTypes[mi].Snds[mode][sndIdx].get(); + if (snd == nullptr || snd->isPlaying()) { + return; + } + + int lVolume = 0; + int lPan = 0; + if (!CalculateSoundPosition(monster.position.tile, &lVolume, &lPan)) + return; + + snd_play_snd(snd, lVolume, lPan); +} + void MissToMonst(int i, Point position) { assurance((DWORD)i < MAXMISSILES, i); @@ -4932,32 +4956,32 @@ void MissToMonst(int i, Point position) MissileStruct *miss = &Missiles[i]; int m = miss->_misource; - assurance((DWORD)m < MAXMONSTERS, m); + assert((DWORD)m < MAXMONSTERS); + auto &monster = Monsters[m]; - MonsterStruct *monst = &Monsters[m]; Point oldPosition = miss->position.tile; dMonster[position.x][position.y] = m + 1; - monst->_mdir = static_cast(miss->_mimfnum); - monst->position.tile = position; - M_StartStand(m, monst->_mdir); - if (monst->MType->mtype < MT_INCIN || monst->MType->mtype > MT_HELLBURN) { - if ((monst->_mFlags & MFLAG_TARGETS_MONSTER) == 0) + monster._mdir = static_cast(miss->_mimfnum); + monster.position.tile = position; + M_StartStand(monster, monster._mdir); + if (monster.MType->mtype < MT_INCIN || monster.MType->mtype > MT_HELLBURN) { + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) == 0) M_StartHit(m, -1, 0); else MonsterHitMonster(m, -1, 0); } else { - StartFadein(m, monst->_mdir, false); + StartFadein(monster, monster._mdir, false); } - if ((monst->_mFlags & MFLAG_TARGETS_MONSTER) == 0) { + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) == 0) { int pnum = dPlayer[oldPosition.x][oldPosition.y] - 1; if (dPlayer[oldPosition.x][oldPosition.y] > 0) { - if (monst->MType->mtype != MT_GLOOM && (monst->MType->mtype < MT_INCIN || monst->MType->mtype > MT_HELLBURN)) { - MonsterAttackPlayer(m, dPlayer[oldPosition.x][oldPosition.y] - 1, 500, monst->mMinDamage2, monst->mMaxDamage2); - if (pnum == dPlayer[oldPosition.x][oldPosition.y] - 1 && (monst->MType->mtype < MT_NSNAKE || monst->MType->mtype > MT_GSNAKE)) { + if (monster.MType->mtype != MT_GLOOM && (monster.MType->mtype < MT_INCIN || monster.MType->mtype > MT_HELLBURN)) { + MonsterAttackPlayer(m, dPlayer[oldPosition.x][oldPosition.y] - 1, 500, monster.mMinDamage2, monster.mMaxDamage2); + if (pnum == dPlayer[oldPosition.x][oldPosition.y] - 1 && (monster.MType->mtype < MT_NSNAKE || monster.MType->mtype > MT_GSNAKE)) { if (Players[pnum]._pmode != PM_GOTHIT && Players[pnum]._pmode != PM_DEATH) StartPlrHit(pnum, 0, true); - Point newPosition = oldPosition + monst->_mdir; + Point newPosition = oldPosition + monster._mdir; if (PosOkPlayer(pnum, newPosition)) { Players[pnum].position.tile = newPosition; FixPlayerLocation(pnum, Players[pnum]._pdir); @@ -4972,24 +4996,24 @@ void MissToMonst(int i, Point position) } if (dMonster[oldPosition.x][oldPosition.y] > 0) { - if (monst->MType->mtype != MT_GLOOM && (monst->MType->mtype < MT_INCIN || monst->MType->mtype > MT_HELLBURN)) { - MonsterAttackMonster(m, dMonster[oldPosition.x][oldPosition.y] - 1, 500, monst->mMinDamage2, monst->mMaxDamage2); - if (monst->MType->mtype < MT_NSNAKE || monst->MType->mtype > MT_GSNAKE) { - Point newPosition = oldPosition + monst->_mdir; - if (PosOkMonst(dMonster[oldPosition.x][oldPosition.y] - 1, newPosition)) { + if (monster.MType->mtype != MT_GLOOM && (monster.MType->mtype < MT_INCIN || monster.MType->mtype > MT_HELLBURN)) { + MonsterAttackMonster(m, dMonster[oldPosition.x][oldPosition.y] - 1, 500, monster.mMinDamage2, monster.mMaxDamage2); + if (monster.MType->mtype < MT_NSNAKE || monster.MType->mtype > MT_GSNAKE) { + Point newPosition = oldPosition + monster._mdir; + if (MonsterIsTileAvalible(dMonster[oldPosition.x][oldPosition.y] - 1, newPosition)) { m = dMonster[oldPosition.x][oldPosition.y]; dMonster[newPosition.x][newPosition.y] = m; dMonster[oldPosition.x][oldPosition.y] = 0; m--; - Monsters[m].position.tile = newPosition; - Monsters[m].position.future = newPosition; + monster.position.tile = newPosition; + monster.position.future = newPosition; } } } } } -bool PosOkMonst(int i, Point position) +bool MonsterIsTileAvalible(int i, Point position) { if (dPlayer[position.x][position.y] != 0 || dMonster[position.x][position.y] != 0) return false; @@ -5015,7 +5039,7 @@ bool SpawnSkeleton(int ii, Point position) if (ii == -1) return false; - if (PosOkMonst(-1, position)) { + if (MonsterIsTileAvalible(-1, position)) { Direction dir = GetDirection(position, position); // TODO useless calculation ActivateSpawn(ii, position.x, position.y, dir); return true; @@ -5028,7 +5052,7 @@ bool SpawnSkeleton(int ii, Point position) for (int j = position.y - 1; j <= position.y + 1; j++) { int xx = 0; for (int k = position.x - 1; k <= position.x + 1; k++) { - monstok[xx][yy] = PosOkMonst(-1, { k, j }); + monstok[xx][yy] = MonsterIsTileAvalible(-1, { k, j }); savail = savail || monstok[xx][yy]; xx++; } @@ -5067,90 +5091,84 @@ int PreSpawnSkeleton() { int skel = AddSkeleton({ 0, 0 }, DIR_S, false); if (skel != -1) - M_StartStand(skel, DIR_S); + M_StartStand(Monsters[skel], DIR_S); return skel; } -void TalktoMonster(int i) +void TalktoMonster(MonsterStruct &monster) { - assurance((DWORD)i < MAXMONSTERS, i); - - MonsterStruct *monst = &Monsters[i]; - int pnum = monst->_menemy; - monst->_mmode = MM_TALK; - if (monst->_mAi != AI_SNOTSPIL && monst->_mAi != AI_LACHDAN) { + int pnum = monster._menemy; + monster._mmode = MM_TALK; + if (monster._mAi != AI_SNOTSPIL && monster._mAi != AI_LACHDAN) { return; } if (QuestStatus(Q_LTBANNER) && Quests[Q_LTBANNER]._qvar1 == 2) { if (Players[pnum].TryRemoveInvItemById(IDI_BANNER)) { Quests[Q_LTBANNER]._qactive = QUEST_DONE; - monst->mtalkmsg = TEXT_BANNER12; - monst->_mgoal = MGOAL_INQUIRING; + monster.mtalkmsg = TEXT_BANNER12; + monster._mgoal = MGOAL_INQUIRING; } } - if (QuestStatus(Q_VEIL) && monst->mtalkmsg >= TEXT_VEIL9) { + if (QuestStatus(Q_VEIL) && monster.mtalkmsg >= TEXT_VEIL9) { if (Players[pnum].TryRemoveInvItemById(IDI_GLDNELIX)) { - monst->mtalkmsg = TEXT_VEIL11; - monst->_mgoal = MGOAL_INQUIRING; + monster.mtalkmsg = TEXT_VEIL11; + monster._mgoal = MGOAL_INQUIRING; } } } void SpawnGolum(int i, Point position, int mi) { - assurance((DWORD)i < MAXMONSTERS, i); + assert((DWORD)i < MAXMONSTERS); + auto &monster = Monsters[i]; dMonster[position.x][position.y] = i + 1; - Monsters[i].position.tile = position; - Monsters[i].position.future = position; - Monsters[i].position.old = position; - Monsters[i]._pathcount = 0; - Monsters[i]._mmaxhp = 2 * (320 * Missiles[mi]._mispllvl + Players[i]._pMaxMana / 3); - Monsters[i]._mhitpoints = Monsters[i]._mmaxhp; - Monsters[i].mArmorClass = 25; - Monsters[i].mHit = 5 * (Missiles[mi]._mispllvl + 8) + 2 * Players[i]._pLevel; - Monsters[i].mMinDamage = 2 * (Missiles[mi]._mispllvl + 4); - Monsters[i].mMaxDamage = 2 * (Missiles[mi]._mispllvl + 8); - Monsters[i]._mFlags |= MFLAG_GOLEM; - StartSpecialStand(i, DIR_S); - UpdateEnemy(i); + monster.position.tile = position; + monster.position.future = position; + monster.position.old = position; + monster._pathcount = 0; + monster._mmaxhp = 2 * (320 * Missiles[mi]._mispllvl + Players[i]._pMaxMana / 3); + monster._mhitpoints = monster._mmaxhp; + monster.mArmorClass = 25; + monster.mHit = 5 * (Missiles[mi]._mispllvl + 8) + 2 * Players[i]._pLevel; + monster.mMinDamage = 2 * (Missiles[mi]._mispllvl + 4); + monster.mMaxDamage = 2 * (Missiles[mi]._mispllvl + 8); + monster._mFlags |= MFLAG_GOLEM; + StartSpecialStand(monster, DIR_S); + UpdateEnemy(monster); if (i == MyPlayerId) { NetSendCmdGolem( - Monsters[i].position.tile.x, - Monsters[i].position.tile.y, - Monsters[i]._mdir, - Monsters[i]._menemy, - Monsters[i]._mhitpoints, + monster.position.tile.x, + monster.position.tile.y, + monster._mdir, + monster._menemy, + monster._mhitpoints, currlevel); } } -bool CanTalkToMonst(int m) +bool CanTalkToMonst(const MonsterStruct &monster) { - commitment((DWORD)m < MAXMONSTERS, m); - - if (Monsters[m]._mgoal == MGOAL_INQUIRING) { + if (monster._mgoal == MGOAL_INQUIRING) { return true; } - return Monsters[m]._mgoal == MGOAL_TALKING; + return monster._mgoal == MGOAL_TALKING; } -bool CheckMonsterHit(int m, bool *ret) +bool CheckMonsterHit(MonsterStruct &monster, bool *ret) { - commitment((DWORD)m < MAXMONSTERS, m); - - if (Monsters[m]._mAi == AI_GARG && (Monsters[m]._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { - Monsters[m]._mFlags &= ~MFLAG_ALLOW_SPECIAL; - Monsters[m]._mmode = MM_SATTACK; + if (monster._mAi == AI_GARG && (monster._mFlags & MFLAG_ALLOW_SPECIAL) != 0) { + monster._mFlags &= ~MFLAG_ALLOW_SPECIAL; + monster._mmode = MM_SATTACK; *ret = true; return true; } - if (Monsters[m].MType->mtype >= MT_COUNSLR && Monsters[m].MType->mtype <= MT_ADVOCATE) { - if (Monsters[m]._mgoal != MGOAL_NORMAL) { + if (monster.MType->mtype >= MT_COUNSLR && monster.MType->mtype <= MT_ADVOCATE) { + if (monster._mgoal != MGOAL_NORMAL) { *ret = false; return true; } @@ -5159,25 +5177,25 @@ bool CheckMonsterHit(int m, bool *ret) return false; } -int encode_enemy(int m) +int encode_enemy(MonsterStruct &monster) { - if ((Monsters[m]._mFlags & MFLAG_TARGETS_MONSTER) != 0) - return Monsters[m]._menemy + MAX_PLRS; + if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) + return monster._menemy + MAX_PLRS; - return Monsters[m]._menemy; + return monster._menemy; } -void decode_enemy(int m, int enemy) +void decode_enemy(MonsterStruct &monster, int enemy) { if (enemy < MAX_PLRS) { - Monsters[m]._mFlags &= ~MFLAG_TARGETS_MONSTER; - Monsters[m]._menemy = enemy; - Monsters[m].enemyPosition = Players[enemy].position.future; + monster._mFlags &= ~MFLAG_TARGETS_MONSTER; + monster._menemy = enemy; + monster.enemyPosition = Players[enemy].position.future; } else { - Monsters[m]._mFlags |= MFLAG_TARGETS_MONSTER; + monster._mFlags |= MFLAG_TARGETS_MONSTER; enemy -= MAX_PLRS; - Monsters[m]._menemy = enemy; - Monsters[m].enemyPosition = Monsters[enemy].position.future; + monster._menemy = enemy; + monster.enemyPosition = Monsters[enemy].position.future; } } diff --git a/Source/monster.h b/Source/monster.h index 81e08fc6f..2c1c8f0a2 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -231,10 +231,10 @@ void InitMonsterGFX(int monst); void monster_some_crypt(); void InitMonsters(); void SetMapMonsters(const uint16_t *dunData, Point startPosition); -int AddMonster(Point position, Direction dir, int mtype, bool InMap); +int AddMonster(Point position, Direction dir, int mtype, bool inMap); void AddDoppelganger(MonsterStruct &monster); -bool M_Talker(int i); -void M_StartStand(int i, Direction md); +bool M_Talker(MonsterStruct &monster); +void M_StartStand(MonsterStruct &monster, Direction md); void M_ClearSquares(int i); void M_GetKnockback(int i); void M_StartHit(int i, int pnum, int dam); @@ -252,22 +252,23 @@ bool DirOK(int i, Direction mdir); bool PosOkMissile(int entity, Point position); bool LineClearMissile(Point startPoint, Point endPoint); bool LineClear(bool (*Clear)(int, Point), int entity, Point startPoint, Point endPoint); -void SyncMonsterAnim(int i); +void SyncMonsterAnim(MonsterStruct &monster); void M_FallenFear(Point position); void PrintMonstHistory(int mt); void PrintUniqueHistory(); +void PlayEffect(MonsterStruct &monster, int mode); void MissToMonst(int i, Point position); -bool PosOkMonst(int i, Point position); +bool MonsterIsTileAvalible(int i, Point position); bool IsSkel(int mt); bool IsGoat(int mt); bool SpawnSkeleton(int ii, Point position); int PreSpawnSkeleton(); -void TalktoMonster(int i); +void TalktoMonster(MonsterStruct &monster); void SpawnGolum(int i, Point position, int mi); -bool CanTalkToMonst(int m); -bool CheckMonsterHit(int m, bool *ret); -int encode_enemy(int m); -void decode_enemy(int m, int enemy); +bool CanTalkToMonst(const MonsterStruct &monster); +bool CheckMonsterHit(MonsterStruct &monster, bool *ret); +int encode_enemy(MonsterStruct &monster); +void decode_enemy(MonsterStruct &monster, int enemy); extern Direction left[8]; extern Direction right[8]; diff --git a/Source/msg.cpp b/Source/msg.cpp index 7a7f8eed3..06e6c14b7 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -387,16 +387,17 @@ void DeltaLeaveSync(BYTE bLevel) for (int i = 0; i < ActiveMonsterCount; i++) { int ma = ActiveMonsters[i]; - if (Monsters[ma]._mhitpoints == 0) + auto &monster = Monsters[ma]; + if (monster._mhitpoints == 0) continue; sgbDeltaChanged = true; DMonsterStr *pD = &sgLevels[bLevel].monster[ma]; - pD->_mx = Monsters[ma].position.tile.x; - pD->_my = Monsters[ma].position.tile.y; - pD->_mdir = Monsters[ma]._mdir; - pD->_menemy = encode_enemy(ma); - pD->_mhitpoints = Monsters[ma]._mhitpoints; - pD->_mactive = Monsters[ma]._msquelch; + pD->_mx = monster.position.tile.x; + pD->_my = monster.position.tile.y; + pD->_mdir = monster._mdir; + pD->_menemy = encode_enemy(monster); + pD->_mhitpoints = monster._mhitpoints; + pD->_mactive = monster._msquelch; } memcpy(&sgLocals[bLevel].automapsv, AutomapView, sizeof(AutomapView)); } @@ -1320,12 +1321,13 @@ DWORD OnMonstDamage(TCmd *pCmd, int pnum) SendPacket(pnum, p, sizeof(*p)); // BUGFIX: change to sizeof(*p) or it still uses TCmdParam2 size for hellfire (fixed) else if (pnum != MyPlayerId) { if (currlevel == Players[pnum].plrlevel) { - Monsters[p->wMon].mWhoHit |= 1 << pnum; - if (Monsters[p->wMon]._mhitpoints > 0) { - Monsters[p->wMon]._mhitpoints -= p->dwDam; - if ((Monsters[p->wMon]._mhitpoints >> 6) < 1) - Monsters[p->wMon]._mhitpoints = 1 << 6; - delta_monster_hp(p->wMon, Monsters[p->wMon]._mhitpoints, Players[pnum].plrlevel); + auto &monster = Monsters[p->wMon]; + monster.mWhoHit |= 1 << pnum; + if (monster._mhitpoints > 0) { + monster._mhitpoints -= p->dwDam; + if ((monster._mhitpoints >> 6) < 1) + monster._mhitpoints = 1 << 6; + delta_monster_hp(p->wMon, monster._mhitpoints, Players[pnum].plrlevel); } } } @@ -2009,34 +2011,35 @@ void DeltaLoadLevel() M_ClearSquares(i); int x = sgLevels[currlevel].monster[i]._mx; int y = sgLevels[currlevel].monster[i]._my; - Monsters[i].position.tile = { x, y }; - Monsters[i].position.old = { x, y }; - Monsters[i].position.future = { x, y }; + auto &monster = Monsters[i]; + monster.position.tile = { x, y }; + monster.position.old = { x, y }; + monster.position.future = { x, y }; if (sgLevels[currlevel].monster[i]._mhitpoints != -1) - Monsters[i]._mhitpoints = sgLevels[currlevel].monster[i]._mhitpoints; + monster._mhitpoints = sgLevels[currlevel].monster[i]._mhitpoints; if (sgLevels[currlevel].monster[i]._mhitpoints == 0) { M_ClearSquares(i); - if (Monsters[i]._mAi != AI_DIABLO) { - if (Monsters[i]._uniqtype == 0) { - assert(Monsters[i].MType != nullptr); - AddDead(Monsters[i].position.tile, Monsters[i].MType->mdeadval, Monsters[i]._mdir); + if (monster._mAi != AI_DIABLO) { + if (monster._uniqtype == 0) { + assert(monster.MType != nullptr); + AddDead(monster.position.tile, monster.MType->mdeadval, monster._mdir); } else { - AddDead(Monsters[i].position.tile, Monsters[i]._udeadval, Monsters[i]._mdir); + AddDead(monster.position.tile, monster._udeadval, monster._mdir); } } - Monsters[i]._mDelFlag = true; + monster._mDelFlag = true; M_UpdateLeader(i); } else { - decode_enemy(i, sgLevels[currlevel].monster[i]._menemy); - if (Monsters[i].position.tile != Point { 0, 0 } && Monsters[i].position.tile != Point { 1, 0 }) - dMonster[Monsters[i].position.tile.x][Monsters[i].position.tile.y] = i + 1; + decode_enemy(monster, sgLevels[currlevel].monster[i]._menemy); + if (monster.position.tile != Point { 0, 0 } && monster.position.tile != Point { 1, 0 }) + dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; if (i < MAX_PLRS) { GolumAi(i); - Monsters[i]._mFlags |= (MFLAG_TARGETS_MONSTER | MFLAG_GOLEM); + monster._mFlags |= (MFLAG_TARGETS_MONSTER | MFLAG_GOLEM); } else { - M_StartStand(i, Monsters[i]._mdir); + M_StartStand(monster, monster._mdir); } - Monsters[i]._msquelch = sgLevels[currlevel].monster[i]._mactive; + monster._msquelch = sgLevels[currlevel].monster[i]._mactive; } } } diff --git a/Source/objects.cpp b/Source/objects.cpp index 61179c49d..dbe0d97ab 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -19,6 +19,7 @@ #include "lighting.h" #include "minitext.h" #include "missiles.h" +#include "monster.h" #include "options.h" #include "setmaps.h" #include "stores.h" @@ -1987,7 +1988,7 @@ void Obj_FlameTrap(int i) MonsterTrapHit(dMonster[x][y] - 1, mindam / 2, maxdam / 2, 0, MIS_FIREWALLC, false); if (dPlayer[x][y] > 0) { bool unused; - PlayerMHit(dPlayer[x][y] - 1, -1, 0, mindam, maxdam, MIS_FIREWALLC, false, 0, &unused); + PlayerMHit(dPlayer[x][y] - 1, nullptr, 0, mindam, maxdam, MIS_FIREWALLC, false, 0, &unused); } if (Objects[i]._oAnimFrame == Objects[i]._oAnimLen) @@ -2704,10 +2705,10 @@ void OperateL3LDoor(int pnum, int oi, bool sendflag) } } -void MonstCheckDoors(int m) +void MonstCheckDoors(MonsterStruct &monster) { - int mx = Monsters[m].position.tile.x; - int my = Monsters[m].position.tile.y; + int mx = monster.position.tile.x; + int my = monster.position.tile.y; if (dObject[mx - 1][my - 1] != 0 || dObject[mx][my - 1] != 0 || dObject[mx + 1][my - 1] != 0 @@ -4421,15 +4422,18 @@ void OperateBookCase(int pnum, int i, bool sendmsg) } SetRndSeed(Objects[i]._oRndSeed); CreateTypeItem(Objects[i].position, false, ITYPE_MISC, IMISC_BOOK, sendmsg, false); - if (QuestStatus(Q_ZHAR) - && Monsters[MAX_PLRS]._mmode == MM_STAND // prevents playing the "angry" message for the second time if zhar got aggroed by losing vision and talking again - && Monsters[MAX_PLRS]._uniqtype - 1 == UMT_ZHAR - && Monsters[MAX_PLRS]._msquelch == UINT8_MAX - && Monsters[MAX_PLRS]._mhitpoints > 0) { - Monsters[MAX_PLRS].mtalkmsg = TEXT_ZHAR2; - M_StartStand(0, Monsters[MAX_PLRS]._mdir); // BUGFIX: first parameter in call to M_StartStand should be MAX_PLRS, not 0. - Monsters[MAX_PLRS]._mgoal = MGOAL_ATTACK2; - Monsters[MAX_PLRS]._mmode = MM_TALK; + + if (QuestStatus(Q_ZHAR)) { + auto &zhar = Monsters[MAX_PLRS]; + if (zhar._mmode == MM_STAND // prevents playing the "angry" message for the second time if zhar got aggroed by losing vision and talking again + && zhar._uniqtype - 1 == UMT_ZHAR + && zhar._msquelch == UINT8_MAX + && zhar._mhitpoints > 0) { + zhar.mtalkmsg = TEXT_ZHAR2; + M_StartStand(Monsters[0], zhar._mdir); // BUGFIX: first parameter in call to M_StartStand should be MAX_PLRS, not 0. + zhar._mgoal = MGOAL_ATTACK2; + zhar._mmode = MM_TALK; + } } if (pnum == MyPlayerId) NetSendCmdParam1(false, CMD_OPERATEOBJ, i); @@ -4995,10 +4999,10 @@ void SyncOpObject(int pnum, int cmd, int i) /** * @brief Checks if all active crux objects of the given type have been broken. - * + * * Called by BreakCrux and SyncCrux to see if the linked map area needs to be updated. In practice I think this is * always true when called by BreakCrux as there *should* only be one instance of each crux with a given _oVar8 value? - * + * * @param cruxType Discriminator/type (_oVar8 value) of the crux object which is currently changing state * @return true if all active cruxes of that type on the level are broken, false if at least one remains unbroken */ @@ -5083,7 +5087,7 @@ void BreakBarrel(int pnum, int i, int dam, bool forcebreak, bool sendmsg) MonsterTrapHit(dMonster[xp][yp] - 1, 1, 4, 0, MIS_FIREBOLT, false); bool unused; if (dPlayer[xp][yp] > 0) - PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, MIS_FIREBOLT, false, 0, &unused); + PlayerMHit(dPlayer[xp][yp] - 1, nullptr, 0, 8, 16, MIS_FIREBOLT, false, 0, &unused); if (dObject[xp][yp] > 0) { int oi = dObject[xp][yp] - 1; if (Objects[oi]._otype == OBJ_BARRELEX && Objects[oi]._oBreak != -1) diff --git a/Source/objects.h b/Source/objects.h index 4dde0ab56..253ec10c5 100644 --- a/Source/objects.h +++ b/Source/objects.h @@ -10,6 +10,7 @@ #include "engine/point.hpp" #include "engine/rectangle.hpp" #include "itemdat.h" +#include "monster.h" #include "objdat.h" #include "textdat.h" @@ -151,7 +152,7 @@ void Obj_Trap(int i); void ProcessObjects(); void ObjSetMicro(Point position, int pn); void RedoPlayerVision(); -void MonstCheckDoors(int m); +void MonstCheckDoors(MonsterStruct &monster); void ObjChangeMap(int x1, int y1, int x2, int y2); void ObjChangeMapResync(int x1, int y1, int x2, int y2); void TryDisarm(int pnum, int i); diff --git a/Source/player.cpp b/Source/player.cpp index d950d5658..eaa99b957 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1934,14 +1934,17 @@ void SyncPlrKill(int pnum, int earflag) void RemovePlrMissiles(int pnum) { - if (currlevel != 0 && pnum == MyPlayerId && (Monsters[MyPlayerId].position.tile.x != 1 || Monsters[MyPlayerId].position.tile.y != 0)) { - M_StartKill(MyPlayerId, MyPlayerId); - AddDead(Monsters[MyPlayerId].position.tile, (Monsters[MyPlayerId].MType)->mdeadval, Monsters[MyPlayerId]._mdir); - int mx = Monsters[MyPlayerId].position.tile.x; - int my = Monsters[MyPlayerId].position.tile.y; - dMonster[mx][my] = 0; - Monsters[MyPlayerId]._mDelFlag = true; - DeleteMonsterList(); + if (currlevel != 0 && pnum == MyPlayerId) { + auto &golem = Monsters[MyPlayerId]; + if (golem.position.tile.x != 1 || golem.position.tile.y != 0) { + M_StartKill(MyPlayerId, MyPlayerId); + AddDead(golem.position.tile, (golem.MType)->mdeadval, golem._mdir); + int mx = golem.position.tile.x; + int my = golem.position.tile.y; + dMonster[mx][my] = 0; + golem._mDelFlag = true; + DeleteMonsterList(); + } } for (int i = 0; i < ActiveMissileCount; i++) { @@ -2254,17 +2257,18 @@ bool PlrHitMonst(int pnum, int m) if ((DWORD)m >= MAXMONSTERS) { app_fatal("PlrHitMonst: illegal monster %i", m); } + auto &monster = Monsters[m]; auto &player = Players[pnum]; - if ((Monsters[m]._mhitpoints >> 6) <= 0) { + if ((monster._mhitpoints >> 6) <= 0) { return false; } - if (Monsters[m].MType->mtype == MT_ILLWEAV && Monsters[m]._mgoal == MGOAL_RETREAT) { + if (monster.MType->mtype == MT_ILLWEAV && monster._mgoal == MGOAL_RETREAT) { return false; } - if (Monsters[m]._mmode == MM_CHARGE) { + if (monster._mmode == MM_CHARGE) { return false; } @@ -2282,11 +2286,11 @@ bool PlrHitMonst(int pnum, int m) } int hit = GenerateRnd(100); - if (Monsters[m]._mmode == MM_STONE) { + if (monster._mmode == MM_STONE) { hit = 0; } - int tmac = Monsters[m].mArmorClass; + int tmac = monster.mArmorClass; if (gbIsHellfire && player._pIEnAc > 0) { int pIEnAc = player._pIEnAc - 1; if (pIEnAc > 0) @@ -2295,7 +2299,7 @@ bool PlrHitMonst(int pnum, int m) tmac -= tmac / 4; if (player._pClass == HeroClass::Barbarian) { - tmac -= Monsters[m].mArmorClass / 8; + tmac -= monster.mArmorClass / 8; } if (tmac < 0) @@ -2317,7 +2321,7 @@ bool PlrHitMonst(int pnum, int m) } bool ret = false; - if (CheckMonsterHit(m, &ret)) { + if (CheckMonsterHit(monster, &ret)) { return ret; } #ifdef _DEBUG @@ -2352,7 +2356,7 @@ bool PlrHitMonst(int pnum, int m) phanditype = ITYPE_MACE; } - switch (Monsters[m].MData->mMonstClass) { + switch (monster.MData->mMonstClass) { case MC_UNDEAD: if (phanditype == ITYPE_SWORD) { dam -= dam / 2; @@ -2378,8 +2382,8 @@ bool PlrHitMonst(int pnum, int m) dam *= 3; } - if ((player.pDamAcFlags & ISPLHF_DOPPELGANGER) != 0 && Monsters[m].MType->mtype != MT_DIABLO && Monsters[m]._uniqtype == 0 && GenerateRnd(100) < 10) { - AddDoppelganger(Monsters[m]); + if ((player.pDamAcFlags & ISPLHF_DOPPELGANGER) != 0 && monster.MType->mtype != MT_DIABLO && monster._uniqtype == 0 && GenerateRnd(100) < 10) { + AddDoppelganger(monster); } dam <<= 6; @@ -2401,7 +2405,7 @@ bool PlrHitMonst(int pnum, int m) } dam *= 2; } - Monsters[m]._mhitpoints -= dam; + monster._mhitpoints -= dam; } int skdam = 0; @@ -2452,24 +2456,24 @@ bool PlrHitMonst(int pnum, int m) drawhpflag = true; } if ((player._pIFlags & ISPL_NOHEALPLR) != 0) { - Monsters[m]._mFlags |= MFLAG_NOHEAL; + monster._mFlags |= MFLAG_NOHEAL; } #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) { - Monsters[m]._mhitpoints = 0; /* double check */ + monster._mhitpoints = 0; /* double check */ } #endif - if ((Monsters[m]._mhitpoints >> 6) <= 0) { - if (Monsters[m]._mmode == MM_STONE) { + if ((monster._mhitpoints >> 6) <= 0) { + if (monster._mmode == MM_STONE) { M_StartKill(m, pnum); - Monsters[m].Petrify(); + monster.Petrify(); } else { M_StartKill(m, pnum); } } else { - if (Monsters[m]._mmode == MM_STONE) { + if (monster._mmode == MM_STONE) { M_StartHit(m, pnum, dam); - Monsters[m].Petrify(); + monster.Petrify(); } else { if ((player._pIFlags & ISPL_KNOCKBACK) != 0) { M_GetKnockback(m); @@ -2614,7 +2618,7 @@ bool PM_DoAttack(int pnum) } else { m = -(dMonster[dx][dy] + 1); } - if (CanTalkToMonst(m)) { + if (CanTalkToMonst(Monsters[m])) { player.position.temp.x = 0; /** @todo Looks to be irrelevant, probably just remove it */ return false; } @@ -2662,15 +2666,15 @@ bool PM_DoAttack(int pnum) dx = position.x; dy = position.y; int m = ((dMonster[dx][dy] > 0) ? dMonster[dx][dy] : -dMonster[dx][dy]) - 1; - if (dMonster[dx][dy] != 0 && !CanTalkToMonst(m) && Monsters[m].position.old.x == dx && Monsters[m].position.old.y == dy) { + auto &monster = Monsters[m]; + if (dMonster[dx][dy] != 0 && !CanTalkToMonst(monster) && monster.position.old.x == dx && monster.position.old.y == dy) { if (PlrHitMonst(-pnum, m)) didhit = true; } position = player.position.tile + left[player._pdir]; dx = position.x; dy = position.y; - m = ((dMonster[dx][dy] > 0) ? dMonster[dx][dy] : -dMonster[dx][dy]) - 1; - if (dMonster[dx][dy] != 0 && !CanTalkToMonst(m) && Monsters[m].position.old.x == dx && Monsters[m].position.old.y == dy) { + if (dMonster[dx][dy] != 0 && !CanTalkToMonst(monster) && monster.position.old.x == dx && monster.position.old.y == dy) { if (PlrHitMonst(-pnum, m)) didhit = true; } @@ -2990,7 +2994,7 @@ void CheckNewPath(int pnum, bool pmWillBeCalled) if (x < 2 && y < 2) { ClrPlrPath(player); if (player.destAction == ACTION_ATTACKMON && Monsters[i].mtalkmsg != TEXT_NONE && Monsters[i].mtalkmsg != TEXT_VILE14) { - TalktoMonster(i); + TalktoMonster(Monsters[i]); } else { StartAttack(pnum, d); } @@ -3065,7 +3069,7 @@ void CheckNewPath(int pnum, bool pmWillBeCalled) if (x <= 1 && y <= 1) { d = GetDirection(player.position.future, Monsters[i].position.future); if (Monsters[i].mtalkmsg != TEXT_NONE && Monsters[i].mtalkmsg != TEXT_VILE14) { - TalktoMonster(i); + TalktoMonster(Monsters[i]); } else { StartAttack(pnum, d); } @@ -3088,7 +3092,7 @@ void CheckNewPath(int pnum, bool pmWillBeCalled) i = player.destParam1; d = GetDirection(player.position.future, Monsters[i].position.future); if (Monsters[i].mtalkmsg != TEXT_NONE && Monsters[i].mtalkmsg != TEXT_VILE14) { - TalktoMonster(i); + TalktoMonster(Monsters[i]); } else { StartRangeAttack(pnum, d, Monsters[i].position.future.x, Monsters[i].position.future.y); } diff --git a/Source/qol/monhealthbar.cpp b/Source/qol/monhealthbar.cpp index 0298e2ca6..d1e033a45 100644 --- a/Source/qol/monhealthbar.cpp +++ b/Source/qol/monhealthbar.cpp @@ -59,7 +59,7 @@ void DrawMonsterHealthBar(const Surface &out) if (pcursmonst == -1) return; - const MonsterStruct &mon = Monsters[pcursmonst]; + const MonsterStruct &monster = Monsters[pcursmonst]; const int width = healthBox.w(); const int height = healthBox.h(); @@ -75,18 +75,18 @@ void DrawMonsterHealthBar(const Surface &out) const int yPos = 18; const int border = 3; - const int maxLife = std::max(mon._mmaxhp, mon._mhitpoints); + const int maxLife = std::max(monster._mmaxhp, monster._mhitpoints); DrawArt(out, xPos, yPos, &healthBox); DrawHalfTransparentRectTo(out, xPos + border, yPos + border, width - (border * 2), height - (border * 2)); - int barProgress = (width * mon._mhitpoints) / maxLife; + int barProgress = (width * monster._mhitpoints) / maxLife; if (barProgress != 0) { DrawArt(out, xPos + border + 1, yPos + border + 1, &health, 0, barProgress, height - (border * 2) - 2); } if (sgOptions.Gameplay.bShowMonsterType) { Uint8 borderColors[] = { 248 /*undead*/, 232 /*demon*/, 150 /*beast*/ }; - Uint8 borderColor = borderColors[mon.MData->mMonstClass]; + Uint8 borderColor = borderColors[monster.MData->mMonstClass]; int borderWidth = width - (border * 2); UnsafeDrawHorizontalLine(out, { xPos + border, yPos + border }, borderWidth, borderColor); UnsafeDrawHorizontalLine(out, { xPos + border, yPos + height - border - 1 }, borderWidth, borderColor); @@ -96,24 +96,24 @@ void DrawMonsterHealthBar(const Surface &out) } int barLabelY = yPos + 10 + (height - 11) / 2; - DrawString(out, mon.mName, { { xPos - 1, barLabelY + 1 }, { width, height } }, UIS_CENTER | UIS_BLACK); + DrawString(out, monster.mName, { { xPos - 1, barLabelY + 1 }, { width, height } }, UIS_CENTER | UIS_BLACK); uint16_t style = UIS_SILVER; - if (mon._uniqtype != 0) + if (monster._uniqtype != 0) style = UIS_GOLD; - else if (mon.leader != 0) + else if (monster.leader != 0) style = UIS_BLUE; - DrawString(out, mon.mName, { { xPos, barLabelY }, { width, height } }, UIS_CENTER | style); + DrawString(out, monster.mName, { { xPos, barLabelY }, { width, height } }, UIS_CENTER | style); - if (mon._uniqtype != 0 || MonsterKillCounts[mon.MType->mtype] >= 15) { + if (monster._uniqtype != 0 || MonsterKillCounts[monster.MType->mtype] >= 15) { monster_resistance immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING }; monster_resistance resists[] = { RESIST_MAGIC, RESIST_FIRE, RESIST_LIGHTNING }; int resOffset = 5; for (int i = 0; i < 3; i++) { - if ((mon.mMagicRes & immunes[i]) != 0) { + if ((monster.mMagicRes & immunes[i]) != 0) { DrawArt(out, xPos + resOffset, yPos + height - 6, &resistance, i * 2 + 1); resOffset += resistance.w() + 2; - } else if ((mon.mMagicRes & resists[i]) != 0) { + } else if ((monster.mMagicRes & resists[i]) != 0) { DrawArt(out, xPos + resOffset, yPos + height - 6, &resistance, i * 2); resOffset += resistance.w() + 2; } diff --git a/Source/quests.cpp b/Source/quests.cpp index 9dd3e21ae..c30b59977 100644 --- a/Source/quests.cpp +++ b/Source/quests.cpp @@ -17,6 +17,7 @@ #include "init.h" #include "minitext.h" #include "missiles.h" +#include "monster.h" #include "options.h" #include "stores.h" #include "towners.h" @@ -301,29 +302,29 @@ bool QuestStatus(int i) return true; } -void CheckQuestKill(int m, bool sendmsg) +void CheckQuestKill(const MonsterStruct &monster, bool sendmsg) { if (gbIsSpawn) return; - if (Monsters[m].MType->mtype == MT_SKING) { + if (monster.MType->mtype == MT_SKING) { Quests[Q_SKELKING]._qactive = QUEST_DONE; Players[MyPlayerId].Say(HeroSpeech::RestWellLeoricIllFindYourSon, 30); if (sendmsg) NetSendCmdQuest(true, Q_SKELKING); - } else if (Monsters[m].MType->mtype == MT_CLEAVER) { + } else if (monster.MType->mtype == MT_CLEAVER) { Quests[Q_BUTCHER]._qactive = QUEST_DONE; Players[MyPlayerId].Say(HeroSpeech::TheSpiritsOfTheDeadAreNowAvenged, 30); if (sendmsg) NetSendCmdQuest(true, Q_BUTCHER); - } else if (Monsters[m]._uniqtype - 1 == UMT_GARBUD) { //"Gharbad the Weak" + } else if (monster._uniqtype - 1 == UMT_GARBUD) { //"Gharbad the Weak" Quests[Q_GARBUD]._qactive = QUEST_DONE; Players[MyPlayerId].Say(HeroSpeech::ImNotImpressed, 30); - } else if (Monsters[m]._uniqtype - 1 == UMT_ZHAR) { //"Zhar the Mad" + } else if (monster._uniqtype - 1 == UMT_ZHAR) { //"Zhar the Mad" Quests[Q_ZHAR]._qactive = QUEST_DONE; Players[MyPlayerId].Say(HeroSpeech::ImSorryDidIBreakYourConcentration, 30); - } else if (Monsters[m]._uniqtype - 1 == UMT_LAZARUS && gbIsMultiplayer) { //"Arch-Bishop Lazarus" + } else if (monster._uniqtype - 1 == UMT_LAZARUS && gbIsMultiplayer) { //"Arch-Bishop Lazarus" Quests[Q_BETRAYER]._qactive = QUEST_DONE; Quests[Q_BETRAYER]._qvar1 = 7; Quests[Q_DIABLO]._qactive = QUEST_ACTIVE; @@ -342,7 +343,7 @@ void CheckQuestKill(int m, bool sendmsg) NetSendCmdQuest(true, Q_BETRAYER); NetSendCmdQuest(true, Q_DIABLO); } - } else if (Monsters[m]._uniqtype - 1 == UMT_LAZARUS && !gbIsMultiplayer) { //"Arch-Bishop Lazarus" + } else if (monster._uniqtype - 1 == UMT_LAZARUS && !gbIsMultiplayer) { //"Arch-Bishop Lazarus" Quests[Q_BETRAYER]._qactive = QUEST_DONE; InitVPTriggers(); Quests[Q_BETRAYER]._qvar1 = 7; @@ -350,7 +351,7 @@ void CheckQuestKill(int m, bool sendmsg) Quests[Q_DIABLO]._qactive = QUEST_ACTIVE; AddMissile({ 35, 32 }, { 35, 32 }, 0, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0); Players[MyPlayerId].Say(HeroSpeech::YourMadnessEndsHereBetrayer, 30); - } else if (Monsters[m]._uniqtype - 1 == UMT_WARLORD) { //"Warlord of Blood" + } else if (monster._uniqtype - 1 == UMT_WARLORD) { //"Warlord of Blood" Quests[Q_WARLORD]._qactive = QUEST_DONE; Players[MyPlayerId].Say(HeroSpeech::YourReignOfPainHasEnded, 30); } diff --git a/Source/quests.h b/Source/quests.h index b3fe516ff..73d5a4f0f 100644 --- a/Source/quests.h +++ b/Source/quests.h @@ -11,6 +11,7 @@ #include "engine/cel_sprite.hpp" #include "engine/point.hpp" #include "gendung.h" +#include "monster.h" #include "textdat.h" #include "utils/stdcompat/optional.hpp" @@ -80,7 +81,7 @@ void InitQuests(); void CheckQuests(); bool ForceQuests(); bool QuestStatus(int i); -void CheckQuestKill(int m, bool sendmsg); +void CheckQuestKill(const MonsterStruct &monster, bool sendmsg); void DRLG_CheckQuests(int x, int y); void SetReturnLvlPos(); void GetReturnLvlPos(); diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 069812cf9..0939741fc 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -414,45 +414,40 @@ void DrawMissile(const Surface &out, int x, int y, int sx, int sy, bool pre) * @param my Output buffer coordinate * @param m Id of monster */ -static void DrawMonster(const Surface &out, int x, int y, int mx, int my, int m) +static void DrawMonster(const Surface &out, int x, int y, int mx, int my, const MonsterStruct &monster) { - if (m < 0 || m >= MAXMONSTERS) { - Log("Draw Monster: tried to draw illegal monster {}", m); + if (monster.AnimInfo.pCelSprite == nullptr) { + Log("Draw Monster \"{}\": NULL Cel Buffer", monster.mName); return; } - if (Monsters[m].AnimInfo.pCelSprite == nullptr) { - Log("Draw Monster \"{}\": NULL Cel Buffer", Monsters[m].mName); - return; - } - - int nCel = Monsters[m].AnimInfo.GetFrameToUseForRendering(); - const auto *frameTable = reinterpret_cast(Monsters[m].AnimInfo.pCelSprite->Data()); + int nCel = monster.AnimInfo.GetFrameToUseForRendering(); + const auto *frameTable = reinterpret_cast(monster.AnimInfo.pCelSprite->Data()); int frames = SDL_SwapLE32(frameTable[0]); if (nCel < 1 || frames > 50 || nCel > frames) { const char *szMode = "unknown action"; - if (Monsters[m]._mmode <= 17) - szMode = MonsterModeNames[Monsters[m]._mmode]; + if (monster._mmode <= 17) + szMode = MonsterModeNames[monster._mmode]; Log( "Draw Monster \"{}\" {}: facing {}, frame {} of {}", - Monsters[m].mName, + monster.mName, szMode, - Monsters[m]._mdir, + monster._mdir, nCel, frames); return; } - const auto &cel = *Monsters[m].AnimInfo.pCelSprite; + const auto &cel = *monster.AnimInfo.pCelSprite; if ((dFlags[x][y] & BFLAG_LIT) == 0) { Cl2DrawLightTbl(out, mx, my, cel, nCel, 1); return; } int trans = 0; - if (Monsters[m]._uniqtype != 0) - trans = Monsters[m]._uniqtrans + 4; - if (Monsters[m]._mmode == MM_STONE) + if (monster._uniqtype != 0) + trans = monster._uniqtrans + 4; + if (monster._mmode == MM_STONE) trans = 2; if (Players[MyPlayerId]._pInfraFlag && LightTableIndex > 8) trans = 1; @@ -788,29 +783,29 @@ static void DrawMonsterHelper(const Surface &out, int x, int y, int oy, int sx, return; } - MonsterStruct *pMonster = &Monsters[mi]; - if ((pMonster->_mFlags & MFLAG_HIDDEN) != 0) { + const auto &monster = Monsters[mi]; + if ((monster._mFlags & MFLAG_HIDDEN) != 0) { return; } - if (pMonster->MType == nullptr) { - Log("Draw Monster \"{}\": uninitialized monster", pMonster->mName); + if (monster.MType == nullptr) { + Log("Draw Monster \"{}\": uninitialized monster", monster.mName); return; } - const CelSprite &cel = *pMonster->AnimInfo.pCelSprite; + const CelSprite &cel = *monster.AnimInfo.pCelSprite; - Displacement offset = pMonster->position.offset; - if (pMonster->IsWalking()) { - offset = GetOffsetForWalking(pMonster->AnimInfo, pMonster->_mdir); + Displacement offset = monster.position.offset; + if (monster.IsWalking()) { + offset = GetOffsetForWalking(monster.AnimInfo, monster._mdir); } int px = sx + offset.deltaX - CalculateWidth2(cel.Width()); int py = sy + offset.deltaY; if (mi == pcursmonst) { - Cl2DrawOutline(out, 233, px, py, cel, pMonster->AnimInfo.GetFrameToUseForRendering()); + Cl2DrawOutline(out, 233, px, py, cel, monster.AnimInfo.GetFrameToUseForRendering()); } - DrawMonster(out, x, y, px, py, mi); + DrawMonster(out, x, y, px, py, monster); } /** diff --git a/Source/sync.cpp b/Source/sync.cpp index 1cb032276..c1fb5a2d1 100644 --- a/Source/sync.cpp +++ b/Source/sync.cpp @@ -23,8 +23,9 @@ void SyncOneMonster() { for (int i = 0; i < ActiveMonsterCount; i++) { int m = ActiveMonsters[i]; - sgnMonsterPriority[m] = Players[MyPlayerId].position.tile.ManhattanDistance(Monsters[m].position.tile); - if (Monsters[m]._msquelch == 0) { + auto &monster = Monsters[m]; + sgnMonsterPriority[m] = Players[MyPlayerId].position.tile.ManhattanDistance(monster.position.tile); + if (monster._msquelch == 0) { sgnMonsterPriority[m] += 0x1000; } else if (sgwLRU[m] != 0) { sgwLRU[m]--; @@ -34,14 +35,15 @@ void SyncOneMonster() void SyncMonsterPos(TSyncMonster *p, int ndx) { + auto &monster = Monsters[ndx]; p->_mndx = ndx; - p->_mx = Monsters[ndx].position.tile.x; - p->_my = Monsters[ndx].position.tile.y; - p->_menemy = encode_enemy(ndx); + p->_mx = monster.position.tile.x; + p->_my = monster.position.tile.y; + p->_menemy = encode_enemy(monster); p->_mdelta = sgnMonsterPriority[ndx] > 255 ? 255 : sgnMonsterPriority[ndx]; sgnMonsterPriority[ndx] = 0xFFFF; - sgwLRU[ndx] = Monsters[ndx]._msquelch == 0 ? 0xFFFF : 0xFFFE; + sgwLRU[ndx] = monster._msquelch == 0 ? 0xFFFF : 0xFFFE; } bool SyncMonsterActive(TSyncMonster *p) @@ -193,11 +195,13 @@ static void SyncMonster(int pnum, const TSyncMonster *p) { int ndx = p->_mndx; - if (Monsters[ndx]._mhitpoints <= 0) { + auto &monster = Monsters[ndx]; + + if (monster._mhitpoints <= 0) { return; } - uint32_t delta = Players[MyPlayerId].position.tile.ManhattanDistance(Monsters[ndx].position.tile); + uint32_t delta = Players[MyPlayerId].position.tile.ManhattanDistance(monster.position.tile); if (delta > 255) { delta = 255; } @@ -205,34 +209,34 @@ static void SyncMonster(int pnum, const TSyncMonster *p) if (delta < p->_mdelta || (delta == p->_mdelta && pnum > MyPlayerId)) { return; } - if (Monsters[ndx].position.future.x == p->_mx && Monsters[ndx].position.future.y == p->_my) { + if (monster.position.future.x == p->_mx && monster.position.future.y == p->_my) { return; } - if (Monsters[ndx]._mmode == MM_CHARGE || Monsters[ndx]._mmode == MM_STONE) { + if (monster._mmode == MM_CHARGE || monster._mmode == MM_STONE) { return; } - if (Monsters[ndx].position.tile.WalkingDistance({ p->_mx, p->_my }) <= 2) { - if (Monsters[ndx]._mmode < MM_WALK || Monsters[ndx]._mmode > MM_WALK3) { - Direction md = GetDirection(Monsters[ndx].position.tile, { p->_mx, p->_my }); + if (monster.position.tile.WalkingDistance({ p->_mx, p->_my }) <= 2) { + if (monster._mmode < MM_WALK || monster._mmode > MM_WALK3) { + Direction md = GetDirection(monster.position.tile, { p->_mx, p->_my }); if (DirOK(ndx, md)) { M_ClearSquares(ndx); - dMonster[Monsters[ndx].position.tile.x][Monsters[ndx].position.tile.y] = ndx + 1; + dMonster[monster.position.tile.x][monster.position.tile.y] = ndx + 1; M_WalkDir(ndx, md); - Monsters[ndx]._msquelch = UINT8_MAX; + monster._msquelch = UINT8_MAX; } } } else if (dMonster[p->_mx][p->_my] == 0) { M_ClearSquares(ndx); dMonster[p->_mx][p->_my] = ndx + 1; - Monsters[ndx].position.tile = { p->_mx, p->_my }; - decode_enemy(ndx, p->_menemy); - Direction md = GetDirection({ p->_mx, p->_my }, Monsters[ndx].enemyPosition); - M_StartStand(ndx, md); - Monsters[ndx]._msquelch = UINT8_MAX; + monster.position.tile = { p->_mx, p->_my }; + decode_enemy(monster, p->_menemy); + Direction md = GetDirection({ p->_mx, p->_my }, monster.enemyPosition); + M_StartStand(monster, md); + monster._msquelch = UINT8_MAX; } - decode_enemy(ndx, p->_menemy); + decode_enemy(monster, p->_menemy); } uint32_t sync_update(int pnum, const byte *pbBuf) diff --git a/test/effects_test.cpp b/test/effects_test.cpp index 234b42f05..af19996c2 100644 --- a/test/effects_test.cpp +++ b/test/effects_test.cpp @@ -5,52 +5,52 @@ using namespace devilution; -TEST(Effects, CalculatePosition_center) +TEST(Effects, CalculateSoundPosition_center) { Players[MyPlayerId].position.tile = { 50, 50 }; int plVolume = 0; int plPan = 0; - EXPECT_EQ(TestCalculatePosition({ 50, 50 }, &plVolume, &plPan), true); + EXPECT_EQ(CalculateSoundPosition({ 50, 50 }, &plVolume, &plPan), true); EXPECT_EQ(plVolume, 0); EXPECT_EQ(plPan, 0); } -TEST(Effects, CalculatePosition_near) +TEST(Effects, CalculateSoundPosition_near) { Players[MyPlayerId].position.tile = { 50, 50 }; int plVolume = 0; int plPan = 0; - EXPECT_EQ(TestCalculatePosition({ 55, 50 }, &plVolume, &plPan), true); + EXPECT_EQ(CalculateSoundPosition({ 55, 50 }, &plVolume, &plPan), true); EXPECT_EQ(plVolume, -320); EXPECT_EQ(plPan, 1280); } -TEST(Effects, CalculatePosition_out_of_range) +TEST(Effects, CalculateSoundPosition_out_of_range) { Players[MyPlayerId].position.tile = { 12, 12 }; int plVolume = 1234; int plPan = 0; - EXPECT_EQ(TestCalculatePosition({ 112, 112 }, &plVolume, &plPan), false); + EXPECT_EQ(CalculateSoundPosition({ 112, 112 }, &plVolume, &plPan), false); EXPECT_EQ(plVolume, 1234); EXPECT_EQ(plPan, 0); } -TEST(Effects, CalculatePosition_extreme_right) +TEST(Effects, CalculateSoundPosition_extreme_right) { Players[MyPlayerId].position.tile = { 50, 50 }; int plVolume = 0; int plPan = 0; - EXPECT_EQ(TestCalculatePosition({ 75, 25 }, &plVolume, &plPan), true); + EXPECT_EQ(CalculateSoundPosition({ 75, 25 }, &plVolume, &plPan), true); EXPECT_EQ(plVolume, -2176); EXPECT_EQ(plPan, 6400); } -TEST(Effects, CalculatePosition_extreme_left) +TEST(Effects, CalculateSoundPosition_extreme_left) { Players[MyPlayerId].position.tile = { 50, 50 }; int plVolume = 0; int plPan = 0; - EXPECT_EQ(TestCalculatePosition({ 25, 75 }, &plVolume, &plPan), true); + EXPECT_EQ(CalculateSoundPosition({ 25, 75 }, &plVolume, &plPan), true); EXPECT_EQ(plVolume, -2176); EXPECT_EQ(plPan, -6400); }