Browse Source

Use scoped enum for Direction

Identified and removed an instance of Direction being used as an argument for a bool parameter

Removed a single-use temporary variable being cast from sprite frame to direction to size_t

Co-authored-by: Anders Jenbo <anders@jenbo.dk>

Fix alignment of WalkSettings array
pull/2845/head
ephphatha 5 years ago committed by Anders Jenbo
parent
commit
b12de6fe12
  1. 20
      Source/automap.cpp
  2. 40
      Source/controls/plrctrls.cpp
  3. 2
      Source/dead.cpp
  4. 20
      Source/engine.cpp
  5. 40
      Source/engine/direction.hpp
  6. 32
      Source/engine/displacement.hpp
  7. 8
      Source/inv.cpp
  8. 4
      Source/items.cpp
  9. 8
      Source/loadsave.cpp
  10. 56
      Source/missiles.cpp
  11. 17
      Source/missiles.h
  12. 223
      Source/monster.cpp
  13. 24
      Source/monster.h
  14. 6
      Source/msg.cpp
  15. 4
      Source/multi.cpp
  16. 62
      Source/objects.cpp
  17. 8
      Source/path.cpp
  18. 16
      Source/path.h
  19. 74
      Source/player.cpp
  20. 2
      Source/portal.cpp
  21. 14
      Source/quests.cpp
  22. 43
      Source/scrollrt.cpp
  23. 2
      Source/spells.cpp
  24. 2
      Source/themes.cpp
  25. 52
      Source/towners.cpp
  26. 5
      Source/towners.h
  27. 8
      test/dead_test.cpp
  28. 148
      test/missiles_test.cpp
  29. 22
      test/path_test.cpp
  30. 2
      test/player_test.cpp

20
Source/automap.cpp

@ -264,7 +264,7 @@ void SearchAutomapItem(const Surface &out, const Displacement &myPlayerOffset)
Point tile = myPlayer.position.tile;
if (myPlayer._pmode == PM_WALK3) {
tile = myPlayer.position.future;
if (myPlayer._pdir == DIR_W)
if (myPlayer._pdir == Direction::West)
tile.x++;
else
tile.y++;
@ -312,7 +312,7 @@ void DrawAutomapPlr(const Surface &out, const Displacement &myPlayerOffset, int
Point tile = player.position.tile;
if (player._pmode == PM_WALK3) {
tile = player.position.future;
if (player._pdir == DIR_W)
if (player._pdir == Direction::West)
tile.x++;
else
tile.y++;
@ -339,49 +339,49 @@ void DrawAutomapPlr(const Surface &out, const Displacement &myPlayerOffset, int
base.y -= AmLine8;
switch (player._pdir) {
case DIR_N: {
case Direction::North: {
const Point point { base.x, base.y - AmLine16 };
DrawVerticalLine(out, point, AmLine16, playerColor);
DrawMapLineSteepNE(out, { point.x - AmLine4, point.y + 2 * AmLine4 }, AmLine4, playerColor);
DrawMapLineSteepNW(out, { point.x + AmLine4, point.y + 2 * AmLine4 }, AmLine4, playerColor);
} break;
case DIR_NE: {
case Direction::NorthEast: {
const Point point { base.x + AmLine16, base.y - AmLine8 };
DrawHorizontalLine(out, { point.x - AmLine8, point.y }, AmLine8, playerColor);
DrawMapLineNE(out, { point.x - 2 * AmLine8, point.y + AmLine8 }, AmLine8, playerColor);
DrawMapLineSteepSW(out, point, AmLine4, playerColor);
} break;
case DIR_E: {
case Direction::East: {
const Point point { base.x + AmLine16, base.y };
DrawMapLineNW(out, point, AmLine4, playerColor);
DrawHorizontalLine(out, { point.x - AmLine16, point.y }, AmLine16, playerColor);
DrawMapLineSW(out, point, AmLine4, playerColor);
} break;
case DIR_SE: {
case Direction::SouthEast: {
const Point point { base.x + AmLine16, base.y + AmLine8 };
DrawMapLineSE(out, { point.x - 2 * AmLine8, point.y - AmLine8 }, AmLine8, playerColor);
DrawHorizontalLine(out, { point.x - (AmLine8 + 1), point.y }, AmLine8 + 1, playerColor);
DrawMapLineSteepNW(out, point, AmLine4, playerColor);
} break;
case DIR_S: {
case Direction::South: {
const Point point { base.x, base.y + AmLine16 };
DrawVerticalLine(out, { point.x, point.y - AmLine16 }, AmLine16, playerColor);
DrawMapLineSteepSW(out, { point.x + AmLine4, point.y - 2 * AmLine4 }, AmLine4, playerColor);
DrawMapLineSteepSE(out, { point.x - AmLine4, point.y - 2 * AmLine4 }, AmLine4, playerColor);
} break;
case DIR_SW: {
case Direction::SouthWest: {
const Point point { base.x - AmLine16, base.y + AmLine8 };
DrawMapLineSteepNE(out, point, AmLine4, playerColor);
DrawMapLineSW(out, { point.x + 2 * AmLine8, point.y - AmLine8 }, AmLine8, playerColor);
DrawHorizontalLine(out, point, AmLine8 + 1, playerColor);
} break;
case DIR_W: {
case Direction::West: {
const Point point { base.x - AmLine16, base.y };
DrawMapLineNE(out, point, AmLine4, playerColor);
DrawHorizontalLine(out, point, AmLine16 + 1, playerColor);
DrawMapLineSE(out, point, AmLine4, playerColor);
} break;
case DIR_NW: {
case Direction::NorthWest: {
const Point point { base.x - AmLine16, base.y - AmLine8 };
DrawMapLineNW(out, { point.x + 2 * AmLine8, point.y + AmLine8 }, AmLine8, playerColor);
DrawHorizontalLine(out, point, AmLine8 + 1, playerColor);

40
Source/controls/plrctrls.cpp

@ -59,8 +59,8 @@ int GetRotaryDistance(Point destination)
if (myPlayer.position.future == destination)
return -1;
int d1 = myPlayer._pdir;
int d2 = GetDirection(myPlayer.position.future, destination);
int d1 = static_cast<int>(myPlayer._pdir);
int d2 = static_cast<int>(GetDirection(myPlayer.position.future, destination));
int d = abs(d1 - d2);
if (d > 4)
@ -1006,10 +1006,10 @@ void SpellBookMove(AxisDirection dir)
}
const Direction FaceDir[3][3] = {
// NONE UP DOWN
{ DIR_S, DIR_N, DIR_S }, // NONE
{ DIR_W, DIR_NW, DIR_SW }, // LEFT
{ DIR_E, DIR_NE, DIR_SE }, // RIGHT
// NONE UP DOWN
{ Direction::South, Direction::North, Direction::South }, // NONE
{ Direction::West, Direction::NorthWest, Direction::SouthWest }, // LEFT
{ Direction::East, Direction::NorthEast, Direction::SouthEast }, // RIGHT
};
/**
@ -1028,21 +1028,21 @@ bool IsPathBlocked(Point position, Direction dir)
Direction d2;
switch (dir) {
case DIR_N:
d1 = DIR_NW;
d2 = DIR_NE;
case Direction::North:
d1 = Direction::NorthWest;
d2 = Direction::NorthEast;
break;
case DIR_E:
d1 = DIR_NE;
d2 = DIR_SE;
case Direction::East:
d1 = Direction::NorthEast;
d2 = Direction::SouthEast;
break;
case DIR_S:
d1 = DIR_SE;
d2 = DIR_SW;
case Direction::South:
d1 = Direction::SouthEast;
d2 = Direction::SouthWest;
break;
case DIR_W:
d1 = DIR_SW;
d2 = DIR_NW;
case Direction::West:
d1 = Direction::SouthWest;
d2 = Direction::NorthWest;
break;
default:
return false;
@ -1415,10 +1415,10 @@ bool TryDropItem()
{
const auto &myPlayer = Players[MyPlayerId];
cursPosition = myPlayer.position.future + DIR_SE;
cursPosition = myPlayer.position.future + Direction::SouthEast;
if (!DropItemBeforeTrig()) {
// Try to drop on the other side
cursPosition = myPlayer.position.future + DIR_SW;
cursPosition = myPlayer.position.future + Direction::SouthWest;
DropItemBeforeTrig();
}

2
Source/dead.cpp

@ -73,7 +73,7 @@ void InitCorpses()
void AddCorpse(Point tilePosition, int8_t dv, Direction ddir)
{
dCorpse[tilePosition.x][tilePosition.y] = (dv & 0x1F) + (ddir << 5);
dCorpse[tilePosition.x][tilePosition.y] = (dv & 0x1F) + (static_cast<int>(ddir) << 5);
}
void SyncUniqDead()

20
Source/engine.cpp

@ -148,30 +148,30 @@ Direction GetDirection(Point start, Point destination)
if (mx >= 0) {
if (my >= 0) {
if (5 * mx <= (my * 2)) // mx/my <= 0.4, approximation of tan(22.5)
return DIR_SW;
md = DIR_S;
return Direction::SouthWest;
md = Direction::South;
} else {
my = -my;
if (5 * mx <= (my * 2))
return DIR_NE;
md = DIR_E;
return Direction::NorthEast;
md = Direction::East;
}
if (5 * my <= (mx * 2)) // my/mx <= 0.4
md = DIR_SE;
md = Direction::SouthEast;
} else {
mx = -mx;
if (my >= 0) {
if (5 * mx <= (my * 2))
return DIR_SW;
md = DIR_W;
return Direction::SouthWest;
md = Direction::West;
} else {
my = -my;
if (5 * mx <= (my * 2))
return DIR_NE;
md = DIR_N;
return Direction::NorthEast;
md = Direction::North;
}
if (5 * my <= (mx * 2))
md = DIR_NW;
md = Direction::NorthWest;
}
return md;
}

40
Source/engine/direction.hpp

@ -1,18 +1,40 @@
#pragma once
#include <cstdint>
#include <type_traits>
namespace devilution {
enum Direction : std::uint8_t {
DIR_S,
DIR_SW,
DIR_W,
DIR_NW,
DIR_N,
DIR_NE,
DIR_E,
DIR_SE,
enum class Direction : std::uint8_t {
South,
SouthWest,
West,
NorthWest,
North,
NorthEast,
East,
SouthEast,
};
/** Maps from direction to a left turn from the direction. */
constexpr Direction Left(Direction facing)
{
//Direction left[8] = { Direction::SouthEast, Direction::South, Direction::SouthWest, Direction::West, Direction::NorthWest, Direction::North, Direction::NorthEast, Direction::East };
return static_cast<Direction>((static_cast<std::underlying_type_t<Direction>>(facing) + 7) % 8);
}
/** Maps from direction to a right turn from the direction. */
constexpr Direction Right(Direction facing)
{
//Direction right[8] = { Direction::SouthWest, Direction::West, Direction::NorthWest, Direction::North, Direction::NorthEast, Direction::East, Direction::SouthEast, Direction::South };
return static_cast<Direction>((static_cast<std::underlying_type_t<Direction>>(facing) + 1) % 8);
}
/** Maps from direction to the opposite direction. */
constexpr Direction Opposite(Direction facing)
{
//Direction opposite[8] = { Direction::North, Direction::NorthEast, Direction::East, Direction::SouthEast, Direction::South, Direction::SouthWest, Direction::West, Direction::NorthWest };
return static_cast<Direction>((static_cast<std::underlying_type_t<Direction>>(facing) + 4) % 8);
}
} // namespace devilution

32
Source/engine/displacement.hpp

@ -103,25 +103,41 @@ struct Displacement {
return { abs(a.deltaX), abs(a.deltaY) };
}
/**
* @brief Returns a new Displacement object in screen coordinates.
*
* Transforming from world space to screen space involves a rotation of -135° and scaling to fit within a 64x32 pixel tile (since Diablo uses isometric projection)
* 32 and 16 are used as the x/y scaling factors being half the relevant max dimension, the rotation matrix is [[-, +], [-, -]] as sin(-135°) = cos(-135°) = ~-0.7.
*
* [-32, 32] [dx] = [-32dx + 32dy] = [ 32dy - 32dx ] = [ 32(dy - dx)]
* [-16, -16] [dy] = [-16dx + -16dy] = [-(16dy + 16dx)] = [-16(dy + dx)]
*
* @return A representation of the original displacement in screen coordinates.
*/
constexpr Displacement WorldToScreen() const
{
return { (deltaY - deltaX) * 32, (deltaY + deltaX) * -16 };
}
private:
static constexpr Displacement fromDirection(Direction direction)
{
switch (direction) {
case DIR_S:
case Direction::South:
return { 1, 1 };
case DIR_SW:
case Direction::SouthWest:
return { 0, 1 };
case DIR_W:
case Direction::West:
return { -1, 1 };
case DIR_NW:
case Direction::NorthWest:
return { -1, 0 };
case DIR_N:
case Direction::North:
return { -1, -1 };
case DIR_NE:
case Direction::NorthEast:
return { 0, -1 };
case DIR_E:
case Direction::East:
return { 1, -1 };
case DIR_SE:
case Direction::SouthEast:
return { 1, 0 };
default:
return { 0, 0 };

8
Source/inv.cpp

@ -1024,11 +1024,11 @@ bool PutItem(Player &player, Point &position)
if (CanPut(position))
return true;
position = player.position.tile + left[d];
position = player.position.tile + Left(d);
if (CanPut(position))
return true;
position = player.position.tile + right[d];
position = player.position.tile + Right(d);
if (CanPut(position))
return true;
@ -1711,11 +1711,11 @@ bool TryInvPut()
return true;
}
if (CanPut(myPlayer.position.tile + left[dir])) {
if (CanPut(myPlayer.position.tile + Left(dir))) {
return true;
}
if (CanPut(myPlayer.position.tile + right[dir])) {
if (CanPut(myPlayer.position.tile + Right(dir))) {
return true;
}

4
Source/items.cpp

@ -2966,10 +2966,10 @@ void CalcPlrItemVals(Player &player, bool loadgfx)
SetPlrAnims(player);
if (player._pmode == PM_STAND) {
LoadPlrGFX(player, player_graphic::Stand);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Stand)].CelSpritesForDirections[player._pdir], player._pNFrames, 4);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Stand)].CelSpritesForDirections[static_cast<size_t>(player._pdir)], player._pNFrames, 4);
} else {
LoadPlrGFX(player, player_graphic::Walk);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Walk)].CelSpritesForDirections[player._pdir], player._pWFrames, 1);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Walk)].CelSpritesForDirections[static_cast<size_t>(player._pdir)], player._pWFrames, 1);
}
} else {
player._pgfxnum = gfxNum;

8
Source/loadsave.cpp

@ -976,7 +976,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(player.destAction);
file.WriteLE<int32_t>(player.destParam1);
file.WriteLE<int32_t>(player.destParam2);
file.WriteLE<int32_t>(player.destParam3);
file.WriteLE<int32_t>(static_cast<int32_t>(player.destParam3));
file.WriteLE<int32_t>(player.destParam4);
file.WriteLE<int32_t>(player.plrlevel);
file.WriteLE<int32_t>(player.position.tile.x);
@ -997,7 +997,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(player.position.offset.deltaY);
file.WriteLE<int32_t>(player.position.velocity.deltaX);
file.WriteLE<int32_t>(player.position.velocity.deltaY);
file.WriteLE<int32_t>(player._pdir);
file.WriteLE<int32_t>(static_cast<int32_t>(player._pdir));
file.Skip(4); // Unused
file.WriteLE<int32_t>(player._pgfxnum);
file.Skip(4); // Skip pointer _pAnimData
@ -1089,7 +1089,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<uint32_t>(player._pInfraFlag ? 1 : 0);
file.WriteLE<int32_t>(player.position.temp.x);
file.WriteLE<int32_t>(player.position.temp.y);
file.WriteLE<int32_t>(player.tempDirection);
file.WriteLE<int32_t>(static_cast<int32_t>(player.tempDirection));
file.WriteLE<int32_t>(player._pVar4);
file.WriteLE<int32_t>(player._pVar5);
file.WriteLE<int32_t>(player.position.offset2.deltaX);
@ -1220,7 +1220,7 @@ void SaveMonster(SaveHelper *file, Monster &monster)
file->WriteLE<int32_t>(monster.position.offset.deltaY);
file->WriteLE<int32_t>(monster.position.velocity.deltaX);
file->WriteLE<int32_t>(monster.position.velocity.deltaY);
file->WriteLE<int32_t>(monster._mdir);
file->WriteLE<int32_t>(static_cast<int32_t>(monster._mdir));
file->WriteLE<int32_t>(monster._menemy);
file->WriteLE<uint8_t>(monster.enemyPosition.x);
file->WriteLE<uint8_t>(monster.enemyPosition.y);

56
Source/missiles.cpp

@ -170,20 +170,20 @@ void MoveMissilePos(Missile &missile)
Displacement offset;
switch (missile._mimfnum) {
case DIR_NW:
case DIR_N:
case DIR_NE:
case Direction::NorthWest:
case Direction::North:
case Direction::NorthEast:
offset = { 0, 0 };
break;
case DIR_E:
case Direction::East:
offset = { 1, 0 };
break;
case DIR_W:
case Direction::West:
offset = { 0, 1 };
break;
case DIR_S:
case DIR_SW:
case DIR_SE:
case Direction::South:
case Direction::SouthWest:
case Direction::SouthEast:
offset = { 1, 1 };
break;
}
@ -835,7 +835,7 @@ void SpawnLightning(Missile &missile, int dam)
AddMissile(
position,
missile.position.start,
DIR_S,
Direction::South,
type,
missile._micaster,
missile._misource,
@ -1429,7 +1429,7 @@ void AddHorkSpawn(Missile &missile, Point dst, Direction midir)
{
UpdateMissileVelocity(missile, dst, 8);
missile._mirange = 9;
missile.var1 = midir;
missile.var1 = static_cast<int32_t>(midir);
PutMissile(missile);
}
@ -1780,7 +1780,7 @@ void AddCboltArrow(Missile &missile, Point dst, Direction midir)
missile._mlid = AddLight(missile.position.start, 5);
UpdateMissileVelocity(missile, dst, 8);
missile.var1 = 5;
missile.var2 = midir;
missile.var2 = static_cast<int32_t>(midir);
missile._mirange = 256;
}
@ -2280,9 +2280,9 @@ namespace {
void InitMissileAnimationFromMonster(Missile &mis, Direction midir, const Monster &mon, MonsterGraphic graphic)
{
const AnimStruct &anim = mon.MType->GetAnimData(graphic);
mis._mimfnum = midir;
mis._mimfnum = static_cast<int32_t>(midir);
mis._miAnimFlags = MissileDataFlags::None;
const auto &celSprite = *anim.CelSpritesForDirections[midir];
const auto &celSprite = *anim.CelSpritesForDirections[mis._mimfnum];
mis._miAnimData = celSprite.Data();
mis._miAnimDelay = anim.Rate;
mis._miAnimLen = anim.Frames;
@ -2596,8 +2596,8 @@ void AddFirewallC(Missile &missile, Point dst, Direction midir)
}
if (!missile._miDelFlag) {
missile.var3 = left[left[midir]];
missile.var4 = right[right[midir]];
missile.var3 = static_cast<int>(Left(Left(midir)));
missile.var4 = static_cast<int>(Right(Right(midir)));
missile._mirange = 7;
UseMana(missile._misource, SPL_FIREWALL);
}
@ -2774,7 +2774,7 @@ void AddCbolt(Missile &missile, Point dst, Direction midir)
UpdateMissileVelocity(missile, dst, 8);
missile.var1 = 5;
missile.var2 = midir;
missile.var2 = static_cast<int>(midir);
missile._mirange = 256;
}
@ -2860,7 +2860,7 @@ void AddDiabApoca(Missile &missile, Point /*dst*/, Direction /*midir*/)
if (!LineClearMissile(missile.position.start, player.position.future))
continue;
AddMissile({ 0, 0 }, player.position.future, DIR_S, MIS_BOOM2, missile._micaster, missile._misource, missile._midam, 0);
AddMissile({ 0, 0 }, player.position.future, Direction::South, MIS_BOOM2, missile._micaster, missile._misource, missile._midam, 0);
}
missile._miDelFlag = true;
}
@ -3340,7 +3340,7 @@ void MI_FireRing(Missile &missile)
continue;
}
AddMissile(target, target, DIR_S, MIS_FIREWALL, TARGET_BOTH, src, dmg, missile._mispllvl);
AddMissile(target, target, Direction::South, MIS_FIREWALL, TARGET_BOTH, src, dmg, missile._mispllvl);
}
}
@ -3400,7 +3400,7 @@ void MI_FireNova(Missile &missile)
int id = missile._misource;
int dam = missile._midam;
Point src = missile.position.tile;
Direction dir = DIR_S;
Direction dir = Direction::South;
mienemy_type en = TARGET_PLAYERS;
if (id != -1) {
dir = Players[id]._pdir;
@ -3428,7 +3428,7 @@ void MI_SpecArrow(Missile &missile)
Point dst = { missile.var1, missile.var2 };
int spllvl = missile.var3;
missile_id mitype = MIS_ARROW;
Direction dir = DIR_S;
Direction dir = Direction::South;
mienemy_type micaster = TARGET_PLAYERS;
if (id != -1) {
auto &player = Players[id];
@ -3598,7 +3598,7 @@ void MI_Firemove(Missile &missile)
ChangeLight(missile._mlid, missile.position.tile, ExpLight[missile.var2]);
missile.var2++;
}
missile.position.tile += DIR_S;
missile.position.tile += Direction::South;
missile.position.offset.deltaY -= 32;
PutMissile(missile);
}
@ -3750,7 +3750,7 @@ void MI_Acidsplat(Missile &missile)
missile._miDelFlag = true;
int monst = missile._misource;
int dam = (Monsters[monst].MData->mLevel >= 2 ? 2 : 1);
AddMissile(missile.position.tile, { 0, 0 }, DIR_S, MIS_ACIDPUD, TARGET_PLAYERS, monst, dam, missile._mispllvl);
AddMissile(missile.position.tile, { 0, 0 }, Direction::South, MIS_ACIDPUD, TARGET_PLAYERS, monst, dam, missile._mispllvl);
} else {
PutMissile(missile);
}
@ -3945,8 +3945,8 @@ void MI_Wave(Missile &missile)
int id = missile._misource;
Point src = missile.position.tile;
Direction sd = GetDirection(src, { missile.var1, missile.var2 });
Direction dira = left[left[sd]];
Direction dirb = right[right[sd]];
Direction dira = Left(Left(sd));
Direction dirb = Right(Right(sd));
Point na = src + sd;
int pn = dPiece[na.x][na.y];
assert(pn >= 0 && pn <= MAXTILES);
@ -3987,7 +3987,7 @@ void MI_Nova(Missile &missile)
int id = missile._misource;
int dam = missile._midam;
Point src = missile.position.tile;
Direction dir = DIR_S;
Direction dir = Direction::South;
mienemy_type en = TARGET_PLAYERS;
if (id != -1) {
dir = Players[id]._pdir;
@ -4075,7 +4075,7 @@ void MI_Flamec(Missile &missile)
AddMissile(
missile.position.tile,
missile.position.start,
DIR_S,
Direction::South,
MIS_FLAME,
missile._micaster,
src,
@ -4103,10 +4103,10 @@ void MI_Cbolt(Missile &missile)
auto md = static_cast<Direction>(missile.var2);
switch (BPath[missile._mirnd]) {
case -1:
md = left[md];
md = Left(md);
break;
case 1:
md = right[md];
md = Right(md);
break;
}

17
Source/missiles.h

@ -142,7 +142,24 @@ Direction16 GetDirection16(Point p1, Point p2);
void DeleteMissile(int i);
bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, missile_id t, bool shift);
bool PlayerMHit(int pnum, Monster *monster, int dist, int mind, int maxd, missile_id mtype, bool shift, int earflag, bool *blocked);
/**
* @brief Sets the missile sprite to represent the direction of travel
* @param missile this object
* @param dir Sprite frame representing the desired facing
*/
void SetMissDir(Missile &missile, int dir);
/**
* @brief Overload to convert a Direction value to the appropriate sprite frame
* @param missile this object
* @param dir Desired facing
*/
inline void SetMissDir(Missile &missile, Direction dir)
{
SetMissDir(missile, static_cast<int>(dir));
}
void InitMissiles();
void AddHiveExplosion(Missile &missile, Point dst, Direction midir);
void AddFireRune(Missile &missile, Point dst, Direction midir);

223
Source/monster.cpp

@ -49,13 +49,6 @@ int ActiveMonsterCount;
int MonsterKillCounts[MAXMONSTERS];
bool sgbSaveSoundOn;
/** Maps from direction to a left turn from the direction. */
Direction left[8] = { DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_N, DIR_NE, DIR_E };
/** Maps from direction to a right turn from the direction. */
Direction right[8] = { DIR_SW, DIR_W, DIR_NW, DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S };
/** Maps from direction to the opposite direction. */
Direction opposite[8] = { DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW };
namespace {
#define NIGHTMARE_TO_HIT_BONUS 85
@ -160,29 +153,26 @@ void InitMonsterTRN(CMonster &monst)
void InitMonster(Monster &monster, Direction rd, int mtype, Point position)
{
auto &monsterType = LevelMonsterTypes[mtype];
const auto &animData = monsterType.GetAnimData(MonsterGraphic::Stand);
monster._mdir = rd;
monster.position.tile = position;
monster.position.future = position;
monster.position.old = position;
monster._mMTidx = mtype;
monster._mmode = MonsterMode::Stand;
monster.mName = _(monsterType.MData->mName);
monster.MType = &monsterType;
monster.MData = monsterType.MData;
monster.MType = &LevelMonsterTypes[mtype];
monster.MData = monster.MType->MData;
monster.mName = _(monster.MData->mName);
monster.AnimInfo = {};
monster.AnimInfo.pCelSprite = animData.CelSpritesForDirections[rd] ? &*animData.CelSpritesForDirections[rd] : nullptr;
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
const auto &animData = monster.MType->GetAnimData(MonsterGraphic::Stand);
monster.AnimInfo.TicksPerFrame = animData.Rate;
monster.AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(monster.AnimInfo.TicksPerFrame - 1);
monster.AnimInfo.NumberOfFrames = animData.Frames;
monster.AnimInfo.CurrentFrame = GenerateRnd(monster.AnimInfo.NumberOfFrames - 1) + 1;
monster.mLevel = monsterType.MData->mLevel;
monster._mmaxhp = (monsterType.mMinHP + GenerateRnd(monsterType.mMaxHP - monsterType.mMinHP + 1)) << 6;
if (monsterType.mtype == MT_DIABLO && !gbIsHellfire) {
monster.mLevel = monster.MData->mLevel;
monster._mmaxhp = (monster.MType->mMinHP + GenerateRnd(monster.MType->mMaxHP - monster.MType->mMinHP + 1)) << 6;
if (monster.MType->mtype == MT_DIABLO && !gbIsHellfire) {
monster._mmaxhp /= 2;
monster.mLevel -= 15;
}
@ -191,8 +181,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 = monsterType.MData->mAi;
monster._mint = monsterType.MData->mInt;
monster._mAi = monster.MData->mAi;
monster._mint = monster.MData->mInt;
monster._mgoal = MGOAL_NORMAL;
monster._mgoalvar1 = 0;
monster._mgoalvar2 = 0;
@ -205,22 +195,22 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position)
monster._mRndSeed = AdvanceRndSeed();
monster._mAISeed = AdvanceRndSeed();
monster.mWhoHit = 0;
monster.mExp = monsterType.MData->mExp;
monster.mHit = monsterType.MData->mHit;
monster.mMinDamage = monsterType.MData->mMinDamage;
monster.mMaxDamage = monsterType.MData->mMaxDamage;
monster.mHit2 = monsterType.MData->mHit2;
monster.mMinDamage2 = monsterType.MData->mMinDamage2;
monster.mMaxDamage2 = monsterType.MData->mMaxDamage2;
monster.mArmorClass = monsterType.MData->mArmorClass;
monster.mMagicRes = monsterType.MData->mMagicRes;
monster.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.leader = 0;
monster.leaderRelation = LeaderRelation::None;
monster._mFlags = monsterType.MData->mFlags;
monster._mFlags = monster.MData->mFlags;
monster.mtalkmsg = TEXT_NONE;
if (monster._mAi == AI_GARG) {
monster.AnimInfo.pCelSprite = &*monsterType.GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[rd];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Special);
monster.AnimInfo.CurrentFrame = 1;
monster._mFlags |= MFLAG_ALLOW_SPECIAL;
monster._mmode = MonsterMode::SpecialMeleeAttack;
@ -258,7 +248,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 += HELL_AC_BONUS;
monster.mMagicRes = monsterType.MData->mMagicRes2;
monster.mMagicRes = monster.MData->mMagicRes2;
}
}
@ -361,7 +351,7 @@ void PlaceGroup(int mtype, int num, UniqueMonsterPack uniqueMonsterPack, int lea
}
if (minion._mAi != AI_GARG) {
minion.AnimInfo.pCelSprite = &*minion.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[minion._mdir];
minion.ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
minion.AnimInfo.CurrentFrame = GenerateRnd(minion.AnimInfo.NumberOfFrames - 1) + 1;
minion._mFlags &= ~MFLAG_ALLOW_SPECIAL;
minion._mmode = MonsterMode::Stand;
@ -596,7 +586,7 @@ void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize)
}
if (monster._mAi != AI_GARG) {
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monster._mdir];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
monster.AnimInfo.CurrentFrame = GenerateRnd(monster.AnimInfo.NumberOfFrames - 1) + 1;
monster._mFlags &= ~MFLAG_ALLOW_SPECIAL;
monster._mmode = MonsterMode::Stand;
@ -798,7 +788,7 @@ void DeleteMonster(int i)
void NewMonsterAnim(Monster &monster, MonsterGraphic graphic, Direction md, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0)
{
const auto &animData = monster.MType->GetAnimData(graphic);
const auto *pCelSprite = &*animData.CelSpritesForDirections[md];
const auto *pCelSprite = &*animData.CelSpritesForDirections[static_cast<size_t>(md)];
monster.AnimInfo.SetNewAnimation(pCelSprite, animData.Frames, animData.Rate, flags, numSkippedFrames, distributeFramesBeforeFrame);
monster._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL);
monster._mdir = md;
@ -944,7 +934,7 @@ void StartWalk(int i, int xvel, int yvel, int xadd, int yadd, Direction endDir)
monster.position.velocity = { xvel, yvel };
monster._mVar1 = xadd;
monster._mVar2 = yadd;
monster._mVar3 = endDir;
monster._mVar3 = static_cast<int>(endDir);
NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1);
monster.position.offset2 = { 0, 0 };
}
@ -968,7 +958,7 @@ void StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yad
monster.position.offset = { xoff, yoff };
monster._mmode = MonsterMode::MoveSouthwards;
monster.position.velocity = { xvel, yvel };
monster._mVar3 = endDir;
monster._mVar3 = static_cast<int>(endDir);
NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1);
monster.position.offset2 = { 16 * xoff, 16 * yoff };
}
@ -996,7 +986,7 @@ void StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yad
monster.position.velocity = { xvel, yvel };
monster._mVar1 = fx;
monster._mVar2 = fy;
monster._mVar3 = endDir;
monster._mVar3 = static_cast<int>(endDir);
NewMonsterAnim(monster, MonsterGraphic::Walk, endDir, AnimationDistributionFlags::ProcessAnimationPending, -1);
monster.position.offset2 = { 16 * xoff, 16 * yoff };
}
@ -1184,7 +1174,7 @@ void MonsterHitMonster(int mid, int i, int dam)
if ((monster.MType->mtype >= MT_SNEAK && monster.MType->mtype <= MT_ILLWEAV) || dam >> 6 >= monster.mLevel + 3) {
if (i >= 0)
monster._mdir = opposite[Monsters[i]._mdir];
monster._mdir = Opposite(Monsters[i]._mdir);
if (monster.MType->mtype == MT_BLINK) {
Teleport(mid);
@ -1233,7 +1223,7 @@ void StartMonsterDeath(int i, int pnum, bool sendmsg)
CheckQuestKill(monster, sendmsg);
M_FallenFear(monster.position.tile);
if ((monster.MType->mtype >= MT_NACID && monster.MType->mtype <= MT_XACID) || monster.MType->mtype == MT_SPIDLORD)
AddMissile(monster.position.tile, { 0, 0 }, DIR_S, MIS_ACIDPUD, TARGET_PLAYERS, i, monster._mint + 1, 0);
AddMissile(monster.position.tile, { 0, 0 }, Direction::South, MIS_ACIDPUD, TARGET_PLAYERS, i, monster._mint + 1, 0);
}
void StartDeathFromMonster(int i, int mid)
@ -1264,9 +1254,9 @@ void StartDeathFromMonster(int i, int mid)
else
PlayEffect(monster, 2);
Direction md = opposite[killer._mdir];
Direction md = Opposite(killer._mdir);
if (monster.MType->mtype == MT_GOLEM)
md = DIR_S;
md = Direction::South;
NewMonsterAnim(monster, MonsterGraphic::Death, md, gGameLogicStep < GameLogicStep::ProcessMonsters ? AnimationDistributionFlags::ProcessAnimationPending : AnimationDistributionFlags::None);
monster._mmode = MonsterMode::Death;
@ -1278,7 +1268,7 @@ void StartDeathFromMonster(int i, int mid)
CheckQuestKill(monster, true);
M_FallenFear(monster.position.tile);
if (monster.MType->mtype >= MT_NACID && monster.MType->mtype <= MT_XACID)
AddMissile(monster.position.tile, { 0, 0 }, DIR_S, MIS_ACIDPUD, TARGET_PLAYERS, mid, monster._mint + 1, 0);
AddMissile(monster.position.tile, { 0, 0 }, Direction::South, MIS_ACIDPUD, TARGET_PLAYERS, mid, monster._mint + 1, 0);
if (gbIsHellfire)
M_StartStand(killer, killer._mdir);
@ -1313,7 +1303,7 @@ void StartFadeout(Monster &monster, Direction md, bool backwards)
void StartHeal(Monster &monster)
{
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Special).CelSpritesForDirections[monster._mdir];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Special);
monster.AnimInfo.CurrentFrame = monster.MType->GetAnimData(MonsterGraphic::Special).Frames;
monster._mFlags |= MFLAG_LOCK_ANIMATION;
monster._mmode = MonsterMode::Heal;
@ -1332,9 +1322,9 @@ void SyncLightPosition(Monster &monster)
bool MonsterIdle(Monster &monster)
{
if (monster.MType->mtype == MT_GOLEM)
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Walk).CelSpritesForDirections[monster._mdir];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Walk);
else
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[monster._mdir];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
if (monster.AnimInfo.CurrentFrame == monster.AnimInfo.NumberOfFrames)
UpdateEnemy(monster);
@ -1774,7 +1764,7 @@ bool MonsterTalk(Monster &monster)
Quests[Q_VEIL]._qlog = true;
}
if (monster.mtalkmsg == TEXT_VEIL11 && (monster._mFlags & MFLAG_QUEST_COMPLETE) == 0) {
SpawnUnique(UITEM_STEELVEIL, monster.position.tile + DIR_S);
SpawnUnique(UITEM_STEELVEIL, monster.position.tile + Direction::South);
monster._mFlags |= MFLAG_QUEST_COMPLETE;
}
}
@ -1851,7 +1841,7 @@ bool MonsterSpecialStand(Monster &monster)
bool MonsterDelay(Monster &monster)
{
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[GetMonsterDirection(monster)];
monster.ActivateAnimation(MonsterGraphic::Stand, GetMonsterDirection(monster));
if (monster._mAi == AI_LAZARUS) {
if (monster._mVar2 > 8 || monster._mVar2 < 0)
monster._mVar2 = 8;
@ -1950,17 +1940,17 @@ bool RandomWalk(int i, Direction md)
Direction mdtemp = md;
bool ok = DirOK(i, md);
if (GenerateRnd(2) != 0)
ok = ok || (md = left[mdtemp], DirOK(i, md)) || (md = right[mdtemp], DirOK(i, md));
ok = ok || (md = Left(mdtemp), DirOK(i, md)) || (md = Right(mdtemp), DirOK(i, md));
else
ok = ok || (md = right[mdtemp], DirOK(i, md)) || (md = left[mdtemp], DirOK(i, md));
ok = ok || (md = Right(mdtemp), DirOK(i, md)) || (md = Left(mdtemp), DirOK(i, md));
if (GenerateRnd(2) != 0) {
ok = ok
|| (md = right[right[mdtemp]], DirOK(i, md))
|| (md = left[left[mdtemp]], DirOK(i, md));
|| (md = Right(Right(mdtemp)), DirOK(i, md))
|| (md = Left(Left(mdtemp)), DirOK(i, md));
} else {
ok = ok
|| (md = left[left[mdtemp]], DirOK(i, md))
|| (md = right[right[mdtemp]], DirOK(i, md));
|| (md = Left(Left(mdtemp)), DirOK(i, md))
|| (md = Right(Right(mdtemp)), DirOK(i, md));
}
if (ok)
M_WalkDir(i, md);
@ -1972,9 +1962,9 @@ bool RandomWalk2(int i, Direction md)
Direction mdtemp = md;
bool ok = DirOK(i, md); // Can we continue in the same direction
if (GenerateRnd(2) != 0) { // Randomly go left or right
ok = ok || (mdtemp = left[md], DirOK(i, left[md])) || (mdtemp = right[md], DirOK(i, right[md]));
ok = ok || (mdtemp = Left(md), DirOK(i, Left(md))) || (mdtemp = Right(md), DirOK(i, Right(md)));
} else {
ok = ok || (mdtemp = right[md], DirOK(i, right[md])) || (mdtemp = left[md], DirOK(i, left[md]));
ok = ok || (mdtemp = Right(md), DirOK(i, Right(md))) || (mdtemp = Left(md), DirOK(i, Left(md)));
}
if (ok)
@ -2044,7 +2034,7 @@ bool AiPlanWalk(int i)
int8_t path[MAX_PATH_LENGTH];
/** Maps from walking path step to facing direction. */
const Direction plr2monst[9] = { DIR_S, DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W };
const Direction plr2monst[9] = { Direction::South, Direction::NorthEast, Direction::NorthWest, Direction::SouthEast, Direction::SouthWest, Direction::North, Direction::East, Direction::South, Direction::West };
assert(i >= 0 && i < MAXMONSTERS);
auto &monster = Monsters[i];
@ -2068,7 +2058,7 @@ bool DumbWalk(int i, Direction md)
Direction Turn(Direction direction, bool turnLeft)
{
return turnLeft ? left[direction] : right[direction];
return turnLeft ? Left(direction) : Right(direction);
}
bool RoundWalk(int i, Direction direction, int *dir)
@ -2096,7 +2086,7 @@ bool RoundWalk(int i, Direction direction, int *dir)
// Try 90 degrees in the opposite than desired direction
*dir = (*dir == 0) ? 1 : 0;
return RandomWalk(i, opposite[turn90deg]);
return RandomWalk(i, Opposite(turn90deg));
}
bool AiPlanPath(int i)
@ -2211,7 +2201,7 @@ void AiRanged(int i, missile_id missileType, bool special)
AiDelay(monster, GenerateRnd(20));
} else if (abs(mx) < 4 && abs(my) < 4) {
if (GenerateRnd(100) < 10 * (monster._mint + 7))
RandomWalk(i, opposite[md]);
RandomWalk(i, Opposite(md));
}
if (monster._mmode == MonsterMode::Stand) {
if (LineClearMissile(monster.position.tile, { fx, fy })) {
@ -2410,7 +2400,7 @@ void SkeletonBowAi(int i)
|| (IsAnyOf(static_cast<MonsterMode>(monster._mVar1), MonsterMode::MoveNorthwards, MonsterMode::MoveSouthwards, MonsterMode::MoveSideways)
&& monster._mVar2 == 0
&& v < 2 * monster._mint + 63)) {
walking = DumbWalk(i, opposite[md]);
walking = DumbWalk(i, Opposite(md));
}
}
@ -2608,7 +2598,7 @@ void FallenAi(int i)
if (monster._mgoal == MGOAL_RETREAT) {
if (monster._mgoalvar1-- == 0) {
monster._mgoal = MGOAL_NORMAL;
M_StartStand(monster, opposite[monster._mgoalvar2]);
M_StartStand(monster, Opposite(static_cast<Direction>(monster._mgoalvar2)));
}
}
@ -2738,13 +2728,13 @@ void BatAi(int i)
int v = GenerateRnd(100);
if (monster._mgoal == MGOAL_RETREAT) {
if (monster._mgoalvar1 == 0) {
RandomWalk(i, opposite[md]);
RandomWalk(i, Opposite(md));
monster._mgoalvar1++;
} else {
if (GenerateRnd(2) != 0)
RandomWalk(i, left[md]);
RandomWalk(i, Left(md));
else
RandomWalk(i, right[md]);
RandomWalk(i, Right(md));
monster._mgoal = MGOAL_NORMAL;
}
return;
@ -2772,7 +2762,7 @@ void BatAi(int i)
monster._mgoal = MGOAL_RETREAT;
monster._mgoalvar1 = 0;
if (monster.MType->mtype == MT_FAMILIAR) {
AddMissile(monster.enemyPosition, { monster.enemyPosition.x + 1, 0 }, DIR_S, MIS_LIGHTNING, TARGET_PLAYERS, i, GenerateRnd(10) + 1, 0);
AddMissile(monster.enemyPosition, { monster.enemyPosition.x + 1, 0 }, Direction::South, MIS_LIGHTNING, TARGET_PLAYERS, i, GenerateRnd(10) + 1, 0);
}
}
@ -2808,7 +2798,7 @@ void GargoyleAi(int i)
if (abs(dx) >= monster._mint + 2 || abs(dy) >= monster._mint + 2) {
monster._mgoal = MGOAL_NORMAL;
StartHeal(monster);
} else if (!RandomWalk(i, opposite[md])) {
} else if (!RandomWalk(i, Opposite(md))) {
monster._mgoal = MGOAL_NORMAL;
}
}
@ -2875,12 +2865,12 @@ void SneakAi(int i)
md = GetDirection(monster.position.tile, Monsters[monster._menemy].position.tile);
else
md = GetDirection(monster.position.tile, Players[monster._menemy].position.last);
md = opposite[md];
md = Opposite(md);
if (monster.MType->mtype == MT_UNSEEN) {
if (GenerateRnd(2) != 0)
md = left[md];
md = Left(md);
else
md = right[md];
md = Right(md);
}
}
monster._mdir = md;
@ -2900,7 +2890,7 @@ void SneakAi(int i)
}
if (monster._mmode == MonsterMode::Stand) {
if (abs(mx) >= 2 || abs(my) >= 2 || v >= 4 * monster._mint + 10)
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[md];
monster.ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
else
StartAttack(monster);
}
@ -3036,24 +3026,25 @@ void SnakeAi(int i)
}
} else if (static_cast<MonsterMode>(monster._mVar1) == MonsterMode::Delay || GenerateRnd(100) >= 35 - 2 * monster._mint) {
if (pattern[monster._mgoalvar1] == -1)
md = left[md];
md = Left(md);
else if (pattern[monster._mgoalvar1] == 1)
md = right[md];
md = Right(md);
monster._mgoalvar1++;
if (monster._mgoalvar1 > 5)
monster._mgoalvar1 = 0;
if (md != monster._mgoalvar2) {
int drift = md - monster._mgoalvar2;
Direction targetDirection = static_cast<Direction>(monster._mgoalvar2);
if (md != targetDirection) {
int drift = static_cast<int>(md) - monster._mgoalvar2;
if (drift < 0)
drift += 8;
if (drift < 4)
md = right[monster._mgoalvar2];
md = Right(targetDirection);
else if (drift > 4)
md = left[monster._mgoalvar2];
monster._mgoalvar2 = md;
md = Left(targetDirection);
monster._mgoalvar2 = static_cast<int>(md);
}
if (!DumbWalk(i, md))
@ -3090,7 +3081,7 @@ void CounselorAi(int i)
int v = GenerateRnd(100);
if (monster._mgoal == MGOAL_RETREAT) {
if (monster._mgoalvar1++ <= 3)
RandomWalk(i, opposite[md]);
RandomWalk(i, Opposite(md));
else {
monster._mgoal = MGOAL_NORMAL;
StartFadein(monster, md, true);
@ -3798,7 +3789,7 @@ void InitMonsters()
{
if (!setlevel) {
for (int i = 0; i < MAX_PLRS; i++)
AddMonster(GolemHoldingCell, DIR_S, 0, false);
AddMonster(GolemHoldingCell, Direction::South, 0, false);
}
if (!gbIsSpawn && !setlevel && currlevel == 16)
@ -3863,7 +3854,7 @@ void SetMapMonsters(const uint16_t *dunData, Point startPosition)
AddMonsterType(MT_GOLEM, PLACE_SPECIAL);
if (setlevel)
for (int i = 0; i < MAX_PLRS; i++)
AddMonster(GolemHoldingCell, DIR_S, 0, false);
AddMonster(GolemHoldingCell, Direction::South, 0, false);
if (setlevel && setlvlnum == SL_VILEBETRAYER) {
AddMonsterType(UniqueMonstersData[UMT_LAZARUS].mtype, PLACE_UNIQUE);
@ -3981,7 +3972,7 @@ void M_GetKnockback(int i)
{
auto &monster = Monsters[i];
Direction d = opposite[monster._mdir];
Direction d = Opposite(monster._mdir);
if (!DirOK(i, d)) {
return;
}
@ -4154,29 +4145,29 @@ void M_WalkDir(int i, Direction md)
int mwi = Monsters[i].MType->GetAnimData(MonsterGraphic::Walk).Frames - 1;
switch (md) {
case DIR_N:
StartWalk(i, 0, -MWVel[mwi][1], -1, -1, DIR_N);
case Direction::North:
StartWalk(i, 0, -MWVel[mwi][1], -1, -1, Direction::North);
break;
case DIR_NE:
StartWalk(i, MWVel[mwi][1], -MWVel[mwi][0], 0, -1, DIR_NE);
case Direction::NorthEast:
StartWalk(i, MWVel[mwi][1], -MWVel[mwi][0], 0, -1, Direction::NorthEast);
break;
case DIR_E:
StartWalk3(i, MWVel[mwi][2], 0, -32, -16, 1, -1, 1, 0, DIR_E);
case Direction::East:
StartWalk3(i, MWVel[mwi][2], 0, -32, -16, 1, -1, 1, 0, Direction::East);
break;
case DIR_SE:
StartWalk2(i, MWVel[mwi][1], MWVel[mwi][0], -32, -16, 1, 0, DIR_SE);
case Direction::SouthEast:
StartWalk2(i, MWVel[mwi][1], MWVel[mwi][0], -32, -16, 1, 0, Direction::SouthEast);
break;
case DIR_S:
StartWalk2(i, 0, MWVel[mwi][1], 0, -32, 1, 1, DIR_S);
case Direction::South:
StartWalk2(i, 0, MWVel[mwi][1], 0, -32, 1, 1, Direction::South);
break;
case DIR_SW:
StartWalk2(i, -MWVel[mwi][1], MWVel[mwi][0], 32, -16, 0, 1, DIR_SW);
case Direction::SouthWest:
StartWalk2(i, -MWVel[mwi][1], MWVel[mwi][0], 32, -16, 0, 1, Direction::SouthWest);
break;
case DIR_W:
StartWalk3(i, -MWVel[mwi][2], 0, 32, -16, -1, 1, 0, 1, DIR_W);
case Direction::West:
StartWalk3(i, -MWVel[mwi][2], 0, 32, -16, -1, 1, 0, 1, Direction::West);
break;
case DIR_NW:
StartWalk(i, -MWVel[mwi][1], -MWVel[mwi][0], -1, 0, DIR_NW);
case Direction::NorthWest:
StartWalk(i, -MWVel[mwi][1], -MWVel[mwi][0], -1, 0, Direction::NorthWest);
break;
}
}
@ -4233,10 +4224,10 @@ void GolumAi(int i)
if (RandomWalk(i, Players[i]._pdir))
return;
Direction md = left[golem._mdir];
Direction md = Left(golem._mdir);
bool ok = false;
for (int j = 0; j < 8 && !ok; j++) {
md = right[md];
md = Right(md);
ok = DirOK(i, md);
}
if (ok)
@ -4412,17 +4403,17 @@ bool DirOK(int i, Direction mdir)
Point futurePosition = position + mdir;
if (futurePosition.y < 0 || futurePosition.y >= MAXDUNY || futurePosition.x < 0 || futurePosition.x >= MAXDUNX || !IsTileAvailable(monster, futurePosition))
return false;
if (mdir == DIR_E) {
if (IsTileSolid(position + DIR_SE) || (dFlags[position.x + 1][position.y] & BFLAG_MONSTLR) != 0)
if (mdir == Direction::East) {
if (IsTileSolid(position + Direction::SouthEast) || (dFlags[position.x + 1][position.y] & BFLAG_MONSTLR) != 0)
return false;
} else if (mdir == DIR_W) {
if (IsTileSolid(position + DIR_SW) || (dFlags[position.x][position.y + 1] & BFLAG_MONSTLR) != 0)
} else if (mdir == Direction::West) {
if (IsTileSolid(position + Direction::SouthWest) || (dFlags[position.x][position.y + 1] & BFLAG_MONSTLR) != 0)
return false;
} else if (mdir == DIR_N) {
if (IsTileSolid(position + DIR_NE) || IsTileSolid(position + DIR_NW))
} else if (mdir == Direction::North) {
if (IsTileSolid(position + Direction::NorthEast) || IsTileSolid(position + Direction::NorthWest))
return false;
} else if (mdir == DIR_S)
if (IsTileSolid(position + DIR_SW) || IsTileSolid(position + DIR_SE))
} else if (mdir == Direction::South)
if (IsTileSolid(position + Direction::SouthWest) || IsTileSolid(position + Direction::SouthEast))
return false;
if (monster.leaderRelation == LeaderRelation::Leashed) {
return futurePosition.WalkingDistance(Monsters[monster.leader].position.future) < 4;
@ -4541,7 +4532,6 @@ void SyncMonsterAnim(Monster &monster)
monster.mName = _(UniqueMonstersData[monster._uniqtype - 1].mName);
else
monster.mName = _(monster.MData->mName);
int mdir = monster._mdir;
MonsterGraphic graphic = MonsterGraphic::Stand;
@ -4584,10 +4574,7 @@ void SyncMonsterAnim(Monster &monster)
break;
}
if (monster.MType->GetAnimData(graphic).CelSpritesForDirections[mdir])
monster.AnimInfo.pCelSprite = &*monster.MType->GetAnimData(graphic).CelSpritesForDirections[mdir];
else
monster.AnimInfo.pCelSprite = nullptr;
monster.ActivateAnimationForCurrentDirection(graphic);
}
void M_FallenFear(Point position)
@ -4626,7 +4613,7 @@ void M_FallenFear(Point position)
monster._mgoal = MGOAL_RETREAT;
monster._mgoalvar1 = rundist;
monster._mgoalvar2 = GetDirection(position, monster.position.tile);
monster._mgoalvar2 = static_cast<int>(GetDirection(position, monster.position.tile));
}
}
@ -4896,9 +4883,9 @@ bool SpawnSkeleton(int ii, Point position)
int PreSpawnSkeleton()
{
int skel = AddSkeleton({ 0, 0 }, DIR_S, false);
int skel = AddSkeleton({ 0, 0 }, Direction::South, false);
if (skel != -1)
M_StartStand(Monsters[skel], DIR_S);
M_StartStand(Monsters[skel], Direction::South);
return skel;
}
@ -4944,7 +4931,7 @@ void SpawnGolem(int i, Point position, Missile &missile)
golem.mMinDamage = 2 * (missile._mispllvl + 4);
golem.mMaxDamage = 2 * (missile._mispllvl + 8);
golem._mFlags |= MFLAG_GOLEM;
StartSpecialStand(golem, DIR_S);
StartSpecialStand(golem, Direction::South);
UpdateEnemy(golem);
if (i == MyPlayerId) {
NetSendCmdGolem(
@ -5007,7 +4994,7 @@ void Monster::CheckStandAnimationIsLoaded(Direction mdir)
{
if (IsAnyOf(_mmode, MonsterMode::Stand, MonsterMode::Talk)) {
_mdir = mdir;
AnimInfo.pCelSprite = &*MType->GetAnimData(MonsterGraphic::Stand).CelSpritesForDirections[mdir];
ActivateAnimationForCurrentDirection(MonsterGraphic::Stand);
}
}

24
Source/monster.h

@ -213,6 +213,26 @@ struct Monster { // note: missing field _mAFNum
CMonster *MType;
const MonsterData *MData;
/**
* @brief Sets the current cell sprite to match the desired direction and animation sequence
* @param graphic Animation sequence of interest
* @param direction Desired direction the monster should be visually facing
*/
void ActivateAnimation(MonsterGraphic graphic, Direction direction)
{
auto &celSprite = this->MType->GetAnimData(graphic).CelSpritesForDirections[static_cast<size_t>(direction)];
this->AnimInfo.pCelSprite = celSprite ? &*celSprite : nullptr;
}
/**
* @brief Sets the current cell sprite to match the desired animation sequence using the direction the monster is currently facing
* @param graphic Animation sequence of interest
*/
void ActivateAnimationForCurrentDirection(MonsterGraphic graphic)
{
this->ActivateAnimation(graphic, this->_mdir);
}
/**
* @brief Check thats the correct stand Animation is loaded. This is needed if direction is changed (monster stands and looks to player).
* @param mdir direction of the monster
@ -283,8 +303,4 @@ bool CheckMonsterHit(Monster &monster, bool *ret);
int encode_enemy(Monster &monster);
void decode_enemy(Monster &monster, int enemy);
extern Direction left[8];
extern Direction right[8];
extern Direction opposite[8];
} // namespace devilution

6
Source/msg.cpp

@ -1532,11 +1532,11 @@ DWORD OnPlayerJoinLevel(TCmd *pCmd, int pnum)
if (currlevel == player.plrlevel) {
SyncInitPlr(pnum);
if ((player._pHitPoints >> 6) > 0) {
StartStand(pnum, DIR_S);
StartStand(pnum, Direction::South);
} else {
player._pgfxnum = 0;
player._pmode = PM_DEATH;
NewPlrAnim(player, player_graphic::Death, DIR_S, player._pDFrames, 1);
NewPlrAnim(player, player_graphic::Death, Direction::South, player._pDFrames, 1);
player.AnimInfo.CurrentFrame = player.AnimInfo.NumberOfFrames - 1;
dFlags[player.position.tile.x][player.position.tile.y] |= BFLAG_DEAD_PLAYER;
}
@ -1779,7 +1779,7 @@ DWORD OnOpenHive(TCmd *pCmd, int pnum)
{
auto *p = (TCmdLocParam2 *)pCmd;
if (gbBufferMsgs != 1) {
AddMissile({ p->x, p->y }, { p->wParam1, p->wParam2 }, DIR_S, MIS_HIVEEXP2, TARGET_MONSTERS, pnum, 0, 0);
AddMissile({ p->x, p->y }, { p->wParam1, p->wParam2 }, Direction::South, MIS_HIVEEXP2, TARGET_MONSTERS, pnum, 0, 0);
TownOpenHive();
InitTownTriggers();
}

4
Source/multi.cpp

@ -828,13 +828,13 @@ void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, bool recv)
}
if (player._pHitPoints >> 6 > 0) {
StartStand(pnum, DIR_S);
StartStand(pnum, Direction::South);
return;
}
player._pgfxnum = 0;
player._pmode = PM_DEATH;
NewPlrAnim(player, player_graphic::Death, DIR_S, player._pDFrames, 1);
NewPlrAnim(player, player_graphic::Death, Direction::South, player._pDFrames, 1);
player.AnimInfo.CurrentFrame = player.AnimInfo.NumberOfFrames - 1;
dFlags[player.position.tile.x][player.position.tile.y] |= BFLAG_DEAD_PLAYER;
}

62
Source/objects.cpp

@ -1475,11 +1475,11 @@ void UpdateCircle(int i)
ObjChangeMapResync(Objects[i]._oVar1, Objects[i]._oVar2, Objects[i]._oVar3, Objects[i]._oVar4);
if (Quests[Q_BETRAYER]._qactive == QUEST_ACTIVE && Quests[Q_BETRAYER]._qvar1 <= 4) // BUGFIX stepping on the circle again will break the quest state (fixed)
Quests[Q_BETRAYER]._qvar1 = 4;
AddMissile(myPlayer.position.tile, { 35, 46 }, DIR_S, MIS_RNDTELEPORT, TARGET_BOTH, MyPlayerId, 0, 0);
AddMissile(myPlayer.position.tile, { 35, 46 }, Direction::South, MIS_RNDTELEPORT, TARGET_BOTH, MyPlayerId, 0, 0);
LastMouseButtonAction = MouseActionType::None;
sgbMouseDown = CLICK_NONE;
ClrPlrPath(myPlayer);
StartStand(MyPlayerId, DIR_S);
StartStand(MyPlayerId, Direction::South);
}
}
@ -1612,9 +1612,9 @@ void ObjSetMini(Point position, int v)
Point megaOrigin = position * 2 + Displacement { 16, 16 };
ObjSetMicro(megaOrigin, SDL_SwapLE16(mega.micro1) + 1);
ObjSetMicro(megaOrigin + DIR_SE, SDL_SwapLE16(mega.micro2) + 1);
ObjSetMicro(megaOrigin + DIR_SW, SDL_SwapLE16(mega.micro3) + 1);
ObjSetMicro(megaOrigin + DIR_S, SDL_SwapLE16(mega.micro4) + 1);
ObjSetMicro(megaOrigin + Direction::SouthEast, SDL_SwapLE16(mega.micro2) + 1);
ObjSetMicro(megaOrigin + Direction::SouthWest, SDL_SwapLE16(mega.micro3) + 1);
ObjSetMicro(megaOrigin + Direction::South, SDL_SwapLE16(mega.micro4) + 1);
}
void ObjL1Special(int x1, int y1, int x2, int y2)
@ -1836,10 +1836,10 @@ void OperateL1RDoor(int pnum, int oi, bool sendflag)
} else {
dSpecial[door.position.x][door.position.y] = 2;
}
SetDoorPiece(door.position + Direction::DIR_NE);
SetDoorPiece(door.position + Direction::NorthEast);
door._oAnimFrame += 2;
door._oPreFlag = true;
DoorSet(door.position + Direction::DIR_NW, false);
DoorSet(door.position + Direction::NorthWest, false);
door._oVar4 = 1;
door._oSelFlag = 2;
RedoPlayerVision();
@ -1861,21 +1861,21 @@ void OperateL1RDoor(int pnum, int oi, bool sendflag)
ObjSetMicro(door.position, door._oVar1);
if (currlevel < 17) {
if (door._oVar2 != 50) {
ObjSetMicro(door.position + Direction::DIR_NW, door._oVar2);
ObjSetMicro(door.position + Direction::NorthWest, door._oVar2);
} else {
if (dPiece[door.position.x - 1][door.position.y] == 396)
ObjSetMicro(door.position + Direction::DIR_NW, 411);
ObjSetMicro(door.position + Direction::NorthWest, 411);
else
ObjSetMicro(door.position + Direction::DIR_NW, 50);
ObjSetMicro(door.position + Direction::NorthWest, 50);
}
} else {
if (door._oVar2 != 86) {
ObjSetMicro(door.position + Direction::DIR_NW, door._oVar2);
ObjSetMicro(door.position + Direction::NorthWest, door._oVar2);
} else {
if (dPiece[door.position.x - 1][door.position.y] == 210)
ObjSetMicro(door.position + Direction::DIR_NW, 232);
ObjSetMicro(door.position + Direction::NorthWest, 232);
else
ObjSetMicro(door.position + Direction::DIR_NW, 86);
ObjSetMicro(door.position + Direction::NorthWest, 86);
}
}
dSpecial[door.position.x][door.position.y] = 0;
@ -1917,10 +1917,10 @@ void OperateL1LDoor(int pnum, int oi, bool sendflag)
} else {
dSpecial[door.position.x][door.position.y] = 1;
}
SetDoorPiece(door.position + Direction::DIR_NW);
SetDoorPiece(door.position + Direction::NorthWest);
door._oAnimFrame += 2;
door._oPreFlag = true;
DoorSet(door.position + Direction::DIR_NE, true);
DoorSet(door.position + Direction::NorthEast, true);
door._oVar4 = 1;
door._oSelFlag = 2;
RedoPlayerVision();
@ -1942,21 +1942,21 @@ void OperateL1LDoor(int pnum, int oi, bool sendflag)
ObjSetMicro(door.position, door._oVar1);
if (currlevel < 17) {
if (door._oVar2 != 50) {
ObjSetMicro(door.position + Direction::DIR_NE, door._oVar2);
ObjSetMicro(door.position + Direction::NorthEast, door._oVar2);
} else {
if (dPiece[door.position.x][door.position.y - 1] == 396)
ObjSetMicro(door.position + Direction::DIR_NE, 412);
ObjSetMicro(door.position + Direction::NorthEast, 412);
else
ObjSetMicro(door.position + Direction::DIR_NE, 50);
ObjSetMicro(door.position + Direction::NorthEast, 50);
}
} else {
if (door._oVar2 != 86) {
ObjSetMicro(door.position + Direction::DIR_NE, door._oVar2);
ObjSetMicro(door.position + Direction::NorthEast, door._oVar2);
} else {
if (dPiece[door.position.x][door.position.y - 1] == 210)
ObjSetMicro(door.position + Direction::DIR_NE, 234);
ObjSetMicro(door.position + Direction::NorthEast, 234);
else
ObjSetMicro(door.position + Direction::DIR_NE, 86);
ObjSetMicro(door.position + Direction::NorthEast, 86);
}
}
dSpecial[door.position.x][door.position.y] = 0;
@ -2208,7 +2208,7 @@ void OperateBook(int pnum, int i)
}
if (doAddMissile) {
Objects[dObject[35][36] - 1]._oVar5++;
AddMissile(player.position.tile, { dx, dy }, DIR_S, MIS_RNDTELEPORT, TARGET_BOTH, pnum, 0, 0);
AddMissile(player.position.tile, { dx, dy }, Direction::South, MIS_RNDTELEPORT, TARGET_BOTH, pnum, 0, 0);
missileAdded = true;
doAddMissile = false;
}
@ -3050,7 +3050,7 @@ bool OperateShrineHoly(int pnum)
if (deltaload)
return false;
AddMissile(Players[pnum].position.tile, { 0, 0 }, DIR_S, MIS_RNDTELEPORT, TARGET_PLAYERS, pnum, 0, 2 * leveltype);
AddMissile(Players[pnum].position.tile, { 0, 0 }, Direction::South, MIS_RNDTELEPORT, TARGET_PLAYERS, pnum, 0, 2 * leveltype);
if (pnum != MyPlayerId)
return false;
@ -4299,25 +4299,25 @@ void SyncL1Doors(Object &door)
if (isLeftDoor) {
ObjSetMicro(door.position, door._oVar1 == 214 ? 408 : 393);
dSpecial[door.position.x][door.position.y] = 7;
SetDoorPiece(door.position + Direction::DIR_NW);
DoorSet(door.position + Direction::DIR_NE, isLeftDoor);
SetDoorPiece(door.position + Direction::NorthWest);
DoorSet(door.position + Direction::NorthEast, isLeftDoor);
} else {
ObjSetMicro(door.position, 395);
dSpecial[door.position.x][door.position.y] = 8;
SetDoorPiece(door.position + Direction::DIR_NE);
DoorSet(door.position + Direction::DIR_NW, isLeftDoor);
SetDoorPiece(door.position + Direction::NorthEast);
DoorSet(door.position + Direction::NorthWest, isLeftDoor);
}
} else {
if (isLeftDoor) {
ObjSetMicro(door.position, 206);
dSpecial[door.position.x][door.position.y] = 1;
SetDoorPiece(door.position + Direction::DIR_NW);
DoorSet(door.position + Direction::DIR_NE, isLeftDoor);
SetDoorPiece(door.position + Direction::NorthWest);
DoorSet(door.position + Direction::NorthEast, isLeftDoor);
} else {
ObjSetMicro(door.position, 209);
dSpecial[door.position.x][door.position.y] = 2;
SetDoorPiece(door.position + Direction::DIR_NE);
DoorSet(door.position + Direction::DIR_NW, isLeftDoor);
SetDoorPiece(door.position + Direction::NorthEast);
DoorSet(door.position + Direction::NorthWest, isLeftDoor);
}
}
}

8
Source/path.cpp

@ -365,16 +365,16 @@ bool path_solid_pieces(Point startPosition, Point destinationPosition)
bool rv = true;
switch (GetPathDirection(startPosition, destinationPosition)) {
case 5: // Stepping north
rv = IsTileNotSolid(destinationPosition + DIR_SW) && IsTileNotSolid(destinationPosition + DIR_SE);
rv = IsTileNotSolid(destinationPosition + Direction::SouthWest) && IsTileNotSolid(destinationPosition + Direction::SouthEast);
break;
case 6: // Stepping east
rv = IsTileNotSolid(destinationPosition + DIR_SW) && IsTileNotSolid(destinationPosition + DIR_NW);
rv = IsTileNotSolid(destinationPosition + Direction::SouthWest) && IsTileNotSolid(destinationPosition + Direction::NorthWest);
break;
case 7: // Stepping south
rv = IsTileNotSolid(destinationPosition + DIR_NE) && IsTileNotSolid(destinationPosition + DIR_NW);
rv = IsTileNotSolid(destinationPosition + Direction::NorthEast) && IsTileNotSolid(destinationPosition + Direction::NorthWest);
break;
case 8: // Stepping west
rv = IsTileNotSolid(destinationPosition + DIR_SE) && IsTileNotSolid(destinationPosition + DIR_NE);
rv = IsTileNotSolid(destinationPosition + Direction::SouthEast) && IsTileNotSolid(destinationPosition + Direction::NorthEast);
break;
}
return rv;

16
Source/path.h

@ -55,14 +55,14 @@ bool path_solid_pieces(Point startPosition, Point destinationPosition);
/** For iterating over the 8 possible movement directions */
const Displacement PathDirs[8] = {
// clang-format off
{ -1, -1 }, //DIR_N
{ -1, 1 }, //DIR_W
{ 1, -1 }, //DIR_E
{ 1, 1 }, //DIR_S
{ -1, 0 }, //DIR_NW
{ 0, -1 }, //DIR_NE
{ 1, 0 }, //DIR_SE
{ 0, 1 }, //DIR_SW
{ -1, -1 }, //Direction::North
{ -1, 1 }, //Direction::West
{ 1, -1 }, //Direction::East
{ 1, 1 }, //Direction::South
{ -1, 0 }, //Direction::NorthWest
{ 0, -1 }, //Direction::NorthEast
{ 1, 0 }, //Direction::SouthEast
{ 0, 1 }, //Direction::SouthWest
// clang-format on
};

74
Source/player.cpp

@ -295,14 +295,14 @@ _sfx_id herosounds[enum_size<HeroClass>::value][enum_size<HeroSpeech>::value] =
constexpr std::array<const DirectionSettings, 8> WalkSettings { {
// clang-format off
{ DIR_S, { 1, 1 }, { 0, -32 }, { 0, 0 }, SDIR_S, PM_WALK2, WalkDownwards },
{ DIR_SW, { 0, 1 }, { 32, -16 }, { 0, 0 }, SDIR_SW, PM_WALK2, WalkDownwards },
{ DIR_W, { -1, 1 }, { 32, -16 }, { 0, 1 }, SDIR_W, PM_WALK3, WalkSides },
{ DIR_NW, { -1, 0 }, { 0, 0 }, { 0, 0 }, SDIR_NW, PM_WALK, WalkUpwards },
{ DIR_N, { -1, -1 }, { 0, 0 }, { 0, 0 }, SDIR_N, PM_WALK, WalkUpwards },
{ DIR_NE, { 0, -1 }, { 0, 0 }, { 0, 0 }, SDIR_NE, PM_WALK, WalkUpwards },
{ DIR_E, { 1, -1 }, { -32, -16 }, { 1, 0 }, SDIR_E, PM_WALK3, WalkSides },
{ DIR_SE, { 1, 0 }, { -32, -16 }, { 0, 0 }, SDIR_SE, PM_WALK2, WalkDownwards }
{ Direction::South, { 1, 1 }, { 0, -32 }, { 0, 0 }, SDIR_S, PM_WALK2, WalkDownwards },
{ Direction::SouthWest, { 0, 1 }, { 32, -16 }, { 0, 0 }, SDIR_SW, PM_WALK2, WalkDownwards },
{ Direction::West, { -1, 1 }, { 32, -16 }, { 0, 1 }, SDIR_W, PM_WALK3, WalkSides },
{ Direction::NorthWest, { -1, 0 }, { 0, 0 }, { 0, 0 }, SDIR_NW, PM_WALK, WalkUpwards },
{ Direction::North, { -1, -1 }, { 0, 0 }, { 0, 0 }, SDIR_N, PM_WALK, WalkUpwards },
{ Direction::NorthEast, { 0, -1 }, { 0, 0 }, { 0, 0 }, SDIR_NE, PM_WALK, WalkUpwards },
{ Direction::East, { 1, -1 }, { -32, -16 }, { 1, 0 }, SDIR_E, PM_WALK3, WalkSides },
{ Direction::SouthEast, { 1, 0 }, { -32, -16 }, { 0, 0 }, SDIR_SE, PM_WALK2, WalkDownwards }
// clang-format on
} };
@ -331,12 +331,12 @@ bool PlrDirOK(const Player &player, Direction dir)
return false;
}
if (dir == DIR_E) {
return !IsTileSolid(position + DIR_SE) && (dFlags[position.x + 1][position.y] & BFLAG_PLAYERLR) == 0;
if (dir == Direction::East) {
return !IsTileSolid(position + Direction::SouthEast) && (dFlags[position.x + 1][position.y] & BFLAG_PLAYERLR) == 0;
}
if (dir == DIR_W) {
return !IsTileSolid(position + DIR_SW) && (dFlags[position.x][position.y + 1] & BFLAG_PLAYERLR) == 0;
if (dir == Direction::West) {
return !IsTileSolid(position + Direction::SouthWest) && (dFlags[position.x][position.y + 1] & BFLAG_PLAYERLR) == 0;
}
return true;
@ -345,7 +345,7 @@ bool PlrDirOK(const Player &player, Direction dir)
void HandleWalkMode(int pnum, Displacement vel, Direction dir)
{
auto &player = Players[pnum];
const auto &dirModeParams = WalkSettings[dir];
const auto &dirModeParams = WalkSettings[static_cast<size_t>(dir)];
SetPlayerOld(player);
if (!PlrDirOK(player, dir)) {
return;
@ -356,7 +356,7 @@ void HandleWalkMode(int pnum, Displacement vel, Direction dir)
player.position.future = player.position.tile + dirModeParams.tileAdd;
if (pnum == MyPlayerId) {
ScrollViewPort(player, WalkSettings[dir].scrollDir);
ScrollViewPort(player, dirModeParams.scrollDir);
}
dirModeParams.walkModeHandler(pnum, dirModeParams);
@ -409,7 +409,7 @@ void SetPlayerGPtrs(const char *path, std::unique_ptr<byte[]> &data, std::array<
void ClearStateVariables(Player &player)
{
player.position.temp = { 0, 0 };
player.tempDirection = DIR_S;
player.tempDirection = Direction::South;
player._pVar4 = 0;
player._pVar5 = 0;
player.position.offset2 = { 0, 0 };
@ -1197,9 +1197,9 @@ bool DoAttack(int pnum)
if ((player._pIFlags & ISPL_FIREDAM) == 0 || (player._pIFlags & ISPL_LIGHTDAM) == 0) {
if ((player._pIFlags & ISPL_FIREDAM) != 0) {
AddMissile({ dx, dy }, { 1, 0 }, DIR_S, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0);
AddMissile({ dx, dy }, { 1, 0 }, Direction::South, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0);
} else if ((player._pIFlags & ISPL_LIGHTDAM) != 0) {
AddMissile({ dx, dy }, { 2, 0 }, DIR_S, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0);
AddMissile({ dx, dy }, { 2, 0 }, Direction::South, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0);
}
}
@ -1233,7 +1233,7 @@ bool DoAttack(int pnum)
|| (player.InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD && player.InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND)
|| (player.InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD && player.InvBody[INVLOC_HAND_RIGHT]._iLoc == ILOC_TWOHAND))
&& !(player.InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD || player.InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD))))) {
position = player.position.tile + right[player._pdir];
position = player.position.tile + Right(player._pdir);
if (dMonster[position.x][position.y] != 0) {
int m = abs(dMonster[position.x][position.y]) - 1;
auto &monster = Monsters[m];
@ -1242,7 +1242,7 @@ bool DoAttack(int pnum)
didhit = true;
}
}
position = player.position.tile + left[player._pdir];
position = player.position.tile + Left(player._pdir);
if (dMonster[position.x][position.y] != 0) {
int m = abs(dMonster[position.x][position.y]) - 1;
auto &monster = Monsters[m];
@ -1617,28 +1617,28 @@ void CheckNewPath(int pnum, bool pmWillBeCalled)
switch (player.walkpath[0]) {
case WALK_N:
StartWalk(pnum, { 0, -xvel }, DIR_N, pmWillBeCalled);
StartWalk(pnum, { 0, -xvel }, Direction::North, pmWillBeCalled);
break;
case WALK_NE:
StartWalk(pnum, { xvel, -yvel }, DIR_NE, pmWillBeCalled);
StartWalk(pnum, { xvel, -yvel }, Direction::NorthEast, pmWillBeCalled);
break;
case WALK_E:
StartWalk(pnum, { xvel3, 0 }, DIR_E, pmWillBeCalled);
StartWalk(pnum, { xvel3, 0 }, Direction::East, pmWillBeCalled);
break;
case WALK_SE:
StartWalk(pnum, { xvel, yvel }, DIR_SE, pmWillBeCalled);
StartWalk(pnum, { xvel, yvel }, Direction::SouthEast, pmWillBeCalled);
break;
case WALK_S:
StartWalk(pnum, { 0, xvel }, DIR_S, pmWillBeCalled);
StartWalk(pnum, { 0, xvel }, Direction::South, pmWillBeCalled);
break;
case WALK_SW:
StartWalk(pnum, { -xvel, yvel }, DIR_SW, pmWillBeCalled);
StartWalk(pnum, { -xvel, yvel }, Direction::SouthWest, pmWillBeCalled);
break;
case WALK_W:
StartWalk(pnum, { -xvel3, 0 }, DIR_W, pmWillBeCalled);
StartWalk(pnum, { -xvel3, 0 }, Direction::West, pmWillBeCalled);
break;
case WALK_NW:
StartWalk(pnum, { -xvel, -yvel }, DIR_NW, pmWillBeCalled);
StartWalk(pnum, { -xvel, -yvel }, Direction::NorthWest, pmWillBeCalled);
break;
}
@ -1705,7 +1705,7 @@ void CheckNewPath(int pnum, bool pmWillBeCalled)
case ACTION_SPELL:
d = GetDirection(player.position.tile, { player.destParam1, player.destParam2 });
StartSpell(pnum, d, player.destParam1, player.destParam2);
player._pVar4 = player.destParam3;
player._pVar4 = static_cast<int>(player.destParam3);
break;
case ACTION_SPELLWALL:
StartSpell(pnum, player.destParam3, player.destParam1, player.destParam2);
@ -2293,11 +2293,9 @@ void NewPlrAnim(Player &player, player_graphic graphic, Direction dir, int numbe
if (player.AnimationData[static_cast<size_t>(graphic)].RawData == nullptr)
LoadPlrGFX(player, graphic);
auto &celSprites = player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections;
auto &celSprite = player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[static_cast<size_t>(dir)];
CelSprite *pCelSprite = nullptr;
if (celSprites[dir])
pCelSprite = &*celSprites[dir];
CelSprite *pCelSprite = celSprite ? &*celSprite : nullptr;
player.AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, delayLen, flags, numSkippedFrames, distributeFramesBeforeFrame);
}
@ -2732,16 +2730,16 @@ void InitPlayer(Player &player, bool firstTime)
if (player._pHitPoints >> 6 > 0) {
player._pmode = PM_STAND;
NewPlrAnim(player, player_graphic::Stand, DIR_S, player._pNFrames, 4);
NewPlrAnim(player, player_graphic::Stand, Direction::South, player._pNFrames, 4);
player.AnimInfo.CurrentFrame = GenerateRnd(player._pNFrames - 1) + 1;
player.AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(3);
} else {
player._pmode = PM_DEATH;
NewPlrAnim(player, player_graphic::Death, DIR_S, player._pDFrames, 2);
NewPlrAnim(player, player_graphic::Death, Direction::South, player._pDFrames, 2);
player.AnimInfo.CurrentFrame = player.AnimInfo.NumberOfFrames - 1;
}
player._pdir = DIR_S;
player._pdir = Direction::South;
if (&player == &myPlayer) {
if (!firstTime || currlevel != 0) {
@ -3090,7 +3088,7 @@ StartPlayerKill(int pnum, int earflag)
} else {
Direction pdd = player._pdir;
for (auto &item : player.InvBody) {
pdd = left[pdd];
pdd = Left(pdd);
DeadItem(player, &item, Displacement(pdd));
}
@ -3544,7 +3542,7 @@ void CheckPlrSpell()
LastMouseButtonAction = MouseActionType::Spell;
Direction sd = GetDirection(myPlayer.position.tile, cursPosition);
sl = GetSpellLevel(MyPlayerId, myPlayer._pRSpell);
NetSendCmdLocParam3(true, CMD_SPELLXYD, cursPosition, myPlayer._pRSpell, sd, sl);
NetSendCmdLocParam3(true, CMD_SPELLXYD, cursPosition, myPlayer._pRSpell, static_cast<uint16_t>(sd), sl);
} else if (pcursmonst != -1) {
LastMouseButtonAction = MouseActionType::SpellMonsterTarget;
sl = GetSpellLevel(MyPlayerId, myPlayer._pRSpell);
@ -3612,7 +3610,7 @@ void SyncPlrAnim(int pnum)
app_fatal("SyncPlrAnim");
}
player.AnimInfo.pCelSprite = &*player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[player._pdir];
player.AnimInfo.pCelSprite = &*player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[static_cast<size_t>(player._pdir)];
}
void SyncInitPlrPos(int pnum)

2
Source/portal.cpp

@ -49,7 +49,7 @@ void AddWarpMissile(int i, int x, int y)
{
MissilesData[MIS_TOWN].mlSFX = SFX_NONE;
int mi = AddMissile({ 0, 0 }, { x, y }, DIR_S, MIS_TOWN, TARGET_MONSTERS, i, 0, 0);
int mi = AddMissile({ 0, 0 }, { x, y }, Direction::South, MIS_TOWN, TARGET_MONSTERS, i, 0, 0);
if (mi == -1)
return;

14
Source/quests.cpp

@ -398,7 +398,7 @@ void CheckQuests()
quest.position.y = 2 * quest.position.y + 16;
int rportx = quest.position.x;
int rporty = quest.position.y;
AddMissile({ rportx, rporty }, { rportx, rporty }, DIR_S, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
AddMissile({ rportx, rporty }, { rportx, rporty }, Direction::South, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
quest._qvar2 = 1;
if (quest._qactive == QUEST_ACTIVE) {
quest._qvar1 = 3;
@ -411,7 +411,7 @@ void CheckQuests()
&& quest._qvar2 == 4) {
int rportx = 35;
int rporty = 32;
AddMissile({ rportx, rporty }, { rportx, rporty }, DIR_S, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
AddMissile({ rportx, rporty }, { rportx, rporty }, Direction::South, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
quest._qvar2 = 3;
}
@ -521,7 +521,7 @@ void CheckQuestKill(const Monster &monster, bool sendmsg)
Quests[Q_BETRAYER]._qvar1 = 7;
Quests[Q_BETRAYER]._qvar2 = 4;
Quests[Q_DIABLO]._qactive = QUEST_ACTIVE;
AddMissile({ 35, 32 }, { 35, 32 }, DIR_S, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
AddMissile({ 35, 32 }, { 35, 32 }, Direction::South, MIS_RPORTAL, TARGET_MONSTERS, MyPlayerId, 0, 0);
myPlayer.Say(HeroSpeech::YourMadnessEndsHereBetrayer, 30);
} else if (monster._uniqtype - 1 == UMT_WARLORD) { //"Warlord of Blood"
Quests[Q_WARLORD]._qactive = QUEST_DONE;
@ -566,24 +566,24 @@ void SetReturnLvlPos()
{
switch (setlvlnum) {
case SL_SKELKING:
ReturnLvlPosition = Quests[Q_SKELKING].position + DIR_SE;
ReturnLvlPosition = Quests[Q_SKELKING].position + Direction::SouthEast;
ReturnLevel = Quests[Q_SKELKING]._qlevel;
ReturnLevelType = DTYPE_CATHEDRAL;
break;
case SL_BONECHAMB:
ReturnLvlPosition = Quests[Q_SCHAMB].position + DIR_SE;
ReturnLvlPosition = Quests[Q_SCHAMB].position + Direction::SouthEast;
ReturnLevel = Quests[Q_SCHAMB]._qlevel;
ReturnLevelType = DTYPE_CATACOMBS;
break;
case SL_MAZE:
break;
case SL_POISONWATER:
ReturnLvlPosition = Quests[Q_PWATER].position + DIR_SW;
ReturnLvlPosition = Quests[Q_PWATER].position + Direction::SouthWest;
ReturnLevel = Quests[Q_PWATER]._qlevel;
ReturnLevelType = DTYPE_CATHEDRAL;
break;
case SL_VILEBETRAYER:
ReturnLvlPosition = Quests[Q_BETRAYER].position + DIR_E;
ReturnLvlPosition = Quests[Q_BETRAYER].position + Direction::East;
ReturnLevel = Quests[Q_BETRAYER]._qlevel;
ReturnLevelType = DTYPE_HELL;
break;

43
Source/scrollrt.cpp

@ -850,9 +850,8 @@ void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosit
if (LightTableIndex < LightsMax && bDead != 0) {
do {
Corpse *pDeadGuy = &Corpses[(bDead & 0x1F) - 1];
auto dd = static_cast<Direction>((bDead >> 5) & 7);
int px = targetBufferPosition.x - CalculateWidth2(pDeadGuy->width);
const byte *pCelBuff = pDeadGuy->data[dd];
const byte *pCelBuff = pDeadGuy->data[(bDead >> 5) & 7];
assert(pCelBuff != nullptr);
const auto *frameTable = reinterpret_cast<const uint32_t *>(pCelBuff);
int frames = SDL_SwapLE32(frameTable[0]);
@ -943,11 +942,11 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio
} else {
world_draw_black_tile(out, targetBufferPosition.x, targetBufferPosition.y);
}
tilePosition += DIR_E;
tilePosition += Direction::East;
targetBufferPosition.x += TILE_WIDTH;
}
// Return to start of row
tilePosition += Displacement(DIR_W) * columns;
tilePosition += Displacement(Direction::West) * columns;
targetBufferPosition.x -= columns * TILE_WIDTH;
// Jump to next row
@ -991,7 +990,7 @@ void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferP
// sprite screen position rather than tile position.
if (IsWall(tilePosition.x, tilePosition.y) && (IsWall(tilePosition.x + 1, tilePosition.y) || (tilePosition.x > 0 && IsWall(tilePosition.x - 1, tilePosition.y)))) { // Part of a wall aligned on the x-axis
if (IsWalkable(tilePosition.x + 1, tilePosition.y - 1) && IsWalkable(tilePosition.x, tilePosition.y - 1)) { // Has walkable area behind it
DrawDungeon(out, tilePosition + DIR_E, { targetBufferPosition.x + TILE_WIDTH, targetBufferPosition.y });
DrawDungeon(out, tilePosition + Direction::East, { targetBufferPosition.x + TILE_WIDTH, targetBufferPosition.y });
}
}
}
@ -999,11 +998,11 @@ void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferP
DrawDungeon(out, tilePosition, targetBufferPosition);
}
}
tilePosition += DIR_E;
tilePosition += Direction::East;
targetBufferPosition.x += TILE_WIDTH;
}
// Return to start of row
tilePosition += Displacement(DIR_W) * columns;
tilePosition += Displacement(Direction::West) * columns;
targetBufferPosition.x -= columns * TILE_WIDTH;
// Jump to next row
@ -1109,23 +1108,23 @@ void DrawGame(const Surface &fullOut, Point position)
if (CanPanelsCoverView()) {
if (zoomflag) {
if (chrflag || QuestLogIsOpen) {
position += Displacement(DIR_E) * 2;
position += Displacement(Direction::East) * 2;
columns -= 4;
sx += SPANEL_WIDTH - TILE_WIDTH / 2;
}
if (invflag || sbookflag) {
position += Displacement(DIR_E) * 2;
position += Displacement(Direction::East) * 2;
columns -= 4;
sx += -TILE_WIDTH / 2;
}
} else {
if (chrflag || QuestLogIsOpen) {
position += DIR_E;
position += Direction::East;
columns -= 2;
sx += -TILE_WIDTH / 2 / 2; // SPANEL_WIDTH accounted for in Zoom()
}
if (invflag || sbookflag) {
position += DIR_E;
position += Direction::East;
columns -= 2;
sx += -TILE_WIDTH / 2 / 2;
}
@ -1138,12 +1137,12 @@ void DrawGame(const Surface &fullOut, Point position)
switch (ScrollInfo._sdir) {
case SDIR_N:
sy -= TILE_HEIGHT;
position += DIR_N;
position += Direction::North;
rows += 2;
break;
case SDIR_NE:
sy -= TILE_HEIGHT;
position += DIR_N;
position += Direction::North;
columns++;
rows += 2;
break;
@ -1159,19 +1158,19 @@ void DrawGame(const Surface &fullOut, Point position)
break;
case SDIR_SW:
sx -= TILE_WIDTH;
position += DIR_W;
position += Direction::West;
columns++;
rows++;
break;
case SDIR_W:
sx -= TILE_WIDTH;
position += DIR_W;
position += Direction::West;
columns++;
break;
case SDIR_NW:
sx -= TILE_WIDTH / 2;
sy -= TILE_HEIGHT / 2;
position += DIR_NW;
position += Direction::NorthWest;
columns++;
rows++;
break;
@ -1403,19 +1402,19 @@ void DrawMain(int dwHgt, bool drawDesc, bool drawHp, bool drawMana, bool drawSba
Displacement GetOffsetForWalking(const AnimationInfo &animationInfo, const Direction dir, bool cameraMode /*= false*/)
{
// clang-format off
// DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_N, DIR_NE, DIR_E, DIR_SE,
// South, SouthWest, West, NorthWest, North, NorthEast, East, SouthEast,
constexpr Displacement StartOffset[8] = { { 0, -32 }, { 32, -16 }, { 32, -16 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -32, -16 }, { -32, -16 } };
constexpr Displacement MovingOffset[8] = { { 0, 32 }, { -32, 16 }, { -64, 0 }, { -32, -16 }, { 0, -32 }, { 32, -16 }, { 64, 0 }, { 32, 16 } };
// clang-format on
float fAnimationProgress = animationInfo.GetAnimationProgress();
Displacement offset = MovingOffset[dir];
Displacement offset = MovingOffset[static_cast<size_t>(dir)];
offset *= fAnimationProgress;
if (cameraMode) {
offset = -offset;
} else {
offset += StartOffset[dir];
offset += StartOffset[static_cast<size_t>(dir)];
}
return offset;
@ -1510,8 +1509,8 @@ void CalcViewportGeometry()
int lrow = tileRows - RowsCoveredByPanel();
// Center player tile on screen
tileShift += Displacement(DIR_W) * (tileColums / 2);
tileShift += Displacement(DIR_N) * (lrow / 2);
tileShift += Displacement(Direction::West) * (tileColums / 2);
tileShift += Displacement(Direction::North) * (lrow / 2);
tileRows *= 2;
@ -1525,7 +1524,7 @@ void CalcViewportGeometry()
}
} else if ((tileColums & 1) != 0 && (lrow & 1) != 0) {
// Offset tile to vertically align the player when both rows and colums are odd
tileShift += Displacement(DIR_N);
tileShift += Displacement(Direction::North);
tileRows++;
tileOffset.deltaY -= TILE_HEIGHT / 2;
}

2
Source/spells.cpp

@ -252,7 +252,7 @@ void DoResurrect(int pnum, uint16_t rid)
auto &target = Players[rid];
AddMissile(target.position.tile, target.position.tile, DIR_S, MIS_RESURRECTBEAM, TARGET_MONSTERS, pnum, 0, 0);
AddMissile(target.position.tile, target.position.tile, Direction::South, MIS_RESURRECTBEAM, TARGET_MONSTERS, pnum, 0, 0);
if (target._pHitPoints != 0)
return;

2
Source/themes.cpp

@ -846,7 +846,7 @@ void Theme_GoatShrine(int t)
for (int yy = themey - 1; yy <= themey + 1; yy++) {
for (int xx = themex - 1; xx <= themex + 1; xx++) {
if (dTransVal[xx][yy] == themes[t].ttval && IsTileNotSolid({ xx, yy }) && (xx != themex || yy != themey)) {
AddMonster({ xx, yy }, DIR_SW, themeVar1, true);
AddMonster({ xx, yy }, Direction::SouthWest, themeVar1, true);
}
}
}

52
Source/towners.cpp

@ -63,7 +63,7 @@ void LoadTownerAnimations(Towner &towner, const char *path, int frames, Directio
for (auto &animation : towner._tNAnim) {
animation = towner.data.get();
}
NewTownerAnim(towner, towner._tNAnim[dir], frames, delay);
NewTownerAnim(towner, towner.GetAnimationPointer(dir), frames, delay);
}
/**
@ -223,12 +223,12 @@ void InitCows(Towner &towner, const TownerData &townerData)
for (int i = 0; i < 8; i++) {
towner._tNAnim[i] = CelGetFrame(CowCels.get(), i);
}
NewTownerAnim(towner, towner._tNAnim[townerData.dir], 12, 3);
NewTownerAnim(towner, towner.GetAnimationPointer(townerData.dir), 12, 3);
towner._tAnimFrame = GenerateRnd(11) + 1;
towner.name = _("Cow");
const Point position = townerData.position;
const Point offset = position + CowOffsets[townerData.dir];
const Point offset = position + CowOffsets[static_cast<size_t>(townerData.dir)];
int index = -dMonster[position.x][position.y];
if (dMonster[position.x][offset.y] == 0)
dMonster[position.x][offset.y] = index;
@ -338,7 +338,7 @@ void TalkToBarOwner(Player &player, Towner &barOwner)
if (bannerQuest._qvar2 == 1 && player.TryRemoveInvItemById(IDI_BANNER)) {
bannerQuest._qactive = QUEST_DONE;
bannerQuest._qvar1 = 3;
SpawnUnique(UITEM_HARCREST, barOwner.position + DIR_SW);
SpawnUnique(UITEM_HARCREST, barOwner.position + Direction::SouthWest);
InitQTextMsg(TEXT_BANNER3);
return;
}
@ -384,7 +384,7 @@ void TalkToBlackSmith(Player &player, Towner &blackSmith)
if (Quests[Q_ROCK]._qvar2 == 1 && player.TryRemoveInvItemById(IDI_ROCK)) {
Quests[Q_ROCK]._qactive = QUEST_DONE;
SpawnUnique(UITEM_INFRARING, blackSmith.position + DIR_SW);
SpawnUnique(UITEM_INFRARING, blackSmith.position + Direction::SouthWest);
InitQTextMsg(TEXT_INFRA7);
return;
}
@ -404,7 +404,7 @@ void TalkToBlackSmith(Player &player, Towner &blackSmith)
if (Quests[Q_ANVIL]._qvar2 == 1 && player.TryRemoveInvItemById(IDI_ANVIL)) {
Quests[Q_ANVIL]._qactive = QUEST_DONE;
SpawnUnique(UITEM_GRISWOLD, blackSmith.position + DIR_SW);
SpawnUnique(UITEM_GRISWOLD, blackSmith.position + Direction::SouthWest);
InitQTextMsg(TEXT_ANVIL7);
return;
}
@ -494,7 +494,7 @@ void TalkToHealer(Player &player, Towner &healer)
if (Quests[Q_PWATER]._qactive == QUEST_DONE && Quests[Q_PWATER]._qvar1 != 2) {
Quests[Q_PWATER]._qvar1 = 2;
InitQTextMsg(TEXT_POISON5);
SpawnUnique(UITEM_TRING, healer.position + DIR_SW);
SpawnUnique(UITEM_TRING, healer.position + Direction::SouthWest);
return;
}
}
@ -650,11 +650,11 @@ void TalkToCowFarmer(Player &player, Towner &cowFarmer)
auto &quest = Quests[Q_JERSEY];
if (player.TryRemoveInvItemById(IDI_BROWNSUIT)) {
SpawnUnique(UITEM_BOVINE, cowFarmer.position + DIR_SE);
SpawnUnique(UITEM_BOVINE, cowFarmer.position + Direction::SouthEast);
InitQTextMsg(TEXT_JERSEY8);
quest._qactive = QUEST_DONE;
auto curFrame = cowFarmer._tAnimFrame;
LoadTownerAnimations(cowFarmer, "Towners\\Farmer\\mfrmrn2.CEL", 15, DIR_SW, 3);
LoadTownerAnimations(cowFarmer, "Towners\\Farmer\\mfrmrn2.CEL", 15, Direction::SouthWest, 3);
cowFarmer._tAnimFrame = std::min(curFrame, cowFarmer._tAnimLen);
return;
}
@ -737,7 +737,7 @@ void TalkToGirl(Player &player, Towner &girl)
quest._qlog = false;
quest._qactive = QUEST_DONE;
auto curFrame = girl._tAnimFrame;
LoadTownerAnimations(girl, "Towners\\Girl\\Girls1.CEL", 20, DIR_S, 6);
LoadTownerAnimations(girl, "Towners\\Girl\\Girls1.CEL", 20, Direction::South, 6);
girl._tAnimFrame = std::min(curFrame, girl._tAnimLen);
if (gbIsMultiplayer)
NetSendCmdQuest(true, quest);
@ -765,22 +765,22 @@ void TalkToGirl(Player &player, Towner &girl)
const TownerData TownersData[] = {
// clang-format off
// type position dir init talk
{ TOWN_SMITH, { 62, 63 }, DIR_SW, InitSmith, TalkToBlackSmith },
{ TOWN_HEALER, { 55, 79 }, DIR_SE, InitHealer, TalkToHealer },
{ TOWN_DEADGUY, { 24, 32 }, DIR_N, InitTownDead, TalkToDeadguy },
{ TOWN_TAVERN, { 55, 62 }, DIR_SW, InitBarOwner, TalkToBarOwner },
{ TOWN_STORY, { 62, 71 }, DIR_S, InitTeller, TalkToStoryteller },
{ TOWN_DRUNK, { 71, 84 }, DIR_S, InitDrunk, TalkToDrunk },
{ TOWN_WITCH, { 80, 20 }, DIR_S, InitWitch, TalkToWitch },
{ TOWN_BMAID, { 43, 66 }, DIR_S, InitBarmaid, TalkToBarmaid },
{ TOWN_PEGBOY, { 11, 53 }, DIR_S, InitBoy, TalkToBoy },
{ TOWN_COW, { 58, 16 }, DIR_SW, InitCows, TalkToCow },
{ TOWN_COW, { 56, 14 }, DIR_NW, InitCows, TalkToCow },
{ TOWN_COW, { 59, 20 }, DIR_N, InitCows, TalkToCow },
{ TOWN_COWFARM, { 61, 22 }, DIR_SW, InitCowFarmer, TalkToCowFarmer },
{ TOWN_FARMER, { 62, 16 }, DIR_S, InitFarmer, TalkToFarmer },
{ TOWN_GIRL, { 77, 43 }, DIR_S, InitGirl, TalkToGirl },
// type position dir init talk
{ TOWN_SMITH, { 62, 63 }, Direction::SouthWest, InitSmith, TalkToBlackSmith },
{ TOWN_HEALER, { 55, 79 }, Direction::SouthEast, InitHealer, TalkToHealer },
{ TOWN_DEADGUY, { 24, 32 }, Direction::North, InitTownDead, TalkToDeadguy },
{ TOWN_TAVERN, { 55, 62 }, Direction::SouthWest, InitBarOwner, TalkToBarOwner },
{ TOWN_STORY, { 62, 71 }, Direction::South, InitTeller, TalkToStoryteller },
{ TOWN_DRUNK, { 71, 84 }, Direction::South, InitDrunk, TalkToDrunk },
{ TOWN_WITCH, { 80, 20 }, Direction::South, InitWitch, TalkToWitch },
{ TOWN_BMAID, { 43, 66 }, Direction::South, InitBarmaid, TalkToBarmaid },
{ TOWN_PEGBOY, { 11, 53 }, Direction::South, InitBoy, TalkToBoy },
{ TOWN_COW, { 58, 16 }, Direction::SouthWest, InitCows, TalkToCow },
{ TOWN_COW, { 56, 14 }, Direction::NorthWest, InitCows, TalkToCow },
{ TOWN_COW, { 59, 20 }, Direction::North, InitCows, TalkToCow },
{ TOWN_COWFARM, { 61, 22 }, Direction::SouthWest, InitCowFarmer, TalkToCowFarmer },
{ TOWN_FARMER, { 62, 16 }, Direction::South, InitFarmer, TalkToFarmer },
{ TOWN_GIRL, { 77, 43 }, Direction::South, InitGirl, TalkToGirl },
// clang-format on
};

5
Source/towners.h

@ -59,6 +59,11 @@ struct Towner {
std::size_t animOrderSize;
void (*talk)(Player &player, Towner &towner);
_talker_id _ttype;
byte *GetAnimationPointer(Direction direction)
{
return this->_tNAnim[static_cast<size_t>(direction)];
}
};
extern Towner Towners[NUM_TOWNERS];

8
test/dead_test.cpp

@ -8,12 +8,12 @@ using namespace devilution;
TEST(Corpses, AddCorpse)
{
AddCorpse({ 21, 48 }, 8, DIR_W);
EXPECT_EQ(dCorpse[21][48], 8 + (DIR_W << 5));
AddCorpse({ 21, 48 }, 8, Direction::West);
EXPECT_EQ(dCorpse[21][48], 8 + (static_cast<int>(Direction::West) << 5));
}
TEST(Corpses, AddCorpse_OOB)
{
AddCorpse({ 21, 48 }, MaxCorpses + 1, DIR_W);
EXPECT_EQ(dCorpse[21][48], 0 + (DIR_W << 5));
AddCorpse({ 21, 48 }, MaxCorpses + 1, Direction::West);
EXPECT_EQ(dCorpse[21][48], 0 + (static_cast<int>(Direction::West) << 5));
}

148
test/missiles_test.cpp

@ -6,82 +6,86 @@ using namespace devilution;
TEST(Missiles, GetDirection8)
{
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 15, 15 }));
EXPECT_EQ(1, GetDirection({ 0, 0 }, { 0, 15 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 8, 15 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 8, 8 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 15, 8 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 15, 7 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 11, 7 }));
EXPECT_EQ(0, GetDirection({ 0, 0 }, { 8, 11 }));
EXPECT_EQ(4, GetDirection({ 15, 15 }, { 0, 0 }));
EXPECT_EQ(5, GetDirection({ 0, 15 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 8, 15 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 8, 8 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 15, 8 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 15, 7 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 11, 7 }, { 0, 0 }));
EXPECT_EQ(4, GetDirection({ 8, 11 }, { 0, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 15 }, { 15, 0 }));
EXPECT_EQ(7, GetDirection({ 0, 0 }, { 15, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 8 }, { 15, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 8 }, { 8, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 15 }, { 8, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 15 }, { 7, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 11 }, { 7, 0 }));
EXPECT_EQ(6, GetDirection({ 0, 8 }, { 11, 0 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 15, 15 }));
EXPECT_EQ(Direction::SouthWest, GetDirection({ 0, 0 }, { 0, 15 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 8, 15 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 8, 8 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 15, 8 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 15, 7 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 11, 7 }));
EXPECT_EQ(Direction::South, GetDirection({ 0, 0 }, { 8, 11 }));
EXPECT_EQ(Direction::North, GetDirection({ 15, 15 }, { 0, 0 }));
EXPECT_EQ(Direction::NorthEast, GetDirection({ 0, 15 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 8, 15 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 8, 8 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 15, 8 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 15, 7 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 11, 7 }, { 0, 0 }));
EXPECT_EQ(Direction::North, GetDirection({ 8, 11 }, { 0, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 15 }, { 15, 0 }));
EXPECT_EQ(Direction::SouthEast, GetDirection({ 0, 0 }, { 15, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 8 }, { 15, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 8 }, { 8, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 15 }, { 8, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 15 }, { 7, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 11 }, { 7, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 0, 8 }, { 11, 0 }));
EXPECT_EQ(0, GetDirection({ 1, 1 }, { 2, 2 }));
EXPECT_EQ(1, GetDirection({ 1, 1 }, { 1, 2 }));
EXPECT_EQ(2, GetDirection({ 1, 1 }, { 0, 2 }));
EXPECT_EQ(3, GetDirection({ 1, 1 }, { 0, 1 }));
EXPECT_EQ(4, GetDirection({ 1, 1 }, { 0, 0 }));
EXPECT_EQ(5, GetDirection({ 1, 1 }, { 1, 0 }));
EXPECT_EQ(6, GetDirection({ 1, 1 }, { 2, 0 }));
EXPECT_EQ(7, GetDirection({ 1, 1 }, { 2, 1 }));
EXPECT_EQ(Direction::South, GetDirection({ 1, 1 }, { 2, 2 }));
EXPECT_EQ(Direction::SouthWest, GetDirection({ 1, 1 }, { 1, 2 }));
EXPECT_EQ(Direction::West, GetDirection({ 1, 1 }, { 0, 2 }));
EXPECT_EQ(Direction::NorthWest, GetDirection({ 1, 1 }, { 0, 1 }));
EXPECT_EQ(Direction::North, GetDirection({ 1, 1 }, { 0, 0 }));
EXPECT_EQ(Direction::NorthEast, GetDirection({ 1, 1 }, { 1, 0 }));
EXPECT_EQ(Direction::East, GetDirection({ 1, 1 }, { 2, 0 }));
EXPECT_EQ(Direction::SouthEast, GetDirection({ 1, 1 }, { 2, 1 }));
EXPECT_EQ(Direction::SouthWest, GetDirection({ 0, 0 }, { 0, 0 })) << "GetDirection is expected to default to Direction::SouthWest when the points occupy the same tile";
}
TEST(Missiles, GetDirection16)
{
EXPECT_EQ(DIR16_S, GetDirection16({ 0, 0 }, { 15, 15 }));
EXPECT_EQ(DIR16_SW, GetDirection16({ 0, 0 }, { 0, 15 }));
EXPECT_EQ(DIR16_Sw, GetDirection16({ 0, 0 }, { 8, 15 }));
EXPECT_EQ(DIR16_S, GetDirection16({ 0, 0 }, { 8, 8 }));
EXPECT_EQ(DIR16_Se, GetDirection16({ 0, 0 }, { 15, 8 }));
EXPECT_EQ(DIR16_Se, GetDirection16({ 0, 0 }, { 15, 7 }));
EXPECT_EQ(DIR16_Se, GetDirection16({ 0, 0 }, { 11, 7 }));
EXPECT_EQ(DIR16_S, GetDirection16({ 0, 0 }, { 8, 11 }));
EXPECT_EQ(DIR16_N, GetDirection16({ 15, 15 }, { 0, 0 }));
EXPECT_EQ(DIR16_NE, GetDirection16({ 0, 15 }, { 0, 0 }));
EXPECT_EQ(DIR16_Ne, GetDirection16({ 8, 15 }, { 0, 0 }));
EXPECT_EQ(DIR16_N, GetDirection16({ 8, 8 }, { 0, 0 }));
EXPECT_EQ(DIR16_Nw, GetDirection16({ 15, 8 }, { 0, 0 }));
EXPECT_EQ(DIR16_Nw, GetDirection16({ 15, 7 }, { 0, 0 }));
EXPECT_EQ(DIR16_Nw, GetDirection16({ 11, 7 }, { 0, 0 }));
EXPECT_EQ(DIR16_N, GetDirection16({ 8, 11 }, { 0, 0 }));
EXPECT_EQ(DIR16_E, GetDirection16({ 0, 15 }, { 15, 0 }));
EXPECT_EQ(DIR16_SE, GetDirection16({ 0, 0 }, { 15, 0 }));
EXPECT_EQ(DIR16_sE, GetDirection16({ 0, 8 }, { 15, 0 }));
EXPECT_EQ(DIR16_E, GetDirection16({ 0, 8 }, { 8, 0 }));
EXPECT_EQ(DIR16_nE, GetDirection16({ 0, 15 }, { 8, 0 }));
EXPECT_EQ(DIR16_nE, GetDirection16({ 0, 15 }, { 7, 0 }));
EXPECT_EQ(DIR16_nE, GetDirection16({ 0, 11 }, { 7, 0 }));
EXPECT_EQ(DIR16_E, GetDirection16({ 0, 8 }, { 11, 0 }));
EXPECT_EQ(Direction16::DIR16_S, GetDirection16({ 0, 0 }, { 15, 15 }));
EXPECT_EQ(Direction16::DIR16_SW, GetDirection16({ 0, 0 }, { 0, 15 }));
EXPECT_EQ(Direction16::DIR16_Sw, GetDirection16({ 0, 0 }, { 8, 15 }));
EXPECT_EQ(Direction16::DIR16_S, GetDirection16({ 0, 0 }, { 8, 8 }));
EXPECT_EQ(Direction16::DIR16_Se, GetDirection16({ 0, 0 }, { 15, 8 }));
EXPECT_EQ(Direction16::DIR16_Se, GetDirection16({ 0, 0 }, { 15, 7 }));
EXPECT_EQ(Direction16::DIR16_Se, GetDirection16({ 0, 0 }, { 11, 7 }));
EXPECT_EQ(Direction16::DIR16_S, GetDirection16({ 0, 0 }, { 8, 11 }));
EXPECT_EQ(Direction16::DIR16_N, GetDirection16({ 15, 15 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_NE, GetDirection16({ 0, 15 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_Ne, GetDirection16({ 8, 15 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_N, GetDirection16({ 8, 8 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_Nw, GetDirection16({ 15, 8 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_Nw, GetDirection16({ 15, 7 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_Nw, GetDirection16({ 11, 7 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_N, GetDirection16({ 8, 11 }, { 0, 0 }));
EXPECT_EQ(Direction16::DIR16_E, GetDirection16({ 0, 15 }, { 15, 0 }));
EXPECT_EQ(Direction16::DIR16_SE, GetDirection16({ 0, 0 }, { 15, 0 }));
EXPECT_EQ(Direction16::DIR16_sE, GetDirection16({ 0, 8 }, { 15, 0 }));
EXPECT_EQ(Direction16::DIR16_E, GetDirection16({ 0, 8 }, { 8, 0 }));
EXPECT_EQ(Direction16::DIR16_nE, GetDirection16({ 0, 15 }, { 8, 0 }));
EXPECT_EQ(Direction16::DIR16_nE, GetDirection16({ 0, 15 }, { 7, 0 }));
EXPECT_EQ(Direction16::DIR16_nE, GetDirection16({ 0, 11 }, { 7, 0 }));
EXPECT_EQ(Direction16::DIR16_E, GetDirection16({ 0, 8 }, { 11, 0 }));
EXPECT_EQ(Direction16::DIR16_S, GetDirection16({ 2, 2 }, { 3, 3 }));
EXPECT_EQ(Direction16::DIR16_Sw, GetDirection16({ 2, 2 }, { 3, 4 }));
EXPECT_EQ(Direction16::DIR16_SW, GetDirection16({ 2, 2 }, { 2, 4 }));
EXPECT_EQ(Direction16::DIR16_sW, GetDirection16({ 2, 2 }, { 1, 4 }));
EXPECT_EQ(Direction16::DIR16_W, GetDirection16({ 2, 2 }, { 1, 3 }));
EXPECT_EQ(Direction16::DIR16_nW, GetDirection16({ 2, 2 }, { 0, 3 }));
EXPECT_EQ(Direction16::DIR16_NW, GetDirection16({ 2, 2 }, { 0, 2 }));
EXPECT_EQ(Direction16::DIR16_Nw, GetDirection16({ 2, 2 }, { 0, 1 }));
EXPECT_EQ(Direction16::DIR16_N, GetDirection16({ 2, 2 }, { 1, 1 }));
EXPECT_EQ(Direction16::DIR16_Ne, GetDirection16({ 2, 2 }, { 1, 0 }));
EXPECT_EQ(Direction16::DIR16_NE, GetDirection16({ 2, 2 }, { 2, 0 }));
EXPECT_EQ(Direction16::DIR16_nE, GetDirection16({ 2, 2 }, { 3, 0 }));
EXPECT_EQ(Direction16::DIR16_E, GetDirection16({ 2, 2 }, { 3, 1 }));
EXPECT_EQ(Direction16::DIR16_sE, GetDirection16({ 2, 2 }, { 4, 1 }));
EXPECT_EQ(Direction16::DIR16_SE, GetDirection16({ 2, 2 }, { 4, 2 }));
EXPECT_EQ(Direction16::DIR16_Se, GetDirection16({ 2, 2 }, { 4, 3 }));
EXPECT_EQ(DIR16_S, GetDirection16({ 2, 2 }, { 3, 3 }));
EXPECT_EQ(DIR16_Sw, GetDirection16({ 2, 2 }, { 3, 4 }));
EXPECT_EQ(DIR16_SW, GetDirection16({ 2, 2 }, { 2, 4 }));
EXPECT_EQ(DIR16_sW, GetDirection16({ 2, 2 }, { 1, 4 }));
EXPECT_EQ(DIR16_W, GetDirection16({ 2, 2 }, { 1, 3 }));
EXPECT_EQ(DIR16_nW, GetDirection16({ 2, 2 }, { 0, 3 }));
EXPECT_EQ(DIR16_NW, GetDirection16({ 2, 2 }, { 0, 2 }));
EXPECT_EQ(DIR16_Nw, GetDirection16({ 2, 2 }, { 0, 1 }));
EXPECT_EQ(DIR16_N, GetDirection16({ 2, 2 }, { 1, 1 }));
EXPECT_EQ(DIR16_Ne, GetDirection16({ 2, 2 }, { 1, 0 }));
EXPECT_EQ(DIR16_NE, GetDirection16({ 2, 2 }, { 2, 0 }));
EXPECT_EQ(DIR16_nE, GetDirection16({ 2, 2 }, { 3, 0 }));
EXPECT_EQ(DIR16_E, GetDirection16({ 2, 2 }, { 3, 1 }));
EXPECT_EQ(DIR16_sE, GetDirection16({ 2, 2 }, { 4, 1 }));
EXPECT_EQ(DIR16_SE, GetDirection16({ 2, 2 }, { 4, 2 }));
EXPECT_EQ(DIR16_Se, GetDirection16({ 2, 2 }, { 4, 3 }));
EXPECT_EQ(Direction16::DIR16_Sw, GetDirection16({ 0, 0 }, { 0, 0 })) << "GetDirection16 is expected to default to DIR16_Sw when the points occupy the same tile";
}

22
test/path_test.cpp

@ -17,29 +17,29 @@ TEST(PathTest, Heuristics)
Point destination = source;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 0) << "Wrong cost for travelling to the same tile";
destination = source + Direction::DIR_NE;
destination = source + Direction::NorthEast;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
destination = source + Direction::DIR_SE;
destination = source + Direction::SouthEast;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
destination = source + Direction::DIR_SW;
destination = source + Direction::SouthWest;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
destination = source + Direction::DIR_NW;
destination = source + Direction::NorthWest;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
destination = source + Direction::DIR_N;
destination = source + Direction::North;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
destination = source + Direction::DIR_E;
destination = source + Direction::East;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
destination = source + Direction::DIR_S;
destination = source + Direction::South;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
destination = source + Direction::DIR_W;
destination = source + Direction::West;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
destination = source + Direction::DIR_SW + Direction::DIR_SE; // Effectively the same as DIR_S
destination = source + Direction::SouthWest + Direction::SouthEast; // Effectively the same as Direction::South
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
destination = source + Direction::DIR_NE + Direction::DIR_N;
destination = source + Direction::NorthEast + Direction::North;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 6) << "Wrong cost for travelling to a { 2, 1 } offset";
destination = source + Direction::DIR_SE + Direction::DIR_SE;
destination = source + Direction::SouthEast + Direction::SouthEast;
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to a { 2, 0 } offset";
}

2
test/player_test.cpp

@ -15,7 +15,7 @@ int RunBlockTest(int frames, int flags)
player._pHFrames = frames;
player._pIFlags = flags;
StartPlrHit(pnum, 5, Direction::DIR_S);
StartPlrHit(pnum, 5, false);
int i = 1;
for (; i < 100; i++) {

Loading…
Cancel
Save