Files
GTASource/game/Vehicles/cargen.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

500 lines
17 KiB
C++

/****************************************
* cargen.h *
* ---------- *
* *
* declarations for *
* car generator control for coop *
* *
* GSW 07/06/00 *
* *
* (c)2000 Rockstar North *
****************************************/
#ifndef CARGEN_H
#define CARGEN_H
#include "atl/queue.h"
#include "atl/pool.h"
#include "modelInfo/vehicleModelInfo.h"
#include "physics/WorldProbe/worldprobe.h"
#include "task/Scenario/ScenarioChaining.h"
#include "vector/vector3.h"
//#define INFINITE_CAR_GENERATE (0xffff)
#define MAX_CAR_GENERATORS_CREATED_BY_SCRIPT (80)
#define STORE_CARGEN_PLACEMENT_FILE __DEV
#define MAX_SCHEDULED_CARS_AT_ONCE (32) // can only have this many vehicles pending spawn at once
enum {
CREATION_RULE_ALL = 0,
CREATION_RULE_ONLY_SPORTS,
CREATION_RULE_NO_SPORTS,
CREATION_RULE_ONLY_BIG,
CREATION_RULE_NO_BIG,
CREATION_RULE_ONLY_BIKES,
CREATION_RULE_NO_BIKES,
CREATION_RULE_ONLY_DELIVERY,
CREATION_RULE_NO_DELIVERY,
CREATION_RULE_BOATS,
CREATION_RULE_ONLY_POOR,
CREATION_RULE_NO_POOR,
CREATION_RULE_CAN_BE_BROKEN_DOWN // Only cars that are valid for broken down car scenario
};
enum {
CARGEN_SCENARIO_NONE = 0xff,
};
enum {
CARGEN_FORCESPAWN = BIT(0),
CARGEN_IGNORE_DENSITY = BIT(1),
CARGEN_POLICE = BIT(2),
CARGEN_FIRETRUCK = BIT(3),
CARGEN_AMBULANCE = BIT(4),
CARGEN_DURING_DAY = BIT(5),
CARGEN_AT_NIGHT = BIT(6),
CARGEN_ALIGN_LEFT = BIT(7),
CARGEN_ALIGN_RIGHT = BIT(8),
CARGEN_SINGLE_PLAYER = BIT(9),
CARGEN_NETWORK_PLAYER = BIT(10),
CARGEN_LOWPRIORITY = BIT(11),
CARGEN_PREVENT_ENTRY = BIT(12)
};
struct CargenPriorityAreas
{
struct Area
{
Vector3 minPos;
Vector3 maxPos;
PAR_SIMPLE_PARSABLE;
};
atArray<Area> areas;
PAR_SIMPLE_PARSABLE;
};
typedef struct
{
s32 nCarIndex;
char szNumPlate[CUSTOM_PLATE_NUM_CHARS+1]; // the text itself
} TSpecialPlate;
class CCarGenerator;
struct ScheduledVehicle
{
ScheduledVehicle() : carGen(NULL), asyncHandle((u32)-1), vehicle(NULL), pDestInteriorProxy(NULL), chainUser(NULL), forceSpawn(false), needsStaticBoundsStreamingTest(true), valid(false), addToGameWorld(true) {}
~ScheduledVehicle() { Invalidate(); }
void Invalidate();
Matrix34 creationMatrix;
fwModelId carModelId;
fwModelId trailerModelId;
CCarGenerator* carGen;
WorldProbe::CShapeTestSingleResult collisionTestResult;
u32 asyncHandle;
RegdVeh vehicle;
CInteriorProxy* pDestInteriorProxy;
s32 destRoomIdx;
CScenarioPointChainUseInfoPtr chainUser;
bool allowedToSwitchOffCarGenIfSomethingOnTop;
bool isAsync;
bool preventEntryIfNotQualified;
bool forceSpawn;
bool needsStaticBoundsStreamingTest;
bool valid;
bool addToGameWorld; // If false, keep the vehicle hidden, the user will need to add to the game world and fade in.
};
class CSpecialPlateHandler
{
public:
enum { MAX_SPECIAL_PLATES=15 };
void Init();
void Add(s32 nCarIndex, char* szNumPlate);
s32 Find(s32 nIndex, char* str);
bool IsFull() { return (m_nSpecialPlates == MAX_SPECIAL_PLATES); }
bool IsEmpty() { return (m_nSpecialPlates == 0); }
void Remove(s32 nIndex);
//protected:
//private:
TSpecialPlate m_aSpecialPlates[MAX_SPECIAL_PLATES];
s32 m_nSpecialPlates;
};
//static CSpecialPlateHandler g_SpecialPlateHandler;
class CTheCarGenerators;
class CPlayerInfo;
class CCarGenerator
{
friend class CTheCarGenerators;
public :
enum {
INFINITE_CAR_GENERATE = 101
};
CCarGenerator() : m_bScheduled(false), m_bTempHighPrio(false), m_bPreAssignedModel(false), m_bIgnoreTooClose(false), m_bSkipStaticBoundsTest(false) {}
void Setup( const float centreX, const float centreY, const float centreZ,
const float vec1X, const float vec1Y,
const float lengthVec2,
const u32 visible_model_hash_key,
const s32 remap1_for_car, const s32 remap2_for_car, const s32 remap3_for_car, const s32 remap4_for_car, const s32 remap5_for_car, const s32 remap6_for_car,
u32 flags,
const u32 ipl,
const u32 creationRule, const u32 scenario, const bool bOwnedByScript,
atHashString popGroup, s8 livery, s8 livery2, bool unlocked, bool canBeStolen);
void SwitchOff(void);
void SwitchOn(void);
bool IsSwitchedOff(void) const;
void GenerateMultipleVehs(u32 number_of_cars_to_generate) { SwitchOn(); GenerateCount = (u8)(MIN((u8)number_of_cars_to_generate, INFINITE_CAR_GENERATE)); }
void BuildCreationMatrix(Matrix34 *pCreationMatrix, u32 MI) const;
bool PlaceOnRoadProperly(CVehicle* pVehicle, Matrix34 *pCreationMatrix, CInteriorInst*& pDestInteriorInst, s32& destRoomIdx, u32& asyncHandle, bool forceSynchronous);
bool Process(bool bWakeUpScenarioPoints=false);
void InstantProcess();
bool CheckIfReadyForSchedule(bool bIgnorePopulation, bool& carModelShouldBeRequested, fwModelId& carToUse, fwModelId& trailerToUse);
bool ScheduleVehsForGenerationIfInRange(bool bIgnorePopulation, bool bVeryClose, bool& bCarModelPicked);
//////////////////////////////////////////////////////////////////////////
// Functions that used by ScheduleVehsForGenerationIfInRange to schedule a cargen attempt
ScheduledVehicle* InsertVehForGen(const fwModelId& carToUse, const fwModelId& trailerToUse, const Matrix34& CreationMatrix, const bool bAllowedToSwitchOffCarGenIfSomethingOnTop, const bool forceSpawn = false);
bool DoSyncProbeForBlockingObjects(const fwModelId &carToUse, const Matrix34& creationMatrix, const CVehicle* excludeVeh);
bool CheckHasSpaceToSchedule();
bool CheckNetworkObjectLimits(const fwModelId &carToUse);
bool CheckScenarioConditionsA();
bool CheckScenarioConditionsB(const fwModelId& carToUse, const fwModelId& trailerToUse);
bool PickValidModels(fwModelId& car_Out, fwModelId& trailer_Out, bool& carModelShouldBeRequested_Out);
bool CheckIsActiveForGen();
bool CheckPopulationHasSpace();
//////////////////////////////////////////////////////////////////////////
bool GetCarGenCullRange(float &fOutRange, bool bUseReducedNetworkScopeDist) const;
bool CheckIfWithinRangeOfAnyPlayers(bool &bTooClose, bool bUseReducedNetworkScopeDist = false);
void SetPlayerHasAlreadyOwnedCar(bool bSet) { m_bPlayerHasAlreadyOwnedCar = bSet; }
bool IsUsed(u16 ipl) const;
bool IsUsed() const;
void SwitchOffIfWithinSwitchArea();
float GetGenerationRange() const;
int GetScenarioType() const { Assert(IsScenarioCarGen()); return m_Scenario; }
bool IsScenarioCarGen() const { return m_Scenario != CARGEN_SCENARIO_NONE; }
// Check if this is a special kind of cargen allowed to place on the ground without collision being loaded.
bool IsDistantGroundScenarioCarGen() const;
bool HasPreassignedModel() const { return m_bPreAssignedModel; }
bool IsOwnedByScript() const { return m_bOwnedByScript; }
bool IsOwnedByMapData() const { return !IsScenarioCarGen() && !IsOwnedByScript(); }
int GetIpl() const { return m_ipl; }
u32 GetVisibleModel() const { return VisibleModel; }
bool IsExtendedRange() const { return m_bExtendedRange; }
bool IsHighPri() const { return m_bHighPriority; }
bool IsScheduled()const { return m_bScheduled; }
bool IsLowPrio() const { return m_bLowPriority; }
Vec3V_Out GetCentre() const { return Vec3V(m_centreX, m_centreY, m_centreZ); }
u32 PickSuitableCar(fwModelId& trailer) const;
s8 GetLivery() const { return m_livery; }
s8 GetLivery2() const { return m_livery2; }
#if __BANK
void RegisterSpawnFailure(int/*FailureType*/ failureType) const;
#endif
private:
#if !__FINAL
void DebugRender(bool forVectorMap);
static const char * GetCreationRuleDesc(int i);
#endif
float m_centreX, m_centreY, m_centreZ;
float m_vec1X, m_vec1Y;
float m_vec2X, m_vec2Y;
atHashString m_popGroup;
u32 VisibleModel;
RegdVeh m_pLatestCar;
u16 m_ipl;
u8 car_remap1, car_remap2, car_remap3, car_remap4, car_remap5, car_remap6;
u8 m_CreationRule : 4;
u16 m_Scenario : 9;
u8 m_bStoredVisibleModel : 1;
u8 m_bReadyToGenerateCar : 1;
u8 m_bHighPriority : 1;
u8 m_bPlayerHasAlreadyOwnedCar : 1;
u8 m_bCarCreatedBefore : 1;
u8 m_bScheduled : 1; // Set if inserted in m_scheduledVehicles.
u8 m_bDestroyAfterSchedule : 1; // Set if the cargen should be removed, but was scheduled - will be destroyed later
u8 m_bReservedForPoliceCar : 1;
u8 m_bReservedForFiretruck : 1;
u8 m_bReservedForAmbulance : 1;
u8 m_bActiveDuringDay : 1;
u8 m_bActiveAtNight : 1;
u8 m_bAlignedToLeft : 1;
u8 m_bAlignedToRight : 1;
u8 m_bOwnedByScript : 1;
u8 m_bExtendedRange : 1;
u8 m_bPreventEntryIfNotQualified:1;
u8 m_bTempHighPrio : 1; // was temporarily set as high prio for being in an area of interest
u8 m_bPreAssignedModel : 1;
u8 m_bIgnoreTooClose : 1;
u8 m_bHasGeneratedACar : 1;
u8 m_bCreateCarUnlocked : 1;
u8 m_bCanBeStolen : 1;
u8 m_bInPrioArea : 1;
u8 m_bLowPriority : 1;
u8 m_bSkipStaticBoundsTest : 1;
u8 GenerateCount;
s8 m_livery;
s8 m_livery2;
#if __BANK
enum
{
FC_NONE,
FC_SCHEDULED,
FC_NO_VALID_MODEL,
FC_CARGEN_RESTRICTIVE_CHECKS_FAILED,
FC_CARGEN_PROBE_FAILED,
FC_CARGEN_PROBE_2_FAILED,
FC_PLACE_ON_ROAD_FAILED,
FC_CARGEN_VEH_STREAMED_OUT,
FC_CARGEN_FACTORY_FAIL,
FC_CARGEN_PROBE_SCHEDULE_FAILED,
FC_VEHICLE_REMOVED,
FC_SCENARIO_POP_FAILED,
FC_COLLISIONS_NOT_LOADED,
FC_NOT_ACTIVE_DURING_DAY,
FC_NOT_ACTIVE_DURING_NIGHT,
FC_SCRIPT_DISABLED,
FC_TOO_MANY_CARS,
FC_TOO_MANY_PARKED_CARS,
FC_TOO_MANY_LOWPRIO_PARKED_CARS,
FC_REJECTED_BY_SCENARIO,
FC_IDENTICAL_MODEL_CLOSE,
FC_NOT_IN_RANGE,
FC_TOO_CLOSE_AT_GEN_TIME,
FC_DONT_SPAWN_COPS,
FC_CANT_REQUEST_NEW_MODEL,
FC_CARGEN_BLOCKED_SCENARIO_CHAIN,
FC_CARGEN_NOT_ALLOWED_IN_MP,
FC_CARGEN_DESTROYED,
FC_CARGEN_LOW_LOCAL_POP_LIMIT
};
u8 m_failCode;
Vector3 m_failPos;
RegdEnt m_hitEntities[4];
float m_hitPosZ[5];
u32 placementFail;
void RemoveRegdEntities() // Clear out m_hitEntities so that we don't try to reference this car generator anymore
{
m_hitEntities[0] = NULL;
m_hitEntities[1] = NULL;
m_hitEntities[2] = NULL;
m_hitEntities[3] = NULL;
}
#endif // __BANK
// Whether range checks should be performed in 2 or 3 dimensions (typically aerial vehicles want three dimensional checks).
bool ShouldCheckRangesIn3D() const;
bool CheckIfWithinRangeOfPlayer(CPlayerInfo* pPlayer, float range);
// Helper function to determine if this point is within range distance of all players.
bool CheckIfOutsideRangeOfAllPlayers(float fRange);
float GetCreationDistanceOnScreen() const;
float GetCreationDistanceOffScreen() const;
#if STORE_CARGEN_PLACEMENT_FILE
#define CARGEN_DEV_FILENAME_LENGTH (16)
char m_placedFrom[CARGEN_DEV_FILENAME_LENGTH];
#endif
};
// This stuff deals with car generators being switched off.
#define MAX_NUM_CAR_GENERATOR_SWITCHES (128)
// class car_generator_container_class
class CTheCarGenerators
{
public:
static void Init();
static atIteratablePool<CCarGenerator> CarGeneratorPool;
static u16* ms_CarGeneratorIPLs;
static s32 NumOfCarGenerators;
static bool NoGenerate;
static bool bScriptDisabledCarGenerators;
static bool bScriptDisabledCarGeneratorsWithHeli;
static bool bScriptForcingAllCarsLockedThisFrame;
static s32 m_iTryToWakeUpScenarioPoints;
static s32 m_iTryToWakeUpPriorityAreaScenarioPoints;
static Vector3 m_CarGenSwitchedOffMin[MAX_NUM_CAR_GENERATOR_SWITCHES];
static Vector3 m_CarGenSwitchedOffMax[MAX_NUM_CAR_GENERATOR_SWITCHES];
static Vector3 m_CarGenAreaOfInterestPosition;
static float m_CarGenAreaOfInterestRadius;
static float m_CarGenAreaOfInterestPercentage;
static float m_CarGenScriptLockedPercentage;
static u32 m_ActivationTime;
static dev_u32 m_TimeBetweenScenarioActivationBoosts;
static dev_float m_MinDistanceToPlayerForScenarioActivation;
static dev_float m_MinDistanceToPlayerForHighPriorityScenarioActivation;
static s32 m_numCarGenSwitches;
static u32 m_NumScheduledVehicles;
static u16 m_scheduledVehiclesNextIndex;
static atFixedArray<ScheduledVehicle, MAX_SCHEDULED_CARS_AT_ONCE> m_scheduledVehicles;
public :
#if !__FINAL
static bool gs_bDisplayCarGenerators;
static bool gs_bDisplayCarGeneratorsOnVMap;
static bool gs_bDisplayCarGeneratorsScenariosOnly;
static bool gs_bDisplayCarGeneratorsPreassignedOnly;
static float gs_fDisplayCarGeneratorsDebugRange;
static bool gs_bDisplayAreaOfInterest;
#endif
#if __BANK
static float gs_fForceSpawnCarRadius;
static bool gs_bCheckPhysicProbeWhenForceSpawn;
#endif // __BANK
// static u8 divider;
static void InitLevelWithMapLoaded(void);
static void InitLevelWithMapUnloaded(void);
static CCarGenerator *GetCarGenerator(s32 Index) { return (CarGeneratorPool.GetSlot(Index)); }
static CCarGenerator *GetCarGeneratorSafe(int index)
{
return index < CarGeneratorPool.GetSize() ? GetCarGenerator(index) : NULL;
}
static int GetSize() { return (int)CarGeneratorPool.GetSize(); }
static int GetIndexForCarGenerator(const CCarGenerator* cargen) { return CarGeneratorPool.GetIndex((void*)cargen); }
static s32 CreateCarGenerator(const float centreX, const float centreY, const float centreZ,
const float vec1X, const float vec1Y,
const float lengthVec2,
const u32 VisModHashKey,
const s32 car_rmap1, const s32 car_rmap2, const s32 car_rmap3, const s32 car_rmap4, const s32 car_rmap5, const s32 car_rmap6,
u32 flags,
const u32 ipl, const bool CreatedByScript,
const u32 creationRule, const u32 scenario,
atHashString popGroup, s8 livery, s8 livery2, bool unlocked, bool canBeStolen);
static void DestroyCarGeneratorByIndex(s32 index, bool shouldBeScenarioCarGen);
static void TryToDestroyUnimportantCarGen();
static void RemoveCarGenerators(u32 ipl);
static void SetCarGeneratorsActiveInArea(const Vector3 &vecMin, const Vector3 &vecMax, bool bActive);
static void SetAllCarGeneratorsBackToActive();
static void CreateCarsOnGeneratorsInArea(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ, float Percentage, s32 maxNumCarsInArea);
static void RemoveCarsFromGeneratorsInArea(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ);
// static s32 HijackCarGenerator(Vector3 &Coors, s32 ModelIndex, u8 Remap1, u8 Remap2, u8 Remap3, u8 Remap4, float bestDist = 50.0f);
// static void HijackCarGenerator(s32 index, s32 ModelIndex, u8 Remap1, u8 Remap2, u8 Remap3, u8 Remap4);
static void ReleaseHijackedCarGenerator(s32 CarGenerator);
static void InteriorHasBeenPopulated(const spdAABB &bbox);
static bool ShouldGenerateVehicles();
static void Process(void);
static void ProcessAll(void);
// static void DoPostSetupPhase(void);
static bool GenerateScheduledVehiclesIfReady();
static bool PerformFinalReadyChecks( ScheduledVehicle &veh );
static bool GenerateScheduledVehicle( ScheduledVehicle &veh, bool ignoreLocalPopulationLimits );
static bool FinishScheduledVehicleCreation( ScheduledVehicle &veh, bool ignoreLocalPopulationLimits );
static bool PostCreationSetup(ScheduledVehicle& veh, bool ignoreLocalPopulationLimits);
static void AddToGameWorld(CVehicle& veh, CVehicle* pTrailer, const fwInteriorLocation& loc);
static bool IsClusteredScenarioCarGen( ScheduledVehicle &veh );
static CSpecialPlateHandler m_SpecialPlateHandler;
static void AddSpecialPlate(s32 carID, char* strPlate) { m_SpecialPlateHandler.Add(carID, strPlate); }
static void StopGenerating() { NoGenerate = true; }
static void StartGenerating() { NoGenerate = false; }
static bool ItIsDay();
static void ClearScheduledQueue();
static s32 GetNumQueuedVehs() { return m_NumScheduledVehicles; }
static CargenPriorityAreas* GetPrioAreas() { return ms_prioAreas; }
static atArray<u32>& GetPreassignedModels() { return ms_preassignedModels; }
static atArray<u32>& GetScenarioModels() { return ms_scenarioModels; }
static void VehicleHasBeenStreamedOut(u32 modelIndex);
static bool RequestVehicleModelForScenario(fwModelId modelId, bool highPri);
static void InstantFill();
#if !__FINAL
static void DebugRender();
static void DumpCargenInfo();
#endif
#if __BANK
static void InitWidgets(bkBank* bank);
static void ForceSpawnCarsWithinRadius();
#endif // __BANK
protected:
static void DropScheduledVehicle(ScheduledVehicle& veh, bool releaseChainUser = true);
static CargenPriorityAreas* ms_prioAreas;
static atArray<u32> ms_preassignedModels;
static atArray<u32> ms_scenarioModels;
// PURPOSE: This is the number of car generators that we more or less guarantee will
// can be available for vehicle scenarios. If we go beyond that, we will no
// longer allow removal of art-placed car generators.
static u16 m_MinAllowedScenarioCarGenerators;
// PURPOSE: The number of car generators currently in use for vehicle scenarios.
static u16 m_NumScenarioCarGenerators;
static u8 m_NumScriptGeneratedCarGenerators;
};
#endif