| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- /*
- ** 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: OverlordContain.cpp ////////////////////////////////////////////////////////////////////////
- // Author: Graham Smallwood, September, 2002
- // Desc: Contain module that acts as transport normally, but when full it redirects queries to the first passenger
- // All of this redirection stuff makes it so that while I am normally a transport
- // for Overlord subObjects, once I have a passenger, _I_ become a transport of their type.
- // So, the answer to this question depends on if it is my passenger asking, or theirs.
- // As always, I can't use convience functions that get redirected on a ? like this.
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/Player.h"
- #include "Common/Xfer.h"
- #include "Common/ThingTemplate.h"
- #include "Common/ThingFactory.h"
- #include "GameClient/ControlBar.h"
- #include "GameClient/Drawable.h"
- #include "GameLogic/ExperienceTracker.h"
- #include "GameLogic/Module/BodyModule.h"
- #include "GameLogic/Module/OverlordContain.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- OverlordContainModuleData::OverlordContainModuleData()
- {
- // m_initialPayload.count = 0;
- m_experienceSinkForRider = TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void OverlordContainModuleData::buildFieldParse(MultiIniFieldParse& p)
- {
- TransportContainModuleData::buildFieldParse(p);
- static const FieldParse dataFieldParse[] =
- {
- { "PayloadTemplateName", INI::parseAsciiStringVectorAppend, NULL, offsetof(OverlordContainModuleData, m_payloadTemplateNameData) },
- { "ExperienceSinkForRider", INI::parseBool, NULL, offsetof(OverlordContainModuleData, m_experienceSinkForRider) },
- { 0, 0, 0, 0 }
- };
- p.add(dataFieldParse);
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- //void OverlordContainModuleData::parseInitialPayload( INI* ini, void *instance, void *store, const void* /*userData*/ )
- //{
- // OverlordContainModuleData* self = (OverlordContainModuleData*)instance;
- // const char* name = ini->getNextToken();
- // const char* countStr = ini->getNextTokenOrNull();
- // Int count = countStr ? INI::scanInt(countStr) : 1;
-
- // self->m_initialPayload.name.set(name);
- // self->m_initialPayload.count = count;
- //}
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- OverlordContain::OverlordContain( Thing *thing, const ModuleData *moduleData ) :
- TransportContain( thing, moduleData )
- {
- m_redirectionActivated = FALSE;
- m_payloadCreated = FALSE;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- OverlordContain::~OverlordContain( void )
- {
- }
- void OverlordContain::onObjectCreated( void )
- {
- OverlordContain::createPayload();
- }
- //-------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void OverlordContain::createPayload()
- {
- OverlordContainModuleData* self = (OverlordContainModuleData*)getOverlordContainModuleData();
- // Any number of different passengers can be loaded here at init time
- Object* object = getObject();
- ContainModuleInterface *contain = object->getContain();
- if( contain )
- {
- contain->enableLoadSounds( FALSE );
- TemplateNameList list = self->m_payloadTemplateNameData;
- TemplateNameIterator iter = list.begin();
- while ( iter != list.end() )
- {
- const ThingTemplate* temp = TheThingFactory->findTemplate( *iter );
- if (temp)
- {
- Object* payload = TheThingFactory->newObject( temp, object->getTeam() );
- if( contain->isValidContainerFor( payload, true ) )
- {
- contain->addToContain( payload );
- }
- else
- {
- DEBUG_CRASH( ( "OverlordContain::createPayload: %s is full, or not valid for the payload %s!", object->getName().str(), self->m_initialPayload.name.str() ) );
- }
- }
- ++iter;
- }
- contain->enableLoadSounds( TRUE );
- } // endif contain
- m_payloadCreated = TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::onBodyDamageStateChange( const DamageInfo* damageInfo,
- BodyDamageType oldState,
- BodyDamageType newState) ///< state change callback
- {
- // I can't use any convienience functions, as they will all get routed to the bunker I may carry.
- // I want just me.
- // Oh, and I don't want this function trying to do death. That is more complicated and will be handled
- // on my death.
- if( newState != BODY_RUBBLE && m_containListSize == 1 )
- {
- Object *myGuy = m_containList.front();
- myGuy->getBodyModule()->setDamageState( newState );
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- ContainModuleInterface *OverlordContain::getRedirectedContain() const
- {
- // Naturally, I can not use a redirectible convienience function
- // to answer if I am redirecting yet.
- // If I am empty, say no.
- if( m_containListSize < 1 )
- return NULL;
- if( !m_redirectionActivated )
- return NULL;// Shut off early to allow death to happen without my bunker having
- // trouble finding me to say goodbye as messages get sucked up the pipe to him.
- Object *myGuy = m_containList.front();
- if( myGuy )
- return myGuy->getContain();
- return NULL;// Or say no if they have no contain.
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::onDie( const DamageInfo *damageInfo )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::onDie( damageInfo );
- return;
- }
- //Everything is fine if I am empty or carrying a regular guy. If I have a redirected contain
- // set up, then I need to handle the order of death explicitly, or things will become confused
- // when I stop redirecting in the middle of the process. Or I will get confused as my commands
- // get sucked up the pipe.
- // So this is an extend that lets me control the order of death.
-
- deactivateRedirectedContain();
- Object *myGuy = m_containList.front();
- myGuy->kill();
-
- TransportContain::onDie( damageInfo );
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::onDelete( void )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::onDelete( );
- return;
- }
- // Without my throwing the redirect switch, teardown deletion will get confused and fire off a bunch of asserts
- getRedirectedContain()->removeAllContained();
- deactivateRedirectedContain();
- removeAllContained();
- TransportContain::onDelete( );
- }
- // ------------------------------------------------------------------------------------------------
- void OverlordContain::onCapture( Player *oldOwner, Player *newOwner )
- {
- if( m_containListSize < 1 )
- return;
-
- // Need to capture our specific rider. He will then kick passengers out if he is a Transport
- Object *myGuy = m_containList.front();
- myGuy->setTeam( newOwner->getDefaultTeam() );
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::isGarrisonable() const
- {
- if( getRedirectedContain() == NULL )
- return FALSE;
- return getRedirectedContain()->isGarrisonable();
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::isKickOutOnCapture()
- {
- if( getRedirectedContain() == NULL )
- return FALSE;// Me the Overlord doesn't want to
-
- return getRedirectedContain()->isKickOutOnCapture();
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::addToContainList( Object *obj )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::addToContainList( obj );
- return;
- }
-
- getRedirectedContain()->addToContainList( obj );
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::addToContain( Object *obj )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::addToContain( obj );
- return;
- }
-
- getRedirectedContain()->addToContain( obj );
- }
- //-------------------------------------------------------------------------------------------------
- /** Remove 'obj' from the m_containList of objects in this module.
- * This will trigger an onRemoving event for the object that this module
- * is a part of and an onRemovedFrom event for the object being removed */
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::removeFromContain( Object *obj, Bool exposeStealthUnits )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::removeFromContain( obj, exposeStealthUnits );
- return;
- }
- getRedirectedContain()->removeFromContain( obj, exposeStealthUnits );
- }
- //-------------------------------------------------------------------------------------------------
- /** Remove all contained objects from the contained list */
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::removeAllContained( Bool exposeStealthUnits )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::removeAllContained( exposeStealthUnits );
- return;
- }
-
- const ContainedItemsList *fullList = getRedirectedContain()->getContainedItemsList();
- Object *obj;
- ContainedItemsList::const_iterator it;
- it = (*fullList).begin();
- while( it != (*fullList).end() )
- {
- obj = *it;
- it++;
- removeFromContain( obj, exposeStealthUnits );
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Iterate the contained list and call the callback on each of the objects */
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::iterateContained( ContainIterateFunc func, void *userData, Bool reverse )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::iterateContained( func, userData, reverse );
- return;
- }
-
- getRedirectedContain()->iterateContained( func, userData, reverse );
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::onContaining( Object *obj, Bool wasSelected )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::onContaining( obj, wasSelected );
- if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) )
- {
- activateRedirectedContain();//Am now carrying something
- // And this contain style explicitly sucks XP from our little friend.
- if( getOverlordContainModuleData()->m_experienceSinkForRider && obj->getExperienceTracker() )
- obj->getExperienceTracker()->setExperienceSink(getObject()->getID());
- if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && getObject()->testStatus( OBJECT_STATUS_STEALTHED ) )
- {
- StealthUpdate *myStealth = obj->getStealth();
- if ( myStealth )
- {
- myStealth->receiveGrant( true );
- // note to anyone... once stealth is granted to this gattlingcannon ( or such )
- // let its own stealthupdate govern the allowedtostealth cases
- // a portable structure never gets removed, so...
- }
- }
-
- }
-
-
- return;
- }
- OpenContain::onContaining( obj, wasSelected );
- getRedirectedContain()->onContaining( obj, wasSelected );
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::killAllContained( void )
- {
- // This is a game call meant to clear actual passengers. We don't want it to kill our turret. That'd be wierd.
- if( getRedirectedContain() )
- {
- getRedirectedContain()->killAllContained();
- }
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::onRemoving( Object *obj )
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- TransportContain::onRemoving( obj );
- return;
- }
- OpenContain::onRemoving(obj);
- getRedirectedContain()->onRemoving( obj );
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::isValidContainerFor(const Object* obj, Bool checkCapacity) const
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- return TransportContain::isValidContainerFor( obj, checkCapacity );
-
- return getRedirectedContain()->isValidContainerFor( obj, checkCapacity );
- }
- //-------------------------------------------------------------------------------------------------
- UnsignedInt OverlordContain::getContainCount() const
- {
- ContainModuleInterface* redir = getRedirectedContain();
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( redir == NULL )
- return TransportContain::getContainCount( );
-
- return redir->getContainCount();
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::getContainerPipsToShow(Int& numTotal, Int& numFull)
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- {
- numTotal = 0;
- numFull = 0;
- return false;
- }
- else
- {
- return getRedirectedContain()->getContainerPipsToShow(numTotal, numFull);
- }
- }
- //-------------------------------------------------------------------------------------------------
- Int OverlordContain::getContainMax( ) const
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- return TransportContain::getContainMax( );
-
- return getRedirectedContain()->getContainMax();
- }
- //-------------------------------------------------------------------------------------------------
- const ContainedItemsList* OverlordContain::getContainedItemsList() const
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- return TransportContain::getContainedItemsList( );
-
- return getRedirectedContain()->getContainedItemsList();
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::isEnclosingContainerFor( const Object *obj ) const
- {
- // All of this redirection stuff makes it so that while I am normally a transport
- // for Overlord subObjects, once I have a passenger, _I_ become a transport of their type.
- // So, the answer to this question depends on if it is my passenger asking, or theirs.
- // As always, I can't use convience functions that get redirected on a ? like this.
- if( m_containListSize > 0 && obj == m_containList.front() )
- return FALSE;
- return TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- Bool OverlordContain::isDisplayedOnControlBar() const
- {
- // Do you mean me the Overlord, or my behavior of passing stuff on to my passengers?
- if( getRedirectedContain() == NULL )
- return FALSE;//No need to call up inheritance, this is a module based question, and I say no.
-
- return getRedirectedContain()->isDisplayedOnControlBar();
- }
- //-------------------------------------------------------------------------------------------------
- const Object *OverlordContain::friend_getRider() const
- {
- // The draw order dependency bug for riders means that our draw module needs to cheat to get
- //around it. So this is another function that knows it is getting around redirection to ask
- // an Overlord specific function.
- if( m_containListSize > 0 )
- return m_containList.front();
- return NULL;
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::activateRedirectedContain()
- {
- m_redirectionActivated = TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- void OverlordContain::deactivateRedirectedContain()
- {
- m_redirectionActivated = FALSE;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- // if my object gets selected, then my visible passengers should, too
- // this gets called from
- void OverlordContain::clientVisibleContainedFlashAsSelected()
- {
- // THIS OVERRIDES GRAHAMS NASTY OVERRIDE THING
- // SO WE CAN FLASH THE PORTABLE BUNKER INSTEAD OF ITS OCCUPANTS
- const ContainedItemsList* items = TransportContain::getContainedItemsList();
- if( items )
- {
- ContainedItemsList::const_iterator it;
- it = items->begin();
- while( *it )
- {
- Object *object = *it;
- if ( object && object->isKindOf( KINDOF_PORTABLE_STRUCTURE ) )
- {
- Drawable *draw = object->getDrawable();
- if ( draw )
- {
- draw->flashAsSelected(); //WOW!
- }
- }
-
- ++it;
- }
- }
- }
- Bool OverlordContain::isPassengerAllowedToFire( ObjectID id ) const
- {
- Object *passenger = TheGameLogic->findObjectByID(id);
- if(passenger != NULL)
- {
- //only allow infantry, and turrets and such. no vehicles.
- if(passenger->isKindOf(KINDOF_INFANTRY) == FALSE && passenger->isKindOf(KINDOF_PORTABLE_STRUCTURE) == FALSE)
- return FALSE;
- }
-
-
- if ( getObject() && getObject()->getContainedBy() ) // nested containment voids firing, always
- return FALSE;
- return TransportContain::isPassengerAllowedToFire();
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void OverlordContain::crc( Xfer *xfer )
- {
- // extend base class
- TransportContain::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void OverlordContain::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- TransportContain::xfer( xfer );
- // redirection activated
- xfer->xferBool( &m_redirectionActivated );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void OverlordContain::loadPostProcess( void )
- {
- // extend base class
- TransportContain::loadPostProcess();
- } // end loadPostProcess
|