diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 1b8148e289..faebd73f6c 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -81,7 +81,7 @@ set(GAMEENGINE_SRC # Include/Common/Money.h # Include/Common/MultiplayerSettings.h # Include/Common/NameKeyGenerator.h -# Include/Common/ObjectStatusTypes.h + Include/Common/ObjectStatusTypes.h # Include/Common/OSDisplay.h # Include/Common/Overridable.h # Include/Common/Override.h @@ -94,7 +94,7 @@ set(GAMEENGINE_SRC # Include/Common/ProductionPrerequisite.h # Include/Common/QuickmatchPreferences.h # Include/Common/QuotedPrintable.h -# Include/Common/Radar.h + Include/Common/Radar.h Include/Common/RAMFile.h Include/Common/RandomValue.h # Include/Common/Recorder.h @@ -660,9 +660,9 @@ set(GAMEENGINE_SRC # Source/Common/System/List.cpp Source/Common/System/LocalFile.cpp Source/Common/System/LocalFileSystem.cpp -# Source/Common/System/ObjectStatusTypes.cpp + Source/Common/System/ObjectStatusTypes.cpp # Source/Common/System/QuotedPrintable.cpp -# Source/Common/System/Radar.cpp + Source/Common/System/Radar.cpp Source/Common/System/RAMFile.cpp # Source/Common/System/registry.cpp # Source/Common/System/SaveGame/GameState.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/Common/ObjectStatusTypes.h b/Core/GameEngine/Include/Common/ObjectStatusTypes.h similarity index 97% rename from GeneralsMD/Code/GameEngine/Include/Common/ObjectStatusTypes.h rename to Core/GameEngine/Include/Common/ObjectStatusTypes.h index df19b3743e..affa254c9e 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/ObjectStatusTypes.h +++ b/Core/GameEngine/Include/Common/ObjectStatusTypes.h @@ -70,6 +70,9 @@ enum ObjectStatusTypes CPP_11(: Int) OBJECT_STATUS_NO_ATTACK_FROM_AI, ///< attacking this object may not be done from commandSource == CMD_FROM_AI OBJECT_STATUS_IGNORING_STEALTH, ///< temporarily ignoring all stealth bits. (used only for some special-case mine clearing stuff.) OBJECT_STATUS_IS_CARBOMB, ///< Object is now a carbomb. + + // TheSuperHackers @info New statuses added in Zero Hour + // Note: Loading old save games that do not track these flags in objects will not recover them. Expect logic bugs. OBJECT_STATUS_DECK_HEIGHT_OFFSET, ///< Object factors deck height on top of ground altitude. OBJECT_STATUS_RIDER1, OBJECT_STATUS_RIDER2, diff --git a/Generals/Code/GameEngine/Include/Common/Radar.h b/Core/GameEngine/Include/Common/Radar.h similarity index 99% rename from Generals/Code/GameEngine/Include/Common/Radar.h rename to Core/GameEngine/Include/Common/Radar.h index 902cc24392..83f779247c 100644 --- a/Generals/Code/GameEngine/Include/Common/Radar.h +++ b/Core/GameEngine/Include/Common/Radar.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp b/Core/GameEngine/Source/Common/System/ObjectStatusTypes.cpp similarity index 97% rename from GeneralsMD/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp rename to Core/GameEngine/Source/Common/System/ObjectStatusTypes.cpp index 8b07bbc5a9..ab689ad343 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp +++ b/Core/GameEngine/Source/Common/System/ObjectStatusTypes.cpp @@ -64,6 +64,7 @@ const char* const ObjectStatusMaskType::s_bitNameList[] = "NO_ATTACK_FROM_AI", "IGNORING_STEALTH", "IS_CARBOMB", + // TheSuperHackers @info New statuses added in Zero Hour "DECK_HEIGHT_OFFSET", "STATUS_RIDER1", "STATUS_RIDER2", diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/Radar.cpp b/Core/GameEngine/Source/Common/System/Radar.cpp similarity index 99% rename from GeneralsMD/Code/GameEngine/Source/Common/System/Radar.cpp rename to Core/GameEngine/Source/Common/System/Radar.cpp index 22e79e4b6a..8883f247e0 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/Radar.cpp +++ b/Core/GameEngine/Source/Common/System/Radar.cpp @@ -362,15 +362,15 @@ void Radar::newMap( TerrainLogic *terrain ) m_waterAverageZ = 0.0f; Coord3D worldPoint; - // since we're averaging let's skip every second sample... - worldPoint.y=0; + // since we're averaging let's skip every second sample... + worldPoint.y=0; for( y = 0; y < RADAR_CELL_HEIGHT; y+=2, worldPoint.y+=2.0*m_ySample ) - { - worldPoint.x=0; - for( x = 0; x < RADAR_CELL_WIDTH; x+=2, worldPoint.x+=2.0*m_xSample ) + { + worldPoint.x=0; + for( x = 0; x < RADAR_CELL_WIDTH; x+=2, worldPoint.x+=2.0*m_xSample ) { // don't use this, we don't really need the - // Z position by this function... radarToWorld( &radarPoint, &worldPoint ); + // Z position by this function... radarToWorld( &radarPoint, &worldPoint ); // and this is done by isUnderwater anyway: z = terrain->getGroundHeight( worldPoint.x, worldPoint.y ); Real z,waterZ; if( terrain->isUnderwater( worldPoint.x, worldPoint.y, &waterZ, &z ) ) @@ -383,9 +383,8 @@ void Radar::newMap( TerrainLogic *terrain ) m_terrainAverageZ += z; terrainSamples++; } - } - } + } // avoid divide by zeros if( terrainSamples == 0 ) @@ -436,7 +435,7 @@ RadarObjectType Radar::addObject( Object *obj ) //Because we have support for disguised units pretending to be units from another //team, we need to intercept it here and make sure it's rendered appropriately //based on which client is rendering it. - StealthUpdate *update = obj->getStealth(); + StealthUpdate *update = obj->getStealth(); if( update ) { if( update->isDisguised() ) @@ -1506,7 +1505,7 @@ void Radar::xfer( Xfer *xfer ) XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); - + if (version <= 1) { const Int localPlayerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex(); diff --git a/Core/GameEngineDevice/CMakeLists.txt b/Core/GameEngineDevice/CMakeLists.txt index 404c1eb60e..1de9abd7d9 100644 --- a/Core/GameEngineDevice/CMakeLists.txt +++ b/Core/GameEngineDevice/CMakeLists.txt @@ -4,7 +4,7 @@ set(GAMEENGINEDEVICE_SRC # Include/W3DDevice/Common/W3DConvert.h # Include/W3DDevice/Common/W3DFunctionLexicon.h # Include/W3DDevice/Common/W3DModuleFactory.h -# Include/W3DDevice/Common/W3DRadar.h + Include/W3DDevice/Common/W3DRadar.h # Include/W3DDevice/Common/W3DThingFactory.h # Include/W3DDevice/GameClient/BaseHeightMap.h # Include/W3DDevice/GameClient/camerashakesystem.h @@ -93,7 +93,7 @@ set(GAMEENGINEDEVICE_SRC Source/MilesAudioDevice/MilesAudioManager.cpp Source/VideoDevice/Bink/BinkVideoPlayer.cpp # Source/W3DDevice/Common/System/W3DFunctionLexicon.cpp -# Source/W3DDevice/Common/System/W3DRadar.cpp + Source/W3DDevice/Common/System/W3DRadar.cpp # Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp # Source/W3DDevice/Common/Thing/W3DThingFactory.cpp # Source/W3DDevice/Common/W3DConvert.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h b/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h rename to Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp similarity index 99% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp rename to Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index 7516211b1c..be576da841 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -890,8 +890,8 @@ void W3DRadar::init( void ) DEBUG_ASSERTCRASH( m_overlayTexture, ("W3DRadar: Unable to allocate overlay texture") ); // set filter type for the overlay texture, try it and see if you like it, I don't ;) -// m_overlayTexture->Set_Min_Filter( TextureClass::FILTER_TYPE_NONE ); -// m_overlayTexture->Set_Mag_Filter( TextureClass::FILTER_TYPE_NONE ); +// m_overlayTexture->Set_Min_Filter( TextureFilterClass::FILTER_TYPE_NONE ); +// m_overlayTexture->Set_Mag_Filter( TextureFilterClass::FILTER_TYPE_NONE ); // allocate our shroud texture m_shroudTexture = MSGNEW("TextureClass") TextureClass( m_textureWidth, m_textureHeight, @@ -1136,7 +1136,7 @@ void W3DRadar::buildTerrainTexture( TerrainLogic *terrain ) radarToWorld2D( &radarPoint, &worldPoint ); // get color for this Z and add to our sample color - Real underwaterZ; + Real underwaterZ; if( terrain->isUnderwater( worldPoint.x, worldPoint.y, NULL, &underwaterZ ) ) { // this is our "color" for water @@ -1544,7 +1544,7 @@ void W3DRadar::refreshObjects() // they are godlike and can see everything) // if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY && - obj->getControllingPlayer() != player && + obj->getControllingPlayer() != player && player->isPlayerActive() ) continue; diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index a9395f9b12..01912ede6e 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -74,7 +74,7 @@ set(GAMEENGINE_SRC Include/Common/Money.h Include/Common/MultiplayerSettings.h Include/Common/NameKeyGenerator.h - Include/Common/ObjectStatusTypes.h +# Include/Common/ObjectStatusTypes.h Include/Common/OSDisplay.h Include/Common/Overridable.h Include/Common/Override.h @@ -87,7 +87,7 @@ set(GAMEENGINE_SRC Include/Common/ProductionPrerequisite.h Include/Common/QuickmatchPreferences.h Include/Common/QuotedPrintable.h - Include/Common/Radar.h +# Include/Common/Radar.h # Include/Common/RAMFile.h # Include/Common/RandomValue.h Include/Common/Recorder.h @@ -610,9 +610,9 @@ set(GAMEENGINE_SRC # Source/Common/System/LocalFile.cpp # Source/Common/System/LocalFileSystem.cpp #Source/Common/System/MemoryInit.cpp - Source/Common/System/ObjectStatusTypes.cpp +# Source/Common/System/ObjectStatusTypes.cpp Source/Common/System/QuotedPrintable.cpp - Source/Common/System/Radar.cpp +# Source/Common/System/Radar.cpp # Source/Common/System/RAMFile.cpp Source/Common/System/registry.cpp Source/Common/System/SaveGame/GameState.cpp diff --git a/Generals/Code/GameEngine/Include/Common/ObjectStatusTypes.h b/Generals/Code/GameEngine/Include/Common/ObjectStatusTypes.h deleted file mode 100644 index f443ad0ac7..0000000000 --- a/Generals/Code/GameEngine/Include/Common/ObjectStatusTypes.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -** Command & Conquer Generals(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: ObjectStatusTypes.h ///////////////////////////////////////////////////////////////////////// -// Author: Kris, May 2003 -// Desc: Object status types that are stackable using the BitSet system. Used to be ObjectStatusBits -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Lib/BaseType.h" -#include "Common/BitFlags.h" -#include "Common/BitFlagsIO.h" - -//------------------------------------------------------------------------------------------------- -/** Object status types */ -//------------------------------------------------------------------------------------------------- -enum ObjectStatusTypes CPP_11(: Int) -{ - //These are saved. Do not insert or remove any! - - OBJECT_STATUS_NONE, ///< no status bit - OBJECT_STATUS_DESTROYED, ///< has been destroyed, pending delete - OBJECT_STATUS_CAN_ATTACK, ///< used by garrissoned buildings, is OR'ed with KINDOF_CAN_ATTACK in isAbleToAttack() - OBJECT_STATUS_UNDER_CONSTRUCTION, ///< object is being constructed and is not yet complete - OBJECT_STATUS_UNSELECTABLE, ///< This is a negative condition since these statuses are overrides. ie their presence forces the condition, but their absence means nothing - OBJECT_STATUS_NO_COLLISIONS, ///< object should be ignored for object-object collisions (but not object-ground); used for thing like collapsing parachutes that are intangible - OBJECT_STATUS_NO_ATTACK, ///< Absolute override to being able to attack - OBJECT_STATUS_AIRBORNE_TARGET, ///< InTheAir as far as AntiAir weapons are concerned only. - OBJECT_STATUS_PARACHUTING, ///< object is on a parachute - OBJECT_STATUS_REPULSOR, ///< object repulses "KINDOF_CAN_BE_REPULSED" objects. - OBJECT_STATUS_HIJACKED, ///< unit is in the possesion of an enemy criminal, call the authorities - OBJECT_STATUS_AFLAME, ///< This object is on fire. - OBJECT_STATUS_BURNED, ///< This object has already burned as much as it can. - OBJECT_STATUS_WET, ///< object has been soaked with water - OBJECT_STATUS_IS_FIRING_WEAPON, ///< Object is firing a weapon, now. Not true for special attacks. --Lorenzen - OBJECT_STATUS_BRAKING, ///< Object is braking, and subverts the physics. - OBJECT_STATUS_STEALTHED, ///< Object is currently "stealthed" - OBJECT_STATUS_DETECTED, ///< Object is in range of a stealth-detector unit (meaningless if STEALTHED not set) - OBJECT_STATUS_CAN_STEALTH, ///< Object has ability to stealth allowing the stealth update module to run. - OBJECT_STATUS_SOLD, ///< Object is being sold - OBJECT_STATUS_UNDERGOING_REPAIR, ///< Object is awaiting/undergoing a repair order that has been issued - OBJECT_STATUS_RECONSTRUCTING, ///< Reconstructing - OBJECT_STATUS_MASKED, ///< Masked objects are not selectable and targetable by players or AI - OBJECT_STATUS_IS_ATTACKING, ///< Object is in the general Attack state (incl. aim, approach, etc.). Note that IS_FIRING_WEAPON and IS_AIMING_WEAPON is a subset of this! - OBJECT_STATUS_IS_USING_ABILITY, ///< Object is in the process of preparing or firing a special ability. - OBJECT_STATUS_IS_AIMING_WEAPON, ///< Object is aiming a weapon, now. Not true for special attacks. - OBJECT_STATUS_NO_ATTACK_FROM_AI, ///< attacking this object may not be done from commandSource == CMD_FROM_AI - OBJECT_STATUS_IGNORING_STEALTH, ///< temporarily ignoring all stealth bits. (used only for some special-case mine clearing stuff.) - OBJECT_STATUS_IS_CARBOMB, ///< Object is now a carbomb. - // add more status types here and don't forget to add to the string table ObjectStatusMaskType::s_bitNameList[] - - OBJECT_STATUS_COUNT - -}; - -typedef BitFlags ObjectStatusMaskType; - -#define MAKE_OBJECT_STATUS_MASK(k) ObjectStatusMaskType(ObjectStatusMaskType::kInit, (k)) -#define MAKE_OBJECT_STATUS_MASK2(k,a) ObjectStatusMaskType(ObjectStatusMaskType::kInit, (k), (a)) -#define MAKE_OBJECT_STATUS_MASK3(k,a,b) ObjectStatusMaskType(ObjectStatusMaskType::kInit, (k), (a), (b)) -#define MAKE_OBJECT_STATUS_MASK4(k,a,b,c) ObjectStatusMaskType(ObjectStatusMaskType::kInit, (k), (a), (b), (c)) -#define MAKE_OBJECT_STATUS_MASK5(k,a,b,c,d) ObjectStatusMaskType(ObjectStatusMaskType::kInit, (k), (a), (b), (c), (d)) - -inline Bool TEST_OBJECT_STATUS_MASK( const ObjectStatusMaskType& m, ObjectStatusTypes t ) -{ - return m.test( t ); -} - -inline Bool TEST_OBJECT_STATUS_MASK_ANY( const ObjectStatusMaskType& m, const ObjectStatusMaskType& mask ) -{ - return m.anyIntersectionWith( mask ); -} - -inline Bool TEST_OBJECT_STATUS_MASK_MULTI( const ObjectStatusMaskType& m, const ObjectStatusMaskType& mustBeSet, const ObjectStatusMaskType& mustBeClear ) -{ - return m.testSetAndClear( mustBeSet, mustBeClear ); -} - -inline Bool OBJECT_STATUS_MASK_ANY_SET( const ObjectStatusMaskType& m) -{ - return m.any(); -} - -inline void CLEAR_OBJECT_STATUS_MASK( ObjectStatusMaskType& m ) -{ - m.clear(); -} - -inline void SET_ALL_OBJECT_STATUS_MASK_BITS( ObjectStatusMaskType& m ) -{ - m.clear( ); - m.flip( ); -} - -inline void FLIP_OBJECT_STATUS_MASK( ObjectStatusMaskType& m ) -{ - m.flip(); -} - -// defined in Common/System/ObjectStatusTypes.cpp -extern ObjectStatusMaskType OBJECT_STATUS_MASK_NONE; // inits to all zeroes diff --git a/Generals/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp b/Generals/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp deleted file mode 100644 index 01dff2c26b..0000000000 --- a/Generals/Code/GameEngine/Source/Common/System/ObjectStatusTypes.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -** Command & Conquer Generals(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: ObjectStatusTypes.cpp //////////////////////////////////////////////////////////////////// -// Author: Kris, May 2003 -// Desc: Object status types that are stackable using the BitSet system. Used to be ObjectStatusBits -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "PreRTS.h" - -#include "Common/ObjectStatusTypes.h" -#include "Common/BitFlagsIO.h" - -template<> -const char* const ObjectStatusMaskType::s_bitNameList[] = -{ - "NONE", - "DESTROYED", - "CAN_ATTACK", - "UNDER_CONSTRUCTION", - "UNSELECTABLE", - "NO_COLLISIONS", - "NO_ATTACK", - "AIRBORNE_TARGET", - "PARACHUTING", - "REPULSOR", - "HIJACKED", - "AFLAME", - "BURNED", - "WET", - "IS_FIRING_WEAPON", - "IS_BRAKING", - "STEALTHED", - "DETECTED", - "CAN_STEALTH", - "SOLD", - "UNDERGOING_REPAIR", - "RECONSTRUCTING", - "MASKED", - "IS_ATTACKING", - "USING_ABILITY", - "IS_AIMING_WEAPON", - "NO_ATTACK_FROM_AI", - "IGNORING_STEALTH", - "IS_CARBOMB", - NULL -}; -static_assert(ARRAY_SIZE(ObjectStatusMaskType::s_bitNameList) == ObjectStatusMaskType::NumBits + 1, "Incorrect array size"); - -ObjectStatusMaskType OBJECT_STATUS_MASK_NONE; // inits to all zeroes diff --git a/Generals/Code/GameEngine/Source/Common/System/Radar.cpp b/Generals/Code/GameEngine/Source/Common/System/Radar.cpp deleted file mode 100644 index 5c33ab13ed..0000000000 --- a/Generals/Code/GameEngine/Source/Common/System/Radar.cpp +++ /dev/null @@ -1,1606 +0,0 @@ -/* -** Command & Conquer Generals(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: Radar.cpp //////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, January 2002 -// Desc: Radar logic implementation -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameAudio.h" -#include "Common/GameState.h" -#include "Common/GameUtility.h" -#include "Common/MiscAudio.h" -#include "Common/Radar.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/ThingTemplate.h" -#include "Common/GlobalData.h" -#include "Common/Xfer.h" - -#include "GameClient/Drawable.h" -#include "GameClient/Eva.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/InGameUI.h" -#include "GameClient/ControlBar.h" - -#include "GameLogic/GameLogic.h" -#include "GameLogic/Object.h" -#include "GameLogic/PartitionManager.h" -#include "GameLogic/TerrainLogic.h" -#include "GameLogic/Module/ContainModule.h" -#include "GameLogic/Module/StealthUpdate.h" - - -// GLOBALS //////////////////////////////////////////////////////////////////////////////////////// -Radar *TheRadar = NULL; ///< the radar global singleton - -// PRIVATE //////////////////////////////////////////////////////////////////////////////////////// -#define RADAR_QUEUE_TERRAIN_REFRESH_DELAY (LOGICFRAMES_PER_SECOND * 3.0f) - -//------------------------------------------------------------------------------------------------- -/** Delete list resources used by the radar and return them to the memory pools */ -//------------------------------------------------------------------------------------------------- -void Radar::deleteListResources( void ) -{ - RadarObject *nextObject; - - // delete entries from the local object list - while( m_localObjectList ) - { - - // get next object - nextObject = m_localObjectList->friend_getNext(); - - // remove radar data from object - m_localObjectList->friend_getObject()->friend_setRadarData( NULL ); - - // delete the head of the list - deleteInstance(m_localObjectList); - - // set head of the list to the next object - m_localObjectList = nextObject; - - } - - // delete entries from the regular object list - while( m_objectList ) - { - - // get next object - nextObject = m_objectList->friend_getNext(); - - // remove radar data from object - m_objectList->friend_getObject()->friend_setRadarData( NULL ); - - // delete the head of the list - deleteInstance(m_objectList); - - // set head of the list to the next object - m_objectList = nextObject; - - } - - Object *obj; - for( obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() ) - { - - DEBUG_ASSERTCRASH( obj->friend_getRadarData() == NULL, ("oops") ); - - } - -} - -// PUBLIC METHODS ///////////////////////////////////////////////////////////////////////////////// -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -RadarObject::RadarObject( void ) -{ - - m_object = NULL; - m_next = NULL; - m_color = GameMakeColor( 255, 255, 255, 255 ); - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -RadarObject::~RadarObject( void ) -{ - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -Bool RadarObject::isTemporarilyHidden() const -{ - return isTemporarilyHidden(m_object); -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -Bool RadarObject::isTemporarilyHidden(const Object* obj) -{ - Drawable* draw = obj->getDrawable(); - if (draw == NULL || draw->getStealthLook() == STEALTHLOOK_INVISIBLE || draw->isDrawableEffectivelyHidden()) - return true; - - return false; -} - -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void RadarObject::crc( Xfer *xfer ) -{ - -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer method - * Version Info: - * 1: Initial version */ -// ------------------------------------------------------------------------------------------------ -void RadarObject::xfer( Xfer *xfer ) -{ - - // version - XferVersion currentVersion = 1; - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - // object id - ObjectID objectID = m_object ? m_object->getID() : INVALID_ID; - xfer->xferObjectID( &objectID ); - if( xfer->getXferMode() == XFER_LOAD ) - { - - // find the object and save - m_object = TheGameLogic->findObjectByID( objectID ); - if( m_object == NULL ) - { - - DEBUG_CRASH(( "RadarObject::xfer - Unable to find object for radar data" )); - throw SC_INVALID_DATA; - - } - - // tell the object we now have some radar data - m_object->friend_setRadarData( this ); - - } - - // color - xfer->xferColor( &m_color ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void RadarObject::loadPostProcess( void ) -{ - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -Radar::Radar( void ) -{ - - m_radarWindow = NULL; - m_objectList = NULL; - m_localObjectList = NULL; - std::fill(m_radarHidden, m_radarHidden + ARRAY_SIZE(m_radarHidden), false); - std::fill(m_radarForceOn, m_radarForceOn + ARRAY_SIZE(m_radarForceOn), false); - m_terrainAverageZ = 0.0f; - m_waterAverageZ = 0.0f; - m_xSample = 0.0f; - m_ySample = 0.0f; - m_mapExtent.lo.x = 0.0f; - m_mapExtent.lo.y = 0.0f; - m_mapExtent.lo.z = 0.0f; - m_mapExtent.hi.x = 0.0f; - m_mapExtent.hi.y = 0.0f; - m_mapExtent.hi.z = 0.0f; - m_queueTerrainRefreshFrame = 0; - - // clear the radar events - clearAllEvents(); - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -Radar::~Radar( void ) -{ - - // delete list resources - deleteListResources(); - -} - -//------------------------------------------------------------------------------------------------- -/** Clear all radar events */ -//------------------------------------------------------------------------------------------------- -void Radar::clearAllEvents( void ) -{ - - // set next free index to the first one - m_nextFreeRadarEvent = 0; - m_lastRadarEvent = -1; - - // zero out all data - for( Int i = 0; i < MAX_RADAR_EVENTS; ++i ) - { - - m_event[ i ].type = RADAR_EVENT_INVALID; - m_event[ i ].active = FALSE; - m_event[ i ].createFrame = 0; - m_event[ i ].dieFrame = 0; - m_event[ i ].fadeFrame = 0; - m_event[ i ].color1.red = 0; - m_event[ i ].color1.green = 0; - m_event[ i ].color1.blue = 0; - m_event[ i ].color2.red = 0; - m_event[ i ].color2.green = 0; - m_event[ i ].color2.blue = 0; - m_event[ i ].worldLoc.x = 0.0f; - m_event[ i ].worldLoc.y = 0.0f; - m_event[ i ].worldLoc.z = 0.0f; - m_event[ i ].radarLoc.x = 0; - m_event[ i ].radarLoc.y = 0; - m_event[ i ].soundPlayed = FALSE; - - } - -} - -//------------------------------------------------------------------------------------------------- -/** Reset radar data */ -//------------------------------------------------------------------------------------------------- -void Radar::reset( void ) -{ - - // delete list resources - deleteListResources(); - - // clear all events - clearAllEvents(); - - // TheSuperHackers @todo Reset m_radarHidden? - //std::fill(m_radarHidden, m_radarHidden + ARRAY_SIZE(m_radarHidden), false); - - // stop forcing the radar on - std::fill(m_radarForceOn, m_radarForceOn + ARRAY_SIZE(m_radarForceOn), false); - -} - -//------------------------------------------------------------------------------------------------- -/** Radar per frame update */ -//------------------------------------------------------------------------------------------------- -void Radar::update( void ) -{ - Int i; - UnsignedInt thisFrame = TheGameLogic->getFrame(); - - // - // traverse the radar event list, if an event has a creationFrame it means that it - // exists ... check to see if it's time for that event to die and if so, just clear - // out the active status - // - for( i = 0; i < MAX_RADAR_EVENTS; i++ ) - { - - if( m_event[ i ].active == TRUE && m_event[ i ].createFrame && - thisFrame > m_event[ i ].dieFrame ) - m_event[ i ].active = FALSE; - - } - - // see if we should refresh the terrain - if( m_queueTerrainRefreshFrame != 0 && - TheGameLogic->getFrame() - m_queueTerrainRefreshFrame > RADAR_QUEUE_TERRAIN_REFRESH_DELAY ) - { - - // refresh the terrain - refreshTerrain( TheTerrainLogic ); - - } - -} - -//------------------------------------------------------------------------------------------------- -/** Reset the radar for the new map data being given to it */ -//------------------------------------------------------------------------------------------------- -void Radar::newMap( TerrainLogic *terrain ) -{ - - // keep a pointer for our radar window - Int id = NAMEKEY( "ControlBar.wnd:LeftHUD" ); - m_radarWindow = TheWindowManager->winGetWindowFromId( NULL, id ); - DEBUG_ASSERTCRASH( m_radarWindow, ("Radar::newMap - Unable to find radar game window") ); - - // reset all the data in the radar - reset(); - - // get the extents of the new map - terrain->getExtent( &m_mapExtent ); - - // we will sample at these intervals across the map - m_xSample = m_mapExtent.width() / RADAR_CELL_WIDTH; - m_ySample = m_mapExtent.height() / RADAR_CELL_HEIGHT; - - // find the "middle" height for the terrain (most used value) and water table - Int x, y, z; - Int terrainSamples = 0, waterSamples = 0; - - m_terrainAverageZ = 0.0f; - m_waterAverageZ = 0.0f; - ICoord2D radarPoint; - Coord3D worldPoint; - for( y = 0; y < RADAR_CELL_HEIGHT; y++ ) - for( x = 0; x < RADAR_CELL_WIDTH; x++ ) - { - - radarPoint.x = x; - radarPoint.y = y; - radarToWorld( &radarPoint, &worldPoint ); - z = terrain->getGroundHeight( worldPoint.x, worldPoint.y ); - Real waterZ; - if( terrain->isUnderwater( worldPoint.x, worldPoint.y, &waterZ ) ) - { - m_waterAverageZ += z; - waterSamples++; - } - else - { - m_terrainAverageZ += z; - terrainSamples++; - } - - } - - // avoid divide by zeros - if( terrainSamples == 0 ) - terrainSamples = 1; - if( waterSamples == 0 ) - waterSamples = 1; - - // compute averages - m_terrainAverageZ = m_terrainAverageZ / INT_TO_REAL( terrainSamples ); - m_waterAverageZ = m_waterAverageZ / INT_TO_REAL( waterSamples ); - -} - -//------------------------------------------------------------------------------------------------- -/** Add an object to the radar list. The object will be sorted in the list to be grouped - * using it's radar priority */ -//------------------------------------------------------------------------------------------------- -RadarObjectType Radar::addObject( Object *obj ) -{ - - // get the radar priority for this object - RadarPriorityType newPriority = obj->getRadarPriority(); - if( isPriorityVisible( newPriority ) == FALSE ) - return RadarObjectType_None; - - // if this object is on the radar, remove it in favor of the new add - RadarObject **list; - RadarObject *newObj; - - // sanity - DEBUG_ASSERTCRASH( obj->friend_getRadarData() == NULL, - ("Radar: addObject - non NULL radar data for '%s'", - obj->getTemplate()->getName().str()) ); - - // allocate a new object - newObj = newInstance(RadarObject); - - // set the object data - newObj->friend_setObject( obj ); - - // set color for this object on the radar - const Player *player = obj->getControllingPlayer(); - Player *clientPlayer = rts::getObservedOrLocalPlayer(); - Bool useIndicatorColor = true; - - if( obj->isKindOf( KINDOF_DISGUISER ) ) - { - //Because we have support for disguised units pretending to be units from another - //team, we need to intercept it here and make sure it's rendered appropriately - //based on which client is rendering it. - StealthUpdate *update = obj->getStealth(); - if( update ) - { - if( update->isDisguised() ) - { - Player *disguisedPlayer = ThePlayerList->getNthPlayer( update->getDisguisedPlayerIndex() ); - if( player->getRelationship( clientPlayer->getDefaultTeam() ) != ALLIES && clientPlayer->isPlayerActive() ) - { - //Neutrals and enemies will see this disguised unit as the team it's disguised as. - player = disguisedPlayer; - if( player ) - useIndicatorColor = false; - } - //Otherwise, the color will show up as the team it really belongs to (already set above). - } - } - } - - if( obj->getContain() ) - { - // To handle Stealth garrison, ask containers what color they are drawing with to the local player. - // Local is okay because radar display is not synced. - player = obj->getContain()->getApparentControllingPlayer( clientPlayer ); - if( player ) - useIndicatorColor = false; - } - - if( useIndicatorColor || (player == NULL) ) - { - newObj->setColor( obj->getIndicatorColor() ); - } - else - { - newObj->setColor( player->getPlayerColor() ); - } - - // set a chunk of radar data in the object - obj->friend_setRadarData( newObj ); - - RadarObjectType objectType; - // - // we will put this on either the local object list for objects that belong to the - // local player, or on the regular object list for all other objects - // - if( obj->isLocallyControlled() ) - { - list = &m_localObjectList; - objectType = RadarObjectType_Local; - } - else - { - list = &m_objectList; - objectType = RadarObjectType_Regular; - } - - // link object to master list at the head of it's priority section - if( *list == NULL ) - *list = newObj; // trivial case, an empty list - else - { - RadarPriorityType prevPriority, currPriority; - RadarObject *currObject, *prevObject, *nextObject; - - prevObject = NULL; - prevPriority = RADAR_PRIORITY_INVALID; - for( currObject = *list; currObject; currObject = nextObject ) - { - - // get the next object - nextObject = currObject->friend_getNext(); - - // get the priority of this entry in the list (currPriority) - currPriority = currObject->friend_getObject()->getRadarPriority(); - - // - // if there is no previous object, or the previous priority is less than the - // our new priority, and the current object in the list has a priority - // higher than our equal to our own we need to be inserted here - // - if( (prevObject == NULL || prevPriority < newPriority ) && - (currPriority >= newPriority) ) - { - - // insert into the list just ahead of currObject - if( prevObject ) - { - - // the new entry next points to what the previous one used to point to - newObj->friend_setNext( prevObject->friend_getNext() ); - - // the previous one next now points to the new entry - prevObject->friend_setNext( newObj ); - - } - else - { - - // the new object next points to the current object - newObj->friend_setNext( currObject ); - - // new list head is now newObj - *list = newObj; - - } - - break; // exit for, stop the insert - - } - else if( nextObject == NULL ) - { - - // at the end of the list, put object here - currObject->friend_setNext( newObj ); - - } - - // our current object is now the previous object - prevObject = currObject; - prevPriority = currPriority; - - } - - } - - return objectType; -} - -//------------------------------------------------------------------------------------------------- -/** Try to delete an object from a specific list */ -//------------------------------------------------------------------------------------------------- -Bool Radar::deleteFromList( Object *obj, RadarObject **list ) -{ - RadarObject *radarObject, *prevObject = NULL; - - // find the object in list - for( radarObject = *list; radarObject; radarObject = radarObject->friend_getNext() ) - { - - if( radarObject->friend_getObject() == obj ) - { - - // unlink the object from list - if( prevObject == NULL ) - *list = radarObject->friend_getNext(); // removing head of list - else - prevObject->friend_setNext( radarObject->friend_getNext() ); - - // set the object radar data to NULL - obj->friend_setRadarData( NULL ); - - // delete the object instance - deleteInstance(radarObject); - - // all done, object found and deleted - return TRUE; - - } - - // save this object as previous one encountered in the list - prevObject = radarObject; - - } - - // object was not found in this list - return FALSE; - -} - -//------------------------------------------------------------------------------------------------- -/** Remove an object from the radar, the object may reside in any list */ -//------------------------------------------------------------------------------------------------- -RadarObjectType Radar::removeObject( Object *obj ) -{ - - // sanity - if( obj->friend_getRadarData() == NULL ) - return RadarObjectType_None; - - if( deleteFromList( obj, &m_localObjectList ) == TRUE ) - return RadarObjectType_Local; - else if( deleteFromList( obj, &m_objectList ) == TRUE ) - return RadarObjectType_Regular; - else - { - - // sanity - DEBUG_ASSERTCRASH( 0, ("Radar: Tried to remove object '%s' which was not found", - obj->getTemplate()->getName().str()) ); - return RadarObjectType_None; - } - -} - -//------------------------------------------------------------------------------------------------- -/** Translate a 2D spot on the radar (from (0,0) to (RADAR_CELL_WIDTH,RADAR_CELL_HEIGHT) - * to a 3D spot in the world. Does not determine Z value! - * Return TRUE if the radar points translates to a valid world position - * Return FALSE if the radar point is not a valid world position */ -//------------------------------------------------------------------------------------------------- -Bool Radar::radarToWorld2D( const ICoord2D *radar, Coord3D *world ) -{ - Int x, y; - - // sanity - if( radar == NULL || world == NULL ) - return FALSE; - - // get the coords - x = radar->x; - y = radar->y; - - // more sanity - if( x < 0 ) - x = 0; - if( x >= RADAR_CELL_WIDTH ) - x = RADAR_CELL_WIDTH - 1; - if( y < 0 ) - y = 0; - if( y >= RADAR_CELL_HEIGHT ) - y = RADAR_CELL_HEIGHT - 1; - - // translate to world - world->x = x * m_xSample; - world->y = y * m_ySample; - return TRUE; -} - -//------------------------------------------------------------------------------------------------- -/** Translate a 2D spot on the radar (from (0,0) to (RADAR_CELL_WIDTH,RADAR_CELL_HEIGHT) - * to a 3D spot in the world on the terrain - * Return TRUE if the radar points translates to a valid world position - * Return FALSE if the radar point is not a valid world position */ -//------------------------------------------------------------------------------------------------- -Bool Radar::radarToWorld( const ICoord2D *radar, Coord3D *world ) -{ - if (!radarToWorld2D(radar,world)) - return FALSE; - - // find the terrain height here - world->z = TheTerrainLogic->getGroundHeight( world->x, world->y ); - - return TRUE; // valid translation - -} - -//------------------------------------------------------------------------------------------------- -/** Translate a point in the world to the 2D radar (x,y) - * Return TRUE if the world point successfully translates to a radar point - * Return FALSE if world point is a bogus off the map position */ -//------------------------------------------------------------------------------------------------- -Bool Radar::worldToRadar( const Coord3D *world, ICoord2D *radar ) -{ - - // sanity - if( world == NULL || radar == NULL ) - return FALSE; - - // sanity check the world position -// if( world->x < m_mapExtent.lo.x || world->x > m_mapExtent.hi.x || -// world->y < m_mapExtent.lo.y || world->y > m_mapExtent.hi.y ) -// return FALSE; - // This is actually an insanity check. Nobody uses the return value, so this just leaves garbage in the - // return pointer. The reason the question gets asked is there are 60 partition cells to 128 radar cells - // (for example), and the radar wants to draw a horizontal line. This line ends up three pixels long - // at the right side, so the radar gives up and doesn't draw the middle one. - // We bind to on radar anyway, and we only ask if we are on radar, so don't intentionally add edge weirdness. - - // convert - radar->x = world->x / m_xSample; - radar->y = world->y / m_ySample; - - // keep it in bounds - if( radar->x < 0 ) - radar->x = 0; - if( radar->x >= RADAR_CELL_WIDTH ) - radar->x = RADAR_CELL_WIDTH - 1; - if( radar->y < 0 ) - radar->y = 0; - if( radar->y >= RADAR_CELL_HEIGHT ) - radar->y = RADAR_CELL_HEIGHT - 1; - - return TRUE; // valid translation - -} - -// ------------------------------------------------------------------------------------------------ -/** Translate an actual pixel location (relative pixel with (0,0) being the top left of - * the radar area) to the "logical" radar coords that would cover the entire area of display - * on the screen. This is needed because some maps are "long" or "tall" and need a translation - * to any radar image that has been scaled to preserve the map aspect ratio */ -// ------------------------------------------------------------------------------------------------ -Bool Radar::localPixelToRadar( const ICoord2D *pixel, ICoord2D *radar ) -{ - - // sanity - if( pixel == NULL || radar == NULL ) - return FALSE; - - // get window size of the radar - ICoord2D size; - m_radarWindow->winGetSize( &size.x, &size.y ); - - // - // act like we're going to draw and find the aspect ratio adjusted points of the - // terrain radar positions - // - ICoord2D start = { 0, 0 }; - ICoord2D ul, lr; - findDrawPositions( start.x, start.y, size.x, size.y, &ul, &lr ); - - // get the scaled width and height - Int scaledWidth = lr.x - ul.x; - Int scaledHeight = lr.y - ul.y; - - // if the pixel is outsize of the adjusted radar area there are no logical coords - if( pixel->x < ul.x || pixel->x > lr.x || - pixel->y < ul.y || pixel->y > lr.y ) - return FALSE; - - if( scaledWidth >= scaledHeight ) - { - - // just normal conversion from full stretched to radar cells - radar->x = (pixel->x - ul.x)* RADAR_CELL_WIDTH / scaledWidth; - - // conversion for scaled Y direction in map - radar->y = REAL_TO_INT( ((pixel->y - ul.y) / INT_TO_REAL( scaledHeight )) * size.y ); - - // - // radar->y now refers to a point that was "as if" the map was square, translate to radar - // note that y is inverted to have the radar align with the world (+x = right, -y = down) - // - radar->y = (size.y - radar->y) * RADAR_CELL_HEIGHT / size.y; - - - } - else - { - - // conversion for scaled Y direction in map - radar->x = REAL_TO_INT( ((pixel->x - ul.x) / INT_TO_REAL( scaledWidth )) * size.x ); - - // radar->x now refers to a point that was "as if" the map was square, translate to radar - radar->x = radar->x * RADAR_CELL_WIDTH / size.x; - - // - // just normal conversion from full stretched to radar cells, note that y is inverted - // to have the radar align with the world (+x = right, -y = down) - // - radar->y = (size.y - pixel->y) * RADAR_CELL_HEIGHT / size.y; - - } - - return TRUE; - -} - -// ------------------------------------------------------------------------------------------------ -/** Translate a screen mouse position to world coords if the screen position is within - * the radar window and that spot in the radar corresponds to a point in the world */ -// ------------------------------------------------------------------------------------------------ -Bool Radar::screenPixelToWorld( const ICoord2D *pixel, Coord3D *world ) -{ - - // sanity - if( pixel == NULL || world == NULL ) - return FALSE; - - // if we have no radar window can't do the conversion - if( m_radarWindow == NULL ) - return FALSE; - - // translate pixel coords to local pixel coords relative to the radar window - ICoord2D localPixel; - ICoord2D screenPos; - m_radarWindow->winGetScreenPosition( &screenPos.x, &screenPos.y ); - localPixel.x = pixel->x - screenPos.x; - localPixel.y = pixel->y - screenPos.y; - - // translate local pixel to radar - ICoord2D radar; - if( localPixelToRadar( &localPixel, &radar ) == FALSE ) - return FALSE; - - // translate radar to world - return radarToWorld( &radar, world ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Given the pixel coordinates, see if there is an object that is exactly in this - * spot represented on the radar */ -// ------------------------------------------------------------------------------------------------ -Object *Radar::objectUnderRadarPixel( const ICoord2D *pixel ) -{ - - // sanity - if( pixel == NULL ) - return NULL; - - // convert pixel location to radar logical radar location - ICoord2D radar; - if( localPixelToRadar( pixel, &radar ) == FALSE ) - return NULL; - - // object we will return - Object *obj = NULL; - - // - // scan the objects on the radar list and return any object that maps its world location - // to the radar location - // - - // search the local object list - obj = searchListForRadarLocationMatch( m_localObjectList, &radar ); - - // search all other objects if not found - if( obj == NULL ) - obj = searchListForRadarLocationMatch( m_objectList, &radar ); - - // return the object found (if any) - return obj; - -} - -// ------------------------------------------------------------------------------------------------ -/** Search the object list for an object that maps to the given logical radar coords */ -// ------------------------------------------------------------------------------------------------ -Object *Radar::searchListForRadarLocationMatch( RadarObject *listHead, ICoord2D *radarMatch ) -{ - - // sanity - if( listHead == NULL || radarMatch == NULL ) - return NULL; - - // scan the list - RadarObject *radarObject; - ICoord2D radar; - for( radarObject = listHead; radarObject; radarObject = radarObject->friend_getNext() ) - { - - // get object - Object *obj = radarObject->friend_getObject(); - - // sanity - if( obj == NULL ) - { - - DEBUG_CRASH(( "Radar::searchListForRadarLocationMatch - NULL object encountered in list" )); - continue; - - } - - // convert object position to logical radar - worldToRadar( obj->getPosition(), &radar ); - - // see if this matches our match radar location - if( radar.x >= radarMatch->x - 1 && - radar.x <= radarMatch->x + 1 && - radar.y >= radarMatch->y - 1 && - radar.y <= radarMatch->y + 1 ) - return obj; - - } - - // no match found - return NULL; - -} - -// ------------------------------------------------------------------------------------------------ -/** Given the RELATIVE SCREEN start X and Y, the width and height of the area to draw the whole - * radar in, compute what the upper left (ul) and lower right (lr) local coordinates are - * that represent the actual terrain image part of the radar that will preserve the - * aspect ratio of the map */ -// ------------------------------------------------------------------------------------------------ -void Radar::findDrawPositions( Int startX, Int startY, Int width, Int height, - ICoord2D *ul, ICoord2D *lr ) -{ - - Real ratioWidth; - Real ratioHeight; - Coord2D radar; - ratioWidth = m_mapExtent.width()/(width * 1.0f); - ratioHeight = m_mapExtent.height()/(height* 1.0f); - - if( ratioWidth >= ratioHeight) - { - radar.x = m_mapExtent.width() / ratioWidth; - radar.y = m_mapExtent.height()/ ratioWidth; - ul->x = 0; - ul->y = (height - radar.y) / 2.0f; - lr->x = radar.x; - lr->y = height - ul->y; - } - else - { - radar.x = m_mapExtent.width() / ratioHeight; - radar.y = m_mapExtent.height()/ ratioHeight; - ul->x = (width - radar.x ) / 2.0f; - ul->y = 0; - lr->x = width - ul->x; - lr->y = radar.y; - } -/* - - if( m_mapExtent.width() > m_mapExtent.height() ) - { - - // - // +---------------+ - // | | - // | | - // +---------------+ - // | map area | - // +---------------+ - // | | - // | | - // +---------------+ - // - ul->x = 0; - ul->y = (height - (m_mapExtent.height() / m_mapExtent.width() * height)) / 2.0f; - lr->x = width; - lr->y = height - ul->y; - - } - else if( m_mapExtent.height() > m_mapExtent.width() ) - { - - // +-----+---+-----+ - // | | m | | - // | | a | | - // | | p | | - // | | | | - // | | a | | - // | | r | | - // | | e | | - // | | a | | - // +-----+---+-----+ - // - - ul->x = (width - (m_mapExtent.width() / m_mapExtent.height() * width)) / 2.0f; - ul->y = 0; - lr->x = width - ul->x; - lr->y = height; - - } - else - { - - ul->x = 0; - ul->y = 0; - lr->x = width; - lr->y = height; - - } -*/ - - // make them pixel positions - ul->x += startX; - ul->y += startY; - lr->x += startX; - lr->y += startY; - -} - -//------------------------------------------------------------------------------------------------- -/** Radar color lookup table */ -//------------------------------------------------------------------------------------------------- -struct RadarColorLookup -{ - RadarEventType event; - RGBAColorInt color1; - RGBAColorInt color2; -}; -static RadarColorLookup radarColorLookupTable[] = -{ - /* Radar Event Color 1 Color 2 */ - { RADAR_EVENT_CONSTRUCTION, { 128, 128, 255, 255 }, { 128, 255, 255, 255 } }, - { RADAR_EVENT_UPGRADE, { 128, 0, 64, 255 }, { 255, 185, 220, 255 } }, - { RADAR_EVENT_UNDER_ATTACK, { 255, 0, 0, 255 }, { 255, 128, 128, 255 } }, - { RADAR_EVENT_INFORMATION, { 255, 255, 0, 255 }, { 255, 255, 128, 255 } }, - { RADAR_EVENT_BEACON_PULSE, { 255, 255, 0, 255 }, { 255, 255, 128, 255 } }, - { RADAR_EVENT_INFILTRATION, { 0, 255, 255, 255 }, { 128, 255, 255, 255 } }, - { RADAR_EVENT_BATTLE_PLAN, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } }, - { RADAR_EVENT_STEALTH_DISCOVERED, { 0, 255, 0, 255 }, { 0, 128, 0, 255 } }, - { RADAR_EVENT_STEALTH_NEUTRALIZED, { 0, 255, 0, 255 }, { 0, 128, 0, 255 } }, - { RADAR_EVENT_FAKE, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - { RADAR_EVENT_INVALID, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } } -}; - -//------------------------------------------------------------------------------------------------- -/** Create a new radar event */ -//------------------------------------------------------------------------------------------------- -void Radar::createEvent( const Coord3D *world, RadarEventType type, Real secondsToLive ) -{ - - // sanity - if( world == NULL ) - return; - - // lookup the colors we are to used based on the event - RGBAColorInt color[ 2 ]; - Int i = 0; - for( ; radarColorLookupTable[ i ].event != RADAR_EVENT_INVALID; ++i ) - { - - if( radarColorLookupTable[ i ].event == type ) - { - - color[ 0 ] = radarColorLookupTable[ i ].color1; - color[ 1 ] = radarColorLookupTable[ i ].color2; - break; - - } - - } - - // check for no match found in color table - if( radarColorLookupTable[ i ].event == RADAR_EVENT_INVALID ) - { - static RGBAColorInt color1 = { 255, 255, 255, 255 }; - static RGBAColorInt color2 = { 255, 255, 255, 255 }; - - DEBUG_CRASH(( "Radar::createEvent - Event not found in color table, using default colors" )); - color[ 0 ] = color1; - color[ 1 ] = color2; - - } - - // call the internal method to create the event with these colors - internalCreateEvent( world, type, secondsToLive, &color[ 0 ], &color[ 1 ] ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Create radar event using a specific colors from the player */ -// ------------------------------------------------------------------------------------------------ -void Radar::createPlayerEvent( Player *player, const Coord3D *world, - RadarEventType type, Real secondsToLive ) -{ - - // sanity - if( player == NULL || world == NULL ) - return; - - // figure out the two colors we should use - Color c; - UnsignedByte r, g, b, a; - RGBAColorInt color[ 2 ]; - - // color 1 - c = player->getPlayerColor(); - GameGetColorComponents( c, &r, &g, &b, &a ); - color[ 0 ].red = r; - color[ 0 ].green = g; - color[ 0 ].blue = b; - color[ 0 ].alpha = a; - - // the second will be a darker color 1 - Real darkScale = 0.75f; - color[ 1 ] = color[ 0 ]; - color[ 1 ].red -= REAL_TO_INT( color[ 0 ].red * darkScale ); - if( color[ 1 ].red < 0 ) - color[ 1 ].red = 0; - color[ 1 ].green -= REAL_TO_INT( color[ 0 ].green * darkScale ); - if( color[ 1 ].green < 0 ) - color[ 1 ].green = 0; - color[ 1 ].blue -= REAL_TO_INT( color[ 0 ].blue * darkScale ); - if( color[ 1 ].blue < 0 ) - color[ 1 ].blue = 0; - - // create the events using these colors - internalCreateEvent( world, type, secondsToLive, &color[ 0 ], &color[ 1 ] ); - -} - -//------------------------------------------------------------------------------------------------- -/** Create a new radar event */ -//------------------------------------------------------------------------------------------------- -void Radar::internalCreateEvent( const Coord3D *world, RadarEventType type, Real secondsToLive, - const RGBAColorInt *color1, const RGBAColorInt *color2 ) -{ - static Real secondsBeforeDieToFade = 0.5f; ///< this many seconds before we hit the die frame we start to fade away - - // sanity - if( world == NULL || color1 == NULL || color2 == NULL ) - return; - - // translate the world coord to radar coords - ICoord2D radar; - worldToRadar( world, &radar ); - - // add to the list of radar events - m_event[ m_nextFreeRadarEvent ].type = type; - m_event[ m_nextFreeRadarEvent ].active = TRUE; - m_event[ m_nextFreeRadarEvent ].createFrame = TheGameLogic->getFrame(); - m_event[ m_nextFreeRadarEvent ].dieFrame = TheGameLogic->getFrame() + LOGICFRAMES_PER_SECOND * secondsToLive; - m_event[ m_nextFreeRadarEvent ].fadeFrame = m_event[ m_nextFreeRadarEvent ].dieFrame - LOGICFRAMES_PER_SECOND * secondsBeforeDieToFade; - m_event[ m_nextFreeRadarEvent ].color1 = *color1; - m_event[ m_nextFreeRadarEvent ].color2 = *color2; - m_event[ m_nextFreeRadarEvent ].worldLoc = *world; - m_event[ m_nextFreeRadarEvent ].radarLoc = radar; - m_event[ m_nextFreeRadarEvent ].soundPlayed = FALSE; - - // record the index of this, our "last" radar event. - if ( type != RADAR_EVENT_BEACON_PULSE ) - m_lastRadarEvent = m_nextFreeRadarEvent; - - // - // increment the next radar event index, wrapping to the beginning. If we ever have so many - // events that they fill up the buffer the oldest ones will just drop off, eh ... should be fine. - // - m_nextFreeRadarEvent++; - if( m_nextFreeRadarEvent >= MAX_RADAR_EVENTS ) - m_nextFreeRadarEvent = 0; - -} - -//------------------------------------------------------------------------------------------------- -/** Get the last event position, if any. - * Returns TRUE if event was found - * Returns FALSE if there is no "last event" */ -//------------------------------------------------------------------------------------------------- -Bool Radar::getLastEventLoc( Coord3D *eventPos ) -{ - - // if we have an index for the last event, one was present - if( m_lastRadarEvent != -1 ) - { - - if( eventPos ) - *eventPos = m_event[ m_lastRadarEvent ].worldLoc; - return TRUE; - - } - - return FALSE; // no last event - -} - -// ------------------------------------------------------------------------------------------------ -/** Try to create a radar event for "we're under attack". This will be called every time - * actual damage is dealt to an object that the player owns that shows up on the radar. - * We don't want to create under attack events every time we are damaged and we also want - * to limit them based on time and local area of other recent attack events */ -// ------------------------------------------------------------------------------------------------ -void Radar::tryUnderAttackEvent( const Object *obj ) -{ - - // sanity - if( obj == NULL ) - return; - - // try to create the event - Bool eventCreated = tryEvent( RADAR_EVENT_UNDER_ATTACK, obj->getPosition() ); - - // if event created, do some more feedback - if( eventCreated ) - { - - TheControlBar->triggerRadarAttackGlow(); - // - ///@todo Should make an INI data driven table for radar event strings, and audio events - // - // UI feedback for being under attack (note that we display these messages and audio - // queues even if we don't have a radar) - // - Player *player = rts::getObservedOrLocalPlayer(); - - // create a message for the attack event - if( obj->isKindOf( KINDOF_INFANTRY ) || obj->isKindOf( KINDOF_VEHICLE ) ) - { - AudioEventRTS unitAttackSound; - if( obj->isKindOf(KINDOF_HARVESTER) ) - { - // display special message - TheInGameUI->message( "RADAR:HarvesterUnderAttack" ); - - // play special audio event - unitAttackSound = TheAudio->getMiscAudio()->m_radarHarvesterUnderAttackSound; - } - else - { - // display message - TheInGameUI->message( "RADAR:UnitUnderAttack" ); - - // play audio event - unitAttackSound = TheAudio->getMiscAudio()->m_radarStructureUnderAttackSound; - } - unitAttackSound.setPlayerIndex(player->getPlayerIndex()); - TheAudio->addAudioEvent( &unitAttackSound ); - - } - else if( obj->isKindOf( KINDOF_STRUCTURE ) && obj->isKindOf( KINDOF_MP_COUNT_FOR_VICTORY ) ) - { - // play EVA. If its our object, play Base under attack. - if (obj->getControllingPlayer()->isLocalPlayer()) - TheEva->setShouldPlay(EVA_BaseUnderAttack); - else if (player->getRelationship(obj->getTeam()) == ALLIES) - TheEva->setShouldPlay(EVA_AllyUnderAttack); - - // display message - TheInGameUI->message( "RADAR:StructureUnderAttack" ); - - // play audio event - static AudioEventRTS structureAttackSound = TheAudio->getMiscAudio()->m_radarStructureUnderAttackSound; - structureAttackSound.setPlayerIndex(player->getPlayerIndex()); - TheAudio->addAudioEvent( &structureAttackSound ); - - } - else - { - - // display message - TheInGameUI->message( "RADAR:UnderAttack" ); - - // play audio event - static AudioEventRTS underAttackSound = TheAudio->getMiscAudio()->m_radarStructureUnderAttackSound; - underAttackSound.setPlayerIndex(player->getPlayerIndex()); - TheAudio->addAudioEvent( &underAttackSound ); - - } - - } - -} - -// ------------------------------------------------------------------------------------------------ -/** Try to create a radar event for "infiltration". - This happens whenever a unit is hijacked, defected, converted to carbomb, hacked, or - otherwise snuck into */ -// ------------------------------------------------------------------------------------------------ -void Radar::tryInfiltrationEvent( const Object *obj ) -{ - - //Sanity! - if( !obj ) - { - return; - } - - Player *player = rts::getObservedOrLocalPlayer(); - - // We should only be warned against infiltrations that are taking place against us. - if( obj->getControllingPlayer() != player ) - return; - - // create the radar event - createEvent( obj->getPosition(), RADAR_EVENT_INFILTRATION ); - - // - ///@todo Should make an INI data driven table for radar event strings, and audio events - // - // UI feedback for being under attack (note that we display these messages and audio - // queues even if we don't have a radar) - // - - // display message - TheInGameUI->message( "RADAR:Infiltration" ); - - // play audio event - static AudioEventRTS infiltrationWarningSound = TheAudio->getMiscAudio()->m_radarInfiltrationSound; - infiltrationWarningSound.setPlayerIndex(player->getPlayerIndex()); - TheAudio->addAudioEvent( &infiltrationWarningSound ); - -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -Bool Radar::tryEvent( RadarEventType event, const Coord3D *pos ) -{ - - // sanity - if( event <= RADAR_EVENT_INVALID || event >= RADAR_EVENT_NUM_EVENTS || pos == NULL ) - return FALSE; - - // see if there was an event of this type within the given range within the given time - UnsignedInt currentFrame = TheGameLogic->getFrame(); - const Real closeEnoughDistanceSq = 250.0f * 250.0f; - const UnsignedInt framesBetweenEvents = LOGICFRAMES_PER_SECOND * 10; - // - - // see if there was any matching radar event within range of this one - // that wasn't too long ago, if there was we won't create another and get outta here - // - for( Int i = 0; i < MAX_RADAR_EVENTS; ++i ) - { - - // only pay attention to under attack events - if( m_event[ i ].type == event ) - { - - // get distance from our new event location to this event location in 2D - Real distSquared = m_event[ i ].worldLoc.x - pos->x * m_event[ i ].worldLoc.x - pos->x + - m_event[ i ].worldLoc.y - pos->y * m_event[ i ].worldLoc.y - pos->y; - - if( distSquared <= closeEnoughDistanceSq ) - { - - // finally only reject making a new event of this existing one is "recent enough" - if( currentFrame - m_event[ i ].createFrame < framesBetweenEvents ) - return FALSE; // reject it - - } - - } - - } - - // if we got here then we want to create a new event - createEvent( pos, event ); - - // return TRUE for successfully created event - return TRUE; - -} - - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void Radar::refreshTerrain( TerrainLogic *terrain ) -{ - - // no future queue is valid now - m_queueTerrainRefreshFrame = 0; - -} - -// ------------------------------------------------------------------------------------------------ -/** Queue a refresh of the radar terrain, we have this so that if there is code that - * rapidly needs to refresh the radar, it should use this so we aren't continually - * rebuilding the radar graphic because that process is slow. If you need to update - * the terrain on the radar immediately use refreshTerrain() */ -// ------------------------------------------------------------------------------------------------ -void Radar::queueTerrainRefresh( void ) -{ - - // - // we just simply overwrite the frame we have recorded for a radar refresh. If there was - // already one there, it's simply just forgotten and whatever changes we wanted to see - // with that refresh will have to wait until enough time has passed to show these - // changes as well. why you ask ... well, because if we're calling this in close enough - // proximity for us to overwrite something, we're changing the terrain features - // quite often and can't afford the expense of rebuilding the radar visual - // - m_queueTerrainRefreshFrame = TheGameLogic->getFrame(); - -} - -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void Radar::crc( Xfer *xfer ) -{ - -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer a radar object list given the head pointer as a parameter - * Version Info; - * 1: Initial version */ -// ------------------------------------------------------------------------------------------------ -static void xferRadarObjectList( Xfer *xfer, RadarObject **head ) -{ - RadarObject *radarObject; - - // sanity - DEBUG_ASSERTCRASH( head != NULL, ("xferRadarObjectList - Invalid parameters" )); - - // version - XferVersion currentVersion = 1; - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - // write could of objects in list - UnsignedShort count = 0; - for( radarObject = *head; radarObject; radarObject = radarObject->friend_getNext() ) - count++; - xfer->xferUnsignedShort( &count ); - - // xfer the list data - if( xfer->getXferMode() == XFER_SAVE ) - { - - // save each object - for( radarObject = *head; radarObject; radarObject = radarObject->friend_getNext() ) - { - - // save this object - xfer->xferSnapshot( radarObject ); - - } - - } - else - { - - // the list should be empty at this point as we are loading it as a whole - if( *head != NULL ) - { -#if 1 - // srj sez: yeah, it SHOULD be, but a few rogue things come into existence (via their ctor) preloaded - // with stuff (eg, "CabooseFullOfTerrorists"). we immediately destroy 'em, but they don't go away just yet. - // so just ignore 'em if possible. - for( radarObject = *head; radarObject; radarObject = radarObject->friend_getNext() ) - { - if (!radarObject->friend_getObject()->isDestroyed()) - { - DEBUG_CRASH(( "xferRadarObjectList - List head should be NULL, or contain only destroyed objects" )); - throw SC_INVALID_DATA; - } - } -#else - DEBUG_CRASH(( "xferRadarObjectList - List head should be NULL, but isn't" )); - throw SC_INVALID_DATA; -#endif - } - - // read each element - for( UnsignedShort i = 0; i < count; ++i ) - { - - // alloate a new radar object - radarObject = newInstance(RadarObject); - - // link to the end of the list - if( *head == NULL ) - *head = radarObject; - else - { - - RadarObject *other; - for( other = *head; other->friend_getNext() != NULL; other = other->friend_getNext() ) - { - } - - // set the end of the list to point to the new object - other->friend_setNext( radarObject ); - - } - - // load the data - xfer->xferSnapshot( radarObject ); - - } - - } - -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer Method - * Version Info: - * 1: Initial version - * 2: TheSuperHackers @tweak Serialize m_radarHidden, m_radarForceOn for each player - */ -// ------------------------------------------------------------------------------------------------ -void Radar::xfer( Xfer *xfer ) -{ - - // version -#if RETAIL_COMPATIBLE_XFER_SAVE - XferVersion currentVersion = 1; -#else - XferVersion currentVersion = 2; -#endif - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - - if (version <= 1) - { - const Int localPlayerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex(); - Bool value; - - // radar hidden - value = m_radarHidden[localPlayerIndex]; - xfer->xferBool( &value ); - m_radarHidden[localPlayerIndex] = value; - - // radar force on - value = m_radarForceOn[localPlayerIndex]; - xfer->xferBool( &value ); - m_radarForceOn[localPlayerIndex] = value; - } - else - { - static_assert(sizeof(m_radarHidden) == 16, "Increase version if size changes"); - xfer->xferUser(&m_radarHidden, sizeof(m_radarHidden)); - - static_assert(sizeof(m_radarForceOn) == 16, "Increase version if size changes"); - xfer->xferUser(&m_radarForceOn, sizeof(m_radarForceOn)); - } - - // save our local object list - xferRadarObjectList( xfer, &m_localObjectList ); - - // save the regular object list - xferRadarObjectList( xfer, &m_objectList ); - - // save the radar event count and data - UnsignedShort eventCountVerify = MAX_RADAR_EVENTS; - UnsignedShort eventCount = eventCountVerify; - xfer->xferUnsignedShort( &eventCount ); - if( eventCount != eventCountVerify ) - { - - DEBUG_CRASH(( "Radar::xfer - size of MAX_RADAR_EVENTS has changed, you must version this xfer method to accomodate the new array size. Was '%d' and is now '%d'", - eventCount, eventCountVerify )); - throw SC_INVALID_DATA; - - } - for( UnsignedShort i = 0; i < eventCount; ++i ) - { - - // xfer event data - xfer->xferUser( &m_event[ i ].type, sizeof( RadarEventType ) ); - xfer->xferBool( &m_event[ i ].active ); - xfer->xferUnsignedInt( &m_event[ i ].createFrame ); - xfer->xferUnsignedInt( &m_event[ i ].dieFrame ); - xfer->xferUnsignedInt( &m_event[ i ].fadeFrame ); - xfer->xferRGBAColorInt( &m_event[ i ].color1 ); - xfer->xferRGBAColorInt( &m_event[ i ].color2 ); - xfer->xferCoord3D( &m_event[ i ].worldLoc ); - xfer->xferICoord2D( &m_event[ i ].radarLoc ); - xfer->xferBool( &m_event[ i ].soundPlayed ); - - } - - // next event index - xfer->xferInt( &m_nextFreeRadarEvent ); - - // last event index - xfer->xferInt( &m_lastRadarEvent ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void Radar::loadPostProcess( void ) -{ - - // - // refresh the radar texture now that all the objects (specifically bridges) have - // been loaded with their correct damage states from save game file - // - refreshTerrain( TheTerrainLogic ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Is the priority type passed in a "visible" one that can show up on the radar */ -// ------------------------------------------------------------------------------------------------ -Bool Radar::isPriorityVisible( RadarPriorityType priority ) -{ - - switch( priority ) - { - - case RADAR_PRIORITY_INVALID: - case RADAR_PRIORITY_NOT_ON_RADAR: - return FALSE; - - default: - return TRUE; - - } - -} diff --git a/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp index c14a6d30cc..168f12307c 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp @@ -2143,7 +2143,12 @@ Bool TerrainLogic::isUnderwater( Real x, Real y, Real *waterZ, Real *terrainZ ) // if no water here, no height, no nuttin if( waterHandle == NULL ) + { + // but we have to return the terrain Z if requested! + if (terrainZ) + *terrainZ=getGroundHeight(x,y); return FALSE; + } // // if this water handle is a grid water use the grid height function, otherwise look into diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp index af3dc0064e..a1f767a712 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp @@ -744,6 +744,7 @@ void StealthUpdate::changeVisualDisguise() FXList::doFXPos( data->m_disguiseFX, self->getPosition() ); m_disguised = true; + self->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_DISGUISED ) ); } else if( m_disguiseAsPlayerIndex != -1 ) { @@ -809,6 +810,7 @@ void StealthUpdate::changeVisualDisguise() FXList::doFXPos( data->m_disguiseRevealFX, self->getPosition() ); m_disguised = false; + self->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_DISGUISED ) ); } //Reset the radar (determines color on add) diff --git a/Generals/Code/GameEngineDevice/CMakeLists.txt b/Generals/Code/GameEngineDevice/CMakeLists.txt index 63a78b15a4..0f26cbd753 100644 --- a/Generals/Code/GameEngineDevice/CMakeLists.txt +++ b/Generals/Code/GameEngineDevice/CMakeLists.txt @@ -4,7 +4,7 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/Common/W3DConvert.h Include/W3DDevice/Common/W3DFunctionLexicon.h Include/W3DDevice/Common/W3DModuleFactory.h - Include/W3DDevice/Common/W3DRadar.h +# Include/W3DDevice/Common/W3DRadar.h Include/W3DDevice/Common/W3DThingFactory.h Include/W3DDevice/GameClient/HeightMap.h Include/W3DDevice/GameClient/Module/W3DDebrisDraw.h @@ -81,7 +81,7 @@ set(GAMEENGINEDEVICE_SRC # Source/MilesAudioDevice/MilesAudioManager.cpp # Source/VideoDevice/Bink/BinkVideoPlayer.cpp Source/W3DDevice/Common/System/W3DFunctionLexicon.cpp - Source/W3DDevice/Common/System/W3DRadar.cpp +# Source/W3DDevice/Common/System/W3DRadar.cpp Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp Source/W3DDevice/Common/Thing/W3DThingFactory.cpp Source/W3DDevice/Common/W3DConvert.cpp diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h deleted file mode 100644 index 2a4f0b554e..0000000000 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -** Command & Conquer Generals(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: W3DRadar.h /////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, January 2002 -// Desc: W3D radar implementation, this has the necessary device dependent drawing -// necessary for the radar - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Common/Radar.h" -#include "WW3D2/ww3dformat.h" - -// FORWARD REFERENCES ///////////////////////////////////////////////////////////////////////////// -class TextureClass; -class TerrainLogic; - -// PROTOTYPES ///////////////////////////////////////////////////////////////////////////////////// -//------------------------------------------------------------------------------------------------- -/** W3D radar class. This has the device specific implementation of the radar such as - * the drawing routines */ -//------------------------------------------------------------------------------------------------- -class W3DRadar : public Radar -{ - -public: - - W3DRadar( void ); - ~W3DRadar( void ); - - virtual void xfer( Xfer *xfer ); - - virtual void init( void ); ///< subsystem init - virtual void update( void ); ///< subsystem update - virtual void reset( void ); ///< subsystem reset - - virtual RadarObjectType addObject( Object *obj ); ///< add object to radar - virtual RadarObjectType removeObject( Object *obj ); ///< remove object from radar - - virtual void newMap( TerrainLogic *terrain ); ///< reset radar for new map - - virtual void draw( Int pixelX, Int pixelY, Int width, Int height ); ///< draw the radar - - virtual void clearShroud(); - virtual void setShroudLevel(Int x, Int y, CellShroudStatus setting); - - virtual void refreshTerrain( TerrainLogic *terrain ); - virtual void refreshObjects(); - -protected: - - void drawSingleBeaconEvent( Int pixelX, Int pixelY, Int width, Int height, Int index ); - void drawSingleGenericEvent( Int pixelX, Int pixelY, Int width, Int height, Int index ); - - void initializeTextureFormats( void ); ///< find format to use for the radar texture - void deleteResources( void ); ///< delete resources used - void drawEvents( Int pixelX, Int pixelY, Int width, Int height); ///< draw all of the radar events - void drawHeroIcon( Int pixelX, Int pixelY, Int width, Int height, const Coord3D *pos ); //< draw a hero icon - void drawViewBox( Int pixelX, Int pixelY, Int width, Int height ); ///< draw view box - void buildTerrainTexture( TerrainLogic *terrain ); ///< create the terrain texture of the radar - void drawIcons( Int pixelX, Int pixelY, Int width, Int height ); ///< draw all of the radar icons - void updateObjectTexture(TextureClass *texture); - void renderObjectList( const RadarObject *listHead, TextureClass *texture, Bool calcHero = FALSE ); ///< render an object list to the texture - void interpolateColorForHeight( RGBColor *color, - Real height, - Real hiZ, - Real midZ, - Real loZ ); ///< "shade" color according to height value - void reconstructViewBox( void ); ///< remake the view box - void radarToPixel( const ICoord2D *radar, ICoord2D *pixel, - Int radarUpperLeftX, Int radarUpperLeftY, - Int radarWidth, Int radarHeight ); ///< convert radar coord to pixel location - - WW3DFormat m_terrainTextureFormat; ///< format to use for terrain texture - Image *m_terrainImage; ///< terrain image abstraction for drawing - TextureClass *m_terrainTexture; ///< terrain background texture - - WW3DFormat m_overlayTextureFormat; ///< format to use for overlay texture - Image *m_overlayImage; ///< overlay image abstraction for drawing - TextureClass *m_overlayTexture; ///< overlay texture - - WW3DFormat m_shroudTextureFormat; ///< format to use for shroud texture - Image *m_shroudImage; ///< shroud image abstraction for drawing - TextureClass *m_shroudTexture; ///< shroud texture - - Int m_textureWidth; ///< width for all radar textures - Int m_textureHeight; ///< height for all radar textures - - // - // we want to keep a flag that tells us when to reconstruct the view box, we want - // to reconstruct the box on map change, and when the camera changes height - // or orientation. We want to avoid making the view box every frame because - // the 4 points visible on the edge of the screen will "jitter" unevenly as we - // translate real world coords to integer radar spots - // - Bool m_reconstructViewBox; ///< true when we need to reconstruct the box - Real m_viewAngle; ///< camera angle used for the view box we have - Real m_viewZoom; ///< camera zoom used for the view box we have - ICoord2D m_viewBox[ 4 ]; ///< radar cell points for the 4 corners of view box - - std::vector m_cachedHeroObjectList; //< cache of hero objects for drawing icons in radar overlay -}; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp deleted file mode 100644 index 1c7d5dcab9..0000000000 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ /dev/null @@ -1,1640 +0,0 @@ -/* -** Command & Conquer Generals(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: W3DRadar.cpp ///////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, January 2002 -// Desc: W3D radar implementation, this has the necessary device dependent drawing -// necessary for the radar -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Common/AudioEventRTS.h" -#include "Common/Debug.h" -#include "Common/GlobalData.h" -#include "Common/GameUtility.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" - -#include "GameLogic/TerrainLogic.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/Object.h" - -#include "GameLogic/Module/StealthUpdate.h" - -#include "GameClient/Color.h" -#include "GameClient/ControlBar.h" -#include "GameClient/Display.h" -#include "GameClient/GameClient.h" -#include "GameClient/GameWindow.h" -#include "GameClient/Image.h" -#include "GameClient/Line2D.h" -#include "GameClient/TerrainVisual.h" -#include "GameClient/Water.h" -#include "W3DDevice/Common/W3DRadar.h" -#include "W3DDevice/GameClient/HeightMap.h" -#include "W3DDevice/GameClient/W3DShroud.h" -#include "WW3D2/texture.h" -#include "WW3D2/dx8caps.h" - - - -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// -enum { OVERLAY_REFRESH_RATE = 6 }; ///< over updates once this many frames - -//------------------------------------------------------------------------------------------------- -/** Is the point legal, that is, inside the resolution of the radar cells */ -//------------------------------------------------------------------------------------------------- -inline Bool legalRadarPoint( Int px, Int py ) -{ - - if( px < 0 || py < 0 || px >= RADAR_CELL_WIDTH || py >= RADAR_CELL_HEIGHT ) - return FALSE; - - return TRUE; - -} - -//------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------ -static WW3DFormat findFormat(const WW3DFormat formats[]) -{ - for( Int i = 0; formats[ i ] != WW3D_FORMAT_UNKNOWN; i++ ) - { - - if( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( formats[ i ] ) ) - { - - return formats[ i ]; - - } - - } - DEBUG_CRASH(("WW3DRadar: No appropriate texture format") ); - return WW3D_FORMAT_UNKNOWN; -} - -//------------------------------------------------------------------------------------------------- -/** Find the texture format we're going to use for the radar. The texture format must - * be supported by the hardware. The "more preferred" formats appear at the top of - * the format tables in order from most preferred to least preferred */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::initializeTextureFormats( void ) -{ - const WW3DFormat terrainFormats[] = - { - WW3D_FORMAT_R8G8B8, - WW3D_FORMAT_X8R8G8B8, - WW3D_FORMAT_R5G6B5, - WW3D_FORMAT_X1R5G5B5, - WW3D_FORMAT_UNKNOWN // keep this one last - }; - const WW3DFormat overlayFormats[] = - { - WW3D_FORMAT_A8R8G8B8, - WW3D_FORMAT_A4R4G4B4, - WW3D_FORMAT_UNKNOWN // keep this one last - }; - const WW3DFormat shroudFormats[] = - { - WW3D_FORMAT_A8R8G8B8, - WW3D_FORMAT_A4R4G4B4, - WW3D_FORMAT_UNKNOWN // keep this one last - }; - - // find a format for the terrain texture - m_terrainTextureFormat = findFormat(terrainFormats); - - // find a format for the overlay texture - m_overlayTextureFormat = findFormat(overlayFormats); - - // find a format for the shroud texture - m_shroudTextureFormat = findFormat(shroudFormats); - -} - -//------------------------------------------------------------------------------------------------- -/** Delete resources used specifically in this W3D radar implemetation */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::deleteResources( void ) -{ - - // - // delete terrain resources used - // - if( m_terrainTexture ) - m_terrainTexture->Release_Ref(); - m_terrainTexture = NULL; - - deleteInstance(m_terrainImage); - m_terrainImage = NULL; - - // - // delete overlay resources used - // - if( m_overlayTexture ) - m_overlayTexture->Release_Ref(); - m_overlayTexture = NULL; - - deleteInstance(m_overlayImage); - m_overlayImage = NULL; - - // - // delete shroud resources used - // - if( m_shroudTexture ) - m_shroudTexture->Release_Ref(); - m_shroudTexture = NULL; - - deleteInstance(m_shroudImage); - m_shroudImage = NULL; - -} - -//------------------------------------------------------------------------------------------------- -/** Reconstruct the view box given the current camera settings */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::reconstructViewBox( void ) -{ - Coord3D world[ 4 ]; - ICoord2D radar[ 4 ]; - Int i; - - // get the 4 points of the view corners in the 3D world at the average Z height in the map - TheTacticalView->getScreenCornerWorldPointsAtZ( &world[ 0 ], - &world[ 1 ], - &world[ 2 ], - &world[ 3 ], - getTerrainAverageZ() ); - - // convert each of the 4 points in the world to radar cell positions - for( i = 0; i < 4; i++ ) - { - - // first convert to radar cells - radar[ i ].x = world[ i ].x / (m_mapExtent.width() / RADAR_CELL_WIDTH); - radar[ i ].y = world[ i ].y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); - - // - // store these points in the view box array which contains a first position - // of (0,0) and then offsets for each additional entry point - // - if( i == 0 ) - { - - m_viewBox[ i ].x = 0; - m_viewBox[ i ].y = 0; - - } - else - { - - m_viewBox[ i ].x = radar[ i ].x - radar[ i - 1 ].x; - m_viewBox[ i ].y = radar[ i ].y - radar[ i - 1 ].y; - - } - - } - - // - // save the camera settings for this view box, we will need to make it again only - // if some of these change - // - m_viewAngle = TheTacticalView->getAngle(); - Coord3D pos; - TheTacticalView->getPosition( &pos ); - m_viewZoom = TheTacticalView->getZoom(); - m_reconstructViewBox = FALSE; - -} - -//------------------------------------------------------------------------------------------------- -/** Convert radar position to actual pixel coord */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::radarToPixel( const ICoord2D *radar, ICoord2D *pixel, - Int radarUpperLeftX, Int radarUpperLeftY, - Int radarWidth, Int radarHeight ) -{ - - // sanity - if( radar == NULL || pixel == NULL ) - return; - - pixel->x = (radar->x * radarWidth / RADAR_CELL_WIDTH) + radarUpperLeftX; - // note the "inverted" y here to orient the way our world looks with +x=right and -y=down - pixel->y = ((RADAR_CELL_HEIGHT - 1 - radar->y) * radarHeight / RADAR_CELL_HEIGHT) + radarUpperLeftY; - -} - - -//------------------------------------------------------------------------------------------------- -/** Draw a hero icon at a position, given radar box upper left location and dimensions. */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::drawHeroIcon( Int pixelX, Int pixelY, Int width, Int height, const Coord3D *pos ) -{ - // get the hero icon image - static const Image *image = (Image *)TheMappedImageCollection->findImageByName("HeroReticle"); - if (image != NULL) - { - // convert world to radar coords - ICoord2D ulRadar; - ulRadar.x = pos->x / (m_mapExtent.width() / RADAR_CELL_WIDTH); - ulRadar.y = pos->y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); - - // convert radar to screen coords - ICoord2D offsetScreen; - radarToPixel( &ulRadar, &offsetScreen, pixelX, pixelY, width, height ); - - // shift from an upper left to a center focus for the icon - int iconWidth = image->getImageWidth(); - int iconHeight = image->getImageHeight(); - offsetScreen.x -= (iconWidth / 2) - 1; - offsetScreen.y -= iconHeight / 2; - - // draw the icon - TheDisplay->drawImage( image, offsetScreen.x , offsetScreen.y, offsetScreen.x + iconWidth, offsetScreen.y + iconHeight ); - } -} - -//------------------------------------------------------------------------------------------------- -/** Draw a "box" into the texture passed in that represents the viewable area for - * the tactical display into the game world */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) -{ - ICoord2D ulScreen; - ICoord2D ulRadar; - Coord3D ulWorld; - ICoord2D ulStart = { 0, 0 }; - ICoord2D start, end; - ICoord2D clipStart, clipEnd; - Real lineWidth = 1.0f; - Color topColor = GameMakeColor( 225, 225, 0, 255 ); - Color bottomColor = GameMakeColor( 158, 158, 0, 255 ); - - // - // setup the clipping region ... note that this clipping region is not over just the - // radar image area ... it's in the WHOLE window available for the radar - // - IRegion2D clipRegion; - ICoord2D radarWindowSize, radarWindowScreenPos; - m_radarWindow->winGetSize( &radarWindowSize.x, &radarWindowSize.y ); - m_radarWindow->winGetScreenPosition( &radarWindowScreenPos.x, &radarWindowScreenPos.y ); - clipRegion.lo.x = radarWindowScreenPos.x; - clipRegion.lo.y = radarWindowScreenPos.y; - clipRegion.hi.x = radarWindowScreenPos.x + radarWindowSize.x; - clipRegion.hi.y = radarWindowScreenPos.y + radarWindowSize.y; - - // convert top left of screen into world position - TheTacticalView->getOrigin( &ulScreen.x, &ulScreen.y ); - TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ); - - // convert world to radar coords - ulRadar.x = ulWorld.x / (m_mapExtent.width() / RADAR_CELL_WIDTH); - ulRadar.y = ulWorld.y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); - - // - // convert radar point to actual pixel coords on the screen, shifted - // into position on the radar for where the radar is drawn and the size of the - // area that the radar is drawn in - // - radarToPixel( &ulRadar, &ulStart, pixelX, pixelY, width, height ); - - // - // using our view box offset array, convert each of those radar cell offset points - // into screen pixels and draw the box. The view box array is setup with the - // first index containing (0,0) (the point we just converted in theory), with cell - // offsets to each of the other corners in the following order - // (upper left, upper right, lower right, lower left) - // - ICoord2D radar; - - // top line - start = ulStart; - radar.x = ulRadar.x + m_viewBox[ 1 ].x; - radar.y = ulRadar.y + m_viewBox[ 1 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) - TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, - lineWidth, topColor ); - - // right line - start = end; - radar.x += m_viewBox[ 2 ].x; - radar.y += m_viewBox[ 2 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) - TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, - lineWidth, topColor, bottomColor ); - - // bottom line - start = end; - radar.x += m_viewBox[ 3 ].x; - radar.y += m_viewBox[ 3 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) - TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, - lineWidth, bottomColor ); - - // left line - start = end; - end = ulStart; - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) - TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, - lineWidth, bottomColor, topColor ); - -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void W3DRadar::drawSingleBeaconEvent( Int pixelX, Int pixelY, Int width, Int height, Int index ) -{ - RadarEvent *event = &(m_event[index]); - ICoord2D tri[ 3 ]; - ICoord2D start, end; - Real angle, addAngle; - Color startColor, endColor; - Real lineWidth = 1.0f; - UnsignedInt currentFrame = TheGameLogic->getFrame(); - UnsignedInt frameDiff; // frames the event has been alive for - Real maxEventSize = width / 10.0f; // max size of the event marker - Int minEventSize = 6; // min size of the event marker - Int eventSize; // current size of a marker to draw - const Real TIME_FROM_FULL_SIZE_TO_SMALL_SIZE = LOGICFRAMES_PER_SECOND * 1.5; - Real totalAnglesToSpin = 2.0f * PI; ///< spin around this many angles going from big to small - UnsignedByte r, g, b, a; - - // setup screen clipping region - IRegion2D clipRegion; - clipRegion.lo.x = pixelX; - clipRegion.lo.y = pixelY; - clipRegion.hi.x = pixelX + width; - clipRegion.hi.y = pixelY + height; - - // get the difference in frame from the current frame to the frame we were created on - frameDiff = currentFrame - event->createFrame; - - // compute the size of the event marker, it is largest when it starts and smallest at the end - eventSize = REAL_TO_INT( maxEventSize * ( 1.0f - frameDiff / TIME_FROM_FULL_SIZE_TO_SMALL_SIZE) ); - - // we never let the event size get too small - if( eventSize < minEventSize ) - eventSize = minEventSize; - - // compute how much "angle" we will add to each point to make it rotate as it's getting small - addAngle = -totalAnglesToSpin * (frameDiff / TIME_FROM_FULL_SIZE_TO_SMALL_SIZE); - - // create a triangle around the event - angle = 0.0f - addAngle; - tri[ 0 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 0 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - angle = 2.0f * PI / 3.0f - addAngle; - tri[ 1 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 1 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - angle = -2.0f * PI / 3.0f - addAngle; - tri[ 2 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 2 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - // translate radar coords to screen coords - radarToPixel( &tri[ 0 ], &tri[ 0 ], pixelX, pixelY, width, height ); - radarToPixel( &tri[ 1 ], &tri[ 1 ], pixelX, pixelY, width, height ); - radarToPixel( &tri[ 2 ], &tri[ 2 ], pixelX, pixelY, width, height ); - - // - // make the colors we're going to use, when we're at our smallest size we will start to - // fade the alpha away to transparent so that at our lifetime frame we are completely gone - // - - // color 1 ------------------ - r = event->color1.red; - g = event->color1.green; - b = event->color1.blue; - a = event->color1.alpha; - if( currentFrame > event->fadeFrame ) - { - - a = REAL_TO_UNSIGNEDBYTE( (Real)a * (1.0f - (Real)(currentFrame - event->fadeFrame) / - (Real)(event->dieFrame - event->fadeFrame) ) ); - - } - startColor = GameMakeColor( r, g, b, a ); - - // color 2 ------------------ - r = event->color2.red; - g = event->color2.green; - b = event->color2.blue; - a = event->color2.alpha; - if( currentFrame > event->fadeFrame ) - { - - a = REAL_TO_UNSIGNEDBYTE( (Real)a * (1.0f - (Real)(currentFrame - event->fadeFrame) / - (Real)(event->dieFrame - event->fadeFrame) ) ); - - } - endColor = GameMakeColor( r, g, b, a ); - - // draw the lines - if( ClipLine2D( &tri[ 0 ], &tri[ 1 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); - if( ClipLine2D( &tri[ 1 ], &tri[ 2 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); - if( ClipLine2D( &tri[ 2 ], &tri[ 0 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void W3DRadar::drawSingleGenericEvent( Int pixelX, Int pixelY, Int width, Int height, Int index ) -{ - RadarEvent *event = &(m_event[index]); - ICoord2D tri[ 3 ]; - ICoord2D start, end; - Real angle, addAngle; - Color startColor, endColor; - Real lineWidth = 1.0f; - UnsignedInt currentFrame = TheGameLogic->getFrame(); - UnsignedInt frameDiff; // frames the event has been alive for - Real maxEventSize = width / 2.0f; // max size of the event marker - Int minEventSize = 6; // min size of the event marker - Int eventSize; // current size of a marker to draw - const Real TIME_FROM_FULL_SIZE_TO_SMALL_SIZE = LOGICFRAMES_PER_SECOND * 1.5; - Real totalAnglesToSpin = 2.0f * PI; ///< spin around this many angles going from big to small - UnsignedByte r, g, b, a; - - // setup screen clipping region - IRegion2D clipRegion; - clipRegion.lo.x = pixelX; - clipRegion.lo.y = pixelY; - clipRegion.hi.x = pixelX + width; - clipRegion.hi.y = pixelY + height; - - // get the difference in frame from the current frame to the frame we were created on - frameDiff = currentFrame - event->createFrame; - - // compute the size of the event marker, it is largest when it starts and smallest at the end - eventSize = REAL_TO_INT( maxEventSize * ( 1.0f - frameDiff / TIME_FROM_FULL_SIZE_TO_SMALL_SIZE) ); - - // we never let the event size get too small - if( eventSize < minEventSize ) - eventSize = minEventSize; - - // compute how much "angle" we will add to each point to make it rotate as it's getting small - addAngle = totalAnglesToSpin * (frameDiff / TIME_FROM_FULL_SIZE_TO_SMALL_SIZE); - - // create a triangle around the event - angle = 0.0f - addAngle; - tri[ 0 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 0 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - angle = 2.0f * PI / 3.0f - addAngle; - tri[ 1 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 1 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - angle = -2.0f * PI / 3.0f - addAngle; - tri[ 2 ].x = REAL_TO_INT( (DOUBLE_TO_REAL( Cos( angle ) ) * eventSize) + event->radarLoc.x ); - tri[ 2 ].y = REAL_TO_INT( (DOUBLE_TO_REAL( Sin( angle ) ) * eventSize) + event->radarLoc.y ); - - // translate radar coords to screen coords - radarToPixel( &tri[ 0 ], &tri[ 0 ], pixelX, pixelY, width, height ); - radarToPixel( &tri[ 1 ], &tri[ 1 ], pixelX, pixelY, width, height ); - radarToPixel( &tri[ 2 ], &tri[ 2 ], pixelX, pixelY, width, height ); - - // - // make the colors we're going to use, when we're at our smallest size we will start to - // fade the alpha away to transparent so that at our lifetime frame we are completely gone - // - - // color 1 ------------------ - r = event->color1.red; - g = event->color1.green; - b = event->color1.blue; - a = event->color1.alpha; - if( currentFrame > event->fadeFrame ) - { - - a = REAL_TO_UNSIGNEDBYTE( (Real)a * (1.0f - (Real)(currentFrame - event->fadeFrame) / - (Real)(event->dieFrame - event->fadeFrame) ) ); - - } - startColor = GameMakeColor( r, g, b, a ); - - // color 2 ------------------ - r = event->color2.red; - g = event->color2.green; - b = event->color2.blue; - a = event->color2.alpha; - if( currentFrame > event->fadeFrame ) - { - - a = REAL_TO_UNSIGNEDBYTE( (Real)a * (1.0f - (Real)(currentFrame - event->fadeFrame) / - (Real)(event->dieFrame - event->fadeFrame) ) ); - - } - endColor = GameMakeColor( r, g, b, a ); - - // draw the lines - if( ClipLine2D( &tri[ 0 ], &tri[ 1 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); - if( ClipLine2D( &tri[ 1 ], &tri[ 2 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); - if( ClipLine2D( &tri[ 2 ], &tri[ 0 ], &start, &end, &clipRegion ) ) - TheDisplay->drawLine( start.x, start.y, end.x, end.y, lineWidth, startColor, endColor ); -} - -//------------------------------------------------------------------------------------------------- -/** Draw all the radar events */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::drawEvents( Int pixelX, Int pixelY, Int width, Int height ) -{ - Int i; - - for( i = 0; i < MAX_RADAR_EVENTS; i++ ) - { - - // only 'active' events actually have something to draw - if( m_event[ i ].active == TRUE && m_event[ i ].type != RADAR_EVENT_FAKE ) - { - - // if we haven't played the sound for this event, do it now that we can see it - if( m_event[ i ].soundPlayed == FALSE && m_event[i].type != RADAR_EVENT_BEACON_PULSE ) - { - static AudioEventRTS eventSound("RadarEvent"); - TheAudio->addAudioEvent( &eventSound ); - - } - - m_event[ i ].soundPlayed = TRUE; - - if ( m_event[ i ].type == RADAR_EVENT_BEACON_PULSE ) - drawSingleBeaconEvent( pixelX, pixelY, width, height, i ); - else - drawSingleGenericEvent( pixelX, pixelY, width, height, i ); - - } - - } - -} - - -//------------------------------------------------------------------------------------------------- -/** Draw all the radar icons */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::drawIcons( Int pixelX, Int pixelY, Int width, Int height ) -{ - // draw the hero icons - std::vector::const_iterator iter = m_cachedHeroObjectList.begin(); - while (iter != m_cachedHeroObjectList.end()) - { - drawHeroIcon( pixelX, pixelY, width, height, (*iter)->getPosition() ); - ++iter; - } -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -void W3DRadar::updateObjectTexture(TextureClass *texture) -{ - // reset the overlay texture - SurfaceClass *surface = texture->Get_Surface_Level(); - surface->Clear(); - REF_PTR_RELEASE(surface); - - // rebuild the object overlay - renderObjectList( getObjectList(), texture ); - renderObjectList( getLocalObjectList(), texture, TRUE ); -} - -//------------------------------------------------------------------------------------------------- -/** Render an object list into the texture passed in */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *texture, Bool calcHero ) -{ - - // sanity - if( listHead == NULL || texture == NULL ) - return; - - // get surface for texture to render into - SurfaceClass *surface = texture->Get_Surface_Level(); - - // loop through all objects and draw - ICoord2D radarPoint; - - Player *player = rts::getObservedOrLocalPlayer(); - const Int playerIndex = player->getPlayerIndex(); - - if( calcHero ) - { - // clear all entries from the cached hero object list - m_cachedHeroObjectList.clear(); - } - - for( const RadarObject *rObj = listHead; rObj; rObj = rObj->friend_getNext() ) - { - - if (rObj->isTemporarilyHidden()) - continue; - - // get object - const Object *obj = rObj->friend_getObject(); - - // check for shrouded status - if (obj->getShroudedStatus(playerIndex) > OBJECTSHROUD_PARTIAL_CLEAR) - continue; //object is fogged or shrouded, don't render it. - - // - // objects with a local only unit priority will only appear on the radar if they - // are controlled by the local player, or if the local player is an observer (cause - // they are godlike and can see everything) - // - if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY && - obj->getControllingPlayer() != player && - player->isPlayerActive() ) - continue; - - // get object position - const Coord3D *pos = obj->getPosition(); - - // compute object position as a radar blip - radarPoint.x = pos->x / (m_mapExtent.width() / RADAR_CELL_WIDTH); - radarPoint.y = pos->y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); - - // get the color we're going to draw in - Color c = rObj->getColor(); - - - - // adjust the alpha for stealth units so they "fade/blink" on the radar for the controller - // if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY ) - // ML-- What the heck is this? local-only and neutral-observer-viewed units are stealthy?? Since when? - // Now it twinkles for any stealthed object, whether locally controlled or neutral-observer-viewed - if( obj->testStatus( OBJECT_STATUS_STEALTHED ) ) - { - StealthUpdate* stealth = obj->getStealth(); - if( !stealth ) - continue; - - if ( TheControlBar->getCurrentlyViewedPlayerRelationship(obj->getTeam()) == ENEMIES ) - if( !obj->testStatus( OBJECT_STATUS_DETECTED ) && !stealth->isDisguised() ) - continue; - - UnsignedByte r, g, b, a; - GameGetColorComponents( c, &r, &g, &b, &a ); - - const UnsignedInt framesForTransition = LOGICFRAMES_PER_SECOND; - const UnsignedByte minAlpha = 32; - - Real alphaScale = INT_TO_REAL(TheGameLogic->getFrame() % framesForTransition) / (framesForTransition / 2.0f); - if( alphaScale > 0.0f ) - a = REAL_TO_UNSIGNEDBYTE( ((alphaScale - 1.0f) * (255.0f - minAlpha)) + minAlpha ); - else - a = REAL_TO_UNSIGNEDBYTE( (alphaScale * (255.0f - minAlpha)) + minAlpha ); - c = GameMakeColor( r, g, b, a ); - - } - - // cache hero objects for drawing in icon layer - if( calcHero && obj->isHero() ) - { - m_cachedHeroObjectList.push_back(obj); - } - - // draw the blip, but make sure the points are legal - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.y++; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.x++; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.y--; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - } - REF_PTR_RELEASE(surface); - -} - -//------------------------------------------------------------------------------------------------- -/** Shade the color passed in using the height parameter to lighten and darken it. Colors - * will be interpolated using the value "height" across the range from loZ to hiZ. The - * midZ is the "middle" point, height values above it will be lightened, while - * lower ones are darkened. */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::interpolateColorForHeight( RGBColor *color, - Real height, - Real hiZ, - Real midZ, - Real loZ ) -{ - const Real howBright = 0.95f; // bigger is brighter (0.0 to 1.0) - const Real howDark = 0.60f; // bigger is darker (0.0 to 1.0) - - // sanity on map height (flat maps bomb) - if (hiZ == midZ) - hiZ = midZ+0.1f; - if (midZ == loZ) - loZ = midZ-0.1f; - if (hiZ == loZ) - hiZ = loZ+0.2f; - - Real t; - RGBColor colorTarget; - - // if "over" the middle height, interpolate lighter - if( height >= midZ ) - { - - // how far are we from the middleZ towards the hi Z - t = (height - midZ) / (hiZ - midZ); - - // compute what our "lightest" color possible we want to use is - colorTarget.red = color->red + (1.0f - color->red) * howBright; - colorTarget.green = color->green + (1.0f - color->green) * howBright; - colorTarget.blue = color->blue + (1.0f - color->blue) * howBright; - - } - else // interpolate darker - { - - // how far are we from the middleZ towards the low Z - t = (midZ - height) / (midZ - loZ); - - // compute what the "darkest" color possible we want to use is - colorTarget.red = color->red + (0.0f - color->red) * howDark; - colorTarget.green = color->green + (0.0f - color->green) * howDark; - colorTarget.blue = color->blue + (0.0f - color->blue) * howDark; - - } - - // interpolate toward the target color - color->red = color->red + (colorTarget.red - color->red) * t; - color->green = color->green + (colorTarget.green - color->green) * t; - color->blue = color->blue + (colorTarget.blue - color->blue) * t; - - // keep the color real - if( color->red < 0.0f ) - color->red = 0.0f; - if( color->red > 1.0f ) - color->red = 1.0f; - if( color->green < 0.0f ) - color->green = 0.0f; - if( color->green > 1.0f ) - color->green = 1.0f; - if( color->blue < 0.0f ) - color->blue = 0.0f; - if( color->blue > 1.0f ) - color->blue = 1.0f; - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// PUBLIC METHODS ///////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DRadar::W3DRadar( void ) -{ - - m_terrainTextureFormat = WW3D_FORMAT_UNKNOWN; - m_terrainImage = NULL; - m_terrainTexture = NULL; - - m_overlayTextureFormat = WW3D_FORMAT_UNKNOWN; - m_overlayImage = NULL; - m_overlayTexture = NULL; - - m_shroudTextureFormat = WW3D_FORMAT_UNKNOWN; - m_shroudImage = NULL; - m_shroudTexture = NULL; - - m_textureWidth = RADAR_CELL_WIDTH; - m_textureHeight = RADAR_CELL_HEIGHT; - - m_reconstructViewBox = TRUE; - m_viewAngle = 0.0f; - m_viewZoom = 0.0f; - for( Int i = 0; i < 4; i++ ) - { - - m_viewBox[ i ].x = 0; - m_viewBox[ i ].y = 0; - - } - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DRadar::~W3DRadar( void ) -{ - - // delete resources used for the W3D radar - deleteResources(); - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -void W3DRadar::xfer( Xfer *xfer ) -{ - Radar::xfer(xfer); -} - -//------------------------------------------------------------------------------------------------- -/** Radar initialization */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::init( void ) -{ - ICoord2D size; - Region2D uv; - - // extending functionality - Radar::init(); - - // gather specific texture format information - initializeTextureFormats(); - - // allocate our terrain texture - // poolify - m_terrainTexture = MSGNEW("TextureClass") TextureClass( m_textureWidth, m_textureHeight, - m_terrainTextureFormat, MIP_LEVELS_1 ); - DEBUG_ASSERTCRASH( m_terrainTexture, ("W3DRadar: Unable to allocate terrain texture") ); - - // allocate our overlay texture - m_overlayTexture = MSGNEW("TextureClass") TextureClass( m_textureWidth, m_textureHeight, - m_overlayTextureFormat, MIP_LEVELS_1 ); - DEBUG_ASSERTCRASH( m_overlayTexture, ("W3DRadar: Unable to allocate overlay texture") ); - - // set filter type for the overlay texture, try it and see if you like it, I don't ;) -// m_overlayTexture->Set_Min_Filter( TextureFilterClass::FILTER_TYPE_NONE ); -// m_overlayTexture->Set_Mag_Filter( TextureFilterClass::FILTER_TYPE_NONE ); - - // allocate our shroud texture - m_shroudTexture = MSGNEW("TextureClass") TextureClass( m_textureWidth, m_textureHeight, - m_shroudTextureFormat, MIP_LEVELS_1 ); - DEBUG_ASSERTCRASH( m_shroudTexture, ("W3DRadar: Unable to allocate shroud texture") ); - m_shroudTexture->Get_Filter().Set_Min_Filter( TextureFilterClass::FILTER_TYPE_DEFAULT ); - m_shroudTexture->Get_Filter().Set_Mag_Filter( TextureFilterClass::FILTER_TYPE_DEFAULT ); - - // - // create images used for rendering and set them up with the textures - // - - // - // the terrain image, note the UV coords change it from (0,0) in the upper left - // to (0,0) in the lower left cause that's how we are initially oriented in the - // world (positive X to the right and positive Y up) - // - m_terrainImage = newInstance(Image); - uv.lo.x = 0.0f; - uv.lo.y = 1.0f; - uv.hi.x = 1.0f; - uv.hi.y = 0.0f; - m_terrainImage->setStatus( IMAGE_STATUS_RAW_TEXTURE ); - m_terrainImage->setRawTextureData( m_terrainTexture ); - m_terrainImage->setUV( &uv ); - m_terrainImage->setTextureWidth( m_textureWidth ); - m_terrainImage->setTextureHeight( m_textureHeight ); - size.x = m_textureWidth; - size.y = m_textureHeight; - m_terrainImage->setImageSize( &size ); - - // the overlay image - m_overlayImage = newInstance(Image); - uv.lo.x = 0.0f; - uv.lo.y = 1.0f; - uv.hi.x = 1.0f; - uv.hi.y = 0.0f; - m_overlayImage->setStatus( IMAGE_STATUS_RAW_TEXTURE ); - m_overlayImage->setRawTextureData( m_overlayTexture ); - m_overlayImage->setUV( &uv ); - m_overlayImage->setTextureWidth( m_textureWidth ); - m_overlayImage->setTextureHeight( m_textureHeight ); - size.x = m_textureWidth; - size.y = m_textureHeight; - m_overlayImage->setImageSize( &size ); - - // the shroud image - m_shroudImage = newInstance(Image); - uv.lo.x = 0.0f; - uv.lo.y = 1.0f; - uv.hi.x = 1.0f; - uv.hi.y = 0.0f; - m_shroudImage->setStatus( IMAGE_STATUS_RAW_TEXTURE ); - m_shroudImage->setRawTextureData( m_shroudTexture ); - m_shroudImage->setUV( &uv ); - m_shroudImage->setTextureWidth( m_textureWidth ); - m_shroudImage->setTextureHeight( m_textureHeight ); - size.x = m_textureWidth; - size.y = m_textureHeight; - m_shroudImage->setImageSize( &size ); - -} - -//------------------------------------------------------------------------------------------------- -/** Reset the radar to the initial empty state ready for new data */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::reset( void ) -{ - - // extending functionality, call base class - Radar::reset(); - - m_cachedHeroObjectList.clear(); - - // clear our texture data, but do not delete the resources - SurfaceClass *surface; - - surface = m_terrainTexture->Get_Surface_Level(); - if( surface ) - { - surface->Clear(); - REF_PTR_RELEASE(surface); - } - - surface = m_overlayTexture->Get_Surface_Level(); - if( surface ) - { - surface->Clear(); - REF_PTR_RELEASE(surface); - } - - // don't call Clear(); that wips to transparent. do this instead. - //gs Dude, it's called CLEARshroud. It needs to clear the shroud. - clearShroud(); - -} - -//------------------------------------------------------------------------------------------------- -/** Update */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::update( void ) -{ - - // extend base class - Radar::update(); - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -RadarObjectType W3DRadar::addObject( Object* obj ) -{ - RadarObjectType addedType = Radar::addObject(obj); - - if (addedType == RadarObjectType_Local) - { - if (obj->isHero() && !RadarObject::isTemporarilyHidden(obj)) - { - m_cachedHeroObjectList.push_back(obj); - } - } - - return addedType; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -RadarObjectType W3DRadar::removeObject( Object* obj ) -{ - RadarObjectType removedType = Radar::removeObject(obj); - - if (removedType == RadarObjectType_Local) - { - stl::find_and_erase_unordered(m_cachedHeroObjectList, obj); - } - - return removedType; -} - -//------------------------------------------------------------------------------------------------- -/** Reset the radar for the new map data being given to it */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::newMap( TerrainLogic *terrain ) -{ - - // - // extending functionality, call the base class ... this will cause a reset of the - // system which will clear out our textures but not free them - // - Radar::newMap( terrain ); - - // sanity - if( terrain == NULL ) - return; - - // build terrain texture - buildTerrainTexture( terrain ); - -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void W3DRadar::buildTerrainTexture( TerrainLogic *terrain ) -{ - SurfaceClass *surface; - RGBColor waterColor; - - // we will want to reconstruct our new view box now - m_reconstructViewBox = TRUE; - - // setup our water color - waterColor.red = TheWaterTransparency->m_radarColor.red; - waterColor.green = TheWaterTransparency->m_radarColor.green; - waterColor.blue = TheWaterTransparency->m_radarColor.blue; - - // get the terrain surface to draw in - surface = m_terrainTexture->Get_Surface_Level(); - DEBUG_ASSERTCRASH( surface, ("W3DRadar: Can't get surface for terrain texture") ); - - // build the terrain - RGBColor sampleColor; - RGBColor color; - Int i, j, samples; - Int x, y, z; - ICoord2D radarPoint; - Coord3D worldPoint; - Bridge *bridge; - for( y = 0; y < m_textureHeight; y++ ) - { - - for( x = 0; x < m_textureWidth; x++ ) - { - - // what point are we inspecting - radarPoint.x = x; - radarPoint.y = y; - radarToWorld( &radarPoint, &worldPoint ); - - // get height of the terrain at this sample point - z = terrain->getGroundHeight( worldPoint.x, worldPoint.y ); - - // check to see if this point is part of a working bridge - Bool workingBridge = FALSE; - bridge = TheTerrainLogic->findBridgeAt( &worldPoint ); - if( bridge != NULL ) - { - Object *obj = TheGameLogic->findObjectByID( bridge->peekBridgeInfo()->bridgeObjectID ); - - if( obj ) - { - BodyModuleInterface *body = obj->getBodyModule(); - - if( body->getDamageState() != BODY_RUBBLE ) - workingBridge = TRUE; - - } - - } - - // create a color based on the Z height of the map - Real waterZ; - if( workingBridge == FALSE && terrain->isUnderwater( worldPoint.x, worldPoint.y, &waterZ ) ) - { - const Int waterSamplesAway = 1; // how many "tiles" from the center tile we will sample away - // to average a color for the tile color - - sampleColor.red = sampleColor.green = sampleColor.blue = 0.0f; - samples = 0; - - for( j = y - waterSamplesAway; j <= y + waterSamplesAway; j++ ) - { - - if( j >= 0 && j < m_textureHeight ) - { - - for( i = x - waterSamplesAway; i <= x + waterSamplesAway; i++ ) - { - - if( i >= 0 && i < m_textureWidth ) - { - - // the the world point we are concerned with - radarPoint.x = i; - radarPoint.y = j; - radarToWorld( &radarPoint, &worldPoint ); - - // get Z at this sample height - Real underwaterZ = terrain->getGroundHeight( worldPoint.x, worldPoint.y ); - - // get color for this Z and add to our sample color - if( terrain->isUnderwater( worldPoint.x, worldPoint.y ) ) - { - - // this is our "color" for water - color = waterColor; - - // interpolate the water color for height in the water table - interpolateColorForHeight( &color, underwaterZ, waterZ, - waterZ, - m_mapExtent.lo.z ); - - // add color to our samples - sampleColor.red += color.red; - sampleColor.green += color.green; - sampleColor.blue += color.blue; - samples++; - - } - - } - - } - - } - - } - - // prevent divide by zeros - if( samples == 0 ) - samples = 1; - - // set the color to an average of the colors read - color.red = sampleColor.red / (Real)samples; - color.green = sampleColor.green / (Real)samples; - color.blue = sampleColor.blue / (Real)samples; - - } - else // regular terrain ... - { - const Int samplesAway = 1; // how many "tiles" from the center tile we will sample away - // to average a color for the tile color - - sampleColor.red = sampleColor.green = sampleColor.blue = 0.0f; - samples = 0; - - for( j = y - samplesAway; j <= y + samplesAway; j++ ) - { - - if( j >= 0 && j < m_textureHeight ) - { - - for( i = x - samplesAway; i <= x + samplesAway; i++ ) - { - - if( i >= 0 && i < m_textureWidth ) - { - - // the the world point we are concerned with - radarPoint.x = i; - radarPoint.y = j; - radarToWorld( &radarPoint, &worldPoint ); - - // get the color we're going to use here - if( workingBridge ) - { - AsciiString bridgeTName = bridge->getBridgeTemplateName(); - TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( bridgeTName ); - - // sanity - DEBUG_ASSERTCRASH( bridgeTemplate, ("W3DRadar::buildTerrainTexture - Can't find bridge template for '%s'", bridgeTName.str()) ); - - // use bridge color - if ( bridgeTemplate ) - color = bridgeTemplate->getRadarColor(); - else - color.setFromInt(0xffffffff); - // - // we won't use the height of the terrain at this sample point, we will - // instead use the height for the entire bridge - // - Real bridgeHeight = (bridge->peekBridgeInfo()->fromLeft.z + - bridge->peekBridgeInfo()->fromRight.z + - bridge->peekBridgeInfo()->toLeft.z + - bridge->peekBridgeInfo()->toRight.z) / 4.0f; - - // interpolate the color, but use the bridge height, not the terrain height - interpolateColorForHeight( &color, bridgeHeight, - getTerrainAverageZ(), - m_mapExtent.hi.z, m_mapExtent.lo.z ); - - } - else - { - - // get the color at this point - TheTerrainVisual->getTerrainColorAt( worldPoint.x, worldPoint.y, &color ); - - // interpolate the color for height - interpolateColorForHeight( &color, z, getTerrainAverageZ(), - m_mapExtent.hi.z, m_mapExtent.lo.z ); - - } - - // add color to our samples - sampleColor.red += color.red; - sampleColor.green += color.green; - sampleColor.blue += color.blue; - samples++; - - } - - } - - } - - } - - // prevent divide by zeros - if( samples == 0 ) - samples = 1; - - // set the color to an average of the colors read - color.red = sampleColor.red / (Real)samples; - color.green = sampleColor.green / (Real)samples; - color.blue = sampleColor.blue / (Real)samples; - - } - - // - // draw the pixel for the terrain at this point, note that because of the orientation - // of our world we draw it with positive y in the "up" direction - // - // FYI: I tried making this faster by pulling out all the code inside DrawPixel - // and locking only once ... but it made absolutely *no* performance difference, - // the sampling and interpolation algorithm for generating pretty looking terrain - // and water for the radar is just, well, expensive. - // - surface->DrawPixel( x, y, GameMakeColor( color.red * 255, - color.green * 255, - color.blue * 255, - 255 ) ); - - } - - } - - // all done with the surface - REF_PTR_RELEASE(surface); - -} - -// ------------------------------------------------------------------------------------------------ -//------------------------------------------------------------------------------------------------- -void W3DRadar::clearShroud() -{ -#if ENABLE_CONFIGURABLE_SHROUD - if (!TheGlobalData->m_shroudOn) - return; -#endif - - SurfaceClass *surface = m_shroudTexture->Get_Surface_Level(); - - // fill to clear, shroud will make black. Don't want to make something black that logic can't clear - unsigned int color = GameMakeColor( 0, 0, 0, 0 ); - for( Int y = 0; y < m_textureHeight; y++ ) - { - surface->DrawHLine(y, 0, m_textureWidth-1, color); - } - REF_PTR_RELEASE(surface); -} - -// ------------------------------------------------------------------------------------------------ -//------------------------------------------------------------------------------------------------- -void W3DRadar::setShroudLevel(Int shroudX, Int shroudY, CellShroudStatus setting) -{ -#if ENABLE_CONFIGURABLE_SHROUD - if (!TheGlobalData->m_shroudOn) - return; -#endif - - W3DShroud* shroud = TheTerrainRenderObject ? TheTerrainRenderObject->getShroud() : NULL; - if (!shroud) - return; - - SurfaceClass* surface = m_shroudTexture->Get_Surface_Level(); - DEBUG_ASSERTCRASH( surface, ("W3DRadar: Can't get surface for Shroud texture") ); - - Int mapMinX = shroudX * shroud->getCellWidth(); - Int mapMinY = shroudY * shroud->getCellHeight(); - Int mapMaxX = (shroudX+1) * shroud->getCellWidth(); - Int mapMaxY = (shroudY+1) * shroud->getCellHeight(); - - ICoord2D radarPoint; - Coord3D worldPoint; - - worldPoint.x = mapMinX; - worldPoint.y = mapMinY; - worldToRadar( &worldPoint, &radarPoint ); - Int radarMinX = radarPoint.x; - Int radarMinY = radarPoint.y; - - worldPoint.x = mapMaxX; - worldPoint.y = mapMaxY; - worldToRadar( &worldPoint, &radarPoint ); - Int radarMaxX = radarPoint.x; - Int radarMaxY = radarPoint.y; - -/* - Int radarMinX = REAL_TO_INT_FLOOR(mapMinX / getXSample()); - Int radarMinY = REAL_TO_INT_FLOOR(mapMinY / getYSample()); - Int radarMaxX = REAL_TO_INT_CEIL(mapMaxX / getXSample()); - Int radarMaxY = REAL_TO_INT_CEIL(mapMaxY / getYSample()); -*/ - - /// @todo srj -- this really needs to smooth the display! - - //Logic is saying shroud. We can add alpha levels here in client if needed. - // W3DShroud is a 0-255 alpha byte. Logic shroud is a double reference count. - Int alpha; - if( setting == CELLSHROUD_SHROUDED ) - alpha = 255; - else if( setting == CELLSHROUD_FOGGED ) - alpha = 127;///< @todo placeholder to get feedback on logic work while graphic side being decided - else - alpha = 0; - - for( Int y = radarMinY; y <= radarMaxY; y++ ) - { - for( Int x = radarMinX; x <= radarMaxX; x++ ) - { - if( legalRadarPoint( x, y ) ) - surface->DrawPixel( x, y, GameMakeColor( 0, 0, 0, alpha ) ); - } - } - REF_PTR_RELEASE(surface); -} - -//------------------------------------------------------------------------------------------------- -/** Actually draw the radar at the screen coordinates provided - * NOTE about how drawing works: The radar images are computed at samples across the - * map and are built into a "square" texture area. At the time of drawing and computing - * radar<->world coords we consider the "ratio" of width to height of the map dimensions - * so that when we draw we preserve the aspect ratio of the map and don't squish it in - * any direction that would cause the map to be distorted. Extra blank space is drawn - * around the radar images to keep the whole radar area covered when the map displayed - * is "long" or "tall" */ -//------------------------------------------------------------------------------------------------- -void W3DRadar::draw( Int pixelX, Int pixelY, Int width, Int height ) -{ - // if the local player does not have a radar then we can't draw anything - if( !rts::localPlayerHasRadar() ) - return; - - // - // given a upper left corner at pixelX|Y and a width and height to draw into, figure out - // where we should start and end the image so that the final drawn image has the - // same ratio as the map and isn't stretched or distorted - // - ICoord2D ul, lr; - findDrawPositions( pixelX, pixelY, width, height, &ul, &lr ); - - Int scaledWidth = lr.x - ul.x; - Int scaledHeight = lr.y - ul.y; - - // draw black border areas where we need map - Color fillColor = GameMakeColor( 0, 0, 0, 255 ); - Color lineColor = GameMakeColor( 50, 50, 50, 255 ); - if( m_mapExtent.width()/width >= m_mapExtent.height()/height ) - { - - // draw horizontal bars at top and bottom - TheDisplay->drawFillRect( pixelX, pixelY, width, ul.y - pixelY - 1, fillColor ); - TheDisplay->drawFillRect( pixelX, lr.y + 1, width, pixelY + height - lr.y - 1, fillColor); - TheDisplay->drawLine(pixelX, ul.y, pixelX + width, ul.y, 1, lineColor); - TheDisplay->drawLine(pixelX, lr.y + 1, pixelX + width, lr.y + 1, 1, lineColor); - - } - else - { - - // draw vertical bars to the left and right - TheDisplay->drawFillRect( pixelX, pixelY, ul.x - pixelX - 1, height, fillColor ); - TheDisplay->drawFillRect( lr.x + 1, pixelY, width - (lr.x - pixelX) - 1, height, fillColor ); - TheDisplay->drawLine(ul.x, pixelY, ul.x, pixelY + height, 1, lineColor); - TheDisplay->drawLine(lr.x + 1, pixelY, lr.x + 1, pixelY + height, 1, lineColor); - - } - - // draw the terrain texture - TheDisplay->drawImage( m_terrainImage, ul.x, ul.y, lr.x, lr.y ); - - // refresh the overlay texture once every so many frames - if( TheGameClient->getFrame() % OVERLAY_REFRESH_RATE == 0 ) - { - updateObjectTexture(m_overlayTexture); - } - - // draw the overlay image - TheDisplay->drawImage( m_overlayImage, ul.x, ul.y, lr.x, lr.y ); - - // draw the shroud image -#if ENABLE_CONFIGURABLE_SHROUD - if( TheGlobalData->m_shroudOn ) -#else - if (true) -#endif - { - TheDisplay->drawImage( m_shroudImage, ul.x, ul.y, lr.x, lr.y ); - } - - // draw any icons - drawIcons( ul.x, ul.y, scaledWidth, scaledHeight ); - - // draw any radar events - drawEvents( ul.x, ul.y, scaledWidth, scaledHeight ); - - // see if we need to reconstruct the view box - if( TheTacticalView->getZoom() != m_viewZoom ) - m_reconstructViewBox = TRUE; - if( TheTacticalView->getAngle() != m_viewAngle ) - m_reconstructViewBox = TRUE; - - if( m_reconstructViewBox == TRUE ) - reconstructViewBox(); - - // draw the view region on top of the radar reconstructing if necessary - drawViewBox( ul.x, ul.y, scaledWidth, scaledHeight ); - -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void W3DRadar::refreshTerrain( TerrainLogic *terrain ) -{ - - // extend base class - Radar::refreshTerrain( terrain ); - - // rebuild the entire terrain texture - buildTerrainTexture( terrain ); - -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void W3DRadar::refreshObjects() -{ - if constexpr (OVERLAY_REFRESH_RATE > 1) - { - if (m_overlayTexture != NULL) - { - updateObjectTexture(m_overlayTexture); - } - } -} - - - -///The following is an "archive" of an attempt to foil the mapshroud hack... saved for later, since it is too close to release to try it - - -/* - * - void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *texture ) -{ - - // sanity - if( listHead == NULL || texture == NULL ) - return; - - // get surface for texture to render into - SurfaceClass *surface = texture->Get_Surface_Level(); - - // loop through all objects and draw - ICoord2D radarPoint; - - Player *player = rts::getObservedOrLocalPlayer(); - const Int playerIndex = player->getPlayerIndex(); - - UnsignedByte minAlpha = 8; - - for( const RadarObject *rObj = listHead; rObj; rObj = rObj->friend_getNext() ) - { - UnsignedByte h = (UnsignedByte)(rObj->isTemporarilyHidden()); - if ( h ) - continue; - - UnsignedByte a = 0; - - // get object - const Object *obj = rObj->friend_getObject(); - UnsignedByte r = 1; // all decoys - - // get the color we're going to draw in - UnsignedInt c = 0xfe000000;// this is a decoy - c |= (UnsignedInt)( obj->testStatus( OBJECT_STATUS_STEALTHED ) );//so is this - - // check for shrouded status - UnsignedByte k = (UnsignedByte)(obj->getShroudedStatus(playerIndex) > OBJECTSHROUD_PARTIAL_CLEAR); - if ( k || a) - continue; //object is fogged or shrouded, don't render it. - - // - // objects with a local only unit priority will only appear on the radar if they - // are controlled by the local player, or if the local player is an observer (cause - // they are godlike and can see everything) - // - if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY && - obj->getControllingPlayer() != player && - player->isPlayerActive() ) - continue; - - UnsignedByte g = c|a; - UnsignedByte b = h|a; - // get object position - const Coord3D *pos = obj->getPosition(); - - // compute object position as a radar blip - radarPoint.x = pos->x / (m_mapExtent.width() / RADAR_CELL_WIDTH); - radarPoint.y = pos->y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); - - - const UnsignedInt framesForTransition = LOGICFRAMES_PER_SECOND; - - - - // adjust the alpha for stealth units so they "fade/blink" on the radar for the controller - // if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY ) - // ML-- What the heck is this? local-only and neutral-observier-viewed units are stealthy?? Since when? - // Now it twinkles for any stealthed object, whether locally controlled or neutral-observier-viewed - c = rObj->getColor(); - - if( g & r ) - { - Real alphaScale = INT_TO_REAL(TheGameLogic->getFrame() % framesForTransition) / (framesForTransition * 0.5f); - minAlpha <<= 2; // decoy - - if ( ( obj->isLocallyControlled() == (Bool)a ) // another decoy, comparing the return of this non-inline with a local - && !obj->testStatus( OBJECT_STATUS_DISGUISED ) - && !obj->testStatus( OBJECT_STATUS_DETECTED ) - && ++a != 0 // The trick is that this increment does not occur unless all three above conditions are true - && minAlpha == 32 // tricksy hobbit decoy - && c != 0 ) // ditto - { - g = (UnsignedByte)(rObj->getColor()); - continue; - } - - a |= k | b; - GameGetColorComponentsWithCheatSpy( c, &r, &g, &b, &a );//this function does not touch the low order bit in 'a' - - - if( alphaScale > 0.0f ) - a = REAL_TO_UNSIGNEDBYTE( ((alphaScale - 1.0f) * (255.0f - minAlpha)) + minAlpha ); - else - a = REAL_TO_UNSIGNEDBYTE( (alphaScale * (255.0f - minAlpha)) + minAlpha ); - c = GameMakeColor( r, g, b, a ); - - } - - - - - // draw the blip, but make sure the points are legal - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.x++; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.y++; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - radarPoint.x--; - if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->DrawPixel( radarPoint.x, radarPoint.y, c ); - - - - - } - REF_PTR_RELEASE(surface); - -} - - - * - */ diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index b45d8684f7..07e074e4c3 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -77,7 +77,7 @@ set(GAMEENGINE_SRC Include/Common/Money.h Include/Common/MultiplayerSettings.h Include/Common/NameKeyGenerator.h - Include/Common/ObjectStatusTypes.h +# Include/Common/ObjectStatusTypes.h Include/Common/OSDisplay.h Include/Common/Overridable.h Include/Common/Override.h @@ -90,7 +90,7 @@ set(GAMEENGINE_SRC Include/Common/ProductionPrerequisite.h Include/Common/QuickmatchPreferences.h Include/Common/QuotedPrintable.h - Include/Common/Radar.h +# Include/Common/Radar.h # Include/Common/RAMFile.h # Include/Common/RandomValue.h Include/Common/Recorder.h @@ -652,9 +652,9 @@ set(GAMEENGINE_SRC # Source/Common/System/LocalFile.cpp # Source/Common/System/LocalFileSystem.cpp #Source/Common/System/MemoryInit.cpp - Source/Common/System/ObjectStatusTypes.cpp +# Source/Common/System/ObjectStatusTypes.cpp Source/Common/System/QuotedPrintable.cpp - Source/Common/System/Radar.cpp +# Source/Common/System/Radar.cpp # Source/Common/System/RAMFile.cpp Source/Common/System/registry.cpp Source/Common/System/SaveGame/GameState.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Radar.h b/GeneralsMD/Code/GameEngine/Include/Common/Radar.h deleted file mode 100644 index bfa7a008e2..0000000000 --- a/GeneralsMD/Code/GameEngine/Include/Common/Radar.h +++ /dev/null @@ -1,312 +0,0 @@ -/* -** 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: Radar.h ////////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, January 2002 -// Desc: Logical radar implementation -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Lib/BaseType.h" -#include "Common/SubsystemInterface.h" -#include "Common/GameMemory.h" -#include "GameClient/Display.h" // for ShroudLevel -#include "GameClient/Color.h" - -// FORWARD REFERENCES ///////////////////////////////////////////////////////////////////////////// -class GameWindow; -class Object; -class Player; -class TerrainLogic; - -// GLOBAL ///////////////////////////////////////////////////////////////////////////////////////// -// -// the following is used for the resolution of the radar "cells" ... this is how accurate -// the radar is and also reflects directly the size of the image we build ... which with -// WW3D must be a square power of two as well -// -enum -{ - RADAR_CELL_WIDTH = 128, // radar created at this horz resolution - RADAR_CELL_HEIGHT = 128 // radar created at this vert resolution -}; - -//------------------------------------------------------------------------------------------------- -/** These event types determine the colors radar events happen in to make it easier for us - * to play events with a consistent color scheme */ -//------------------------------------------------------------------------------------------------- -enum RadarEventType CPP_11(: Int) -{ - RADAR_EVENT_INVALID = 0, - RADAR_EVENT_CONSTRUCTION, - RADAR_EVENT_UPGRADE, - RADAR_EVENT_UNDER_ATTACK, - RADAR_EVENT_INFORMATION, - RADAR_EVENT_BEACON_PULSE, - RADAR_EVENT_INFILTRATION, //for defection, hijacking, hacking, carbombing, and other sneaks - RADAR_EVENT_BATTLE_PLAN, - RADAR_EVENT_STEALTH_DISCOVERED, // we discovered a stealth unit - RADAR_EVENT_STEALTH_NEUTRALIZED, // our stealth unit has been revealed - RADAR_EVENT_FAKE, //Internally creates a radar event, but doesn't notify the player (unit lost - //for example, so we can use the spacebar to jump to the event). - - RADAR_EVENT_NUM_EVENTS - -}; - -enum RadarObjectType CPP_11(: Int) -{ - RadarObjectType_None = 0, - RadarObjectType_Regular, - RadarObjectType_Local, -}; - -// PROTOTYPES ///////////////////////////////////////////////////////////////////////////////////// - -//------------------------------------------------------------------------------------------------- -/** Radar objects are objects that are on the radar, go figure :) */ -//------------------------------------------------------------------------------------------------- -class RadarObject : public MemoryPoolObject, - public Snapshot -{ - - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( RadarObject, "RadarObject" ) - -public: - - RadarObject( void ); - // destructor prototype defined by memory pool glue - - // color management - void setColor( Color c ) { m_color = c; } - inline Color getColor( void ) const { return m_color; } - - inline void friend_setObject( Object *obj ) { m_object = obj; } - inline Object *friend_getObject( void ) { return m_object; } - inline const Object *friend_getObject( void ) const { return m_object; } - - inline void friend_setNext( RadarObject *next ) { m_next = next; } - inline RadarObject *friend_getNext( void ) { return m_next; } - inline const RadarObject *friend_getNext( void ) const { return m_next; } - - Bool isTemporarilyHidden() const; - static Bool isTemporarilyHidden(const Object* obj); - -protected: - - // snapshot methods - virtual void crc( Xfer *xfer ); - virtual void xfer( Xfer *xfer ); - virtual void loadPostProcess( void ); - - Object *m_object; ///< the object - RadarObject *m_next; ///< next radar object - Color m_color; ///< color to draw for this object on the radar - -}; - -//------------------------------------------------------------------------------------------------- -/** Radar priorities. Keep this in sync with the priority names list below */ -//------------------------------------------------------------------------------------------------- -enum RadarPriorityType CPP_11(: Int) -{ - RADAR_PRIORITY_INVALID, // a priority that has not been set (in general it won't show up on the radar) - RADAR_PRIORITY_NOT_ON_RADAR, // object specifically forbidden from being on the radar - RADAR_PRIORITY_STRUCTURE, // structure level drawing priority - RADAR_PRIORITY_UNIT, // unit level drawing priority - RADAR_PRIORITY_LOCAL_UNIT_ONLY, // unit priority, but only on the radar if controlled by the local player - - RADAR_PRIORITY_NUM_PRIORITIES -}; -#ifdef DEFINE_RADAR_PRIORITY_NAMES -static const char *const RadarPriorityNames[] = -{ - "INVALID", // a priority that has not been set (in general it won't show up on the radar) - "NOT_ON_RADAR", // object specifically forbidden from being on the radar - "STRUCTURE", // structure level drawing priority - "UNIT", // unit level drawing priority - "LOCAL_UNIT_ONLY", // unit priority, but only on the radar if controlled by the local player - - NULL -}; -static_assert(ARRAY_SIZE(RadarPriorityNames) == RADAR_PRIORITY_NUM_PRIORITIES + 1, "Incorrect array size"); -#endif // DEFINE_RADAR_PRIOTITY_NAMES - -//------------------------------------------------------------------------------------------------- -/** Interface for the radar */ -//------------------------------------------------------------------------------------------------- -class Radar : public Snapshot, - public SubsystemInterface -{ - -public: - - Radar( void ); - virtual ~Radar( void ); - - virtual void init( void ) { } ///< subsystem initialization - virtual void reset( void ); ///< subsystem reset - virtual void update( void ); ///< subsystem per frame update - - // is the game window parameter the radar window - Bool isRadarWindow( GameWindow *window ) { return (m_radarWindow == window) && (m_radarWindow != NULL); } - - Bool radarToWorld( const ICoord2D *radar, Coord3D *world ); ///< radar point to world point on terrain - Bool radarToWorld2D( const ICoord2D *radar, Coord3D *world ); ///< radar point to world point (x,y only!) - Bool worldToRadar( const Coord3D *world, ICoord2D *radar ); ///< translate world point to radar (x,y) - Bool localPixelToRadar( const ICoord2D *pixel, ICoord2D *radar ); ///< translate pixel (with UL of radar being (0,0)) to logical radar coordinates - Bool screenPixelToWorld( const ICoord2D *pixel, Coord3D *world ); ///< translate pixel (with UL of the screen being (0,0)) to world position in the world - Object *objectUnderRadarPixel( const ICoord2D *pixel ); ///< return the object (if any) represented by the pixel coordinates passed in - void findDrawPositions( Int startX, Int startY, Int width, Int height, - ICoord2D *ul, ICoord2D *lr ); ///< make translation for screen area of radar square to scaled aspect ratio preserving points inside the radar area - - // priority inquiry - static Bool isPriorityVisible( RadarPriorityType priority ); ///< is the priority passed in a "visible" one on the radar - - // radar events - void createEvent( const Coord3D *world, RadarEventType type, Real secondsToLive = 4.0f ); ///< create radar event at location in world - void createPlayerEvent( Player *player, const Coord3D *world, RadarEventType type, Real secondsToLive = 4.0f ); ///< create radar event using player colors - - Bool getLastEventLoc( Coord3D *eventPos ); ///< get last event loc (if any) - void tryUnderAttackEvent( const Object *obj ); ///< try to make an "under attack" event if it's the proper time - void tryInfiltrationEvent( const Object *obj ); ///< try to make an "infiltration" event if it's the proper time - Bool tryEvent( RadarEventType event, const Coord3D *pos ); ///< try to make a "stealth" event - - // adding and removing objects from the radar - virtual RadarObjectType addObject( Object *obj ); ///< add object to radar - virtual RadarObjectType removeObject( Object *obj ); ///< remove object from radar - - // radar options - void hide( Int playerIndex, Bool hide ) { m_radarHidden[playerIndex] = hide; } ///< hide/show the radar - Bool isRadarHidden( Int playerIndex ) { return m_radarHidden[playerIndex]; } ///< is radar hidden - // other radar option methods here like the ability to show a certain - // team, show buildings, show units at all, etc - - // forcing the radar on/off regardless of player situation - void forceOn( Int playerIndex, Bool force ) { m_radarForceOn[playerIndex] = force; } ///< force the radar to be on - Bool isRadarForced( Int playerIndex ) { return m_radarForceOn[playerIndex]; } ///< is radar forced on? - - /// refresh the water values for the radar - virtual void refreshTerrain( TerrainLogic *terrain ); - - /// refresh the radar when the state of world objects changes drastically - virtual void refreshObjects() {}; - - /// queue a refresh of the terrain at the next available time - virtual void queueTerrainRefresh( void ); - - virtual void newMap( TerrainLogic *terrain ); ///< reset radar for new map - - virtual void draw( Int pixelX, Int pixelY, Int width, Int height ) = 0; ///< draw the radar - - /// empty the entire shroud - virtual void clearShroud() = 0; - - /// set the shroud level at shroud cell x,y - virtual void setShroudLevel( Int x, Int y, CellShroudStatus setting ) = 0; - -protected: - - // snapshot methods - virtual void crc( Xfer *xfer ); - virtual void xfer( Xfer *xfer ); - virtual void loadPostProcess( void ); - - /// internal method for creating a radar event with specific colors - void internalCreateEvent( const Coord3D *world, RadarEventType type, Real secondsToLive, - const RGBAColorInt *color1, const RGBAColorInt *color2 ); - - void deleteListResources( void ); ///< delete list radar resources used - Bool deleteFromList( Object *obj, RadarObject **list ); ///< try to remove object from specific list - - inline Real getTerrainAverageZ() const { return m_terrainAverageZ; } - inline Real getWaterAverageZ() const { return m_waterAverageZ; } - inline const RadarObject* getObjectList() const { return m_objectList; } - inline const RadarObject* getLocalObjectList() const { return m_localObjectList; } - - void clearAllEvents( void ); ///< remove all radar events in progress - - // search the object list for an object that maps to the given logical radar coordinates - Object *searchListForRadarLocationMatch( RadarObject *listHead, ICoord2D *radarMatch ); - - Bool m_radarHidden[MAX_PLAYER_COUNT]; ///< true when radar is not visible - Bool m_radarForceOn[MAX_PLAYER_COUNT]; ///< true when radar is forced to be on - RadarObject *m_objectList; ///< list of objects in the radar - RadarObject *m_localObjectList; /** list of objects for the local player, sorted - * in exactly the same priority as the regular - * object list for all other objects */ -// typedef std::list HeroList; -// HeroList m_heroList; //< list of pointers to objects with radar icon representations - - Real m_terrainAverageZ; ///< average Z for terrain samples - Real m_waterAverageZ; ///< average Z for water samples - - // - // when dealing with world sampling we will sample at these intervals so that - // the whole map can be accounted for within our RADAR_CELL_WIDTH and - // RADAR_CELL_HEIGHT resolutions - // - Real m_xSample; - Real m_ySample; - - enum { MAX_RADAR_EVENTS = 64 }; - struct RadarEvent - { - RadarEventType type; ///< type of this radar event - Bool active; ///< TRUE when event is "active", otherwise it's just historical information in the event array to look through - UnsignedInt createFrame; ///< frame event was created on - UnsignedInt dieFrame; ///< frame the event will go away on - UnsignedInt fadeFrame; ///< start fading out on this frame - RGBAColorInt color1; ///< color 1 for drawing - RGBAColorInt color2; ///< color 2 for drawing - Coord3D worldLoc; ///< location of event in the world - ICoord2D radarLoc; ///< 2D radar location of the event - Bool soundPlayed; ///< TRUE when we have played the radar sound for this - }; - RadarEvent m_event[ MAX_RADAR_EVENTS ];///< our radar events - Int m_nextFreeRadarEvent; ///< index into m_event for where to store the next event - Int m_lastRadarEvent; ///< index of the most recent radar event - - GameWindow *m_radarWindow; ///< window we display the radar in - - Region3D m_mapExtent; ///< extents of the current map - - UnsignedInt m_queueTerrainRefreshFrame; ///< frame we requested the last terrain refresh on - -}; - -// EXTERNALS ////////////////////////////////////////////////////////////////////////////////////// -extern Radar *TheRadar; ///< the radar singleton extern - -// TheSuperHackers @feature helmutbuhler 10/04/2025 -// Radar that does nothing. Used for Headless Mode. -class RadarDummy : public Radar -{ -public: - virtual void draw(Int pixelX, Int pixelY, Int width, Int height) { } - virtual void clearShroud() { } - virtual void setShroudLevel(Int x, Int y, CellShroudStatus setting) { } -}; diff --git a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt index 82c1bb4259..472da80af8 100644 --- a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt @@ -4,7 +4,7 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/Common/W3DConvert.h Include/W3DDevice/Common/W3DFunctionLexicon.h Include/W3DDevice/Common/W3DModuleFactory.h - Include/W3DDevice/Common/W3DRadar.h +# Include/W3DDevice/Common/W3DRadar.h Include/W3DDevice/Common/W3DThingFactory.h Include/W3DDevice/GameClient/BaseHeightMap.h Include/W3DDevice/GameClient/camerashakesystem.h @@ -93,7 +93,7 @@ set(GAMEENGINEDEVICE_SRC # Source/MilesAudioDevice/MilesAudioManager.cpp # Source/VideoDevice/Bink/BinkVideoPlayer.cpp Source/W3DDevice/Common/System/W3DFunctionLexicon.cpp - Source/W3DDevice/Common/System/W3DRadar.cpp +# Source/W3DDevice/Common/System/W3DRadar.cpp Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp Source/W3DDevice/Common/Thing/W3DThingFactory.cpp Source/W3DDevice/Common/W3DConvert.cpp diff --git a/scripts/cpp/unify_move_files.py b/scripts/cpp/unify_move_files.py index d43aa33496..55ade9d389 100644 --- a/scripts/cpp/unify_move_files.py +++ b/scripts/cpp/unify_move_files.py @@ -166,6 +166,13 @@ def main(): #unify_move_file(Game.GENERALS, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl") #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/ObjectStatusTypes.h", Game.CORE, "GameEngine/Include/Common/ObjectStatusTypes.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/Radar.h", Game.CORE, "GameEngine/Include/Common/Radar.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/ObjectStatusTypes.cpp", Game.CORE, "GameEngine/Source/Common/System/ObjectStatusTypes.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/Radar.cpp", Game.CORE, "GameEngine/Source/Common/System/Radar.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp") + return