#pragma once #include "Automobile.h" #include "audio_enums.h" #include "Camera.h" #include "config.h" class CVehicle; class CCamera; enum eGarageState : int8 { GS_FULLYCLOSED, GS_OPENED, GS_CLOSING, GS_OPENING, GS_OPENEDCONTAINSCAR, GS_CLOSEDCONTAINSCAR, GS_AFTERDROPOFF, }; enum eGarageType : int8 { GARAGE_NONE, GARAGE_MISSION, GARAGE_BOMBSHOP1, GARAGE_BOMBSHOP2, GARAGE_BOMBSHOP3, GARAGE_RESPRAY, GARAGE_COLLECTORSITEMS, GARAGE_COLLECTSPECIFICCARS, GARAGE_COLLECTCARS_1, GARAGE_COLLECTCARS_2, GARAGE_COLLECTCARS_3, GARAGE_FORCARTOCOMEOUTOF, GARAGE_60SECONDS, GARAGE_CRUSHER, GARAGE_MISSION_KEEPCAR, GARAGE_FOR_SCRIPT_TO_OPEN, GARAGE_HIDEOUT_ONE, GARAGE_HIDEOUT_TWO, GARAGE_HIDEOUT_THREE, GARAGE_FOR_SCRIPT_TO_OPEN_AND_CLOSE, GARAGE_KEEPS_OPENING_FOR_SPECIFIC_CAR, GARAGE_MISSION_KEEPCAR_REMAINCLOSED, }; enum { TOTAL_COLLECTCARS_GARAGES = GARAGE_COLLECTCARS_3 - GARAGE_COLLECTCARS_1 + 1, TOTAL_COLLECTCARS_CARS = 16 }; class CStoredCar { int32 m_nModelIndex; CVector m_vecPos; CVector m_vecAngle; int32 m_bBulletproof : 1; int32 m_bFireproof : 1; int32 m_bExplosionproof : 1; int32 m_bCollisionproof : 1; int32 m_bMeleeproof : 1; int8 m_nPrimaryColor; int8 m_nSecondaryColor; int8 m_nRadioStation; int8 m_nVariationA; int8 m_nVariationB; int8 m_nCarBombType; public: void Init() { m_nModelIndex = 0; } void Clear() { m_nModelIndex = 0; } bool HasCar() { return m_nModelIndex != 0; } CStoredCar(const CStoredCar& other); void StoreCar(CVehicle*); CVehicle* RestoreCar(); }; static_assert(sizeof(CStoredCar) == 0x28, "CStoredCar"); #define SWITCH_GARAGE_DISTANCE_CLOSE 40.0f class CGarage { eGarageType m_eGarageType; eGarageState m_eGarageState; bool field_2; // unused bool m_bClosingWithoutTargetCar; bool m_bDeactivated; bool m_bResprayHappened; int m_nTargetModelIndex; CEntity *m_pDoor1; CEntity *m_pDoor2; uint8 m_bDoor1PoolIndex; uint8 m_bDoor2PoolIndex; bool m_bDoor1IsDummy; bool m_bDoor2IsDummy; bool m_bRecreateDoorOnNextRefresh; bool m_bRotatedDoor; bool m_bCameraFollowsPlayer; float m_fX1; float m_fX2; float m_fY1; float m_fY2; float m_fZ1; float m_fZ2; float m_fDoorPos; float m_fDoorHeight; float m_fDoor1X; float m_fDoor1Y; float m_fDoor2X; float m_fDoor2Y; float m_fDoor1Z; float m_fDoor2Z; uint32 m_nTimeToStartAction; uint8 m_bCollectedCarsState; CVehicle *m_pTarget; void* field_96; // unused CStoredCar m_sStoredCar; // not needed void OpenThisGarage(); void CloseThisGarage(); bool IsOpen() { return m_eGarageState == GS_OPENED || m_eGarageState == GS_OPENEDCONTAINSCAR; } bool IsClosed() { return m_eGarageState == GS_FULLYCLOSED; } bool IsUsed() { return m_eGarageType != GARAGE_NONE; } void Update(); float GetGarageCenterX() { return (m_fX1 + m_fX2) / 2; } float GetGarageCenterY() { return (m_fY1 + m_fY2) / 2; } bool IsFar() { #ifdef FIX_BUGS return Abs(TheCamera.GetPosition().x - GetGarageCenterX()) > SWITCH_GARAGE_DISTANCE_CLOSE || Abs(TheCamera.GetPosition().y - GetGarageCenterY()) > SWITCH_GARAGE_DISTANCE_CLOSE; #else return Abs(TheCamera.GetPosition().x - m_fX1) > SWITCH_GARAGE_DISTANCE_CLOSE || Abs(TheCamera.GetPosition().y - m_fY1) > SWITCH_GARAGE_DISTANCE_CLOSE; #endif } void TidyUpGarageClose(); void TidyUpGarage(); void RefreshDoorPointers(bool); void UpdateCrusherAngle(); void UpdateDoorsHeight(); bool IsEntityEntirelyInside3D(CEntity*, float); bool IsEntityEntirelyOutside(CEntity*, float); bool IsEntityEntirelyInside(CEntity*); float CalcDistToGarageRectangleSquared(float, float); float CalcSmallestDistToGarageDoorSquared(float, float); bool IsAnyOtherCarTouchingGarage(CVehicle* pException); bool IsStaticPlayerCarEntirelyInside(); bool IsPlayerOutsideGarage(); bool IsAnyCarBlockingDoor(); void CenterCarInGarage(CVehicle*); bool DoesCraigNeedThisCar(int32); bool MarkThisCarAsCollectedForCraig(int32); bool HasCraigCollectedThisCar(int32); bool IsGarageEmpty(); void UpdateCrusherShake(float, float); int32 CountCarsWithCenterPointWithinGarage(CEntity* pException); void RemoveCarsBlockingDoorNotInside(); void StoreAndRemoveCarsForThisHideout(CStoredCar*, int32); bool RestoreCarsForThisHideout(CStoredCar*); bool IsEntityTouching3D(CEntity*); bool EntityHasASphereWayOutsideGarage(CEntity*, float); bool IsAnyOtherPedTouchingGarage(CPed* pException); void BuildRotatedDoorMatrix(CEntity*, float); void FindDoorsEntities(); void FindDoorsEntitiesSectorList(CPtrList&, bool); void PlayerArrestedOrDied(); friend class CGarages; friend class cAudioManager; friend class CCamera; }; static_assert(sizeof(CGarage) == 140, "CGarage"); class CGarages { enum { MESSAGE_LENGTH = 8 }; static int32 &BankVansCollected; static bool &BombsAreFree; static bool &RespraysAreFree; static int32 &CarsCollected; static int32 (&CarTypesCollected)[TOTAL_COLLECTCARS_GARAGES]; static int32 &CrushedCarId; static uint32 &LastTimeHelpMessage; static int32 &MessageNumberInString; static char(&MessageIDString)[MESSAGE_LENGTH]; static int32 &MessageNumberInString2; static uint32 &MessageStartTime; static uint32 &MessageEndTime; static uint32 &NumGarages; static bool &PlayerInGarage; static int32 &PoliceCarsCollected; static uint32 &GarageToBeTidied; static CGarage(&aGarages)[NUM_GARAGES]; static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS]; static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS]; static CStoredCar(&aCarsInSafeHouse3)[NUM_GARAGE_STORED_CARS]; static int32 &AudioEntity; static bool &bCamShouldBeOutisde; public: static void Init(void); #ifndef PS2 static void Shutdown(void); #endif static void Update(void); static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId); static void ChangeGarageType(int16, eGarageType, int32); static void PrintMessages(void); static void TriggerMessage(const char* text, int16, uint16 time, int16); static void SetTargetCarForMissonGarage(int16, CVehicle*); static bool HasCarBeenDroppedOffYet(int16); static void DeActivateGarage(int16); static void ActivateGarage(int16); static int32 QueryCarsCollected(int16); static bool HasImportExportGarageCollectedThisCar(int16, int8); static bool IsGarageOpen(int16); static bool IsGarageClosed(int16); static bool HasThisCarBeenCollected(int16, uint8); static void OpenGarage(int16 garage) { aGarages[garage].OpenThisGarage(); } static void CloseGarage(int16 garage) { aGarages[garage].CloseThisGarage(); } static bool HasResprayHappened(int16); static void SetGarageDoorToRotate(int16); static void SetLeaveCameraForThisGarage(int16); static bool IsThisCarWithinGarageArea(int16, CEntity*); static bool HasCarBeenCrushed(int32); static bool IsPointInAGarageCameraZone(CVector); static bool CameraShouldBeOutside(void); static void GivePlayerDetonator(void); static void PlayerArrestedOrDied(void); static bool IsPointWithinHideOutGarage(CVector&); static bool IsPointWithinAnyGarage(CVector&); static void SetAllDoorsBackToOriginalHeight(void); static void Save(uint8* buf, uint32* size); static void Load(uint8* buf, uint32 size); static bool IsModelIndexADoor(uint32 id); static void SetFreeBombs(bool bValue) { BombsAreFree = bValue; } static void SetFreeResprays(bool bValue) { RespraysAreFree = bValue; } private: static bool IsCarSprayable(CVehicle*); static float FindDoorHeightForMI(int32); static void CloseHideOutGaragesBeforeSave(void); static int32 CountCarsInHideoutGarage(eGarageType); static int32 FindMaxNumStoredCarsForGarage(eGarageType); static int32 GetBombTypeForGarageType(eGarageType type) { return type - GARAGE_BOMBSHOP1 + 1; } static int32 GetCarsCollectedIndexForGarageType(eGarageType type) { return type - GARAGE_COLLECTCARS_1; } friend class cAudioManager; friend class CGarage; };