#pragma once #include "common.h" #include "Sprite2d.h" class CEntity; class CBuilding; class CVehicle; class CPed; class CObject; struct CScriptRectangle { int8 m_bIsUsed; bool m_bBeforeFade; int16 m_nTextureId; CRect m_sRect; CRGBA m_sColor; }; static_assert(sizeof(CScriptRectangle) == 0x18, "Script.h: error"); enum { SCRIPT_TEXT_MAX_LENGTH = 500 }; struct CTextLine { float m_fScaleX; float m_fScaleY; CRGBA m_sColor; bool m_bJustify; bool m_bCentered; bool m_bBackground; bool m_bBackgroundOnly; float m_fWrapX; float m_fCenterSize; CRGBA m_sBackgroundColor; bool m_bTextProportional; bool m_bTextBeforeFade; bool m_bRightJustify; int32 m_nFont; float m_fAtX; float m_fAtY; wchar m_Text[SCRIPT_TEXT_MAX_LENGTH]; void Reset(); }; static_assert(sizeof(CTextLine) == 0x414, "Script.h: error"); struct CScriptSphere { bool m_bInUse; uint16 m_Index; uint32 m_Id; CVector m_vecCenter; float m_fRadius; }; enum { MAX_STACK_DEPTH = 6, NUM_LOCAL_VARS = 16, NUM_TIMERS = 2 }; class CRunningScript { CRunningScript *next; CRunningScript *prev; char m_abScriptName[8]; uint32 m_nIp; uint32 m_anStack[MAX_STACK_DEPTH]; uint16 m_nStackPointer; int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS]; bool m_bCondResult; bool m_bIsMissionScript; bool m_bSkipWakeTime; uint32 m_nWakeTime; uint16 m_nAndOrState; bool m_bNotFlag; bool m_bWBCheckEnabled; bool m_bWBChecked; bool m_bMissionFlag; public: void SetIP(uint32 ip) { m_nIp = ip; } CRunningScript* GetNext() { return next; } void UpdateTimers(float timeStep){ m_anLocalVariables[NUM_LOCAL_VARS] += timeStep; m_anLocalVariables[NUM_LOCAL_VARS + 1] += timeStep; } void CollectParameters(uint32*, int16); int32 CollectNextParameterWithoutIncreasingPC(uint32); int32* GetPointerToScriptVariable(uint32*, int16); void StoreParameters(uint32*, int16); void Init(); void RemoveScriptFromList(CRunningScript**); void AddScriptToList(CRunningScript**); void Process(); int8 ProcessOneCommand(); void DoDeatharrestCheck(); int8 ProcessCommandsFrom0To99(int32); int8 ProcessCommandsFrom100To199(int32); int8 ProcessCommandsFrom200To299(int32); int8 ProcessCommandsFrom300To399(int32); int8 ProcessCommandsFrom400To499(int32); int8 ProcessCommandsFrom500To599(int32); int8 ProcessCommandsFrom600To699(int32); int8 ProcessCommandsFrom700To799(int32); int8 ProcessCommandsFrom800To899(int32); int8 ProcessCommandsFrom900To999(int32); int8 ProcessCommandsFrom1000To1099(int32); int8 ProcessCommandsFrom1100To1199(int32); void UpdateCompareFlag(bool); }; enum { CLEANUP_UNUSED = 0, CLEANUP_CAR, CLEANUP_CHAR, CLEANUP_OBJECT }; struct CMissionCleanupEntity { uint8 type; int32 id; }; enum { MAX_CLEANUP = 50, MAX_UPSIDEDOWN_CAR_CHECKS = 6, MAX_STUCK_CAR_CHECKS = 6 }; class CMissionCleanup { CMissionCleanupEntity m_sEntities[MAX_CLEANUP]; uint8 m_nCount; public: CMissionCleanup(); void Init(); CMissionCleanupEntity* FindFree(); void AddEntityToList(int32, uint8); void RemoveEntityFromList(int32, uint8); void Process(); }; struct CUpsideDownCarCheckEntry { int32 m_nVehicleIndex; uint32 m_nUpsideDownTimer; }; class CUpsideDownCarCheck { CUpsideDownCarCheckEntry m_sCars[MAX_UPSIDEDOWN_CAR_CHECKS]; public: void Init(); bool IsCarUpsideDown(int32); void UpdateTimers(); bool AreAnyCarsUpsideDown(); void AddCarToCheck(int32); void RemoveCarFromCheck(int32); bool HasCarBeenUpsideDownForAWhile(int32); }; struct CStuckCarCheckEntry { int32 m_nVehicleIndex; CVector m_vecPos; int32 m_nLastCheck; float m_fRadius; uint32 m_nStuckTime; bool m_bStuck; inline void Reset(); }; class CStuckCarCheck { CStuckCarCheckEntry m_sCars[MAX_STUCK_CAR_CHECKS]; public: void Init(); void Process(); void AddCarToCheck(int32, float, uint32); void RemoveCarFromCheck(int32); bool HasCarBeenStuckForAWhile(int32); }; enum { ARGUMENT_END = 0, ARGUMENT_INT32, ARGUMENT_GLOBALVAR, ARGUMENT_LOCALVAR, ARGUMENT_INT8, ARGUMENT_INT16, ARGUMENT_FLOAT }; struct tCollectiveData { int32 index; uint32 unk_data; }; enum { USED_OBJECT_NAME_LENGTH = 24 }; struct tUsedObject { char name[USED_OBJECT_NAME_LENGTH]; int32 index; }; struct tBuildingSwap { CBuilding* m_pBuilding; int32 m_nNewModel; int32 m_nOldModel; }; enum { VAR_LOCAL = 1, VAR_GLOBAL = 2, }; enum { SIZE_MAIN_SCRIPT = 128 * 1024, SIZE_MISSION_SCRIPT = 32 * 1024, SIZE_SCRIPT_SPACE = SIZE_MAIN_SCRIPT + SIZE_MISSION_SCRIPT }; enum { MAX_NUM_SCRIPTS = 128, MAX_NUM_CONTACTS = 16, MAX_NUM_INTRO_TEXT_LINES = 2, MAX_NUM_INTRO_RECTANGLES = 16, MAX_NUM_SCRIPT_SRPITES = 16, MAX_NUM_SCRIPT_SPHERES = 16, MAX_NUM_COLLECTIVES = 32, MAX_NUM_USED_OBJECTS = 200, MAX_NUM_MISSION_SCRIPTS = 120, MAX_NUM_BUILDING_SWAPS = 25, MAX_NUM_INVISIBILITY_SETTINGS = 20 }; class CTheScripts { public: static uint8(&ScriptSpace)[SIZE_SCRIPT_SPACE]; static CRunningScript(&ScriptsArray)[MAX_NUM_SCRIPTS]; static int32(&BaseBriefIdForContact)[MAX_NUM_CONTACTS]; static int32(&OnAMissionForContactFlag)[MAX_NUM_CONTACTS]; static CTextLine(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES]; static CScriptRectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES]; static CSprite2d(&ScriptSprites)[MAX_NUM_SCRIPT_SRPITES]; static CScriptSphere(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES]; static tCollectiveData(&CollectiveArray)[MAX_NUM_COLLECTIVES]; static tUsedObject(&UsedObjectArray)[MAX_NUM_USED_OBJECTS]; static int32(&MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS]; static tBuildingSwap(&BuildingSwapArray)[MAX_NUM_BUILDING_SWAPS]; static CEntity*(&InvisibilitySettingArray)[MAX_NUM_INVISIBILITY_SETTINGS]; static bool &DbgFlag; static uint32 &OnAMissionFlag; static CMissionCleanup &MissionCleanup; static CStuckCarCheck &StuckCars; static CUpsideDownCarCheck &UpsideDownCars; static int32 &StoreVehicleIndex; static bool &StoreVehicleWasRandom; static CRunningScript *&pIdleScripts; static CRunningScript *&pActiveScripts; static uint32 &NextFreeCollectiveIndex; static int32 &LastRandomPedId; static uint16 &NumberOfUsedObjects; static bool &bAlreadyRunningAMissionScript; static bool &bUsingAMultiScriptFile; static uint16 &NumberOfMissionScripts; static uint32 &LargestMissionScriptSize; static uint32 &MainScriptSize; static uint8 &FailCurrentMission; static uint8 &CountdownToMakePlayerUnsafe; static uint8 &DelayMakingPlayerUnsafeThisTime; static uint16 &NumScriptDebugLines; static uint16 &NumberOfIntroRectanglesThisFrame; static uint16 &NumberOfIntroTextLinesThisFrame; static bool &UseTextCommands; static uint16 &CommandsExecuted; static uint16 &ScriptsUpdated; public: static void ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, int col, int col2); static void CleanUpThisVehicle(CVehicle*); static void CleanUpThisPed(CPed*); static void CleanUpThisObject(CObject*); static void Init(); static CRunningScript* StartNewScript(uint32); static void Process(); static CRunningScript* StartTestScript(); static bool IsPlayerOnAMission(); static void ReadObjectNamesFromScript(); static void UpdateObjectIndices(); static void ReadMultiScriptFileOffsetsFromScript(); static void DrawScriptSpheres(); static void ClearSpaceForMissionEntity(const CVector&, CEntity*); static void HighlightImportantArea(uint32, float, float, float, float, float); static void DrawDebugSquare(float, float, float, float); static void DrawDebugCube(float, float, float, float, float, float); static int32 Read4BytesFromScript(uint32* pIp){ int32 retval = 0; for (int i = 0; i < 4; i++){ retval |= ScriptSpace[(*pIp)++] << (8 * i); } return retval; } static int16 Read2BytesFromScript(uint32* pIp){ int16 retval = 0; for (int i = 0; i < 2; i++){ retval |= ScriptSpace[(*pIp)++] << (8 * i); } return retval; } static int8 Read1ByteFromScript(uint32* pIp){ int8 retval = 0; for (int i = 0; i < 1; i++){ retval |= ScriptSpace[(*pIp)++] << (8 * i); } return retval; } static float ReadFloatFromScript(uint32* pIp){ return Read2BytesFromScript(pIp) / 16.0f; } };