summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/control/CarAI.cpp1
-rw-r--r--src/control/CarCtrl.cpp44
-rw-r--r--src/control/Script.cpp6
-rw-r--r--src/control/SetPieces.cpp319
-rw-r--r--src/control/SetPieces.h48
-rw-r--r--src/core/Game.cpp4
-rw-r--r--src/core/config.h2
-rw-r--r--src/peds/Ped.cpp1
-rw-r--r--src/peds/Ped.h1
-rw-r--r--src/vehicles/Vehicle.cpp1
-rw-r--r--src/vehicles/Vehicle.h1
11 files changed, 425 insertions, 3 deletions
diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp
index a4406da9..589cc53b 100644
--- a/src/control/CarAI.cpp
+++ b/src/control/CarAI.cpp
@@ -350,6 +350,7 @@ void CCarAI::UpdateCarAI(CVehicle* pVehicle)
if (!FindPlayerVehicle() || DotProduct2D(CVector2D(diff.x / distance, diff.y / distance), FindPlayerSpeed()) > 0.05f)
pVehicle->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_CLOSE;
BackToCruisingIfNoWantedLevel(pVehicle);
+ break;
}
default:
if (pVehicle->bIsLawEnforcer && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && !CCullZones::NoPolice()){
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index b250cb97..5e8324ed 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -971,7 +971,8 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle)
pVehicle->GetModelIndex() == MI_AMBULAN ||
pVehicle->GetModelIndex() == MI_FIRETRUCK ||
pVehicle->bIsLawEnforcer ||
- pVehicle->bIsCarParkVehicle
+ pVehicle->bIsCarParkVehicle ||
+ CTimer::GetTimeInMilliseconds() < pVehicle->m_nSetPieceExtendedRangeTime
){
threshold = ONSCREEN_DESPAWN_RANGE * TheCamera.GenerationDistMultiplier;
}
@@ -2515,7 +2516,7 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe
pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_BLOCKPLAYER_FORWARDANDBACK:
- //SteerAICarBlockingPlayerForwardAndBack(pVehicle, pSwerve, pAccel, pBrake, pHandbrake);
+ SteerAICarBlockingPlayerForwardAndBack(pVehicle, pSwerve, pAccel, pBrake, pHandbrake);
return;
default:
assert(0);
@@ -2523,6 +2524,45 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe
}
}
+void CCarCtrl::SteerAICarBlockingPlayerForwardAndBack(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+ *pSwerve = 0.0f;
+ *pHandbrake = false;
+ CVector player = FindPlayerSpeed() + 0.1f * FindPlayerEntity()->GetForward();
+ player.z = 0.0f;
+ CVector right(pVehicle->GetRight().x, pVehicle->GetRight().y, 0.0f);
+ right.Normalise();
+ CVector forward(pVehicle->GetForward().x, pVehicle->GetForward().y, 0.0f);
+ forward.Normalise();
+ float dpPlayerAndRight = DotProduct(player, right);
+ if (dpPlayerAndRight == 0.0f)
+ dpPlayerAndRight = 0.01f;
+ float dpDiffAndRight = -DotProduct((FindPlayerCoors() - pVehicle->GetPosition()), right) / dpPlayerAndRight;
+ if (dpDiffAndRight < 0.0f) {
+ *pAccel = 0.0f;
+ *pBrake = 0.0f;
+ return;
+ }
+ float dpSpeedAndForward = DotProduct(pVehicle->GetMoveSpeed(), forward);
+ float dpPlayerAndForward = DotProduct(player, forward);
+ float dpDiffAndForward = DotProduct((FindPlayerCoors() - pVehicle->GetPosition()), forward);
+ float multiplier = dpPlayerAndForward * dpDiffAndRight + dpDiffAndForward - dpSpeedAndForward * dpDiffAndRight;
+ if (multiplier > 0) {
+ *pAccel = Min(1.0f, 0.1f * multiplier);
+ *pBrake = 0.0f;
+ }
+ else if (dpSpeedAndForward > 0) {
+ *pAccel = 0.0f;
+ *pBrake = Min(1.0f, -0.1f * multiplier);
+ if (*pBrake > 0.95f)
+ *pHandbrake = true;
+ }
+ else {
+ *pAccel = Max(-1.0f, 0.1f * multiplier);
+ *pBrake = 0.0f;
+ }
+}
+
void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CVehicle* pVehicle, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake)
{
CVector2D forward = pVehicle->GetForward();
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 4350d08b..e029ad35 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -59,6 +59,7 @@
#include "RpAnimBlend.h"
#include "Rubbish.h"
#include "SimpleModelInfo.h"
+#include "SetPieces.h"
#include "Shadows.h"
#include "SpecialFX.h"
#include "Sprite.h"
@@ -10900,7 +10901,10 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
case COMMAND_ADD_SET_PIECE:
{
CollectParameters(&m_nIp, 13);
- debug("ADD_SET_PIECE not implemented, skipping\n");
+ CSetPieces::AddOne(ScriptParams[0],
+ *(CVector2D*)&ScriptParams[1], *(CVector2D*)&ScriptParams[3],
+ *(CVector2D*)&ScriptParams[5], *(CVector2D*)&ScriptParams[7],
+ *(CVector2D*)&ScriptParams[9], *(CVector2D*)&ScriptParams[11]);
return 0;
}
case COMMAND_SET_EXTRA_COLOURS:
diff --git a/src/control/SetPieces.cpp b/src/control/SetPieces.cpp
new file mode 100644
index 00000000..fb2a1f14
--- /dev/null
+++ b/src/control/SetPieces.cpp
@@ -0,0 +1,319 @@
+#include "common.h"
+
+#include "SetPieces.h"
+#include "Automobile.h"
+#include "CarAI.h"
+#include "CopPed.h"
+#include "GenericGameStorage.h"
+#include "PlayerPed.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "Wanted.h"
+#include "World.h"
+
+#define TIME_BETWEEN_SETPIECE_SPAWNS 20000
+
+// MIAMI: file done
+
+bool CSetPieces::bDebug;
+uint32 CSetPieces::NumSetPieces;
+CSetPiece CSetPieces::aSetPieces[NUM_SETPIECES];
+
+void CSetPieces::Init(void)
+{
+ bDebug = false;
+ NumSetPieces = 0;
+}
+
+void CSetPieces::AddOne(uint8 type, CVector2D vTriggerInf, CVector2D vTriggerSup, CVector2D vSpawn1, CVector2D vTarget1, CVector2D vSpawn2, CVector2D vTarget2)
+{
+ if (NumSetPieces >= NUM_SETPIECES)
+ return;
+ aSetPieces[NumSetPieces].m_nType = (eSetPieceType)type;
+ aSetPieces[NumSetPieces].m_vTriggerInf.x = Min(vTriggerInf.x, vTriggerSup.x);
+ aSetPieces[NumSetPieces].m_vTriggerInf.y = Min(vTriggerInf.y, vTriggerSup.y);
+ aSetPieces[NumSetPieces].m_vTriggerSup.x = Max(vTriggerInf.x, vTriggerSup.x);
+ aSetPieces[NumSetPieces].m_vTriggerSup.y = Max(vTriggerInf.y, vTriggerSup.y);
+ aSetPieces[NumSetPieces].m_vSpawn1 = vSpawn1;
+ aSetPieces[NumSetPieces].m_vSpawn2 = vSpawn2;
+ aSetPieces[NumSetPieces].m_vTarget1 = vTarget1;
+ aSetPieces[NumSetPieces].m_vTarget2 = vTarget2;
+ ++NumSetPieces;
+}
+
+void CSetPieces::Update(void)
+{
+ int nFirst = NumSetPieces * (CTimer::GetFrameCounter() % 8) / 8;
+ int nLast = NumSetPieces * (CTimer::GetFrameCounter() % 8 + 1) / 8;
+ for (int i = nFirst; i < nLast; i++)
+ aSetPieces[i].Update();
+}
+
+void CSetPieces::Save(uint8* buf, uint32* size)
+{
+INITSAVEBUF
+ WriteSaveBuf(buf, NumSetPieces);
+ for (int i = 0; i < NUM_SETPIECES; i++)
+ WriteSaveBuf(buf, aSetPieces[i]);
+ *size = sizeof(NumSetPieces) + NUM_SETPIECES * sizeof(CSetPiece);
+VALIDATESAVEBUF(*size)
+}
+
+void CSetPieces::Load(uint8* buf, uint32 size)
+{
+INITSAVEBUF
+ NumSetPieces = ReadSaveBuf<uint32>(buf);
+ for (int i = 0; i < NUM_SETPIECES; i++)
+ aSetPieces[i] = ReadSaveBuf<CSetPiece>(buf);
+VALIDATESAVEBUF(size)
+}
+
+void CSetPiece::Update(void)
+{
+ if (m_nLastTimeCreated != 0 && CTimer::GetTimeInMilliseconds() <= m_nLastTimeCreated + TIME_BETWEEN_SETPIECE_SPAWNS)
+ return;
+ CVector pos = FindPlayerCoors();
+ if (pos.x < m_vTriggerInf.x || pos.x > m_vTriggerSup.x ||
+ pos.y < m_vTriggerInf.y || pos.y > m_vTriggerSup.y)
+ return;
+ switch (m_nType) {
+ case SETPIECE_TWOCOPCARSINALLEY:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 1 || FindPlayerVehicle())
+ return;
+ CVehicle* pVehicle1 = TryToGenerateCopCar(m_vSpawn1, m_vTarget1);
+ if (!pVehicle1)
+ return;
+ CVehicle* pVehicle2 = TryToGenerateCopCar(m_vSpawn2, m_vTarget2);
+ if (!pVehicle2) {
+ CWorld::Remove(pVehicle1);
+ delete pVehicle1;
+ return;
+ }
+ pVehicle1->SetStatus(STATUS_PHYSICS);
+ pVehicle1->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 4;
+ pVehicle1->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_SLOW_DOWN_FOR_CARS;
+ pVehicle1->AutoPilot.m_nCarMission = MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_1;
+ pVehicle1->AutoPilot.m_vecDestinationCoors.x = m_vTarget1.x;
+ pVehicle1->AutoPilot.m_vecDestinationCoors.y = m_vTarget1.y;
+ pVehicle1->AutoPilot.m_vecDestinationCoors.z = 0.0f;
+ pVehicle1->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 25000;
+ CCarAI::AddPoliceCarOccupants(pVehicle1);
+ pVehicle2->SetStatus(STATUS_PHYSICS);
+ pVehicle2->AutoPilot.m_fMaxTrafficSpeed = pVehicle2->AutoPilot.m_nCruiseSpeed = 4;
+ pVehicle2->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_SLOW_DOWN_FOR_CARS;
+ pVehicle2->AutoPilot.m_nCarMission = MISSION_SLOWLY_DRIVE_TOWARDS_PLAYER_1;
+ pVehicle2->AutoPilot.m_vecDestinationCoors.x = m_vTarget2.x;
+ pVehicle2->AutoPilot.m_vecDestinationCoors.y = m_vTarget2.y;
+ pVehicle2->AutoPilot.m_vecDestinationCoors.z = 0.0f;
+ pVehicle2->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 25000;
+ CCarAI::AddPoliceCarOccupants(pVehicle2);
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ break;
+ }
+ case SETPIECE_CARBLOCKINGPLAYERFROMSIDE:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 2)
+ return;
+ if (!FindPlayerVehicle())
+ return;
+ if (DotProduct2D(FindPlayerSpeed(), (CVector2D)FindPlayerCoors() - m_vSpawn1) >= 0.0f)
+ return;
+ CVehicle* pVehicle1 = TryToGenerateCopCar(m_vSpawn1, m_vTarget1);
+ if (!pVehicle1)
+ return;
+ pVehicle1->SetStatus(STATUS_PHYSICS);
+ pVehicle1->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle1->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
+ pVehicle1->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_FORWARDANDBACK;
+ pVehicle1->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle1->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle1->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle1->SetMoveSpeed(2.0f * pVehicle1->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle1);
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ case SETPIECE_CARRAMMINGPLAYERFROMSIDE:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 2)
+ return;
+ if (!FindPlayerVehicle())
+ return;
+ if (DotProduct2D(FindPlayerSpeed(), (CVector2D)FindPlayerCoors() - m_vSpawn1) >= 0.0f)
+ return;
+ CVehicle* pVehicle1 = TryToGenerateCopCar(m_vSpawn1, m_vTarget1);
+ if (!pVehicle1)
+ return;
+ pVehicle1->SetStatus(STATUS_PHYSICS);
+ pVehicle1->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle1->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+ pVehicle1->AutoPilot.m_nCarMission = MISSION_RAMCAR_CLOSE;
+ pVehicle1->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle1->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle1->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle1->SetMoveSpeed(2.0f * pVehicle1->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle1);
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ case SETPIECE_CREATECOPPERONFOOT:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 1 || FindPlayerVehicle())
+ return;
+ CCopPed* pCop = TryToGenerateCopPed(m_vSpawn1);
+ if (!pCop)
+ return;
+ float z = CWorld::FindGroundZForCoord(m_vTarget1.x, m_vTarget1.y);
+ pCop->bScriptObjectiveCompleted = false;
+ pCop->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, CVector(m_vTarget1.x, m_vTarget1.y, z));
+ pCop->m_nExtendedRangeTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ case SETPIECE_CREATETWOCOPPERSONFOOT:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 1 || FindPlayerVehicle())
+ return;
+ CCopPed* pCop = TryToGenerateCopPed(m_vSpawn1);
+ if (!pCop)
+ return;
+ float z = CWorld::FindGroundZForCoord(m_vTarget1.x, m_vTarget1.y);
+ pCop->bScriptObjectiveCompleted = false;
+ pCop->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, CVector(m_vTarget1.x, m_vTarget1.y, z));
+ pCop->m_nExtendedRangeTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ CCopPed* pCop2 = TryToGenerateCopPed(m_vSpawn2);
+ if (!pCop2) {
+ CWorld::Remove(pCop);
+ delete pCop;
+ return;
+ }
+ z = CWorld::FindGroundZForCoord(m_vTarget2.x, m_vTarget2.y);
+ pCop2->bScriptObjectiveCompleted = false;
+ pCop2->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, CVector(m_vTarget2.x, m_vTarget2.y, z));
+ pCop2->m_nExtendedRangeTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ case SETPIECE_TWOCARSBLOCKINGPLAYERFROMSIDE:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 2)
+ return;
+ if (!FindPlayerVehicle())
+ return;
+ if (DotProduct2D(FindPlayerSpeed(), (CVector2D)FindPlayerCoors() - m_vSpawn1) >= 0.0f)
+ return;
+ CVehicle* pVehicle1 = TryToGenerateCopCar(m_vSpawn1, m_vTarget1);
+ if (!pVehicle1)
+ return;
+ pVehicle1->SetStatus(STATUS_PHYSICS);
+ pVehicle1->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle1->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
+ pVehicle1->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_FORWARDANDBACK;
+ pVehicle1->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle1->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle1->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle1->SetMoveSpeed(2.0f * pVehicle1->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle1);
+ CVehicle* pVehicle2 = TryToGenerateCopCar(m_vSpawn2, m_vTarget2);
+ if (!pVehicle2) {
+ CWorld::Remove(pVehicle1);
+ delete pVehicle1;
+ return;
+ }
+ pVehicle2->SetStatus(STATUS_PHYSICS);
+ pVehicle2->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle2->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
+ pVehicle2->AutoPilot.m_nCarMission = MISSION_BLOCKPLAYER_FORWARDANDBACK;
+ pVehicle2->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle2->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle2->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle2->SetMoveSpeed(2.0f * pVehicle2->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle2);
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ case SETPIECE_TWOCARSRAMMINGPLAYERFROMSIDE:
+ {
+ if (FindPlayerPed()->m_pWanted->m_nWantedLevel < 2)
+ return;
+ if (!FindPlayerVehicle())
+ return;
+ if (DotProduct2D(FindPlayerSpeed(), (CVector2D)FindPlayerCoors() - m_vSpawn1) >= 0.0f)
+ return;
+ CVehicle* pVehicle1 = TryToGenerateCopCar(m_vSpawn1, m_vTarget1);
+ if (!pVehicle1)
+ return;
+ pVehicle1->SetStatus(STATUS_PHYSICS);
+ pVehicle1->AutoPilot.m_fMaxTrafficSpeed = pVehicle1->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle1->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+ pVehicle1->AutoPilot.m_nCarMission = MISSION_RAMCAR_CLOSE;
+ pVehicle1->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle1->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle1->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle1->SetMoveSpeed(2.0f * pVehicle1->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle1);
+ CVehicle* pVehicle2 = TryToGenerateCopCar(m_vSpawn2, m_vTarget2);
+ if (!pVehicle2) {
+ CWorld::Remove(pVehicle2);
+ delete pVehicle2;
+ return;
+ }
+ pVehicle2->SetStatus(STATUS_PHYSICS);
+ pVehicle2->AutoPilot.m_fMaxTrafficSpeed = pVehicle2->AutoPilot.m_nCruiseSpeed = 16;
+ pVehicle2->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+ pVehicle2->AutoPilot.m_nCarMission = MISSION_RAMCAR_CLOSE;
+ pVehicle2->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+ pVehicle2->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 100;
+ pVehicle2->m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 10000;
+ pVehicle2->SetMoveSpeed(2.0f * pVehicle2->GetForward() / 3.0f);
+ CCarAI::AddPoliceCarOccupants(pVehicle2);
+ m_nLastTimeCreated = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ }
+}
+
+CVehicle* CSetPiece::TryToGenerateCopCar(CVector2D vSpawn, CVector2D vTarget)
+{
+ CVehicle* pVehicle = new CAutomobile(MI_POLICE, RANDOM_VEHICLE);
+ CVector pos(vSpawn.x, vSpawn.y, 1000.0f);
+ CColPoint point;
+ CEntity* pEntity;
+ if (CWorld::ProcessVerticalLine(pos, -1000.0f, point, pEntity, true, false, false, false, true, false, nil))
+ pos.z = point.point.z + pVehicle->GetHeightAboveRoad();
+ CVector vDirection(vTarget.x - vSpawn.x, vTarget.y - vSpawn.y, 0.0f);
+ vDirection.Normalise();
+ pVehicle->GetForward() = CVector(vDirection.x, vDirection.y, 0.0f);
+ pVehicle->GetRight() = CVector(vDirection.y, -vDirection.x, 0.0f);
+ pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f);
+ pVehicle->SetPosition(pos);
+ int16 total;
+ CWorld::FindObjectsKindaColliding(pos, pVehicle->GetColModel()->spheres->radius, false, &total, 16, nil, false, true, true, false, false);
+ if (total != 0) {
+ delete pVehicle;
+ return nil;
+ }
+ pVehicle->ChangeLawEnforcerState(true);
+ CWorld::Add(pVehicle);
+ return pVehicle;
+}
+
+CCopPed* CSetPiece::TryToGenerateCopPed(CVector2D vSpawn)
+{
+ CCopPed* pCop = new CCopPed(COP_STREET);
+ CVector pos(vSpawn.x, vSpawn.y, 1000.0f);
+ CColPoint point;
+ CEntity* pEntity;
+ if (CWorld::ProcessVerticalLine(pos, -1000.0f, point, pEntity, true, false, false, false, true, false, nil))
+ pos.z = point.point.z + 0.9f;
+ pCop->SetPosition(pos);
+ int16 total;
+ CWorld::FindObjectsKindaColliding(pos, pCop->GetColModel()->spheres->radius, false, &total, 16, nil, false, true, true, false, false);
+ if (total != 0) {
+ delete pCop;
+ return nil;
+ }
+ CWorld::Add(pCop);
+ return pCop;
+} \ No newline at end of file
diff --git a/src/control/SetPieces.h b/src/control/SetPieces.h
new file mode 100644
index 00000000..5776d35a
--- /dev/null
+++ b/src/control/SetPieces.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "config.h"
+
+class CVehicle;
+class CCopPed;
+
+enum eSetPieceType : uint8
+{
+ SETPIECE_NONE = 0,
+ SETPIECE_TWOCOPCARSINALLEY,
+ SETPIECE_CARBLOCKINGPLAYERFROMSIDE,
+ SETPIECE_CARRAMMINGPLAYERFROMSIDE,
+ SETPIECE_CREATECOPPERONFOOT,
+ SETPIECE_CREATETWOCOPPERSONFOOT,
+ SETPIECE_TWOCARSBLOCKINGPLAYERFROMSIDE,
+ SETPIECE_TWOCARSRAMMINGPLAYERFROMSIDE
+};
+
+class CSetPiece
+{
+public:
+ eSetPieceType m_nType;
+ uint32 m_nLastTimeCreated;
+ CVector2D m_vTriggerInf;
+ CVector2D m_vTriggerSup;
+ CVector2D m_vSpawn1;
+ CVector2D m_vSpawn2;
+ CVector2D m_vTarget1;
+ CVector2D m_vTarget2;
+
+ CVehicle* TryToGenerateCopCar(CVector2D, CVector2D);
+ CCopPed* TryToGenerateCopPed(CVector2D);
+ void Update(void);
+};
+
+class CSetPieces
+{
+ static bool bDebug;
+ static uint32 NumSetPieces;
+ static CSetPiece aSetPieces[NUM_SETPIECES];
+public:
+ static void Init(void);
+ static void AddOne(uint8 type, CVector2D, CVector2D, CVector2D, CVector2D, CVector2D, CVector2D);
+ static void Save(uint8*, uint32*);
+ static void Load(uint8*, uint32);
+ static void Update(void);
+};
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index 437bd5ec..02648b27 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -64,6 +64,7 @@
#include "Script.h"
#include "Shadows.h"
#include "Skidmarks.h"
+#include "SetPieces.h"
#include "SpecialFX.h"
#include "Sprite2d.h"
#include "Stats.h"
@@ -275,6 +276,7 @@ bool CGame::Initialise(const char* datFile)
CCullZones::Init();
COcclusion::Init();
CCollision::Init();
+ CSetPieces::Init();
CTheZones::Init();
CUserDisplay::Init();
CMessages::Init();
@@ -529,6 +531,7 @@ void CGame::ShutDownForRestart(void)
CRadar::RemoveRadarSections();
FrontEndMenuManager.UnloadTextures();
CParticleObject::RemoveAllParticleObjects();
+ CSetPieces::Init();
CPedType::Shutdown();
CSpecialFX::Shutdown();
TidyUpMemory(true, false);
@@ -622,6 +625,7 @@ void CGame::Process(void)
CAntennas::Update();
CGlass::Update();
CSceneEdit::Update();
+ CSetPieces::Update();
CEventList::Update();
CParticle::Update();
gFireManager.Update();
diff --git a/src/core/config.h b/src/core/config.h
index 294dafbc..ea31a3c8 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -135,6 +135,8 @@ enum Config {
NUM_CRANES = 8,
NUM_EXPLOSIONS = 48,
+
+ NUM_SETPIECES = 96
};
// We'll use this once we're ready to become independent of the game
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index d5659a4a..7eb2491b 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -673,6 +673,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_nPedMoney = random % 25;
if (m_nPedMoney == 23)
m_nPedMoney = 400;
+ m_nExtendedRangeTimer = 0;
m_bleedCounter = 0;
#ifdef PED_SKIN
m_pWeaponModel = nil;
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 2a774f9a..776aa1dd 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -523,6 +523,7 @@ public:
CPathNode *m_pNextPathNode;
float m_fHealth;
float m_fArmour;
+ uint32 m_nExtendedRangeTimer;
int16 m_routeLastPoint;
uint16 m_routeStartPoint;
int16 m_routePointsPassed;
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 5ac69905..f07b633c 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -110,6 +110,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
bTyresDontBurst = false;
bCreatedAsPoliceVehicle = false;
bParking = false;
+ m_nSetPieceExtendedRangeTime = 0;
m_nAlarmState = 0;
m_nDoorLock = CARLOCK_UNLOCKED;
m_nLastWeaponDamage = -1;
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 9ec48850..7b5a1e11 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -201,6 +201,7 @@ public:
float m_fChangeGearTime;
CEntity* m_pBombRigger;
uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats)
+ uint32 m_nSetPieceExtendedRangeTime;
uint32 m_nTimeOfDeath;
uint16 m_nTimeBlocked;
int16 m_nBombTimer; // goes down with each frame