diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 2df8622f8c..8847e25e45 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -449,6 +449,7 @@ Phobos fixes: - Fixed game crashing on loading save games if the saved game state had active radiation sites (by Starkku) - Fixed a desync error caused by air/top layer sorting (by Starkku) - Fixed heal / repair weapons being unable to remove parasites from shielded targets if they were unable to heal / repair the parent unit (by Starkku) +- Fixed `Inviso=true` interceptor projectiles applying damage on interceptable, armor type-having projectiles twice (by Starkku) Fixes / interactions with other extensions: - All forms of type conversion (including Ares') now correctly update `OpenTopped` state of passengers in transport that is converted (by Starkku) diff --git a/src/Ext/Bullet/Body.cpp b/src/Ext/Bullet/Body.cpp index 9fbd3824fa..5438561a2b 100644 --- a/src/Ext/Bullet/Body.cpp +++ b/src/Ext/Bullet/Body.cpp @@ -31,13 +31,7 @@ void BulletExt::ExtData::InterceptBullet(TechnoClass* pSource, WeaponTypeClass* this->CurrentStrength -= damage; if (Phobos::DisplayDamageNumbers && damage != 0) - { - int width = Unsorted::CellWidthInPixels / 2; - wchar_t damageStr[0x20]; - swprintf_s(damageStr, L"%d", damage); - ColorStruct color = damage > 0 ? ColorStruct { 255, 128, 128 } : ColorStruct { 128, 255, 128 }; - FlyingStrings::Add(damageStr, this->OwnerObject()->Location, color, Point2D { ScenarioClass::Instance->Random.RandomRanged(-width, width), 0 }); - } + GeneralUtils::DisplayDamageNumberString(damage, DamageDisplayType::Intercept, this->OwnerObject()->GetRenderCoords(), this->DamageNumberOffset); if (this->CurrentStrength <= 0) isIntercepted = true; @@ -178,6 +172,7 @@ void BulletExt::ExtData::Serialize(T& Stm) .Process(this->DetonateOnInterception) .Process(this->LaserTrails) .Process(this->SnappedToTarget) + .Process(this->DamageNumberOffset) ; this->Trajectory = PhobosTrajectory::ProcessFromStream(Stm, this->Trajectory); diff --git a/src/Ext/Bullet/Body.h b/src/Ext/Bullet/Body.h index f214caa809..257767ed4f 100644 --- a/src/Ext/Bullet/Body.h +++ b/src/Ext/Bullet/Body.h @@ -27,6 +27,7 @@ class BulletExt bool DetonateOnInterception; std::vector LaserTrails; bool SnappedToTarget; // Used for custom trajectory projectile target snap checks + int DamageNumberOffset; PhobosTrajectory* Trajectory; // TODO: why not unique_ptr @@ -40,6 +41,7 @@ class BulletExt , LaserTrails {} , Trajectory { nullptr } , SnappedToTarget { false } + , DamageNumberOffset { INT32_MIN } { } virtual ~ExtData() = default; diff --git a/src/Ext/Techno/Body.Visuals.cpp b/src/Ext/Techno/Body.Visuals.cpp index 91a0d4f183..8de43cd091 100644 --- a/src/Ext/Techno/Body.Visuals.cpp +++ b/src/Ext/Techno/Body.Visuals.cpp @@ -2,40 +2,8 @@ #include #include -#include #include -#include - - -void TechnoExt::DisplayDamageNumberString(TechnoClass* pThis, int damage, bool isShieldDamage) -{ - if (!pThis || damage == 0) - return; - - const auto pExt = TechnoExt::ExtMap.Find(pThis); - ColorStruct color; - - if (!isShieldDamage) - color = damage > 0 ? ColorStruct { 255, 0, 0 } : ColorStruct { 0, 255, 0 }; - else - color = damage > 0 ? ColorStruct { 0, 160, 255 } : ColorStruct { 0, 255, 230 }; - - auto coords = pThis->GetRenderCoords(); - int maxOffset = Unsorted::CellWidthInPixels / 2; - int width = 0, height = 0; - wchar_t damageStr[0x20]; - swprintf_s(damageStr, L"%d", damage); - - BitFont::Instance->GetTextDimension(damageStr, &width, &height, 120); - - if (pExt->DamageNumberOffset >= maxOffset || pExt->DamageNumberOffset.empty()) - pExt->DamageNumberOffset = -maxOffset; - - FlyingStrings::Add(damageStr, coords, color, Point2D { pExt->DamageNumberOffset - (width / 2), 0 }); - - pExt->DamageNumberOffset = pExt->DamageNumberOffset + width; -} void TechnoExt::DrawSelfHealPips(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds) { diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 815fa37883..5bebb0c86a 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -32,7 +32,7 @@ class TechnoExt int LastWarpDistance; CDTimerClass AutoDeathTimer; AnimTypeClass* MindControlRingAnimType; - OptionalStruct DamageNumberOffset; + int DamageNumberOffset; bool IsInTunnel; bool HasBeenPlacedOnMap; // Set to true on first Unlimbo() call. CDTimerClass DeployFireTimer; @@ -54,7 +54,7 @@ class TechnoExt , LastWarpDistance {} , AutoDeathTimer {} , MindControlRingAnimType { nullptr } - , DamageNumberOffset {} + , DamageNumberOffset { INT32_MIN } , OriginalPassengerOwner {} , IsInTunnel { false } , HasBeenPlacedOnMap { false } @@ -134,7 +134,6 @@ class TechnoExt static void ObjectKilledBy(TechnoClass* pThis, TechnoClass* pKiller); static void UpdateSharedAmmo(TechnoClass* pThis); static double GetCurrentSpeedMultiplier(FootClass* pThis); - static void DisplayDamageNumberString(TechnoClass* pThis, int damage, bool isShieldDamage); static void DrawSelfHealPips(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds); static void DrawInsignia(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds); static void ApplyGainedSelfHeal(TechnoClass* pThis); diff --git a/src/Ext/Techno/Hooks.Firing.cpp b/src/Ext/Techno/Hooks.Firing.cpp index a261420c2f..dded71a8bc 100644 --- a/src/Ext/Techno/Hooks.Firing.cpp +++ b/src/Ext/Techno/Hooks.Firing.cpp @@ -477,7 +477,6 @@ DEFINE_HOOK(0x6FF660, TechnoClass_FireAt_Interceptor, 0x6) { GET(TechnoClass* const, pSource, ESI); GET_BASE(AbstractClass* const, pTarget, 0x8); - GET(WeaponTypeClass* const, pWeaponType, EBX); GET_STACK(BulletClass* const, pBullet, STACK_OFFSET(0xB0, -0x74)); auto const pSourceTypeExt = TechnoTypeExt::ExtMap.Find(pSource->GetTechnoType()); @@ -491,13 +490,6 @@ DEFINE_HOOK(0x6FF660, TechnoClass_FireAt_Interceptor, 0x6) pBulletExt->IsInterceptor = true; pBulletExt->InterceptedStatus = InterceptedStatus::Targeted; } - - // If using Inviso projectile, can intercept bullets right after firing. - if (pTargetObject->IsAlive && pWeaponType->Projectile->Inviso) - { - if (auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWeaponType->Warhead)) - pWHExt->InterceptBullets(pSource, pWeaponType, pTargetObject->Location); - } } } diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index d130a2d1fc..283774e5d9 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -153,7 +153,7 @@ DEFINE_HOOK(0x701DFF, TechnoClass_ReceiveDamage_FlyingStrings, 0x7) GET(int* const, pDamage, EBX); if (Phobos::DisplayDamageNumbers && *pDamage) - TechnoExt::DisplayDamageNumberString(pThis, *pDamage, false); + GeneralUtils::DisplayDamageNumberString(*pDamage, DamageDisplayType::Regular, pThis->GetRenderCoords(), TechnoExt::ExtMap.Find(pThis)->DamageNumberOffset); return 0; } diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index d65c58f719..34647180ff 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -318,8 +318,10 @@ void WarheadTypeExt::ExtData::InterceptBullets(TechnoClass* pOwner, WeaponTypeCl auto const pExt = BulletExt::ExtMap.Find(pBullet); auto const pTypeExt = pExt->TypeExtData; - // 1/8th of a cell as a margin of error. - if (pTypeExt && pTypeExt->Interceptable && pBullet->Location.DistanceFrom(coords) <= Unsorted::LeptonsPerCell / 8.0) + // 1/8th of a cell as a margin of error if not Inviso interceptor. + bool distanceCheck = pWeapon->Projectile->Inviso || pBullet->Location.DistanceFrom(coords) <= Unsorted::LeptonsPerCell / 8.0; + + if (pTypeExt && pTypeExt->Interceptable && distanceCheck) pExt->InterceptBullet(pOwner, pWeapon); } } diff --git a/src/New/Entity/ShieldClass.cpp b/src/New/Entity/ShieldClass.cpp index fba550851f..55ca011732 100644 --- a/src/New/Entity/ShieldClass.cpp +++ b/src/New/Entity/ShieldClass.cpp @@ -194,7 +194,7 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) pWHExt->Shield_ReceivedDamage_Maximum.Get(this->Type->ReceivedDamage_Maximum)); if (Phobos::DisplayDamageNumbers && shieldDamage != 0) - TechnoExt::DisplayDamageNumberString(this->Techno, shieldDamage, true); + GeneralUtils::DisplayDamageNumberString(shieldDamage, DamageDisplayType::Shield, this->Techno->GetRenderCoords(), TechnoExt::ExtMap.Find(this->Techno)->DamageNumberOffset); if (shieldDamage > 0) { diff --git a/src/Utilities/Enum.h b/src/Utilities/Enum.h index 45bfb95b71..5ee6da22dd 100644 --- a/src/Utilities/Enum.h +++ b/src/Utilities/Enum.h @@ -195,6 +195,13 @@ enum class TargetZoneScanType InRange = 2 }; +enum class DamageDisplayType +{ + Regular = 0, + Shield = 1, + Intercept = 2 +}; + enum class ChronoSparkleDisplayPosition : unsigned char { None = 0x0, diff --git a/src/Utilities/GeneralUtils.cpp b/src/Utilities/GeneralUtils.cpp index db1f3f6321..b4c1077cfe 100644 --- a/src/Utilities/GeneralUtils.cpp +++ b/src/Utilities/GeneralUtils.cpp @@ -2,6 +2,9 @@ #include "Debug.h" #include #include +#include + +#include bool GeneralUtils::IsValidString(const char* str) { @@ -175,3 +178,40 @@ CoordStruct GeneralUtils::CalculateCoordsFromDistance(CoordStruct currentCoords, return CoordStruct { x, y, targetCoords.Z }; } + +void GeneralUtils::DisplayDamageNumberString(int damage, DamageDisplayType type, CoordStruct coords, int& offset) +{ + if (damage == 0) + return; + + ColorStruct color; + + switch (type) + { + case DamageDisplayType::Regular: + color = damage > 0 ? ColorStruct { 255, 0, 0 } : ColorStruct { 0, 255, 0 }; + break; + case DamageDisplayType::Shield: + color = damage > 0 ? ColorStruct { 0, 160, 255 } : ColorStruct { 0, 255, 230 }; + break; + case DamageDisplayType::Intercept: + color = damage > 0 ? ColorStruct { 255, 128, 128 } : ColorStruct { 128, 255, 128 }; + break; + default: + break; + } + + int maxOffset = Unsorted::CellWidthInPixels / 2; + int width = 0, height = 0; + wchar_t damageStr[0x20]; + swprintf_s(damageStr, L"%d", damage); + + BitFont::Instance->GetTextDimension(damageStr, &width, &height, 120); + + if (offset >= maxOffset || offset == INT32_MIN) + offset = -maxOffset; + + FlyingStrings::Add(damageStr, coords, color, Point2D { offset - (width / 2), 0 }); + + offset = offset + width; +} diff --git a/src/Utilities/GeneralUtils.h b/src/Utilities/GeneralUtils.h index e057959af4..5a075cd96f 100644 --- a/src/Utilities/GeneralUtils.h +++ b/src/Utilities/GeneralUtils.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ class GeneralUtils static std::string IntToDigits(int num); static int CountDigitsInNumber(int number); static CoordStruct CalculateCoordsFromDistance(CoordStruct currentCoords, CoordStruct targetCoords, int distance); + static void DisplayDamageNumberString(int damage, DamageDisplayType type, CoordStruct coords, int& offset); template static T FastPow(T x, size_t n)