From 5e91a58fd2e550db25facf805b186941f261801c Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:10:30 +0200 Subject: [PATCH 1/2] feat(client): Make opacity and shadows of build placement preview objects customizable Adds new fields ObjectPlacementOpacity=0..1 and ObjectPlacementShadows=Yes/No to GameData.ini --- .../GameEngine/Include/Common/GlobalData.h | 3 ++ .../GameEngine/Source/Common/GlobalData.cpp | 10 +++++- .../GameEngine/Source/GameClient/InGameUI.cpp | 32 +++++++++++-------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h index 381d1123c0..190f2ac35a 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h @@ -436,6 +436,9 @@ class GlobalData : public SubsystemInterface AsciiString m_specialPowerViewObjectName; ///< Created when certain special powers are fired so players can watch. + Real m_objectPlacementOpacity; ///< Sets the opacity of build preview objects. + Bool m_objectPlacementShadows; ///< Enables or disables shadows of build preview objects. + std::vector m_standardPublicBones; Real m_standardMinefieldDensity; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index bf41e41c1c..de74c70fb0 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -398,6 +398,7 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "EnforceMaxCameraHeight", INI::parseBool, NULL, offsetof( GlobalData, m_enforceMaxCameraHeight ) }, { "KeyboardScrollSpeedFactor", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardScrollFactor ) }, { "KeyboardDefaultScrollSpeedFactor", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardDefaultScrollFactor ) }, + { "KeyboardCameraRotateSpeed", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardCameraRotateSpeed ) }, { "MovementPenaltyDamageState", INI::parseIndexList, TheBodyDamageTypeNames, offsetof( GlobalData, m_movementPenaltyDamageState ) }, // you cannot set this; it always has a value of 100%. @@ -457,6 +458,11 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "SpecialPowerViewObject", INI::parseAsciiString, NULL, offsetof( GlobalData, m_specialPowerViewObjectName ) }, + // TheSuperHackers @feature Customize the opacity (0..1) and shadows of build preview objects. Shadows are enabled by default. + // Note that disabling shadows loses a fair bit of contrast visually and warrants raising the opacity. + { "ObjectPlacementOpacity", INI::parseReal, NULL, offsetof( GlobalData, m_objectPlacementOpacity ) }, + { "ObjectPlacementShadows", INI::parseBool, NULL, offsetof( GlobalData, m_objectPlacementShadows ) }, + { "StandardPublicBone", INI::parseAsciiStringVectorAppend, NULL, offsetof(GlobalData, m_standardPublicBones) }, { "ShowMetrics", INI::parseBool, NULL, offsetof( GlobalData, m_showMetrics ) }, { "DefaultStartingCash", Money::parseMoneyAmount, NULL, offsetof( GlobalData, m_defaultStartingCash ) }, @@ -486,7 +492,6 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "NetworkPlayerTimeoutTime", INI::parseInt, NULL, offsetof(GlobalData, m_networkPlayerTimeoutTime) }, { "NetworkDisconnectScreenNotifyTime", INI::parseInt, NULL, offsetof(GlobalData, m_networkDisconnectScreenNotifyTime) }, - { "KeyboardCameraRotateSpeed", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardCameraRotateSpeed ) }, { "PlayStats", INI::parseInt, NULL, offsetof( GlobalData, m_playStats ) }, #if defined(RTS_DEBUG) @@ -874,6 +879,9 @@ GlobalData::GlobalData() m_standardMinefieldDensity = 0.01f; m_standardMinefieldDistance = 40.0f; + m_objectPlacementOpacity = 0.45f; + m_objectPlacementShadows = TRUE; + m_groupSelectMinSelectSize = 5; m_groupSelectVolumeBase = 0.5f; m_groupSelectVolumeIncrement = 0.02f; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index ac7104f221..03859cf913 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -91,8 +91,7 @@ // ------------------------------------------------------------------------------------------------ -static const Real placementOpacity = 0.45f; -static const RGBColor illegalBuildColor = { 1.0, 0.0, 0.0 }; +static const RGBColor IllegalBuildColor = { 1.0, 0.0, 0.0 }; //------------------------------------------------------------------------------------------------- /// The InGameUI singleton instance. @@ -1523,8 +1522,9 @@ void InGameUI::handleBuildPlacements( void ) BuildAssistant::IGNORE_STEALTHED, builderObject, NULL ); + if( lbc != LBC_OK ) - m_placeIcon[ 0 ]->colorTint( &illegalBuildColor ); + m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); else m_placeIcon[ 0 ]->colorTint( NULL ); @@ -1584,8 +1584,11 @@ void InGameUI::handleBuildPlacements( void ) { if( m_placeIcon[ i ] == NULL ) - m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, - DRAWABLE_STATUS_SHADOWS | DRAWABLE_STATUS_NO_STATE_PARTICLES ); + { + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + } } @@ -1609,11 +1612,11 @@ void InGameUI::handleBuildPlacements( void ) for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) { - // set the drawble position + // set the drawable position m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); - // set opacity for the drawble - m_placeIcon[ i ]->setDrawableOpacity( placementOpacity ); + // set opacity for the drawable + m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); // set the drawable angle m_placeIcon[ i ]->setOrientation( angle ); @@ -3119,8 +3122,12 @@ void InGameUI::placeBuildAvailable( const ThingTemplate *build, Drawable *buildD ///@ todo when message stream order more formalized eliminate this // TheInGameUI->deselectAllDrawables(); - // create a drawble of what we are building to be "attached" at the cursor - draw = TheThingFactory->newDrawable( build, DRAWABLE_STATUS_SHADOWS | DRAWABLE_STATUS_NO_STATE_PARTICLES ); + { + // create a drawable of what we are building to be "attached" at the cursor + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + draw = TheThingFactory->newDrawable( build, drawableStatus ); + } if (sourceObject) { if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) @@ -3138,14 +3145,11 @@ void InGameUI::placeBuildAvailable( const ThingTemplate *build, Drawable *buildD // Real angle = build->getPlacementViewAngle(); - // don't forget to take into account the current view angle - // angle += TheTacticalView->getAngle(); Don't do this - makes odd angled building placements. jba. - // set the angle in the icon we just created draw->setOrientation( angle ); // set the build icon attached to the cursor to be "see-thru" - draw->setDrawableOpacity( placementOpacity ); + draw->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); // set the "icon" in the icon array at the first index DEBUG_ASSERTCRASH( m_placeIcon[ 0 ] == NULL, ("placeBuildAvailable, build icon array is not empty!") ); From e164ec05d11d4f9139f309f9d0c14a0cdebb4387 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:13:08 +0200 Subject: [PATCH 2/2] Replicate in Generals --- .../GameEngine/Include/Common/GlobalData.h | 3 ++ .../GameEngine/Source/Common/GlobalData.cpp | 10 +++++- .../GameEngine/Source/GameClient/InGameUI.cpp | 32 +++++++++++-------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Generals/Code/GameEngine/Include/Common/GlobalData.h b/Generals/Code/GameEngine/Include/Common/GlobalData.h index 8631dc87df..5e2bf47be9 100644 --- a/Generals/Code/GameEngine/Include/Common/GlobalData.h +++ b/Generals/Code/GameEngine/Include/Common/GlobalData.h @@ -425,6 +425,9 @@ class GlobalData : public SubsystemInterface AsciiString m_specialPowerViewObjectName; ///< Created when certain special powers are fired so players can watch. + Real m_objectPlacementOpacity; ///< Sets the opacity of build preview objects. + Bool m_objectPlacementShadows; ///< Enables or disables shadows of build preview objects. + std::vector m_standardPublicBones; Real m_standardMinefieldDensity; diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index 25fec838d1..a44456ef55 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -398,6 +398,7 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "EnforceMaxCameraHeight", INI::parseBool, NULL, offsetof( GlobalData, m_enforceMaxCameraHeight ) }, { "KeyboardScrollSpeedFactor", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardScrollFactor ) }, { "KeyboardDefaultScrollSpeedFactor", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardDefaultScrollFactor ) }, + { "KeyboardCameraRotateSpeed", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardCameraRotateSpeed ) }, { "MovementPenaltyDamageState", INI::parseIndexList, TheBodyDamageTypeNames, offsetof( GlobalData, m_movementPenaltyDamageState ) }, // you cannot set this; it always has a value of 100%. @@ -457,6 +458,11 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "SpecialPowerViewObject", INI::parseAsciiString, NULL, offsetof( GlobalData, m_specialPowerViewObjectName ) }, + // TheSuperHackers @feature Customize the opacity (0..1) and shadows of build preview objects. Shadows are enabled by default. + // Note that disabling shadows loses a fair bit of contrast visually and warrants raising the opacity. + { "ObjectPlacementOpacity", INI::parseReal, NULL, offsetof( GlobalData, m_objectPlacementOpacity ) }, + { "ObjectPlacementShadows", INI::parseBool, NULL, offsetof( GlobalData, m_objectPlacementShadows ) }, + { "StandardPublicBone", INI::parseAsciiStringVectorAppend, NULL, offsetof(GlobalData, m_standardPublicBones) }, { "ShowMetrics", INI::parseBool, NULL, offsetof( GlobalData, m_showMetrics ) }, { "DefaultStartingCash", INI::parseUnsignedInt, NULL, offsetof( GlobalData, m_defaultStartingCash ) }, @@ -486,7 +492,6 @@ GlobalData* GlobalData::m_theOriginal = NULL; { "NetworkPlayerTimeoutTime", INI::parseInt, NULL, offsetof(GlobalData, m_networkPlayerTimeoutTime) }, { "NetworkDisconnectScreenNotifyTime", INI::parseInt, NULL, offsetof(GlobalData, m_networkDisconnectScreenNotifyTime) }, - { "KeyboardCameraRotateSpeed", INI::parseReal, NULL, offsetof( GlobalData, m_keyboardCameraRotateSpeed ) }, { "PlayStats", INI::parseInt, NULL, offsetof( GlobalData, m_playStats ) }, #if defined(RTS_DEBUG) @@ -868,6 +873,9 @@ GlobalData::GlobalData() m_standardMinefieldDensity = 0.01f; m_standardMinefieldDistance = 40.0f; + m_objectPlacementOpacity = 0.45f; + m_objectPlacementShadows = TRUE; + m_groupSelectMinSelectSize = 5; m_groupSelectVolumeBase = 0.5f; m_groupSelectVolumeIncrement = 0.02f; diff --git a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp index ca527d40a0..881f74b053 100644 --- a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -87,8 +87,7 @@ // ------------------------------------------------------------------------------------------------ -static const Real placementOpacity = 0.45f; -static const RGBColor illegalBuildColor = { 1.0, 0.0, 0.0 }; +static const RGBColor IllegalBuildColor = { 1.0, 0.0, 0.0 }; //------------------------------------------------------------------------------------------------- /// The InGameUI singleton instance. @@ -1467,8 +1466,9 @@ void InGameUI::handleBuildPlacements( void ) BuildAssistant::SHROUD_REVEALED, builderObject, NULL ); + if( lbc != LBC_OK ) - m_placeIcon[ 0 ]->colorTint( &illegalBuildColor ); + m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); else m_placeIcon[ 0 ]->colorTint( NULL ); @@ -1528,8 +1528,11 @@ void InGameUI::handleBuildPlacements( void ) { if( m_placeIcon[ i ] == NULL ) - m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, - DRAWABLE_STATUS_SHADOWS | DRAWABLE_STATUS_NO_STATE_PARTICLES ); + { + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + } } @@ -1553,11 +1556,11 @@ void InGameUI::handleBuildPlacements( void ) for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) { - // set the drawble position + // set the drawable position m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); - // set opacity for the drawble - m_placeIcon[ i ]->setDrawableOpacity( placementOpacity ); + // set opacity for the drawable + m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); // set the drawable angle m_placeIcon[ i ]->setOrientation( angle ); @@ -3039,8 +3042,12 @@ void InGameUI::placeBuildAvailable( const ThingTemplate *build, Drawable *buildD ///@ todo when message stream order more formalized eliminate this // TheInGameUI->deselectAllDrawables(); - // create a drawble of what we are building to be "attached" at the cursor - draw = TheThingFactory->newDrawable( build, DRAWABLE_STATUS_SHADOWS | DRAWABLE_STATUS_NO_STATE_PARTICLES ); + { + // create a drawable of what we are building to be "attached" at the cursor + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + draw = TheThingFactory->newDrawable( build, drawableStatus ); + } if (sourceObject) { if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) @@ -3058,14 +3065,11 @@ void InGameUI::placeBuildAvailable( const ThingTemplate *build, Drawable *buildD // Real angle = build->getPlacementViewAngle(); - // don't forget to take into account the current view angle - // angle += TheTacticalView->getAngle(); Don't do this - makes odd angled building placements. jba. - // set the angle in the icon we just created draw->setOrientation( angle ); // set the build icon attached to the cursor to be "see-thru" - draw->setDrawableOpacity( placementOpacity ); + draw->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); // set the "icon" in the icon array at the first index DEBUG_ASSERTCRASH( m_placeIcon[ 0 ] == NULL, ("placeBuildAvailable, build icon array is not empty!") );