From 375446201279216c57b2d9726b4b957f5592f6d1 Mon Sep 17 00:00:00 2001 From: andreasw Date: Thu, 21 May 2026 20:35:10 +0200 Subject: [PATCH 1/4] basic implementation --- .../System/GameMemoryInitPools_GeneralsMD.inl | 1 + GeneralsMD/Code/GameEngine/CMakeLists.txt | 3 +- .../Code/GameEngine/Include/Common/KindOf.h | 2 + .../GameEngine/Include/Common/SpecialPower.h | 2 + .../GameEngine/Include/GameClient/InGameUI.h | 8 + .../GameLogic/Module/RadiusDecalBehavior.h | 2 +- .../Module/SpecialPowerDesignatorUpdate.h | 126 ++++++++++ .../Source/Common/RTS/ActionManager.cpp | 60 +++++ .../Source/Common/RTS/SpecialPower.cpp | 1 + .../Source/Common/System/KindOf.cpp | 2 + .../Source/Common/Thing/ModuleFactory.cpp | 2 + .../GameEngine/Source/GameClient/InGameUI.cpp | 99 ++++++++ .../Update/SpecialPowerDesignatorUpdate.cpp | 220 ++++++++++++++++++ 13 files changed, 526 insertions(+), 2 deletions(-) create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h create mode 100644 GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index 1ec6dcec40f..f640def4ebf 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -198,6 +198,7 @@ static PoolSizeRec PoolSizes[] = { "BaikonurLaunchPower", 4, 4 }, { "RadiusDecalUpdate", 16, 16 }, { "RadiusDecalBehavior", 32, 32 }, + { "SpecialPowerDesignatorUpdate", 32, 32 }, { "BattlePlanUpdate", 32, 32 }, { "LifetimeUpdate", 32, 32 }, { "LocomotorSetUpgrade", 512, 128 }, diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index e6de4f095ae..8cd9d3132ca 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -415,6 +415,7 @@ set(GAMEENGINE_SRC Include/GameLogic/Module/RadarUpgrade.h Include/GameLogic/Module/RadiusDecalUpdate.h Include/GameLogic/Module/RadiusDecalBehavior.h + Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h Include/GameLogic/Module/RailedTransportAIUpdate.h Include/GameLogic/Module/RailedTransportContain.h Include/GameLogic/Module/RailedTransportDockUpdate.h @@ -1090,6 +1091,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Update/RadarUpdate.cpp Source/GameLogic/Object/Update/RadiusDecalUpdate.cpp Source/GameLogic/Object/Update/RadiusDecalBehavior.cpp + Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp Source/GameLogic/Object/Update/ResetSpecialPowerTimerWhileAliveUpdate.cpp Source/GameLogic/Object/Update/ScatterShotUpdate.cpp Source/GameLogic/Object/Update/SlavedUpdate.cpp @@ -1220,7 +1222,6 @@ endif() add_library(z_gameengine STATIC) target_sources(z_gameengine PRIVATE ${GAMEENGINE_SRC}) - target_include_directories(z_gameengine PUBLIC Include ) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h index 74acacacfaa..9518def0d66 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h @@ -213,6 +213,8 @@ enum KindOfType CPP_11(: Int) KINDOF_EXTRA15, KINDOF_EXTRA16, + KINDOF_TARGET_DESIGNATOR, + KINDOF_COUNT, // total number of kindofs KINDOF_FIRST = 0, }; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/SpecialPower.h b/GeneralsMD/Code/GameEngine/Include/Common/SpecialPower.h index 53360161585..279dacd2f68 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/SpecialPower.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/SpecialPower.h @@ -125,6 +125,7 @@ class SpecialPowerTemplate : public Overridable Real getViewObjectRange( void ) const { return getFO()->m_viewObjectRange; } Real getRadiusCursorRadius() const { return getFO()->m_radiusCursorRadius; } Bool isShortcutPower() const { return getFO()->m_shortcutPower; } + Bool isNeedsTargetDesignator() const { return getFO()->m_needsTargetDesignator; } AcademyClassificationType getAcademyClassificationType() const { return m_academyClassificationType; } EvaMessage getEvaDetectedOwn( void ) const { return getFO()->m_eva_detected_own; } EvaMessage getEvaDetectedAlly( void ) const { return getFO()->m_eva_detected_ally; } @@ -156,6 +157,7 @@ class SpecialPowerTemplate : public Overridable Bool m_publicTimer; ///< display a countdown timer for this special power for all to see Bool m_sharedNSync; ///< If true, this is a special that is shared between all of a player's command centers Bool m_shortcutPower; ///< Is this shortcut power capable of being fired by the side panel? + Bool m_needsTargetDesignator; ///< Is this special power only allowed to hit designated areas SpecialPowerType m_type_behavior; //< behave like a default special power, used by new ones only EvaMessage m_eva_detected_own; //< eva event when constructed by self EvaMessage m_eva_detected_ally; //< eva event when constructed by ally diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h index e0aaff613d0..c4b5a45a60d 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h @@ -687,6 +687,9 @@ friend class Drawable; // for selection/deselection transactions void handleBuildPlacements( void ); ///< handle updating of placement icons based on mouse pos void handleRadiusCursor(); ///< handle updating of "radius cursors" that follow the mouse pos + void showDesignatorDecals(const SpecialPowerTemplate* powerTemplate); + void hideDesignatorDecals(void); + void incrementSelectCount( void ) { ++m_selectCount; } ///< Increase by one the running total of "selected" drawables void decrementSelectCount( void ) { --m_selectCount; } ///< Decrease by one the running total of "selected" drawables virtual View *createView( void ) = 0; ///< Factory for Views @@ -969,6 +972,11 @@ friend class Drawable; // for selection/deselection transactions DrawableID m_soloNexusSelectedDrawableID; ///< The drawable of the nexus, if only one angry mob is selected, otherwise, null + // UI Decals + Bool m_showDesignatorDecals; + const CommandButton* m_designatorCommand; + + // ---------------------------------------------------------------------------------------------- // STATIC Protected Data ------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h index acaa1984030..dc134ec25fc 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h @@ -83,6 +83,7 @@ class RadiusDecalBehavior : public UpdateModule, public UpgradeMux protected: + void clearDecal(void); virtual void upgradeImplementation() { @@ -119,7 +120,6 @@ class RadiusDecalBehavior : public UpdateModule, public UpgradeMux RadiusDecal m_radiusDecal; - void clearDecal( void ); }; #endif // __RadiusDecalBehavior_H_ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h new file mode 100644 index 00000000000..0959cc42521 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h @@ -0,0 +1,126 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +//////////////////////////////////////////////////////////////////////////////// +// // +// (c) 2001-2003 Electronic Arts Inc. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: SpecialPowerDesignatorUpdate.h ///////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef __SpecialPowerDesignatorUpdate_H_ +#define __SpecialPowerDesignatorUpdate_H_ + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "GameLogic/Module/RadiusDecalBehavior.h" + +// FORWARD REFERENCES ///////////////////////////////////////////////////////// +class SpecialPowerTemplate; +class Thing; + +//------------------------------------------------------------------------------------------------- +class SpecialPowerDesignatorUpdateModuleData : public RadiusDecalBehaviorModuleData +{ +public: + SpecialPowerTemplate* m_specialPowerTemplate; + Real m_designatorRadius; + Bool m_alwaysShowDecal; + ObjectStatusTypes m_triggerStatusType; + UnsignedInt m_triggerStatusTime; + + SpecialPowerDesignatorUpdateModuleData(); + + static void buildFieldParse(MultiIniFieldParse& p); +}; + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +class SpecialPowerDesignatorUpdate : public RadiusDecalBehavior +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( SpecialPowerDesignatorUpdate, "SpecialPowerDesignatorUpdate" ) + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( SpecialPowerDesignatorUpdate, SpecialPowerDesignatorUpdateModuleData ) + +public: + + SpecialPowerDesignatorUpdate( Thing *thing, const ModuleData* moduleData ); + // virtual destructor prototype provided by memory pool declaration + + //void createRadiusDecal( void ); + //void killRadiusDecal( void ); + + // UpdateModuleInterface + virtual UpdateSleepTime update(); + + //virtual DisabledMaskType getDisabledTypesToProcess() const { return MAKE_DISABLED_MASK(DISABLED_HELD); } + + Real getDesignatorRadius() { return getSpecialPowerDesignatorUpdateModuleData()->m_designatorRadius; } + + Bool isValidDesignatorForSpecialPower(const SpecialPowerTemplate* templ); + + void setActive(bool status); + + void triggerSpecialPower(); + +protected: + + //virtual void upgradeImplementation() + //{ + // createRadiusDecal(); + // setWakeFrame(getObject(), UPDATE_SLEEP_NONE); + //} + + //virtual void getUpgradeActivationMasks(UpgradeMaskType& activation, UpgradeMaskType& conflicting) const + //{ + // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.getUpgradeActivationMasks(activation, conflicting); + //} + + //virtual void performUpgradeFX() + //{ + // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.performUpgradeFX(getObject()); + //} + + //virtual void processUpgradeRemoval() + //{ + // // I can't take it any more. Let the record show that I think the UpgradeMux multiple inheritence is CRAP. + // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.muxDataProcessUpgradeRemoval(getObject()); + //} + + //virtual Bool requiresAllActivationUpgrades() const + //{ + // return getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.m_requiresAllTriggers; + //} + + //inline Bool isUpgradeActive() const { return isAlreadyUpgraded(); } + + //virtual Bool isSubObjectsUpgrade() { return false; } + +private: + + Bool m_targetingActive; // We are currently looking for targets + + UnsignedInt m_statusClearFrame; + +}; + +#endif // __SpecialPowerDesignatorUpdate_H_ + diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index 1c07289db41..7ede8394fc0 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -60,6 +60,7 @@ #include "GameLogic/Module/SupplyWarehouseDockUpdate.h" #include "GameLogic/Module/SpecialPowerModule.h" #include "GameLogic/Module/SpecialAbilityUpdate.h" +#include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" #include "GameLogic/Weapon.h" #include "GameLogic/ExperienceTracker.h"//LORENZEN @@ -1567,6 +1568,65 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 } } + // Check target designator + + if (spTemplate->isNeedsTargetDesignator()) { + bool isDesignatorInRange = false; + static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); + + //Iterate over all object and find this module! + + //PartitionFilterRelationship relationship( obj, PartitionFilterRelationship::ALLOW_ALLIES ); + PartitionFilterSamePlayer filterPlayer(obj->getControllingPlayer()); + PartitionFilterSameMapStatus filterMapStatus(obj); + PartitionFilterAlive filterAlive; + PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); + PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterMapStatus, &filterKindOf, NULL }; + Real max_scan_range = 2000.0f; //Should be all units on screen + margin + // scan objects in our region + ObjectIterator* iter = ThePartitionManager->iterateObjectsInRange(loc, max_scan_range, FROM_CENTER_2D, filters); + Object* obj2; + MemoryPoolObjectHolder hold(iter); + for (obj2 = iter->first(); obj2; obj2 = iter->next()) { + + SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj2->findUpdateModule(key_SpecialPowerDesignatorUpdate); + if (update) { + if (update->isValidDesignatorForSpecialPower(spTemplate)) { + + Real distSqr = ThePartitionManager->getDistanceSquared(obj2, loc, FROM_CENTER_2D); + Real radiusSqr = update->getDesignatorRadius(); + if (distSqr <= radiusSqr) { + isDesignatorInRange = true; + break; + } + } + } + } + if (!isDesignatorInRange) + return FALSE; + } + + //static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); + + //PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); + //PartitionFilterAlive filterAlive; + //PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); + //PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; + //// scan objects on entire map + //ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); + //Object* obj; + //MemoryPoolObjectHolder hold(iter); + //for (obj = iter->first(); obj; obj = iter->next()) { + + // SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); + // if (update) { + // if (update->isValidDesignatorForSpecialPower(powerTemplate)) { + // update->setActive(true); + // } + // } + //} + + // First check terrain type, if it is cared about. Don't return a true, since there are more checks. switch(behaviorType) { diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/SpecialPower.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/SpecialPower.cpp index 08345baf7fe..8e45ce5c1ff 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/SpecialPower.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/SpecialPower.cpp @@ -304,6 +304,7 @@ void SpecialPowerStore::parseSpecialPowerDefinition( INI *ini ) { "EvaReadyOwn", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_own) }, { "EvaReadyAlly", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_ally) }, { "EvaReadyEnemy", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_enemy) }, + { "NeedsTargetDesignator", INI::parseBool, nullptr, offsetof(SpecialPowerTemplate, m_needsTargetDesignator) }, { "Cost", INI::parseInt, NULL, offsetof(SpecialPowerTemplate, m_cost) }, { nullptr, nullptr, nullptr, 0 } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp index 7961fcc2743..8e763d471bd 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp @@ -202,6 +202,8 @@ const char* const KindOfMaskType::s_bitNameList[] = "EXTRA15", "EXTRA16", + "TARGET_DESIGNATOR", + nullptr }; static_assert(ARRAY_SIZE(KindOfMaskType::s_bitNameList) == KindOfMaskType::NumBits + 1, "Incorrect array size"); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp index 2a23bca6b99..248a89aec8c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp @@ -156,6 +156,7 @@ #include "GameLogic/Module/LifetimeUpdate.h" #include "GameLogic/Module/RadiusDecalUpdate.h" #include "GameLogic/Module/RadiusDecalBehavior.h" +#include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" #include "GameLogic/Module/AutoDepositUpdate.h" #include "GameLogic/Module/MissileAIUpdate.h" #include "GameLogic/Module/NeutronMissileUpdate.h" @@ -436,6 +437,7 @@ void ModuleFactory::init( void ) addModule( LifetimeUpdate ); addModule( RadiusDecalUpdate ); addModule( RadiusDecalBehavior ); + addModule( SpecialPowerDesignatorUpdate ); addModule( EMPUpdate ); addModule( LeafletDropBehavior ); addModule( AutoDepositUpdate ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index 9a267dd088a..1f0575eca63 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -84,6 +84,7 @@ #include "GameLogic/Module/ContainModule.h" #include "GameLogic/Module/ProductionUpdate.h" #include "GameLogic/Module/SpecialPowerModule.h" +#include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" #include "GameLogic/Module/StealthUpdate.h" #include "GameLogic/Module/SupplyWarehouseDockUpdate.h" #include "GameLogic/Module/MobMemberSlavedUpdate.h"//ML @@ -3255,6 +3256,13 @@ void InGameUI::setGUICommand( const CommandButton *command ) setRadiusCursor(command->getRadiusCursorType(), //***************************************************************** command->getSpecialPowerTemplate(), command->getWeaponSlot()); + + const SpecialPowerTemplate* sp = command->getSpecialPowerTemplate(); + if (sp != nullptr && sp->isNeedsTargetDesignator()) { + m_showDesignatorDecals = TRUE; + showDesignatorDecals(command->getSpecialPowerTemplate()); + m_designatorCommand = command; + } } else { @@ -6429,3 +6437,94 @@ void InGameUI::drawPlayerInfoList() drawY += lineH; } } + +// ---------------------------------------------------------- +//static void showDesignatorDecal(Object* obj, void* userData) +//{ +// //SpecialPowerTemplate *powerTemplate = (SpecialPowerTemplate*)userData; +// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); +// +// if (obj) { +// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); +// if (update) { // && update->getSpecialPowerTemplate() == powerTemplate) { +// //update->showDesignatorDecal(true); +// +// Drawable* draw = obj->getDrawable(); +// draw->setTerrainDecal(TERRAIN_DECAL_RING); +// Real size = 3.0f * update->getDesignatorRadius(); +// draw->setTerrainDecalSize(size, size); +// +// // if (update->getSpecialPowerTemplate() == powerTemplate) { +// +// // Real distSqr = ThePartitionManager->getDistanceSquared(obj2, loc, FROM_CENTER_2D); +// // Real dist = sqrt(distSqr); +// // if (dist <= update->getDesignatorRadius()) { +// // isDesignatorInRange = true; +// // break; +// // } +// // } +// } +// } +//} +// +//static void hideDesignatorDecal(Object* obj, void* userData) +//{ +// //SpecialPowerTemplate *powerTemplate = (SpecialPowerTemplate*)userData; +// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); +// +// if (obj) { +// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); +// if (update) { // && update->getSpecialPowerTemplate() == powerTemplate) { +// //update->showDesignatorDecal(false); +// Drawable* draw = obj->getDrawable(); +// draw->setTerrainDecal(TERRAIN_DECAL_NONE); +// } +// } +//} + + +// ------------- +void InGameUI::showDesignatorDecals(const SpecialPowerTemplate* powerTemplate) { + + static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); + + PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); + PartitionFilterAlive filterAlive; + PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); + PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; + // scan objects on entire map + ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); + Object* obj; + MemoryPoolObjectHolder hold(iter); + for (obj = iter->first(); obj; obj = iter->next()) { + + SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); + if (update) { + if (update->isValidDesignatorForSpecialPower(powerTemplate)) { + update->setActive(true); + } + } + } +} + +void InGameUI::hideDesignatorDecals() { //const SpecialPowerTemplate *powerTemplate) { + //ThePlayerList->getLocalPlayer()->iterateObjects( hideDesignatorDecal, &powerTemplate ); + + static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); + + PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); + PartitionFilterAlive filterAlive; + PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); + PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; + // scan objects on entire map + ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); + Object* obj; + MemoryPoolObjectHolder hold(iter); + for (obj = iter->first(); obj; obj = iter->next()) { + + SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); + if (update) { + update->setActive(false); + } + } +} diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp new file mode 100644 index 00000000000..edf3bf34e08 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp @@ -0,0 +1,220 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +//////////////////////////////////////////////////////////////////////////////// +// // +// (c) 2001-2003 Electronic Arts Inc. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: SpecialPowerDesignatorUpdate.cpp /////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine + +#include "Common/RandomValue.h" +#include "Common/Xfer.h" +#include "GameLogic/GameLogic.h" +#include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" +#include "GameLogic/Object.h" + + + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- + +SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() +{ + m_specialPowerTemplate = nullptr; + m_designatorRadius = 0.0f; + m_alwaysShowDecal = false; + m_triggerStatusTime = 0; + m_triggerStatusType = OBJECT_STATUS_NONE; +} +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +/*static*/ void SpecialPowerDesignatorUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) +{ + RadiusDecalBehaviorModuleData::buildFieldParse(p); + static const FieldParse dataFieldParse[] = + { + { "SpecialPowerTemplate", INI::parseSpecialPowerTemplate, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_specialPowerTemplate) }, + { "DesignatorRadius", INI::parseReal, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_designatorRadius) }, + { "AlwaysShowDecal", INI::parseBool, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_alwaysShowDecal) }, + { "TriggerStatusTime", INI::parseDurationUnsignedInt, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusTime) }, + { "TriggerStatusType", ObjectStatusMaskType::parseSingleBitFromINI, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusType) }, + { "DecalRadius", INI::parseReal, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalRadius) }, + { 0, 0, 0, 0 } + }; + + p.add(dataFieldParse); +} + + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +SpecialPowerDesignatorUpdate::SpecialPowerDesignatorUpdate( Thing *thing, const ModuleData* moduleData ) : RadiusDecalBehavior( thing, moduleData ) +{ + m_targetingActive = false; + m_statusClearFrame = 0; + + /*if (getSpecialPowerDesignatorUpdateModuleData()->m_initiallyActive) + { + giveSelfUpgrade(); + } + else { + clearDecal(); + setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); + }*/ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +SpecialPowerDesignatorUpdate::~SpecialPowerDesignatorUpdate( void ) +{ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +//void SpecialPowerDesignatorUpdate::createRadiusDecal( void ) +//{ +// const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); +// +// if (data->m_alwaysShowDecal || m_targetingActive) { +// RadiusDecalBehavior::createRadiusDecal(); +// } +// else { +// setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); +// } +//} +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +void SpecialPowerDesignatorUpdate::setActive(bool status) +{ + const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); + + m_targetingActive = status; + + if (!status && !data->m_alwaysShowDecal) + clearDecal(); + + setWakeFrame(getObject(), UPDATE_SLEEP_NONE); +} +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +void SpecialPowerDesignatorUpdate::triggerSpecialPower() +{ + const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); + if (data->m_triggerStatusTime > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE) { + getObject()->setStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); + + m_statusClearFrame = TheGameLogic->getFrame() + data->m_triggerStatusTime; + setWakeFrame(getObject(), UPDATE_SLEEP_NONE); + } +} +// +////------------------------------------------------------------------------------------------------- +////------------------------------------------------------------------------------------------------- +//void SpecialPowerDesignatorUpdate::killRadiusDecal() +//{ +// clearDecal(); +// setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); +//} +// +//// ----------------------------------------------------------------------------------------------- +//void SpecialPowerDesignatorUpdate::clearDecal() +//{ +// m_radiusDecal.clear(); +//} +// +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +UpdateSleepTime SpecialPowerDesignatorUpdate::update( void ) +{ + const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); + + // First handle status + if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE) { + if (TheGameLogic->getFrame() == m_statusClearFrame) { + getObject()->clearStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); + } + else { + return UPDATE_SLEEP_NONE; + } + } + + // Then decal + + if (!m_targetingActive && !data->m_alwaysShowDecal) { + return UPDATE_SLEEP_FOREVER; + } + + return RadiusDecalBehavior::update(); +} + +// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ +Bool SpecialPowerDesignatorUpdate::isValidDesignatorForSpecialPower(const SpecialPowerTemplate* templ) +{ + return (isUpgradeActive() && templ == getSpecialPowerDesignatorUpdateModuleData()->m_specialPowerTemplate); +} + +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void SpecialPowerDesignatorUpdate::crc( Xfer *xfer ) +{ + + // extend base class + RadiusDecalBehavior::crc( xfer ); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ +// ------------------------------------------------------------------------------------------------ +void SpecialPowerDesignatorUpdate::xfer( Xfer *xfer ) +{ + + // version + XferVersion currentVersion = 1; + XferVersion version = currentVersion; + xfer->xferVersion( &version, currentVersion ); + + // extend base class + RadiusDecalBehavior::xfer( xfer ); + + xfer->xferBool(&m_targetingActive); + xfer->xferUnsignedInt(&m_statusClearFrame); + + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void SpecialPowerDesignatorUpdate::loadPostProcess( void ) +{ + + // extend base class + UpdateModule::loadPostProcess(); + +} // end loadPostProcess From dea07e6521f78912ab667749278bfe91b6da2173 Mon Sep 17 00:00:00 2001 From: Andi Date: Fri, 22 May 2026 19:37:35 +0200 Subject: [PATCH 2/4] Target designator V1 updates --- .../GameLogic/Module/RadiusDecalBehavior.h | 2 +- .../Module/SpecialPowerDesignatorUpdate.h | 2 +- .../Source/Common/RTS/ActionManager.cpp | 4 +-- .../GameEngine/Source/GameClient/InGameUI.cpp | 25 +++++++++++++------ .../Object/Update/RadiusDecalBehavior.cpp | 4 ++- .../Update/SpecialPowerDesignatorUpdate.cpp | 19 ++++++++++---- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h index dc134ec25fc..cc9b92305da 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h @@ -42,7 +42,7 @@ class RadiusDecalBehaviorModuleData : public UpdateModuleData public: UpgradeMuxData m_upgradeMuxData; Bool m_initiallyActive; - + Bool m_worksWhileContained; RadiusDecalTemplate m_decalTemplate; Real m_decalRadius; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h index 0959cc42521..211fe3fe9c1 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h @@ -71,7 +71,7 @@ class SpecialPowerDesignatorUpdate : public RadiusDecalBehavior // UpdateModuleInterface virtual UpdateSleepTime update(); - //virtual DisabledMaskType getDisabledTypesToProcess() const { return MAKE_DISABLED_MASK(DISABLED_HELD); } + // virtual DisabledMaskType getDisabledTypesToProcess() const { return getSpecialPowerDesignatorUpdateModuleData()->m_worksWhileContained ? DISABLEDMASK_ALL : MAKE_DISABLED_MASK(DISABLED_HELD); } Real getDesignatorRadius() { return getSpecialPowerDesignatorUpdateModuleData()->m_designatorRadius; } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index 7ede8394fc0..f94d81a36f5 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -1594,8 +1594,8 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 if (update->isValidDesignatorForSpecialPower(spTemplate)) { Real distSqr = ThePartitionManager->getDistanceSquared(obj2, loc, FROM_CENTER_2D); - Real radiusSqr = update->getDesignatorRadius(); - if (distSqr <= radiusSqr) { + Real radius = update->getDesignatorRadius(); + if (distSqr <= (radius*radius)) { isDesignatorInRange = true; break; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index 1f0575eca63..f57622ac18d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1102,6 +1102,9 @@ InGameUI::InGameUI() m_tooltipsDisabledUntil = 0; + m_showDesignatorDecals = FALSE; + m_designatorCommand = NULL; + // init hint lists for( i = 0; i < MAX_MOVE_HINTS; i++ ) { @@ -3246,6 +3249,21 @@ void InGameUI::setGUICommand( const CommandButton *command ) // set the command m_pendingGUICommand = command; + // Target designator checks + if (m_designatorCommand && m_designatorCommand != m_pendingGUICommand) { + hideDesignatorDecals(); + m_designatorCommand = NULL; + } + + if (command && BitIsSet(command->getOptions(), COMMAND_OPTION_NEED_TARGET)) { + const SpecialPowerTemplate* sp = command->getSpecialPowerTemplate(); + if (sp != nullptr && sp->isNeedsTargetDesignator()) { + m_showDesignatorDecals = TRUE; + showDesignatorDecals(command->getSpecialPowerTemplate()); + m_designatorCommand = command; + } + } + // set the mouse cursor for commands that need a targeting or to normal with no command if( command && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_TARGET ) && !command->isContextCommand() ) { @@ -3256,13 +3274,6 @@ void InGameUI::setGUICommand( const CommandButton *command ) setRadiusCursor(command->getRadiusCursorType(), //***************************************************************** command->getSpecialPowerTemplate(), command->getWeaponSlot()); - - const SpecialPowerTemplate* sp = command->getSpecialPowerTemplate(); - if (sp != nullptr && sp->isNeedsTargetDesignator()) { - m_showDesignatorDecals = TRUE; - showDesignatorDecals(command->getSpecialPowerTemplate()); - m_designatorCommand = command; - } } else { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/RadiusDecalBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/RadiusDecalBehavior.cpp index 7b3fbd13a56..b175a109f68 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/RadiusDecalBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/RadiusDecalBehavior.cpp @@ -42,6 +42,7 @@ RadiusDecalBehaviorModuleData::RadiusDecalBehaviorModuleData() { m_initiallyActive = false; m_decalRadius = 0.0f; + m_worksWhileContained = false; } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- @@ -53,6 +54,7 @@ RadiusDecalBehaviorModuleData::RadiusDecalBehaviorModuleData() { "StartsActive", INI::parseBool, NULL, offsetof(RadiusDecalBehaviorModuleData, m_initiallyActive) }, { "RadiusDecal", RadiusDecalTemplate::parseRadiusDecalTemplate, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalTemplate) }, { "Radius", INI::parseReal, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalRadius) }, + { "WorksWhileContained", INI::parseBool, NULL, offsetof(RadiusDecalBehaviorModuleData, m_worksWhileContained) }, { 0, 0, 0, 0 } }; @@ -120,7 +122,7 @@ void RadiusDecalBehavior::clearDecal() //------------------------------------------------------------------------------------------------- UpdateSleepTime RadiusDecalBehavior::update( void ) { - if (getObject()->isDisabledByType(DISABLED_HELD)) { + if (getObject()->isDisabledByType(DISABLED_HELD) && !getRadiusDecalBehaviorModuleData()->m_worksWhileContained) { if (!m_radiusDecal.isEmpty()) clearDecal(); return UPDATE_SLEEP_NONE; // We wait to be re-enabled diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp index edf3bf34e08..bc7dafb9ec9 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp @@ -57,6 +57,7 @@ SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() { "SpecialPowerTemplate", INI::parseSpecialPowerTemplate, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_specialPowerTemplate) }, { "DesignatorRadius", INI::parseReal, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_designatorRadius) }, { "AlwaysShowDecal", INI::parseBool, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_alwaysShowDecal) }, + // { "WorksWhileContained", INI::parseBool, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_worksWhileContained) }, { "TriggerStatusTime", INI::parseDurationUnsignedInt, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusTime) }, { "TriggerStatusType", ObjectStatusMaskType::parseSingleBitFromINI, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusType) }, { "DecalRadius", INI::parseReal, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalRadius) }, @@ -107,6 +108,8 @@ SpecialPowerDesignatorUpdate::~SpecialPowerDesignatorUpdate( void ) //------------------------------------------------------------------------------------------------- void SpecialPowerDesignatorUpdate::setActive(bool status) { + DEBUG_LOG((">>> SpecialPowerDesignatorUpdate::setActive = %d", status)); + const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); m_targetingActive = status; @@ -149,30 +152,36 @@ UpdateSleepTime SpecialPowerDesignatorUpdate::update( void ) { const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); + UpdateSleepTime result = UPDATE_SLEEP_FOREVER; // First handle status if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE) { if (TheGameLogic->getFrame() == m_statusClearFrame) { getObject()->clearStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); } else { - return UPDATE_SLEEP_NONE; + result = UPDATE_SLEEP_NONE; } } - // Then decal + //if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE && TheGameLogic->getFrame() == m_statusClearFrame) { + // getObject()->clearStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); + //} + // Then decal if (!m_targetingActive && !data->m_alwaysShowDecal) { - return UPDATE_SLEEP_FOREVER; + return MIN(result, UPDATE_SLEEP_FOREVER); } - return RadiusDecalBehavior::update(); + return MIN(RadiusDecalBehavior::update(), UPDATE_SLEEP_FOREVER); } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ Bool SpecialPowerDesignatorUpdate::isValidDesignatorForSpecialPower(const SpecialPowerTemplate* templ) { - return (isUpgradeActive() && templ == getSpecialPowerDesignatorUpdateModuleData()->m_specialPowerTemplate); + return isUpgradeActive() && templ == getSpecialPowerDesignatorUpdateModuleData()->m_specialPowerTemplate && + (getSpecialPowerDesignatorUpdateModuleData()->m_worksWhileContained || !getObject()->isDisabledByType(DISABLED_HELD)); + } // ------------------------------------------------------------------------------------------------ From 1654687af49a2b938645159654c543549a9d5322 Mon Sep 17 00:00:00 2001 From: Andi Date: Sat, 23 May 2026 08:50:12 +0200 Subject: [PATCH 3/4] rework module; add FX --- .../GameEngine/Include/GameClient/InGameUI.h | 8 +- .../GameLogic/Module/RadiusDecalBehavior.h | 1 - .../Module/SpecialPowerDesignatorUpdate.h | 4 +- .../GameLogic/Module/SpecialPowerModule.h | 2 + .../Source/Common/RTS/ActionManager.cpp | 4 +- .../GameEngine/Source/GameClient/InGameUI.cpp | 102 ++++++++++-------- .../SpecialPower/SpecialPowerModule.cpp | 57 +++++++++- .../Update/SpecialPowerDesignatorUpdate.cpp | 53 ++++----- 8 files changed, 153 insertions(+), 78 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h index c4b5a45a60d..c6d1f6348ba 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h @@ -618,6 +618,8 @@ friend class Drawable; // for selection/deselection transactions virtual void DEBUG_addFloatingText(const AsciiString& text,const Coord3D * pos, Color color); #endif + const SpecialPowerTemplate* getTargetDesignatorPower(); + protected: // snapshot methods virtual void crc( Xfer *xfer ); @@ -687,8 +689,8 @@ friend class Drawable; // for selection/deselection transactions void handleBuildPlacements( void ); ///< handle updating of placement icons based on mouse pos void handleRadiusCursor(); ///< handle updating of "radius cursors" that follow the mouse pos - void showDesignatorDecals(const SpecialPowerTemplate* powerTemplate); - void hideDesignatorDecals(void); + //void showDesignatorDecals(const SpecialPowerTemplate* powerTemplate); + //void hideDesignatorDecals(void); void incrementSelectCount( void ) { ++m_selectCount; } ///< Increase by one the running total of "selected" drawables void decrementSelectCount( void ) { --m_selectCount; } ///< Decrease by one the running total of "selected" drawables @@ -973,7 +975,7 @@ friend class Drawable; // for selection/deselection transactions DrawableID m_soloNexusSelectedDrawableID; ///< The drawable of the nexus, if only one angry mob is selected, otherwise, null // UI Decals - Bool m_showDesignatorDecals; + //Bool m_showDesignatorDecals; const CommandButton* m_designatorCommand; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h index cc9b92305da..dc89a95c8c4 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/RadiusDecalBehavior.h @@ -116,7 +116,6 @@ class RadiusDecalBehavior : public UpdateModule, public UpgradeMux virtual Bool isSubObjectsUpgrade() { return false; } -private: RadiusDecal m_radiusDecal; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h index 211fe3fe9c1..6a08aea777a 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h @@ -36,6 +36,7 @@ // FORWARD REFERENCES ///////////////////////////////////////////////////////// class SpecialPowerTemplate; class Thing; +class FXList; //------------------------------------------------------------------------------------------------- class SpecialPowerDesignatorUpdateModuleData : public RadiusDecalBehaviorModuleData @@ -46,6 +47,7 @@ class SpecialPowerDesignatorUpdateModuleData : public RadiusDecalBehaviorModuleD Bool m_alwaysShowDecal; ObjectStatusTypes m_triggerStatusType; UnsignedInt m_triggerStatusTime; + const FXList* m_triggerFX; SpecialPowerDesignatorUpdateModuleData(); @@ -77,7 +79,7 @@ class SpecialPowerDesignatorUpdate : public RadiusDecalBehavior Bool isValidDesignatorForSpecialPower(const SpecialPowerTemplate* templ); - void setActive(bool status); + //void setActive(bool status); void triggerSpecialPower(); diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerModule.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerModule.h index 739b170c080..2742fcb1946 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerModule.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerModule.h @@ -170,6 +170,8 @@ class SpecialPowerModule : public BehaviorModule, void resolveSpecialPower( void ); void aboutToDoSpecialPower( const Coord3D *location ); + void handleTargetDesignator(const Coord3D* location); + UnsignedInt m_availableOnFrame; ///< on this frame, this special power is available Int m_pausedCount; ///< Reference count of sources pausing me UnsignedInt m_pausedOnFrame; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index f94d81a36f5..c5be55ec02c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -1582,9 +1582,9 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 PartitionFilterAlive filterAlive; PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterMapStatus, &filterKindOf, NULL }; - Real max_scan_range = 2000.0f; //Should be all units on screen + margin + Real MAX_SCAN_RANGE = 5000.0f; //TODO: GlobalData? // scan objects in our region - ObjectIterator* iter = ThePartitionManager->iterateObjectsInRange(loc, max_scan_range, FROM_CENTER_2D, filters); + ObjectIterator* iter = ThePartitionManager->iterateObjectsInRange(loc, MAX_SCAN_RANGE, FROM_CENTER_2D, filters); Object* obj2; MemoryPoolObjectHolder hold(iter); for (obj2 = iter->first(); obj2; obj2 = iter->next()) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index f57622ac18d..c1e769bbfee 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1102,7 +1102,7 @@ InGameUI::InGameUI() m_tooltipsDisabledUntil = 0; - m_showDesignatorDecals = FALSE; + //m_showDesignatorDecals = FALSE; m_designatorCommand = NULL; // init hint lists @@ -3251,15 +3251,15 @@ void InGameUI::setGUICommand( const CommandButton *command ) // Target designator checks if (m_designatorCommand && m_designatorCommand != m_pendingGUICommand) { - hideDesignatorDecals(); + //hideDesignatorDecals(); m_designatorCommand = NULL; } if (command && BitIsSet(command->getOptions(), COMMAND_OPTION_NEED_TARGET)) { const SpecialPowerTemplate* sp = command->getSpecialPowerTemplate(); if (sp != nullptr && sp->isNeedsTargetDesignator()) { - m_showDesignatorDecals = TRUE; - showDesignatorDecals(command->getSpecialPowerTemplate()); + /* m_showDesignatorDecals = TRUE; + showDesignatorDecals(command->getSpecialPowerTemplate());*/ m_designatorCommand = command; } } @@ -6495,47 +6495,57 @@ void InGameUI::drawPlayerInfoList() // ------------- -void InGameUI::showDesignatorDecals(const SpecialPowerTemplate* powerTemplate) { - - static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); - - PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); - PartitionFilterAlive filterAlive; - PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); - PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; - // scan objects on entire map - ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); - Object* obj; - MemoryPoolObjectHolder hold(iter); - for (obj = iter->first(); obj; obj = iter->next()) { - - SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); - if (update) { - if (update->isValidDesignatorForSpecialPower(powerTemplate)) { - update->setActive(true); - } - } - } -} - -void InGameUI::hideDesignatorDecals() { //const SpecialPowerTemplate *powerTemplate) { - //ThePlayerList->getLocalPlayer()->iterateObjects( hideDesignatorDecal, &powerTemplate ); - - static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); - - PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); - PartitionFilterAlive filterAlive; - PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); - PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; - // scan objects on entire map - ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); - Object* obj; - MemoryPoolObjectHolder hold(iter); - for (obj = iter->first(); obj; obj = iter->next()) { +// ------------- +const SpecialPowerTemplate* InGameUI::getTargetDesignatorPower() +{ + if (m_designatorCommand != nullptr) + return m_designatorCommand->getSpecialPowerTemplate(); - SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); - if (update) { - update->setActive(false); - } - } + return nullptr; } +// ------------- +// ------------- +//void InGameUI::showDesignatorDecals(const SpecialPowerTemplate* powerTemplate) { +// +// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); +// +// PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); +// PartitionFilterAlive filterAlive; +// PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); +// PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; +// // scan objects on entire map +// ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); +// Object* obj; +// MemoryPoolObjectHolder hold(iter); +// for (obj = iter->first(); obj; obj = iter->next()) { +// +// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); +// if (update) { +// if (update->isValidDesignatorForSpecialPower(powerTemplate)) { +// update->setActive(true); +// } +// } +// } +//} +// +//void InGameUI::hideDesignatorDecals() { //const SpecialPowerTemplate *powerTemplate) { +// //ThePlayerList->getLocalPlayer()->iterateObjects( hideDesignatorDecal, &powerTemplate ); +// +// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); +// +// PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); +// PartitionFilterAlive filterAlive; +// PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); +// PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; +// // scan objects on entire map +// ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); +// Object* obj; +// MemoryPoolObjectHolder hold(iter); +// for (obj = iter->first(); obj; obj = iter->next()) { +// +// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); +// if (update) { +// update->setActive(false); +// } +// } +//} diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp index d4ae0fbb575..393982643d3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp @@ -48,7 +48,9 @@ #include "GameLogic/Module/UpdateModule.h" #include "GameLogic/Module/SpecialPowerModule.h" #include "GameLogic/Module/SpecialPowerUpdateModule.h" +#include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" #include "GameLogic/ScriptEngine.h" +#include "GameLogic/PartitionManager.h" #include "GameClient/Eva.h" #include "GameClient/InGameUI.h" @@ -500,6 +502,8 @@ void SpecialPowerModule::triggerSpecialPower( const Coord3D *location ) aboutToDoSpecialPower( location ); // do BEFORE recharge + handleTargetDesignator(location); + createViewObject(location); // we won't be able to use the power for X number of frames now @@ -553,7 +557,6 @@ void SpecialPowerModule::markSpecialPowerTriggered( const Coord3D *location ) triggerSpecialPower( location ); } - //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) @@ -948,6 +951,58 @@ UnsignedInt SpecialPowerModule::getReadyFrame( void ) const } } +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +void SpecialPowerModule::handleTargetDesignator(const Coord3D* loc) +{ + const SpecialPowerModuleData* data = getSpecialPowerModuleData(); + if (!data->m_specialPowerTemplate->isNeedsTargetDesignator()) + return; + + // Get closest Target designator object + static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); + + //Iterate over all object and find this module! + Object* obj = getObject(); + + //PartitionFilterRelationship relationship( obj, PartitionFilterRelationship::ALLOW_ALLIES ); + PartitionFilterSamePlayer filterPlayer(obj->getControllingPlayer()); + PartitionFilterSameMapStatus filterMapStatus(obj); + PartitionFilterAlive filterAlive; + PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); + PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterMapStatus, &filterKindOf, NULL }; + Real MAX_SCAN_RANGE = 5000.0f; //TODO: GlobalData? + // scan objects in our region + ObjectIterator* iter = ThePartitionManager->iterateObjectsInRange(loc, MAX_SCAN_RANGE, FROM_CENTER_2D, filters); + Object* obj2; + //Object* closestObj = nullptr; + SpecialPowerDesignatorUpdate* closestObjUpdate = nullptr; + MemoryPoolObjectHolder hold(iter); + Real minDistSqr = INFINITY; + for (obj2 = iter->first(); obj2; obj2 = iter->next()) { + + SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj2->findUpdateModule(key_SpecialPowerDesignatorUpdate); + if (update) { + if (update->isValidDesignatorForSpecialPower(data->m_specialPowerTemplate)) { + + Real distSqr = ThePartitionManager->getDistanceSquared(obj2, loc, FROM_CENTER_2D); + Real radius = update->getDesignatorRadius(); + if (distSqr <= (radius * radius) && minDistSqr) { + if (distSqr < minDistSqr) { + //closestObj = obj2; + closestObjUpdate = update; + minDistSqr = distSqr; + } + } + } + } + } + if (closestObjUpdate != nullptr) + closestObjUpdate->triggerSpecialPower(); + +} + + // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp index bc7dafb9ec9..92955f4ccdf 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp @@ -33,6 +33,8 @@ #include "GameLogic/GameLogic.h" #include "GameLogic/Module/SpecialPowerDesignatorUpdate.h" #include "GameLogic/Object.h" +#include "GameClient/FXList.h" +#include "GameClient/InGameUI.h" @@ -46,6 +48,7 @@ SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() m_alwaysShowDecal = false; m_triggerStatusTime = 0; m_triggerStatusType = OBJECT_STATUS_NONE; + m_triggerFX = nullptr; } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- @@ -61,6 +64,7 @@ SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() { "TriggerStatusTime", INI::parseDurationUnsignedInt, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusTime) }, { "TriggerStatusType", ObjectStatusMaskType::parseSingleBitFromINI, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusType) }, { "DecalRadius", INI::parseReal, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalRadius) }, + { "TriggerFX", INI::parseFXList, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerFX) }, { 0, 0, 0, 0 } }; @@ -106,19 +110,19 @@ SpecialPowerDesignatorUpdate::~SpecialPowerDesignatorUpdate( void ) //} //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- -void SpecialPowerDesignatorUpdate::setActive(bool status) -{ - DEBUG_LOG((">>> SpecialPowerDesignatorUpdate::setActive = %d", status)); - - const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); - - m_targetingActive = status; - - if (!status && !data->m_alwaysShowDecal) - clearDecal(); - - setWakeFrame(getObject(), UPDATE_SLEEP_NONE); -} +//void SpecialPowerDesignatorUpdate::setActive(bool status) +//{ +// DEBUG_LOG((">>> SpecialPowerDesignatorUpdate::setActive = %d", status)); +// +// const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); +// +// m_targetingActive = status; +// +// if (!status && !data->m_alwaysShowDecal) +// clearDecal(); +// +// setWakeFrame(getObject(), UPDATE_SLEEP_NONE); +//} //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void SpecialPowerDesignatorUpdate::triggerSpecialPower() @@ -130,6 +134,8 @@ void SpecialPowerDesignatorUpdate::triggerSpecialPower() m_statusClearFrame = TheGameLogic->getFrame() + data->m_triggerStatusTime; setWakeFrame(getObject(), UPDATE_SLEEP_NONE); } + + FXList::doFXObj(data->m_triggerFX, getObject()); } // ////------------------------------------------------------------------------------------------------- @@ -152,27 +158,26 @@ UpdateSleepTime SpecialPowerDesignatorUpdate::update( void ) { const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); - UpdateSleepTime result = UPDATE_SLEEP_FOREVER; + //UpdateSleepTime result = UPDATE_SLEEP_FOREVER; // First handle status if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE) { if (TheGameLogic->getFrame() == m_statusClearFrame) { getObject()->clearStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); } - else { - result = UPDATE_SLEEP_NONE; - } } - //if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE && TheGameLogic->getFrame() == m_statusClearFrame) { - // getObject()->clearStatus(MAKE_OBJECT_STATUS_MASK(data->m_triggerStatusType)); - //} + if (data->m_alwaysShowDecal) + return RadiusDecalBehavior::update(); - // Then decal - if (!m_targetingActive && !data->m_alwaysShowDecal) { - return MIN(result, UPDATE_SLEEP_FOREVER); + const SpecialPowerTemplate *tmpl = TheInGameUI->getTargetDesignatorPower(); + if (tmpl != nullptr && tmpl == data->m_specialPowerTemplate) { + RadiusDecalBehavior::update(); + } + else if (!m_radiusDecal.isEmpty()) { + clearDecal(); } - return MIN(RadiusDecalBehavior::update(), UPDATE_SLEEP_FOREVER); + return UPDATE_SLEEP_NONE; } // ------------------------------------------------------------------------------------------------ From 2d4329a466fd98279d53f9bf62f143be6801e506 Mon Sep 17 00:00:00 2001 From: Andi Date: Sat, 23 May 2026 08:54:07 +0200 Subject: [PATCH 4/4] Clean up --- .../Module/SpecialPowerDesignatorUpdate.h | 40 -------- .../GameEngine/Source/GameClient/InGameUI.cpp | 92 ------------------- .../Update/SpecialPowerDesignatorUpdate.cpp | 56 ----------- 3 files changed, 188 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h index 6a08aea777a..59e8759e049 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SpecialPowerDesignatorUpdate.h @@ -67,59 +67,19 @@ class SpecialPowerDesignatorUpdate : public RadiusDecalBehavior SpecialPowerDesignatorUpdate( Thing *thing, const ModuleData* moduleData ); // virtual destructor prototype provided by memory pool declaration - //void createRadiusDecal( void ); - //void killRadiusDecal( void ); - // UpdateModuleInterface virtual UpdateSleepTime update(); - // virtual DisabledMaskType getDisabledTypesToProcess() const { return getSpecialPowerDesignatorUpdateModuleData()->m_worksWhileContained ? DISABLEDMASK_ALL : MAKE_DISABLED_MASK(DISABLED_HELD); } - Real getDesignatorRadius() { return getSpecialPowerDesignatorUpdateModuleData()->m_designatorRadius; } Bool isValidDesignatorForSpecialPower(const SpecialPowerTemplate* templ); - //void setActive(bool status); - void triggerSpecialPower(); protected: - //virtual void upgradeImplementation() - //{ - // createRadiusDecal(); - // setWakeFrame(getObject(), UPDATE_SLEEP_NONE); - //} - - //virtual void getUpgradeActivationMasks(UpgradeMaskType& activation, UpgradeMaskType& conflicting) const - //{ - // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.getUpgradeActivationMasks(activation, conflicting); - //} - - //virtual void performUpgradeFX() - //{ - // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.performUpgradeFX(getObject()); - //} - - //virtual void processUpgradeRemoval() - //{ - // // I can't take it any more. Let the record show that I think the UpgradeMux multiple inheritence is CRAP. - // getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.muxDataProcessUpgradeRemoval(getObject()); - //} - - //virtual Bool requiresAllActivationUpgrades() const - //{ - // return getSpecialPowerDesignatorUpdateModuleData()->m_upgradeMuxData.m_requiresAllTriggers; - //} - - //inline Bool isUpgradeActive() const { return isAlreadyUpgraded(); } - - //virtual Bool isSubObjectsUpgrade() { return false; } - private: - Bool m_targetingActive; // We are currently looking for targets - UnsignedInt m_statusClearFrame; }; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index c1e769bbfee..2ab2c519e8a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -3251,15 +3251,12 @@ void InGameUI::setGUICommand( const CommandButton *command ) // Target designator checks if (m_designatorCommand && m_designatorCommand != m_pendingGUICommand) { - //hideDesignatorDecals(); m_designatorCommand = NULL; } if (command && BitIsSet(command->getOptions(), COMMAND_OPTION_NEED_TARGET)) { const SpecialPowerTemplate* sp = command->getSpecialPowerTemplate(); if (sp != nullptr && sp->isNeedsTargetDesignator()) { - /* m_showDesignatorDecals = TRUE; - showDesignatorDecals(command->getSpecialPowerTemplate());*/ m_designatorCommand = command; } } @@ -6449,51 +6446,6 @@ void InGameUI::drawPlayerInfoList() } } -// ---------------------------------------------------------- -//static void showDesignatorDecal(Object* obj, void* userData) -//{ -// //SpecialPowerTemplate *powerTemplate = (SpecialPowerTemplate*)userData; -// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); -// -// if (obj) { -// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); -// if (update) { // && update->getSpecialPowerTemplate() == powerTemplate) { -// //update->showDesignatorDecal(true); -// -// Drawable* draw = obj->getDrawable(); -// draw->setTerrainDecal(TERRAIN_DECAL_RING); -// Real size = 3.0f * update->getDesignatorRadius(); -// draw->setTerrainDecalSize(size, size); -// -// // if (update->getSpecialPowerTemplate() == powerTemplate) { -// -// // Real distSqr = ThePartitionManager->getDistanceSquared(obj2, loc, FROM_CENTER_2D); -// // Real dist = sqrt(distSqr); -// // if (dist <= update->getDesignatorRadius()) { -// // isDesignatorInRange = true; -// // break; -// // } -// // } -// } -// } -//} -// -//static void hideDesignatorDecal(Object* obj, void* userData) -//{ -// //SpecialPowerTemplate *powerTemplate = (SpecialPowerTemplate*)userData; -// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); -// -// if (obj) { -// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); -// if (update) { // && update->getSpecialPowerTemplate() == powerTemplate) { -// //update->showDesignatorDecal(false); -// Drawable* draw = obj->getDrawable(); -// draw->setTerrainDecal(TERRAIN_DECAL_NONE); -// } -// } -//} - - // ------------- // ------------- const SpecialPowerTemplate* InGameUI::getTargetDesignatorPower() @@ -6505,47 +6457,3 @@ const SpecialPowerTemplate* InGameUI::getTargetDesignatorPower() } // ------------- // ------------- -//void InGameUI::showDesignatorDecals(const SpecialPowerTemplate* powerTemplate) { -// -// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); -// -// PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); -// PartitionFilterAlive filterAlive; -// PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); -// PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; -// // scan objects on entire map -// ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); -// Object* obj; -// MemoryPoolObjectHolder hold(iter); -// for (obj = iter->first(); obj; obj = iter->next()) { -// -// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); -// if (update) { -// if (update->isValidDesignatorForSpecialPower(powerTemplate)) { -// update->setActive(true); -// } -// } -// } -//} -// -//void InGameUI::hideDesignatorDecals() { //const SpecialPowerTemplate *powerTemplate) { -// //ThePlayerList->getLocalPlayer()->iterateObjects( hideDesignatorDecal, &powerTemplate ); -// -// static NameKeyType key_SpecialPowerDesignatorUpdate = NAMEKEY("SpecialPowerDesignatorUpdate"); -// -// PartitionFilterSamePlayer filterPlayer(ThePlayerList->getLocalPlayer()); -// PartitionFilterAlive filterAlive; -// PartitionFilterAcceptByKindOf filterKindOf(MAKE_KINDOF_MASK(KINDOF_TARGET_DESIGNATOR), KINDOFMASK_NONE); -// PartitionFilter* filters[] = { &filterPlayer, &filterAlive, &filterKindOf, NULL }; -// // scan objects on entire map -// ObjectIterator* iter = ThePartitionManager->iterateAllObjects(filters); -// Object* obj; -// MemoryPoolObjectHolder hold(iter); -// for (obj = iter->first(); obj; obj = iter->next()) { -// -// SpecialPowerDesignatorUpdate* update = (SpecialPowerDesignatorUpdate*)obj->findUpdateModule(key_SpecialPowerDesignatorUpdate); -// if (update) { -// update->setActive(false); -// } -// } -//} diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp index 92955f4ccdf..8d2c8e19c0a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SpecialPowerDesignatorUpdate.cpp @@ -60,7 +60,6 @@ SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() { "SpecialPowerTemplate", INI::parseSpecialPowerTemplate, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_specialPowerTemplate) }, { "DesignatorRadius", INI::parseReal, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_designatorRadius) }, { "AlwaysShowDecal", INI::parseBool, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_alwaysShowDecal) }, - // { "WorksWhileContained", INI::parseBool, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_worksWhileContained) }, { "TriggerStatusTime", INI::parseDurationUnsignedInt, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusTime) }, { "TriggerStatusType", ObjectStatusMaskType::parseSingleBitFromINI, NULL, offsetof(SpecialPowerDesignatorUpdateModuleData, m_triggerStatusType) }, { "DecalRadius", INI::parseReal, NULL, offsetof( RadiusDecalBehaviorModuleData, m_decalRadius) }, @@ -76,17 +75,7 @@ SpecialPowerDesignatorUpdateModuleData::SpecialPowerDesignatorUpdateModuleData() //------------------------------------------------------------------------------------------------- SpecialPowerDesignatorUpdate::SpecialPowerDesignatorUpdate( Thing *thing, const ModuleData* moduleData ) : RadiusDecalBehavior( thing, moduleData ) { - m_targetingActive = false; m_statusClearFrame = 0; - - /*if (getSpecialPowerDesignatorUpdateModuleData()->m_initiallyActive) - { - giveSelfUpgrade(); - } - else { - clearDecal(); - setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); - }*/ } //------------------------------------------------------------------------------------------------- @@ -95,34 +84,6 @@ SpecialPowerDesignatorUpdate::~SpecialPowerDesignatorUpdate( void ) { } -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -//void SpecialPowerDesignatorUpdate::createRadiusDecal( void ) -//{ -// const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); -// -// if (data->m_alwaysShowDecal || m_targetingActive) { -// RadiusDecalBehavior::createRadiusDecal(); -// } -// else { -// setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); -// } -//} -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -//void SpecialPowerDesignatorUpdate::setActive(bool status) -//{ -// DEBUG_LOG((">>> SpecialPowerDesignatorUpdate::setActive = %d", status)); -// -// const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); -// -// m_targetingActive = status; -// -// if (!status && !data->m_alwaysShowDecal) -// clearDecal(); -// -// setWakeFrame(getObject(), UPDATE_SLEEP_NONE); -//} //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void SpecialPowerDesignatorUpdate::triggerSpecialPower() @@ -137,28 +98,12 @@ void SpecialPowerDesignatorUpdate::triggerSpecialPower() FXList::doFXObj(data->m_triggerFX, getObject()); } -// -////------------------------------------------------------------------------------------------------- -////------------------------------------------------------------------------------------------------- -//void SpecialPowerDesignatorUpdate::killRadiusDecal() -//{ -// clearDecal(); -// setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); -//} -// -//// ----------------------------------------------------------------------------------------------- -//void SpecialPowerDesignatorUpdate::clearDecal() -//{ -// m_radiusDecal.clear(); -//} -// //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- UpdateSleepTime SpecialPowerDesignatorUpdate::update( void ) { const SpecialPowerDesignatorUpdateModuleData* data = getSpecialPowerDesignatorUpdateModuleData(); - //UpdateSleepTime result = UPDATE_SLEEP_FOREVER; // First handle status if (m_statusClearFrame > 0 && data->m_triggerStatusType != OBJECT_STATUS_NONE) { if (TheGameLogic->getFrame() == m_statusClearFrame) { @@ -216,7 +161,6 @@ void SpecialPowerDesignatorUpdate::xfer( Xfer *xfer ) // extend base class RadiusDecalBehavior::xfer( xfer ); - xfer->xferBool(&m_targetingActive); xfer->xferUnsignedInt(&m_statusClearFrame);