| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: TunnelTracker.cpp ///////////////////////////////////////////////////////////
- // The part of a Player's brain that holds the communal Passenger list of all tunnels.
- // Author: Graham Smallwood, March, 2002
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/GameState.h"
- #include "Common/GlobalData.h"
- #include "Common/KindOf.h"
- #include "Common/TunnelTracker.h"
- #include "Common/Xfer.h"
- #include "GameClient/ControlBar.h"
- #include "GameClient/Drawable.h"
- #include "GameLogic/AI.h"
- #include "GameLogic/AIPathfind.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #include "GameLogic/Module/BodyModule.h"
- #include "GameLogic/Module/TunnelContain.h"
- // ------------------------------------------------------------------------
- TunnelTracker::TunnelTracker()
- {
- m_tunnelCount = 0;
- m_containListSize = 0;
- m_curNemesisID = INVALID_ID;
- m_nemesisTimestamp = 0;
- }
- // ------------------------------------------------------------------------
- TunnelTracker::~TunnelTracker()
- {
- m_tunnelIDs.clear();
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::iterateContained( ContainIterateFunc func, void *userData, Bool reverse )
- {
- if (reverse)
- {
- // note that this has to be smart enough to handle items in the list being deleted
- // via the callback function.
- for(ContainedItemsList::reverse_iterator it = m_containList.rbegin(); it != m_containList.rend(); )
- {
- // save the obj...
- Object* obj = *it;
-
- // incr the iterator BEFORE calling the func (if the func removes the obj,
- // the iterator becomes invalid)
- ++it;
-
- // call it
- (*func)( obj, userData );
- }
- }
- else
- {
- // note that this has to be smart enough to handle items in the list being deleted
- // via the callback function.
- for(ContainedItemsList::iterator it = m_containList.begin(); it != m_containList.end(); )
- {
- // save the obj...
- Object* obj = *it;
-
- // incr the iterator BEFORE calling the func (if the func removes the obj,
- // the iterator becomes invalid)
- ++it;
-
- // call it
- (*func)( obj, userData );
- }
- }
- }
- // ------------------------------------------------------------------------
- Int TunnelTracker::getContainMax() const
- {
- return TheGlobalData->m_maxTunnelCapacity;
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::updateNemesis(const Object *target)
- {
- if (getCurNemesis()==NULL) {
- if (target) {
- if (target->isKindOf(KINDOF_VEHICLE) || target->isKindOf(KINDOF_STRUCTURE) ||
- target->isKindOf(KINDOF_INFANTRY) || target->isKindOf(KINDOF_AIRCRAFT)) {
- m_curNemesisID = target->getID();
- m_nemesisTimestamp = TheGameLogic->getFrame();
- }
- }
- } else if (getCurNemesis()==target) {
- m_nemesisTimestamp = TheGameLogic->getFrame();
- }
- }
- // ------------------------------------------------------------------------
- Object *TunnelTracker::getCurNemesis(void)
- {
- if (m_curNemesisID == INVALID_ID) {
- return NULL;
- }
- if (m_nemesisTimestamp + 4*LOGICFRAMES_PER_SECOND < TheGameLogic->getFrame()) {
- m_curNemesisID = INVALID_ID;
- return NULL;
- }
- Object *target = TheGameLogic->findObjectByID(m_curNemesisID);
- if (target) {
- //If the enemy unit is stealthed and not detected, then we can't attack it!
- UnsignedInt status = target->getStatusBits();
- if( (status & OBJECT_STATUS_STEALTHED) && !(status & OBJECT_STATUS_DETECTED) ) {
- target = NULL;
- }
- }
- if (target && target->isEffectivelyDead()) {
- target = NULL;
- }
- if (target == NULL) {
- m_curNemesisID = INVALID_ID;
- }
- return target;
- }
- // ------------------------------------------------------------------------
- Bool TunnelTracker::isValidContainerFor(const Object* obj, Bool checkCapacity) const
- {
- //October 11, 2002 -- Kris : Dustin wants ALL units to be able to use tunnels!
- // srj sez: um, except aircraft.
- if (obj && !obj->isKindOf(KINDOF_AIRCRAFT))
- {
- if (checkCapacity)
- {
- Int containMax = getContainMax();
- Int containCount = getContainCount();
- return ( containCount < containMax );
- }
- else
- {
- return true;
- }
- }
- return false;
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::addToContainList( Object *obj )
- {
- m_containList.push_back(obj);
- ++m_containListSize;
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::removeFromContain( Object *obj, Bool exposeStealthUnits )
- {
- ContainedItemsList::iterator it = std::find(m_containList.begin(), m_containList.end(), obj);
- if (it != m_containList.end())
- {
- // note that this invalidates the iterator!
- m_containList.erase(it);
- --m_containListSize;
- }
- }
- // ------------------------------------------------------------------------
- Bool TunnelTracker::isInContainer( Object *obj )
- {
- return (std::find(m_containList.begin(), m_containList.end(), obj) != m_containList.end()) ;
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::onTunnelCreated( const Object *newTunnel )
- {
- m_tunnelCount++;
- m_tunnelIDs.push_back( newTunnel->getID() );
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::onTunnelDestroyed( const Object *deadTunnel )
- {
- m_tunnelCount--;
- m_tunnelIDs.remove( deadTunnel->getID() );
- if( m_tunnelCount == 0 )
- {
- // Kill everyone in our contain list. Cave in!
- iterateContained( destroyObject, NULL, FALSE );
- m_containList.clear();
- m_containListSize = 0;
- }
- else
- {
- Object *validTunnel = TheGameLogic->findObjectByID( m_tunnelIDs.front() );
- // Otherwise, make sure nobody inside remembers the dead tunnel as the one they entered
- // (scripts need to use so there must be something valid here)
- for(ContainedItemsList::iterator it = m_containList.begin(); it != m_containList.end(); )
- {
- Object* obj = *it;
- ++it;
- if( obj->getContainedBy() == deadTunnel )
- obj->onContainedBy( validTunnel );
- }
- }
- }
- // ------------------------------------------------------------------------
- void TunnelTracker::destroyObject( Object *obj, void * )
- {
- // Now that tunnels consider ContainedBy to be "the tunnel you entered", I need to say goodbye
- // llike other contain types so they don't look us up on their deletion and crash
- obj->onRemovedFrom( obj->getContainedBy() );
- TheGameLogic->destroyObject( obj );
- }
- // ------------------------------------------------------------------------
- // heal all the objects within the tunnel system using the iterateContained function
- void TunnelTracker::healObjects(Real frames)
- {
- iterateContained(healObject, &frames, FALSE);
- }
- // ------------------------------------------------------------------------
- // heal one object within the tunnel network system
- void TunnelTracker::healObject( Object *obj, void *frames)
- {
-
- //get the number of frames to heal
- Real *framesForFullHeal = (Real*)frames;
- // setup the healing damageInfo structure with all but the amount
- DamageInfo healInfo;
- healInfo.in.m_damageType = DAMAGE_HEALING;
- healInfo.in.m_deathType = DEATH_NONE;
- //healInfo.in.m_sourceID = getObject()->getID();
- // get body module of the thing to heal
- BodyModuleInterface *body = obj->getBodyModule();
- // if we've been in here long enough ... set our health to max
- if( TheGameLogic->getFrame() - obj->getContainedByFrame() >= *framesForFullHeal )
- {
-
- // set the amount to max just to be sure we're at the top
- healInfo.in.m_amount = body->getMaxHealth();
-
- // set max health
- body->attemptHealing( &healInfo );
- } // end if
- else
- {
- //
- // given the *whole* time it would take to heal this object, lets pretend that the
- // object is at zero health ... and give it a sliver of health as if it were at 0 health
- // and would be fully healed at 'framesForFullHeal'
- //
- healInfo.in.m_amount = body->getMaxHealth() / *framesForFullHeal;
- // do the healing
- body->attemptHealing( &healInfo );
- } // end else
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void TunnelTracker::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void TunnelTracker::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // tunnel object id list
- xfer->xferSTLObjectIDList( &m_tunnelIDs );
- // contain list count
- xfer->xferInt( &m_containListSize );
- // contain list data
- ObjectID objectID;
- if( xfer->getXferMode() == XFER_SAVE )
- {
- ContainedItemsList::const_iterator it;
- for( it = m_containList.begin(); it != m_containList.end(); ++it )
- {
- objectID = (*it)->getID();
- xfer->xferObjectID( &objectID );
- } // end for, it
- } // end if, save
- else
- {
- for( UnsignedShort i = 0; i < m_containListSize; ++i )
- {
- xfer->xferObjectID( &objectID );
- m_xferContainList.push_back( objectID );
- } // end for, i
- } // end else, load
- // tunnel count
- xfer->xferUnsignedInt( &m_tunnelCount );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void TunnelTracker::loadPostProcess( void )
- {
- // sanity, the contain list should be empty until we post process the id list
- if( m_containList.size() != 0 )
- {
- DEBUG_CRASH(( "TunnelTracker::loadPostProcess - m_containList should be empty but is not\n" ));
- throw SC_INVALID_DATA;
- } // end if
- // translate each object ids on the xferContainList into real object pointers in the contain list
- Object *obj;
- std::list< ObjectID >::const_iterator it;
- for( it = m_xferContainList.begin(); it != m_xferContainList.end(); ++it )
- {
- obj = TheGameLogic->findObjectByID( *it );
- if( obj == NULL )
- {
- DEBUG_CRASH(( "TunnelTracker::loadPostProcess - Unable to find object ID '%d'\n", *it ));
- throw SC_INVALID_DATA;
- } // end if
- // push on the back of the contain list
- m_containList.push_back( obj );
- // Crap. This is in OpenContain as a fix, but not here.
- {
- // remove object from its group (if any)
- obj->leaveGroup();
-
- // remove rider from partition manager
- ThePartitionManager->unRegisterObject( obj );
-
- // hide the drawable associated with rider
- if( obj->getDrawable() )
- obj->getDrawable()->setDrawableHidden( true );
-
- // remove object from pathfind map
- if( TheAI )
- TheAI->pathfinder()->removeObjectFromPathfindMap( obj );
-
- }
- } // end for, it
- // we're done with the xfer contain list now
- m_xferContainList.clear();
- } // end loadPostProcess
|