Merge pull request #183 from Nick007J/master
CCarCtrl::GenerateOneRandomCar
This commit is contained in:
commit
1fa2fe566c
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
class CVehicle;
|
class CVehicle;
|
||||||
|
|
||||||
@ -62,15 +63,15 @@ public:
|
|||||||
uint32 m_nCurrentRouteNode;
|
uint32 m_nCurrentRouteNode;
|
||||||
uint32 m_nNextRouteNode;
|
uint32 m_nNextRouteNode;
|
||||||
uint32 m_nPrevRouteNode;
|
uint32 m_nPrevRouteNode;
|
||||||
uint32 m_nTotalSpeedScaleFactor;
|
uint32 m_nTimeEnteredCurve;
|
||||||
uint32 m_nSpeedScaleFactor;
|
uint32 m_nCurveSpeedScale;
|
||||||
uint32 m_nCurrentPathNodeInfo;
|
uint32 m_nCurrentPathNodeInfo;
|
||||||
uint32 m_nNextPathNodeInfo;
|
uint32 m_nNextPathNodeInfo;
|
||||||
uint32 m_nPreviousPathNodeInfo;
|
uint32 m_nPreviousPathNodeInfo;
|
||||||
uint32 m_nTimeToStartMission;
|
uint32 m_nTimeToStartMission;
|
||||||
uint32 m_nTimeSwitchedToRealPhysics;
|
uint32 m_nTimeSwitchedToRealPhysics;
|
||||||
int8 m_nPreviousDirection;
|
int8 m_nPreviousDirection;
|
||||||
int8 m_nCurrentDirecton;
|
int8 m_nCurrentDirection;
|
||||||
int8 m_nNextDirection;
|
int8 m_nNextDirection;
|
||||||
int8 m_nPreviousLane;
|
int8 m_nPreviousLane;
|
||||||
int8 m_nCurrentLane;
|
int8 m_nCurrentLane;
|
||||||
@ -94,13 +95,13 @@ public:
|
|||||||
m_nPrevRouteNode = 0;
|
m_nPrevRouteNode = 0;
|
||||||
m_nNextRouteNode = m_nPrevRouteNode;
|
m_nNextRouteNode = m_nPrevRouteNode;
|
||||||
m_nCurrentRouteNode = m_nNextRouteNode;
|
m_nCurrentRouteNode = m_nNextRouteNode;
|
||||||
m_nTotalSpeedScaleFactor = 0;
|
m_nTimeEnteredCurve = 0;
|
||||||
m_nSpeedScaleFactor = 1000;
|
m_nCurveSpeedScale = 1000;
|
||||||
m_nPreviousPathNodeInfo = 0;
|
m_nPreviousPathNodeInfo = 0;
|
||||||
m_nNextPathNodeInfo = m_nPreviousPathNodeInfo;
|
m_nNextPathNodeInfo = m_nPreviousPathNodeInfo;
|
||||||
m_nCurrentPathNodeInfo = m_nNextPathNodeInfo;
|
m_nCurrentPathNodeInfo = m_nNextPathNodeInfo;
|
||||||
m_nNextDirection = 1;
|
m_nNextDirection = 1;
|
||||||
m_nCurrentDirecton = m_nNextDirection;
|
m_nCurrentDirection = m_nNextDirection;
|
||||||
m_nPreviousLane = m_nCurrentLane = 0;
|
m_nPreviousLane = m_nCurrentLane = 0;
|
||||||
m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
|
m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
|
||||||
m_nCarMission = MISSION_NONE;
|
m_nCarMission = MISSION_NONE;
|
||||||
|
@ -4,3 +4,6 @@
|
|||||||
|
|
||||||
WRAPPER void CCarAI::UpdateCarAI(CVehicle*) { EAXJMP(0x413E50); }
|
WRAPPER void CCarAI::UpdateCarAI(CVehicle*) { EAXJMP(0x413E50); }
|
||||||
WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
|
WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
|
||||||
|
WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
|
||||||
|
WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
|
||||||
|
WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "AutoPilot.h"
|
||||||
|
|
||||||
class CVehicle;
|
class CVehicle;
|
||||||
|
|
||||||
class CCarAI
|
class CCarAI
|
||||||
@ -7,4 +9,7 @@ class CCarAI
|
|||||||
public:
|
public:
|
||||||
static void UpdateCarAI(CVehicle*);
|
static void UpdateCarAI(CVehicle*);
|
||||||
static void MakeWayForCarWithSiren(CVehicle *veh);
|
static void MakeWayForCarWithSiren(CVehicle *veh);
|
||||||
|
static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*);
|
||||||
|
static eCarMission FindPoliceCarMissionForWantedLevel();
|
||||||
|
static void AddPoliceOccupants(CVehicle*);
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,29 @@
|
|||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "CarCtrl.h"
|
#include "CarCtrl.h"
|
||||||
|
|
||||||
|
#include "Automobile.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "CarAI.h"
|
||||||
|
#include "CarGen.h"
|
||||||
|
#include "Curves.h"
|
||||||
|
#include "CutsceneMgr.h"
|
||||||
|
#include "General.h"
|
||||||
|
#include "IniFile.h"
|
||||||
|
#include "ModelIndices.h"
|
||||||
|
#include "PathFind.h"
|
||||||
|
#include "Ped.h"
|
||||||
|
#include "PlayerInfo.h"
|
||||||
|
#include "PlayerPed.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "Vehicle.h"
|
||||||
|
#include "Wanted.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Zones.h"
|
||||||
|
|
||||||
|
#define LANE_WIDTH 5.0f
|
||||||
|
#define INFINITE_Z 1000000000.0f
|
||||||
|
|
||||||
int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
|
int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
|
||||||
int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0;
|
int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0;
|
||||||
int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0;
|
int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0;
|
||||||
@ -10,6 +33,9 @@ float& CCarCtrl::CarDensityMultiplier = *(float*)0x5EC8B4;
|
|||||||
int32 &CCarCtrl::NumMissionCars = *(int32*)0x8F1B54;
|
int32 &CCarCtrl::NumMissionCars = *(int32*)0x8F1B54;
|
||||||
int32 &CCarCtrl::NumRandomCars = *(int32*)0x943118;
|
int32 &CCarCtrl::NumRandomCars = *(int32*)0x943118;
|
||||||
int32 &CCarCtrl::NumParkedCars = *(int32*)0x8F29E0;
|
int32 &CCarCtrl::NumParkedCars = *(int32*)0x8F29E0;
|
||||||
|
int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63;
|
||||||
|
int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
|
||||||
|
uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
|
||||||
|
|
||||||
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
|
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
|
||||||
WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); }
|
WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); }
|
||||||
@ -21,6 +47,470 @@ WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
|
|||||||
WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); }
|
WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); }
|
||||||
WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); }
|
WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); }
|
||||||
WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
|
WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
|
||||||
|
WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); }
|
||||||
|
WRAPPER int32 CCarCtrl::ChooseModel(CZoneInfo*, CVector*, int*) { EAXJMP(0x417EC0); }
|
||||||
|
WRAPPER int32 CCarCtrl::ChoosePoliceCarModel(void) { EAXJMP(0x4181F0); }
|
||||||
|
|
||||||
|
void
|
||||||
|
CCarCtrl::GenerateRandomCars()
|
||||||
|
{
|
||||||
|
if (CCutsceneMgr::IsCutsceneProcessing())
|
||||||
|
return;
|
||||||
|
if (NumRandomCars < 30){
|
||||||
|
if (CountDownToCarsAtStart == 0){
|
||||||
|
GenerateOneRandomCar();
|
||||||
|
}
|
||||||
|
else if (--CountDownToCarsAtStart == 0) {
|
||||||
|
for (int i = 0; i < 50; i++)
|
||||||
|
GenerateOneRandomCar();
|
||||||
|
CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Approximately once per 4 seconds. */
|
||||||
|
if ((CTimer::GetTimeInMilliseconds() & 0xFFFFF000) != (CTimer::GetPreviousTimeInMilliseconds() & 0xFFFFF000))
|
||||||
|
GenerateEmergencyServicesCar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CCarCtrl::GenerateOneRandomCar()
|
||||||
|
{
|
||||||
|
static int32 unk = 0;
|
||||||
|
CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus];
|
||||||
|
CVector vecTargetPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus);
|
||||||
|
CVector2D vecPlayerSpeed = FindPlayerSpeed();
|
||||||
|
CZoneInfo zone;
|
||||||
|
CTheZones::GetZoneInfoForTimeOfDay(&vecTargetPos, &zone);
|
||||||
|
pPlayer->m_nTrafficMultiplier = pPlayer->m_fRoadDensity * zone.carDensity;
|
||||||
|
if (NumRandomCars >= pPlayer->m_nTrafficMultiplier * CarDensityMultiplier * CIniFile::CarNumberMultiplier)
|
||||||
|
return;
|
||||||
|
if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars >= MaxNumberOfCarsInUse)
|
||||||
|
return;
|
||||||
|
CWanted* pWanted = pPlayer->m_pPed->m_pWanted;
|
||||||
|
int carClass;
|
||||||
|
int carModel;
|
||||||
|
if (pWanted->m_nWantedLevel > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles &&
|
||||||
|
pWanted->m_CurrentCops < pWanted->m_MaxCops && (
|
||||||
|
pWanted->m_nWantedLevel > 3 ||
|
||||||
|
pWanted->m_nWantedLevel > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 ||
|
||||||
|
pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) {
|
||||||
|
/* Last pWanted->m_nWantedLevel > 1 is unnecessary but I added it for better readability. */
|
||||||
|
/* Wouldn't be surprised it was there originally but was optimized out. */
|
||||||
|
carClass = COPS;
|
||||||
|
carModel = ChoosePoliceCarModel();
|
||||||
|
}else{
|
||||||
|
carModel = ChooseModel(&zone, &vecTargetPos, &carClass);
|
||||||
|
if (carClass == COPS && pWanted->m_nWantedLevel >= 1)
|
||||||
|
/* All cop spawns with wanted level are handled by condition above. */
|
||||||
|
/* In particular it means that cop cars never spawn if player has wanted level of 1. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float frontX, frontY;
|
||||||
|
float preferredDistance, angleLimit;
|
||||||
|
bool invertAngleLimitTest;
|
||||||
|
CVector spawnPosition;
|
||||||
|
int32 curNodeId, nextNodeId;
|
||||||
|
float positionBetweenNodes;
|
||||||
|
bool testForCollision;
|
||||||
|
CVehicle* pPlayerVehicle = FindPlayerVehicle();
|
||||||
|
CVector2D vecPlayerVehicleSpeed;
|
||||||
|
float fPlayerVehicleSpeed;
|
||||||
|
if (pPlayerVehicle) {
|
||||||
|
vecPlayerVehicleSpeed = FindPlayerVehicle()->GetMoveSpeed();
|
||||||
|
fPlayerVehicleSpeed = vecPlayerVehicleSpeed.Magnitude();
|
||||||
|
}
|
||||||
|
if (TheCamera.GetForward().z < -0.9f){
|
||||||
|
/* Player uses topdown camera. */
|
||||||
|
/* Spawn essentially anywhere. */
|
||||||
|
frontX = frontY = 0.707f; /* 45 degrees */
|
||||||
|
angleLimit = -1.0f;
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 40.0f;
|
||||||
|
/* BUG: testForCollision not initialized in original game. */
|
||||||
|
testForCollision = false;
|
||||||
|
}else if (!pPlayerVehicle){
|
||||||
|
/* Player is not in vehicle. */
|
||||||
|
testForCollision = true;
|
||||||
|
frontX = TheCamera.CamFrontXNorm;
|
||||||
|
frontY = TheCamera.CamFrontYNorm;
|
||||||
|
switch (CTimer::GetFrameCounter() & 1) {
|
||||||
|
case 0:
|
||||||
|
/* Spawn a vehicle relatively far away from player. */
|
||||||
|
/* Forward to his current direction (camera direction). */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* Spawn a vehicle close to player to his side. */
|
||||||
|
/* Kinda not within camera angle. */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = false;
|
||||||
|
preferredDistance = 40.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if (fPlayerVehicleSpeed > 0.4f){ /* 72 km/h */
|
||||||
|
/* Player is moving fast in vehicle */
|
||||||
|
/* Prefer spawning vehicles very far away from him. */
|
||||||
|
frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed;
|
||||||
|
frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed;
|
||||||
|
testForCollision = false;
|
||||||
|
switch (CTimer::GetFrameCounter() & 3) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
/* Spawn a vehicle in a very narrow gap in front of a player */
|
||||||
|
angleLimit = 0.85f; /* approx 30 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Spawn a vehicle relatively far away from player. */
|
||||||
|
/* Forward to his current direction (camera direction). */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* Spawn a vehicle close to player to his side. */
|
||||||
|
/* Kinda not within camera angle. */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = false;
|
||||||
|
preferredDistance = 40.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if (fPlayerVehicleSpeed > 0.1f){ /* 18 km/h */
|
||||||
|
/* Player is moving moderately fast in vehicle */
|
||||||
|
/* Spawn more vehicles to player's side. */
|
||||||
|
frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed;
|
||||||
|
frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed;
|
||||||
|
testForCollision = false;
|
||||||
|
switch (CTimer::GetFrameCounter() & 3) {
|
||||||
|
case 0:
|
||||||
|
/* Spawn a vehicle in a very narrow gap in front of a player */
|
||||||
|
angleLimit = 0.85f; /* approx 30 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* Spawn a vehicle relatively far away from player. */
|
||||||
|
/* Forward to his current direction (camera direction). */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
/* Spawn a vehicle close to player to his side. */
|
||||||
|
/* Kinda not within camera angle. */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = false;
|
||||||
|
preferredDistance = 40.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
/* Player is in vehicle but moving very slow. */
|
||||||
|
/* Then use camera direction instead of vehicle direction. */
|
||||||
|
testForCollision = true;
|
||||||
|
frontX = TheCamera.CamFrontXNorm;
|
||||||
|
frontY = TheCamera.CamFrontYNorm;
|
||||||
|
switch (CTimer::GetFrameCounter() & 1) {
|
||||||
|
case 0:
|
||||||
|
/* Spawn a vehicle relatively far away from player. */
|
||||||
|
/* Forward to his current direction (camera direction). */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = true;
|
||||||
|
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* Spawn a vehicle close to player to his side. */
|
||||||
|
/* Kinda not within camera angle. */
|
||||||
|
angleLimit = 0.707f; /* 45 degrees */
|
||||||
|
invertAngleLimitTest = false;
|
||||||
|
preferredDistance = 40.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ThePaths.NewGenerateCarCreationCoors(vecTargetPos.x, vecTargetPos.y, frontX, frontY,
|
||||||
|
preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId,
|
||||||
|
&positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1))
|
||||||
|
return;
|
||||||
|
int16 colliding;
|
||||||
|
CWorld::FindObjectsKindaColliding(spawnPosition, 10.0f, true, &colliding, 2, nil, false, true, true, false, false);
|
||||||
|
if (colliding)
|
||||||
|
/* If something is already present in spawn position, do not create vehicle*/
|
||||||
|
return;
|
||||||
|
if (!ThePaths.TestCoorsCloseness(vecTargetPos, false, spawnPosition))
|
||||||
|
/* Testing if spawn position can reach target position via valid path. */
|
||||||
|
return;
|
||||||
|
int16 idInNode = 0;
|
||||||
|
CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId];
|
||||||
|
CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId];
|
||||||
|
while (idInNode < pCurNode->numLinks &&
|
||||||
|
ThePaths.m_connections[idInNode + pCurNode->firstLink] != nextNodeId)
|
||||||
|
idInNode++;
|
||||||
|
int16 connectionId = ThePaths.m_carPathConnections[idInNode + pCurNode->firstLink];
|
||||||
|
CCarPathLink* pPathLink = &ThePaths.m_carPathLinks[connectionId];
|
||||||
|
int16 lanesOnCurrentRoad = pPathLink->pathNodeIndex == nextNodeId ? pPathLink->numLeftLanes : pPathLink->numRightLanes;
|
||||||
|
CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(carModel);
|
||||||
|
if (lanesOnCurrentRoad == 0 || pModelInfo->m_vehicleType == VEHICLE_TYPE_BIKE)
|
||||||
|
/* Not spawning vehicle if road is one way and intended direction is opposide to that way. */
|
||||||
|
/* Also not spawning bikes but they don't exist in final game. */
|
||||||
|
return;
|
||||||
|
CAutomobile* pCar = new CAutomobile(carModel, RANDOM_VEHICLE);
|
||||||
|
pCar->AutoPilot.m_nPrevRouteNode = 0;
|
||||||
|
pCar->AutoPilot.m_nCurrentRouteNode = curNodeId;
|
||||||
|
pCar->AutoPilot.m_nNextRouteNode = nextNodeId;
|
||||||
|
switch (carClass) {
|
||||||
|
case POOR:
|
||||||
|
case RICH:
|
||||||
|
case EXEC:
|
||||||
|
case WORKER:
|
||||||
|
case SPECIAL:
|
||||||
|
case BIG:
|
||||||
|
case TAXI:
|
||||||
|
case MAFIA:
|
||||||
|
case TRIAD:
|
||||||
|
case DIABLO:
|
||||||
|
case YAKUZA:
|
||||||
|
case YARDIE:
|
||||||
|
case COLOMB:
|
||||||
|
case NINES:
|
||||||
|
case GANG8:
|
||||||
|
case GANG9:
|
||||||
|
{
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14);
|
||||||
|
if (carClass == EXEC)
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18);
|
||||||
|
else if (carClass == POOR || carClass == SPECIAL)
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10);
|
||||||
|
CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(pCar->GetModelIndex());
|
||||||
|
if (pVehicleInfo->GetColModel()->boundingBox.max.y - pVehicleInfo->GetColModel()->boundingBox.min.y > 10.0f || carClass == BIG) {
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed *= 3;
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed /= 4;
|
||||||
|
}
|
||||||
|
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed;
|
||||||
|
pCar->AutoPilot.m_nCarMission = MISSION_CRUISE;
|
||||||
|
pCar->AutoPilot.m_nAnimationId = TEMPACT_NONE;
|
||||||
|
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COPS:
|
||||||
|
pCar->AutoPilot.m_nAnimationId = TEMPACT_NONE;
|
||||||
|
if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed = CCarAI::FindPoliceCarSpeedForWantedLevel(pCar);
|
||||||
|
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed / 2;
|
||||||
|
pCar->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel();
|
||||||
|
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
|
||||||
|
}else{
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 16);
|
||||||
|
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed;
|
||||||
|
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
|
||||||
|
pCar->AutoPilot.m_nCarMission = MISSION_CRUISE;
|
||||||
|
}
|
||||||
|
if (carModel == MI_FBICAR){
|
||||||
|
pCar->m_currentColour1 = 0;
|
||||||
|
pCar->m_currentColour2 = 0;
|
||||||
|
/* FBI cars are gray in carcols, but we want them black if they going after player. */
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pCar && pCar->GetModelIndex() == MI_MRWHOOP)
|
||||||
|
pCar->m_bSirenOrAlarm = true;
|
||||||
|
pCar->AutoPilot.m_nNextPathNodeInfo = connectionId;
|
||||||
|
pCar->AutoPilot.m_nCurrentLane = pCar->AutoPilot.m_nPreviousLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad;
|
||||||
|
CColBox* boundingBox = &CModelInfo::GetModelInfo(pCar->GetModelIndex())->GetColModel()->boundingBox;
|
||||||
|
float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2;
|
||||||
|
float distanceBetweenNodes = (pCurNode->pos - pNextNode->pos).Magnitude2D();
|
||||||
|
/* If car is so long that it doesn't fit between two car nodes, place it directly in the middle. */
|
||||||
|
/* Otherwise put it at least in a way that full vehicle length fits between two nodes. */
|
||||||
|
if (distanceBetweenNodes / 2 < carLength)
|
||||||
|
positionBetweenNodes = 0.5f;
|
||||||
|
else
|
||||||
|
positionBetweenNodes = min(1.0f - carLength / distanceBetweenNodes, max(carLength / distanceBetweenNodes, positionBetweenNodes));
|
||||||
|
pCar->AutoPilot.m_nNextDirection = (curNodeId >= nextNodeId) ? 1 : -1;
|
||||||
|
if (pCurNode->numLinks == 1){
|
||||||
|
/* Do not create vehicle if there is nowhere to go. */
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int16 nextConnection = pCar->AutoPilot.m_nNextPathNodeInfo;
|
||||||
|
int16 newLink;
|
||||||
|
while (nextConnection == pCar->AutoPilot.m_nNextPathNodeInfo){
|
||||||
|
newLink = CGeneral::GetRandomNumber() % pCurNode->numLinks;
|
||||||
|
nextConnection = ThePaths.m_carPathConnections[newLink + pCurNode->firstLink];
|
||||||
|
}
|
||||||
|
pCar->AutoPilot.m_nCurrentPathNodeInfo = nextConnection;
|
||||||
|
pCar->AutoPilot.m_nCurrentDirection = (ThePaths.m_connections[newLink + pCurNode->firstLink] >= curNodeId) ? 1 : -1;
|
||||||
|
CVector2D vecBetweenNodes = pNextNode->pos - pCurNode->pos;
|
||||||
|
float forwardX, forwardY;
|
||||||
|
float distBetweenNodes = vecBetweenNodes.Magnitude();
|
||||||
|
if (distanceBetweenNodes == 0.0f){
|
||||||
|
forwardX = 1.0f;
|
||||||
|
forwardY = 0.0f;
|
||||||
|
}else{
|
||||||
|
forwardX = vecBetweenNodes.x / distBetweenNodes;
|
||||||
|
forwardY = vecBetweenNodes.y / distBetweenNodes;
|
||||||
|
}
|
||||||
|
/* I think the following might be some form of SetRotateZOnly. */
|
||||||
|
/* Setting up direction between two car nodes. */
|
||||||
|
pCar->GetForward() = CVector(forwardX, forwardY, 0.0f);
|
||||||
|
pCar->GetRight() = CVector(forwardY, -forwardX, 0.0f);
|
||||||
|
pCar->GetUp() = CVector(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
float currentPathLinkForwardX = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dirX;
|
||||||
|
float currentPathLinkForwardY = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dirY;
|
||||||
|
float nextPathLinkForwardX = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dirX;
|
||||||
|
float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dirY;
|
||||||
|
|
||||||
|
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
|
||||||
|
float currentLaneCoefficient = (pCurrentLink->numLeftLanes == 0) ? (0.5f - 0.5f * pCurrentLink->numRightLanes) :
|
||||||
|
((pCurrentLink->numRightLanes == 0) ? (0.5f - 0.5f * pCurrentLink->numLeftLanes) : 0.5f);
|
||||||
|
float roadShiftAlongCurrentNode = (pCar->AutoPilot.m_nPreviousLane + currentLaneCoefficient) * LANE_WIDTH;
|
||||||
|
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
|
||||||
|
float nextLaneCoefficient = (pNextLink->numLeftLanes == 0) ? (0.5f - 0.5f * pNextLink->numRightLanes) :
|
||||||
|
((pNextLink->numRightLanes == 0) ? (0.5f - 0.5f * pNextLink->numLeftLanes) : 0.5f);
|
||||||
|
float roadShiftAlongNextNode = (pCar->AutoPilot.m_nCurrentLane + nextLaneCoefficient) * LANE_WIDTH;
|
||||||
|
CVector positionOnCurrentLinkIncludingLane(
|
||||||
|
pCurrentLink->posX + roadShiftAlongCurrentNode * currentPathLinkForwardY,
|
||||||
|
pCurrentLink->posY - roadShiftAlongCurrentNode * currentPathLinkForwardX,
|
||||||
|
0.0f);
|
||||||
|
CVector positionOnNextLinkIncludingLane(
|
||||||
|
pNextLink->posX + roadShiftAlongNextNode * nextPathLinkForwardY,
|
||||||
|
pNextLink->posY - roadShiftAlongNextNode * nextPathLinkForwardX,
|
||||||
|
0.0f);
|
||||||
|
float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection;
|
||||||
|
float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection;
|
||||||
|
float directionNextLinkX = pNextLink->dirX * pCar->AutoPilot.m_nNextDirection;
|
||||||
|
float directionNextLinkY = pNextLink->dirY * pCar->AutoPilot.m_nNextDirection;
|
||||||
|
/* We want to make a path between two links that may not have the same forward directions a curve. */
|
||||||
|
pCar->AutoPilot.m_nCurveSpeedScale = CCurves::CalcSpeedScaleFactor(
|
||||||
|
&positionOnCurrentLinkIncludingLane,
|
||||||
|
&positionOnNextLinkIncludingLane,
|
||||||
|
directionCurrentLinkX, directionCurrentLinkY,
|
||||||
|
directionNextLinkX, directionNextLinkY
|
||||||
|
) * (1000.0f / pCar->AutoPilot.m_fMaxTrafficSpeed);
|
||||||
|
#ifdef FIX_BUGS
|
||||||
|
/* Casting timer to float is very unwanted. In this case it's not awful */
|
||||||
|
/* but in CAutoPilot::ModifySpeed it can even cause crashes (see SilentPatch). */
|
||||||
|
pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
|
||||||
|
(uint32)((0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nCurveSpeedScale);
|
||||||
|
#else
|
||||||
|
pCar->AutoPilot.m_nTotalSpeedScaleFactor = CTimer::GetTimeInMilliseconds() -
|
||||||
|
(0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nSpeedScaleFactor;
|
||||||
|
#endif
|
||||||
|
uint32 timeAlreadyInCurve = CTimer::GetTimeInMilliseconds() - pCar->AutoPilot.m_nTimeEnteredCurve;
|
||||||
|
float positionAlongCurve = (float)timeAlreadyInCurve / pCar->AutoPilot.m_nCurveSpeedScale;
|
||||||
|
CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f);
|
||||||
|
CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f);
|
||||||
|
CVector positionIncludingCurve;
|
||||||
|
CVector directionIncludingCurve;
|
||||||
|
CCurves::CalcCurvePoint(
|
||||||
|
&positionOnCurrentLinkIncludingLane,
|
||||||
|
&positionOnNextLinkIncludingLane,
|
||||||
|
&directionCurrentLink,
|
||||||
|
&directionNextLink,
|
||||||
|
positionAlongCurve,
|
||||||
|
pCar->AutoPilot.m_nCurveSpeedScale,
|
||||||
|
&positionIncludingCurve,
|
||||||
|
&directionIncludingCurve
|
||||||
|
);
|
||||||
|
CVector vectorBetweenNodes = pCurNode->pos - pNextNode->pos;
|
||||||
|
CVector finalPosition = positionIncludingCurve + vectorBetweenNodes * 2.0f / vectorBetweenNodes.Magnitude();
|
||||||
|
finalPosition.z = positionBetweenNodes * pNextNode->pos.z +
|
||||||
|
(1.0f - positionBetweenNodes) * pCurNode->pos.z;
|
||||||
|
float groundZ = INFINITE_Z;
|
||||||
|
CColPoint colPoint;
|
||||||
|
CEntity* pEntity;
|
||||||
|
if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil))
|
||||||
|
groundZ = colPoint.point.z;
|
||||||
|
if (CWorld::ProcessVerticalLine(finalPosition, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)){
|
||||||
|
if (ABS(colPoint.point.z - finalPosition.z) < ABS(groundZ - finalPosition.z))
|
||||||
|
groundZ = colPoint.point.z;
|
||||||
|
}
|
||||||
|
if (groundZ == INFINITE_Z || ABS(groundZ - finalPosition.z) > 7.0f) {
|
||||||
|
/* Failed to find ground or too far from expected position. */
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finalPosition.z = groundZ + pCar->GetHeightAboveRoad();
|
||||||
|
pCar->GetPosition() = finalPosition;
|
||||||
|
pCar->SetMoveSpeed(directionIncludingCurve / 60.0f);
|
||||||
|
CVector2D speedDifferenceWithTarget = (CVector2D)pCar->GetMoveSpeed() - vecPlayerSpeed;
|
||||||
|
CVector2D distanceToTarget = positionIncludingCurve - vecTargetPos;
|
||||||
|
switch (carClass) {
|
||||||
|
case POOR:
|
||||||
|
case RICH:
|
||||||
|
case EXEC:
|
||||||
|
case WORKER:
|
||||||
|
case SPECIAL:
|
||||||
|
case BIG:
|
||||||
|
case TAXI:
|
||||||
|
case MAFIA:
|
||||||
|
case TRIAD:
|
||||||
|
case DIABLO:
|
||||||
|
case YAKUZA:
|
||||||
|
case YARDIE:
|
||||||
|
case COLOMB:
|
||||||
|
case NINES:
|
||||||
|
case GANG8:
|
||||||
|
case GANG9:
|
||||||
|
pCar->m_status = STATUS_SIMPLE;
|
||||||
|
break;
|
||||||
|
case COPS:
|
||||||
|
pCar->m_status = (pCar->AutoPilot.m_nCarMission == MISSION_CRUISE) ? STATUS_SIMPLE : STATUS_PHYSICS;
|
||||||
|
pCar->ChangeLawEnforcerState(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CVisibilityPlugins::SetClumpAlpha(pCar->GetClump(), 0);
|
||||||
|
if (!pCar->GetIsOnScreen()){
|
||||||
|
if ((vecTargetPos - pCar->GetPosition()).Magnitude2D() > 50.0f) {
|
||||||
|
/* Too far away cars that are not visible aren't needed. */
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else if((vecTargetPos - pCar->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * 130.0f ||
|
||||||
|
(vecTargetPos - pCar->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 110.0f){
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}else if((TheCamera.GetPosition() - pCar->GetPosition()).Magnitude2D() < 90.0f * TheCamera.GenerationDistMultiplier){
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CVehicleModelInfo* pVehicleModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(pCar->GetModelIndex());
|
||||||
|
float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius;
|
||||||
|
if (testForCollision){
|
||||||
|
CWorld::FindObjectsKindaColliding(pCar->GetPosition(), radiusToTest + 20.0f, true, &colliding, 2, nil, false, true, false, false, false);
|
||||||
|
if (colliding){
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CWorld::FindObjectsKindaColliding(pCar->GetPosition(), radiusToTest, true, &colliding, 2, nil, false, true, false, false, false);
|
||||||
|
if (colliding){
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (speedDifferenceWithTarget.x * distanceToTarget.x +
|
||||||
|
speedDifferenceWithTarget.y * distanceToTarget.y >= 0.0f){
|
||||||
|
delete pCar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pVehicleModel->AvoidSameVehicleColour(&pCar->m_currentColour1, &pCar->m_currentColour2);
|
||||||
|
CWorld::Add(pCar);
|
||||||
|
if (carClass == COPS)
|
||||||
|
CCarAI::AddPoliceOccupants(pCar);
|
||||||
|
else
|
||||||
|
pCar->SetUpDriver();
|
||||||
|
if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */
|
||||||
|
pCar->m_status = STATUS_PHYSICS;
|
||||||
|
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
|
||||||
|
pCar->AutoPilot.m_nCruiseSpeed += 10;
|
||||||
|
}
|
||||||
|
if (carClass == COPS)
|
||||||
|
LastTimeLawEnforcerCreated = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CCarCtrl::MapCouldMoveInThisArea(float x, float y)
|
CCarCtrl::MapCouldMoveInThisArea(float x, float y)
|
||||||
@ -29,3 +519,7 @@ CCarCtrl::MapCouldMoveInThisArea(float x, float y)
|
|||||||
return x > -342.0f && x < -219.0f &&
|
return x > -342.0f && x < -219.0f &&
|
||||||
y > -677.0f && y < -580.0f;
|
y > -677.0f && y < -580.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x416580, &CCarCtrl::GenerateRandomCars, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
@ -1,9 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class CVehicle;
|
class CVehicle;
|
||||||
|
class CZoneInfo;
|
||||||
|
|
||||||
class CCarCtrl
|
class CCarCtrl
|
||||||
{
|
{
|
||||||
|
enum eCarClass {
|
||||||
|
POOR = 0,
|
||||||
|
RICH,
|
||||||
|
EXEC,
|
||||||
|
WORKER,
|
||||||
|
SPECIAL,
|
||||||
|
BIG,
|
||||||
|
TAXI,
|
||||||
|
CLASS7,
|
||||||
|
MAFIA,
|
||||||
|
TRIAD,
|
||||||
|
DIABLO,
|
||||||
|
YAKUZA,
|
||||||
|
YARDIE,
|
||||||
|
COLOMB,
|
||||||
|
NINES,
|
||||||
|
GANG8,
|
||||||
|
GANG9,
|
||||||
|
COPS
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
static void SwitchVehicleToRealPhysics(CVehicle*);
|
static void SwitchVehicleToRealPhysics(CVehicle*);
|
||||||
static void AddToCarArray(int32 id, int32 vehclass);
|
static void AddToCarArray(int32 id, int32 vehclass);
|
||||||
@ -16,6 +37,11 @@ public:
|
|||||||
static bool MapCouldMoveInThisArea(float x, float y);
|
static bool MapCouldMoveInThisArea(float x, float y);
|
||||||
static void ScanForPedDanger(CVehicle *veh);
|
static void ScanForPedDanger(CVehicle *veh);
|
||||||
static void RemoveFromInterestingVehicleList(CVehicle*);
|
static void RemoveFromInterestingVehicleList(CVehicle*);
|
||||||
|
static void GenerateRandomCars(void);
|
||||||
|
static void GenerateOneRandomCar(void);
|
||||||
|
static void GenerateEmergencyServicesCar(void);
|
||||||
|
static int32 ChooseModel(CZoneInfo*, CVector*, int*);
|
||||||
|
static int32 ChoosePoliceCarModel(void);
|
||||||
|
|
||||||
static int32 &NumLawEnforcerCars;
|
static int32 &NumLawEnforcerCars;
|
||||||
static int32 &NumAmbulancesOnDuty;
|
static int32 &NumAmbulancesOnDuty;
|
||||||
@ -25,4 +51,7 @@ public:
|
|||||||
static int32 &NumParkedCars;
|
static int32 &NumParkedCars;
|
||||||
static bool &bCarsGeneratedAroundCamera;
|
static bool &bCarsGeneratedAroundCamera;
|
||||||
static float &CarDensityMultiplier;
|
static float &CarDensityMultiplier;
|
||||||
|
static int8 &CountDownToCarsAtStart;
|
||||||
|
static int32 &MaxNumberOfCarsInUse;
|
||||||
|
static uint32 &LastTimeLawEnforcerCreated;
|
||||||
};
|
};
|
||||||
|
6
src/control/Curves.cpp
Normal file
6
src/control/Curves.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Curves.h"
|
||||||
|
|
||||||
|
WRAPPER float CCurves::CalcSpeedScaleFactor(CVector*, CVector*, float, float, float, float) { EAXJMP(0x420410); }
|
||||||
|
WRAPPER void CCurves::CalcCurvePoint(CVector*, CVector*, CVector*, CVector*, float, int32, CVector*, CVector*) { EAXJMP(0x4204D0); }
|
9
src/control/Curves.h
Normal file
9
src/control/Curves.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
class CVector;
|
||||||
|
|
||||||
|
class CCurves
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static float CalcSpeedScaleFactor(CVector*, CVector*, float, float, float, float);
|
||||||
|
static void CalcCurvePoint(CVector*, CVector*, CVector*, CVector*, float, int32, CVector*, CVector*);
|
||||||
|
};
|
@ -6,6 +6,8 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754;
|
|||||||
|
|
||||||
WRAPPER int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels) { EAXJMP(0x42CC30); }
|
WRAPPER int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels) { EAXJMP(0x42CC30); }
|
||||||
WRAPPER CPathNode** CPathFind::FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*) { EAXJMP(0x42B9F0); }
|
WRAPPER CPathNode** CPathFind::FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*) { EAXJMP(0x42B9F0); }
|
||||||
|
WRAPPER bool CPathFind::NewGenerateCarCreationCoors(float, float, float, float, float, float, bool, CVector*, int32*, int32*, float*, bool) { EAXJMP(0x42BF10); }
|
||||||
|
WRAPPER bool CPathFind::TestCoorsCloseness(CVector, bool, CVector) { EAXJMP(0x42C8C0); }
|
||||||
int TempListLength;
|
int TempListLength;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -130,6 +130,8 @@ public:
|
|||||||
void RegisterMapObject(CTreadable *mapObject);
|
void RegisterMapObject(CTreadable *mapObject);
|
||||||
int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels);
|
int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels);
|
||||||
CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*);
|
CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*);
|
||||||
|
bool NewGenerateCarCreationCoors(float spawnX, float spawnY, float frontX, float frontY, float preferredDistance, float angleLimit /* angle limit between camera direction and vector to spawn */, bool invertAngleLimitTest, CVector* pSpawnPosition, int32* pNode1, int32* pNode2, float* pPositionBetweenNodes, bool ignoreSwitchedOff);
|
||||||
|
bool TestCoorsCloseness(CVector pos1, bool, CVector pos2);
|
||||||
|
|
||||||
bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); }
|
bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); }
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6;
|
|||||||
int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570;
|
int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570;
|
||||||
float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C;
|
float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C;
|
||||||
uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70;
|
uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70;
|
||||||
|
int32 &CPopulation::MaxNumberOfPedsInUse = *(int32*)0x5FA574;
|
||||||
|
|
||||||
WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); }
|
WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); }
|
||||||
WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); }
|
WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); }
|
||||||
|
@ -17,6 +17,7 @@ public:
|
|||||||
static int32 &m_AllRandomPedsThisType;
|
static int32 &m_AllRandomPedsThisType;
|
||||||
static float &PedDensityMultiplier;
|
static float &PedDensityMultiplier;
|
||||||
static uint32 &ms_nTotalMissionPeds;
|
static uint32 &ms_nTotalMissionPeds;
|
||||||
|
static int32 &MaxNumberOfPedsInUse;
|
||||||
|
|
||||||
static void UpdatePedCount(uint32, bool);
|
static void UpdatePedCount(uint32, bool);
|
||||||
static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool);
|
static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class CRestart
|
class CRestart
|
||||||
{
|
{
|
||||||
|
28
src/core/IniFile.cpp
Normal file
28
src/core/IniFile.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "IniFile.h"
|
||||||
|
|
||||||
|
#include "CarCtrl.h"
|
||||||
|
#include "FileMgr.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "Population.h"
|
||||||
|
|
||||||
|
float &CIniFile::PedNumberMultiplier = *(float*)0x6182F4;
|
||||||
|
float &CIniFile::CarNumberMultiplier = *(float*)0x6182F8;
|
||||||
|
|
||||||
|
void CIniFile::LoadIniFile()
|
||||||
|
{
|
||||||
|
CFileMgr::SetDir("");
|
||||||
|
int f = CFileMgr::OpenFile("gta3.ini", "r");
|
||||||
|
if (f){
|
||||||
|
CFileMgr::ReadLine(f, gString, 200);
|
||||||
|
sscanf(gString, "%f", &PedNumberMultiplier);
|
||||||
|
PedNumberMultiplier = min(3.0f, max(0.5f, PedNumberMultiplier));
|
||||||
|
CFileMgr::ReadLine(f, gString, 200);
|
||||||
|
sscanf(gString, "%f", &CarNumberMultiplier);
|
||||||
|
CarNumberMultiplier = min(3.0f, max(0.5f, CarNumberMultiplier));
|
||||||
|
CFileMgr::CloseFile(f);
|
||||||
|
}
|
||||||
|
CPopulation::MaxNumberOfPedsInUse = 25.0f * PedNumberMultiplier;
|
||||||
|
CCarCtrl::MaxNumberOfCarsInUse = 12.0f * CarNumberMultiplier;
|
||||||
|
}
|
10
src/core/IniFile.h
Normal file
10
src/core/IniFile.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CIniFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void LoadIniFile();
|
||||||
|
|
||||||
|
static float& PedNumberMultiplier;
|
||||||
|
static float& CarNumberMultiplier;
|
||||||
|
};
|
@ -179,7 +179,7 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con
|
|||||||
|
|
||||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#define ABS(a) (((a) < 0) ? (-a) : (a))
|
#define ABS(a) (((a) < 0) ? (-(a)) : (a))
|
||||||
#define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min)))))
|
#define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min)))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,6 +115,9 @@ public:
|
|||||||
m_vecMoveSpeed.y = y;
|
m_vecMoveSpeed.y = y;
|
||||||
m_vecMoveSpeed.z = z;
|
m_vecMoveSpeed.z = z;
|
||||||
}
|
}
|
||||||
|
void SetMoveSpeed(const CVector& speed) {
|
||||||
|
m_vecMoveSpeed = speed;
|
||||||
|
}
|
||||||
const CVector &GetTurnSpeed() { return m_vecTurnSpeed; }
|
const CVector &GetTurnSpeed() { return m_vecTurnSpeed; }
|
||||||
void SetTurnSpeed(float x, float y, float z) {
|
void SetTurnSpeed(float x, float y, float z) {
|
||||||
m_vecTurnSpeed.x = x;
|
m_vecTurnSpeed.x = x;
|
||||||
|
Loading…
Reference in New Issue
Block a user