diff --git a/Core/GameEngine/Include/Common/Radar.h b/Core/GameEngine/Include/Common/Radar.h index 83f779247c..c3ccbc29e8 100644 --- a/Core/GameEngine/Include/Common/Radar.h +++ b/Core/GameEngine/Include/Common/Radar.h @@ -77,13 +77,6 @@ enum RadarEventType CPP_11(: Int) }; -enum RadarObjectType CPP_11(: Int) -{ - RadarObjectType_None = 0, - RadarObjectType_Regular, - RadarObjectType_Local, -}; - // PROTOTYPES ///////////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- @@ -196,8 +189,8 @@ class Radar : public Snapshot, 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 + virtual Bool addObject( Object *obj ); ///< add object to radar + virtual Bool removeObject( Object *obj ); ///< remove object from radar // radar options void hide( Int playerIndex, Bool hide ) { m_radarHidden[playerIndex] = hide; } ///< hide/show the radar @@ -239,26 +232,35 @@ class Radar : public Snapshot, void internalCreateEvent( const Coord3D *world, RadarEventType type, Real secondsToLive, const RGBAColorInt *color1, const RGBAColorInt *color2 ); + void deleteList( RadarObject **list ); 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 ); + void linkRadarObject( RadarObject *newObj, RadarObject **list ); + void assignObjectColorToRadarObject( RadarObject *radarObj, Object *obj ); + 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 */ + // TheSuperHackers @bugfix xezon 22/11/2025 Now stores local heroes in a separate list, + // because they are treated with special icons but should otherwise work like all other + // radar objects. In retail version, the cached hero object data was able to dangle + // for a few frames and cause undefined behavior. + RadarObject *m_localHeroObjectList; ///< list of hero objects for the local player + Real m_terrainAverageZ; ///< average Z for terrain samples Real m_waterAverageZ; ///< average Z for water samples diff --git a/Core/GameEngine/Source/Common/System/Radar.cpp b/Core/GameEngine/Source/Common/System/Radar.cpp index 8883f247e0..86ac2046b8 100644 --- a/Core/GameEngine/Source/Common/System/Radar.cpp +++ b/Core/GameEngine/Source/Common/System/Radar.cpp @@ -62,56 +62,34 @@ Radar *TheRadar = NULL; ///< the radar global singleton #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 ) +void Radar::deleteList( RadarObject **list ) { - RadarObject *nextObject; - - // delete entries from the local object list - while( m_localObjectList ) + while( *list ) { - - // 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; - + RadarObject *nextObject = (*list)->friend_getNext(); + (*list)->friend_getObject()->friend_setRadarData( NULL ); + deleteInstance(*list); + *list = 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; - - } +//------------------------------------------------------------------------------------------------- +/** Delete list resources used by the radar and return them to the memory pools */ +//------------------------------------------------------------------------------------------------- +void Radar::deleteListResources( void ) +{ + deleteList(&m_objectList); + deleteList(&m_localObjectList); + deleteList(&m_localHeroObjectList); - Object *obj; - for( obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() ) +#ifdef DEBUG_CRASHING + for( Object *obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() ) { - - DEBUG_ASSERTCRASH( obj->friend_getRadarData() == NULL, ("oops") ); - + DEBUG_ASSERTCRASH( obj->friend_getRadarData() == NULL, + ("Radar::deleteListResources: Unexpectedly an object still has radar data assigned") ); } - +#endif } // PUBLIC METHODS ///////////////////////////////////////////////////////////////////////////////// @@ -214,6 +192,7 @@ Radar::Radar( void ) m_radarWindow = NULL; m_objectList = NULL; m_localObjectList = NULL; + m_localHeroObjectList = 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; @@ -402,13 +381,13 @@ void Radar::newMap( TerrainLogic *terrain ) /** 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 ) +Bool Radar::addObject( Object *obj ) { // get the radar priority for this object RadarPriorityType newPriority = obj->getRadarPriority(); if( isPriorityVisible( newPriority ) == FALSE ) - return RadarObjectType_None; + return FALSE; // if this object is on the radar, remove it in favor of the new add RadarObject **list; @@ -426,140 +405,31 @@ RadarObjectType Radar::addObject( Object *obj ) 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() ); - } + assignObjectColorToRadarObject( newObj, obj ); // 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; + if ( obj->isHero() ) + list = &m_localHeroObjectList; + else + list = &m_localObjectList; } 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 ) - { + linkRadarObject(newObj, list); - // 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; + return TRUE; } //------------------------------------------------------------------------------------------------- @@ -606,24 +476,24 @@ Bool Radar::deleteFromList( Object *obj, RadarObject **list ) //------------------------------------------------------------------------------------------------- /** Remove an object from the radar, the object may reside in any list */ //------------------------------------------------------------------------------------------------- -RadarObjectType Radar::removeObject( Object *obj ) +Bool Radar::removeObject( Object *obj ) { // sanity if( obj->friend_getRadarData() == NULL ) - return RadarObjectType_None; + return FALSE; + if( deleteFromList( obj, &m_localHeroObjectList ) == TRUE ) + return TRUE; if( deleteFromList( obj, &m_localObjectList ) == TRUE ) - return RadarObjectType_Local; + return TRUE; else if( deleteFromList( obj, &m_objectList ) == TRUE ) - return RadarObjectType_Regular; + return TRUE; else { - - // sanity DEBUG_ASSERTCRASH( 0, ("Radar: Tried to remove object '%s' which was not found", obj->getTemplate()->getName().str()) ); - return RadarObjectType_None; + return FALSE; } } @@ -848,10 +718,14 @@ Object *Radar::objectUnderRadarPixel( const ICoord2D *pixel ) // to the radar location // - // search the local object list - obj = searchListForRadarLocationMatch( m_localObjectList, &radar ); + // search the local hero object list + obj = searchListForRadarLocationMatch( m_localHeroObjectList, &radar ); - // search all other objects if not found + // search the local object list if not found + if( obj == NULL ) + obj = searchListForRadarLocationMatch( m_localObjectList, &radar ); + + // search all other objects if still not found if( obj == NULL ) obj = searchListForRadarLocationMatch( m_objectList, &radar ); @@ -1491,6 +1365,7 @@ static void xferRadarObjectList( Xfer *xfer, RadarObject **head ) * Version Info: * 1: Initial version * 2: TheSuperHackers @tweak Serialize m_radarHidden, m_radarForceOn for each player + * 3: TheSuperHackers @tweak Serialize m_localHeroObjectList */ // ------------------------------------------------------------------------------------------------ void Radar::xfer( Xfer *xfer ) @@ -1500,7 +1375,7 @@ void Radar::xfer( Xfer *xfer ) #if RETAIL_COMPATIBLE_XFER_SAVE XferVersion currentVersion = 1; #else - XferVersion currentVersion = 2; + XferVersion currentVersion = 3; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -1530,12 +1405,66 @@ void Radar::xfer( Xfer *xfer ) xfer->xferUser(&m_radarForceOn, sizeof(m_radarForceOn)); } + if (version <= 2) + { + if (xfer->getXferMode() == XFER_SAVE) + { + // TheSuperHackers @info For legacy xfer compatibility. + // Transfer all local hero objects to local object list. + RadarObject **fromList = &m_localHeroObjectList; + RadarObject **toList = &m_localObjectList; + while (*fromList != NULL) + { + RadarObject* nextObject = (*fromList)->friend_getNext(); + (*fromList)->friend_setNext(NULL); + linkRadarObject(*fromList, toList); + *fromList = nextObject; + } + } + } + else + { + xferRadarObjectList( xfer, &m_localHeroObjectList ); + } + // save our local object list xferRadarObjectList( xfer, &m_localObjectList ); // save the regular object list xferRadarObjectList( xfer, &m_objectList ); + if (version <= 2) + { + // TheSuperHackers @info For legacy xfer compatibility. + // Transfer hero local object(s) back to local hero object list. + // This needs to be done on both load and save. + RadarObject **fromList = &m_localObjectList; + RadarObject **toList = &m_localHeroObjectList; + RadarObject *currObject; + RadarObject *prevObject; + RadarObject *nextObject; + prevObject = NULL; + for (currObject = *fromList; currObject != NULL; currObject = nextObject) + { + nextObject = currObject->friend_getNext(); + if (currObject->friend_getObject()->isHero()) + { + if (prevObject != NULL) + { + prevObject->friend_setNext(nextObject); + } + else + { + *fromList = nextObject; + } + currObject->friend_setNext(NULL); + linkRadarObject(currObject, toList); + continue; + } + prevObject = currObject; + } + } + // save the radar event count and data UnsignedShort eventCountVerify = MAX_RADAR_EVENTS; UnsignedShort eventCount = eventCountVerify; @@ -1606,3 +1535,121 @@ Bool Radar::isPriorityVisible( RadarPriorityType priority ) } } + +// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ +void Radar::linkRadarObject( RadarObject *newObj, RadarObject **list ) +{ + if( *list == NULL ) + { + // trivial case, an empty list + *list = newObj; + return; + } + + RadarPriorityType newPriority = newObj->friend_getObject()->getRadarPriority(); + RadarPriorityType prevPriority; + RadarPriorityType currPriority; + RadarObject *currObject; + RadarObject *prevObject; + RadarObject *nextObject; + + DEBUG_ASSERTCRASH(newObj->friend_getNext() == NULL, ("newObj->friend_getNext is not NULL")); + + 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; + } + 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; + } +} + +// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ +void Radar::assignObjectColorToRadarObject( RadarObject *radarObj, Object *obj ) +{ + 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) ) + { + radarObj->setColor( obj->getIndicatorColor() ); + } + else + { + radarObj->setColor( player->getPlayerColor() ); + } +} diff --git a/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h b/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h index 193d755f68..528ddb52a9 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h +++ b/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h @@ -58,9 +58,6 @@ class W3DRadar : public Radar 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 @@ -84,7 +81,8 @@ class W3DRadar : public Radar 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 + static Bool canRenderObject( const RadarObject *rObj, const Player *localPlayer ); + void renderObjectList( const RadarObject *listHead, TextureClass *texture ); void interpolateColorForHeight( RGBColor *color, Real height, Real hiZ, @@ -121,6 +119,4 @@ class W3DRadar : public Radar 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/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index be576da841..21aea05038 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -602,12 +602,13 @@ void W3DRadar::drawEvents( Int pixelX, Int pixelY, Int width, Int height ) //------------------------------------------------------------------------------------------------- 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()) + Player *player = rts::getObservedOrLocalPlayer(); + for (RadarObject *heroObj = m_localHeroObjectList; heroObj; heroObj = heroObj->friend_getNext()) { - drawHeroIcon( pixelX, pixelY, width, height, (*iter)->getPosition() ); - ++iter; + if (canRenderObject(heroObj, player)) + { + drawHeroIcon(pixelX, pixelY, width, height, heroObj->friend_getObject()->getPosition()); + } } } @@ -621,14 +622,63 @@ void W3DRadar::updateObjectTexture(TextureClass *texture) REF_PTR_RELEASE(surface); // rebuild the object overlay - renderObjectList( getObjectList(), texture ); - renderObjectList( getLocalObjectList(), texture, TRUE ); + renderObjectList( m_objectList, texture ); + renderObjectList( m_localObjectList, texture ); + renderObjectList( m_localHeroObjectList, texture ); +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +Bool W3DRadar::canRenderObject( const RadarObject *rObj, const Player *localPlayer ) +{ + if (rObj->isTemporarilyHidden()) + { + return false; + } + + const Int playerIndex = localPlayer->getPlayerIndex(); + const Object *obj = rObj->friend_getObject(); + + // + // check for shrouded status + // if object is fogged or shrouded, don't render it + // + if (obj->getShroudedStatus(playerIndex) > OBJECTSHROUD_PARTIAL_CLEAR) + { + return false; + } + + // + // 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() != localPlayer && + localPlayer->isPlayerActive() ) + { + return false; + } + + // + // 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 (TheControlBar->getCurrentlyViewedPlayerRelationship(obj->getTeam()) == ENEMIES && + obj->testStatus( OBJECT_STATUS_STEALTHED ) && + !obj->testStatus( OBJECT_STATUS_DETECTED ) && + !obj->testStatus( OBJECT_STATUS_DISGUISED ) ) + { + return false; + } + + return true; } //------------------------------------------------------------------------------------------------- /** Render an object list into the texture passed in */ //------------------------------------------------------------------------------------------------- -void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *texture, Bool calcHero ) +void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *texture ) { // sanity @@ -642,59 +692,29 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text 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()) + if (!canRenderObject(rObj, player)) 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 Object *obj = rObj->friend_getObject(); 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 + // 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 ) ) { - if ( TheControlBar->getCurrentlyViewedPlayerRelationship(obj->getTeam()) == ENEMIES ) - if( !obj->testStatus( OBJECT_STATUS_DETECTED ) && !obj->testStatus( OBJECT_STATUS_DISGUISED ) ) - continue; - UnsignedByte r, g, b, a; GameGetColorComponents( c, &r, &g, &b, &a ); @@ -710,12 +730,6 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text } - // 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 ); @@ -964,8 +978,6 @@ 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; @@ -1000,37 +1012,6 @@ void W3DRadar::update( void ) } -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -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 */ //------------------------------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index 4803ccc2fd..217474b898 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -1045,12 +1045,12 @@ void Player::becomingLocalPlayer(Bool yes) { // Added support for updating the perceptions of garrisoned buildings containing enemy stealth units. // When changing teams, it is necessary to update this information. + Bool requireRadarRefresh = false; ContainModuleInterface *contain = object->getContain(); if( contain ) { contain->recalcApparentControllingPlayer(); - TheRadar->removeObject( object ); - TheRadar->addObject( object ); + requireRadarRefresh = true; } if( object->isKindOf( KINDOF_DISGUISER ) ) @@ -1080,11 +1080,16 @@ void Player::becomingLocalPlayer(Bool yes) else draw->setIndicatorColor( object->getIndicatorColor() ); } - TheRadar->removeObject( object ); - TheRadar->addObject( object ); + requireRadarRefresh = true; } } } + + if (requireRadarRefresh) + { + TheRadar->removeObject( object ); + TheRadar->addObject( object ); + } } deleteInstance(iter); } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 758c63d504..fbda3ce5b8 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -5442,10 +5442,8 @@ void Object::goInvulnerable( UnsignedInt time ) // ------------------------------------------------------------------------------------------------ RadarPriorityType Object::getRadarPriority( void ) const { - RadarPriorityType priority = RADAR_PRIORITY_INVALID; - // first, get the priority at the thing template level - priority = getTemplate()->getDefaultRadarPriority(); + RadarPriorityType priority = getTemplate()->getDefaultRadarPriority(); // // there are some objects that we want to show up on the radar when they have diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index 79f8392c89..48296af878 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -1086,12 +1086,12 @@ void Player::becomingLocalPlayer(Bool yes) { // Added support for updating the perceptions of garrisoned buildings containing enemy stealth units. // When changing teams, it is necessary to update this information. + Bool requireRadarRefresh = false; ContainModuleInterface *contain = object->getContain(); if( contain ) { contain->recalcApparentControllingPlayer(); - TheRadar->removeObject( object ); - TheRadar->addObject( object ); + requireRadarRefresh = true; } if( object->isKindOf( KINDOF_DISGUISER ) ) @@ -1123,11 +1123,16 @@ void Player::becomingLocalPlayer(Bool yes) else draw->setIndicatorColor( object->getIndicatorColor() ); } - TheRadar->removeObject( object ); - TheRadar->addObject( object ); + requireRadarRefresh = true; } } } + + if (requireRadarRefresh) + { + TheRadar->removeObject( object ); + TheRadar->addObject( object ); + } } deleteInstance(iter); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 3083c4738e..45a31a7f43 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -6282,10 +6282,8 @@ void Object::goInvulnerable( UnsignedInt time ) // ------------------------------------------------------------------------------------------------ RadarPriorityType Object::getRadarPriority( void ) const { - RadarPriorityType priority = RADAR_PRIORITY_INVALID; - // first, get the priority at the thing template level - priority = getTemplate()->getDefaultRadarPriority(); + RadarPriorityType priority = getTemplate()->getDefaultRadarPriority(); // // there are some objects that we want to show up on the radar when they have