| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (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 int the GameEngine
- #include "Common/GameAudio.h"
- #include "Common/GameState.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"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- // 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
- m_localObjectList->deleteInstance();
- // set head of the list to the next object
- m_localObjectList = nextObject;
- } // end while
- // 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
- m_objectList->deleteInstance();
- // set head of the list to the next object
- m_objectList = nextObject;
- } // end while
- Object *obj;
- for( obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() )
- {
- DEBUG_ASSERTCRASH( obj->friend_getRadarData() == NULL, ("oops") );
- }
- } // end deleteListResources
- // 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
- {
- Drawable* draw = m_object->getDrawable();
- if (draw->getStealthLook() == STEALTHLOOK_INVISIBLE || draw->isDrawableEffectivelyHidden())
- return true;
- return false;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void RadarObject::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** 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\n" ));
- throw SC_INVALID_DATA;
- } // end if
- // tell the object we now have some radar data
- m_object->friend_setRadarData( this );
- } // end if
- // color
- xfer->xferColor( &m_color );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void RadarObject::loadPostProcess( void )
- {
- } // end loadPostProcess
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- Radar::Radar( void )
- {
- m_radarWindow = NULL;
- m_objectList = NULL;
- m_localObjectList = NULL;
- m_radarHidden = false;
- 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();
- } // end Radar
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- Radar::~Radar( void )
- {
- // delete list resources
- deleteListResources();
- } // end ~Radar
- //-------------------------------------------------------------------------------------------------
- /** 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;
- } // end for i
- } // end clearAllEvents
- //-------------------------------------------------------------------------------------------------
- /** Reset radar data */
- //-------------------------------------------------------------------------------------------------
- void Radar::reset( void )
- {
- // delete list resources
- deleteListResources();
- // clear all events
- clearAllEvents();
- // stop forcing the radar on
- m_radarForceOn = false;
- } // end reset
- //-------------------------------------------------------------------------------------------------
- /** 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;
-
- } // end for i
- // 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 );
- } // end if
- } // end update
- //-------------------------------------------------------------------------------------------------
- /** 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\n") );
- // 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;
- Int terrainSamples = 0, waterSamples = 0;
- m_terrainAverageZ = 0.0f;
- m_waterAverageZ = 0.0f;
- Coord3D worldPoint;
-
- // 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 )
- {
- // don't use this, we don't really need the
- // 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 ) )
- {
- m_waterAverageZ += z;
- waterSamples++;
- }
- else
- {
- m_terrainAverageZ += z;
- terrainSamples++;
- }
- } // end for x
- }
- // 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 );
- } // end newMap
- //-------------------------------------------------------------------------------------------------
- /** Add an object to the radar list. The object will be sorted in the list to be grouped
- * using it's radar priority */
- //-------------------------------------------------------------------------------------------------
- void Radar::addObject( Object *obj )
- {
- // get the radar priority for this object
- RadarPriorityType newPriority = obj->getRadarPriority();
- if( isPriorityVisible( newPriority ) == FALSE )
- return;
- // 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'\n",
- 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();
- 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 *clientPlayer = ThePlayerList->getLocalPlayer();
- 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( ThePlayerList->getLocalPlayer() );
- 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 );
- //
- // 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;
- else
- list = &m_objectList;
- // 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 );
- } // end if
- else
- {
- // the new object next points to the current object
- newObj->friend_setNext( currObject );
- // new list head is now newObj
- *list = newObj;
- } // end else
- break; // exit for, stop the insert
- } // end if
- else if( nextObject == NULL )
- {
- // at the end of the list, put object here
- currObject->friend_setNext( newObj );
- } // end else if
- // our current object is now the previous object
- prevObject = currObject;
- prevPriority = currPriority;
- } // end if
- } // end else
- } // end addObject
- //-------------------------------------------------------------------------------------------------
- /** 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
- radarObject->deleteInstance();
- // all done, object found and deleted
- return TRUE;
- } // end if
- // save this object as previous one encountered in the list
- prevObject = radarObject;
- } // end for, radarObject
- // object was not found in this list
- return FALSE;
- } // end deleteFromList
- //-------------------------------------------------------------------------------------------------
- /** Remove an object from the radar, the object may reside in any list */
- //-------------------------------------------------------------------------------------------------
- void Radar::removeObject( Object *obj )
- {
- // sanity
- if( obj->friend_getRadarData() == NULL )
- return;
- if( deleteFromList( obj, &m_localObjectList ) == TRUE )
- return;
- else if( deleteFromList( obj, &m_objectList ) == TRUE )
- return;
- else
- {
- // sanity
- DEBUG_ASSERTCRASH( 0, ("Radar: Tried to remove object '%s' which was not found\n",
- obj->getTemplate()->getName().str()) );
- } // end else
- } // end removeObject
- //-------------------------------------------------------------------------------------------------
- /** 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
- } // end radarToWorld
- //-------------------------------------------------------------------------------------------------
- /** 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
- } // end worldToRadar
- // ------------------------------------------------------------------------------------------------
- /** 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;
- } // end if
- 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;
- } // end else
- return TRUE;
- } // end localPixelToRadar
- // ------------------------------------------------------------------------------------------------
- /** 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 );
- } // end screenPixelToWorld
- // ------------------------------------------------------------------------------------------------
- /** 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;
- } // end objectUnderRadarPixel
- // ------------------------------------------------------------------------------------------------
- /** 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\n" ));
- continue;
- } // end if
- // 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;
- } // end for, radarObject
- // no match found
- return NULL;
- } // end searchListForRadarLocationMatch
- // ------------------------------------------------------------------------------------------------
- /** 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;
- } // end if
- 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;
- } // end else
- else
- {
- ul->x = 0;
- ul->y = 0;
- lr->x = width;
- lr->y = height;
- } // end else
- */
- // make them pixel positions
- ul->x += startX;
- ul->y += startY;
- lr->x += startX;
- lr->y += startY;
- } // end findDrawPositions
- //-------------------------------------------------------------------------------------------------
- /** 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 ];
- for( Int i = 0; radarColorLookupTable[ i ].event != RADAR_EVENT_INVALID; ++i )
- {
- if( radarColorLookupTable[ i ].event == type )
- {
- color[ 0 ] = radarColorLookupTable[ i ].color1;
- color[ 1 ] = radarColorLookupTable[ i ].color2;
- break;
- } // end if
- } // end while
- // 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\n" ));
- color[ 0 ] = color1;
- color[ 1 ] = color2;
- } // end if
- // call the internal method to create the event with these colors
- internalCreateEvent( world, type, secondsToLive, &color[ 0 ], &color[ 1 ] );
- } // end createEvent
- // ------------------------------------------------------------------------------------------------
- /** 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 ] );
- } // end createPlayerEvent
- //-------------------------------------------------------------------------------------------------
- /** 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;
- } // end createEvent
- //-------------------------------------------------------------------------------------------------
- /** 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;
- } // end if
- return FALSE; // no last event
- } // end getLastEventLoc
- // ------------------------------------------------------------------------------------------------
- /** 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 = ThePlayerList->getLocalPlayer();
- // 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 );
- } // end if
- 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 (ThePlayerList->getLocalPlayer()->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 );
- } // end else if
- else
- {
- // display message
- TheInGameUI->message( "RADAR:UnderAttack" );
- // play audio event
- static AudioEventRTS underAttackSound = TheAudio->getMiscAudio()->m_radarStructureUnderAttackSound;
- underAttackSound.setPlayerIndex(player->getPlayerIndex());
- TheAudio->addAudioEvent( &underAttackSound );
- } // end else
- } // end if
- } // end tryUnderAttackEvent
- // ------------------------------------------------------------------------------------------------
- /** 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;
- }
- // We should only be warned against infiltrations that are taking place against us.
- if( obj->getControllingPlayer() != ThePlayerList->getLocalPlayer() )
- 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)
- //
- Player *player = ThePlayerList->getLocalPlayer();
- // display message
- TheInGameUI->message( "RADAR:Infiltration" );
- // play audio event
- static AudioEventRTS infiltrationWarningSound = TheAudio->getMiscAudio()->m_radarInfiltrationSound;
- infiltrationWarningSound.setPlayerIndex(player->getPlayerIndex());
- TheAudio->addAudioEvent( &infiltrationWarningSound );
- } // end tryInfiltrationEvent
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- 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
- } // end if
- } // end if
- } // end for i
- // if we got here then we want to create a new event
- createEvent( pos, event );
- // return TRUE for successfully created event
- return TRUE;
- } // end tryEvent
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void Radar::refreshTerrain( TerrainLogic *terrain )
- {
- // no future queue is valid now
- m_queueTerrainRefreshFrame = 0;
- } // end refreshTerrain
- // ------------------------------------------------------------------------------------------------
- /** 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();
- } // end queueTerrainRefresh
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void Radar::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** 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\n" ));
- // 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 );
- } // end for, radarObject
- } // end if, save
- 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\n" ));
- throw SC_INVALID_DATA;
- }
- }
- #else
- DEBUG_CRASH(( "xferRadarObjectList - List head should be NULL, but isn't\n" ));
- throw SC_INVALID_DATA;
- #endif
- } // end if
- // 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() )
- {
- } // end for, other
- // set the end of the list to point to the new object
- other->friend_setNext( radarObject );
- } // end else
- // load the data
- xfer->xferSnapshot( radarObject );
-
- } // end for i
- } // end else, load
- } // end xferRadarObjectList
- // ------------------------------------------------------------------------------------------------
- /** Xfer Method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void Radar::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // radar hidden
- xfer->xferBool( &m_radarHidden );
- // radar force on
- xfer->xferBool( &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'\n",
- eventCount, eventCountVerify ));
- throw SC_INVALID_DATA;
- } // end if
- 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 );
-
- } // end for i
- // next event index
- xfer->xferInt( &m_nextFreeRadarEvent );
- // last event index
- xfer->xferInt( &m_lastRadarEvent );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** 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 );
- } // end loadPostProcess
- // ------------------------------------------------------------------------------------------------
- /** Is the priority type passed in a "visible" one that can show up on the radar */
- // ------------------------------------------------------------------------------------------------
- Bool Radar::isPriorityVisible( RadarPriorityType priority ) const
- {
- switch( priority )
- {
- case RADAR_PRIORITY_INVALID:
- case RADAR_PRIORITY_NOT_ON_RADAR:
- return FALSE;
- default:
- return TRUE;
- } // end switch
- } // end isPriorityVisible
|