Browse Source

Monster: Remove MType/MData pointers

These pointers are redundant, replaces them with methods.
pull/4820/head
Gleb Mazovetskiy 4 years ago
parent
commit
6949a6f418
  1. 2
      Source/control.cpp
  2. 28
      Source/cursor.cpp
  3. 2
      Source/dead.cpp
  4. 2
      Source/debug.cpp
  5. 5
      Source/engine/render/scrollrt.cpp
  6. 18
      Source/items.cpp
  7. 4
      Source/loadsave.cpp
  8. 46
      Source/missiles.cpp
  9. 189
      Source/monster.cpp
  10. 17
      Source/monster.h
  11. 5
      Source/msg.cpp
  12. 6
      Source/player.cpp
  13. 4
      Source/qol/monhealthbar.cpp
  14. 4
      Source/quests.cpp

2
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);

28
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;
}

2
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++;

2
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;
}

5
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;

18
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;

4
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<int8_t>(monster.mlid);
// Omit pointer mName;
// Omit pointer MType;
// Omit pointer data;
}
void SaveMissile(SaveHelper *file, const Missile &missile)

46
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 &parameter)
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 &parameter)
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 &parameter)
void AddMisexp(Missile &missile, const AddMissileParameter &parameter)
{
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 &parameter)
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<int32_t>(midir);
mis._miAnimFlags = MissileDataFlags::None;
CelSprite celSprite = *anim.getCelSpritesForDirection(midir);
@ -2038,14 +2038,14 @@ void AddRhino(Missile &missile, const AddMissileParameter &parameter)
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 &parameter)
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 &parameter)
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];
}
}

189
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<missile_id>(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<Direction>(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<bool(Point)> &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<int>(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()

17
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<uint8_t[]> 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];

5
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 {

6
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;

4
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 };

4
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);

Loading…
Cancel
Save