Browse Source

Add helpers for checking object type (#3357)

* Add helper to test if an object is a trap source
* Add helper to test if an object is a barrel
* Add helper to test if an object is a crucifix
* Add helpers to check if an object is a chest (and statuses)
* Add helpers to check if an object is a (basic) shrine
pull/3123/head
Andrew James 4 years ago committed by GitHub
parent
commit
021c7a652f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      Source/engine.h
  2. 8
      Source/missiles.cpp
  3. 4
      Source/msg.cpp
  4. 43
      Source/objects.cpp
  5. 70
      Source/objects.h

8
Source/engine.h

@ -45,25 +45,25 @@
namespace devilution {
template <typename V, typename X>
bool IsAnyOf(const V &v, X x)
constexpr bool IsAnyOf(const V &v, X x)
{
return v == x;
}
template <typename V, typename X, typename... Xs>
bool IsAnyOf(const V &v, X x, Xs... xs)
constexpr bool IsAnyOf(const V &v, X x, Xs... xs)
{
return IsAnyOf(v, x) || IsAnyOf(v, xs...);
}
template <typename V, typename X>
bool IsNoneOf(const V &v, X x)
constexpr bool IsNoneOf(const V &v, X x)
{
return v != x;
}
template <typename V, typename X, typename... Xs>
bool IsNoneOf(const V &v, X x, Xs... xs)
constexpr bool IsNoneOf(const V &v, X x, Xs... xs)
{
return IsNoneOf(v, x) && IsNoneOf(v, xs...);
}

8
Source/missiles.cpp

@ -3042,11 +3042,11 @@ void MI_Lightball(Missile &missile)
MoveMissileAndCheckMissileCol(missile, missile._midam, missile._midam, false, false);
if (missile._miHitFlag)
missile._mirange = j;
int8_t obj = dObject[tx][ty];
if (obj != 0 && missile.position.tile == Point { tx, ty }) {
int oi = (obj > 0) ? (obj - 1) : -(obj + 1);
if (Objects[oi]._otype == OBJ_SHRINEL || Objects[oi]._otype == OBJ_SHRINER)
if (missile.position.tile == Point { tx, ty }) {
int8_t oi = abs(dObject[tx][ty]) - 1;
if (oi >= 0 && Objects[oi].IsShrine()) {
missile._mirange = j;
}
}
if (missile._mirange == 0)
missile._miDelFlag = true;

4
Source/msg.cpp

@ -2280,9 +2280,9 @@ void DeltaLoadLevel()
}
for (int i = 0; i < ActiveObjectCount; i++) {
int ot = Objects[ActiveObjects[i]]._otype;
if (ot == OBJ_TRAPL || ot == OBJ_TRAPR)
if (Objects[ActiveObjects[i]].IsTrap()) {
OperateTrap(Objects[ActiveObjects[i]]);
}
}
}
deltaload = false;

43
Source/objects.cpp

@ -635,7 +635,7 @@ void AddChestTraps()
for (int i = 0; i < MAXDUNX; i++) { // NOLINT(modernize-loop-convert)
if (dObject[i][j] > 0) {
int8_t oi = dObject[i][j] - 1;
if (Objects[oi]._otype >= OBJ_CHEST1 && Objects[oi]._otype <= OBJ_CHEST3 && !Objects[oi]._oTrapFlag && GenerateRnd(100) < 10) {
if (Objects[oi].IsUntrappedChest() && GenerateRnd(100) < 10) {
switch (Objects[oi]._otype) {
case OBJ_CHEST1:
Objects[oi]._otype = OBJ_TCHEST1;
@ -2365,7 +2365,7 @@ void OperateChest(int pnum, int i, bool sendmsg)
CreateRndUseful(Objects[i].position, sendmsg);
}
}
if (Objects[i]._oTrapFlag && Objects[i]._otype >= OBJ_TCHEST1 && Objects[i]._otype <= OBJ_TCHEST3) {
if (Objects[i].IsTrappedChest()) {
auto &player = Players[pnum];
Direction mdir = GetDirection(Objects[i].position, player.position.tile);
missile_id mtype;
@ -2854,7 +2854,7 @@ bool OperateShrineThaumaturgic(int pnum)
for (int j = 0; j < ActiveObjectCount; j++) {
int v1 = ActiveObjects[j];
assert(v1 >= 0 && v1 < MAXOBJECTS);
if (IsAnyOf(Objects[v1]._otype, OBJ_CHEST1, OBJ_CHEST2, OBJ_CHEST3, OBJ_TCHEST1, OBJ_TCHEST2, OBJ_TCHEST3) && Objects[v1]._oSelFlag == 0) {
if (Objects[v1].IsChest() && Objects[v1]._oSelFlag == 0) {
Objects[v1]._oRndSeed = AdvanceRndSeed();
Objects[v1]._oSelFlag = 1;
Objects[v1]._oAnimFrame -= 2;
@ -4101,7 +4101,7 @@ bool AreAllCruxesOfTypeBroken(int cruxType)
{
for (int j = 0; j < ActiveObjectCount; j++) {
const auto &testObject = Objects[ActiveObjects[j]];
if (IsNoneOf(testObject._otype, OBJ_CRUX1, OBJ_CRUX2, OBJ_CRUX3))
if (!testObject.IsCrux())
continue; // Not a Crux object, keep searching
if (cruxType != testObject._oVar8 || testObject._oBreak == -1)
continue; // Found either a different crux or a previously broken crux, keep searching
@ -4338,7 +4338,7 @@ bool Object::IsDisabled() const
if (IsAnyOf(_otype, _object_id::OBJ_GOATSHRINE, _object_id::OBJ_CAULDRON)) {
return true;
}
if (IsNoneOf(_otype, _object_id::OBJ_SHRINEL, _object_id::OBJ_SHRINER)) {
if (!IsShrine()) {
return false;
}
return IsAnyOf(static_cast<shrine_type>(_oVar1), shrine_type::ShrineFascinating, shrine_type::ShrineOrnate, shrine_type::ShrineSacred);
@ -5015,21 +5015,15 @@ void TryDisarm(int pnum, int i)
return;
}
for (int j = 0; j < ActiveObjectCount; j++) {
bool checkflag = false;
int oi = ActiveObjects[j];
int oti = Objects[oi]._otype;
if (oti == OBJ_TRAPL)
checkflag = true;
if (oti == OBJ_TRAPR)
checkflag = true;
if (checkflag && dObject[Objects[oi]._oVar1][Objects[oi]._oVar2] - 1 == i) {
Objects[oi]._oVar4 = 1;
Object &trap = Objects[ActiveObjects[j]];
if (trap.IsTrap() && dObject[trap._oVar1][trap._oVar2] - 1 == i) {
trap._oVar4 = 1;
Objects[i]._oTrapFlag = false;
}
}
int oti = Objects[i]._otype;
if (oti >= OBJ_TCHEST1 && oti <= OBJ_TCHEST3)
if (Objects[i].IsTrappedChest()) {
Objects[i]._oTrapFlag = false;
}
}
int ItemMiscIdIdx(item_misc_id imiscid)
@ -5268,25 +5262,18 @@ void BreakObject(int pnum, int oi)
objdam += player._pDamageMod + player._pIBonusDamMod + objdam * player._pIBonusDam / 100;
}
switch (Objects[oi]._otype) {
case OBJ_CRUX1:
case OBJ_CRUX2:
case OBJ_CRUX3:
BreakCrux(Objects[oi]);
break;
case OBJ_BARREL:
case OBJ_BARRELEX:
if (Objects[oi].IsBarrel()) {
BreakBarrel(pnum, oi, objdam, false, true);
break;
default:
break;
} else if (Objects[oi].IsCrux()) {
BreakCrux(Objects[oi]);
}
}
void SyncBreakObj(int pnum, int oi)
{
if (Objects[oi]._otype >= OBJ_BARREL && Objects[oi]._otype <= OBJ_BARRELEX)
if (Objects[oi].IsBarrel()) {
BreakBarrel(pnum, oi, 0, true, false);
}
}
void SyncObjectAnim(Object &object)

70
Source/objects.h

@ -127,14 +127,82 @@ struct Object {
*/
[[nodiscard]] bool IsDisabled() const;
/**
* @brief Check if this object is barrel (or explosive barrel)
* @return True if the object is one of the barrel types (see _object_id)
*/
[[nodiscard]] constexpr bool IsBarrel() const
{
return IsAnyOf(_otype, _object_id::OBJ_BARREL, _object_id::OBJ_BARRELEX);
}
/**
* @brief Check if this object is a chest (or trapped chest).
*
* Trapped chests get their base type change in addition to having the trap flag set, but if they get "refilled" by
* a Thaumaturgic shrine the base type is not reverted. This means you need to consider both the base type and the
* trap flag to differentiate between chests that are currently trapped and chests which have never been trapped.
*
* @return True if the object is any of the chest types (see _object_id)
*/
[[nodiscard]] constexpr bool IsChest() const
{
return IsAnyOf(_otype, _object_id::OBJ_CHEST1, _object_id::OBJ_CHEST2, _object_id::OBJ_CHEST3, _object_id::OBJ_TCHEST1, _object_id::OBJ_TCHEST2, _object_id::OBJ_TCHEST3);
}
/**
* @brief Check if this object is a trapped chest (specifically a chest which is currently trapped).
* @return True if the object is one of the trapped chest types (see _object_id) and has an active trap.
*/
[[nodiscard]] constexpr bool IsTrappedChest() const
{
return IsAnyOf(_otype, _object_id::OBJ_TCHEST1, _object_id::OBJ_TCHEST2, _object_id::OBJ_TCHEST3) && _oTrapFlag;
}
/**
* @brief Check if this object is an untrapped chest (specifically a chest which has not been trapped).
* @return True if the object is one of the untrapped chest types (see _object_id) and has no active trap.
*/
[[nodiscard]] constexpr bool IsUntrappedChest() const
{
return IsAnyOf(_otype, _object_id::OBJ_CHEST1, _object_id::OBJ_CHEST2, _object_id::OBJ_CHEST3) && !_oTrapFlag;
}
/**
* @brief Check if this object is a crucifix
* @return True if the object is one of the crux types (see _object_id)
*/
[[nodiscard]] constexpr bool IsCrux() const
{
return IsAnyOf(_otype, _object_id::OBJ_CRUX1, _object_id::OBJ_CRUX2, _object_id::OBJ_CRUX3);
}
/**
* @brief Check if this object is a door
* @return True if the object is one of the door types (see _object_id)
*/
bool IsDoor() const
[[nodiscard]] constexpr bool IsDoor() const
{
return IsAnyOf(_otype, _object_id::OBJ_L1LDOOR, _object_id::OBJ_L1RDOOR, _object_id::OBJ_L2LDOOR, _object_id::OBJ_L2RDOOR, _object_id::OBJ_L3LDOOR, _object_id::OBJ_L3RDOOR);
}
/**
* @brief Check if this object is a shrine
* @return True if the object is one of the shrine types (see _object_id)
*/
[[nodiscard]] constexpr bool IsShrine() const
{
return IsAnyOf(_otype, _object_id::OBJ_SHRINEL, _object_id::OBJ_SHRINER);
}
/**
* @brief Check if this object is a trap source
* @return True if the object is one of the trap types (see _object_id)
*/
[[nodiscard]] constexpr bool IsTrap() const
{
return IsAnyOf(_otype, _object_id::OBJ_TRAPL, _object_id::OBJ_TRAPR);
}
};
extern Object Objects[MAXOBJECTS];

Loading…
Cancel
Save