From 6949a6f4185677babaf84ce32feacdb041187bdc Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sun, 3 Jul 2022 10:10:07 +0100 Subject: [PATCH] Monster: Remove MType/MData pointers These pointers are redundant, replaces them with methods. --- Source/control.cpp | 2 +- Source/cursor.cpp | 28 ++--- Source/dead.cpp | 2 +- Source/debug.cpp | 2 +- Source/engine/render/scrollrt.cpp | 5 - Source/items.cpp | 18 +-- Source/loadsave.cpp | 4 - Source/missiles.cpp | 46 ++++---- Source/monster.cpp | 189 +++++++++++++----------------- Source/monster.h | 17 ++- Source/msg.cpp | 5 +- Source/player.cpp | 6 +- Source/qol/monhealthbar.cpp | 4 +- Source/quests.cpp | 4 +- 14 files changed, 154 insertions(+), 178 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index 2a100394e..ae5a269ee 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -911,7 +911,7 @@ void DrawInfoBox(const Surface &out) InfoColor = UiFlags::ColorWhitegold; PrintUniqueHistory(); } else { - PrintMonstHistory(monster.MType->type); + PrintMonstHistory(monster.type().type); } } else if (pcursitem == -1) { InfoString = string_view(Towners[pcursmonst].name); diff --git a/Source/cursor.cpp b/Source/cursor.cpp index ea1ac9b3d..01c6c39ea 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -404,49 +404,49 @@ void CheckCursMove() if (pcurstemp != -1) { if (!flipflag && mx + 2 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 2][my + 1] != 0 && IsTileLit({ mx + 2, my + 1 })) { int mi = abs(dMonster[mx + 2][my + 1]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 2, 1 }; pcursmonst = mi; } } if (flipflag && mx + 1 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 1][my + 2] != 0 && IsTileLit({ mx + 1, my + 2 })) { int mi = abs(dMonster[mx + 1][my + 2]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 2 }; pcursmonst = mi; } } if (mx + 2 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 2][my + 2] != 0 && IsTileLit({ mx + 2, my + 2 })) { int mi = abs(dMonster[mx + 2][my + 2]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 2, 2 }; pcursmonst = mi; } } if (mx + 1 < MAXDUNX && !flipflag && dMonster[mx + 1][my] != 0 && IsTileLit({ mx + 1, my })) { int mi = abs(dMonster[mx + 1][my]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 0 }; pcursmonst = mi; } } if (my + 1 < MAXDUNY && flipflag && dMonster[mx][my + 1] != 0 && IsTileLit({ mx, my + 1 })) { int mi = abs(dMonster[mx][my + 1]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 0, 1 }; pcursmonst = mi; } } if (dMonster[mx][my] != 0 && IsTileLit({ mx, my })) { int mi = abs(dMonster[mx][my]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 1) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 1) != 0) { cursPosition = { mx, my }; pcursmonst = mi; } } if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 1][my + 1] != 0 && IsTileLit({ mx + 1, my + 1 })) { int mi = abs(dMonster[mx + 1][my + 1]) - 1; - if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (mi == pcurstemp && Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 1 }; pcursmonst = mi; } @@ -464,49 +464,49 @@ void CheckCursMove() } if (!flipflag && mx + 2 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 2][my + 1] != 0 && IsTileLit({ mx + 2, my + 1 })) { int mi = abs(dMonster[mx + 2][my + 1]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 2, 1 }; pcursmonst = mi; } } if (flipflag && mx + 1 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 1][my + 2] != 0 && IsTileLit({ mx + 1, my + 2 })) { int mi = abs(dMonster[mx + 1][my + 2]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 2 }; pcursmonst = mi; } } if (mx + 2 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 2][my + 2] != 0 && IsTileLit({ mx + 2, my + 2 })) { int mi = abs(dMonster[mx + 2][my + 2]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 4) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 4) != 0) { cursPosition = Point { mx, my } + Displacement { 2, 2 }; pcursmonst = mi; } } if (!flipflag && mx + 1 < MAXDUNX && dMonster[mx + 1][my] != 0 && IsTileLit({ mx + 1, my })) { int mi = abs(dMonster[mx + 1][my]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 0 }; pcursmonst = mi; } } if (flipflag && my + 1 < MAXDUNY && dMonster[mx][my + 1] != 0 && IsTileLit({ mx, my + 1 })) { int mi = abs(dMonster[mx][my + 1]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 0, 1 }; pcursmonst = mi; } } if (dMonster[mx][my] != 0 && IsTileLit({ mx, my })) { int mi = abs(dMonster[mx][my]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 1) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 1) != 0) { cursPosition = { mx, my }; pcursmonst = mi; } } if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 1][my + 1] != 0 && IsTileLit({ mx + 1, my + 1 })) { int mi = abs(dMonster[mx + 1][my + 1]) - 1; - if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].MData->mSelFlag & 2) != 0) { + if (Monsters[mi]._mhitpoints >> 6 > 0 && (Monsters[mi].data().mSelFlag & 2) != 0) { cursPosition = Point { mx, my } + Displacement { 1, 1 }; pcursmonst = mi; } diff --git a/Source/dead.cpp b/Source/dead.cpp index 6189b8c8d..d15359e5e 100644 --- a/Source/dead.cpp +++ b/Source/dead.cpp @@ -58,7 +58,7 @@ void InitCorpses() for (int i = 0; i < ActiveMonsterCount; i++) { auto &monster = Monsters[ActiveMonsters[i]]; if (monster._uniqtype != 0) { - InitDeadAnimationFromMonster(Corpses[nd], *monster.MType); + InitDeadAnimationFromMonster(Corpses[nd], monster.type()); Corpses[nd].translationPaletteIndex = ActiveMonsters[i] + 1; nd++; diff --git a/Source/debug.cpp b/Source/debug.cpp index cfbb0d94e..426004195 100644 --- a/Source/debug.cpp +++ b/Source/debug.cpp @@ -335,7 +335,7 @@ std::string ExportDun(const string_view parameter) uint16_t monsterId = 0; if (dMonster[x][y] > 0) { for (int i = 0; i < 157; i++) { - if (MonstConvTbl[i] == Monsters[abs(dMonster[x][y]) - 1].MType->type) { + if (MonstConvTbl[i] == Monsters[abs(dMonster[x][y]) - 1].type().type) { monsterId = i + 1; break; } diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 51c2387bf..33bea3a05 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -772,11 +772,6 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe return; } - if (monster.MType == nullptr) { - Log("Draw Monster \"{}\": uninitialized monster", monster.mName); - return; - } - CelSprite cel = *monster.AnimInfo.celSprite; Displacement offset = monster.position.offset; diff --git a/Source/items.cpp b/Source/items.cpp index b7993bc51..6b8acc762 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1334,8 +1334,8 @@ void GetItemBonus(Item &item, int minlvl, int maxlvl, bool onlygood, bool allows int RndUItem(Monster *monster) { - if (monster != nullptr && (monster->MData->mTreasure & T_UNIQ) != 0 && !gbIsMultiplayer) - return -((monster->MData->mTreasure & T_MASK) + 1); + if (monster != nullptr && (monster->data().mTreasure & T_UNIQ) != 0 && !gbIsMultiplayer) + return -((monster->data().mTreasure & T_MASK) + 1); int ril[512]; @@ -3007,10 +3007,10 @@ void SetupItem(Item &item) int RndItem(const Monster &monster) { - if ((monster.MData->mTreasure & T_UNIQ) != 0) - return -((monster.MData->mTreasure & T_MASK) + 1); + if ((monster.data().mTreasure & T_UNIQ) != 0) + return -((monster.data().mTreasure & T_MASK) + 1); - if ((monster.MData->mTreasure & T_NODROP) != 0) + if ((monster.data().mTreasure & T_NODROP) != 0) return 0; if (GenerateRnd(100) > 40) @@ -3070,7 +3070,7 @@ void SpawnItem(Monster &monster, Point position, bool sendmsg) int idx; bool onlygood = true; - if (monster._uniqtype != 0 || ((monster.MData->mTreasure & T_UNIQ) != 0 && gbIsMultiplayer)) { + if (monster._uniqtype != 0 || ((monster.data().mTreasure & T_UNIQ) != 0 && gbIsMultiplayer)) { idx = RndUItem(&monster); if (idx < 0) { SpawnUnique((_unique_items) - (idx + 1), position); @@ -3101,8 +3101,8 @@ void SpawnItem(Monster &monster, Point position, bool sendmsg) GetSuperItemSpace(position, ii); int uper = monster._uniqtype != 0 ? 15 : 1; - int8_t mLevel = monster.MData->mLevel; - if (!gbIsHellfire && monster.MType->type == MT_DIABLO) + int8_t mLevel = monster.data().mLevel; + if (!gbIsHellfire && monster.type().type == MT_DIABLO) mLevel -= 15; SetupAllItems(item, idx, AdvanceRndSeed(), mLevel, uper, onlygood, false, false); @@ -4462,7 +4462,7 @@ std::string DebugSpawnItem(std::string itemName) uint32_t begin = SDL_GetTicks(); Monster fake_m; - fake_m.MData = &MonstersData[0]; + fake_m._mMTidx = 0; fake_m._uniqtype = 0; int i = 0; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index a14797bad..be1b6b633 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -657,8 +657,6 @@ void LoadMonster(LoadHelper *file, Monster &monster) monster.mlid = NO_LIGHT; // Correct incorect values in old saves // Omit pointer mName; - // Omit pointer MType; - // Omit pointer data; if (gbSkipSync) return; @@ -1396,8 +1394,6 @@ void SaveMonster(SaveHelper *file, Monster &monster) file->WriteLE(monster.mlid); // Omit pointer mName; - // Omit pointer MType; - // Omit pointer data; } void SaveMissile(SaveHelper *file, const Missile &missile) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index af6d96cc1..d1d0c6864 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -228,7 +228,7 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, missile_id t dam += player._pDamageMod; else dam += player._pDamageMod / 2; - if (monster.MData->mMonstClass == MonsterClass::Demon && HasAnyOf(player._pIFlags, ItemSpecialEffect::TripleDemonDamage)) + if (monster.data().mMonstClass == MonsterClass::Demon && HasAnyOf(player._pIFlags, ItemSpecialEffect::TripleDemonDamage)) dam *= 3; } bool resist = monster.IsResistant(t); @@ -250,7 +250,7 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, missile_id t } else { if (monster._mmode != MonsterMode::Petrified && MissilesData[t].mType == 0 && HasAnyOf(player._pIFlags, ItemSpecialEffect::Knockback)) M_GetKnockback(m); - if (monster.MType->type != MT_GOLEM) + if (monster.type().type != MT_GOLEM) M_StartHit(m, pnum, dam); } @@ -594,7 +594,7 @@ bool GuardianTryFireAt(Missile &missile, Point target) if (mid < 0) return false; const Monster &monster = Monsters[mid]; - if (monster.MType->type == MT_GOLEM) + if (monster.type().type == MT_GOLEM) return false; if (monster._mhitpoints >> 6 <= 0) return false; @@ -641,7 +641,7 @@ void SpawnLightning(Missile &missile, int dam) if (position != Point { missile.var1, missile.var2 } && InDungeonBounds(position)) { missile_id type = MIS_LIGHTNING; if (!missile.IsTrap() && missile._micaster == TARGET_PLAYERS - && IsAnyOf(Monsters[missile._misource].MType->type, MT_STORM, MT_RSTORM, MT_STORML, MT_MAEL)) { + && IsAnyOf(Monsters[missile._misource].type().type, MT_STORM, MT_RSTORM, MT_STORML, MT_MAEL)) { type = MIS_LIGHTNING2; } AddMissile( @@ -882,7 +882,7 @@ bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, missile_id t, bool } else if (resist) { PlayEffect(monster, 1); } else { - if (monster.MType->type != MT_GOLEM) + if (monster.type().type != MT_GOLEM) M_StartHit(m, dam); } return true; @@ -1144,7 +1144,7 @@ void AddBerserk(Missile &missile, const AddMissileParameter ¶meter) return false; const Monster &monster = Monsters[monsterId]; - if (monster.MType->type == MT_GOLEM) + if (monster.type().type == MT_GOLEM) return false; if ((monster._mFlags & MFLAG_BERSERK) != 0) return false; @@ -1786,7 +1786,7 @@ void AddLightning(Missile &missile, const AddMissileParameter ¶meter) missile._miAnimFrame = GenerateRnd(8) + 1; if (missile._micaster == TARGET_PLAYERS || missile.IsTrap()) { - if (missile.IsTrap() || Monsters[missile._misource].MType->type == MT_FAMILIAR) + if (missile.IsTrap() || Monsters[missile._misource].type().type == MT_FAMILIAR) missile._mirange = 8; else missile._mirange = 10; @@ -1799,7 +1799,7 @@ void AddLightning(Missile &missile, const AddMissileParameter ¶meter) void AddMisexp(Missile &missile, const AddMissileParameter ¶meter) { if (missile._micaster != TARGET_MONSTERS && missile._misource >= 0) { - switch (Monsters[missile._misource].MType->type) { + switch (Monsters[missile._misource].type().type) { case MT_SUCCUBUS: SetMissAnim(missile, MFILE_FLAREEXP); break; @@ -2016,7 +2016,7 @@ void AddChain(Missile &missile, const AddMissileParameter ¶meter) namespace { void InitMissileAnimationFromMonster(Missile &mis, Direction midir, const Monster &mon, MonsterGraphic graphic) { - const AnimStruct &anim = mon.MType->getAnimData(graphic); + const AnimStruct &anim = mon.type().getAnimData(graphic); mis._mimfnum = static_cast(midir); mis._miAnimFlags = MissileDataFlags::None; CelSprite celSprite = *anim.getCelSpritesForDirection(midir); @@ -2038,14 +2038,14 @@ void AddRhino(Missile &missile, const AddMissileParameter ¶meter) Monster &monster = Monsters[missile._misource]; MonsterGraphic graphic = MonsterGraphic::Walk; - if (IsAnyOf(monster.MType->type, MT_HORNED, MT_MUDRUN, MT_FROSTC, MT_OBLORD)) { + if (IsAnyOf(monster.type().type, MT_HORNED, MT_MUDRUN, MT_FROSTC, MT_OBLORD)) { graphic = MonsterGraphic::Special; - } else if (IsAnyOf(monster.MType->type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) { + } else if (IsAnyOf(monster.type().type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) { graphic = MonsterGraphic::Attack; } UpdateMissileVelocity(missile, parameter.dst, 18); InitMissileAnimationFromMonster(missile, parameter.midir, monster, graphic); - if (IsAnyOf(monster.MType->type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) + if (IsAnyOf(monster.type().type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) missile._miAnimFrame = 7; if (monster._uniqtype != 0) { missile._mlid = monster.mlid; @@ -2069,13 +2069,13 @@ void AddFlare(Missile &missile, const AddMissileParameter ¶meter) ApplyPlrDamage(missile._misource, 5); } else if (missile._misource > 0) { auto &monster = Monsters[missile._misource]; - if (monster.MType->type == MT_SUCCUBUS) + if (monster.type().type == MT_SUCCUBUS) SetMissAnim(missile, MFILE_FLARE); - if (monster.MType->type == MT_SNOWWICH) + if (monster.type().type == MT_SNOWWICH) SetMissAnim(missile, MFILE_SCUBMISB); - if (monster.MType->type == MT_HLSPWN) + if (monster.type().type == MT_HLSPWN) SetMissAnim(missile, MFILE_SCUBMISD); - if (monster.MType->type == MT_SOLBRNR) + if (monster.type().type == MT_SOLBRNR) SetMissAnim(missile, MFILE_SCUBMISC); } @@ -2121,7 +2121,7 @@ void AddStone(Missile &missile, const AddMissileParameter ¶meter) auto &monster = Monsters[monsterId]; - if (IsAnyOf(monster.MType->type, MT_GOLEM, MT_DIABLO, MT_NAKRUL)) { + if (IsAnyOf(monster.type().type, MT_GOLEM, MT_DIABLO, MT_NAKRUL)) { return false; } if (IsAnyOf(monster._mmode, MonsterMode::FadeIn, MonsterMode::FadeOut, MonsterMode::Charge)) { @@ -3455,7 +3455,7 @@ void MI_Acidsplat(Missile &missile) if (missile._mirange == 0) { missile._miDelFlag = true; int monst = missile._misource; - int dam = (Monsters[monst].MData->mLevel >= 2 ? 2 : 1); + int dam = (Monsters[monst].data().mLevel >= 2 ? 2 : 1); AddMissile(missile.position.tile, { 0, 0 }, Direction::South, MIS_ACIDPUD, TARGET_PLAYERS, monst, dam, missile._mispllvl); } else { PutMissile(missile); @@ -3620,7 +3620,7 @@ void MI_Apoca(Missile &missile) int mid = dMonster[k][j] - 1; if (mid < 0) continue; - if (Monsters[mid].MType->type == MT_GOLEM) + if (Monsters[mid].type().type == MT_GOLEM) continue; if (TileHasAny(dPiece[k][j], TileProperties::Solid)) continue; @@ -4016,17 +4016,17 @@ void missiles_process_charge() if (missile._mitype != MIS_RHINO) continue; - CMonster *mon = Monsters[missile._misource].MType; + const CMonster &mon = Monsters[missile._misource].type(); MonsterGraphic graphic; - if (IsAnyOf(mon->type, MT_HORNED, MT_MUDRUN, MT_FROSTC, MT_OBLORD)) { + if (IsAnyOf(mon.type, MT_HORNED, MT_MUDRUN, MT_FROSTC, MT_OBLORD)) { graphic = MonsterGraphic::Special; - } else if (IsAnyOf(mon->type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) { + } else if (IsAnyOf(mon.type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) { graphic = MonsterGraphic::Attack; } else { graphic = MonsterGraphic::Walk; } - missile._miAnimData = mon->getAnimData(graphic).celSpritesForDirections[missile._mimfnum]; + missile._miAnimData = mon.getAnimData(graphic).celSpritesForDirections[missile._mimfnum]; } } diff --git a/Source/monster.cpp b/Source/monster.cpp index aa080dea3..f0bcce73f 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -196,17 +196,15 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position) monster.position.old = position; monster._mMTidx = mtype; monster._mmode = MonsterMode::Stand; - monster.MType = &LevelMonsterTypes[mtype]; - monster.MData = monster.MType->data; - monster.mName = pgettext("monster", monster.MData->mName).data(); + monster.mName = pgettext("monster", monster.data().mName).data(); monster.AnimInfo = {}; monster.ChangeAnimationData(MonsterGraphic::Stand); monster.AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(monster.AnimInfo.TicksPerFrame - 1); monster.AnimInfo.CurrentFrame = GenerateRnd(monster.AnimInfo.NumberOfFrames - 1); - monster.mLevel = monster.MData->mLevel; - int maxhp = monster.MData->mMinHP + GenerateRnd(monster.MData->mMaxHP - monster.MData->mMinHP + 1); - if (monster.MType->type == MT_DIABLO && !gbIsHellfire) { + monster.mLevel = monster.data().mLevel; + int maxhp = monster.data().mMinHP + GenerateRnd(monster.data().mMaxHP - monster.data().mMinHP + 1); + if (monster.type().type == MT_DIABLO && !gbIsHellfire) { maxhp /= 2; monster.mLevel -= 15; } @@ -216,8 +214,8 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position) monster._mmaxhp = std::max(monster._mmaxhp / 2, 64); monster._mhitpoints = monster._mmaxhp; - monster._mAi = monster.MData->mAi; - monster._mint = monster.MData->mInt; + monster._mAi = monster.data().mAi; + monster._mint = monster.data().mInt; monster._mgoal = MGOAL_NORMAL; monster._mgoalvar1 = 0; monster._mgoalvar2 = 0; @@ -230,18 +228,18 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position) monster._mRndSeed = AdvanceRndSeed(); monster._mAISeed = AdvanceRndSeed(); monster.mWhoHit = 0; - monster.mExp = monster.MData->mExp; - monster.mHit = monster.MData->mHit; - monster.mMinDamage = monster.MData->mMinDamage; - monster.mMaxDamage = monster.MData->mMaxDamage; - monster.mHit2 = monster.MData->mHit2; - monster.mMinDamage2 = monster.MData->mMinDamage2; - monster.mMaxDamage2 = monster.MData->mMaxDamage2; - monster.mArmorClass = monster.MData->mArmorClass; - monster.mMagicRes = monster.MData->mMagicRes; + monster.mExp = monster.data().mExp; + monster.mHit = monster.data().mHit; + monster.mMinDamage = monster.data().mMinDamage; + monster.mMaxDamage = monster.data().mMaxDamage; + monster.mHit2 = monster.data().mHit2; + monster.mMinDamage2 = monster.data().mMinDamage2; + monster.mMaxDamage2 = monster.data().mMaxDamage2; + monster.mArmorClass = monster.data().mArmorClass; + monster.mMagicRes = monster.data().mMagicRes; monster.leader = 0; monster.leaderRelation = LeaderRelation::None; - monster._mFlags = monster.MData->mFlags; + monster._mFlags = monster.data().mFlags; monster.mtalkmsg = TEXT_NONE; if (monster._mAi == AI_GARG) { @@ -283,7 +281,7 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position) monster.mMinDamage2 = 4 * monster.mMinDamage2 + 6; monster.mMaxDamage2 = 4 * monster.mMaxDamage2 + 6; monster.mArmorClass += HellAcBonus; - monster.mMagicRes = monster.MData->mMagicRes2; + monster.mMagicRes = monster.data().mMagicRes2; } } @@ -304,7 +302,7 @@ void PlaceMonster(int i, int mtype, Point position) if (Monsters[j]._mMTidx == mtype) { return; } - if (Monsters[j].MType->type == MT_NAKRUL) { + if (Monsters[j].type().type == MT_NAKRUL) { return; } } @@ -677,7 +675,7 @@ void DeleteMonster(size_t activeIndex) void NewMonsterAnim(Monster &monster, MonsterGraphic graphic, Direction md, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int8_t numSkippedFrames = 0, int8_t distributeFramesBeforeFrame = 0) { - const auto &animData = monster.MType->getAnimData(graphic); + const auto &animData = monster.type().getAnimData(graphic); monster.AnimInfo.SetNewAnimation(animData.getCelSpritesForDirection(md), animData.frames, animData.rate, flags, numSkippedFrames, distributeFramesBeforeFrame); monster._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL); monster._mdir = md; @@ -686,9 +684,9 @@ void NewMonsterAnim(Monster &monster, MonsterGraphic graphic, Direction md, Anim void StartMonsterGotHit(int monsterId) { auto &monster = Monsters[monsterId]; - if (monster.MType->type != MT_GOLEM) { + if (monster.type().type != MT_GOLEM) { auto animationFlags = gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None; - int8_t numSkippedFrames = (gbIsHellfire && monster.MType->type == MT_DIABLO) ? 4 : 0; + int8_t numSkippedFrames = (gbIsHellfire && monster.type().type == MT_DIABLO) ? 4 : 0; NewMonsterAnim(monster, MonsterGraphic::GotHit, monster._mdir, animationFlags, numSkippedFrames); monster._mmode = MonsterMode::HitRecovery; } @@ -907,7 +905,7 @@ void StartRangedSpecialAttack(Monster &monster, missile_id missileType, int dam) Direction md = GetMonsterDirection(monster); int8_t distributeFramesBeforeFrame = 0; if (monster._mAi == AI_MEGA) - distributeFramesBeforeFrame = monster.MData->mAFNum2; + distributeFramesBeforeFrame = monster.data().mAFNum2; NewMonsterAnim(monster, MonsterGraphic::Special, md, AnimationDistributionFlags::ProcessAnimationPending, 0, distributeFramesBeforeFrame); monster._mmode = MonsterMode::SpecialRangedAttack; monster._mVar1 = missileType; @@ -949,7 +947,7 @@ void DiabloDeath(Monster &diablo, bool sendmsg) for (int j = 0; j < ActiveMonsterCount; j++) { int k = ActiveMonsters[j]; auto &monster = Monsters[k]; - if (monster.MType->type == MT_DIABLO || diablo._msquelch == 0) + if (monster.type().type == MT_DIABLO || diablo._msquelch == 0) continue; NewMonsterAnim(monster, MonsterGraphic::Death, monster._mdir); @@ -974,7 +972,7 @@ void DiabloDeath(Monster &diablo, bool sendmsg) void SpawnLoot(Monster &monster, bool sendmsg) { - if (monster.MType->type == MT_HORKSPWN) { + if (monster.type().type == MT_HORKSPWN) { return; } @@ -991,7 +989,7 @@ void SpawnLoot(Monster &monster, bool sendmsg) } else { CreateAmulet(monster.position.tile, 13, sendmsg, false); } - } else if (monster.MType->type == MT_NAKRUL) { + } else if (monster.type().type == MT_NAKRUL) { int nSFX = IsUberRoomOpened ? USFX_NAKRUL4 : USFX_NAKRUL5; if (sgGameInitInfo.bCowQuest != 0) nSFX = USFX_NAKRUL6; @@ -1003,7 +1001,7 @@ void SpawnLoot(Monster &monster, bool sendmsg) CreateMagicWeapon(monster.position.tile, ItemType::Staff, ICURS_WAR_STAFF, sendmsg, false); CreateMagicWeapon(monster.position.tile, ItemType::Bow, ICURS_LONG_WAR_BOW, sendmsg, false); CreateSpellBook(monster.position.tile, SPL_APOCA, sendmsg, false); - } else if (monster.MType->type != MT_GOLEM) { + } else if (monster.type().type != MT_GOLEM) { SpawnItem(monster, monster.position.tile, sendmsg); } } @@ -1057,16 +1055,15 @@ void HitMonster(int monsterId, int dam) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); delta_monster_hp(monsterId, monster._mhitpoints, *MyPlayer); NetSendCmdMonDmg(false, monsterId, dam); PlayEffect(monster, 1); - if (IsAnyOf(monster.MType->type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { - if (monster.MType->type == MT_BLINK) { + if (IsAnyOf(monster.type().type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { + if (monster.type().type == MT_BLINK) { Teleport(monsterId); - } else if (IsAnyOf(monster.MType->type, MT_NSCAV, MT_BSCAV, MT_WSCAV, MT_YSCAV, MT_GRAVEDIG)) { + } else if (IsAnyOf(monster.type().type, MT_NSCAV, MT_BSCAV, MT_WSCAV, MT_YSCAV, MT_GRAVEDIG)) { monster._mgoal = MGOAL_NORMAL; monster._mgoalvar1 = 0; monster._mgoalvar2 = 0; @@ -1082,12 +1079,11 @@ void MonsterHitMonster(int monsterId, int i, int dam) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); if (i < MAX_PLRS) monster.mWhoHit |= 1 << i; - if (IsAnyOf(monster.MType->type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { + if (IsAnyOf(monster.type().type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { monster._mdir = Opposite(Monsters[i]._mdir); } @@ -1098,28 +1094,27 @@ void MonsterDeath(int monsterId, int pnum, Direction md, bool sendmsg) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); if (pnum < MAX_PLRS) { if (pnum >= 0) monster.mWhoHit |= 1 << pnum; - if (monster.MType->type != MT_GOLEM) + if (monster.type().type != MT_GOLEM) AddPlrMonstExper(monster.mLevel, monster.mExp, monster.mWhoHit); } - MonsterKillCounts[monster.MType->type]++; + MonsterKillCounts[monster.type().type]++; monster._mhitpoints = 0; SetRndSeed(monster._mRndSeed); SpawnLoot(monster, sendmsg); - if (monster.MType->type == MT_DIABLO) + if (monster.type().type == MT_DIABLO) DiabloDeath(monster, true); else PlayEffect(monster, 2); if (monster._mmode != MonsterMode::Petrified) { - if (monster.MType->type == MT_GOLEM) + if (monster.type().type == MT_GOLEM) md = Direction::South; NewMonsterAnim(monster, MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None); monster._mmode = MonsterMode::Death; @@ -1133,7 +1128,7 @@ void MonsterDeath(int monsterId, int pnum, Direction md, bool sendmsg) dMonster[monster.position.tile.x][monster.position.tile.y] = monsterId + 1; CheckQuestKill(monster, sendmsg); M_FallenFear(monster.position.tile); - if (IsAnyOf(monster.MType->type, MT_NACID, MT_RACID, MT_BACID, MT_XACID, MT_SPIDLORD)) + if (IsAnyOf(monster.type().type, MT_NACID, MT_RACID, MT_BACID, MT_XACID, MT_SPIDLORD)) AddMissile(monster.position.tile, { 0, 0 }, Direction::South, MIS_ACIDPUD, TARGET_PLAYERS, monsterId, monster._mint + 1, 0); } @@ -1183,7 +1178,7 @@ void StartFadeout(Monster &monster, Direction md, bool backwards) void StartHeal(Monster &monster) { monster.ChangeAnimationData(MonsterGraphic::Special); - monster.AnimInfo.CurrentFrame = monster.MType->getAnimData(MonsterGraphic::Special).frames - 1; + monster.AnimInfo.CurrentFrame = monster.type().getAnimData(MonsterGraphic::Special).frames - 1; monster._mFlags |= MFLAG_LOCK_ANIMATION; monster._mmode = MonsterMode::Heal; monster._mVar1 = monster._mmaxhp / (16 * (GenerateRnd(5) + 4)); @@ -1200,7 +1195,7 @@ void SyncLightPosition(Monster &monster) bool MonsterIdle(Monster &monster) { - if (monster.MType->type == MT_GOLEM) + if (monster.type().type == MT_GOLEM) monster.ChangeAnimationData(MonsterGraphic::Walk); else monster.ChangeAnimationData(MonsterGraphic::Stand); @@ -1220,7 +1215,6 @@ bool MonsterWalk(int monsterId, MonsterMode variant) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); // Check if we reached new tile const bool isAnimationEnd = monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames - 1; @@ -1249,7 +1243,7 @@ bool MonsterWalk(int monsterId, MonsterMode variant) M_StartStand(monster, monster._mdir); } else { // We didn't reach new tile so update monster's "sub-tile" position if (monster.AnimInfo.TickCounterOfCurrentFrame == 0) { - if (monster.AnimInfo.CurrentFrame == 0 && monster.MType->type == MT_FLESTHNG) + if (monster.AnimInfo.CurrentFrame == 0 && monster.type().type == MT_FLESTHNG) PlayEffect(monster, 3); monster.position.offset2 += monster.position.velocity; monster.position.offset.deltaX = monster.position.offset2.deltaX >> 4; @@ -1267,7 +1261,6 @@ void MonsterAttackMonster(int i, int mid, int hper, int mind, int maxd) { assert(mid >= 0 && mid < MaxMonsters); auto &monster = Monsters[mid]; - assert(monster.MType != nullptr); if (!monster.IsPossibleToHit()) return; @@ -1317,7 +1310,6 @@ void MonsterAttackPlayer(int monsterId, int pnum, int hit, int minDam, int maxDa { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); if ((monster._mFlags & MFLAG_TARGETS_MONSTER) != 0) { MonsterAttackMonster(monsterId, pnum, hit, minDam, maxDam); @@ -1337,9 +1329,9 @@ void MonsterAttackPlayer(int monsterId, int pnum, int hit, int minDam, int maxDa hper = 1000; #endif int ac = player.GetArmor(); - if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::ACAgainstDemons) && monster.MData->mMonstClass == MonsterClass::Demon) + if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::ACAgainstDemons) && monster.data().mMonstClass == MonsterClass::Demon) ac += 40; - if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::ACAgainstUndead) && monster.MData->mMonstClass == MonsterClass::Undead) + if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::ACAgainstUndead) && monster.data().mMonstClass == MonsterClass::Undead) ac += 20; hit += 2 * (monster.mLevel - player._pLevel) + 30 @@ -1370,7 +1362,7 @@ void MonsterAttackPlayer(int monsterId, int pnum, int hit, int minDam, int maxDa } return; } - if (monster.MType->type == MT_YZOMBIE && pnum == MyPlayerId) { + if (monster.type().type == MT_YZOMBIE && pnum == MyPlayerId) { if (player._pMaxHP > 64) { if (player._pMaxHPBase > 64) { player._pMaxHP -= 64; @@ -1401,7 +1393,7 @@ void MonsterAttackPlayer(int monsterId, int pnum, int hit, int minDam, int maxDa else M_StartHit(monsterId, pnum, mdam); } - if ((monster._mFlags & MFLAG_NOLIFESTEAL) == 0 && monster.MType->type == MT_SKING && gbIsMultiplayer) + if ((monster._mFlags & MFLAG_NOLIFESTEAL) == 0 && monster.type().type == MT_SKING && gbIsMultiplayer) monster._mhitpoints += dam; if (player._pHitPoints >> 6 <= 0) { if (gbIsHellfire) @@ -1428,19 +1420,17 @@ bool MonsterAttack(int monsterId) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); - assert(monster.MData != nullptr); - if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum - 1) { + if (monster.AnimInfo.CurrentFrame == monster.data().mAFNum - 1) { MonsterAttackPlayer(monsterId, monster._menemy, monster.mHit, monster.mMinDamage, monster.mMaxDamage); if (monster._mAi != AI_SNAKE) PlayEffect(monster, 0); } - if (IsAnyOf(monster.MType->type, MT_NMAGMA, MT_YMAGMA, MT_BMAGMA, MT_WMAGMA) && monster.AnimInfo.CurrentFrame == 8) { + if (IsAnyOf(monster.type().type, MT_NMAGMA, MT_YMAGMA, MT_BMAGMA, MT_WMAGMA) && monster.AnimInfo.CurrentFrame == 8) { MonsterAttackPlayer(monsterId, monster._menemy, monster.mHit + 10, monster.mMinDamage - 2, monster.mMaxDamage - 2); PlayEffect(monster, 0); } - if (IsAnyOf(monster.MType->type, MT_STORM, MT_RSTORM, MT_STORML, MT_MAEL) && monster.AnimInfo.CurrentFrame == 12) { + if (IsAnyOf(monster.type().type, MT_STORM, MT_RSTORM, MT_STORML, MT_MAEL) && monster.AnimInfo.CurrentFrame == 12) { MonsterAttackPlayer(monsterId, monster._menemy, monster.mHit - 20, monster.mMinDamage + 4, monster.mMaxDamage + 4); PlayEffect(monster, 0); } @@ -1458,10 +1448,8 @@ bool MonsterRangedAttack(int monsterId) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); - assert(monster.MData != nullptr); - if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum - 1) { + if (monster.AnimInfo.CurrentFrame == monster.data().mAFNum - 1) { const auto &missileType = static_cast(monster._mVar1); if (missileType != MIS_NULL) { int multimissiles = 1; @@ -1494,10 +1482,8 @@ bool MonsterRangedSpecialAttack(int monsterId) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); - assert(monster.MData != nullptr); - if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2 - 1 && monster.AnimInfo.TickCounterOfCurrentFrame == 0) { + if (monster.AnimInfo.CurrentFrame == monster.data().mAFNum2 - 1 && monster.AnimInfo.TickCounterOfCurrentFrame == 0) { if (AddMissile( monster.position.tile, monster.enemyPosition, @@ -1512,7 +1498,7 @@ bool MonsterRangedSpecialAttack(int monsterId) } } - if (monster._mAi == AI_MEGA && monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2 - 1) { + if (monster._mAi == AI_MEGA && monster.AnimInfo.CurrentFrame == monster.data().mAFNum2 - 1) { if (monster._mVar2++ == 0) { monster._mFlags |= MFLAG_ALLOW_SPECIAL; } else if (monster._mVar2 == 15) { @@ -1532,10 +1518,8 @@ bool MonsterSpecialAttack(int monsterId) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); - assert(monster.MData != nullptr); - if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2 - 1) + if (monster.AnimInfo.CurrentFrame == monster.data().mAFNum2 - 1) MonsterAttackPlayer(monsterId, monster._menemy, monster.mHit2, monster.mMinDamage2, monster.mMaxDamage2); if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames - 1) { @@ -1673,10 +1657,9 @@ bool MonsterDeath(int monsterId) { assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - assert(monster.MType != nullptr); monster._mVar1++; - if (monster.MType->type == MT_DIABLO) { + if (monster.type().type == MT_DIABLO) { if (monster.position.tile.x < ViewPosition.x) { ViewPosition.x--; } else if (monster.position.tile.x > ViewPosition.x) { @@ -1693,7 +1676,7 @@ bool MonsterDeath(int monsterId) PrepDoEnding(); } else if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames - 1) { if (monster._uniqtype == 0) - AddCorpse(monster.position.tile, monster.MType->corpseId, monster._mdir); + AddCorpse(monster.position.tile, monster.type().corpseId, monster._mdir); else AddCorpse(monster.position.tile, monster._udeadval, monster._mdir); @@ -1707,7 +1690,7 @@ bool MonsterDeath(int monsterId) bool MonsterSpecialStand(Monster &monster) { - if (monster.AnimInfo.CurrentFrame == monster.MData->mAFNum2 - 1) + if (monster.AnimInfo.CurrentFrame == monster.data().mAFNum2 - 1) PlayEffect(monster, 3); if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames - 1) { @@ -1877,8 +1860,8 @@ bool IsTileSafe(const Monster &monster, Point position) return true; } - bool fearsFire = (monster.mMagicRes & IMMUNE_FIRE) == 0 || monster.MType->type == MT_DIABLO; - bool fearsLightning = (monster.mMagicRes & IMMUNE_LIGHTNING) == 0 || monster.MType->type == MT_DIABLO; + bool fearsFire = (monster.mMagicRes & IMMUNE_FIRE) == 0 || monster.type().type == MT_DIABLO; + bool fearsLightning = (monster.mMagicRes & IMMUNE_LIGHTNING) == 0 || monster.type().type == MT_DIABLO; for (auto &missile : Missiles) { if (missile.position.tile == position) { @@ -1987,7 +1970,7 @@ bool AiPlanPath(int monsterId) assert(monsterId >= 0 && monsterId < MaxMonsters); auto &monster = Monsters[monsterId]; - if (monster.MType->type != MT_GOLEM) { + if (monster.type().type != MT_GOLEM) { if (monster._msquelch == 0) return false; if (monster._mmode != MonsterMode::Stand) @@ -2012,7 +1995,7 @@ bool AiPlanPath(int monsterId) return true; } - if (monster.MType->type != MT_GOLEM) + if (monster.type().type != MT_GOLEM) monster._pathcount = 0; return false; @@ -2468,7 +2451,7 @@ void RhinoAi(int monsterId) && v < 2 * monster._mint + 43 && LineClear([&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, { fx, fy })) { if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, TARGET_PLAYERS, monsterId, 0, 0) != nullptr) { - if (monster.MData->snd_special) + if (monster.data().snd_special) PlayEffect(monster, 3); dMonster[monster.position.tile.x][monster.position.tile.y] = -(monsterId + 1); monster._mmode = MonsterMode::Charge; @@ -2653,7 +2636,7 @@ void BatAi(int monsterId) int fx = monster.enemyPosition.x; int fy = monster.enemyPosition.y; - if (monster.MType->type == MT_GLOOM + if (monster.type().type == MT_GLOOM && (abs(xd) >= 5 || abs(yd) >= 5) && v < 4 * monster._mint + 33 && LineClear([&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, { fx, fy })) { @@ -2672,7 +2655,7 @@ void BatAi(int monsterId) StartAttack(monster); monster._mgoal = MGOAL_RETREAT; monster._mgoalvar1 = 0; - if (monster.MType->type == MT_FAMILIAR) { + if (monster.type().type == MT_FAMILIAR) { AddMissile(monster.enemyPosition, { monster.enemyPosition.x + 1, 0 }, Direction::South, MIS_LIGHTNING, TARGET_PLAYERS, monsterId, GenerateRnd(10) + 1, 0); } } @@ -2772,7 +2755,7 @@ void SneakAi(int monsterId) else md = GetDirection(monster.position.tile, Players[monster._menemy].position.last); md = Opposite(md); - if (monster.MType->type == MT_UNSEEN) { + if (monster.type().type == MT_UNSEEN) { if (GenerateRnd(2) != 0) md = Left(md); else @@ -3423,7 +3406,7 @@ void PrepareUniqueMonst(Monster &monster, int uniqindex, int miniontype, int bos if (uniqueMonsterData.mlevel != 0) { monster.mLevel = 2 * uniqueMonsterData.mlevel; } else { - monster.mLevel = monster.MData->mLevel + 5; + monster.mLevel = monster.data().mLevel + 5; } monster.mExp *= 2; @@ -3857,10 +3840,6 @@ int AddMonster(Point position, Direction dir, int mtype, bool inMap) void AddDoppelganger(Monster &monster) { - if (monster.MType == nullptr) { - return; - } - Point target = { 0, 0 }; for (int d = 0; d < 8; d++) { const Point position = monster.position.tile + static_cast(d); @@ -3870,7 +3849,7 @@ void AddDoppelganger(Monster &monster) } if (target != Point { 0, 0 }) { for (int j = 0; j < MaxLvlMTypes; j++) { - if (LevelMonsterTypes[j].type == monster.MType->type) { + if (LevelMonsterTypes[j].type == monster.type().type) { AddMonster(target, monster._mdir, j, true); break; } @@ -3886,7 +3865,7 @@ bool M_Talker(const Monster &monster) void M_StartStand(Monster &monster, Direction md) { ClearMVars(monster); - if (monster.MType->type == MT_GOLEM) + if (monster.type().type == MT_GOLEM) NewMonsterAnim(monster, MonsterGraphic::Walk, md); else NewMonsterAnim(monster, MonsterGraphic::Stand, md); @@ -3936,11 +3915,11 @@ void M_StartHit(int monsterId, int dam) PlayEffect(monster, 1); - if (IsAnyOf(monster.MType->type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { - if (monster.MType->type == MT_BLINK) { + if (IsAnyOf(monster.type().type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { + if (monster.type().type == MT_BLINK) { Teleport(monsterId); - } else if (IsAnyOf(monster.MType->type, MT_NSCAV, MT_BSCAV, MT_WSCAV, MT_YSCAV) - || monster.MType->type == MT_GRAVEDIG) { + } else if (IsAnyOf(monster.type().type, MT_NSCAV, MT_BSCAV, MT_WSCAV, MT_YSCAV) + || monster.type().type == MT_GRAVEDIG) { monster._mgoal = MGOAL_NORMAL; monster._mgoalvar1 = 0; monster._mgoalvar2 = 0; @@ -3960,7 +3939,7 @@ void M_StartHit(int monsterId, int pnum, int dam) delta_monster_hp(monsterId, monster._mhitpoints, *MyPlayer); NetSendCmdMonDmg(false, monsterId, dam); } - if (IsAnyOf(monster.MType->type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { + if (IsAnyOf(monster.type().type, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) { monster._menemy = pnum; monster.enemyPosition = Players[pnum].position.future; monster._mFlags &= ~MFLAG_TARGETS_MONSTER; @@ -4103,7 +4082,7 @@ void M_WalkDir(int monsterId, Direction md) { assert(monsterId >= 0 && monsterId < MaxMonsters); - int mwi = Monsters[monsterId].MType->getAnimData(MonsterGraphic::Walk).frames - 1; + int mwi = Monsters[monsterId].type().getAnimData(MonsterGraphic::Walk).frames - 1; switch (md) { case Direction::North: StartWalk(monsterId, 0, -MWVel[mwi][1], -1, -1, Direction::North); @@ -4242,10 +4221,10 @@ void ProcessMonsters() } if (IsTileVisible(monster.position.tile) && monster._msquelch == 0) { - if (monster.MType->type == MT_CLEAVER) { + if (monster.type().type == MT_CLEAVER) { PlaySFX(USFX_CLEAVER); } - if (monster.MType->type == MT_NAKRUL) { + if (monster.type().type == MT_NAKRUL) { if (sgGameInitInfo.bCowQuest != 0) { PlaySFX(USFX_NAKRUL6); } else { @@ -4255,7 +4234,7 @@ void ProcessMonsters() PlaySFX(USFX_NAKRUL5); } } - if (monster.MType->type == MT_DEFILER) + if (monster.type().type == MT_DEFILER) PlaySFX(USFX_DEFILER8); UpdateEnemy(monster); } @@ -4271,7 +4250,7 @@ void ProcessMonsters() if (IsTileVisible(monster.position.tile)) { monster._msquelch = UINT8_MAX; monster.position.last = player.position.future; - } else if (monster._msquelch != 0 && monster.MType->type != MT_DIABLO) { + } else if (monster._msquelch != 0 && monster.type().type != MT_DIABLO) { monster._msquelch--; } } @@ -4467,7 +4446,6 @@ bool LineClear(const std::function &clear, Point startPoint, Point void SyncMonsterAnim(Monster &monster) { - monster.MType = &LevelMonsterTypes[monster._mMTidx]; #ifdef _DEBUG // fix for saves with debug monsters having type originally not on the level if (LevelMonsterTypes[monster._mMTidx].data == nullptr) { @@ -4475,11 +4453,10 @@ void SyncMonsterAnim(Monster &monster) LevelMonsterTypes[monster._mMTidx].corpseId = 1; } #endif - monster.MData = LevelMonsterTypes[monster._mMTidx].data; if (monster._uniqtype != 0) monster.mName = pgettext("monster", UniqueMonstersData[monster._uniqtype - 1].mName).data(); else - monster.mName = pgettext("monster", monster.MData->mName).data(); + monster.mName = pgettext("monster", monster.data().mName).data(); if (monster._uniqtype != 0) InitTRNForUniqueMonster(monster); @@ -4539,7 +4516,7 @@ void M_FallenFear(Point position) if (monster._mAi != AI_FALLEN || monster._mhitpoints >> 6 <= 0) continue; - int runDistance = std::max((8 - monster.MData->mLevel), 2); + int runDistance = std::max((8 - monster.data().mLevel), 2); monster._mgoal = MGOAL_RETREAT; monster._mgoalvar1 = runDistance; monster._mgoalvar2 = static_cast(GetDirection(position, monster.position.tile)); @@ -4618,7 +4595,7 @@ void PrintUniqueHistory() { auto &monster = Monsters[pcursmonst]; if (*sgOptions.Gameplay.showMonsterType) { - AddPanelString(fmt::format(fmt::runtime(_("Type: {:s}")), GetMonsterTypeText(*monster.MData))); + AddPanelString(fmt::format(fmt::runtime(_("Type: {:s}")), GetMonsterTypeText(monster.data()))); } int res = monster.mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING); @@ -4680,7 +4657,7 @@ void MissToMonst(Missile &missile, Point position) else HitMonster(m, 0); - if (monster.MType->type == MT_GLOOM) + if (monster.type().type == MT_GLOOM) return; if ((monster._mFlags & MFLAG_TARGETS_MONSTER) == 0) { @@ -4690,7 +4667,7 @@ void MissToMonst(Missile &missile, Point position) int pnum = dPlayer[oldPosition.x][oldPosition.y] - 1; MonsterAttackPlayer(m, pnum, 500, monster.mMinDamage2, monster.mMaxDamage2); - if (IsAnyOf(monster.MType->type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) + if (IsAnyOf(monster.type().type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) return; Player &player = Players[pnum]; @@ -4713,7 +4690,7 @@ void MissToMonst(Missile &missile, Point position) int mid = dMonster[oldPosition.x][oldPosition.y] - 1; MonsterAttackMonster(m, mid, 500, monster.mMinDamage2, monster.mMaxDamage2); - if (IsAnyOf(monster.MType->type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) + if (IsAnyOf(monster.type().type, MT_NSNAKE, MT_RSNAKE, MT_BSNAKE, MT_GSNAKE)) return; Point newPosition = oldPosition + monster._mdir; @@ -4924,7 +4901,7 @@ bool Monster::IsImmune(missile_id mName) const || ((mMagicRes & IMMUNE_LIGHTNING) != 0 && missileElement == MISR_LIGHTNING) || ((mMagicRes & IMMUNE_ACID) != 0 && missileElement == MISR_ACID)) return true; - if (mName == MIS_HBOLT && MType->type != MT_DIABLO && MData->mMonstClass != MonsterClass::Undead) + if (mName == MIS_HBOLT && type().type != MT_DIABLO && data().mMonstClass != MonsterClass::Undead) return true; return false; } @@ -4937,7 +4914,7 @@ bool Monster::IsResistant(missile_id mName) const || ((mMagicRes & RESIST_FIRE) != 0 && missileElement == MISR_FIRE) || ((mMagicRes & RESIST_LIGHTNING) != 0 && missileElement == MISR_LIGHTNING)) return true; - if (gbIsHellfire && mName == MIS_HBOLT && IsAnyOf(MType->type, MT_DIABLO, MT_BONEDEMN)) + if (gbIsHellfire && mName == MIS_HBOLT && IsAnyOf(type().type, MT_DIABLO, MT_BONEDEMN)) return true; return false; } @@ -4946,9 +4923,9 @@ bool Monster::IsPossibleToHit() const { return !(_mhitpoints >> 6 <= 0 || mtalkmsg != TEXT_NONE - || (MType->type == MT_ILLWEAV && _mgoal == MGOAL_RETREAT) + || (type().type == MT_ILLWEAV && _mgoal == MGOAL_RETREAT) || _mmode == MonsterMode::Charge - || (IsAnyOf(MType->type, MT_COUNSLR, MT_MAGISTR, MT_CABALIST, MT_ADVOCATE) && _mgoal != MGOAL_NORMAL)); + || (IsAnyOf(type().type, MT_COUNSLR, MT_MAGISTR, MT_CABALIST, MT_ADVOCATE) && _mgoal != MGOAL_NORMAL)); } bool Monster::TryLiftGargoyle() diff --git a/Source/monster.h b/Source/monster.h index 8e9e520da..8b09ad77b 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -165,10 +165,10 @@ struct CMonster { const MonsterData *data; }; +extern CMonster LevelMonsterTypes[MaxLvlMTypes]; + struct Monster { // note: missing field _mAFNum const char *mName; - CMonster *MType; - const MonsterData *MData; std::unique_ptr uniqueTRN; AnimationInfo AnimInfo; int _mgoalvar1; @@ -233,7 +233,7 @@ struct Monster { // note: missing field _mAFNum */ void ChangeAnimationData(MonsterGraphic graphic, Direction direction) { - auto &animationData = this->MType->getAnimData(graphic); + auto &animationData = type().getAnimData(graphic); // Passing the Frames and rate properties here is only relevant when initialising a monster, but doesn't cause any harm when switching animations. this->AnimInfo.ChangeAnimationData(animationData.getCelSpritesForDirection(direction), animationData.frames, animationData.rate); @@ -259,6 +259,16 @@ struct Monster { // note: missing field _mAFNum */ void Petrify(); + const CMonster &type() const + { + return LevelMonsterTypes[_mMTidx]; + } + + const MonsterData &data() const + { + return *type().data; + } + /** * @brief Is the monster currently walking? */ @@ -269,7 +279,6 @@ struct Monster { // note: missing field _mAFNum bool TryLiftGargoyle(); }; -extern CMonster LevelMonsterTypes[MaxLvlMTypes]; extern int LevelMonsterTypeCount; extern Monster Monsters[MaxMonsters]; extern int ActiveMonsters[MaxMonsters]; diff --git a/Source/msg.cpp b/Source/msg.cpp index 7b90de820..fd9a067b7 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -2417,8 +2417,7 @@ void DeltaLoadLevel() M_ClearSquares(i); if (monster._mAi != AI_DIABLO) { if (monster._uniqtype == 0) { - assert(monster.MType != nullptr); - AddCorpse(monster.position.tile, monster.MType->corpseId, monster._mdir); + AddCorpse(monster.position.tile, monster.type().corpseId, monster._mdir); } else { AddCorpse(monster.position.tile, monster._udeadval, monster._mdir); } @@ -2429,7 +2428,7 @@ void DeltaLoadLevel() decode_enemy(monster, deltaLevel.monster[i]._menemy); if (monster.position.tile != Point { 0, 0 } && monster.position.tile != GolemHoldingCell) dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; - if (monster.MType->type == MT_GOLEM) { + if (monster.type().type == MT_GOLEM) { GolumAi(i); monster._mFlags |= (MFLAG_TARGETS_MONSTER | MFLAG_GOLEM); } else { diff --git a/Source/player.cpp b/Source/player.cpp index f71b0706a..1c04e0601 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -868,7 +868,7 @@ bool PlrHitMonst(int pnum, int m, bool adjacentDamage = false) phanditype = ItemType::Mace; } - switch (monster.MData->mMonstClass) { + switch (monster.data().mMonstClass) { case MonsterClass::Undead: if (phanditype == ItemType::Sword) { dam -= dam / 2; @@ -894,7 +894,7 @@ bool PlrHitMonst(int pnum, int m, bool adjacentDamage = false) dam *= 3; } - if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::Doppelganger) && monster.MType->type != MT_DIABLO && monster._uniqtype == 0 && GenerateRnd(100) < 10) { + if (HasAnyOf(player.pDamAcFlags, ItemSpecialEffectHf::Doppelganger) && monster.type().type != MT_DIABLO && monster._uniqtype == 0 && GenerateRnd(100) < 10) { AddDoppelganger(monster); } @@ -3193,7 +3193,7 @@ void RemovePlrMissiles(int pnum) auto &golem = Monsters[MyPlayerId]; if (golem.position.tile.x != 1 || golem.position.tile.y != 0) { M_StartKill(MyPlayerId, MyPlayerId); - AddCorpse(golem.position.tile, golem.MType->corpseId, golem._mdir); + AddCorpse(golem.position.tile, golem.type().corpseId, golem._mdir); int mx = golem.position.tile.x; int my = golem.position.tile.y; dMonster[mx][my] = 0; diff --git a/Source/qol/monhealthbar.cpp b/Source/qol/monhealthbar.cpp index f96a573f1..801ee1621 100644 --- a/Source/qol/monhealthbar.cpp +++ b/Source/qol/monhealthbar.cpp @@ -122,7 +122,7 @@ void DrawMonsterHealthBar(const Surface &out) }; if (*sgOptions.Gameplay.showMonsterType) { - Uint8 borderColor = getBorderColor(monster.MData->mMonstClass); + Uint8 borderColor = getBorderColor(monster.data().mMonstClass); int borderWidth = width - (border * 2); UnsafeDrawHorizontalLine(out, { position.x + border, position.y + border }, borderWidth, borderColor); UnsafeDrawHorizontalLine(out, { position.x + border, position.y + height - border - 1 }, borderWidth, borderColor); @@ -143,7 +143,7 @@ void DrawMonsterHealthBar(const Surface &out) if (multiplier > 0) DrawString(out, fmt::format("x{:d}", multiplier), { position, { width - 2, height } }, UiFlags::ColorWhite | UiFlags::AlignRight | UiFlags::VerticalCenter); - if (monster._uniqtype != 0 || MonsterKillCounts[monster.MType->type] >= 15) { + if (monster._uniqtype != 0 || MonsterKillCounts[monster.type().type] >= 15) { monster_resistance immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING }; monster_resistance resists[] = { RESIST_MAGIC, RESIST_FIRE, RESIST_LIGHTNING }; diff --git a/Source/quests.cpp b/Source/quests.cpp index 80b383b93..b0cfe8fa2 100644 --- a/Source/quests.cpp +++ b/Source/quests.cpp @@ -405,14 +405,14 @@ void CheckQuestKill(const Monster &monster, bool sendmsg) Player &myPlayer = *MyPlayer; - if (monster.MType->type == MT_SKING) { + if (monster.type().type == MT_SKING) { auto &quest = Quests[Q_SKELKING]; quest._qactive = QUEST_DONE; myPlayer.Say(HeroSpeech::RestWellLeoricIllFindYourSon, 30); if (sendmsg) NetSendCmdQuest(true, quest); - } else if (monster.MType->type == MT_CLEAVER) { + } else if (monster.type().type == MT_CLEAVER) { auto &quest = Quests[Q_BUTCHER]; quest._qactive = QUEST_DONE; myPlayer.Say(HeroSpeech::TheSpiritsOfTheDeadAreNowAvenged, 30);