2019-08-11 13:11:54 -04:00
|
|
|
#include "common.h"
|
|
|
|
#include "patcher.h"
|
|
|
|
#include "RoadBlocks.h"
|
2020-03-25 10:13:06 -04:00
|
|
|
#include "PathFind.h"
|
2020-04-11 12:45:49 -04:00
|
|
|
#include "ModelIndices.h"
|
|
|
|
#include "Streaming.h"
|
|
|
|
#include "World.h"
|
|
|
|
#include "PedPlacement.h"
|
|
|
|
#include "Automobile.h"
|
|
|
|
#include "CopPed.h"
|
|
|
|
#include "VisibilityPlugins.h"
|
|
|
|
#include "PlayerPed.h"
|
|
|
|
#include "Wanted.h"
|
|
|
|
#include "Camera.h"
|
|
|
|
#include "CarCtrl.h"
|
|
|
|
#include "General.h"
|
2020-03-25 10:13:06 -04:00
|
|
|
|
|
|
|
int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34;
|
|
|
|
int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8;
|
|
|
|
bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810;
|
2019-08-11 13:11:54 -04:00
|
|
|
|
2020-03-25 10:13:06 -04:00
|
|
|
void
|
|
|
|
CRoadBlocks::Init(void)
|
|
|
|
{
|
2020-04-11 12:45:49 -04:00
|
|
|
NumRoadBlocks = 0;
|
|
|
|
for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
|
|
|
|
if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
|
2020-04-13 17:13:00 -04:00
|
|
|
if (NumRoadBlocks < NUMROADBLOCKS) {
|
2020-04-11 12:45:49 -04:00
|
|
|
InOrOut[NumRoadBlocks] = true;
|
|
|
|
RoadBlockObjects[NumRoadBlocks] = objId;
|
|
|
|
NumRoadBlocks++;
|
|
|
|
} else {
|
2020-03-25 10:13:06 -04:00
|
|
|
#ifndef MASTER
|
2020-04-11 12:45:49 -04:00
|
|
|
printf("Not enough room for the potential roadblocks\n");
|
2020-03-25 10:13:06 -04:00
|
|
|
#endif
|
2020-04-11 12:45:49 -04:00
|
|
|
// FIX: Don't iterate loop after NUMROADBLOCKS
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode)
|
|
|
|
{
|
2020-04-11 17:08:16 -04:00
|
|
|
static const CVector vecRoadBlockOffets[6] = { {-1.5, 1.8f, 0.0f}, {-1.5f, -1.8f, 0.0f}, {1.5f, 1.8f, 0.0f},
|
2020-04-11 12:45:49 -04:00
|
|
|
{1.5f, -1.8f, 0.0f}, {-1.5f, 0.0f, 0.0f}, {1.5, 0.0, 0.0} };
|
|
|
|
CEntity* pEntityToAttack = (CEntity*)FindPlayerVehicle();
|
|
|
|
if (!pEntityToAttack)
|
|
|
|
pEntityToAttack = (CEntity*)FindPlayerPed();
|
|
|
|
CColModel* pPoliceColModel = CModelInfo::GetModelInfo(MI_POLICE)->GetColModel();
|
|
|
|
float fRadius = pVehicle->GetBoundRadius() / pPoliceColModel->boundingSphere.radius;
|
|
|
|
for (int32 i = 0; i < 2; i++) {
|
|
|
|
const int32 roadBlockIndex = i + 2 * roadBlockType;
|
|
|
|
CVector posForZ = pVehicle->m_matrix * (fRadius * vecRoadBlockOffets[roadBlockIndex]);
|
2020-04-11 17:08:16 -04:00
|
|
|
int32 modelInfoId = MI_COP;
|
2020-04-11 12:45:49 -04:00
|
|
|
eCopType copType = COP_STREET;
|
|
|
|
switch (pVehicle->GetModelIndex())
|
|
|
|
{
|
|
|
|
case MI_FBICAR:
|
|
|
|
modelInfoId = MI_FBI;
|
|
|
|
copType = COP_FBI;
|
|
|
|
break;
|
|
|
|
case MI_ENFORCER:
|
|
|
|
modelInfoId = MI_SWAT;
|
|
|
|
copType = COP_SWAT;
|
|
|
|
break;
|
|
|
|
case MI_BARRACKS:
|
|
|
|
modelInfoId = MI_ARMY;
|
|
|
|
copType = COP_ARMY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!CStreaming::HasModelLoaded(modelInfoId))
|
|
|
|
copType = COP_STREET;
|
|
|
|
CCopPed* pCopPed = new CCopPed(copType);
|
|
|
|
if (copType == COP_STREET)
|
|
|
|
pCopPed->SetCurrentWeapon(WEAPONTYPE_COLT45);
|
|
|
|
CPedPlacement::FindZCoorForPed(&posForZ);
|
|
|
|
pCopPed->m_matrix.GetPosition() = posForZ;
|
|
|
|
CVector vecSavedPos = pCopPed->m_matrix.GetPosition();
|
|
|
|
pCopPed->m_matrix.SetRotate(0.0f, 0.0f, -HALFPI);
|
|
|
|
pCopPed->m_matrix.GetPosition() += vecSavedPos;
|
|
|
|
pCopPed->m_bIsDisabledCop = true;
|
|
|
|
pCopPed->SetIdle();
|
|
|
|
pCopPed->bKindaStayInSamePlace = true;
|
|
|
|
pCopPed->bNotAllowedToDuck = false;
|
|
|
|
pCopPed->m_wRoadblockNode = roadBlockNode;
|
|
|
|
pCopPed->bCrouchWhenShooting = roadBlockType != 2;
|
|
|
|
if (pEntityToAttack) {
|
|
|
|
pCopPed->m_pPointGunAt = pEntityToAttack;
|
|
|
|
pEntityToAttack->RegisterReference(&pCopPed->m_pPointGunAt);
|
|
|
|
pCopPed->SetAttack(pEntityToAttack);
|
|
|
|
}
|
|
|
|
pCopPed->m_pMyVehicle = pVehicle;
|
|
|
|
pVehicle->RegisterReference((CEntity**)&pCopPed->m_pMyVehicle);
|
|
|
|
pCopPed->bCullExtraFarAway = true;
|
|
|
|
CVisibilityPlugins::SetClumpAlpha(pCopPed->GetClump(), 0);
|
|
|
|
CWorld::Add(pCopPed);
|
|
|
|
}
|
|
|
|
}
|
2020-03-25 10:13:06 -04:00
|
|
|
|
2020-04-11 12:45:49 -04:00
|
|
|
void
|
|
|
|
CRoadBlocks::GenerateRoadBlocks(void)
|
|
|
|
{
|
|
|
|
CMatrix offsetMatrix;
|
2020-04-11 17:08:16 -04:00
|
|
|
uint32 frame = CTimer::GetFrameCounter() & 0xF;
|
2020-04-13 17:13:00 -04:00
|
|
|
int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16;
|
|
|
|
const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16;
|
2020-04-11 12:45:49 -04:00
|
|
|
int16 numRoadBlocks = CRoadBlocks::NumRoadBlocks;
|
|
|
|
if (CRoadBlocks::NumRoadBlocks >= maxRoadBlocks)
|
|
|
|
numRoadBlocks = maxRoadBlocks;
|
|
|
|
for (; nRoadblockNode < numRoadBlocks; nRoadblockNode++) {
|
|
|
|
CTreadable *mapObject = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[nRoadblockNode]];
|
2020-04-13 06:21:39 -04:00
|
|
|
CVector2D vecDistance = FindPlayerCoors() - mapObject->GetPosition();
|
|
|
|
if (vecDistance.x > -80.0f && vecDistance.x < 80.0f &&
|
|
|
|
vecDistance.y > -80.0f && vecDistance.y < 80.0f &&
|
|
|
|
vecDistance.Magnitude() < 80.0f) {
|
|
|
|
if (!CRoadBlocks::InOrOut[nRoadblockNode]) {
|
|
|
|
CRoadBlocks::InOrOut[nRoadblockNode] = true;
|
|
|
|
if (FindPlayerVehicle() && (CGeneral::GetRandomNumber() & 0x7F) < FindPlayerPed()->m_pWanted->m_RoadblockDensity) {
|
|
|
|
CWanted *pPlayerWanted = FindPlayerPed()->m_pWanted;
|
|
|
|
float fMapObjectRadius = 2.0f * mapObject->GetColModel()->boundingBox.max.x;
|
|
|
|
int32 vehicleId = MI_POLICE;
|
|
|
|
if (pPlayerWanted->AreArmyRequired())
|
|
|
|
vehicleId = MI_BARRACKS;
|
|
|
|
else if (pPlayerWanted->AreFbiRequired())
|
|
|
|
vehicleId = MI_FBICAR;
|
|
|
|
else if (pPlayerWanted->AreSwatRequired())
|
|
|
|
vehicleId = MI_ENFORCER;
|
|
|
|
if (!CStreaming::HasModelLoaded(vehicleId))
|
|
|
|
vehicleId = MI_POLICE;
|
|
|
|
CColModel *pVehicleColModel = CModelInfo::GetModelInfo(vehicleId)->GetColModel();
|
|
|
|
float fModelRadius = 2.0f * pVehicleColModel->boundingSphere.radius + 0.25f;
|
|
|
|
int16 radius = (int16)(fMapObjectRadius / fModelRadius);
|
|
|
|
if (radius > 0 && radius < 6) {
|
|
|
|
CVector2D vecDistanceToCamera = TheCamera.GetPosition() - mapObject->m_matrix.GetPosition();
|
|
|
|
float fDotProduct = DotProduct2D(vecDistanceToCamera, mapObject->m_matrix.GetUp());
|
|
|
|
float fOffset = 0.5f * fModelRadius * (float)(radius - 1);
|
|
|
|
for (int16 i = 0; i < radius; i++) {
|
|
|
|
uint8 nRoadblockType = fDotProduct < 0.0f;
|
|
|
|
if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f + HALFPI);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nRoadblockType = !nRoadblockType;
|
|
|
|
offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f - HALFPI);
|
|
|
|
}
|
|
|
|
if (ThePaths.m_objectFlags[CRoadBlocks::RoadBlockObjects[nRoadblockNode]] & ObjectEastWest)
|
|
|
|
offsetMatrix.GetPosition() = CVector(0.0f, -fOffset, 0.6f);
|
|
|
|
else
|
|
|
|
offsetMatrix.GetPosition() = CVector(-fOffset, 0.0f, 0.6f);
|
|
|
|
CMatrix vehicleMatrix = mapObject->m_matrix * offsetMatrix;
|
|
|
|
float fModelRadius = CModelInfo::GetModelInfo(vehicleId)->GetColModel()->boundingSphere.radius - 0.25f;
|
|
|
|
int16 colliding = 0;
|
|
|
|
CWorld::FindObjectsKindaColliding(vehicleMatrix.GetPosition(), fModelRadius, 0, &colliding, 2, nil, false, true, true, false, false);
|
|
|
|
if (!colliding) {
|
|
|
|
CAutomobile *pVehicle = new CAutomobile(vehicleId, RANDOM_VEHICLE);
|
|
|
|
pVehicle->m_status = STATUS_ABANDONED;
|
|
|
|
// pVehicle->GetHeightAboveRoad(); // called but return value is ignored?
|
|
|
|
vehicleMatrix.GetPosition().z += fModelRadius - 0.6f;
|
|
|
|
pVehicle->m_matrix = vehicleMatrix;
|
|
|
|
pVehicle->PlaceOnRoadProperly();
|
|
|
|
pVehicle->bIsStatic = false;
|
|
|
|
pVehicle->m_matrix.UpdateRW();
|
|
|
|
pVehicle->m_nDoorLock = CARLOCK_UNLOCKED;
|
|
|
|
CCarCtrl::JoinCarWithRoadSystem(pVehicle);
|
|
|
|
pVehicle->bIsLocked = false;
|
|
|
|
pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
|
|
|
|
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
|
|
|
|
pVehicle->AutoPilot.m_nCurrentLane = 0;
|
|
|
|
pVehicle->AutoPilot.m_nNextLane = 0;
|
|
|
|
pVehicle->AutoPilot.m_fMaxTrafficSpeed = 0.0f;
|
|
|
|
pVehicle->AutoPilot.m_nCruiseSpeed = 0.0f;
|
|
|
|
pVehicle->bExtendedRange = true;
|
|
|
|
if (pVehicle->UsesSiren(pVehicle->GetModelIndex()) && CGeneral::GetRandomNumber() & 1)
|
|
|
|
pVehicle->m_bSirenOrAlarm = true;
|
|
|
|
if (pVehicle->m_matrix.GetForward().z > 0.94f) {
|
|
|
|
CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0);
|
|
|
|
CWorld::Add(pVehicle);
|
|
|
|
pVehicle->bCreateRoadBlockPeds = true;
|
|
|
|
pVehicle->m_nRoadblockType = nRoadblockType;
|
|
|
|
pVehicle->m_nRoadblockNode = nRoadblockNode;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete pVehicle;
|
|
|
|
}
|
2020-04-12 20:52:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-11 12:45:49 -04:00
|
|
|
}
|
2020-04-13 06:21:39 -04:00
|
|
|
} else {
|
|
|
|
CRoadBlocks::InOrOut[nRoadblockNode] = false;
|
2020-04-11 12:45:49 -04:00
|
|
|
}
|
|
|
|
}
|
2020-03-25 10:13:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
STARTPATCHES
|
|
|
|
InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
|
2020-04-11 12:45:49 -04:00
|
|
|
InjectHook(0x4376A0, &CRoadBlocks::GenerateRoadBlockCopsForCar, PATCH_JUMP);
|
|
|
|
InjectHook(0x436FA0, &CRoadBlocks::GenerateRoadBlocks, PATCH_JUMP);
|
2020-03-25 10:13:06 -04:00
|
|
|
ENDPATCHES
|