/* ** 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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: ScriptEngine.h /////////////////////////////////////////////////////////////////////////// // Script evaluation engine. // Author: John Ahlquist, Nov. 2001 /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef __SCRIPTENGINE_H_ #define __SCRIPTENGINE_H_ #include "Common/GameType.h" #include "Common/GameMemory.h" #include "Common/STLTypedefs.h" #include "Common/Science.h" #include "Common/Snapshot.h" #include "Common/SubsystemInterface.h" #include "GameLogic/Scripts.h" class DataChunkInput; struct DataChunkInfo; class DataChunkOutput; class Team; class Object; class ThingTemplate; class Player; class PolygonTrigger; class ObjectTypes; #ifdef _INTERNAL #define SPECIAL_SCRIPT_PROFILING #endif // Slightly odd place to put breeze info, but the breeze info is // set by script, so it's as good a place as any. john a. struct BreezeInfo { Real m_direction; ///< Direction of the breeze in radians. 0 == +x direction. Coord2D m_directionVec; ///< sin/cos of direction, for efficiency. Real m_intensity; ///< How far to sway back & forth in radians. 0 = none. Real m_lean; ///< How far to lean with the wind in radians. 0 = none. Real m_randomness; ///< Randomness 0=perfectly uniform, 1 = +- up to 50% randomly. Short m_breezePeriod; ///< How many frames it takes to sway forward & back. Short m_breezeVersion; ///< Incremented each time the settings are updated. }; // This could belong elsewhere, but for now... struct NamedReveal { AsciiString m_revealName; AsciiString m_waypointName; Real m_radiusToReveal; AsciiString m_playerName; }; struct TScriptListReadInfo { Int numLists; ScriptList *readLists[MAX_PLAYER_COUNT]; }; struct TCounter { Int value; AsciiString name; Bool isCountdownTimer; }; struct TFlag { Bool value; AsciiString name; }; typedef std::list ListAsciiString; typedef std::list::iterator ListAsciiStringIt; typedef std::pair PairAsciiStringUINT; typedef std::list ListAsciiStringUINT; typedef ListAsciiStringUINT::iterator ListAsciiStringUINTIt; typedef std::map< const ThingTemplate *, Int, std::less > AttackPriorityMap; typedef std::pair AsciiStringObjectIDPair; typedef std::list ListAsciiStringObjectID; typedef std::list::iterator ListAsciiStringObjectIDIt; typedef std::pair AsciiStringCoord3DPair; typedef std::list ListAsciiStringCoord3D; typedef ListAsciiStringCoord3D::iterator ListAsciiStringCoord3DIt; typedef std::map< AsciiString, Int > ObjectTypeCount; typedef std::vector VectorPlayerPtr; typedef VectorPlayerPtr::iterator VectorPlayerPtrIt; typedef std::vector AllObjectTypes; typedef AllObjectTypes::iterator AllObjectTypesIt; typedef std::vector VecNamedReveal; typedef VecNamedReveal::iterator VecNamedRevealIt; class AttackPriorityInfo : public MemoryPoolObject, public Snapshot { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(AttackPriorityInfo, "AttackPriorityInfo") // friend bad for MPOs. (srj) //friend class ScriptEngine; public: AttackPriorityInfo(); //~AttackPriorityInfo(); public: void setPriority(const ThingTemplate *tThing, Int priority); Int getPriority(const ThingTemplate *tThing) const; AsciiString getName(void) const {return m_name;} #ifdef _DEBUG void dumpPriorityInfo(void); #endif void friend_setName(const AsciiString& n) { m_name = n; } void friend_setDefaultPriority(Int n) { m_defaultPriority = n; } void reset(void); protected: // sanapshot methods virtual void crc( Xfer *xfer ); virtual void xfer( Xfer *xfer ); virtual void loadPostProcess( void ); AsciiString m_name; Int m_defaultPriority; AttackPriorityMap *m_priorityMap; }; class SequentialScript : public MemoryPoolObject, public Snapshot { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SequentialScript, "SequentialScript") public: enum { START_INSTRUCTION = -1 }; Team *m_teamToExecOn; ObjectID m_objectID; Script *m_scriptToExecuteSequentially; Int m_currentInstruction; // Which action within m_scriptToExecuteSequentially am I currently executing? Int m_timesToLoop; // 0 = do once, >0, loop till 0, <0, loop infinitely Int m_framesToWait; // 0 = transition to next instruction, >0 = countdown to 0, <0 = advance on idle only Bool m_dontAdvanceInstruction; // Must be set every frame by the instruction requesting the wait. // so this parm tells us how many we've been idle so far. SequentialScript *m_nextScriptInSequence; SequentialScript(); protected: // snapshot methods virtual void crc( Xfer *xfer ); virtual void xfer( Xfer *xfer ); virtual void loadPostProcess( void ); }; EMPTY_DTOR(SequentialScript) #ifdef NOT_IN_USE class SequentialScriptStatus : public MemoryPoolObject, public Snapshot { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SequentialScriptStatus, "SequentialScriptStatus") public: ObjectID m_objectID; AsciiString m_sequentialScriptCompleted; Bool m_isExecutingSequentially; protected: // snapshot methods virtual void crc( Xfer *xfer ); virtual void xfer( Xfer *xfer ); virtual void loadPostProcess( void ); }; #endif //----------------------------------------------------------------------------- // ScriptEngine //----------------------------------------------------------------------------- /** Implementation for the Script Engine singleton */ //----------------------------------------------------------------------------- class ScriptEngine : public SubsystemInterface, public Snapshot { public: enum {MAX_COUNTERS=256, MAX_FLAGS=256, MAX_ATTACK_PRIORITIES=256}; enum TFade {FADE_NONE, FADE_SUBTRACT, FADE_ADD, FADE_SATURATE, FADE_MULTIPLY}; ScriptEngine(); virtual ~ScriptEngine(); virtual void init( void ); ///< Init virtual void reset( void ); ///< Reset virtual void update( void ); ///< Update void appendSequentialScript(const SequentialScript *scriptToSequence); void removeSequentialScript(SequentialScript *scriptToRemove); void notifyOfTeamDestruction(Team *teamDestroyed); void notifyOfObjectCreationOrDestruction(void); UnsignedInt getFrameObjectCountChanged(void) {return m_frameObjectCountChanged;} void setSequentialTimer(Object *obj, Int frameCount); void setSequentialTimer(Team *team, Int frameCount); void removeAllSequentialScripts(Object *obj); void removeAllSequentialScripts(Team *team); AsciiString getStats(Real *curTime, Real *script1Time, Real *script2Time); virtual void newMap( ); ///< reset script engine for new map virtual const ActionTemplate *getActionTemplate( Int ndx); ///< Get the template for a script action. virtual const ConditionTemplate *getConditionTemplate( Int ndx); ///< Get the template for a script Condition. virtual void startEndGameTimer(void); ///< Starts the end game timer after a mission is won or lost. Bool isGameEnding( void ) { return m_endGameTimer >= 0; } virtual void startQuickEndGameTimer(void); ///< Starts the quick end game timer after a campaign is won or lost. virtual void startCloseWindowTimer(void); ///< Starts the timer to close windows after a mission is won or lost. virtual void runScript(const AsciiString& scriptName, Team *pThisTeam=NULL); ///< Runs a script. virtual void runObjectScript(const AsciiString& scriptName, Object *pThisObject=NULL); ///< Runs a script attached to this object. virtual Team *getTeamNamed(const AsciiString& teamName); ///< Gets the named team. May be null. virtual Player *getSkirmishEnemyPlayer(void); ///< Gets the ai's enemy Human player. May be null. virtual Player *getCurrentPlayer(void); ///< Gets the player that owns the current script. May be null. virtual Player *getPlayerFromAsciiString(const AsciiString& skirmishPlayerString); void setObjectsShouldReceiveDifficultyBonus(Bool receive) { m_objectsShouldReceiveDifficultyBonus = receive; } Bool getObjectsShouldReceiveDifficultyBonus() const { return m_objectsShouldReceiveDifficultyBonus; } void setChooseVictimAlwaysUsesNormal(Bool receive) { m_ChooseVictimAlwaysUsesNormal = receive; } Bool getChooseVictimAlwaysUsesNormal() const { return m_ChooseVictimAlwaysUsesNormal; } Bool hasShownMPLocalDefeatWindow(void); void markMPLocalDefeatWindowShown(void); // NOTE NOTE NOTE: do not store of the return value of this call (getObjectTypeList) beyond the life of the // function it will be used in, as it can be deleted from under you if maintenance is performed on the object. virtual ObjectTypes *getObjectTypes(const AsciiString& objectTypeList); virtual void doObjectTypeListMaintenance(const AsciiString& objectTypeList, const AsciiString& objectType, Bool addObject); /// Return the trigger area with the given name virtual PolygonTrigger *getQualifiedTriggerAreaByName( AsciiString name ); // For other systems to evaluate Conditions, execute Actions, etc. ///< if pThisTeam is specified, then scripts in here can use to mean the team this script is attached to. virtual Bool evaluateConditions( Script *pScript, Team *pThisTeam = NULL, Player *pPlayer=NULL ); virtual void friend_executeAction( ScriptAction *pActionHead, Team *pThisTeam = NULL); ///< Use this at yer peril. virtual Object *getUnitNamed(const AsciiString& unitName); ///< Gets the named unit. May be null. virtual Bool didUnitExist(const AsciiString& unitName); virtual void addObjectToCache( Object* pNewObject ); virtual void removeObjectFromCache( Object* pDeadObject ); virtual void transferObjectName( const AsciiString& unitName, Object *pNewObject ); virtual void notifyOfObjectDestruction( Object *pDeadObject ); virtual void notifyOfCompletedVideo( const AsciiString& completedVideo ); ///< Notify the script engine that a video has completed virtual void notifyOfTriggeredSpecialPower( Int playerIndex, const AsciiString& completedPower, ObjectID sourceObj ); virtual void notifyOfMidwaySpecialPower ( Int playerIndex, const AsciiString& completedPower, ObjectID sourceObj ); virtual void notifyOfCompletedSpecialPower( Int playerIndex, const AsciiString& completedPower, ObjectID sourceObj ); virtual void notifyOfCompletedUpgrade ( Int playerIndex, const AsciiString& upgrade, ObjectID sourceObj ); virtual void notifyOfAcquiredScience ( Int playerIndex, ScienceType science ); virtual void signalUIInteract(const AsciiString& hookName); ///< Notify that a UI button was pressed and some flag should go true, for one frame only. virtual Bool isVideoComplete( const AsciiString& completedVideo, Bool removeFromList ); ///< Determine whether a video has completed virtual Bool isSpeechComplete( const AsciiString& completedSpeech, Bool removeFromList ); ///< Determine whether a speech has completed virtual Bool isAudioComplete( const AsciiString& completedAudio, Bool removeFromList ); ///< Determine whether a sound has completed virtual Bool isSpecialPowerTriggered( Int playerIndex, const AsciiString& completedPower, Bool removeFromList, ObjectID sourceObj ); virtual Bool isSpecialPowerMidway ( Int playerIndex, const AsciiString& completedPower, Bool removeFromList, ObjectID sourceObj ); virtual Bool isSpecialPowerComplete ( Int playerIndex, const AsciiString& completedPower, Bool removeFromList, ObjectID sourceObj ); virtual Bool isUpgradeComplete ( Int playerIndex, const AsciiString& upgrade, Bool removeFromList, ObjectID sourceObj ); virtual Bool isScienceAcquired ( Int playerIndex, ScienceType science, Bool removeFromList ); void setToppleDirection( const AsciiString& objectName, const Coord3D *direction ); virtual void adjustToppleDirection( Object *object, Coord2D *direction); virtual void adjustToppleDirection( Object *object, Coord3D *direction); virtual const Script *findScriptByName(const AsciiString& scriptName) {return findScript(scriptName);} ///< Finds a script. const BreezeInfo& getBreezeInfo() const {return m_breezeInfo;} Bool isTimeFrozenScript( void ); ///< Ask whether a script has frozen time or not void doFreezeTime( void ); void doUnfreezeTime( void ); /// The following functions are used to update and query the debug window Bool isTimeFrozenDebug( void ); ///< Ask whether the debug window has requested a pause. Bool isTimeFast( void ); ///< Ask whether the debug window has requested a fast forward. void forceUnfreezeTime( void ); ///< Force that time becomes unfrozen temporarily. void AppendDebugMessage(const AsciiString& strToAdd, Bool forcePause); void AdjustDebugVariableData(const AsciiString& variableName, Int value, Bool forcePause); void clearTeamFlags(void); ///< Hack for dustin. void clearFlag(const AsciiString &name); ///< Hack for dustin. TFade getFade(void) {return m_fade;} Real getFadeValue(void) {return m_curFadeValue;} AsciiString getCurrentTrackName() const { return m_currentTrackName; } void setCurrentTrackName(AsciiString a) { m_currentTrackName = a; } GameDifficulty getGlobalDifficulty( void ) const { return m_gameDifficulty; } void setGlobalDifficulty( GameDifficulty difficulty ); /// Attack priority stuff. const AttackPriorityInfo *getDefaultAttackInfo(void); const AttackPriorityInfo *getAttackInfo(const AsciiString& name); const TCounter *getCounter(const AsciiString& counterName); void createNamedMapReveal(const AsciiString& revealName, const AsciiString& waypointName, Real radiusToReveal, const AsciiString& playerName); void doNamedMapReveal(const AsciiString& revealName); void undoNamedMapReveal(const AsciiString& revealName); void removeNamedMapReveal(const AsciiString& revealName); Int getObjectCount(Int playerIndex, const AsciiString& objectTypeName) const; void setObjectCount(Int playerIndex, const AsciiString& objectTypeName, Int newCount); //Kris: Moved to public... so that I can refresh it when building abilities in script dialogs. void createNamedCache( void ); ///Begin VTUNE void setEnableVTune(Bool value); Bool getEnableVTune() const; ///End VTUNE //#if defined(_DEBUG) || defined(_INTERNAL) void debugVictory( void ); //#endif protected: // snapshot methods virtual void crc( Xfer *xfer ); virtual void xfer( Xfer *xfer ); virtual void loadPostProcess( void ); Int allocateCounter( const AsciiString& name); Int allocateFlag( const AsciiString& name); void executeScripts( Script *pScriptHead ); void executeScript( Script *pScript ); Script *findScript(const AsciiString& name); ScriptGroup *findGroup(const AsciiString& name); void setSway( ScriptAction *pAction ); void setCounter( ScriptAction *pAction ); void addCounter( ScriptAction *pAction ); void subCounter( ScriptAction *pAction ); void setFade( ScriptAction *pAction ); void setFlag( ScriptAction *pAction ); void pauseTimer( ScriptAction *pAction ); void restartTimer( ScriptAction *pAction ); void setTimer( ScriptAction *pAction, Bool milisecondTimer, Bool random); void adjustTimer( ScriptAction *pAction, Bool milisecondTimer, Bool add); void enableScript( ScriptAction *pAction ); void disableScript( ScriptAction *pAction ); void callSubroutine( ScriptAction *pAction ); void checkConditionsForTeamNames(Script *pScript); Bool evaluateCounter( Condition *pCondition ); Bool evaluateFlag( Condition *pCondition ); Bool evaluateTimer( Condition *pCondition ); Bool evaluateCondition( Condition *pCondition ); void executeActions( ScriptAction *pActionHead ); void setPriorityThing( ScriptAction *pAction ); void setPriorityKind( ScriptAction *pAction ); void setPriorityDefault( ScriptAction *pAction ); // For Object types maintenance. void removeObjectTypes(ObjectTypes *typesToRemove); void particleEditorUpdate( void ); void updateFades( void ); AttackPriorityInfo *findAttackInfo(const AsciiString& name, Bool addIfNotFound); protected: /// Stuff to execute scripts sequentially typedef std::vector VecSequentialScriptPtr; typedef VecSequentialScriptPtr::iterator VecSequentialScriptPtrIt; VecSequentialScriptPtr m_sequentialScripts; void evaluateAndProgressAllSequentialScripts( void ); VecSequentialScriptPtrIt cleanupSequentialScript(VecSequentialScriptPtrIt it, Bool cleanDanglers); Bool hasUnitCompletedSequentialScript( Object *object, const AsciiString& sequentialScriptName ); Bool hasTeamCompletedSequentialScript( Team *team, const AsciiString& sequentialScriptName ); protected: ActionTemplate m_actionTemplates[ScriptAction::NUM_ITEMS]; ConditionTemplate m_conditionTemplates[Condition::NUM_ITEMS]; TCounter m_counters[MAX_COUNTERS]; Int m_numCounters; TFlag m_flags[MAX_FLAGS]; Int m_numFlags; AttackPriorityInfo m_attackPriorityInfo[MAX_ATTACK_PRIORITIES]; Int m_numAttackInfo; Int m_endGameTimer; Int m_closeWindowTimer; Team *m_callingTeam; ///< Team that is calling script, used for THIS_TEAM Object *m_callingObject; ///< Object that is calling script, used for THIS_OBJECT Team *m_conditionTeam; ///< Team that is being used to evaluate conditions, used for THIS_TEAM Object *m_conditionObject; ///< Unit that is being used to evaluate conditions, used for THIS_OBJECT VecNamedRequests m_namedObjects; Bool m_firstUpdate; Player *m_currentPlayer; Player *m_skirmishHumanPlayer; AsciiString m_currentTrackName; TFade m_fade; Real m_minFade; Real m_maxFade; Real m_curFadeValue; Int m_curFadeFrame; Int m_fadeFramesIncrease; Int m_fadeFramesHold; Int m_fadeFramesDecrease; UnsignedInt m_frameObjectCountChanged; ObjectTypeCount m_objectCounts[MAX_PLAYER_COUNT]; /// These are three separate lists rather than one to increase speed efficiency ListAsciiString m_completedVideo; ListAsciiStringUINT m_testingSpeech; ListAsciiStringUINT m_testingAudio; ListAsciiString m_uiInteractions; ListAsciiStringObjectID m_triggeredSpecialPowers[MAX_PLAYER_COUNT]; ListAsciiStringObjectID m_midwaySpecialPowers [MAX_PLAYER_COUNT]; ListAsciiStringObjectID m_finishedSpecialPowers [MAX_PLAYER_COUNT]; ListAsciiStringObjectID m_completedUpgrades [MAX_PLAYER_COUNT]; ScienceVec m_acquiredSciences [MAX_PLAYER_COUNT]; ListAsciiStringCoord3D m_toppleDirections; VecNamedReveal m_namedReveals; BreezeInfo m_breezeInfo; GameDifficulty m_gameDifficulty; Bool m_freezeByScript; AllObjectTypes m_allObjectTypeLists; Bool m_objectsShouldReceiveDifficultyBonus; Bool m_ChooseVictimAlwaysUsesNormal; Bool m_shownMPLocalDefeatWindow; #ifdef SPECIAL_SCRIPT_PROFILING #ifdef DEBUG_LOGGING double m_numFrames; double m_totalUpdateTime; double m_maxUpdateTime; double m_curUpdateTime; #endif #endif }; // end class ScriptEngine extern ScriptEngine *TheScriptEngine; ///< singleton definition #endif // end __SCRIPTENGINE_H_