mirror of
https://github.com/diasurgical/DevilutionX.git
synced 2026-10-11 22:29:54 +00:00
FixedPoint: Implement comparison with int
This commit is contained in:
+2
-2
@@ -543,7 +543,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState)
|
||||
}
|
||||
}
|
||||
// Disallow player from accessing escape menu during the frames before the death message appears
|
||||
if (vkey == SDLK_ESCAPE && MyPlayer->_pHitPoints > Fixed26_6::fromInt(0)) {
|
||||
if (vkey == SDLK_ESCAPE && MyPlayer->_pHitPoints > 0) {
|
||||
if (!PressEscKey()) {
|
||||
LastPlayerAction = PlayerActionType::None;
|
||||
gamemenu_on();
|
||||
@@ -3188,7 +3188,7 @@ void LoadGameLevelSyncPlayerEntry(lvl_entry lvldir)
|
||||
{
|
||||
for (Player &player : Players) {
|
||||
if (player.plractive && player.isOnActiveLevel() && (!player._pLvlChanging || &player == MyPlayer)) {
|
||||
if (player._pHitPoints > Fixed26_6::fromInt(0)) {
|
||||
if (player._pHitPoints > 0) {
|
||||
if (lvldir != ENTRY_LOAD)
|
||||
SyncInitPlrPos(player);
|
||||
} else {
|
||||
|
||||
@@ -62,7 +62,7 @@ std::string DebugCmdChangeHealth(int change)
|
||||
|
||||
Fixed26_6 newHealth = myPlayer._pHitPoints + Fixed26_6::fromInt(change);
|
||||
SetPlayerHitPoints(myPlayer, newHealth);
|
||||
if (newHealth <= Fixed26_6::fromInt(0))
|
||||
if (newHealth <= 0)
|
||||
SyncPlrKill(myPlayer, DeathReason::MonsterOrTrap);
|
||||
|
||||
return StrCat("Changed life by ", change);
|
||||
|
||||
+2
-2
@@ -3688,7 +3688,7 @@ void ProcessStoneCurse(Missile &missile)
|
||||
{
|
||||
missile.duration--;
|
||||
Monster &monster = Monsters[missile.var2];
|
||||
if (monster.hitPoints == Fixed26_6::fromInt(0) && missile._miAnimType != MissileGraphicID::StoneCurseShatter) {
|
||||
if (monster.hitPoints == 0 && missile._miAnimType != MissileGraphicID::StoneCurseShatter) {
|
||||
missile.setDefaultFrameGroup();
|
||||
missile._miDrawFlag = true;
|
||||
missile.setAnimation(MissileGraphicID::StoneCurseShatter);
|
||||
@@ -3701,7 +3701,7 @@ void ProcessStoneCurse(Missile &missile)
|
||||
|
||||
if (missile.duration == 0) {
|
||||
missile._miDelFlag = true;
|
||||
if (monster.hitPoints > Fixed26_6::fromInt(0)) {
|
||||
if (monster.hitPoints > 0) {
|
||||
monster.mode = static_cast<MonsterMode>(missile.var1);
|
||||
monster.animInfo.isPetrified = false;
|
||||
} else {
|
||||
|
||||
+5
-5
@@ -1562,7 +1562,7 @@ bool MonsterDelay(Monster &monster)
|
||||
|
||||
void MonsterPetrified(Monster &monster)
|
||||
{
|
||||
if (monster.hitPoints <= Fixed26_6::fromInt(0)) {
|
||||
if (monster.hitPoints <= 0) {
|
||||
dMonster[monster.position.tile.x][monster.position.tile.y] = 0;
|
||||
MarkWalkabilityChanged();
|
||||
monster.isInvalid = true;
|
||||
@@ -4060,7 +4060,7 @@ void M_StartKill(Monster &monster, const Player &player)
|
||||
|
||||
void M_SyncStartKill(Monster &monster, Point position, const Player &player)
|
||||
{
|
||||
if (monster.hitPoints == Fixed26_6::fromInt(0) || monster.mode == MonsterMode::Death) {
|
||||
if (monster.hitPoints == 0 || monster.mode == MonsterMode::Death) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4682,7 +4682,7 @@ Monster *FindGolemForPlayer(const Player &player)
|
||||
continue;
|
||||
if (monster.goalVar3 != player.getId())
|
||||
continue;
|
||||
if (monster.hitPoints == Fixed26_6::fromInt(0))
|
||||
if (monster.hitPoints == 0)
|
||||
continue;
|
||||
return &monster;
|
||||
}
|
||||
@@ -4820,14 +4820,14 @@ void SpawnGolem(const Player &player, Point position, uint8_t spellLevel)
|
||||
// 1. Prefer MonsterIndex = PlayerIndex for vanilla compatibility
|
||||
if (player.getId() < ReservedMonsterSlotsForGolems) {
|
||||
Monster &reservedGolem = Monsters[player.getId()];
|
||||
if (reservedGolem.position.tile == GolemHoldingCell || reservedGolem.hitPoints == Fixed26_6::fromInt(0))
|
||||
if (reservedGolem.position.tile == GolemHoldingCell || reservedGolem.hitPoints == 0)
|
||||
golem = &reservedGolem;
|
||||
}
|
||||
// 2. Use reserved slots, so additional Monsters can spawn
|
||||
if (golem == nullptr) {
|
||||
for (int i = 0; i < ReservedMonsterSlotsForGolems; i++) {
|
||||
Monster &reservedGolem = Monsters[i];
|
||||
if (reservedGolem.position.tile == GolemHoldingCell || reservedGolem.hitPoints == Fixed26_6::fromInt(0)) {
|
||||
if (reservedGolem.position.tile == GolemHoldingCell || reservedGolem.hitPoints == 0) {
|
||||
golem = &reservedGolem;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace {
|
||||
bool IsEnemyValid(size_t enemyId, bool checkMonsterTable)
|
||||
{
|
||||
if (enemyId < MaxMonsters)
|
||||
return !checkMonsterTable || Monsters[enemyId].hitPoints > Fixed26_6::fromInt(0);
|
||||
return !checkMonsterTable || Monsters[enemyId].hitPoints > 0;
|
||||
const size_t playerId = enemyId - MaxMonsters;
|
||||
return playerId < Players.size() && Players[playerId].plractive;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1027,7 +1027,7 @@ void DeltaLeaveSync(uint8_t bLevel)
|
||||
for (size_t i = 0; i < ActiveMonsterCount; i++) {
|
||||
const unsigned ma = ActiveMonsters[i];
|
||||
Monster &monster = Monsters[ma];
|
||||
if (monster.hitPoints == Fixed26_6::fromInt(0))
|
||||
if (monster.hitPoints == 0)
|
||||
continue;
|
||||
DMonsterStr &delta = deltaLevel.monster[ma];
|
||||
delta.position = monster.position.tile;
|
||||
@@ -1930,7 +1930,7 @@ size_t OnResurrect(const TCmdParam1 &message, Player &caster)
|
||||
|
||||
SpawnResurrectBeam(caster, target);
|
||||
|
||||
if (&target == MyPlayer && target._pHitPoints <= Fixed26_6::fromInt(0)) {
|
||||
if (&target == MyPlayer && target._pHitPoints <= 0) {
|
||||
NetSendCmd(true, CMD_PLRALIVE);
|
||||
}
|
||||
|
||||
@@ -2053,7 +2053,7 @@ size_t OnMonstDamage(const TCmdMonDamage &message, Player &player)
|
||||
if (player.isOnActiveLevel() && leveltype != DTYPE_TOWN && monsterIdx < MaxMonsters) {
|
||||
Monster &monster = Monsters[monsterIdx];
|
||||
monster.tag(player);
|
||||
if (monster.hitPoints > Fixed26_6::fromInt(0)) {
|
||||
if (monster.hitPoints > 0) {
|
||||
monster.hitPoints -= Fixed26_6::fromRaw(Swap32LE(message.dwDam));
|
||||
if (monster.hitPoints.whole() < 1)
|
||||
monster.hitPoints = Fixed26_6::fromInt(1);
|
||||
|
||||
+1
-1
@@ -3145,7 +3145,7 @@ void OperateBookcase(Object &bookcase, bool sendmsg, bool sendLootMsg)
|
||||
if (zhar.mode == MonsterMode::Stand // prevents playing the "angry" message for the second time if zhar got aggroed by losing vision and talking again
|
||||
&& zhar.uniqueType == UniqueMonsterType::Zhar
|
||||
&& zhar.activeForTicks == UINT8_MAX
|
||||
&& zhar.hitPoints > Fixed26_6::fromInt(0)) {
|
||||
&& zhar.hitPoints > 0) {
|
||||
zhar.talkMsg = TEXT_ZHAR2;
|
||||
M_StartStand(zhar, zhar.direction); // BUGFIX: first parameter in call to M_StartStand should be MAX_PLRS, not 0. (fixed)
|
||||
zhar.goal = MonsterGoal::Attack;
|
||||
|
||||
@@ -185,7 +185,7 @@ void DrawPartyMemberInfoPanel(const Surface &out)
|
||||
const PlayerSpriteData &spriteData = GetPlayerSpriteDataForClass(player._pClass);
|
||||
Point offset = (player.isOnLevel(0)) ? spriteData.partyOffsetTown : spriteData.partyOffsetDungeon;
|
||||
|
||||
if (player._pHitPoints <= Fixed26_6::fromInt(0) && IsPlayerUnarmed(player))
|
||||
if (player._pHitPoints <= 0 && IsPlayerUnarmed(player))
|
||||
offset = spriteData.partyOffsetDead;
|
||||
|
||||
// Calculate the players portait position
|
||||
@@ -218,7 +218,7 @@ void DrawPartyMemberInfoPanel(const Surface &out)
|
||||
}
|
||||
|
||||
// Check to see if the player is dead and if so we draw a half transparent red rect over the portrait
|
||||
if (player._pHitPoints <= Fixed26_6::fromInt(0)) {
|
||||
if (player._pHitPoints <= 0) {
|
||||
DrawHalfTransparentRectTo(
|
||||
frameSubregion,
|
||||
0, 0,
|
||||
@@ -230,7 +230,7 @@ void DrawPartyMemberInfoPanel(const Surface &out)
|
||||
// Add to the position before continuing to the next item
|
||||
pos.y += PortraitFrameSize.height;
|
||||
|
||||
if (player._pMaxMana > Fixed26_6::fromInt(0)) {
|
||||
if (player._pMaxMana > 0) {
|
||||
// Get the players remaining mana
|
||||
const int manaTicks = ((player._pMana.raw() * PortraitFrameSize.width) + (player._pMaxMana.raw() / 2)) / player._pMaxMana.raw();
|
||||
const uint8_t manaBarColor = PAL8_BLUE + 3;
|
||||
|
||||
+3
-3
@@ -2822,7 +2822,7 @@ void ApplyPlrDamage(DamageType damageType, Player &player, Fixed26_6 dam, int mi
|
||||
if (&player == MyPlayer && !player.hasNoLife()) {
|
||||
lua::OnPlayerTakeDamage(&player, totalDamage.raw(), static_cast<int>(damageType));
|
||||
}
|
||||
if (totalDamage > Fixed26_6::fromInt(0) && player.pManaShield && HasNoneOf(player._pIFlags, ItemSpecialEffect::NoMana)) {
|
||||
if (totalDamage > 0 && player.pManaShield && HasNoneOf(player._pIFlags, ItemSpecialEffect::NoMana)) {
|
||||
const uint8_t manaShieldLevel = player._pSplLvl[static_cast<int8_t>(SpellID::ManaShield)];
|
||||
if (manaShieldLevel > 0) {
|
||||
totalDamage += totalDamage / -player.GetManaShieldDamageReduction();
|
||||
@@ -2845,7 +2845,7 @@ void ApplyPlrDamage(DamageType damageType, Player &player, Fixed26_6 dam, int mi
|
||||
}
|
||||
}
|
||||
|
||||
if (totalDamage == Fixed26_6::fromInt(0))
|
||||
if (totalDamage == 0)
|
||||
return;
|
||||
|
||||
RedrawComponent(PanelDrawComponent::Health);
|
||||
@@ -3459,7 +3459,7 @@ void PlayDungMsgs()
|
||||
} else if (!setlevel && currlevel == 16 && !myPlayer._pLvlVisited[16] && (myPlayer.pDungMsgs & DungMsgDiablo) == 0) {
|
||||
for (auto &monster : Monsters) {
|
||||
if (monster.type().type != MT_DIABLO) continue;
|
||||
if (monster.hitPoints > Fixed26_6::fromInt(0)) {
|
||||
if (monster.hitPoints > 0) {
|
||||
sfxdelay = 40;
|
||||
sfxdnum = SfxID::DiabloGreeting;
|
||||
myPlayer.pDungMsgs |= DungMsgDiablo;
|
||||
|
||||
+2
-2
@@ -682,7 +682,7 @@ public:
|
||||
*/
|
||||
int UpdateHitPointPercentage()
|
||||
{
|
||||
if (_pMaxHP <= Fixed26_6::fromInt(0)) { // divide by zero guard
|
||||
if (_pMaxHP <= 0) { // divide by zero guard
|
||||
_pHPPer = 0;
|
||||
} else {
|
||||
// Maximum achievable HP is approximately 1200. Diablo uses fixed point integers where the last 6 bits are
|
||||
@@ -696,7 +696,7 @@ public:
|
||||
|
||||
int UpdateManaPercentage()
|
||||
{
|
||||
if (_pMaxMana <= Fixed26_6::fromInt(0)) {
|
||||
if (_pMaxMana <= 0) {
|
||||
_pManaPer = 0;
|
||||
} else {
|
||||
_pManaPer = std::clamp<int>(_pMana.raw() * 81 / _pMaxMana.raw(), 0, 81);
|
||||
|
||||
@@ -100,7 +100,7 @@ void DrawMonsterHealthBar(const Surface &out)
|
||||
if (monster.hitPoints > monster.maxHitPoints) {
|
||||
multiplier = monster.hitPoints.raw() / monster.maxHitPoints.raw();
|
||||
currLife = monster.hitPoints - monster.maxHitPoints * multiplier;
|
||||
if (currLife == Fixed26_6::fromInt(0) && multiplier > 0) {
|
||||
if (currLife == 0 && multiplier > 0) {
|
||||
multiplier--;
|
||||
currLife = monster.maxHitPoints;
|
||||
}
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ void SyncPlrInv(TSyncHeader *pHdr)
|
||||
void SyncMonster(bool isOwner, const TSyncMonster &monsterSync)
|
||||
{
|
||||
Monster &monster = Monsters[monsterSync._mndx];
|
||||
if (monster.hitPoints <= Fixed26_6::fromInt(0) || monster.mode == MonsterMode::Death) {
|
||||
if (monster.hitPoints <= 0 || monster.mode == MonsterMode::Death) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,81 @@ template <typename StorageT, unsigned FractionalBits>
|
||||
return FixedPoint<decltype(raw), FractionalBits>::fromRaw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares against a plain `int`, treated as a whole number of units (as if by `fromInt`).
|
||||
*/
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator==(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return a == FixedPoint<StorageT, FractionalBits>::fromInt(whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator==(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return a == whole;
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator!=(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return !(a == whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator!=(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return !(a == whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator<(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return a < FixedPoint<StorageT, FractionalBits>::fromInt(whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator<(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return a > whole;
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator<=(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return a <= FixedPoint<StorageT, FractionalBits>::fromInt(whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator<=(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return a >= whole;
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator>(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return a > FixedPoint<StorageT, FractionalBits>::fromInt(whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator>(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return a < whole;
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator>=(FixedPoint<StorageT, FractionalBits> a, int whole)
|
||||
{
|
||||
return a >= FixedPoint<StorageT, FractionalBits>::fromInt(whole);
|
||||
}
|
||||
|
||||
template <typename StorageT, unsigned FractionalBits>
|
||||
[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool operator>=(int whole, FixedPoint<StorageT, FractionalBits> a)
|
||||
{
|
||||
return a <= whole;
|
||||
}
|
||||
|
||||
using Fixed10_6 = FixedPoint<int16_t, 6>;
|
||||
using Fixed26_6 = FixedPoint<int32_t, 6>;
|
||||
|
||||
|
||||
@@ -146,5 +146,26 @@ TEST(FixedPointTest, CompoundAssignmentNarrowsBackToTheLeftHandSideType)
|
||||
EXPECT_EQ(value, Fixed10_6::fromInt(3));
|
||||
}
|
||||
|
||||
TEST(FixedPointTest, ComparisonWithIntTreatsItAsWholeUnits)
|
||||
{
|
||||
const Fixed10_6 value = Fixed10_6::fromInt(3);
|
||||
EXPECT_TRUE(value == 3);
|
||||
EXPECT_TRUE(3 == value);
|
||||
EXPECT_TRUE(value != 4);
|
||||
EXPECT_TRUE(4 != value);
|
||||
EXPECT_TRUE(value < 4);
|
||||
EXPECT_TRUE(2 < value);
|
||||
EXPECT_TRUE(value <= 3);
|
||||
EXPECT_TRUE(3 <= value);
|
||||
EXPECT_TRUE(value > 2);
|
||||
EXPECT_TRUE(4 > value);
|
||||
EXPECT_TRUE(value >= 3);
|
||||
EXPECT_TRUE(3 >= value);
|
||||
|
||||
const Fixed10_6 fractional = Fixed10_6::fromRaw((3 << 6) + 1);
|
||||
EXPECT_FALSE(fractional == 3); // has a fractional part, so it's not exactly 3
|
||||
EXPECT_TRUE(fractional > 3);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace devilution
|
||||
|
||||
Reference in New Issue
Block a user