From 72c82b645c59a2e306488c94860d6b4fb9382999 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Tue, 18 Nov 2025 23:45:50 +1100 Subject: [PATCH 1/6] tweak: Make getEnclosingContainedBy logic const --- Generals/Code/GameEngine/Include/GameLogic/Object.h | 2 +- Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp | 4 ++-- GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h | 2 +- GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Object.h b/Generals/Code/GameEngine/Include/GameLogic/Object.h index 9252f81886..21915e7f52 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Object.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Object.h @@ -417,7 +417,7 @@ class Object : public Thing, public Snapshot void onRemovedFrom( Object *removedFrom ); Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } - Object* getEnclosingContainedBy(); ///< Find the first enclosing container in the containment chain. + const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index d6fa162257..b1bc5574ab 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -667,9 +667,9 @@ Int Object::getTransportSlotCount() const return count; } -Object* Object::getEnclosingContainedBy() +const Object* Object::getEnclosingContainedBy() const { - for (Object* child = this, *container = getContainedBy(); container; child = container, container = container->getContainedBy()) + for (const Object* child = this, *container = getContainedBy(); container; child = container, container = container->getContainedBy()) { ContainModuleInterface* containModule = container->getContain(); if (containModule && containModule->isEnclosingContainerFor(child)) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index 9a37ddeb1e..aaa5642f2c 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -442,7 +442,7 @@ class Object : public Thing, public Snapshot void onRemovedFrom( Object *removedFrom ); Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } - Object* getEnclosingContainedBy(); ///< Find the first enclosing container in the containment chain. + const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index dad917d20a..62f77f8998 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -731,9 +731,9 @@ Int Object::getTransportSlotCount() const return count; } -Object* Object::getEnclosingContainedBy() +const Object* Object::getEnclosingContainedBy() const { - for (Object* child = this, *container = getContainedBy(); container; child = container, container = container->getContainedBy()) + for (const Object* child = this, *container = getContainedBy(); container; child = container, container = container->getContainedBy()) { ContainModuleInterface* containModule = container->getContain(); if (containModule && containModule->isEnclosingContainerFor(child)) From 7e10fcfb136c7b09c0e74881a1080adacd086649 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Tue, 18 Nov 2025 23:52:28 +1100 Subject: [PATCH 2/6] chore: Implement logic for returning whether the top-level enclosing container is visible --- Generals/Code/GameEngine/Include/GameLogic/Object.h | 1 + .../Code/GameEngine/Source/GameLogic/Object/Object.cpp | 9 +++++++++ GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h | 1 + .../Code/GameEngine/Source/GameLogic/Object/Object.cpp | 9 +++++++++ 4 files changed, 20 insertions(+) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Object.h b/Generals/Code/GameEngine/Include/GameLogic/Object.h index 21915e7f52..9c29faeba1 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Object.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Object.h @@ -418,6 +418,7 @@ class Object : public Thing, public Snapshot Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. + Bool isSelfOrEnclosingContainedByVisible() const; ///< Is this object or its top-level container visible? // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index b1bc5574ab..d46d941ba7 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -679,6 +679,15 @@ const Object* Object::getEnclosingContainedBy() const return NULL; } +Bool Object::isSelfOrEnclosingContainedByVisible() const +{ + if (getDrawable() && getDrawable()->isVisible()) + return TRUE; + + const Object* container = getEnclosingContainedBy(); + return container && container->getDrawable() && container->getDrawable()->isVisible(); +} + //------------------------------------------------------------------------------------------------- /** Run from GameLogic::destroyObject */ //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index aaa5642f2c..7b58101629 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -443,6 +443,7 @@ class Object : public Thing, public Snapshot Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. + Bool isSelfOrEnclosingContainedByVisible() const; ///< Is this object or its top-level container visible? // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 62f77f8998..d88254d79c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -743,6 +743,15 @@ const Object* Object::getEnclosingContainedBy() const return NULL; } +Bool Object::isSelfOrEnclosingContainedByVisible() const +{ + if (getDrawable() && getDrawable()->isVisible()) + return TRUE; + + const Object* container = getEnclosingContainedBy(); + return container && container->getDrawable() && container->getDrawable()->isVisible(); +} + //------------------------------------------------------------------------------------------------- /** Run from GameLogic::destroyObject */ //------------------------------------------------------------------------------------------------- From 1501134a4c0ee5c56fca12be206b81898d5daf49 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Tue, 18 Nov 2025 23:56:52 +1100 Subject: [PATCH 3/6] refactor: Apply new enclosing container visibility logic --- Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp | 2 +- Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp | 2 +- GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp | 2 +- .../GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AutoDepositUpdate.cpp | 3 +-- .../Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp | 3 +-- GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp | 2 +- 7 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index d46d941ba7..a69f02598c 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -2833,7 +2833,7 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && getDrawable()->isVisible(); + && isSelfOrEnclosingContainedByVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 65439088f0..5d0dad5c80 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -886,7 +886,7 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. - if(!sourceObj->getDrawable()->isVisible() // if user watching cannot see us + if(!sourceObj->isSelfOrEnclosingContainedByVisible() // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index d88254d79c..e0c6ee7469 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -3148,7 +3148,7 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && getDrawable()->isVisible(); + && isSelfOrEnclosingContainedByVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp index 1567f4e887..a02ec10997 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp @@ -543,7 +543,7 @@ StateReturnType HackInternetState::update() //Grant the unit some experience for a successful hack. xp->addExperiencePoints( ai->getXpPerCashUpdate() ); - if (owner->getDrawable()->isVisible()) + if (owner->isSelfOrEnclosingContainedByVisible()) { // OY LOOK! I AM USING LOCAL PLAYER. Do not put anything other than TheInGameUI->addFloatingText in the block this controls!!! //Display cash income floating over the hacker. diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp index 28db02d0ee..4ccac94377 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp @@ -63,7 +63,6 @@ #include "GameLogic/Module/AutoDepositUpdate.h" #include "GameLogic/Module/AIUpdate.h" #include "GameLogic/Object.h" -#include "GameClient/Drawable.h" #include "GameClient/InGameUI.h" #include "GameClient/Color.h" #include "GameClient/GameText.h" @@ -173,7 +172,7 @@ UpdateSleepTime AutoDepositUpdate::update( void ) getObject()->getControllingPlayer()->getScoreKeeper()->addMoneyEarned( modData->m_depositAmount); } - if (moneyAmount > 0 && getObject()->getDrawable()->isVisible()) + if (moneyAmount > 0 && getObject()->isSelfOrEnclosingContainedByVisible()) { const Object *owner = getObject(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp index c1db777c70..4c21fb0111 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp @@ -34,7 +34,6 @@ #include "GameLogic/Module/SupplyCenterDockUpdate.h" #include "GameLogic/Module/SupplyTruckAIUpdate.h" #include "GameClient/Color.h" -#include "GameClient/Drawable.h" #include "GameClient/InGameUI.h" #include "GameClient/GameText.h" @@ -129,7 +128,7 @@ Bool SupplyCenterDockUpdate::action( Object* docker, Object *drone ) } } - if (value > 0 && getObject()->getDrawable()->isVisible()) + if (value > 0 && getObject()->isSelfOrEnclosingContainedByVisible()) { // OY LOOK! I AM USING LOCAL PLAYER. Do not put anything other than TheInGameUI->addFloatingText in the block this controls!!! // Setup info for adding a floating text diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 5c761a654c..09fd60381c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -917,7 +917,7 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. - if(!sourceObj->getDrawable()->isVisible() // if user watching cannot see us + if(!sourceObj->isSelfOrEnclosingContainedByVisible() // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed ) From 7f06777de3e0625a62dfd2aab863a4094df2b1fc Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 20 Nov 2025 00:03:05 +1100 Subject: [PATCH 4/6] refactor: Implement cleaner solution --- Generals/Code/GameEngine/Include/GameLogic/Object.h | 2 +- .../GameEngine/Source/GameLogic/Object/Object.cpp | 12 ++++++------ .../GameEngine/Source/GameLogic/Object/Weapon.cpp | 3 ++- .../Code/GameEngine/Include/GameLogic/Object.h | 2 +- .../GameEngine/Source/GameLogic/Object/Object.cpp | 12 ++++++------ .../Object/Update/AIUpdate/HackInternetAIUpdate.cpp | 3 ++- .../GameLogic/Object/Update/AutoDepositUpdate.cpp | 4 +++- .../Update/DockUpdate/SupplyCenterDockUpdate.cpp | 4 +++- .../GameEngine/Source/GameLogic/Object/Weapon.cpp | 3 ++- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Object.h b/Generals/Code/GameEngine/Include/GameLogic/Object.h index 9c29faeba1..d26ffd6edf 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Object.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Object.h @@ -418,7 +418,7 @@ class Object : public Thing, public Snapshot Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. - Bool isSelfOrEnclosingContainedByVisible() const; ///< Is this object or its top-level container visible? + const Object* getOuterObject() const; ///< Get the top-level object // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index a69f02598c..e5580d5e7e 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -679,13 +679,12 @@ const Object* Object::getEnclosingContainedBy() const return NULL; } -Bool Object::isSelfOrEnclosingContainedByVisible() const +const Object* Object::getOuterObject() const { - if (getDrawable() && getDrawable()->isVisible()) - return TRUE; + if (const Object* enclosing = getEnclosingContainedBy()) + return enclosing; - const Object* container = getEnclosingContainedBy(); - return container && container->getDrawable() && container->getDrawable()->isVisible(); + return this; } //------------------------------------------------------------------------------------------------- @@ -2833,7 +2832,8 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && isSelfOrEnclosingContainedByVisible(); + && getOuterObject()->getDrawable() + && getOuterObject()->getDrawable()->isVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 5d0dad5c80..556c566019 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -886,7 +886,8 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. - if(!sourceObj->isSelfOrEnclosingContainedByVisible() // if user watching cannot see us + Drawable* outerDrawable = sourceObj->getOuterObject()->getDrawable(); + if ((!outerDrawable || !outerDrawable->isVisible()) // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed ) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index 7b58101629..cbf10e4bfd 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -443,7 +443,7 @@ class Object : public Thing, public Snapshot Int getTransportSlotCount() const; void friend_setContainedBy( Object *containedBy ) { m_containedBy = containedBy; } const Object* getEnclosingContainedBy() const; ///< Find the first enclosing container in the containment chain. - Bool isSelfOrEnclosingContainedByVisible() const; ///< Is this object or its top-level container visible? + const Object* getOuterObject() const; ///< Get the top-level object // Special Powers ------------------------------------------------------------------------------- SpecialPowerModuleInterface *getSpecialPowerModule( const SpecialPowerTemplate *specialPowerTemplate ) const; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index e0c6ee7469..86acd62406 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -743,13 +743,12 @@ const Object* Object::getEnclosingContainedBy() const return NULL; } -Bool Object::isSelfOrEnclosingContainedByVisible() const +const Object* Object::getOuterObject() const { - if (getDrawable() && getDrawable()->isVisible()) - return TRUE; + if (const Object* enclosing = getEnclosingContainedBy()) + return enclosing; - const Object* container = getEnclosingContainedBy(); - return container && container->getDrawable() && container->getDrawable()->isVisible(); + return this; } //------------------------------------------------------------------------------------------------- @@ -3148,7 +3147,8 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && isSelfOrEnclosingContainedByVisible(); + && getOuterObject()->getDrawable() + && getOuterObject()->getDrawable()->isVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp index a02ec10997..b395edd50e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/HackInternetAIUpdate.cpp @@ -543,7 +543,8 @@ StateReturnType HackInternetState::update() //Grant the unit some experience for a successful hack. xp->addExperiencePoints( ai->getXpPerCashUpdate() ); - if (owner->isSelfOrEnclosingContainedByVisible()) + Drawable* outerDrawable = owner->getOuterObject()->getDrawable(); + if (outerDrawable && outerDrawable->isVisible()) { // OY LOOK! I AM USING LOCAL PLAYER. Do not put anything other than TheInGameUI->addFloatingText in the block this controls!!! //Display cash income floating over the hacker. diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp index 4ccac94377..dbda4390ce 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp @@ -63,6 +63,7 @@ #include "GameLogic/Module/AutoDepositUpdate.h" #include "GameLogic/Module/AIUpdate.h" #include "GameLogic/Object.h" +#include "GameClient/Drawable.h" #include "GameClient/InGameUI.h" #include "GameClient/Color.h" #include "GameClient/GameText.h" @@ -172,7 +173,8 @@ UpdateSleepTime AutoDepositUpdate::update( void ) getObject()->getControllingPlayer()->getScoreKeeper()->addMoneyEarned( modData->m_depositAmount); } - if (moneyAmount > 0 && getObject()->isSelfOrEnclosingContainedByVisible()) + Drawable* outerDrawable = getObject()->getOuterObject()->getDrawable(); + if (moneyAmount > 0 && outerDrawable && outerDrawable->isVisible()) { const Object *owner = getObject(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp index 4c21fb0111..407b32a0dc 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DockUpdate/SupplyCenterDockUpdate.cpp @@ -34,6 +34,7 @@ #include "GameLogic/Module/SupplyCenterDockUpdate.h" #include "GameLogic/Module/SupplyTruckAIUpdate.h" #include "GameClient/Color.h" +#include "GameClient/Drawable.h" #include "GameClient/InGameUI.h" #include "GameClient/GameText.h" @@ -128,7 +129,8 @@ Bool SupplyCenterDockUpdate::action( Object* docker, Object *drone ) } } - if (value > 0 && getObject()->isSelfOrEnclosingContainedByVisible()) + Drawable* outerDrawable = getObject()->getOuterObject()->getDrawable(); + if (value > 0 && outerDrawable && outerDrawable->isVisible()) { // OY LOOK! I AM USING LOCAL PLAYER. Do not put anything other than TheInGameUI->addFloatingText in the block this controls!!! // Setup info for adding a floating text diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 09fd60381c..8218922627 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -917,7 +917,8 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. - if(!sourceObj->isSelfOrEnclosingContainedByVisible() // if user watching cannot see us + Drawable* outerDrawable = sourceObj->getOuterObject()->getDrawable(); + if ((!outerDrawable || !outerDrawable->isVisible()) // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed ) From 1be8dc72234be2a90f5b666343c9fc192aa98e09 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 20 Nov 2025 00:55:42 +1100 Subject: [PATCH 5/6] tweak: Cache outer drawable --- Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp | 6 ++++-- .../Code/GameEngine/Source/GameLogic/Object/Object.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index e5580d5e7e..870d5fa384 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -2829,11 +2829,13 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne break; } + Drawable* outerDrawable = getOuterObject()->getDrawable(); + Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && getOuterObject()->getDrawable() - && getOuterObject()->getDrawable()->isVisible(); + && outerDrawable + && outerDrawable->isVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 86acd62406..48a7f739b3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -3144,11 +3144,13 @@ void Object::onVeterancyLevelChanged( VeterancyLevel oldLevel, VeterancyLevel ne break; } + Drawable* outerDrawable = getOuterObject()->getDrawable(); + Bool doAnimation = provideFeedback && newLevel > oldLevel && !isKindOf(KINDOF_IGNORED_IN_GUI) - && getOuterObject()->getDrawable() - && getOuterObject()->getDrawable()->isVisible(); + && outerDrawable + && outerDrawable->isVisible(); if( doAnimation && TheGameLogic->getDrawIconUI() ) { From 335666bf1691dc9feb6a48f4001c77d87585bf4e Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 20 Nov 2025 01:17:28 +1100 Subject: [PATCH 6/6] refactor: Improve readability --- Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp | 4 +++- GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 556c566019..a104f9d9da 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -887,7 +887,9 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. Drawable* outerDrawable = sourceObj->getOuterObject()->getDrawable(); - if ((!outerDrawable || !outerDrawable->isVisible()) // if user watching cannot see us + const Bool isVisible = outerDrawable && outerDrawable->isVisible(); + + if (!isVisible // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 8218922627..996a06cb1e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -918,7 +918,9 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // TheSuperHackers @todo: Remove hardcoded KINDOF_MINE check and apply PlayFXWhenStealthed = Yes to the mine weapons instead. Drawable* outerDrawable = sourceObj->getOuterObject()->getDrawable(); - if ((!outerDrawable || !outerDrawable->isVisible()) // if user watching cannot see us + const Bool isVisible = outerDrawable && outerDrawable->isVisible(); + + if (!isVisible // if user watching cannot see us && !sourceObj->isKindOf(KINDOF_MINE) // and not a mine (which always do the FX, even if hidden)... && !isPlayFXWhenStealthed() // and not a weapon marked to playwhenstealthed )