| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /*
- ** 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: CreateCrateDie.cpp /////////////////////////////////////////////////////////////////////////////
- // Author: Graham Smallwood, February 2002
- // Desc: A chance to create a crate on death according to certain condition checks
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/PlayerList.h"
- #include "Common/Player.h"
- #include "Common/RandomValue.h"
- #include "Common/ThingFactory.h"
- #include "Common/ThingTemplate.h"
- #include "Common/Xfer.h"
- #include "GameLogic/CrateSystem.h"
- #include "GameLogic/ExperienceTracker.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #include "GameLogic/Module/CreateCrateDie.h"
- #include "GameLogic/Module/AIUpdate.h"
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- CreateCrateDie::CreateCrateDie( Thing *thing, const ModuleData* moduleData ) : DieModule( thing, moduleData )
- {
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- CreateCrateDie::~CreateCrateDie( void )
- {
- }
- void CreateCrateDieModuleData::parseCrateData( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
- {
- CreateCrateDieModuleData* self = (CreateCrateDieModuleData*)instance;
- AsciiString crateName = ini->getNextToken();
- self->m_crateNameList.push_back( crateName );
- }
- //-------------------------------------------------------------------------------------------------
- /** The die callback. */
- //-------------------------------------------------------------------------------------------------
- void CreateCrateDie::onDie( const DamageInfo * damageInfo )
- {
- if (!isDieApplicable(damageInfo))
- return;
- CrateTemplate const *currentCrateData = NULL;
- Object *killer = TheGameLogic->findObjectByID( damageInfo->in.m_sourceID );
- Object *me = getObject();
- if( killer && killer->getRelationship( me ) == ALLIES )
- return; //Nope, no crate for killing ally at all.
- for( AsciiStringListConstIterator iter = getCreateCrateDieModuleData()->m_crateNameList.begin();
- iter != getCreateCrateDieModuleData()->m_crateNameList.end();
- iter++
- )
- {
- currentCrateData = TheCrateSystem->findCrateTemplate( *iter );
- if( currentCrateData )
- {
- if( ! testCreationChance( currentCrateData ) )
- continue;// always test this
- if( (currentCrateData->m_veterancyLevel != LEVEL_INVALID) && ! testVeterancyLevel( currentCrateData ) )
- continue; //If this is set up to test and it fails
- if( KINDOFMASK_ANY_SET(currentCrateData->m_killedByTypeKindof) && !testKillerType( currentCrateData, killer ) )
- continue; //If this is set up to test and it fails
-
- if( (currentCrateData->m_killerScience != SCIENCE_INVALID) && !testKillerScience( currentCrateData, killer ) )
- continue; //If this is set up to test and it fails
- Object *crate = createCrate( currentCrateData );//Make the crate
- if( crate )
- {
- // Design needs to set ownership of crates sometimes
- if( currentCrateData->m_isOwnedByMaker )
- {
- crate->setTeam( me->getControllingPlayer()->getDefaultTeam() );
- }
- if (killer)
- {
- // If the killer is a computer controlled player, notify that the crate exists.
- if (killer->getControllingPlayer() &&
- killer->getControllingPlayer()->getPlayerType()==PLAYER_COMPUTER)
- {
- AIUpdateInterface *ai = killer->getAIUpdateInterface();
- if (ai)
- {
- ai->notifyCrate( crate->getID() );
- }
- }
- }
- }
- }
- }
- }
- Bool CreateCrateDie::testCreationChance( CrateTemplate const *currentCrateData )
- {
- Real testAgainst = currentCrateData->m_creationChance;
- Real testWith = GameLogicRandomValueReal( 0, 1 );
- return testWith < testAgainst;
- }
- Bool CreateCrateDie::testVeterancyLevel( CrateTemplate const *currentCrateData )
- {
- VeterancyLevel testAgainst = currentCrateData->m_veterancyLevel;
- VeterancyLevel testWith = getObject()->getVeterancyLevel();
- return testAgainst == testWith;
- }
- Bool CreateCrateDie::testKillerType( CrateTemplate const *currentCrateData, Object *killer )
- {
- if( killer == NULL )
- return FALSE;
- // Must match the whole group of bits set in the KilledBy description (most likely One).
- if( ! killer->getTemplate()->isKindOfMulti( currentCrateData->m_killedByTypeKindof, KINDOFMASK_NONE ) )
- return FALSE;
- return TRUE;
- }
- Bool CreateCrateDie::testKillerScience( CrateTemplate const *currentCrateData, Object *killer )
- {
- if( killer == NULL )
- return FALSE;
- // killer's player must have the listed science
- Player *killerPlayer = killer->getControllingPlayer();
- if( killerPlayer == NULL )
- return FALSE;
- if( ! killerPlayer->hasScience( currentCrateData->m_killerScience ) )
- return FALSE;
- return TRUE;
- }
- Object *CreateCrateDie::createCrate( CrateTemplate const *currentCrateData )
- {
- Coord3D centerPoint = *getObject()->getPosition();
- PathfindLayerEnum layer = getObject()->getLayer();
- // CreationChance is used for the success of this block, but this block can have any number of potential actual crates
- Real multipleCratePick = GameLogicRandomValueReal( 0, 1 );
- Real multipleCrateRunningTotal = 0;
- AsciiString crateName = "";
- for( crateCreationEntryConstIterator iter = currentCrateData->m_possibleCrates.begin();
- iter != currentCrateData->m_possibleCrates.end();
- iter++
- )
- {
- multipleCrateRunningTotal += (*iter).crateChance;
- if( multipleCrateRunningTotal > multipleCratePick )
- {
- // Run through the list of possibles, and if the sum of the chances is greater than my random pick,
- // then this is the correct one. (This simulates contiguous %, or weighted distribution)
- crateName = (*iter).crateName;
- break;
- }
- }
- // At this point, I could very well have a "" for the type, if the Designer didn't make the sum of chances 1
- ThingTemplate const *crateType = TheThingFactory->findTemplate( crateName );
- if( crateType == NULL )
- return NULL;
- Bool spotFound = FALSE;
- Coord3D creationPoint;
- FindPositionOptions fpOptions;
- fpOptions.minRadius = 0.0f;
- fpOptions.maxRadius = 5.0f;
- fpOptions.relationshipObject = getObject();
- fpOptions.flags = FPF_IGNORE_ALLY_OR_NEUTRAL_UNITS; // So the dead guy won't block, nor will his dead hulk.
- if (layer != LAYER_GROUND) {
- creationPoint = centerPoint;
- spotFound = true;
- } else if( ThePartitionManager->findPositionAround( ¢erPoint, &fpOptions, &creationPoint ) )
- {
- spotFound = TRUE;
- }
- else
- {
- // If the tight ignore units scan fails, then try a great big scan so we appear on the edge
- // of the large dead thing (building rubble)
- fpOptions.minRadius = 0.0f;
- fpOptions.maxRadius = 125.0f;
- fpOptions.relationshipObject = NULL;
- fpOptions.flags = FPF_NONE;
- if( ThePartitionManager->findPositionAround( ¢erPoint, &fpOptions, &creationPoint ) )
- {
- spotFound = TRUE;
- }
- }
- if( spotFound )
- {
- Object *newCrate = TheThingFactory->newObject( crateType, NULL );
- newCrate->setPosition( &creationPoint );
- newCrate->setOrientation( GameLogicRandomValueReal( 0, 2*PI ) );
- newCrate->setLayer(layer);
- Drawable *crateDrawable = newCrate->getDrawable();
- if( crateDrawable )
- {
- crateDrawable->setTerrainDecal(TERRAIN_DECAL_CRATE);
- crateDrawable->setTerrainDecalSize(2.5f * newCrate->getGeometryInfo().getMajorRadius(),
- 2.5f * newCrate->getGeometryInfo().getMajorRadius() ) ;
- crateDrawable->setTerrainDecalFadeTarget(1.0f, 0.03f);
- }
- return newCrate;
- }
- return NULL;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void CreateCrateDie::crc( Xfer *xfer )
- {
- // extend base class
- DieModule::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void CreateCrateDie::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- DieModule::xfer( xfer );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void CreateCrateDie::loadPostProcess( void )
- {
- // extend base class
- DieModule::loadPostProcess();
- } // end loadPostProcess
|