This commit is contained in:
Nikolay Korolev 2019-09-15 02:28:07 +03:00
parent 67701df91f
commit 368ce0d4e5
9 changed files with 427 additions and 50 deletions

View 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;
}

View 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;

View File

@ -11,6 +11,8 @@ 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); }
WRAPPER void CCarAI::AddAmbulanceOccupants(CVehicle*) { EAXJMP(0x415CE0); }
WRAPPER void CCarAI::AddFiretruckOccupants(CVehicle*) { EAXJMP(0x415D00); }
WRAPPER void CCarAI::TellOccupantsToLeaveCar(CVehicle*) { EAXJMP(0x415D20); }
void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)

View File

@ -12,6 +12,8 @@ public:
static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*);
static eCarMission FindPoliceCarMissionForWantedLevel();
static void AddPoliceOccupants(CVehicle*);
static void AddAmbulanceOccupants(CVehicle*);
static void AddFiretruckOccupants(CVehicle*);
static void CarHasReasonToStop(CVehicle*);
static void TellOccupantsToLeaveCar(CVehicle*);
};

View File

@ -2,6 +2,7 @@
#include "patcher.h"
#include "CarCtrl.h"
#include "AccidentManager.h"
#include "Automobile.h"
#include "Camera.h"
#include "CarAI.h"
@ -81,21 +82,14 @@ int32 &CCarCtrl::NumPermanentCars = *(int32*)0x8F29F0;
int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63;
int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x941450;
uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x880F5C;
uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x880F5C;
uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x941450;
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::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;
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
CCarCtrl::GenerateRandomCars()
{
@ -753,44 +747,6 @@ CCarCtrl::CountCarsOfType(int32 mi)
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
CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
{
@ -1651,7 +1607,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
) * (1000.0f / pVehicle->AutoPilot.m_fMaxTrafficSpeed);
if (pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve < 10)
/* Oh hey there Obbe */
debug("fout\n");
printf("fout\n");
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = max(10, pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve);
}
@ -2484,6 +2440,305 @@ void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CBoat* pBoat, float target
*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)
{
return mi == MI_BRIDGELIFT || mi == MI_BRIDGEROADSEGMENT;
@ -2503,4 +2758,12 @@ InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP);
InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
InjectHook(0x41D280, &CCarCtrl::Init, 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

View File

@ -96,6 +96,9 @@ public:
static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
static bool ThisRoadObjectCouldMove(int16);
static void ClearInterestingVehicleList();
static void FindLinksToGoWithTheseNodes(CVehicle*);
static bool GenerateOneEmergencyServicesCar(uint32, CVector);
static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
{

View File

@ -6,5 +6,30 @@ CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
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 CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }

View File

@ -6,7 +6,7 @@ class CFire
{
public:
bool m_bIsOngoing;
bool m_bExists;
bool m_bIsScriptFire;
bool m_bPropogationFlag;
bool m_bAudioSet;
CVector m_vecPos;
@ -16,7 +16,7 @@ public:
int m_nStartTime;
int field_20;
int field_24;
int field_28;
uint32 m_nFiremenPuttingOut;
float field_2C;
void Extinguish(void);
@ -24,8 +24,15 @@ public:
class CFireManager
{
enum {
MAX_FIREMEN_ATTENDING = 2,
};
uint32 m_nTotalFires;
CFire m_aFires[NUM_FIRES];
public:
void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
CFire *FindNearestFire(CVector, float*);
uint32 GetTotalActiveFires() const { return m_nTotalFires; }
};
extern CFireManager &gFireManager;

View File

@ -75,6 +75,9 @@ enum Config {
NUM_CARGENS = 160,
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