| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- /*
- ** 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: DynamicShroudClearingRangeUpdate.cpp /////////////////////////////////////////////////////////////////////////
- // Author: Graham Smallwood, August 2002
- // Desc: Changes the Objects Shroud Clearing range
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h"
- #include "Common/Xfer.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/Module/DynamicShroudClearingRangeUpdate.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-------------------------------------------------------------------------------------------------
- DynamicShroudClearingRangeUpdateModuleData::DynamicShroudClearingRangeUpdateModuleData()
- {
- m_shrinkDelay = 0;
- m_shrinkTime = 0;
- m_growDelay = 0;
- m_growTime = 0;
- m_finalVision = 0.0f;
- m_changeInterval = 0;
- m_growInterval = 0;
- m_doSpySatFX = FALSE;
- }
- //-------------------------------------------------------------------------------------------------
- /*static*/ void DynamicShroudClearingRangeUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
- {
- UpdateModuleData::buildFieldParse(p);
- static const FieldParse dataFieldParse[] =
- {
- { "ChangeInterval", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_changeInterval ) },
- { "GrowInterval", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growInterval ) },
- { "ShrinkDelay", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_shrinkDelay ) },
- { "ShrinkTime", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_shrinkTime ) },
- { "GrowDelay", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growDelay ) },
- { "GrowTime", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growTime ) },
- { "FinalVision", INI::parseReal, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_finalVision ) },
- { "GridDecalTemplate", RadiusDecalTemplate::parseRadiusDecalTemplate, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_gridDecalTemplate ) },
- { 0, 0, 0, 0 }
- };
- p.add(dataFieldParse);
- }
- //-------------------------------------------------------------------------------------------------
- //
- // doneForeverFrame
- // o | shrinkdelay |
- // |<-----------------------------------stateCountDown---------------------------------->|
- // | shrinktime | | growtime | growdelay |
- // | shrinkStartDeadline sustain growStartDeadline|
- //
- //-------------------------------------------------------------------------------------------------
- DynamicShroudClearingRangeUpdate::DynamicShroudClearingRangeUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData )
- {
- DynamicShroudClearingRangeUpdateModuleData *md = (DynamicShroudClearingRangeUpdateModuleData *)moduleData;
- // m_shrinkStartCountdown = md->m_shrinkDelay;
- // m_shrinkDeadline = 0;
- m_changeIntervalCountdown = 0;
- m_visionChangePerInterval = 0.0f;
- m_stateCountDown = md->m_shrinkDelay + md->m_shrinkTime;// total time
- m_totalFrames = max(1,m_stateCountDown);
- m_shrinkStartDeadline = m_stateCountDown - md->m_shrinkDelay;
- m_growStartDeadline = m_stateCountDown - md->m_growDelay;
- m_sustainDeadline = m_growStartDeadline - md->m_growTime;
- DEBUG_ASSERTCRASH((m_sustainDeadline >= m_shrinkStartDeadline),("DynamicShroudClearingRangeUpdate\nYOU WILL NEVER REACH FULL SHROUD CLEARING RANGE WITH THESE TIMES AND DELAYS"));
- DEBUG_ASSERTCRASH((m_growStartDeadline >= m_shrinkStartDeadline),("DynamicShroudClearingRangeUpdate\nYOU WILL NEVER REACH FULL SHROUD CLEARING RANGE WITH THESE TIMES AND DELAYS"));
- m_doneForeverFrame = TheGameLogic->getFrame() + m_stateCountDown;// a failsafe to force a shutdown on schedule
- // m_shrinkStartDeadline;
- // m_doneForeverFrame; //
- m_decalsCreated = FALSE;
- m_nativeClearingRange = 200;// a sensible default
- m_currentClearingRange = 0;
- m_state = DSCRU_NOT_STARTED_YET;
- // m_shrinkFinished = FALSE;
- // m_shrinkStarted = FALSE;
- Object* obj = getObject();
- if ( ! obj )
- return;
- Player* controller = obj->getControllingPlayer();
- if ( ! controller )
- return;
- m_nativeClearingRange = obj->getShroudClearingRange();//capture this before we start monkeying with it
- for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
- {
- m_gridDecal[d].clear();
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- DynamicShroudClearingRangeUpdate::~DynamicShroudClearingRangeUpdate( void )
- {
- killGridDecals();// just in case
- }
- //-------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::createGridDecals( const RadiusDecalTemplate& tmpl, Real radius, const Coord3D& pos )
- {
- for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
- {
- m_gridDecal[d].clear();
- tmpl.createRadiusDecal(pos, radius, getObject()->getControllingPlayer(), m_gridDecal[d]);
- m_gridDecal[d].setPosition(pos);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::animateGridDecals( void )
- {
- const Coord3D *ctr = getObject()->getPosition();
- Coord3D pos;
- pos.z = 0;
- Real radius = m_currentClearingRange + ((m_totalFrames - m_stateCountDown) * 2);
- Real angle = 0.0f;
- Real angleInc = (PI*2.0f) / (Real)GRID_FX_DECAL_COUNT;
- Real opacity = 1.0f - (m_currentClearingRange / m_nativeClearingRange);
- for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
- {
- pos.x = ctr->x + (sinf(angle) * radius);
- pos.y = ctr->y + (cosf(angle) * radius);
- pos.x -= ((Int)pos.x)%23;
- pos.y -= ((Int)pos.y)%23;
- m_gridDecal[d].setPosition(pos);
- m_gridDecal[d].setOpacity( opacity );
- angle += angleInc;
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::killGridDecals()
- {
- for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
- {
- m_gridDecal[d].clear();
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- UpdateSleepTime DynamicShroudClearingRangeUpdate::update( void )
- {
- if (m_state == DSCRU_SLEEPING) {
- return UPDATE_SLEEP_NONE;
- }
- //Housekeeping-----------------------------------------
- Object *me = getObject();
- const DynamicShroudClearingRangeUpdateModuleData *md = getDynamicShroudClearingRangeUpdateModuleData();
- UnsignedInt currentFrame = TheGameLogic->getFrame();
- if ( ! m_decalsCreated )
- {
- createGridDecals(md->m_gridDecalTemplate, 100, *(me->getPosition()));
- m_decalsCreated = TRUE;
- }
- //-----------------------------------------------------
- if( m_stateCountDown <= 0 || currentFrame > m_doneForeverFrame )
- m_state = DSCRU_DONE_FOREVER;
- else if ( m_stateCountDown <= m_shrinkStartDeadline )
- m_state = DSCRU_SHRINKING;
- else if ( m_stateCountDown <= m_sustainDeadline )
- m_state = DSCRU_SUSTAINING;
- else if ( m_stateCountDown <= m_growStartDeadline )
- m_state = DSCRU_GROWING;
- switch (m_state)
- {
- case DSCRU_NOT_STARTED_YET :
- {
- animateGridDecals();
- break;
- }
- case DSCRU_GROWING :
- {
- animateGridDecals();
- m_currentClearingRange += m_nativeClearingRange / max(1.0f, (Real)md->m_growTime);
- if (m_currentClearingRange >= m_nativeClearingRange)
- m_state = DSCRU_SUSTAINING;
- break;
- }
- case DSCRU_SUSTAINING :
- {
- m_currentClearingRange = m_nativeClearingRange;
- killGridDecals();
- break;
- }
- case DSCRU_SHRINKING :
- {
- m_currentClearingRange -= (m_nativeClearingRange-md->m_finalVision) / max(1.0f, (Real)md->m_shrinkTime);
- break;
- }
- case DSCRU_DONE_FOREVER :
- {
- killGridDecals();
- m_currentClearingRange = md->m_finalVision;
- break;
- }
- }
- if ( m_stateCountDown > 0 ) m_stateCountDown --;// it is important that this gets called every frame without sleeping
- //beacuse it handles animation and may need to respond to changing vision range from scripts & stuff
- if( m_changeIntervalCountdown > 0 )
- m_changeIntervalCountdown--;
- else
- {// reset per change timer
- m_changeIntervalCountdown = ( m_state == DSCRU_GROWING ? md->m_growInterval : md->m_changeInterval);
- me->setShroudClearingRange( m_currentClearingRange );
- if (m_state == DSCRU_DONE_FOREVER) { // We are done forever, and have done the final update, so sleep.+
- m_state = DSCRU_SLEEPING;
- }
- }
- return UPDATE_SLEEP_NONE;
- // if( !m_shrinkStarted )
- // {
- // //To allow a start delay of zero, check before dec, and look for trigger after
- // if( m_shrinkStartCountdown > 0 )
- // m_shrinkStartCountdown--;
- // if( m_shrinkStartCountdown == 0 )
- // {
- // m_shrinkStarted = TRUE;
- //
- // // Timer for how often to change
- // m_changeIntervalCountdown = md->m_changeInterval;
- // // Marker to make sure we end up precisely correct regardless of interval
- // m_shrinkDeadline = TheGameLogic->getFrame() + md->m_shrinkTime;
- // // Figure out how much to change each interval
- // Real visionDiff = me->getShroudClearingRange() - md->m_finalVision;
- // m_visionChangePerInterval = -visionDiff/(md->m_shrinkTime/md->m_changeInterval);
- // }
- // else
- // {
- // return UPDATE_SLEEP_NONE;// waiting to start
- // }
- // }
- // if( m_changeIntervalCountdown > 0 )
- // m_changeIntervalCountdown--;
- // if( m_changeIntervalCountdown != 0 )
- // return UPDATE_SLEEP_NONE;
- // // reset per change timer
- // m_changeIntervalCountdown = getDynamicShroudClearingRangeUpdateModuleData()->m_changeInterval;
- // UnsignedInt currentFrame = TheGameLogic->getFrame();
- // if( currentFrame > m_shrinkDeadline )
- // {
- // // Time to stop doing anything.
- // me->setShroudClearingRange( getDynamicShroudClearingRangeUpdateModuleData()->m_finalVision );
- // m_shrinkFinished = TRUE;
- // killGridDecals();
- // }
- // else
- // {
- // // bump the vision again
- // me->setShroudClearingRange( me->getShroudClearingRange() + m_visionChangePerInterval );
- // }
- // return UPDATE_SLEEP_NONE;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::crc( Xfer *xfer )
- {
- // extend base class
- UpdateModule::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- UpdateModule::xfer( xfer );
- // shrink start countdown
- xfer->xferInt( &m_stateCountDown );
- xfer->xferInt( &m_totalFrames );
- xfer->xferUnsignedInt( &m_growStartDeadline );
- xfer->xferUnsignedInt( &m_sustainDeadline );
- xfer->xferUnsignedInt( &m_shrinkStartDeadline );
- xfer->xferUnsignedInt( &m_doneForeverFrame );
- xfer->xferUnsignedInt( &m_changeIntervalCountdown );
- // vision change per interval
- xfer->xferBool( &m_decalsCreated );
- xfer->xferReal( &m_visionChangePerInterval );
-
- xfer->xferReal( &m_nativeClearingRange );
- xfer->xferReal( &m_currentClearingRange );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void DynamicShroudClearingRangeUpdate::loadPostProcess( void )
- {
- // extend base class
- UpdateModule::loadPostProcess();
- } // end loadPostProcess
|