mirror of
https://github.com/halpz/re3.git
synced 2024-12-25 18:05:27 +00:00
Merge branch 'carctrl_dev'
This commit is contained in:
commit
8355a6dccd
45
src/control/AccidentManager.cpp
Normal file
45
src/control/AccidentManager.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "AccidentManager.h"
|
||||||
|
|
||||||
|
#include "Ped.h"
|
||||||
|
|
||||||
|
CAccidentManager& gAccidentManager = *(CAccidentManager*)0x87FD10;
|
||||||
|
|
||||||
|
uint16 CAccidentManager::CountActiveAccidents()
|
||||||
|
{
|
||||||
|
uint16 accidents = 0;
|
||||||
|
for (int i = 0; i < NUM_ACCIDENTS; i++){
|
||||||
|
if (m_aAccidents[i].m_pVictim)
|
||||||
|
accidents++;
|
||||||
|
}
|
||||||
|
return accidents;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAccident* CAccidentManager::FindNearestAccident(CVector vecPos, float* pDistance)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_MEDICS_TO_ATTEND_ACCIDENT; i++){
|
||||||
|
int accidentId = -1;
|
||||||
|
float minDistance = 999999;
|
||||||
|
for (int j = 0; j < NUM_ACCIDENTS; j++){
|
||||||
|
CPed* pVictim = m_aAccidents[j].m_pVictim;
|
||||||
|
if (!pVictim)
|
||||||
|
continue;
|
||||||
|
if (pVictim->CharCreatedBy == MISSION_CHAR)
|
||||||
|
continue;
|
||||||
|
if (pVictim->m_fHealth != 0.0f)
|
||||||
|
continue;
|
||||||
|
if (m_aAccidents[j].m_nMedicsPerformingCPR != i)
|
||||||
|
continue;
|
||||||
|
float distance = (pVictim->GetPosition() - vecPos).Magnitude2D();
|
||||||
|
if (distance / 2 > pVictim->GetPosition().z - vecPos.z && distance < minDistance){
|
||||||
|
minDistance = distance;
|
||||||
|
accidentId = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pDistance = minDistance;
|
||||||
|
if (accidentId != -1)
|
||||||
|
return &m_aAccidents[accidentId];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
27
src/control/AccidentManager.h
Normal file
27
src/control/AccidentManager.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
class CPed;
|
||||||
|
|
||||||
|
class CAccident
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CPed *m_pVictim;
|
||||||
|
uint32 m_nMedicsAttending;
|
||||||
|
uint32 m_nMedicsPerformingCPR;
|
||||||
|
CAccident() : m_pVictim(nil), m_nMedicsAttending(0), m_nMedicsPerformingCPR(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAccidentManager
|
||||||
|
{
|
||||||
|
CAccident m_aAccidents[NUM_ACCIDENTS];
|
||||||
|
enum {
|
||||||
|
MAX_MEDICS_TO_ATTEND_ACCIDENT = 2
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
uint16 CountActiveAccidents();
|
||||||
|
CAccident* FindNearestAccident(CVector, float*);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CAccidentManager& gAccidentManager;
|
|
@ -11,6 +11,8 @@ WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
|
||||||
WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
|
WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
|
||||||
WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
|
WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
|
||||||
WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
|
WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
|
||||||
|
WRAPPER void CCarAI::AddAmbulanceOccupants(CVehicle*) { EAXJMP(0x415CE0); }
|
||||||
|
WRAPPER void CCarAI::AddFiretruckOccupants(CVehicle*) { EAXJMP(0x415D00); }
|
||||||
WRAPPER void CCarAI::TellOccupantsToLeaveCar(CVehicle*) { EAXJMP(0x415D20); }
|
WRAPPER void CCarAI::TellOccupantsToLeaveCar(CVehicle*) { EAXJMP(0x415D20); }
|
||||||
|
|
||||||
void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)
|
void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)
|
||||||
|
|
|
@ -12,6 +12,8 @@ public:
|
||||||
static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*);
|
static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*);
|
||||||
static eCarMission FindPoliceCarMissionForWantedLevel();
|
static eCarMission FindPoliceCarMissionForWantedLevel();
|
||||||
static void AddPoliceOccupants(CVehicle*);
|
static void AddPoliceOccupants(CVehicle*);
|
||||||
|
static void AddAmbulanceOccupants(CVehicle*);
|
||||||
|
static void AddFiretruckOccupants(CVehicle*);
|
||||||
static void CarHasReasonToStop(CVehicle*);
|
static void CarHasReasonToStop(CVehicle*);
|
||||||
static void TellOccupantsToLeaveCar(CVehicle*);
|
static void TellOccupantsToLeaveCar(CVehicle*);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "CarCtrl.h"
|
#include "CarCtrl.h"
|
||||||
|
|
||||||
|
#include "AccidentManager.h"
|
||||||
#include "Automobile.h"
|
#include "Automobile.h"
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "CarAI.h"
|
#include "CarAI.h"
|
||||||
|
@ -81,21 +82,14 @@ int32 &CCarCtrl::NumPermanentCars = *(int32*)0x8F29F0;
|
||||||
int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63;
|
int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63;
|
||||||
int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
|
int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
|
||||||
uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
|
uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
|
||||||
uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x941450;
|
uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x880F5C;
|
||||||
uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x880F5C;
|
uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x941450;
|
||||||
int32 (&CCarCtrl::TotalNumOfCarsOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x8F1A60;
|
int32 (&CCarCtrl::TotalNumOfCarsOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x8F1A60;
|
||||||
int32 (&CCarCtrl::NextCarOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x9412AC;
|
int32 (&CCarCtrl::NextCarOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x9412AC;
|
||||||
int32 (&CCarCtrl::CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860;
|
int32 (&CCarCtrl::CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860;
|
||||||
CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x70D830;
|
CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x70D830;
|
||||||
uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x87F9A8;
|
uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x87F9A8;
|
||||||
|
|
||||||
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
|
|
||||||
WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); }
|
|
||||||
WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); }
|
|
||||||
WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
|
|
||||||
WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
|
|
||||||
WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CCarCtrl::GenerateRandomCars()
|
CCarCtrl::GenerateRandomCars()
|
||||||
{
|
{
|
||||||
|
@ -753,44 +747,6 @@ CCarCtrl::CountCarsOfType(int32 mi)
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
CCarCtrl::IsThisVehicleInteresting(CVehicle* pVehicle)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
|
||||||
if (apCarsToKeep[i] == pVehicle)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CCarCtrl::RegisterVehicleOfInterest(CVehicle* pVehicle)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
|
||||||
if (apCarsToKeep[i] == pVehicle) {
|
|
||||||
aCarsToKeepTime[i] = CTimer::GetTimeInMilliseconds();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
|
||||||
if (!apCarsToKeep[i]) {
|
|
||||||
apCarsToKeep[i] = pVehicle;
|
|
||||||
aCarsToKeepTime[i] = CTimer::GetTimeInMilliseconds();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32 oldestCarWeKeepTime = UINT_MAX;
|
|
||||||
int oldestCarWeKeepIndex = 0;
|
|
||||||
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
|
||||||
if (apCarsToKeep[i] && aCarsToKeepTime[i] < oldestCarWeKeepTime) {
|
|
||||||
oldestCarWeKeepTime = aCarsToKeepTime[i];
|
|
||||||
oldestCarWeKeepIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apCarsToKeep[oldestCarWeKeepIndex] = pVehicle;
|
|
||||||
aCarsToKeepTime[oldestCarWeKeepIndex] = CTimer::GetTimeInMilliseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
|
CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
|
||||||
{
|
{
|
||||||
|
@ -1651,7 +1607,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
|
||||||
) * (1000.0f / pVehicle->AutoPilot.m_fMaxTrafficSpeed);
|
) * (1000.0f / pVehicle->AutoPilot.m_fMaxTrafficSpeed);
|
||||||
if (pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve < 10)
|
if (pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve < 10)
|
||||||
/* Oh hey there Obbe */
|
/* Oh hey there Obbe */
|
||||||
debug("fout\n");
|
printf("fout\n");
|
||||||
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = max(10, pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve);
|
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = max(10, pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2484,6 +2440,305 @@ void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CBoat* pBoat, float target
|
||||||
*pSwerve = angleDiff;
|
*pSwerve = angleDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CCarCtrl::RegisterVehicleOfInterest(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
if (apCarsToKeep[i] == pVehicle) {
|
||||||
|
aCarsToKeepTime[i] = CTimer::GetTimeInMilliseconds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
if (!apCarsToKeep[i]) {
|
||||||
|
apCarsToKeep[i] = pVehicle;
|
||||||
|
aCarsToKeepTime[i] = CTimer::GetTimeInMilliseconds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32 oldestCarWeKeepTime = UINT_MAX;
|
||||||
|
int oldestCarWeKeepIndex = 0;
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
if (apCarsToKeep[i] && aCarsToKeepTime[i] < oldestCarWeKeepTime) {
|
||||||
|
oldestCarWeKeepTime = aCarsToKeepTime[i];
|
||||||
|
oldestCarWeKeepIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apCarsToKeep[oldestCarWeKeepIndex] = pVehicle;
|
||||||
|
aCarsToKeepTime[oldestCarWeKeepIndex] = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CCarCtrl::IsThisVehicleInteresting(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
if (apCarsToKeep[i] == pVehicle)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
if (apCarsToKeep[i] == pVehicle)
|
||||||
|
apCarsToKeep[i] = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::ClearInterestingVehicleList()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
|
||||||
|
apCarsToKeep[i] = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
|
||||||
|
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
|
||||||
|
pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
|
||||||
|
pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::JoinCarWithRoadSystem(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
pVehicle->AutoPilot.m_nPrevRouteNode = pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nNextRouteNode = 0;
|
||||||
|
pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nPreviousPathNodeInfo = pVehicle->AutoPilot.m_nNextPathNodeInfo = 0;
|
||||||
|
int nodeId = ThePaths.FindNodeClosestToCoorsFavourDirection(pVehicle->GetPosition(), 0, pVehicle->GetForward().x, pVehicle->GetForward().y);
|
||||||
|
CPathNode* pNode = &ThePaths.m_pathNodes[nodeId];
|
||||||
|
int prevNodeId = -1;
|
||||||
|
float minDistance = 999999.9f;
|
||||||
|
for (int i = 0; i < pNode->numLinks; i++){
|
||||||
|
int candidateId = ThePaths.m_connections[i + pNode->firstLink];
|
||||||
|
CPathNode* pCandidateNode = &ThePaths.m_pathNodes[candidateId];
|
||||||
|
float distance = (pCandidateNode->pos - pNode->pos).Magnitude2D();
|
||||||
|
if (distance < minDistance){
|
||||||
|
minDistance = distance;
|
||||||
|
prevNodeId = candidateId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prevNodeId < 0)
|
||||||
|
return;
|
||||||
|
CVector2D forward = pVehicle->GetForward();
|
||||||
|
CPathNode* pPrevNode = &ThePaths.m_pathNodes[prevNodeId];
|
||||||
|
if (forward.x == 0.0f && forward.y == 0.0f)
|
||||||
|
forward.x = 1.0f;
|
||||||
|
if (DotProduct2D(pNode->pos - pPrevNode->pos, forward) < 0.0f){
|
||||||
|
int tmp;
|
||||||
|
tmp = prevNodeId;
|
||||||
|
prevNodeId = nodeId;
|
||||||
|
nodeId = tmp;
|
||||||
|
}
|
||||||
|
pVehicle->AutoPilot.m_nPrevRouteNode = 0;
|
||||||
|
pVehicle->AutoPilot.m_nCurrentRouteNode = prevNodeId;
|
||||||
|
pVehicle->AutoPilot.m_nNextRouteNode = nodeId;
|
||||||
|
pVehicle->AutoPilot.m_nPathFindNodesCount = 0;
|
||||||
|
FindLinksToGoWithTheseNodes(pVehicle);
|
||||||
|
pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle* pVehicle, CVector vecTarget, bool isProperNow)
|
||||||
|
{
|
||||||
|
pVehicle->AutoPilot.m_vecDestinationCoors = vecTarget;
|
||||||
|
ThePaths.DoPathSearch(0, pVehicle->GetPosition(), -1, vecTarget, pVehicle->AutoPilot.m_aPathFindNodesInfo,
|
||||||
|
&pVehicle->AutoPilot.m_nPathFindNodesCount, NUM_PATH_NODES_IN_AUTOPILOT, pVehicle, nil, 999999.9f, -1);
|
||||||
|
ThePaths.RemoveBadStartNode(pVehicle->GetPosition(),
|
||||||
|
pVehicle->AutoPilot.m_aPathFindNodesInfo, &pVehicle->AutoPilot.m_nPathFindNodesCount);
|
||||||
|
if (pVehicle->AutoPilot.m_nPathFindNodesCount < 2){
|
||||||
|
pVehicle->AutoPilot.m_nPrevRouteNode = pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nNextRouteNode = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pVehicle->AutoPilot.m_nPrevRouteNode = 0;
|
||||||
|
pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_aPathFindNodesInfo[0] - ThePaths.m_pathNodes;
|
||||||
|
pVehicle->AutoPilot.RemoveOnePathNode();
|
||||||
|
pVehicle->AutoPilot.m_nNextRouteNode = pVehicle->AutoPilot.m_aPathFindNodesInfo[0] - ThePaths.m_pathNodes;
|
||||||
|
pVehicle->AutoPilot.RemoveOnePathNode();
|
||||||
|
FindLinksToGoWithTheseNodes(pVehicle);
|
||||||
|
pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle)
|
||||||
|
{
|
||||||
|
int nextLink;
|
||||||
|
CPathNode* pCurNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nCurrentRouteNode];
|
||||||
|
for (nextLink = 0; nextLink < 12; nextLink++)
|
||||||
|
if (ThePaths.m_connections[nextLink + pCurNode->firstLink] != pVehicle->AutoPilot.m_nNextRouteNode)
|
||||||
|
break;
|
||||||
|
pVehicle->AutoPilot.m_nNextPathNodeInfo = ThePaths.m_carPathConnections[nextLink + pCurNode->firstLink];
|
||||||
|
pVehicle->AutoPilot.m_nNextDirection = (pVehicle->AutoPilot.m_nCurrentRouteNode >= pVehicle->AutoPilot.m_nNextRouteNode) ? 1 : -1;
|
||||||
|
int curLink;
|
||||||
|
int curConnection;
|
||||||
|
if (pCurNode->numLinks == 1) {
|
||||||
|
curLink = 0;
|
||||||
|
curConnection = ThePaths.m_carPathConnections[pCurNode->firstLink];
|
||||||
|
}else{
|
||||||
|
curConnection = pVehicle->AutoPilot.m_nNextPathNodeInfo;
|
||||||
|
while (curConnection == pVehicle->AutoPilot.m_nNextPathNodeInfo){
|
||||||
|
curLink = CGeneral::GetRandomNumber() % pCurNode->numLinks;
|
||||||
|
curConnection = ThePaths.m_carPathConnections[curLink + pCurNode->firstLink];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVehicle->AutoPilot.m_nCurrentPathNodeInfo = curConnection;
|
||||||
|
pVehicle->AutoPilot.m_nCurrentDirection = (ThePaths.m_connections[curLink + pCurNode->firstLink] >= pVehicle->AutoPilot.m_nCurrentRouteNode) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::GenerateEmergencyServicesCar(void)
|
||||||
|
{
|
||||||
|
if (FindPlayerPed()->m_pWanted->m_nWantedLevel > 3)
|
||||||
|
return;
|
||||||
|
if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars +
|
||||||
|
NumLawEnforcerCars + NumRandomCars > MaxNumberOfCarsInUse)
|
||||||
|
return;
|
||||||
|
if (NumAmbulancesOnDuty == 0){
|
||||||
|
if (gAccidentManager.CountActiveAccidents() < 2){
|
||||||
|
if (CStreaming::HasModelLoaded(MI_AMBULAN))
|
||||||
|
CStreaming::SetModelIsDeletable(MI_MEDIC);
|
||||||
|
}else{
|
||||||
|
float distance = 30.0f;
|
||||||
|
CAccident* pNearestAccident = gAccidentManager.FindNearestAccident(FindPlayerCoors(), &distance);
|
||||||
|
if (pNearestAccident){
|
||||||
|
if (CountCarsOfType(MI_AMBULAN) < 2 && CTimer::GetTimeInMilliseconds() > LastTimeAmbulanceCreated + 30000){
|
||||||
|
CStreaming::RequestModel(MI_AMBULAN, STREAMFLAGS_DEPENDENCY);
|
||||||
|
CStreaming::RequestModel(MI_MEDIC, STREAMFLAGS_DONT_REMOVE);
|
||||||
|
if (CStreaming::HasModelLoaded(MI_AMBULAN) && CStreaming::HasModelLoaded(MI_MEDIC)){
|
||||||
|
if (GenerateOneEmergencyServicesCar(MI_AMBULAN, pNearestAccident->m_pVictim->GetPosition()))
|
||||||
|
LastTimeAmbulanceCreated = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NumFiretrucksOnDuty == 0){
|
||||||
|
if (gFireManager.GetTotalActiveFires() < 3){
|
||||||
|
if (CStreaming::HasModelLoaded(MI_FIRETRUCK))
|
||||||
|
CStreaming::SetModelIsDeletable(MI_FIREMAN);
|
||||||
|
}else{
|
||||||
|
float distance = 30.0f;
|
||||||
|
CFire* pNearestFire = gFireManager.FindNearestFire(FindPlayerCoors(), &distance);
|
||||||
|
if (pNearestFire) {
|
||||||
|
if (CountCarsOfType(MI_FIRETRUCK) < 2 && CTimer::GetTimeInMilliseconds() > LastTimeFireTruckCreated + 30000){
|
||||||
|
CStreaming::RequestModel(MI_FIRETRUCK, STREAMFLAGS_DEPENDENCY);
|
||||||
|
CStreaming::RequestModel(MI_FIREMAN, STREAMFLAGS_DONT_REMOVE);
|
||||||
|
if (CStreaming::HasModelLoaded(MI_FIRETRUCK) && CStreaming::HasModelLoaded(MI_FIREMAN)){
|
||||||
|
if (GenerateOneEmergencyServicesCar(MI_FIRETRUCK, pNearestFire->m_vecPos))
|
||||||
|
LastTimeFireTruckCreated = CTimer::GetTimeInMilliseconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCarCtrl::GenerateOneEmergencyServicesCar(uint32 mi, CVector vecPos)
|
||||||
|
{
|
||||||
|
CVector pPlayerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus);
|
||||||
|
bool created = false;
|
||||||
|
int attempts = 0;
|
||||||
|
CVector spawnPos;
|
||||||
|
int curNode, nextNode;
|
||||||
|
float posBetweenNodes;
|
||||||
|
while (!created && attempts < 5){
|
||||||
|
if (ThePaths.NewGenerateCarCreationCoors(pPlayerPos.x, pPlayerPos.y, 0.707f, 0.707f,
|
||||||
|
120.0f, -1.0f, true, &spawnPos, &curNode, &nextNode, &posBetweenNodes, false)){
|
||||||
|
int16 colliding[2];
|
||||||
|
CWorld::FindObjectsKindaColliding(spawnPos, 10.0f, true, colliding, 2, nil, false, true, true, false, false);
|
||||||
|
if (colliding[0] == 0)
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
attempts += 1;
|
||||||
|
}
|
||||||
|
if (attempts >= 5)
|
||||||
|
return nil;
|
||||||
|
CAutomobile* pVehicle = new CAutomobile(mi, RANDOM_VEHICLE);
|
||||||
|
pVehicle->AutoPilot.m_vecDestinationCoors = vecPos;
|
||||||
|
pVehicle->GetPosition() = spawnPos;
|
||||||
|
pVehicle->AutoPilot.m_nCarMission = (JoinCarWithRoadSystemGotoCoors(pVehicle, vecPos, false)) ? MISSION_GOTOCOORDS_STRAIGHT : MISSION_GOTOCOORDS;
|
||||||
|
pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed = 25;
|
||||||
|
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
|
||||||
|
pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
|
||||||
|
CVector2D direction = vecPos - spawnPos;
|
||||||
|
direction.Normalise();
|
||||||
|
pVehicle->GetForward() = CVector(direction.x, direction.y, 0.0f);
|
||||||
|
pVehicle->GetRight() = CVector(direction.y, -direction.x, 0.0f);
|
||||||
|
pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f);
|
||||||
|
spawnPos.z = posBetweenNodes * ThePaths.m_pathNodes[curNode].pos.z + (1.0f - posBetweenNodes) * ThePaths.m_pathNodes[nextNode].pos.z;
|
||||||
|
float groundZ = INFINITE_Z;
|
||||||
|
CColPoint colPoint;
|
||||||
|
CEntity* pEntity;
|
||||||
|
if (CWorld::ProcessVerticalLine(spawnPos, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil))
|
||||||
|
groundZ = colPoint.point.z;
|
||||||
|
if (CWorld::ProcessVerticalLine(spawnPos, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) {
|
||||||
|
if (ABS(colPoint.point.z - spawnPos.z) < ABS(groundZ - spawnPos.z))
|
||||||
|
groundZ = colPoint.point.z;
|
||||||
|
}
|
||||||
|
if (groundZ == INFINITE_Z) {
|
||||||
|
delete pVehicle;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spawnPos.z = groundZ + pVehicle->GetDistanceFromCentreOfMassToBaseOfModel();
|
||||||
|
pVehicle->GetPosition() = spawnPos;
|
||||||
|
pVehicle->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));
|
||||||
|
pVehicle->m_status = STATUS_PHYSICS;
|
||||||
|
switch (mi){
|
||||||
|
case MI_FIRETRUCK:
|
||||||
|
pVehicle->bIsFireTruckOnDuty = true;
|
||||||
|
++NumFiretrucksOnDuty;
|
||||||
|
CCarAI::AddFiretruckOccupants(pVehicle);
|
||||||
|
break;
|
||||||
|
case MI_AMBULAN:
|
||||||
|
pVehicle->bIsAmbulanceOnDuty = true;
|
||||||
|
++NumAmbulancesOnDuty;
|
||||||
|
CCarAI::AddAmbulanceOccupants(pVehicle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pVehicle->m_bSirenOrAlarm = true;
|
||||||
|
CWorld::Add(pVehicle);
|
||||||
|
printf("CREATED EMERGENCY VEHICLE\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCarCtrl::UpdateCarCount(CVehicle* pVehicle, bool remove)
|
||||||
|
{
|
||||||
|
if (remove){
|
||||||
|
switch (pVehicle->VehicleCreatedBy){
|
||||||
|
case RANDOM_VEHICLE:
|
||||||
|
if (pVehicle->bIsLawEnforcer)
|
||||||
|
--NumLawEnforcerCars;
|
||||||
|
--NumRandomCars;
|
||||||
|
return;
|
||||||
|
case MISSION_VEHICLE:
|
||||||
|
--NumMissionCars;
|
||||||
|
return;
|
||||||
|
case PARKED_VEHICLE:
|
||||||
|
--NumParkedCars;
|
||||||
|
return;
|
||||||
|
case PERMANENT_VEHICLE:
|
||||||
|
--NumPermanentCars;;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
switch (pVehicle->VehicleCreatedBy){
|
||||||
|
case RANDOM_VEHICLE:
|
||||||
|
if (pVehicle->bIsLawEnforcer)
|
||||||
|
++NumLawEnforcerCars;
|
||||||
|
++NumRandomCars;
|
||||||
|
return;
|
||||||
|
case MISSION_VEHICLE:
|
||||||
|
++NumMissionCars;
|
||||||
|
return;
|
||||||
|
case PARKED_VEHICLE:
|
||||||
|
++NumParkedCars;
|
||||||
|
return;
|
||||||
|
case PERMANENT_VEHICLE:
|
||||||
|
++NumPermanentCars;;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi)
|
bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi)
|
||||||
{
|
{
|
||||||
return mi == MI_BRIDGELIFT || mi == MI_BRIDGEROADSEGMENT;
|
return mi == MI_BRIDGELIFT || mi == MI_BRIDGEROADSEGMENT;
|
||||||
|
@ -2503,4 +2758,12 @@ InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP);
|
||||||
InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
|
InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
|
||||||
InjectHook(0x41D280, &CCarCtrl::Init, PATCH_JUMP);
|
InjectHook(0x41D280, &CCarCtrl::Init, PATCH_JUMP);
|
||||||
InjectHook(0x41D3B0, &CCarCtrl::ReInit, PATCH_JUMP);
|
InjectHook(0x41D3B0, &CCarCtrl::ReInit, PATCH_JUMP);
|
||||||
|
InjectHook(0x41E250, &CCarCtrl::SteerAIBoatWithPhysics, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F6E0, &CCarCtrl::RegisterVehicleOfInterest, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F780, &CCarCtrl::IsThisVehicleInteresting, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F7A0, &CCarCtrl::RemoveFromInterestingVehicleList, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F7D0, &CCarCtrl::ClearInterestingVehicleList, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F7F0, &CCarCtrl::SwitchVehicleToRealPhysics, PATCH_JUMP);
|
||||||
|
InjectHook(0x41F820, &CCarCtrl::JoinCarWithRoadSystem, PATCH_JUMP);
|
||||||
|
InjectHook(0x41FA00, &CCarCtrl::JoinCarWithRoadSystemGotoCoors, PATCH_JUMP);
|
||||||
ENDPATCHES
|
ENDPATCHES
|
||||||
|
|
|
@ -96,6 +96,9 @@ public:
|
||||||
static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
|
static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
|
||||||
static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
|
static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
|
||||||
static bool ThisRoadObjectCouldMove(int16);
|
static bool ThisRoadObjectCouldMove(int16);
|
||||||
|
static void ClearInterestingVehicleList();
|
||||||
|
static void FindLinksToGoWithTheseNodes(CVehicle*);
|
||||||
|
static bool GenerateOneEmergencyServicesCar(uint32, CVector);
|
||||||
|
|
||||||
static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
|
static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,5 +6,30 @@ CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
|
||||||
|
|
||||||
WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
|
WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
|
||||||
|
|
||||||
|
CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) {
|
||||||
|
int fireId = -1;
|
||||||
|
float minDistance = 999999;
|
||||||
|
for (int j = 0; j < NUM_FIRES; j++) {
|
||||||
|
if (!m_aFires[j].m_bIsOngoing)
|
||||||
|
continue;
|
||||||
|
if (m_aFires[j].m_bIsScriptFire)
|
||||||
|
continue;
|
||||||
|
if (m_aFires[j].m_nFiremenPuttingOut != i)
|
||||||
|
continue;
|
||||||
|
float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D();
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
fireId = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pDistance = minDistance;
|
||||||
|
if (fireId != -1)
|
||||||
|
return &m_aFires[fireId];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
|
WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
|
||||||
WRAPPER CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }
|
WRAPPER CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }
|
||||||
|
|
|
@ -6,7 +6,7 @@ class CFire
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool m_bIsOngoing;
|
bool m_bIsOngoing;
|
||||||
bool m_bExists;
|
bool m_bIsScriptFire;
|
||||||
bool m_bPropogationFlag;
|
bool m_bPropogationFlag;
|
||||||
bool m_bAudioSet;
|
bool m_bAudioSet;
|
||||||
CVector m_vecPos;
|
CVector m_vecPos;
|
||||||
|
@ -16,7 +16,7 @@ public:
|
||||||
int m_nStartTime;
|
int m_nStartTime;
|
||||||
int field_20;
|
int field_20;
|
||||||
int field_24;
|
int field_24;
|
||||||
int field_28;
|
uint32 m_nFiremenPuttingOut;
|
||||||
float field_2C;
|
float field_2C;
|
||||||
|
|
||||||
void Extinguish(void);
|
void Extinguish(void);
|
||||||
|
@ -24,8 +24,15 @@ public:
|
||||||
|
|
||||||
class CFireManager
|
class CFireManager
|
||||||
{
|
{
|
||||||
|
enum {
|
||||||
|
MAX_FIREMEN_ATTENDING = 2,
|
||||||
|
};
|
||||||
|
uint32 m_nTotalFires;
|
||||||
|
CFire m_aFires[NUM_FIRES];
|
||||||
public:
|
public:
|
||||||
void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
|
void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
|
||||||
CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
|
CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
|
||||||
|
CFire *FindNearestFire(CVector, float*);
|
||||||
|
uint32 GetTotalActiveFires() const { return m_nTotalFires; }
|
||||||
};
|
};
|
||||||
extern CFireManager &gFireManager;
|
extern CFireManager &gFireManager;
|
||||||
|
|
|
@ -75,6 +75,9 @@ enum Config {
|
||||||
NUM_CARGENS = 160,
|
NUM_CARGENS = 160,
|
||||||
|
|
||||||
NUM_PATH_NODES_IN_AUTOPILOT = 8,
|
NUM_PATH_NODES_IN_AUTOPILOT = 8,
|
||||||
|
|
||||||
|
NUM_ACCIDENTS = 20,
|
||||||
|
NUM_FIRES = 40
|
||||||
};
|
};
|
||||||
|
|
||||||
// We'll use this once we're ready to become independent of the game
|
// We'll use this once we're ready to become independent of the game
|
||||||
|
|
Loading…
Reference in a new issue