summaryrefslogtreecommitdiffstats
path: root/src/control
diff options
context:
space:
mode:
Diffstat (limited to 'src/control')
-rw-r--r--src/control/AutoPilot.cpp16
-rw-r--r--src/control/CarCtrl.cpp146
-rw-r--r--src/control/CarGen.cpp312
-rw-r--r--src/control/CarGen.h56
-rw-r--r--src/control/Cranes.cpp14
-rw-r--r--src/control/Cranes.h61
-rw-r--r--src/control/GameLogic.cpp572
-rw-r--r--src/control/GameLogic.h24
-rw-r--r--src/control/Gangs.cpp89
-rw-r--r--src/control/Gangs.h44
-rw-r--r--src/control/Garages.cpp49
-rw-r--r--src/control/Garages.h1
-rw-r--r--src/control/OnscreenTimer.h96
-rw-r--r--src/control/PathFind.cpp167
-rw-r--r--src/control/PathFind.h12
-rw-r--r--src/control/Pickups.cpp2501
-rw-r--r--src/control/Pickups.h271
-rw-r--r--src/control/PowerPoints.cpp42
-rw-r--r--src/control/PowerPoints.h50
-rw-r--r--src/control/Record.cpp526
-rw-r--r--src/control/Record.h90
-rw-r--r--src/control/Replay.cpp8
-rw-r--r--src/control/Restart.cpp434
-rw-r--r--src/control/RoadBlocks.cpp200
-rw-r--r--src/control/RoadBlocks.h2
-rw-r--r--src/control/Script.cpp34
-rw-r--r--src/control/Script.h31
-rw-r--r--src/control/TrafficLights.cpp334
-rw-r--r--src/control/TrafficLights.h7
29 files changed, 3628 insertions, 2561 deletions
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
index 70099291..b5bca21d 100644
--- a/src/control/AutoPilot.cpp
+++ b/src/control/AutoPilot.cpp
@@ -12,17 +12,17 @@ void CAutoPilot::ModifySpeed(float speed)
float positionBetweenNodes = (float)(CTimer::GetTimeInMilliseconds() - m_nTimeEnteredCurve) / m_nTimeToSpendOnCurrentCurve;
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[m_nNextPathNodeInfo];
- float currentPathLinkForwardX = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dirX;
- float currentPathLinkForwardY = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dirY;
- float nextPathLinkForwardX = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dirX;
- float nextPathLinkForwardY = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dirY;
+ float currentPathLinkForwardX = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dir.x;
+ float currentPathLinkForwardY = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dir.y;
+ float nextPathLinkForwardX = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dir.x;
+ float nextPathLinkForwardY = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dir.y;
CVector positionOnCurrentLinkIncludingLane(
- pCurrentLink->posX + ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardY,
- pCurrentLink->posY - ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurrentLink->pos.x + ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardY,
+ pCurrentLink->pos.y - ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f);
m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 3174a253..264f1f3f 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -90,7 +90,7 @@ uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(ui
void
CCarCtrl::GenerateRandomCars()
{
- if (CCutsceneMgr::IsCutsceneProcessing())
+ if (CCutsceneMgr::IsRunning())
return;
if (NumRandomCars < 30){
if (CountDownToCarsAtStart == 0){
@@ -393,25 +393,25 @@ CCarCtrl::GenerateOneRandomCar()
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;
+ float currentPathLinkForwardX = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dir.x;
+ float currentPathLinkForwardY = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dir.y;
+ float nextPathLinkForwardX = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dir.x;
+ float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dir.y;
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
CVector positionOnCurrentLinkIncludingLane(
- pCurrentLink->posX + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
- pCurrentLink->posY - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurrentLink->pos.x + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+ pCurrentLink->pos.y - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * 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;
+ float directionCurrentLinkX = pCurrentLink->dir.x * pCar->AutoPilot.m_nCurrentDirection;
+ float directionCurrentLinkY = pCurrentLink->dir.y * pCar->AutoPilot.m_nCurrentDirection;
+ float directionNextLinkX = pNextLink->dir.x * pCar->AutoPilot.m_nNextDirection;
+ float directionNextLinkY = pNextLink->dir.y * 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_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
@@ -763,17 +763,17 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
return;
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
- float currentPathLinkForwardX = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
- float currentPathLinkForwardY = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
- float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ float currentPathLinkForwardX = pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+ float currentPathLinkForwardY = pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+ float nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ float nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
CVector positionOnCurrentLinkIncludingLane(
- pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
- pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+ pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f);
CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f);
CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f);
@@ -1553,8 +1553,8 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
pVehicle->AutoPilot.m_nNextDirection = -1;
lanesOnNextNode = pNextLink->numRightLanes;
}
- float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
- float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
+ float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+ float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
if (lanesOnNextNode >= 0){
if ((CGeneral::GetRandomNumber() & 0x600) == 0){
/* 25% chance vehicle will try to switch lane */
@@ -1574,17 +1574,17 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane(
- pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
- pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
+ pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
- pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
+ pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f);
- float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
/* We want to make a path between two links that may not have the same forward directions a curve. */
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
@@ -1725,10 +1725,10 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
pVehicle->AutoPilot.m_nNextDirection = -1;
lanesOnNextNode = pNextLink->numRightLanes;
}
- float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
- float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirY;
- float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
- float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirY;
+ float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+ float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.y;
+ float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
+ float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.y;
if (lanesOnNextNode >= 0) {
CVector2D dist = pNextPathNode->pos - pCurNode->pos;
if (dist.MagnitudeSqr() >= SQR(7.0f)){
@@ -1755,17 +1755,17 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane(
- pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
- pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+ pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f);
- float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
/* We want to make a path between two links that may not have the same forward directions a curve. */
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
@@ -1814,10 +1814,10 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
pVehicle->AutoPilot.m_nNextDirection = -1;
lanesOnNextNode = pNextLink->numRightLanes;
}
- float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
- float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirY;
- float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
- float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirY;
+ float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+ float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.y;
+ float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
+ float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.y;
if (lanesOnNextNode >= 0) {
CVector2D dist = pNextPathNode->pos - pCurNode->pos;
if (dist.MagnitudeSqr() >= SQR(7.0f) && (CGeneral::GetRandomNumber() & 0x600) == 0) {
@@ -1835,17 +1835,17 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane(
- pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
- pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+ pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+ pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+ pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f);
- float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
- float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+ float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
/* We want to make a path between two links that may not have the same forward directions a curve. */
pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
@@ -2192,16 +2192,16 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
forward.Normalise();
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
- CVector2D currentPathLinkForward(pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection,
- pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection);
- float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ CVector2D currentPathLinkForward(pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection,
+ pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection);
+ float nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ float nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
CVector2D positionOnCurrentLinkIncludingLane(
- pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
- pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+ pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+ pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
CVector2D positionOnNextLinkIncludingLane(
- pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
- pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
+ pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+ pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
CVector2D distanceToNextNode = (CVector2D)pVehicle->GetPosition() - positionOnCurrentLinkIncludingLane;
float scalarDistanceToNextNode = distanceToNextNode.Magnitude();
CVector2D distanceBetweenNodes = positionOnNextLinkIncludingLane - positionOnCurrentLinkIncludingLane;
@@ -2230,16 +2230,16 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
}
pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
scalarDistanceToNextNode = CVector2D(
- pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
- pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();
+ pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
+ pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();
pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
- currentPathLinkForward.x = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
- currentPathLinkForward.y = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
- nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
- nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ currentPathLinkForward.x = pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+ currentPathLinkForward.y = pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+ nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+ nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
}
- positionOnCurrentLinkIncludingLane.x = pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
- positionOnCurrentLinkIncludingLane.y = pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
+ positionOnCurrentLinkIncludingLane.x = pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
+ positionOnCurrentLinkIncludingLane.y = pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
CVector2D projectedPosition = positionOnCurrentLinkIncludingLane - currentPathLinkForward * scalarDistanceToNextNode * 0.4f;
if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN){
projectedPosition.x = positionOnCurrentLinkIncludingLane.x;
@@ -2281,8 +2281,8 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
CCarAI::CarHasReasonToStop(pVehicle);
speedStyleMultiplier = 0.0f;
}
- CVector2D trajectory(pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
- pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+ CVector2D trajectory(pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+ pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
trajectory -= pVehicle->GetPosition();
float speedAngleMultiplier = FindSpeedMultiplier(
CGeneral::GetATanOfXY(trajectory.x, trajectory.y) - angleForward,
diff --git a/src/control/CarGen.cpp b/src/control/CarGen.cpp
deleted file mode 100644
index 49a96f50..00000000
--- a/src/control/CarGen.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-#include "common.h"
-#include "patcher.h"
-#include "CarGen.h"
-
-#include "Automobile.h"
-#include "Boat.h"
-#include "Camera.h"
-#include "CarCtrl.h"
-#include "CutsceneMgr.h"
-#include "General.h"
-#include "Pools.h"
-#include "Streaming.h"
-#include "Timer.h"
-#include "Vehicle.h"
-#include "World.h"
-
-uint8 &CTheCarGenerators::ProcessCounter = *(uint8*)0x95CDAF;
-uint32 &CTheCarGenerators::NumOfCarGenerators = *(uint32*)0x8E2C1C;
-CCarGenerator (&CTheCarGenerators::CarGeneratorArray)[NUM_CARGENS] = *(CCarGenerator(*)[NUM_CARGENS])*(uintptr*)0x87CB18;
-uint8 &CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = *(uint8*)0x95CDC6;
-uint32 &CTheCarGenerators::CurrentActiveCount = *(uint32*)0x8F2C5C;
-
-void CCarGenerator::SwitchOff()
-{
- m_nUsesRemaining = 0;
- --CTheCarGenerators::CurrentActiveCount;
-}
-
-void CCarGenerator::SwitchOn()
-{
- m_nUsesRemaining = -1;
- m_nTimer = CalcNextGen();
- ++CTheCarGenerators::CurrentActiveCount;
-}
-
-uint32 CCarGenerator::CalcNextGen()
-{
- return CTimer::GetTimeInMilliseconds() + 4;
-}
-
-void CCarGenerator::DoInternalProcessing()
-{
- if (CheckForBlockage()) {
- m_nTimer += 4;
- if (m_nUsesRemaining == 0)
- --CTheCarGenerators::CurrentActiveCount;
- return;
- }
- if (CCarCtrl::NumParkedCars >= 10)
- return;
- CStreaming::RequestModel(m_nModelIndex, STREAMFLAGS_DEPENDENCY);
- if (!CStreaming::HasModelLoaded(m_nModelIndex))
- return;
- if (CModelInfo::IsBoatModel(m_nModelIndex)){
- CBoat* pBoat = new CBoat(m_nModelIndex, PARKED_VEHICLE);
- pBoat->bIsStatic = false;
- pBoat->bEngineOn = false;
- CVector pos = m_vecPos;
- if (pos.z <= -100.0f)
- pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
- pos.z += pBoat->GetDistanceFromCentreOfMassToBaseOfModel();
- pBoat->GetPosition() = pos;
- pBoat->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
- pBoat->m_status = STATUS_ABANDONED;
- pBoat->m_nDoorLock = CARLOCK_UNLOCKED;
- CWorld::Add(pBoat);
- if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
- pBoat->m_nAlarmState = -1;
- if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
- pBoat->m_nDoorLock = CARLOCK_LOCKED;
- if (m_nColor1 != -1 && m_nColor2){
- pBoat->m_currentColour1 = m_nColor1;
- pBoat->m_currentColour2 = m_nColor2;
- }
- m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pBoat);
- }else{
- bool groundFound = false;
- CVector pos = m_vecPos;
- if (pos.z > -100.0f){
- pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &groundFound);
- }else{
- CColPoint cp;
- CEntity* pEntity;
- groundFound = CWorld::ProcessVerticalLine(CVector(pos.x, pos.y, 1000.0f), -1000.0f,
- cp, pEntity, true, false, false, false, false, false, nil);
- if (groundFound)
- pos.z = cp.point.z;
- }
- if (!groundFound) {
- debug("CCarGenerator::DoInternalProcessing - can't find ground z for new car x = %f y = %f \n", m_vecPos.x, m_vecPos.y);
- }else{
- CAutomobile* pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE);
- pCar->bIsStatic = false;
- pCar->bEngineOn = false;
- pos.z += pCar->GetDistanceFromCentreOfMassToBaseOfModel();
- pCar->GetPosition() = pos;
- pCar->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
- pCar->m_status = STATUS_ABANDONED;
- pCar->bLightsOn = false;
- pCar->m_nDoorLock = CARLOCK_UNLOCKED;
- CWorld::Add(pCar);
- if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
- pCar->m_nAlarmState = -1;
- if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
- pCar->m_nDoorLock = CARLOCK_LOCKED;
- if (m_nColor1 != -1 && m_nColor2) {
- pCar->m_currentColour1 = m_nColor1;
- pCar->m_currentColour2 = m_nColor2;
- }
- m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pCar);
- }
- }
- if (m_nUsesRemaining < -1) /* I don't think this is a correct comparasion */
- --m_nUsesRemaining;
- m_nTimer = CalcNextGen();
- if (m_nUsesRemaining == 0)
- --CTheCarGenerators::CurrentActiveCount;
-}
-
-void CCarGenerator::Process()
-{
- if (m_nVehicleHandle == -1 &&
- (CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter || CTimer::GetTimeInMilliseconds() >= m_nTimer) &&
- m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayer())
- DoInternalProcessing();
- if (m_nVehicleHandle == -1)
- return;
- CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(m_nVehicleHandle);
- if (!pVehicle){
- m_nVehicleHandle = -1;
- return;
- }
- if (pVehicle->m_status != STATUS_PLAYER)
- return;
- m_nTimer += 60000;
- m_nVehicleHandle = -1;
- m_bIsBlocking = true;
- pVehicle->bExtendedRange = false;
-}
-
-void CCarGenerator::Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
-{
- CMatrix m1, m2, m3; /* Unused but present on stack, so I'll leave them. */
- m_vecPos = CVector(x, y, z);
- m_fAngle = angle;
- m_nModelIndex = mi;
- m_nColor1 = color1;
- m_nColor2 = color2;
- m_bForceSpawn = force;
- m_nAlarm = alarm;
- m_nDoorlock = lock;
- m_nMinDelay = min_delay;
- m_nMaxDelay = max_delay;
- m_nVehicleHandle = -1;
- m_nTimer = CTimer::GetTimeInMilliseconds() + 1;
- m_nUsesRemaining = 0;
- m_bIsBlocking = false;
- m_vecInf = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.min;
- m_vecSup = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.max;
- m_fSize = max(m_vecInf.Magnitude(), m_vecSup.Magnitude());
-}
-
-bool CCarGenerator::CheckForBlockage()
-{
- int16 entities;
- CWorld::FindObjectsKindaColliding(CVector(m_vecPos), m_fSize, 1, &entities, 2, nil, false, true, true, false, false);
- return entities > 0;
-}
-
-bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
-{
- CVector2D direction = FindPlayerCentreOfWorld(CWorld::PlayerInFocus) - m_vecPos;
- float distance = direction.Magnitude();
- float farclip = 120.0f * TheCamera.GenerationDistMultiplier;
- float nearclip = farclip - 20.0f;
- if (distance >= farclip){
- if (m_bIsBlocking)
- m_bIsBlocking = false;
- return false;
- }
- if (CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter)
- return true;
- if (m_bIsBlocking)
- return false;
- if (distance < nearclip)
- return false;
- return DotProduct2D(direction, FindPlayerSpeed()) <= 0;
-}
-
-void CCarGenerator::Save(uint8 *&buffer)
-{
- WriteSaveBuf(buffer, m_nModelIndex);
- WriteSaveBuf(buffer, m_vecPos);
- WriteSaveBuf(buffer, m_fAngle);
- WriteSaveBuf(buffer, m_nColor1);
- WriteSaveBuf(buffer, m_nColor2);
- WriteSaveBuf(buffer, m_bForceSpawn);
- WriteSaveBuf(buffer, m_nAlarm);
- WriteSaveBuf(buffer, m_nDoorlock);
- WriteSaveBuf(buffer, (uint8)0);
- WriteSaveBuf(buffer, m_nMinDelay);
- WriteSaveBuf(buffer, m_nMaxDelay);
- WriteSaveBuf(buffer, m_nTimer);
- WriteSaveBuf(buffer, m_nVehicleHandle);
- WriteSaveBuf(buffer, m_nUsesRemaining);
- WriteSaveBuf(buffer, m_bIsBlocking);
- WriteSaveBuf(buffer, (uint8)0);
- WriteSaveBuf(buffer, m_vecInf);
- WriteSaveBuf(buffer, m_vecSup);
- WriteSaveBuf(buffer, m_fSize);
-
- // or
- //WriteSaveBuf(buffer, *this);
-
-}
-
-void CCarGenerator::Load(uint8 *&buffer)
-{
- m_nModelIndex = ReadSaveBuf<uint32>(buffer);
- m_vecPos = ReadSaveBuf<CVector>(buffer);
- m_fAngle = ReadSaveBuf<float>(buffer);
- m_nColor1 = ReadSaveBuf<int16>(buffer);
- m_nColor2 = ReadSaveBuf<int16>(buffer);
- m_bForceSpawn = ReadSaveBuf<uint8>(buffer);
- m_nAlarm = ReadSaveBuf<uint8>(buffer);
- m_nDoorlock = ReadSaveBuf<uint8>(buffer);
- ReadSaveBuf<uint8>(buffer);
- m_nMinDelay = ReadSaveBuf<uint16>(buffer);
- m_nMaxDelay = ReadSaveBuf<uint16>(buffer);
- m_nTimer = ReadSaveBuf<uint32>(buffer);
- m_nVehicleHandle = ReadSaveBuf<int32>(buffer);
- m_nUsesRemaining = ReadSaveBuf<uint16>(buffer);
- m_bIsBlocking = ReadSaveBuf<bool>(buffer);
- ReadSaveBuf<uint8>(buffer);
- m_vecInf = ReadSaveBuf<CVector>(buffer);
- m_vecSup = ReadSaveBuf<CVector>(buffer);
- m_fSize = ReadSaveBuf<float>(buffer);
-
- // or
- //*this = ReadSaveBuf<CCarGenerator>(buffer);
-}
-
-void CTheCarGenerators::Process()
-{
- if (FindPlayerTrain() || CCutsceneMgr::IsRunning())
- return;
- if (++CTheCarGenerators::ProcessCounter == 4)
- CTheCarGenerators::ProcessCounter = 0;
- for (uint32 i = ProcessCounter; i < NumOfCarGenerators; i += 4)
- CTheCarGenerators::CarGeneratorArray[i].Process();
- if (GenerateEvenIfPlayerIsCloseCounter)
- GenerateEvenIfPlayerIsCloseCounter--;
-}
-
-int32 CTheCarGenerators::CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
-{
- CarGeneratorArray[NumOfCarGenerators].Setup(x, y, z, angle, mi, color1, color2, force, alarm, lock, min_delay, max_delay);
- return NumOfCarGenerators++;
-}
-
-void CTheCarGenerators::Init()
-{
- GenerateEvenIfPlayerIsCloseCounter = 0;
- NumOfCarGenerators = 0;
- ProcessCounter = 0;
- CurrentActiveCount = 0;
-}
-
-void CTheCarGenerators::SaveAllCarGenerators(uint8 *buffer, uint32 *size)
-{
- *size = 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE;
-INITSAVEBUF
- WriteSaveHeader(buffer, 'C','G','N','\0', *size - SAVE_HEADER_SIZE);
-
- WriteSaveBuf(buffer, 12); /* what is this? */
- WriteSaveBuf(buffer, NumOfCarGenerators);
- WriteSaveBuf(buffer, CurrentActiveCount);
- WriteSaveBuf(buffer, ProcessCounter);
- WriteSaveBuf(buffer, GenerateEvenIfPlayerIsCloseCounter);
- WriteSaveBuf(buffer, (int16)0);
- WriteSaveBuf(buffer, sizeof(CarGeneratorArray));
- for (int i = 0; i < NUM_CARGENS; i++){
- CarGeneratorArray[i].Save(buffer);
- }
-VALIDATESAVEBUF(*size)
-}
-
-void CTheCarGenerators::LoadAllCarGenerators(uint8* buffer, uint32 size)
-{
- Init();
-INITSAVEBUF
- assert(size == 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE);
- CheckSaveHeader(buffer, 'C','G','N','\0', size - SAVE_HEADER_SIZE);
- ReadSaveBuf<uint32>(buffer);
- NumOfCarGenerators = ReadSaveBuf<uint32>(buffer);
- CurrentActiveCount = ReadSaveBuf<uint32>(buffer);
- ProcessCounter = ReadSaveBuf<uint8>(buffer);
- GenerateEvenIfPlayerIsCloseCounter = ReadSaveBuf<uint8>(buffer);
- ReadSaveBuf<int16>(buffer);
- assert(ReadSaveBuf<uint32>(buffer) == sizeof(CarGeneratorArray));
- for (int i = 0; i < NUM_CARGENS; i++) {
- CarGeneratorArray[i].Load(buffer);
- }
-VALIDATESAVEBUF(size)
-}
-
-STARTPATCHES
-InjectHook(0x543020, CTheCarGenerators::Init, PATCH_JUMP);
-InjectHook(0x542F40, CTheCarGenerators::Process, PATCH_JUMP);
-InjectHook(0x543050, CTheCarGenerators::SaveAllCarGenerators, PATCH_JUMP);
-InjectHook(0x5431E0, CTheCarGenerators::LoadAllCarGenerators, PATCH_JUMP);
-ENDPATCHES
diff --git a/src/control/CarGen.h b/src/control/CarGen.h
deleted file mode 100644
index 75acdd56..00000000
--- a/src/control/CarGen.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#pragma once
-#include "common.h"
-#include "config.h"
-
-enum {
- CARGEN_MAXACTUALLIMIT = 100
-};
-
-class CCarGenerator
-{
- int32 m_nModelIndex;
- CVector m_vecPos;
- float m_fAngle;
- int16 m_nColor1;
- int16 m_nColor2;
- uint8 m_bForceSpawn;
- uint8 m_nAlarm;
- uint8 m_nDoorlock;
- int16 m_nMinDelay;
- int16 m_nMaxDelay;
- uint32 m_nTimer;
- int32 m_nVehicleHandle;
- uint16 m_nUsesRemaining;
- bool m_bIsBlocking;
- CVector m_vecInf;
- CVector m_vecSup;
- float m_fSize;
-public:
- void SwitchOff();
- void SwitchOn();
- uint32 CalcNextGen();
- void DoInternalProcessing();
- void Process();
- void Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
- bool CheckForBlockage();
- bool CheckIfWithinRangeOfAnyPlayer();
- void Save(uint8*&);
- void Load(uint8*&);
- void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
-};
-
-class CTheCarGenerators
-{
-public:
- static uint8 &ProcessCounter;
- static uint32 &NumOfCarGenerators;
- static CCarGenerator (&CarGeneratorArray)[NUM_CARGENS];
- static uint8 &GenerateEvenIfPlayerIsCloseCounter;
- static uint32 &CurrentActiveCount;
-
- static void Process();
- static int32 CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
- static void Init();
- static void SaveAllCarGenerators(uint8 *, uint32 *);
- static void LoadAllCarGenerators(uint8 *, uint32);
-};
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp
deleted file mode 100644
index 4c1bf2c8..00000000
--- a/src/control/Cranes.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "common.h"
-#include "patcher.h"
-#include "Cranes.h"
-
-WRAPPER bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle*) { EAXJMP(0x5451E0); }
-WRAPPER bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle*) { EAXJMP(0x545190); }
-WRAPPER bool CCranes::IsThisCarPickedUp(float, float, CVehicle*) { EAXJMP(0x543940); }
-WRAPPER bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane() { EAXJMP(0x544BE0); }
-WRAPPER void CCranes::ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float) { EAXJMP(0x543650); }
-WRAPPER void CCranes::DeActivateCrane(float, float) { EAXJMP(0x543890); }
-WRAPPER void CCranes::InitCranes(void) { EAXJMP(0x543360); }
-WRAPPER void CCranes::UpdateCranes(void) { EAXJMP(0x5439E0); }
-WRAPPER void CCranes::Save(uint8*, uint32*) { EAXJMP(0x545210); }
-WRAPPER void CranesLoad(uint8*, uint32) { EAXJMP(0x5454d0); }
diff --git a/src/control/Cranes.h b/src/control/Cranes.h
deleted file mode 100644
index b40454ea..00000000
--- a/src/control/Cranes.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-#include "common.h"
-
-class CVehicle;
-class CEntity;
-class CObject;
-
-class CCrane
-{
-public:
- CEntity *m_pObject;
- CObject *m_pMagnet;
- int m_nAudioEntity;
- float m_fPickupX1;
- float m_fPickupX2;
- float m_fPickupY1;
- float m_fPickupY2;
- CVector m_vecDropoffTarget;
- float m_fDropoffHeading;
- float m_fPickupAngle;
- float m_fDropoffAngle;
- float m_fPickupDistance;
- float m_fDropoffDistance;
- float m_fAngle;
- float m_fDistance;
- float m_fHeight;
- float m_fHookOffset;
- float m_fHookHeight;
- CVector m_vecHookInitPos;
- CVector m_vecHookCurPos;
- float m_fHookVelocityX;
- float m_fHookVelocityY;
- CVehicle *m_pVehiclePickedUp;
- int m_nUpdateTimer;
- char m_bCraneActive;
- char m_bCraneStatus;
- char m_bVehiclesCollected;
- char m_bIsCrusher;
- char m_bIsMilitaryCrane;
- char field_125;
- char m_bNotMilitaryCrane;
- char gap_127[1];
-};
-
-static_assert(sizeof(CCrane) == 128, "CCrane: error");
-
-class CCranes
-{
-public:
- static bool IsThisCarBeingTargettedByAnyCrane(CVehicle*);
- static bool IsThisCarBeingCarriedByAnyCrane(CVehicle*);
- static bool IsThisCarPickedUp(float, float, CVehicle*);
- static bool HaveAllCarsBeenCollectedByMilitaryCrane();
- static void ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float);
- static void DeActivateCrane(float, float);
- static void InitCranes(void);
- static void UpdateCranes(void);
- static void Save(uint8*, uint32*);
-};
-
-void CranesLoad(uint8*, uint32); // is this really outside CCranes?
diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp
index 0abae7d6..8e0ea02d 100644
--- a/src/control/GameLogic.cpp
+++ b/src/control/GameLogic.cpp
@@ -1,294 +1,294 @@
#include "common.h"
#include "patcher.h"
-#include "GameLogic.h"
-#include "Clock.h"
-#include "Stats.h"
-#include "Pickups.h"
-#include "Timer.h"
-#include "Streaming.h"
-#include "CutsceneMgr.h"
-#include "World.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "Camera.h"
-#include "Messages.h"
-#include "CarCtrl.h"
-#include "Restart.h"
-#include "Pad.h"
-#include "References.h"
-#include "Fire.h"
-#include "Script.h"
-#include "Garages.h"
-
-uint8 CGameLogic::ActivePlayers; // 0x95CD5E
-
-void
-CGameLogic::InitAtStartOfGame()
-{
- ActivePlayers = 1;
-}
-
-void
-CGameLogic::PassTime(uint32 time)
-{
- int32 minutes, hours, days;
-
- minutes = time + CClock::GetMinutes();
- hours = CClock::GetHours();
-
- for (; minutes >= 60; minutes -= 60)
- hours++;
-
- if (hours > 23) {
- days = CStats::DaysPassed;
- for (; hours >= 24; hours -= 24)
- days++;
- CStats::DaysPassed = days;
- }
-
- CClock::SetGameClock(hours, minutes);
- CPickups::PassTime(time * 1000);
-}
-
-void
-CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
-{
- CTimer::Stop();
- CStreaming::FlushRequestList();
- CStreaming::DeleteRwObjectsAfterDeath(pos);
- CStreaming::RemoveUnusedModelsInLoadedList();
- CGame::DrasticTidyUpMemory(true);
- CStreaming::LoadScene(pos);
- CTimer::Update();
-}
-
-void
-CGameLogic::Update()
-{
- CVector vecRestartPos;
- float fRestartFloat;
-
- if (CCutsceneMgr::IsCutsceneProcessing()) return;
-
- CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus];
- switch (pPlayerInfo.m_WBState) {
- case WBSTATE_PLAYING:
- if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) {
- pPlayerInfo.m_pPed->ClearAdrenaline();
- pPlayerInfo.KillPlayer();
- }
- if (pPlayerInfo.m_pPed->m_nPedState == PED_ARRESTED) {
- pPlayerInfo.m_pPed->ClearAdrenaline();
- pPlayerInfo.ArrestPlayer();
- }
- break;
- case WBSTATE_WASTED:
- if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
- TheCamera.SetFadeColour(200, 200, 200);
- TheCamera.Fade(2.0f, FADE_OUT);
- }
-
- if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
- pPlayerInfo.m_WBState = WBSTATE_PLAYING;
- if (pPlayerInfo.m_bGetOutOfHospitalFree) {
- pPlayerInfo.m_bGetOutOfHospitalFree = false;
- } else {
- pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - 1000);
- pPlayerInfo.m_pPed->ClearWeapons();
- }
-
- if (pPlayerInfo.m_pPed->bInVehicle) {
- CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
- if (pVehicle != nil) {
- if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
- pVehicle->pDriver = nil;
- if (pVehicle->m_status != STATUS_WRECKED)
- pVehicle->m_status = STATUS_ABANDONED;
- } else
- pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
- }
- }
- CEventList::Initialise();
- CMessages::ClearMessages();
- CCarCtrl::ClearInterestingVehicleList();
- CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
- CRestart::FindClosestHospitalRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
- CRestart::OverrideHospitalLevel = LEVEL_NONE;
- CRestart::OverridePoliceStationLevel = LEVEL_NONE;
- PassTime(720);
- RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
- SortOutStreamingAndMemory(pPlayerInfo.GetPos());
- TheCamera.m_fCamShakeForce = 0.0f;
- TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
- CPad::GetPad(0)->StopShaking(0);
- CReferences::RemoveReferencesToPlayer();
- CCarCtrl::CountDownToCarsAtStart = 2;
- CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
- if (CRestart::bFadeInAfterNextDeath) {
- TheCamera.SetFadeColour(200, 200, 200);
- TheCamera.Fade(4.0f, FADE_IN);
- } else CRestart::bFadeInAfterNextDeath = true;
- }
- break;
- case WBSTATE_BUSTED:
- if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
- TheCamera.SetFadeColour(0, 0, 0);
- TheCamera.Fade(2.0f, FADE_OUT);
- }
- if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
- pPlayerInfo.m_WBState = WBSTATE_PLAYING;
- int takeMoney;
-
- switch (pPlayerInfo.m_pPed->m_pWanted->m_nWantedLevel) {
- case 0:
- case 1:
- takeMoney = 100;
- break;
- case 2:
- takeMoney = 200;
- break;
- case 3:
- takeMoney = 400;
- break;
- case 4:
- takeMoney = 600;
- break;
- case 5:
- takeMoney = 900;
- break;
- case 6:
- takeMoney = 1500;
- break;
- }
- if (pPlayerInfo.m_bGetOutOfJailFree) {
- pPlayerInfo.m_bGetOutOfJailFree = false;
- } else {
- pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - takeMoney);
- pPlayerInfo.m_pPed->ClearWeapons();
- }
-
- if (pPlayerInfo.m_pPed->bInVehicle) {
- CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
- if (pVehicle != nil) {
- if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
- pVehicle->pDriver = nil;
- if (pVehicle->m_status != STATUS_WRECKED)
- pVehicle->m_status = STATUS_ABANDONED;
- }
- else
- pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
- }
- }
- CEventList::Initialise();
- CMessages::ClearMessages();
- CCarCtrl::ClearInterestingVehicleList();
- CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
- CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
- CRestart::OverrideHospitalLevel = LEVEL_NONE;
- CRestart::OverridePoliceStationLevel = LEVEL_NONE;
- PassTime(720);
- RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
- pPlayerInfo.m_pPed->ClearWeapons();
- SortOutStreamingAndMemory(pPlayerInfo.GetPos());
- TheCamera.m_fCamShakeForce = 0.0f;
- TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
- CPad::GetPad(0)->StopShaking(0);
- CReferences::RemoveReferencesToPlayer();
- CCarCtrl::CountDownToCarsAtStart = 2;
- CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
- if (CRestart::bFadeInAfterNextArrest) {
- TheCamera.SetFadeColour(0, 0, 0);
- TheCamera.Fade(4.0f, FADE_IN);
- } else CRestart::bFadeInAfterNextArrest = true;
- }
- break;
- case WBSTATE_FAILED_CRITICAL_MISSION:
- if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800 && CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800) {
- TheCamera.SetFadeColour(0, 0, 0);
- TheCamera.Fade(2.0f, FADE_OUT);
- }
- if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
- pPlayerInfo.m_WBState = WBSTATE_PLAYING;
- if (pPlayerInfo.m_pPed->bInVehicle) {
- CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
- if (pVehicle != nil) {
- if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
- pVehicle->pDriver = nil;
- if (pVehicle->m_status != STATUS_WRECKED)
- pVehicle->m_status = STATUS_ABANDONED;
- } else
- pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
- }
- }
- CEventList::Initialise();
- CMessages::ClearMessages();
- CCarCtrl::ClearInterestingVehicleList();
- CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
- CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
- CRestart::OverridePoliceStationLevel = LEVEL_NONE;
- CRestart::OverrideHospitalLevel = LEVEL_NONE;
- RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
- SortOutStreamingAndMemory(pPlayerInfo.GetPos());
- TheCamera.m_fCamShakeForce = 0.0f;
- TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
- CPad::GetPad(0)->StopShaking(0);
- CReferences::RemoveReferencesToPlayer();
- CCarCtrl::CountDownToCarsAtStart = 2;
- CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
- TheCamera.SetFadeColour(0, 0, 0);
- TheCamera.Fade(4.0f, FADE_IN);
- }
- break;
- case 4:
- return;
- }
-}
-
-void
-CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle)
-{
- pPlayerPed->m_fHealth = 100.0f;
- pPlayerPed->m_fArmour = 0.0f;
- pPlayerPed->bIsVisible = true;
- pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0;
- pPlayerPed->bDoBloodyFootprints = false;
- pPlayerPed->ClearAdrenaline();
- pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
- if (pPlayerPed->m_pFire)
- pPlayerPed->m_pFire->Extinguish();
- pPlayerPed->bInVehicle = false;
- pPlayerPed->m_pMyVehicle = nil;
- pPlayerPed->m_pVehicleAnim = nil;
- pPlayerPed->m_pWanted->Reset();
- pPlayerPed->RestartNonPartialAnims();
- pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false);
- pPlayerPed->bRemoveFromWorld = false;
- pPlayerPed->ClearWeaponTarget();
- pPlayerPed->SetInitialState();
- CCarCtrl::ClearInterestingVehicleList();
-
- pos.z += 1.0f;
- pPlayerPed->Teleport(pos);
- pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));
-
- pPlayerPed->m_fRotationCur = DEGTORAD(angle);
- pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur;
- pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur);
- CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed);
- CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1);
- pPlayerPed->RestoreHeadingRate();
- TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString();
- CReferences::RemoveReferencesToPlayer();
- CGarages::PlayerArrestedOrDied();
- CStats::CheckPointReachedUnsuccessfully();
- CWorld::Remove(pPlayerPed);
- CWorld::Add(pPlayerPed);
-}
-
+#include "GameLogic.h"
+#include "Clock.h"
+#include "Stats.h"
+#include "Pickups.h"
+#include "Timer.h"
+#include "Streaming.h"
+#include "CutsceneMgr.h"
+#include "World.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "Camera.h"
+#include "Messages.h"
+#include "CarCtrl.h"
+#include "Restart.h"
+#include "Pad.h"
+#include "References.h"
+#include "Fire.h"
+#include "Script.h"
+#include "Garages.h"
+
+uint8 CGameLogic::ActivePlayers; // 0x95CD5E
+
+void
+CGameLogic::InitAtStartOfGame()
+{
+ ActivePlayers = 1;
+}
+
+void
+CGameLogic::PassTime(uint32 time)
+{
+ int32 minutes, hours, days;
+
+ minutes = time + CClock::GetMinutes();
+ hours = CClock::GetHours();
+
+ for (; minutes >= 60; minutes -= 60)
+ hours++;
+
+ if (hours > 23) {
+ days = CStats::DaysPassed;
+ for (; hours >= 24; hours -= 24)
+ days++;
+ CStats::DaysPassed = days;
+ }
+
+ CClock::SetGameClock(hours, minutes);
+ CPickups::PassTime(time * 1000);
+}
+
+void
+CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
+{
+ CTimer::Stop();
+ CStreaming::FlushRequestList();
+ CStreaming::DeleteRwObjectsAfterDeath(pos);
+ CStreaming::RemoveUnusedModelsInLoadedList();
+ CGame::DrasticTidyUpMemory(true);
+ CStreaming::LoadScene(pos);
+ CTimer::Update();
+}
+
+void
+CGameLogic::Update()
+{
+ CVector vecRestartPos;
+ float fRestartFloat;
+
+ if (CCutsceneMgr::IsCutsceneProcessing()) return;
+
+ CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus];
+ switch (pPlayerInfo.m_WBState) {
+ case WBSTATE_PLAYING:
+ if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) {
+ pPlayerInfo.m_pPed->ClearAdrenaline();
+ pPlayerInfo.KillPlayer();
+ }
+ if (pPlayerInfo.m_pPed->m_nPedState == PED_ARRESTED) {
+ pPlayerInfo.m_pPed->ClearAdrenaline();
+ pPlayerInfo.ArrestPlayer();
+ }
+ break;
+ case WBSTATE_WASTED:
+ if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
+ TheCamera.SetFadeColour(200, 200, 200);
+ TheCamera.Fade(2.0f, FADE_OUT);
+ }
+
+ if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+ pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+ if (pPlayerInfo.m_bGetOutOfHospitalFree) {
+ pPlayerInfo.m_bGetOutOfHospitalFree = false;
+ } else {
+ pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - 1000);
+ pPlayerInfo.m_pPed->ClearWeapons();
+ }
+
+ if (pPlayerInfo.m_pPed->bInVehicle) {
+ CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+ if (pVehicle != nil) {
+ if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+ pVehicle->pDriver = nil;
+ if (pVehicle->m_status != STATUS_WRECKED)
+ pVehicle->m_status = STATUS_ABANDONED;
+ } else
+ pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+ }
+ }
+ CEventList::Initialise();
+ CMessages::ClearMessages();
+ CCarCtrl::ClearInterestingVehicleList();
+ CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+ CRestart::FindClosestHospitalRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+ CRestart::OverrideHospitalLevel = LEVEL_NONE;
+ CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+ PassTime(720);
+ RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+ SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+ TheCamera.m_fCamShakeForce = 0.0f;
+ TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+ CPad::GetPad(0)->StopShaking(0);
+ CReferences::RemoveReferencesToPlayer();
+ CCarCtrl::CountDownToCarsAtStart = 2;
+ CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+ if (CRestart::bFadeInAfterNextDeath) {
+ TheCamera.SetFadeColour(200, 200, 200);
+ TheCamera.Fade(4.0f, FADE_IN);
+ } else CRestart::bFadeInAfterNextDeath = true;
+ }
+ break;
+ case WBSTATE_BUSTED:
+ if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(2.0f, FADE_OUT);
+ }
+ if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+ pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+ int takeMoney;
+
+ switch (pPlayerInfo.m_pPed->m_pWanted->m_nWantedLevel) {
+ case 0:
+ case 1:
+ takeMoney = 100;
+ break;
+ case 2:
+ takeMoney = 200;
+ break;
+ case 3:
+ takeMoney = 400;
+ break;
+ case 4:
+ takeMoney = 600;
+ break;
+ case 5:
+ takeMoney = 900;
+ break;
+ case 6:
+ takeMoney = 1500;
+ break;
+ }
+ if (pPlayerInfo.m_bGetOutOfJailFree) {
+ pPlayerInfo.m_bGetOutOfJailFree = false;
+ } else {
+ pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - takeMoney);
+ pPlayerInfo.m_pPed->ClearWeapons();
+ }
+
+ if (pPlayerInfo.m_pPed->bInVehicle) {
+ CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+ if (pVehicle != nil) {
+ if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+ pVehicle->pDriver = nil;
+ if (pVehicle->m_status != STATUS_WRECKED)
+ pVehicle->m_status = STATUS_ABANDONED;
+ }
+ else
+ pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+ }
+ }
+ CEventList::Initialise();
+ CMessages::ClearMessages();
+ CCarCtrl::ClearInterestingVehicleList();
+ CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+ CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+ CRestart::OverrideHospitalLevel = LEVEL_NONE;
+ CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+ PassTime(720);
+ RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+ pPlayerInfo.m_pPed->ClearWeapons();
+ SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+ TheCamera.m_fCamShakeForce = 0.0f;
+ TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+ CPad::GetPad(0)->StopShaking(0);
+ CReferences::RemoveReferencesToPlayer();
+ CCarCtrl::CountDownToCarsAtStart = 2;
+ CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+ if (CRestart::bFadeInAfterNextArrest) {
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(4.0f, FADE_IN);
+ } else CRestart::bFadeInAfterNextArrest = true;
+ }
+ break;
+ case WBSTATE_FAILED_CRITICAL_MISSION:
+ if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800 && CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800) {
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(2.0f, FADE_OUT);
+ }
+ if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+ pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+ if (pPlayerInfo.m_pPed->bInVehicle) {
+ CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+ if (pVehicle != nil) {
+ if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+ pVehicle->pDriver = nil;
+ if (pVehicle->m_status != STATUS_WRECKED)
+ pVehicle->m_status = STATUS_ABANDONED;
+ } else
+ pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+ }
+ }
+ CEventList::Initialise();
+ CMessages::ClearMessages();
+ CCarCtrl::ClearInterestingVehicleList();
+ CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+ CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+ CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+ CRestart::OverrideHospitalLevel = LEVEL_NONE;
+ RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+ SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+ TheCamera.m_fCamShakeForce = 0.0f;
+ TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+ CPad::GetPad(0)->StopShaking(0);
+ CReferences::RemoveReferencesToPlayer();
+ CCarCtrl::CountDownToCarsAtStart = 2;
+ CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+ TheCamera.SetFadeColour(0, 0, 0);
+ TheCamera.Fade(4.0f, FADE_IN);
+ }
+ break;
+ case 4:
+ return;
+ }
+}
+
+void
+CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle)
+{
+ pPlayerPed->m_fHealth = 100.0f;
+ pPlayerPed->m_fArmour = 0.0f;
+ pPlayerPed->bIsVisible = true;
+ pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0;
+ pPlayerPed->bDoBloodyFootprints = false;
+ pPlayerPed->ClearAdrenaline();
+ pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
+ if (pPlayerPed->m_pFire)
+ pPlayerPed->m_pFire->Extinguish();
+ pPlayerPed->bInVehicle = false;
+ pPlayerPed->m_pMyVehicle = nil;
+ pPlayerPed->m_pVehicleAnim = nil;
+ pPlayerPed->m_pWanted->Reset();
+ pPlayerPed->RestartNonPartialAnims();
+ pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false);
+ pPlayerPed->bRemoveFromWorld = false;
+ pPlayerPed->ClearWeaponTarget();
+ pPlayerPed->SetInitialState();
+ CCarCtrl::ClearInterestingVehicleList();
+
+ pos.z += 1.0f;
+ pPlayerPed->Teleport(pos);
+ pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));
+
+ pPlayerPed->m_fRotationCur = DEGTORAD(angle);
+ pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur;
+ pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur);
+ CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed);
+ CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1);
+ pPlayerPed->RestoreHeadingRate();
+ TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString();
+ CReferences::RemoveReferencesToPlayer();
+ CGarages::PlayerArrestedOrDied();
+ CStats::CheckPointReachedUnsuccessfully();
+ CWorld::Remove(pPlayerPed);
+ CWorld::Add(pPlayerPed);
+}
+
STARTPATCHES
InjectHook(0x4213F0, &CGameLogic::InitAtStartOfGame, PATCH_JUMP);
InjectHook(0x421C00, &CGameLogic::PassTime, PATCH_JUMP);
InjectHook(0x421A20, &CGameLogic::SortOutStreamingAndMemory, PATCH_JUMP);
InjectHook(0x421400, &CGameLogic::Update, PATCH_JUMP);
- InjectHook(0x421A60, &CGameLogic::RestorePlayerStuffDuringResurrection, PATCH_JUMP);
+ InjectHook(0x421A60, &CGameLogic::RestorePlayerStuffDuringResurrection, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/control/GameLogic.h b/src/control/GameLogic.h
index db626558..43e244a3 100644
--- a/src/control/GameLogic.h
+++ b/src/control/GameLogic.h
@@ -1,13 +1,13 @@
-#pragma once
-
-class CGameLogic
-{
-public:
- static void InitAtStartOfGame();
- static void PassTime(uint32 time);
- static void SortOutStreamingAndMemory(const CVector &pos);
- static void Update();
- static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle);
-
- static uint8 ActivePlayers;
+#pragma once
+
+class CGameLogic
+{
+public:
+ static void InitAtStartOfGame();
+ static void PassTime(uint32 time);
+ static void SortOutStreamingAndMemory(const CVector &pos);
+ static void Update();
+ static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle);
+
+ static uint8 ActivePlayers;
}; \ No newline at end of file
diff --git a/src/control/Gangs.cpp b/src/control/Gangs.cpp
deleted file mode 100644
index ac32ad98..00000000
--- a/src/control/Gangs.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "common.h"
-#include "patcher.h"
-#include "ModelIndices.h"
-#include "Gangs.h"
-#include "Weapon.h"
-
-//CGangInfo(&CGangs::Gang)[NUM_GANGS] = *(CGangInfo(*)[NUM_GANGS])*(uintptr*)0x6EDF78;
-CGangInfo CGangs::Gang[NUM_GANGS];
-
-CGangInfo::CGangInfo() :
- m_nVehicleMI(MI_BUS),
- m_nPedModelOverride(-1),
- m_Weapon1(WEAPONTYPE_UNARMED),
- m_Weapon2(WEAPONTYPE_UNARMED)
-{}
-
-void CGangs::Initialise(void)
-{
- Gang[GANG_MAFIA].m_nVehicleMI = MI_MAFIA;
- Gang[GANG_TRIAD].m_nVehicleMI = MI_BELLYUP;
- Gang[GANG_DIABLOS].m_nVehicleMI = MI_DIABLOS;
- Gang[GANG_YAKUZA].m_nVehicleMI = MI_YAKUZA;
- Gang[GANG_YARDIE].m_nVehicleMI = MI_YARDIE;
- Gang[GANG_COLUMB].m_nVehicleMI = MI_COLUMB;
- Gang[GANG_HOODS].m_nVehicleMI = MI_HOODS;
- Gang[GANG_7].m_nVehicleMI = -1;
- Gang[GANG_8].m_nVehicleMI = -1;
-#ifdef FIX_BUGS
- for (int i = 0; i < NUM_GANGS; i++)
- Gang[i].m_nPedModelOverride = -1;
-#endif
-}
-
-void CGangs::SetGangVehicleModel(int16 gang, int32 model)
-{
- GetGangInfo(gang)->m_nVehicleMI = model;
-}
-
-void CGangs::SetGangWeapons(int16 gang, int32 weapon1, int32 weapon2)
-{
- CGangInfo *gi = GetGangInfo(gang);
- gi->m_Weapon1 = weapon1;
- gi->m_Weapon2 = weapon2;
-}
-
-void CGangs::SetGangPedModelOverride(int16 gang, int8 ovrd)
-{
- GetGangInfo(gang)->m_nPedModelOverride = ovrd;
-}
-
-int8 CGangs::GetGangPedModelOverride(int16 gang)
-{
- return GetGangInfo(gang)->m_nPedModelOverride;
-}
-
-void CGangs::SaveAllGangData(uint8 *buf, uint32 *size)
-{
-INITSAVEBUF
-
- *size = SAVE_HEADER_SIZE + sizeof(Gang);
- WriteSaveHeader(buf, 'G','N','G','\0', *size - SAVE_HEADER_SIZE);
- for (int i = 0; i < NUM_GANGS; i++)
- WriteSaveBuf(buf, Gang[i]);
-
-VALIDATESAVEBUF(*size);
-}
-
-void CGangs::LoadAllGangData(uint8 *buf, uint32 size)
-{
- Initialise();
-
-INITSAVEBUF
- // original: SkipSaveBuf(buf, SAVE_HEADER_SIZE);
- CheckSaveHeader(buf, 'G','N','G','\0', size - SAVE_HEADER_SIZE);
-
- for (int i = 0; i < NUM_GANGS; i++)
- Gang[i] = ReadSaveBuf<CGangInfo>(buf);
-VALIDATESAVEBUF(size);
-}
-
-STARTPATCHES
- InjectHook(0x4C3FB0, CGangs::Initialise, PATCH_JUMP);
- InjectHook(0x4C4010, CGangs::SetGangVehicleModel, PATCH_JUMP);
- InjectHook(0x4C4030, CGangs::SetGangWeapons, PATCH_JUMP);
- InjectHook(0x4C4050, CGangs::SetGangPedModelOverride, PATCH_JUMP);
- InjectHook(0x4C4070, CGangs::GetGangPedModelOverride, PATCH_JUMP);
- InjectHook(0x4C4080, CGangs::SaveAllGangData, PATCH_JUMP);
- InjectHook(0x4C4100, CGangs::LoadAllGangData, PATCH_JUMP);
-ENDPATCHES
diff --git a/src/control/Gangs.h b/src/control/Gangs.h
deleted file mode 100644
index dd7a7f93..00000000
--- a/src/control/Gangs.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-struct CGangInfo
-{
- int32 m_nVehicleMI;
- int8 m_nPedModelOverride;
- int32 m_Weapon1;
- int32 m_Weapon2;
-
- CGangInfo();
-};
-
-static_assert(sizeof(CGangInfo) == 0x10, "CGangInfo: error");
-
-enum {
- GANG_MAFIA = 0,
- GANG_TRIAD,
- GANG_DIABLOS,
- GANG_YAKUZA,
- GANG_YARDIE,
- GANG_COLUMB,
- GANG_HOODS,
- GANG_7,
- GANG_8,
- NUM_GANGS
-};
-
-class CGangs
-{
-public:
- static void Initialise(void);
- static void SetGangVehicleModel(int16, int32);
- static void SetGangWeapons(int16, int32, int32);
- static void SetGangPedModelOverride(int16, int8);
- static int8 GetGangPedModelOverride(int16);
- static void SaveAllGangData(uint8 *, uint32 *);
- static void LoadAllGangData(uint8 *, uint32);
-
- static int32 GetGangVehicleModel(int16 gang) { return Gang[gang].m_nVehicleMI; }
- static CGangInfo *GetGangInfo(int16 gang) { return &Gang[gang]; }
-
-private:
- static CGangInfo Gang[NUM_GANGS];
-};
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 6a91da76..e4b2aee3 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -126,7 +126,6 @@ uint32& CGarages::MessageEndTime = *(uint32*)0x8F597C;
uint32& CGarages::NumGarages = *(uint32*)0x8F29F4;
bool& CGarages::PlayerInGarage = *(bool*)0x95CD83;
int32& CGarages::PoliceCarsCollected = *(int32*)0x941444;
-uint32& CGarages::GarageToBeTidied = *(uint32*)0x623570;
CStoredCar(&CGarages::aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA210;
CStoredCar(&CGarages::aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA300;
CStoredCar(&CGarages::aCarsInSafeHouse3)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA3F0;
@@ -322,6 +321,9 @@ void CGarage::Update()
}
}
}
+ break;
+ default:
+ break;
}
}
if (m_bDeactivated && m_eGarageState == GS_FULLYCLOSED)
@@ -408,11 +410,11 @@ void CGarage::Update()
if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) {
uint8 colour1, colour2;
uint16 attempt;
- ((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+ FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
for (attempt = 0; attempt < 10; attempt++) {
if (colour1 != FindPlayerVehicle()->m_currentColour1 || colour2 != FindPlayerVehicle()->m_currentColour2)
break;
- ((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+ FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
}
bChangedColour = (attempt < 10);
FindPlayerVehicle()->m_currentColour1 = colour1;
@@ -490,7 +492,7 @@ void CGarage::Update()
break;
}
if (!CGarages::BombsAreFree && CWorld::Players[CWorld::PlayerInFocus].m_nMoney < BOMB_PRICE) {
- CGarages::TriggerMessage("GA_4", -1, 4000, -1); // "Car bombs are $1000 each"
+ CGarages::TriggerMessage("GA_4", -1, 4000, -1); // "Car bombs are $1000 each" - weird that the price is hardcoded in message
m_eGarageState = GS_OPENEDCONTAINSCAR;
DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1);
break;
@@ -524,7 +526,7 @@ void CGarage::Update()
((CAutomobile*)(FindPlayerVehicle()))->m_pBombRigger = FindPlayerPed();
if (m_eGarageType == GARAGE_BOMBSHOP3)
CGarages::GivePlayerDetonator();
- CStats::KgOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB;
+ CStats::KgsOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB;
}
switch (m_eGarageType) {
case GARAGE_BOMBSHOP1:
@@ -1184,7 +1186,7 @@ bool CGarage::IsEntityEntirelyInside(CEntity * pEntity)
if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 ||
pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2)
return false;
- CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1201,7 +1203,7 @@ bool CGarage::IsEntityEntirelyInside3D(CEntity * pEntity, float fMargin)
pEntity->GetPosition().y < m_fY1 - fMargin || pEntity->GetPosition().y > m_fY2 + fMargin ||
pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin)
return false;
- CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1218,7 +1220,7 @@ bool CGarage::IsEntityEntirelyOutside(CEntity * pEntity, float fMargin)
if (pEntity->GetPosition().x > m_fX1 - fMargin && pEntity->GetPosition().x < m_fX2 + fMargin &&
pEntity->GetPosition().y > m_fY1 - fMargin && pEntity->GetPosition().y < m_fY2 + fMargin)
return false;
- CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1250,7 +1252,7 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity)
pEntity->GetPosition().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 ||
pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2)
return false;
- CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
radius = pColModel->spheres[i].radius;
@@ -1264,7 +1266,7 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity)
bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin)
{
- CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1285,7 +1287,7 @@ bool CGarage::IsAnyOtherCarTouchingGarage(CVehicle * pException)
continue;
if (!IsEntityTouching3D(pVehicle))
continue;
- CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1307,7 +1309,7 @@ bool CGarage::IsAnyOtherPedTouchingGarage(CPed * pException)
continue;
if (!IsEntityTouching3D(pPed))
continue;
- CColModel* pColModel = CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pException->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1329,7 +1331,7 @@ bool CGarage::IsAnyCarBlockingDoor()
continue;
if (!IsEntityTouching3D(pVehicle))
continue;
- CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -1677,7 +1679,7 @@ float CGarage::CalcDistToGarageRectangleSquared(float X, float Y)
else
distX = 0.0f;
if (Y < m_fY1)
- distY = m_fY1 - X;
+ distY = m_fY1 - Y;
else if (Y > m_fY2)
distY = Y - m_fY2;
else
@@ -1698,8 +1700,8 @@ float CGarage::CalcSmallestDistToGarageDoorSquared(float X, float Y)
void CGarage::FindDoorsEntities()
{
- m_pDoor1 = false;
- m_pDoor2 = false;
+ m_pDoor1 = nil;
+ m_pDoor2 = nil;
int xstart = max(0, CWorld::GetSectorIndexX(m_fX1));
int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2));
int ystart = max(0, CWorld::GetSectorIndexY(m_fY1));
@@ -1992,7 +1994,7 @@ void CGarage::TidyUpGarageClose()
continue;
bool bRemove = false;
if (m_eGarageState != GS_FULLYCLOSED) {
- CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+ CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius;
@@ -2106,7 +2108,7 @@ void CGarages::CloseHideOutGaragesBeforeSave()
aGarages[i].m_eGarageType != GARAGE_HIDEOUT_THREE)
continue;
if (aGarages[i].m_eGarageState != GS_FULLYCLOSED &&
- aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor()) {
+ (aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor())) {
aGarages[i].m_eGarageState = GS_FULLYCLOSED;
switch (aGarages[i].m_eGarageType) {
case GARAGE_HIDEOUT_ONE:
@@ -2227,6 +2229,7 @@ void CGarages::SetAllDoorsBackToOriginalHeight()
void CGarages::Save(uint8 * buf, uint32 * size)
{
#ifdef FIX_GARAGE_SIZE
+ INITSAVEBUF
*size = (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
#else
* size = 5484;
@@ -2248,6 +2251,9 @@ void CGarages::Save(uint8 * buf, uint32 * size)
}
for (int i = 0; i < NUM_GARAGES; i++)
WriteSaveBuf(buf, aGarages[i]);
+#ifdef FIX_GARAGE_SIZE
+ VALIDATESAVEBUF(*size);
+#endif
}
CStoredCar::CStoredCar(const CStoredCar & other)
@@ -2271,6 +2277,7 @@ CStoredCar::CStoredCar(const CStoredCar & other)
void CGarages::Load(uint8* buf, uint32 size)
{
#ifdef FIX_GARAGE_SIZE
+ INITSAVEBUF
assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
#else
assert(size == 5484);
@@ -2303,6 +2310,9 @@ void CGarages::Load(uint8* buf, uint32 size)
else
aGarages[i].UpdateDoorsHeight();
}
+#ifdef FIX_GARAGE_SIZE
+ VALIDATESAVEBUF(size);
+#endif
}
bool
@@ -2345,8 +2355,7 @@ CGarages::IsModelIndexADoor(uint32 id)
STARTPATCHES
- InjectHook(0x426B20, CGarages::TriggerMessage, PATCH_JUMP); // CCrane::Update, CCrane::FindCarInSectorList
InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl
InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl
InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad
-ENDPATCHES \ No newline at end of file
+ENDPATCHES
diff --git a/src/control/Garages.h b/src/control/Garages.h
index e3864a48..26e7a89a 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -194,7 +194,6 @@ class CGarages
static uint32 &NumGarages;
static bool &PlayerInGarage;
static int32 &PoliceCarsCollected;
- static uint32 &GarageToBeTidied;
static CGarage(&aGarages)[NUM_GARAGES];
static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS];
static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS];
diff --git a/src/control/OnscreenTimer.h b/src/control/OnscreenTimer.h
index b1e0e622..fb139266 100644
--- a/src/control/OnscreenTimer.h
+++ b/src/control/OnscreenTimer.h
@@ -1,49 +1,49 @@
-#pragma once
-
-enum
-{
- COUNTER_DISPLAY_NUMBER,
- COUNTER_DISPLAY_BAR,
-};
-
-class COnscreenTimerEntry
-{
-public:
- uint32 m_nTimerOffset;
- uint32 m_nCounterOffset;
- char m_aTimerText[10];
- char m_aCounterText[10];
- uint16 m_nType;
- char m_bCounterBuffer[42];
- char m_bTimerBuffer[42];
- bool m_bTimerProcessed;
- bool m_bCounterProcessed;
-
- void Process();
- bool ProcessForDisplay();
-
- void ProcessForDisplayClock();
- void ProcessForDisplayCounter();
-};
-
-static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");
-
-class COnscreenTimer
-{
-public:
- COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES];
- bool m_bProcessed;
- bool m_bDisabled;
-
- void Init();
- void Process();
- void ProcessForDisplay();
-
- void ClearCounter(uint32 offset);
- void ClearClock(uint32 offset);
-
- void AddCounter(uint32 offset, uint16 type, char* text);
- void AddClock(uint32 offset, char* text);
-};
-
+#pragma once
+
+enum
+{
+ COUNTER_DISPLAY_NUMBER,
+ COUNTER_DISPLAY_BAR,
+};
+
+class COnscreenTimerEntry
+{
+public:
+ uint32 m_nTimerOffset;
+ uint32 m_nCounterOffset;
+ char m_aTimerText[10];
+ char m_aCounterText[10];
+ uint16 m_nType;
+ char m_bCounterBuffer[42];
+ char m_bTimerBuffer[42];
+ bool m_bTimerProcessed;
+ bool m_bCounterProcessed;
+
+ void Process();
+ bool ProcessForDisplay();
+
+ void ProcessForDisplayClock();
+ void ProcessForDisplayCounter();
+};
+
+static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");
+
+class COnscreenTimer
+{
+public:
+ COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES];
+ bool m_bProcessed;
+ bool m_bDisabled;
+
+ void Init();
+ void Process();
+ void ProcessForDisplay();
+
+ void ClearCounter(uint32 offset);
+ void ClearClock(uint32 offset);
+
+ void AddCounter(uint32 offset, uint16 type, char* text);
+ void AddClock(uint32 offset, char* text);
+};
+
static_assert(sizeof(COnscreenTimer) == 0x78, "COnscreenTimer: error"); \ No newline at end of file
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index 608a209a..61cd3d4e 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -5,8 +5,13 @@
#include "Camera.h"
#include "Vehicle.h"
#include "World.h"
+#include "Lines.h" // for debug
#include "PathFind.h"
+bool gbShowPedPaths;
+bool gbShowCarPaths;
+bool gbShowCarPathsLinks;
+
CPathFind &ThePaths = *(CPathFind*)0x8F6754;
WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
@@ -466,20 +471,20 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
// IMPROVE: use a goto here
// Find existing car path link
for(k = 0; k < m_numCarPathLinks; k++){
- if(m_carPathLinks[k].dirX == tempnodes[j].dirX &&
- m_carPathLinks[k].dirY == tempnodes[j].dirY &&
- m_carPathLinks[k].posX == tempnodes[j].pos.x &&
- m_carPathLinks[k].posY == tempnodes[j].pos.y){
+ if(m_carPathLinks[k].dir.x == tempnodes[j].dirX &&
+ m_carPathLinks[k].dir.y == tempnodes[j].dirY &&
+ m_carPathLinks[k].pos.x == tempnodes[j].pos.x &&
+ m_carPathLinks[k].pos.y == tempnodes[j].pos.y){
m_carPathConnections[m_numConnections] = k;
k = m_numCarPathLinks;
}
}
// k is m_numCarPathLinks+1 if we found one
if(k == m_numCarPathLinks){
- m_carPathLinks[m_numCarPathLinks].dirX = tempnodes[j].dirX;
- m_carPathLinks[m_numCarPathLinks].dirY = tempnodes[j].dirY;
- m_carPathLinks[m_numCarPathLinks].posX = tempnodes[j].pos.x;
- m_carPathLinks[m_numCarPathLinks].posY = tempnodes[j].pos.y;
+ m_carPathLinks[m_numCarPathLinks].dir.x = tempnodes[j].dirX;
+ m_carPathLinks[m_numCarPathLinks].dir.y = tempnodes[j].dirY;
+ m_carPathLinks[m_numCarPathLinks].pos.x = tempnodes[j].pos.x;
+ m_carPathLinks[m_numCarPathLinks].pos.y = tempnodes[j].pos.y;
m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i;
m_carPathLinks[m_numCarPathLinks].numLeftLanes = tempnodes[j].numLeftLanes;
m_carPathLinks[m_numCarPathLinks].numRightLanes = tempnodes[j].numRightLanes;
@@ -529,20 +534,20 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
// IMPROVE: use a goto here
// Find existing car path link
for(k = 0; k < m_numCarPathLinks; k++){
- if(m_carPathLinks[k].dirX == dx &&
- m_carPathLinks[k].dirY == dy &&
- m_carPathLinks[k].posX == posx &&
- m_carPathLinks[k].posY == posy){
+ if(m_carPathLinks[k].dir.x == dx &&
+ m_carPathLinks[k].dir.y == dy &&
+ m_carPathLinks[k].pos.x == posx &&
+ m_carPathLinks[k].pos.y == posy){
m_carPathConnections[m_numConnections] = k;
k = m_numCarPathLinks;
}
}
// k is m_numCarPathLinks+1 if we found one
if(k == m_numCarPathLinks){
- m_carPathLinks[m_numCarPathLinks].dirX = dx;
- m_carPathLinks[m_numCarPathLinks].dirY = dy;
- m_carPathLinks[m_numCarPathLinks].posX = posx;
- m_carPathLinks[m_numCarPathLinks].posY = posy;
+ m_carPathLinks[m_numCarPathLinks].dir.x = dx;
+ m_carPathLinks[m_numCarPathLinks].dir.y = dy;
+ m_carPathLinks[m_numCarPathLinks].pos.x = posx;
+ m_carPathLinks[m_numCarPathLinks].pos.y = posy;
m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i;
m_carPathLinks[m_numCarPathLinks].numLeftLanes = -1;
m_carPathLinks[m_numCarPathLinks].numRightLanes = -1;
@@ -760,8 +765,8 @@ CPathFind::SetLinksBridgeLights(float x1, float x2, float y1, float y2, bool ena
{
int i;
for(i = 0; i < m_numCarPathLinks; i++)
- if(x1 < m_carPathLinks[i].posX && m_carPathLinks[i].posX < x2 &&
- y1 < m_carPathLinks[i].posY && m_carPathLinks[i].posY < y2)
+ if(x1 < m_carPathLinks[i].pos.x && m_carPathLinks[i].pos.x < x2 &&
+ y1 < m_carPathLinks[i].pos.y && m_carPathLinks[i].pos.y < y2)
m_carPathLinks[i].bBridgeLights = enable;
}
@@ -1444,6 +1449,132 @@ CPathFind::Load(uint8 *buf, uint32 size)
m_pathNodes[i].bBetweenLevels = false;
}
+void
+CPathFind::DisplayPathData(void)
+{
+ // Not the function from mobm_carPathLinksile but my own!
+
+ int i, j, k;
+ // Draw 50 units around camera
+ CVector pos = TheCamera.GetPosition();
+ const float maxDist = 50.0f;
+
+ // Render car path nodes
+ if(gbShowCarPaths)
+ for(i = 0; i < m_numCarPathNodes; i++){
+ if((m_pathNodes[i].pos - pos).MagnitudeSqr() > SQR(maxDist))
+ continue;
+
+ CVector n1 = m_pathNodes[i].pos;
+ n1.z += 0.3f;
+
+ // Draw node itself
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n1.x, n1.y, n1.z + 1.0f,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ for(j = 0; j < m_pathNodes[i].numLinks; j++){
+ k = m_connections[m_pathNodes[i].firstLink + j];
+ CVector n2 = m_pathNodes[k].pos;
+ n2.z += 0.3f;
+ // Draw links to neighbours
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n2.x, n2.y, n2.z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ }
+ }
+
+ // Render car path nodes
+ if(gbShowCarPathsLinks)
+ for(i = 0; i < m_numCarPathLinks; i++){
+ CVector2D n1_2d = m_carPathLinks[i].pos;
+ if((n1_2d - pos).MagnitudeSqr() > SQR(maxDist))
+ continue;
+
+ int ni = m_carPathLinks[i].pathNodeIndex;
+ CVector pn1 = m_pathNodes[ni].pos;
+ pn1.z += 0.3f;
+ CVector n1(n1_2d.x, n1_2d.y, pn1.z);
+ n1.z += 0.3f;
+
+ // Draw car node itself
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n1.x, n1.y, n1.z + 1.0f,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z + 0.5f,
+ n1.x+m_carPathLinks[i].dir.x, n1.y+m_carPathLinks[i].dir.y, n1.z + 0.5f,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ // Draw connection to car path node
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ pn1.x, pn1.y, pn1.z,
+ 0xFF0000FF, 0xFFFFFFFF);
+
+ // traffic light type
+ uint32 col = 0xFF;
+ if((m_carPathLinks[i].trafficLightType&0x7F) == 1)
+ col += 0xFF000000;
+ if((m_carPathLinks[i].trafficLightType&0x7F) == 2)
+ col += 0x00FF0000;
+ if(m_carPathLinks[i].trafficLightType & 0x80)
+ col += 0x0000FF00;
+ CLines::RenderLineWithClipping(n1.x+0.2f, n1.y, n1.z,
+ n1.x+0.2f, n1.y, n1.z + 1.0f,
+ col, col);
+
+ for(j = 0; j < m_pathNodes[ni].numLinks; j++){
+ k = m_carPathConnections[m_pathNodes[ni].firstLink + j];
+ CVector2D n2_2d = m_carPathLinks[k].pos;
+ int nk = m_carPathLinks[k].pathNodeIndex;
+ CVector pn2 = m_pathNodes[nk].pos;
+ pn2.z += 0.3f;
+ CVector n2(n2_2d.x, n2_2d.y, pn2.z);
+ n2.z += 0.3f;
+
+ // Draw links to neighbours
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n2.x, n2.y, n2.z,
+ 0xFF00FFFF, 0xFF00FFFF);
+ }
+ }
+
+ // Render ped path nodes
+ if(gbShowPedPaths)
+ for(i = m_numCarPathNodes; i < m_numPathNodes; i++){
+ if((m_pathNodes[i].pos - pos).MagnitudeSqr() > SQR(maxDist))
+ continue;
+
+ CVector n1 = m_pathNodes[i].pos;
+ n1.z += 0.3f;
+
+ // Draw node itself
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n1.x, n1.y, n1.z + 1.0f,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ for(j = 0; j < m_pathNodes[i].numLinks; j++){
+ k = m_connections[m_pathNodes[i].firstLink + j];
+ CVector n2 = m_pathNodes[k].pos;
+ n2.z += 0.3f;
+ // Draw links to neighbours
+ CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+ n2.x, n2.y, n2.z,
+ 0xFFFFFFFF, 0xFFFFFFFF);
+
+ // Draw connection flags
+ CVector mid = (n1+n2)/2.0f;
+ uint32 col = 0xFF;
+ if(m_connectionFlags[m_pathNodes[i].firstLink + j].bCrossesRoad)
+ col += 0x00FF0000;
+ if(m_connectionFlags[m_pathNodes[i].firstLink + j].bTrafficLight)
+ col += 0xFF000000;
+ CLines::RenderLineWithClipping(mid.x, mid.y, mid.z,
+ mid.x, mid.y, mid.z + 1.0f,
+ col, col);
+ }
+ }
+}
+
STARTPATCHES
InjectHook(0x4294A0, &CPathFind::Init, PATCH_JUMP);
InjectHook(0x42D580, &CPathFind::AllocatePathFindInfoMem, PATCH_JUMP);
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index c51cb7c7..81467cdf 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -84,10 +84,8 @@ union CConnectionFlags
struct CCarPathLink
{
- float posX;
- float posY;
- float dirX;
- float dirY;
+ CVector2D pos;
+ CVector2D dir;
int16 pathNodeIndex;
int8 numLeftLanes;
int8 numRightLanes;
@@ -208,7 +206,13 @@ public:
bool TestCoorsCloseness(CVector target, uint8 type, CVector start);
void Save(uint8 *buf, uint32 *size);
void Load(uint8 *buf, uint32 size);
+
+ void DisplayPathData(void);
};
static_assert(sizeof(CPathFind) == 0x49bf4, "CPathFind: error");
extern CPathFind &ThePaths;
+
+extern bool gbShowPedPaths;
+extern bool gbShowCarPaths;
+extern bool gbShowCarPathsLinks;
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index 3e3c2a48..eb561670 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -1,1049 +1,1452 @@
-#include "common.h"
-#include "patcher.h"
-#include "main.h"
-
-#include "Camera.h"
-#include "Coronas.h"
-#include "Darkel.h"
-#include "Entity.h"
-#include "Explosion.h"
-#include "Font.h"
-#include "Garages.h"
-#include "General.h"
-#include "ModelIndices.h"
-#include "Object.h"
-#include "Pad.h"
-#include "Pickups.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "DMAudio.h"
-#include "Fire.h"
-#include "PointLights.h"
-#include "Pools.h"
-#ifdef FIX_BUGS
-#include "Replay.h"
-#endif
-#include "Script.h"
-#include "Shadows.h"
-#include "SpecialFX.h"
-#include "Sprite.h"
-#include "Timer.h"
-#include "WaterLevel.h"
-#include "World.h"
-
-CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98;
-int16 CPickups::NumMessages;// = *(int16*)0x95CC98;
-int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538;
-int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A;
-
-// unused
-bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71;
-CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8;
-CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8;
-uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C;
-
-tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
-
-// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4)
-uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
-uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 };
-uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
-
-uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 };
-uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 };
-uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 };
-float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f };
-
-WRAPPER void CPacManPickups::Init(void) { EAXJMP(0x432760); }
-WRAPPER void CPacManPickups::Update(void) { EAXJMP(0x432800); }
-WRAPPER void CPacManPickups::GeneratePMPickUps(CVector, float, int16, uint8) { EAXJMP(0x432AE0); }
-WRAPPER void CPacManPickups::GeneratePMPickUpsForRace(int32) { EAXJMP(0x432D50); }
-WRAPPER void CPacManPickups::GenerateOnePMPickUp(CVector) { EAXJMP(0x432F20); }
-WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); }
-WRAPPER void CPacManPickups::DoCleanUpPacManStuff(void) { EAXJMP(0x433150); }
-WRAPPER void CPacManPickups::StartPacManRace(int32) { EAXJMP(0x433340); }
-WRAPPER void CPacManPickups::StartPacManRecord(void) { EAXJMP(0x433360); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsEatenInRace(void) { EAXJMP(0x4333A0); }
-WRAPPER void CPacManPickups::ResetPowerPillsEatenInRace(void) { EAXJMP(0x4333B0); }
-WRAPPER void CPacManPickups::CleanUpPacManStuff(void) { EAXJMP(0x4333C0); }
-WRAPPER void CPacManPickups::StartPacManScramble(CVector, float, int16) { EAXJMP(0x4333D0); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsCarriedByPlayer(void) { EAXJMP(0x4333F0); }
-WRAPPER void CPacManPickups::ResetPowerPillsCarriedByPlayer(void) { EAXJMP(0x433410); }
-
-
-void
-CPickup::RemoveKeepType()
-{
- CWorld::Remove(m_pObject);
- delete m_pObject;
-
- m_bRemoved = true;
- m_pObject = nil;
-}
-
-void
-CPickup::Remove()
-{
- RemoveKeepType();
- m_eType = PICKUP_NONE;
-}
-
-CObject *
-CPickup::GiveUsAPickUpObject(int32 handle)
-{
- CObject *object;
-
- if (handle <= 0) object = new CObject(m_eModelIndex, false);
- else {
- CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
- object = new(handle) CObject(m_eModelIndex, false);
- }
-
- if (object == nil) return nil;
- object->ObjectCreatedBy = MISSION_OBJECT;
- object->GetPosition() = m_vecPos;
- object->SetOrientation(0.0f, 0.0f, -HALFPI);
- object->GetMatrix().UpdateRW();
- object->UpdateRwFrame();
-
- object->bAffectedByGravity = false;
- object->bExplosionProof = true;
- object->bUsesCollision = false;
- object->bIsPickup = true;
-
- object->field_172 = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
-
- switch (m_eType)
- {
- case PICKUP_IN_SHOP:
- object->m_obj_flag2 = true;
- object->bOutOfStock = false;
- break;
- case PICKUP_ON_STREET:
- case PICKUP_ONCE:
- case PICKUP_ONCE_TIMEOUT:
- case PICKUP_COLLECTABLE1:
- case PICKUP_MONEY:
- case PICKUP_MINE_INACTIVE:
- case PICKUP_MINE_ARMED:
- case PICKUP_NAUTICAL_MINE_INACTIVE:
- case PICKUP_NAUTICAL_MINE_ARMED:
- case PICKUP_FLOATINGPACKAGE:
- case PICKUP_ON_STREET_SLOW:
- object->m_obj_flag2 = false;
- object->bOutOfStock = false;
- break;
- case PICKUP_IN_SHOP_OUT_OF_STOCK:
- object->m_obj_flag2 = false;
- object->bOutOfStock = true;
- object->bRenderScorched = true;
- break;
- case PICKUP_FLOATINGPACKAGE_FLOATING:
- default:
- break;
- }
- return object;
-}
-
-bool
-CPickup::CanBePickedUp(CPlayerPed *player)
-{
- assert(m_pObject != nil);
- bool cannotBePickedUp =
- (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f)
- || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f)
- || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0)
- || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame));
- return !cannotBePickedUp;
-}
-
-bool
-CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
-{
- float waterLevel;
-
- if (m_bRemoved) {
- if (CTimer::GetTimeInMilliseconds() > m_nTimer) {
- // respawn pickup if we're far enough
- float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y);
- if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) {
- m_pObject = GiveUsAPickUpObject(-1);
- if (m_pObject) {
- CWorld::Add(m_pObject);
- m_bRemoved = false;
- }
- }
- }
- return false;
- }
-
- if (!m_pObject) return false;
-
- if (!IsMine()) {
- // let's check if we touched the pickup
- bool isPickupTouched = false;
- if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) {
- if (vehicle != nil) {
- if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f))
- isPickupTouched = true;
- }
- else {
- if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
- if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
- (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
- isPickupTouched = true;
- }
- }
- } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) {
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- isPickupTouched = true;
- }
- } else if (vehicle == nil) {
- if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
- if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
- (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
- isPickupTouched = true;
- }
- }
-
- // if we didn't then we've got nothing to do
- if (isPickupTouched && CanBePickedUp(player)) {
- CPad::GetPad(0)->StartShake(120, 100);
- switch (m_eType)
- {
- case PICKUP_IN_SHOP:
- if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) {
- CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
- } else {
- CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())];
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
- }
- RemoveKeepType();
- m_nTimer = CTimer::GetTimeInMilliseconds() + 5000;
- return true;
- }
- break;
- case PICKUP_ON_STREET:
- case PICKUP_ON_STREET_SLOW:
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) {
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- }
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
- } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- CPickups::bPickUpcamActivated = true;
- CPickups::pPlayerVehicle = FindPlayerVehicle();
- CPickups::StaticCamCoors = m_pObject->GetPosition();
- CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds();
- }
- }
- if (m_eType == PICKUP_ON_STREET) {
- m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
- } else if (m_eType == PICKUP_ON_STREET_SLOW) {
- if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex)
- m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
- else
- m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
- }
-
- RemoveKeepType();
- return true;
- case PICKUP_ONCE:
- case PICKUP_ONCE_TIMEOUT:
- if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
- if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
- player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
- if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
- player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
- }
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
- }
- Remove();
- return true;
- case PICKUP_COLLECTABLE1:
- CWorld::Players[playerId].m_nCollectedPackages++;
- CWorld::Players[playerId].m_nMoney += 1000;
-
- if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) {
- printf("All collectables have been picked up\n");
- CGarages::TriggerMessage("CO_ALL", -1, 5000, -1);
- CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000;
- } else
- CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
-
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
- return true;
- case PICKUP_MONEY:
- CWorld::Players[playerId].m_nMoney += m_nQuantity;
- sprintf(gString, "$%d", m_nQuantity);
-#ifdef MONEY_MESSAGES
- CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f);
-#endif
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
- return true;
- //case PICKUP_IN_SHOP_OUT_OF_STOCK:
- //case PICKUP_MINE_INACTIVE:
- //case PICKUP_MINE_ARMED:
- //case PICKUP_NAUTICAL_MINE_INACTIVE:
- //case PICKUP_NAUTICAL_MINE_ARMED:
- //case PICKUP_FLOATINGPACKAGE:
- //case PICKUP_FLOATINGPACKAGE_FLOATING:
- default:
- break;
- }
- }
- } else {
- switch (m_eType)
- {
- case PICKUP_MINE_INACTIVE:
- if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- m_eType = PICKUP_MINE_ARMED;
- m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
- }
- break;
- case PICKUP_NAUTICAL_MINE_INACTIVE:
- {
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
- m_pObject->GetPosition().z = waterLevel + 0.6f;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
-
- bool touched = false;
- for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
- CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
- touched = true;
- break; // added break here
- }
- }
-
- if (!touched) {
- m_eType = PICKUP_NAUTICAL_MINE_ARMED;
- m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
- }
- break;
- }
- case PICKUP_NAUTICAL_MINE_ARMED:
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
- m_pObject->GetPosition().z = waterLevel + 0.6f;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- // no break here
- case PICKUP_MINE_ARMED:
- {
- bool explode = false;
- if (CTimer::GetTimeInMilliseconds() > m_nTimer)
- explode = true;
- else {// added else here since vehicle lookup is useless
- for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
- CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
- explode = true;
- break; // added break here
- }
- }
- }
- if (explode) {
- CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
- Remove();
- }
- break;
- }
- case PICKUP_FLOATINGPACKAGE:
- m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
- m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep();
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z)
- m_eType = PICKUP_FLOATINGPACKAGE_FLOATING;
- break;
- case PICKUP_FLOATINGPACKAGE_FLOATING:
- if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0))
- m_pObject->GetPosition().z = waterLevel;
-
- m_pObject->GetMatrix().UpdateRW();
- m_pObject->UpdateRwFrame();
- if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
- Remove();
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
- return true;
- }
- break;
- }
- }
- if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
- Remove();
- return false;
-}
-
-void
-CPickups::Init(void)
-{
- NumMessages = 0;
- for (int i = 0; i < NUMPICKUPS; i++) {
- aPickUps[i].m_eType = PICKUP_NONE;
- aPickUps[i].m_nIndex = 1;
- aPickUps[i].m_pObject = nil;
- }
-
- for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- aPickUpsCollected[i] = 0;
-
- CollectedPickUpIndex = 0;
-}
-
-bool
-CPickups::IsPickUpPickedUp(int32 pickupId)
-{
- for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) {
- if (pickupId == aPickUpsCollected[i]) {
- aPickUpsCollected[i] = 0;
- return true;
- }
- }
- return false;
-}
-
-void
-CPickups::PassTime(uint32 time)
-{
- for (int i = 0; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE) {
- if (aPickUps[i].m_nTimer <= time)
- aPickUps[i].m_nTimer = 0;
- else
- aPickUps[i].m_nTimer -= time;
- }
- }
-}
-
-int32
-CPickups::GetActualPickupIndex(int32 index)
-{
- if (index == -1) return -1;
-
- // doesn't look nice
- if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1;
- return (uint16)index;
-}
-
-bool
-CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
-{
- CPlayerPed *player;
-
- if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
- else player = CWorld::Players[playerIndex].m_pPed;
-
- if (modelIndex == MI_PICKUP_ADRENALINE) {
- player->m_bAdrenalineActive = true;
- player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000;
- player->m_fCurrentStamina = player->m_fMaxStamina;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BODYARMOUR) {
- player->m_fArmour = 100.0f;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_INFO) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_HEALTH) {
- player->m_fHealth = 100.0f;
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BONUS) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_BRIBE) {
- int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1;
- if (level < 0) level = 0;
- player->SetWantedLevel(level);
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- } else if (modelIndex == MI_PICKUP_KILLFRENZY) {
- DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
- return true;
- }
- return false;
-}
-
-void
-CPickups::RemoveAllFloatingPickups()
-{
- for (int i = 0; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) {
- if (aPickUps[i].m_pObject) {
- CWorld::Remove(aPickUps[i].m_pObject);
- delete aPickUps[i].m_pObject;
- aPickUps[i].m_pObject = nil;
- }
- }
- }
-}
-
-void
-CPickups::RemovePickUp(int32 pickupIndex)
-{
- int32 index = CPickups::GetActualPickupIndex(pickupIndex);
- if (index == -1) return;
-
- if (aPickUps[index].m_pObject) {
- CWorld::Remove(aPickUps[index].m_pObject);
- delete aPickUps[index].m_pObject;
- aPickUps[index].m_pObject = nil;
- }
- aPickUps[index].m_eType = PICKUP_NONE;
- aPickUps[index].m_bRemoved = true;
-}
-
-int32
-CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity)
-{
- bool bFreeFound = false;
- int32 slot = 0;
-
- if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) {
- for (slot = NUMPICKUPS; slot >= 0; slot--) {
- if (aPickUps[slot].m_eType == PICKUP_NONE) {
- bFreeFound = true;
- break;
- }
- }
- } else {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_NONE) {
- bFreeFound = true;
- break;
- }
- }
- }
-
- if (!bFreeFound)
- {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_MONEY) break;
- }
-
- if (slot >= NUMGENERALPICKUPS)
- {
- for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
- if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break;
- }
-
- if (slot >= NUMGENERALPICKUPS) return -1;
- }
- }
-
- if (slot >= NUMPICKUPS) return -1;
-
- aPickUps[slot].m_eType = (ePickupType)type;
- aPickUps[slot].m_bRemoved = false;
- aPickUps[slot].m_nQuantity = quantity;
- if (type == PICKUP_ONCE_TIMEOUT)
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
- else if (type == PICKUP_MONEY)
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
- else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) {
- aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE;
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
- } else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) {
- aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE;
- aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
- }
- aPickUps[slot].m_eModelIndex = modelIndex;
- aPickUps[slot].m_vecPos = pos;
- aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
- if (aPickUps[slot].m_pObject)
- CWorld::Add(aPickUps[slot].m_pObject);
- return GetNewUniquePickupIndex(slot);
-}
-
-int32
-CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
-{
- return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
-}
-
-int32
-CPickups::GetNewUniquePickupIndex(int32 slot)
-{
- if (aPickUps[slot].m_nIndex >= 0xFFFE)
- aPickUps[slot].m_nIndex = 1;
- else
- aPickUps[slot].m_nIndex++;
- return slot | (aPickUps[slot].m_nIndex << 16);
-}
-
-int32
-CPickups::ModelForWeapon(eWeaponType weaponType)
-{
- switch (weaponType)
- {
- case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT;
- case WEAPONTYPE_COLT45: return MI_COLT;
- case WEAPONTYPE_UZI: return MI_UZI;
- case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN;
- case WEAPONTYPE_AK47: return MI_AK47;
- case WEAPONTYPE_M16: return MI_M16;
- case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER;
- case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER;
- case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER;
- case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV;
- case WEAPONTYPE_GRENADE: return MI_GRENADE;
- }
- return 0;
-}
-
-eWeaponType
-CPickups::WeaponForModel(int32 model)
-{
- if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
- switch (model)
- {
- case MI_GRENADE: return WEAPONTYPE_GRENADE;
- case MI_AK47: return WEAPONTYPE_AK47;
- case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT;
- case MI_COLT: return WEAPONTYPE_COLT45;
- case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV;
- case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER;
- case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN;
- case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE;
- case MI_UZI: return WEAPONTYPE_UZI;
- case MI_MISSILE: return WEAPONTYPE_UNARMED;
- case MI_M16: return WEAPONTYPE_M16;
- case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER;
- }
- return WEAPONTYPE_UNARMED;
-}
-
-int32
-CPickups::FindColourIndexForWeaponMI(int32 model)
-{
- return WeaponForModel(model) - 1;
-}
-
-void
-CPickups::AddToCollectedPickupsArray(int32 index)
-{
- aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16);
- if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS)
- CollectedPickUpIndex = 0;
-}
-
-void
-CPickups::Update()
-{
-#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
- if (CReplay::IsPlayingBack())
- return;
-#endif
-#define PICKUPS_FRAME_SPAN (6)
-#ifdef FIX_BUGS
- for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
-#else // BUG: this code can only reach 318 out of 320 pickups
- for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
-#endif
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-#undef PICKUPS_FRAME_SPAN
- for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-}
-
-void
-CPickups::DoPickUpEffects(CEntity *entity)
-{
- if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
- entity->m_flagD80 = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
-
- if (!entity->m_flagD80) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
- float modifiedSin = 0.3f * (s + 1.0f);
-
-
- int16 colorId;
-
- if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA)
- colorId = 11;
- else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE)
- colorId = 12;
- else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
- colorId = 13;
- else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS)
- colorId = 14;
- else
- colorId = FindColourIndexForWeaponMI(entity->GetModelIndex());
-
- assert(colorId >= 0);
-
- CVector &pos = entity->GetPosition();
-
- float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f;
- CShadows::StoreStaticShadow(
- (uintptr)entity,
- SHADOWTYPE_ADDITIVE,
- gpShadowExplosionTex,
- &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
-
- float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f;
- CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true);
- float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f;
- CCoronas::RegisterCorona( (uintptr)entity,
- aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f,
- 255,
- pos,
- size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-
- CObject *object = (CObject*)entity;
- if (object->m_obj_flag2 || object->bOutOfStock || object->field_172) {
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 12.0f;
-
- if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
- RwV3d vecOut;
- float fDistX, fDistY;
- if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) {
- aMessages[NumMessages].m_pos.x = vecOut.x;
- aMessages[NumMessages].m_pos.y = vecOut.y;
- aMessages[NumMessages].m_dist.x = fDistX;
- aMessages[NumMessages].m_dist.y = fDistY;
- aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex());
- aMessages[NumMessages].m_color.red = aWeaponReds[colorId];
- aMessages[NumMessages].m_color.green = aWeaponGreens[colorId];
- aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId];
- aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
- aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
- aMessages[NumMessages].m_quantity = object->field_172;
- NumMessages++;
- }
- }
- }
-
- entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]);
- }
-}
-
-void
-CPickups::DoMineEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 20.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200));
-
- int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- red, 0, 0,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
-}
-
-void
-CPickups::DoMoneyEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 20.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400));
-
- int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- 0, green, 0,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
-}
-
-void
-CPickups::DoCollectableEffects(CEntity *entity)
-{
- CVector &pos = entity->GetPosition();
- float dist = (TheCamera.GetPosition() - pos).Magnitude();
- const float MAXDIST = 14.0f;
-
- if (dist < MAXDIST) {
- float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
-
- int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f;
- CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
- 2.0f, 0.0f, 0.0f, -2.0f,
- 255, // this is 0 on PC which results in no shadow
- color, color, color,
- 4.0f, 1.0f, 40.0f, false, 0.0f);
- CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
- }
-
- entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
-}
-
-void
-CPickups::RenderPickUpText()
-{
- wchar *strToPrint;
- for (int32 i = 0; i < NumMessages; i++) {
- if (aMessages[i].m_quantity <= 39) {
- switch (aMessages[i].m_quantity) // could use some enum maybe
- {
- case 0:
- if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code?
- // what is this??
- sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
- } else {
- if (aMessages[i].m_bOutOfStock)
- strToPrint = TheText.Get("STOCK");
- else {
- sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]);
- AsciiToUnicode(gString, gUString);
- strToPrint = gUString;
- }
- }
- break;
- case 1:
- strToPrint = TheText.Get("SECURI");
- break;
- case 2:
- strToPrint = TheText.Get("MOONBM");
- break;
- case 3:
- strToPrint = TheText.Get("COACH");
- break;
- case 4:
- strToPrint = TheText.Get("FLATBED");
- break;
- case 5:
- strToPrint = TheText.Get("LINERUN");
- break;
- case 6:
- strToPrint = TheText.Get("TRASHM");
- break;
- case 7:
- strToPrint = TheText.Get("PATRIOT");
- break;
- case 8:
- strToPrint = TheText.Get("WHOOPEE");
- break;
- case 9:
- strToPrint = TheText.Get("BLISTA");
- break;
- case 10:
- strToPrint = TheText.Get("MULE");
- break;
- case 11:
- strToPrint = TheText.Get("YANKEE");
- break;
- case 12:
- strToPrint = TheText.Get("BOBCAT");
- break;
- case 13:
- strToPrint = TheText.Get("DODO");
- break;
- case 14:
- strToPrint = TheText.Get("BUS");
- break;
- case 15:
- strToPrint = TheText.Get("RUMPO");
- break;
- case 16:
- strToPrint = TheText.Get("PONY");
- break;
- case 17:
- strToPrint = TheText.Get("SENTINL");
- break;
- case 18:
- strToPrint = TheText.Get("CHEETAH");
- break;
- case 19:
- strToPrint = TheText.Get("BANSHEE");
- break;
- case 20:
- strToPrint = TheText.Get("IDAHO");
- break;
- case 21:
- strToPrint = TheText.Get("INFERNS");
- break;
- case 22:
- strToPrint = TheText.Get("TAXI");
- break;
- case 23:
- strToPrint = TheText.Get("KURUMA");
- break;
- case 24:
- strToPrint = TheText.Get("STRETCH");
- break;
- case 25:
- strToPrint = TheText.Get("PEREN");
- break;
- case 26:
- strToPrint = TheText.Get("STINGER");
- break;
- case 27:
- strToPrint = TheText.Get("MANANA");
- break;
- case 28:
- strToPrint = TheText.Get("LANDSTK");
- break;
- case 29:
- strToPrint = TheText.Get("STALION");
- break;
- case 30:
- strToPrint = TheText.Get("BFINJC");
- break;
- case 31:
- strToPrint = TheText.Get("CABBIE");
- break;
- case 32:
- strToPrint = TheText.Get("ESPERAN");
- break;
- case 33:
- strToPrint = TheText.Get("FIRETRK");
- break;
- case 34:
- strToPrint = TheText.Get("AMBULAN");
- break;
- case 35:
- strToPrint = TheText.Get("ENFORCR");
- break;
- case 36:
- strToPrint = TheText.Get("FBICAR");
- break;
- case 37:
- strToPrint = TheText.Get("RHINO");
- break;
- case 38:
- strToPrint = TheText.Get("BARRCKS");
- break;
- case 39:
- strToPrint = TheText.Get("POLICAR");
- break;
- default:
- break;
- }
- }
- CFont::SetPropOn();
- CFont::SetBackgroundOff();
-
- const float MAX_SCALE = 1.0f;
-
- float fScaleY = aMessages[i].m_dist.y / 100.0f;
- if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
-
- float fScaleX = aMessages[i].m_dist.x / 100.0f;
- if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
-
- CFont::SetScale(fScaleX, fScaleY);
- CFont::SetCentreOn();
- CFont::SetCentreSize(SCREEN_WIDTH);
- CFont::SetJustifyOff();
-
- CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha));
- CFont::SetBackGroundOnlyTextOff();
- CFont::SetFontStyle(FONT_BANK);
- CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
- }
- NumMessages = 0;
-}
-
-void
-CPickups::Load(uint8 *buf, uint32 size)
-{
-INITSAVEBUF
-
- for (int32 i = 0; i < NUMPICKUPS; i++) {
- aPickUps[i] = ReadSaveBuf<CPickup>(buf);
-
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil)
- aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1);
- }
-
- CollectedPickUpIndex = ReadSaveBuf<uint16>(buf);
- ReadSaveBuf<uint16>(buf);
- NumMessages = 0;
-
- for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- aPickUpsCollected[i] = ReadSaveBuf<int32>(buf);
-
-VALIDATESAVEBUF(size)
-}
-
-void
-CPickups::Save(uint8 *buf, uint32 *size)
-{
- *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
-
-INITSAVEBUF
-
- for (int32 i = 0; i < NUMPICKUPS; i++) {
- CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
- if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil)
- buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
- }
-
- WriteSaveBuf(buf, CollectedPickUpIndex);
- WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
-
- for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
- WriteSaveBuf(buf, aPickUpsCollected[i]);
-
-VALIDATESAVEBUF(*size)
-}
-
-STARTPATCHES
- InjectHook(0x430220, CPickups::Init, PATCH_JUMP);
- InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP);
- InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP);
- InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP);
- InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP);
- InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP);
- InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP);
- InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP);
- InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP);
- InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP);
- InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP);
- InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP);
- InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP);
- InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP);
- InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP);
- InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/
- InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP);
- InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP);
- InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP);
- InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP);
- InjectHook(0x433F60, CPickups::Load, PATCH_JUMP);
- InjectHook(0x433E40, CPickups::Save, PATCH_JUMP);
- InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP);
- InjectHook(0x430860, &CPickup::Update, PATCH_JUMP);
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+
+#include "Camera.h"
+#include "Coronas.h"
+#include "Darkel.h"
+#include "Entity.h"
+#include "Explosion.h"
+#include "Font.h"
+#include "Garages.h"
+#include "General.h"
+#include "ModelIndices.h"
+#include "Object.h"
+#include "Pad.h"
+#include "Pickups.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
+#include "Fire.h"
+#include "PointLights.h"
+#include "Pools.h"
+#ifdef FIX_BUGS
+#include "Replay.h"
+#endif
+#include "Script.h"
+#include "Shadows.h"
+#include "SpecialFX.h"
+#include "Sprite.h"
+#include "Timer.h"
+#include "WaterLevel.h"
+#include "World.h"
+
+CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98;
+int16 CPickups::NumMessages;// = *(int16*)0x95CC98;
+int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538;
+int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A;
+
+// unused
+bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71;
+CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8;
+CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8;
+uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C;
+
+tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
+
+// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4)
+uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
+uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 };
+uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
+
+uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 };
+uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 };
+uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 };
+float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f };
+
+void
+CPickup::RemoveKeepType()
+{
+ CWorld::Remove(m_pObject);
+ delete m_pObject;
+
+ m_bRemoved = true;
+ m_pObject = nil;
+}
+
+void
+CPickup::Remove()
+{
+ RemoveKeepType();
+ m_eType = PICKUP_NONE;
+}
+
+CObject *
+CPickup::GiveUsAPickUpObject(int32 handle)
+{
+ CObject *object;
+
+ if (handle <= 0) object = new CObject(m_eModelIndex, false);
+ else {
+ CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
+ object = new(handle) CObject(m_eModelIndex, false);
+ }
+
+ if (object == nil) return nil;
+ object->ObjectCreatedBy = MISSION_OBJECT;
+ object->GetPosition() = m_vecPos;
+ object->SetOrientation(0.0f, 0.0f, -HALFPI);
+ object->GetMatrix().UpdateRW();
+ object->UpdateRwFrame();
+
+ object->bAffectedByGravity = false;
+ object->bExplosionProof = true;
+ object->bUsesCollision = false;
+ object->bIsPickup = true;
+
+ object->m_nBonusValue = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
+
+ switch (m_eType)
+ {
+ case PICKUP_IN_SHOP:
+ object->m_obj_flag2 = true;
+ object->bOutOfStock = false;
+ break;
+ case PICKUP_ON_STREET:
+ case PICKUP_ONCE:
+ case PICKUP_ONCE_TIMEOUT:
+ case PICKUP_COLLECTABLE1:
+ case PICKUP_MONEY:
+ case PICKUP_MINE_INACTIVE:
+ case PICKUP_MINE_ARMED:
+ case PICKUP_NAUTICAL_MINE_INACTIVE:
+ case PICKUP_NAUTICAL_MINE_ARMED:
+ case PICKUP_FLOATINGPACKAGE:
+ case PICKUP_ON_STREET_SLOW:
+ object->m_obj_flag2 = false;
+ object->bOutOfStock = false;
+ break;
+ case PICKUP_IN_SHOP_OUT_OF_STOCK:
+ object->m_obj_flag2 = false;
+ object->bOutOfStock = true;
+ object->bRenderScorched = true;
+ break;
+ case PICKUP_FLOATINGPACKAGE_FLOATING:
+ default:
+ break;
+ }
+ return object;
+}
+
+bool
+CPickup::CanBePickedUp(CPlayerPed *player)
+{
+ assert(m_pObject != nil);
+ bool cannotBePickedUp =
+ (m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f)
+ || (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f)
+ || (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0)
+ || (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame));
+ return !cannotBePickedUp;
+}
+
+bool
+CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
+{
+ float waterLevel;
+
+ if (m_bRemoved) {
+ if (CTimer::GetTimeInMilliseconds() > m_nTimer) {
+ // respawn pickup if we're far enough
+ float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y);
+ if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) {
+ m_pObject = GiveUsAPickUpObject(-1);
+ if (m_pObject) {
+ CWorld::Add(m_pObject);
+ m_bRemoved = false;
+ }
+ }
+ }
+ return false;
+ }
+
+ if (!m_pObject) return false;
+
+ if (!IsMine()) {
+ // let's check if we touched the pickup
+ bool isPickupTouched = false;
+ if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) {
+ if (vehicle != nil) {
+ if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f))
+ isPickupTouched = true;
+ }
+ else {
+ if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
+ if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
+ (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
+ isPickupTouched = true;
+ }
+ }
+ } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) {
+ if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+ isPickupTouched = true;
+ }
+ } else if (vehicle == nil) {
+ if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
+ if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
+ (player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
+ isPickupTouched = true;
+ }
+ }
+
+ // if we didn't then we've got nothing to do
+ if (isPickupTouched && CanBePickedUp(player)) {
+ CPad::GetPad(0)->StartShake(120, 100);
+ switch (m_eType)
+ {
+ case PICKUP_IN_SHOP:
+ if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) {
+ CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
+ } else {
+ CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())];
+ if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+ player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+ player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
+ }
+ RemoveKeepType();
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ return true;
+ }
+ break;
+ case PICKUP_ON_STREET:
+ case PICKUP_ON_STREET_SLOW:
+ if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+ if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
+ player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+ if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) {
+ player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+ }
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
+ } else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) {
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+ CPickups::bPickUpcamActivated = true;
+ CPickups::pPlayerVehicle = FindPlayerVehicle();
+ CPickups::StaticCamCoors = m_pObject->GetPosition();
+ CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds();
+ }
+ }
+ if (m_eType == PICKUP_ON_STREET) {
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
+ } else if (m_eType == PICKUP_ON_STREET_SLOW) {
+ if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex)
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
+ else
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
+ }
+
+ RemoveKeepType();
+ return true;
+ case PICKUP_ONCE:
+ case PICKUP_ONCE_TIMEOUT:
+ if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+ if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
+ player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+ if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
+ player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+ }
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
+ }
+ Remove();
+ return true;
+ case PICKUP_COLLECTABLE1:
+ CWorld::Players[playerId].m_nCollectedPackages++;
+ CWorld::Players[playerId].m_nMoney += 1000;
+
+ if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) {
+ printf("All collectables have been picked up\n");
+ CGarages::TriggerMessage("CO_ALL", -1, 5000, -1);
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000;
+ } else
+ CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
+
+ Remove();
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
+ return true;
+ case PICKUP_MONEY:
+ CWorld::Players[playerId].m_nMoney += m_nQuantity;
+ sprintf(gString, "$%d", m_nQuantity);
+#ifdef MONEY_MESSAGES
+ CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f);
+#endif
+ Remove();
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
+ return true;
+ default:
+ break;
+ }
+ }
+ } else {
+ switch (m_eType)
+ {
+ case PICKUP_MINE_INACTIVE:
+ if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+ m_eType = PICKUP_MINE_ARMED;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ }
+ break;
+ case PICKUP_NAUTICAL_MINE_INACTIVE:
+ {
+ if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
+ m_pObject->GetPosition().z = waterLevel + 0.6f;
+
+ m_pObject->GetMatrix().UpdateRW();
+ m_pObject->UpdateRwFrame();
+
+ bool touched = false;
+ for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
+ CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
+ touched = true;
+ break; // added break here
+ }
+ }
+
+ if (!touched) {
+ m_eType = PICKUP_NAUTICAL_MINE_ARMED;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ }
+ break;
+ }
+ case PICKUP_NAUTICAL_MINE_ARMED:
+ if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
+ m_pObject->GetPosition().z = waterLevel + 0.6f;
+
+ m_pObject->GetMatrix().UpdateRW();
+ m_pObject->UpdateRwFrame();
+ // no break here
+ case PICKUP_MINE_ARMED:
+ {
+ bool explode = false;
+ if (CTimer::GetTimeInMilliseconds() > m_nTimer)
+ explode = true;
+ else {// added else here since vehicle lookup is useless
+ for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
+ CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
+ explode = true;
+ break; // added break here
+ }
+ }
+ }
+ if (explode) {
+ CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
+ Remove();
+ }
+ break;
+ }
+ case PICKUP_FLOATINGPACKAGE:
+ m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
+ m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep();
+
+ m_pObject->GetMatrix().UpdateRW();
+ m_pObject->UpdateRwFrame();
+ if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z)
+ m_eType = PICKUP_FLOATINGPACKAGE_FLOATING;
+ break;
+ case PICKUP_FLOATINGPACKAGE_FLOATING:
+ if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0))
+ m_pObject->GetPosition().z = waterLevel;
+
+ m_pObject->GetMatrix().UpdateRW();
+ m_pObject->UpdateRwFrame();
+ if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+ Remove();
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
+ return true;
+ }
+ break;
+ }
+ }
+ if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
+ Remove();
+ return false;
+}
+
+void
+CPickups::Init(void)
+{
+ NumMessages = 0;
+ for (int i = 0; i < NUMPICKUPS; i++) {
+ aPickUps[i].m_eType = PICKUP_NONE;
+ aPickUps[i].m_nIndex = 1;
+ aPickUps[i].m_pObject = nil;
+ }
+
+ for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+ aPickUpsCollected[i] = 0;
+
+ CollectedPickUpIndex = 0;
+}
+
+bool
+CPickups::IsPickUpPickedUp(int32 pickupId)
+{
+ for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) {
+ if (pickupId == aPickUpsCollected[i]) {
+ aPickUpsCollected[i] = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CPickups::PassTime(uint32 time)
+{
+ for (int i = 0; i < NUMPICKUPS; i++) {
+ if (aPickUps[i].m_eType != PICKUP_NONE) {
+ if (aPickUps[i].m_nTimer <= time)
+ aPickUps[i].m_nTimer = 0;
+ else
+ aPickUps[i].m_nTimer -= time;
+ }
+ }
+}
+
+int32
+CPickups::GetActualPickupIndex(int32 index)
+{
+ if (index == -1) return -1;
+
+ // doesn't look nice
+ if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1;
+ return (uint16)index;
+}
+
+bool
+CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
+{
+ CPlayerPed *player;
+
+ if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+ else player = CWorld::Players[playerIndex].m_pPed;
+
+ if (modelIndex == MI_PICKUP_ADRENALINE) {
+ player->m_bAdrenalineActive = true;
+ player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000;
+ player->m_fCurrentStamina = player->m_fMaxStamina;
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_BODYARMOUR) {
+ player->m_fArmour = 100.0f;
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_INFO) {
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_HEALTH) {
+ player->m_fHealth = 100.0f;
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_BONUS) {
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_BRIBE) {
+ int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1;
+ if (level < 0) level = 0;
+ player->SetWantedLevel(level);
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+ return true;
+ } else if (modelIndex == MI_PICKUP_KILLFRENZY) {
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+ return true;
+ }
+ return false;
+}
+
+void
+CPickups::RemoveAllFloatingPickups()
+{
+ for (int i = 0; i < NUMPICKUPS; i++) {
+ if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) {
+ if (aPickUps[i].m_pObject) {
+ CWorld::Remove(aPickUps[i].m_pObject);
+ delete aPickUps[i].m_pObject;
+ aPickUps[i].m_pObject = nil;
+ }
+ }
+ }
+}
+
+void
+CPickups::RemovePickUp(int32 pickupIndex)
+{
+ int32 index = CPickups::GetActualPickupIndex(pickupIndex);
+ if (index == -1) return;
+
+ if (aPickUps[index].m_pObject) {
+ CWorld::Remove(aPickUps[index].m_pObject);
+ delete aPickUps[index].m_pObject;
+ aPickUps[index].m_pObject = nil;
+ }
+ aPickUps[index].m_eType = PICKUP_NONE;
+ aPickUps[index].m_bRemoved = true;
+}
+
+int32
+CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity)
+{
+ bool bFreeFound = false;
+ int32 slot = 0;
+
+ if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) {
+ for (slot = NUMPICKUPS; slot >= 0; slot--) {
+ if (aPickUps[slot].m_eType == PICKUP_NONE) {
+ bFreeFound = true;
+ break;
+ }
+ }
+ } else {
+ for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+ if (aPickUps[slot].m_eType == PICKUP_NONE) {
+ bFreeFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!bFreeFound) {
+ for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+ if (aPickUps[slot].m_eType == PICKUP_MONEY) break;
+ }
+
+ if (slot >= NUMGENERALPICKUPS) {
+ for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+ if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break;
+ }
+
+ if (slot >= NUMGENERALPICKUPS) return -1;
+ }
+ }
+
+ if (slot >= NUMPICKUPS) return -1;
+
+ aPickUps[slot].m_eType = (ePickupType)type;
+ aPickUps[slot].m_bRemoved = false;
+ aPickUps[slot].m_nQuantity = quantity;
+ if (type == PICKUP_ONCE_TIMEOUT)
+ aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
+ else if (type == PICKUP_MONEY)
+ aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
+ else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) {
+ aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE;
+ aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
+ } else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) {
+ aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE;
+ aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
+ }
+ aPickUps[slot].m_eModelIndex = modelIndex;
+ aPickUps[slot].m_vecPos = pos;
+ aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
+ if (aPickUps[slot].m_pObject)
+ CWorld::Add(aPickUps[slot].m_pObject);
+ return GetNewUniquePickupIndex(slot);
+}
+
+int32
+CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
+{
+ return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
+}
+
+int32
+CPickups::GetNewUniquePickupIndex(int32 slot)
+{
+ if (aPickUps[slot].m_nIndex >= 0xFFFE)
+ aPickUps[slot].m_nIndex = 1;
+ else
+ aPickUps[slot].m_nIndex++;
+ return slot | (aPickUps[slot].m_nIndex << 16);
+}
+
+int32
+CPickups::ModelForWeapon(eWeaponType weaponType)
+{
+ switch (weaponType)
+ {
+ case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT;
+ case WEAPONTYPE_COLT45: return MI_COLT;
+ case WEAPONTYPE_UZI: return MI_UZI;
+ case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN;
+ case WEAPONTYPE_AK47: return MI_AK47;
+ case WEAPONTYPE_M16: return MI_M16;
+ case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER;
+ case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER;
+ case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER;
+ case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV;
+ case WEAPONTYPE_GRENADE: return MI_GRENADE;
+ }
+ return 0;
+}
+
+eWeaponType
+CPickups::WeaponForModel(int32 model)
+{
+ if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
+ switch (model)
+ {
+ case MI_GRENADE: return WEAPONTYPE_GRENADE;
+ case MI_AK47: return WEAPONTYPE_AK47;
+ case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT;
+ case MI_COLT: return WEAPONTYPE_COLT45;
+ case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV;
+ case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER;
+ case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN;
+ case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE;
+ case MI_UZI: return WEAPONTYPE_UZI;
+ case MI_MISSILE: return WEAPONTYPE_UNARMED;
+ case MI_M16: return WEAPONTYPE_M16;
+ case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER;
+ }
+ return WEAPONTYPE_UNARMED;
+}
+
+int32
+CPickups::FindColourIndexForWeaponMI(int32 model)
+{
+ return WeaponForModel(model) - 1;
+}
+
+void
+CPickups::AddToCollectedPickupsArray(int32 index)
+{
+ aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16);
+ if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS)
+ CollectedPickUpIndex = 0;
+}
+
+void
+CPickups::Update()
+{
+#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
+ if (CReplay::IsPlayingBack())
+ return;
+#endif
+#define PICKUPS_FRAME_SPAN (6)
+#ifdef FIX_BUGS
+ for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
+#else // BUG: this code can only reach 318 out of 320 pickups
+ for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
+#endif
+ if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
+ AddToCollectedPickupsArray(i);
+ }
+ }
+#undef PICKUPS_FRAME_SPAN
+ for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
+ if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
+ AddToCollectedPickupsArray(i);
+ }
+ }
+}
+
+void
+CPickups::DoPickUpEffects(CEntity *entity)
+{
+ if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
+ entity->bDoNotRender = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
+
+ if (!entity->bDoNotRender) {
+ float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
+ float modifiedSin = 0.3f * (s + 1.0f);
+
+
+ int16 colorId;
+
+ if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA)
+ colorId = 11;
+ else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE)
+ colorId = 12;
+ else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
+ colorId = 13;
+ else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS)
+ colorId = 14;
+ else
+ colorId = FindColourIndexForWeaponMI(entity->GetModelIndex());
+
+ assert(colorId >= 0);
+
+ CVector &pos = entity->GetPosition();
+
+ float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f;
+ CShadows::StoreStaticShadow(
+ (uintptr)entity,
+ SHADOWTYPE_ADDITIVE,
+ gpShadowExplosionTex,
+ &pos,
+ 2.0f, 0.0f, 0.0f, -2.0f,
+ 255, // this is 0 on PC which results in no shadow
+ aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier,
+ 4.0f, 1.0f, 40.0f, false, 0.0f);
+
+ float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f;
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true);
+ float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f;
+ CCoronas::RegisterCorona( (uintptr)entity,
+ aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f,
+ 255,
+ pos,
+ size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+
+ CObject *object = (CObject*)entity;
+ if (object->m_obj_flag2 || object->bOutOfStock || object->m_nBonusValue) {
+ float dist = (TheCamera.GetPosition() - pos).Magnitude();
+ const float MAXDIST = 12.0f;
+
+ if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
+ RwV3d vecOut;
+ float fDistX, fDistY;
+ if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) {
+ aMessages[NumMessages].m_pos.x = vecOut.x;
+ aMessages[NumMessages].m_pos.y = vecOut.y;
+ aMessages[NumMessages].m_dist.x = fDistX;
+ aMessages[NumMessages].m_dist.y = fDistY;
+ aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex());
+ aMessages[NumMessages].m_color.red = aWeaponReds[colorId];
+ aMessages[NumMessages].m_color.green = aWeaponGreens[colorId];
+ aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId];
+ aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
+ aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
+ aMessages[NumMessages].m_quantity = object->m_nBonusValue;
+ NumMessages++;
+ }
+ }
+ }
+
+ entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]);
+ }
+}
+
+void
+CPickups::DoMineEffects(CEntity *entity)
+{
+ CVector &pos = entity->GetPosition();
+ float dist = (TheCamera.GetPosition() - pos).Magnitude();
+ const float MAXDIST = 20.0f;
+
+ if (dist < MAXDIST) {
+ float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200));
+
+ int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f;
+ CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+ 2.0f, 0.0f, 0.0f, -2.0f,
+ 255, // this is 0 on PC which results in no shadow
+ red, 0, 0,
+ 4.0f, 1.0f, 40.0f, false, 0.0f);
+ CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ }
+
+ entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
+}
+
+void
+CPickups::DoMoneyEffects(CEntity *entity)
+{
+ CVector &pos = entity->GetPosition();
+ float dist = (TheCamera.GetPosition() - pos).Magnitude();
+ const float MAXDIST = 20.0f;
+
+ if (dist < MAXDIST) {
+ float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400));
+
+ int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f;
+ CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+ 2.0f, 0.0f, 0.0f, -2.0f,
+ 255, // this is 0 on PC which results in no shadow
+ 0, green, 0,
+ 4.0f, 1.0f, 40.0f, false, 0.0f);
+ CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ }
+
+ entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
+}
+
+void
+CPickups::DoCollectableEffects(CEntity *entity)
+{
+ CVector &pos = entity->GetPosition();
+ float dist = (TheCamera.GetPosition() - pos).Magnitude();
+ const float MAXDIST = 14.0f;
+
+ if (dist < MAXDIST) {
+ float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
+
+ int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f;
+ CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+ 2.0f, 0.0f, 0.0f, -2.0f,
+ 255, // this is 0 on PC which results in no shadow
+ color, color, color,
+ 4.0f, 1.0f, 40.0f, false, 0.0f);
+ CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ }
+
+ entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
+}
+
+void
+CPickups::RenderPickUpText()
+{
+ wchar *strToPrint;
+ for (int32 i = 0; i < NumMessages; i++) {
+ if (aMessages[i].m_quantity <= 39) {
+ switch (aMessages[i].m_quantity) // could use some enum maybe
+ {
+ case 0:
+ if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code?
+ // what is this??
+ sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
+ } else {
+ if (aMessages[i].m_bOutOfStock)
+ strToPrint = TheText.Get("STOCK");
+ else {
+ sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]);
+ AsciiToUnicode(gString, gUString);
+ strToPrint = gUString;
+ }
+ }
+ break;
+ case 1:
+ strToPrint = TheText.Get("SECURI");
+ break;
+ case 2:
+ strToPrint = TheText.Get("MOONBM");
+ break;
+ case 3:
+ strToPrint = TheText.Get("COACH");
+ break;
+ case 4:
+ strToPrint = TheText.Get("FLATBED");
+ break;
+ case 5:
+ strToPrint = TheText.Get("LINERUN");
+ break;
+ case 6:
+ strToPrint = TheText.Get("TRASHM");
+ break;
+ case 7:
+ strToPrint = TheText.Get("PATRIOT");
+ break;
+ case 8:
+ strToPrint = TheText.Get("WHOOPEE");
+ break;
+ case 9:
+ strToPrint = TheText.Get("BLISTA");
+ break;
+ case 10:
+ strToPrint = TheText.Get("MULE");
+ break;
+ case 11:
+ strToPrint = TheText.Get("YANKEE");
+ break;
+ case 12:
+ strToPrint = TheText.Get("BOBCAT");
+ break;
+ case 13:
+ strToPrint = TheText.Get("DODO");
+ break;
+ case 14:
+ strToPrint = TheText.Get("BUS");
+ break;
+ case 15:
+ strToPrint = TheText.Get("RUMPO");
+ break;
+ case 16:
+ strToPrint = TheText.Get("PONY");
+ break;
+ case 17:
+ strToPrint = TheText.Get("SENTINL");
+ break;
+ case 18:
+ strToPrint = TheText.Get("CHEETAH");
+ break;
+ case 19:
+ strToPrint = TheText.Get("BANSHEE");
+ break;
+ case 20:
+ strToPrint = TheText.Get("IDAHO");
+ break;
+ case 21:
+ strToPrint = TheText.Get("INFERNS");
+ break;
+ case 22:
+ strToPrint = TheText.Get("TAXI");
+ break;
+ case 23:
+ strToPrint = TheText.Get("KURUMA");
+ break;
+ case 24:
+ strToPrint = TheText.Get("STRETCH");
+ break;
+ case 25:
+ strToPrint = TheText.Get("PEREN");
+ break;
+ case 26:
+ strToPrint = TheText.Get("STINGER");
+ break;
+ case 27:
+ strToPrint = TheText.Get("MANANA");
+ break;
+ case 28:
+ strToPrint = TheText.Get("LANDSTK");
+ break;
+ case 29:
+ strToPrint = TheText.Get("STALION");
+ break;
+ case 30:
+ strToPrint = TheText.Get("BFINJC");
+ break;
+ case 31:
+ strToPrint = TheText.Get("CABBIE");
+ break;
+ case 32:
+ strToPrint = TheText.Get("ESPERAN");
+ break;
+ case 33:
+ strToPrint = TheText.Get("FIRETRK");
+ break;
+ case 34:
+ strToPrint = TheText.Get("AMBULAN");
+ break;
+ case 35:
+ strToPrint = TheText.Get("ENFORCR");
+ break;
+ case 36:
+ strToPrint = TheText.Get("FBICAR");
+ break;
+ case 37:
+ strToPrint = TheText.Get("RHINO");
+ break;
+ case 38:
+ strToPrint = TheText.Get("BARRCKS");
+ break;
+ case 39:
+ strToPrint = TheText.Get("POLICAR");
+ break;
+ default:
+ break;
+ }
+ }
+ CFont::SetPropOn();
+ CFont::SetBackgroundOff();
+
+ const float MAX_SCALE = 1.0f;
+
+ float fScaleY = aMessages[i].m_dist.y / 100.0f;
+ if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
+
+ float fScaleX = aMessages[i].m_dist.x / 100.0f;
+ if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
+
+ CFont::SetScale(fScaleX, fScaleY);
+ CFont::SetCentreOn();
+ CFont::SetCentreSize(SCREEN_WIDTH);
+ CFont::SetJustifyOff();
+
+ CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha));
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
+ }
+ NumMessages = 0;
+}
+
+void
+CPickups::Load(uint8 *buf, uint32 size)
+{
+INITSAVEBUF
+
+ for (int32 i = 0; i < NUMPICKUPS; i++) {
+ aPickUps[i] = ReadSaveBuf<CPickup>(buf);
+
+ if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil)
+ aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1);
+ }
+
+ CollectedPickUpIndex = ReadSaveBuf<uint16>(buf);
+ ReadSaveBuf<uint16>(buf);
+ NumMessages = 0;
+
+ for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+ aPickUpsCollected[i] = ReadSaveBuf<int32>(buf);
+
+VALIDATESAVEBUF(size)
+}
+
+void
+CPickups::Save(uint8 *buf, uint32 *size)
+{
+ *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
+
+INITSAVEBUF
+
+ for (int32 i = 0; i < NUMPICKUPS; i++) {
+ CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
+ if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil)
+ buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
+ }
+
+ WriteSaveBuf(buf, CollectedPickUpIndex);
+ WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
+
+ for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+ WriteSaveBuf(buf, aPickUpsCollected[i]);
+
+VALIDATESAVEBUF(*size)
+}
+
+void
+CPacManPickup::Update()
+{
+ if (FindPlayerVehicle() == nil) return;
+
+ CVehicle *veh = FindPlayerVehicle();
+
+ if (DistanceSqr2D(FindPlayerVehicle()->GetPosition(), m_vecPosn.x, m_vecPosn.y) < 100.0f && veh->IsSphereTouchingVehicle(m_vecPosn.x, m_vecPosn.y, m_vecPosn.z, 1.5f)) {
+ switch (m_eType)
+ {
+ case PACMAN_SCRAMBLE:
+ {
+ veh->m_nPacManPickupsCarried++;
+ veh->m_vecMoveSpeed *= 0.65f;
+ float massMult = (veh->m_fMass + 250.0f) / veh->m_fMass;
+ veh->m_fMass *= massMult;
+ veh->m_fTurnMass *= massMult;
+ veh->m_fForceMultiplier *= massMult;
+ FindPlayerPed()->m_pWanted->m_nChaos += 10;
+ FindPlayerPed()->m_pWanted->UpdateWantedLevel();
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PACKAGE, 0);
+ break;
+ }
+ case PACMAN_RACE:
+ CPacManPickups::PillsEatenInRace++;
+ DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PILL, 0);
+ break;
+ default:
+ break;
+ }
+ m_eType = PACMAN_NONE;
+ if (m_pObject != nil) {
+ CWorld::Remove(m_pObject);
+ delete m_pObject;
+ m_pObject = nil;
+ }
+ }
+}
+
+int32 CollectGameState;
+int16 ThingsToCollect;
+
+CPacManPickup CPacManPickups::aPMPickUps[NUMPACMANPICKUPS];
+CVector CPacManPickups::LastPickUpCoors;
+int32 CPacManPickups::PillsEatenInRace;
+bool CPacManPickups::bPMActive;
+
+void
+CPacManPickups::Init()
+{
+ for (int i = 0; i < NUMPACMANPICKUPS; i++)
+ aPMPickUps[i].m_eType = PACMAN_NONE;
+ bPMActive = false;
+}
+
+void
+CPacManPickups::Update()
+{
+ if (FindPlayerVehicle()) {
+ float dist = Distance(FindPlayerCoors(), CVector(1072.0f, -948.0f, 14.5f));
+ switch (CollectGameState) {
+ case 1:
+ if (dist < 10.0f) {
+ ThingsToCollect -= FindPlayerVehicle()->m_nPacManPickupsCarried;
+ FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
+ FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
+ FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
+ FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
+ }
+ if (ThingsToCollect <= 0) {
+ CollectGameState = 2;
+ ClearPMPickUps();
+ }
+ break;
+ case 2:
+ if (dist > 11.0f)
+ CollectGameState = 0;
+ break;
+ case 20:
+ if (Distance(FindPlayerCoors(), LastPickUpCoors) > 30.0f) {
+ LastPickUpCoors = FindPlayerCoors();
+ printf("%f, %f, %f,\n", LastPickUpCoors.x, LastPickUpCoors.y, LastPickUpCoors.z);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (bPMActive) {
+#define PACMANPICKUPS_FRAME_SPAN (4)
+ for (uint32 i = (CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i < ((CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) + 1) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i++) {
+ if (aPMPickUps[i].m_eType != PACMAN_NONE)
+ aPMPickUps[i].Update();
+ }
+#undef PACMANPICKUPS_FRAME_SPAN
+ }
+}
+
+void
+CPacManPickups::GeneratePMPickUps(CVector pos, float scrambleMult, int16 count, uint8 type)
+{
+ int i = 0;
+ while (count > 0) {
+ while (aPMPickUps[i].m_eType != PACMAN_NONE)
+ i++;
+
+ bool bPickupCreated = false;
+ while (!bPickupCreated) {
+ CVector newPos = pos;
+ CColPoint colPoint;
+ CEntity *pRoad;
+ uint16 nRand = CGeneral::GetRandomNumber();
+ newPos.x += ((nRand & 0xFF) - 128) * scrambleMult / 128.0f;
+ newPos.y += (((nRand >> 8) & 0xFF) - 128) * scrambleMult / 128.0f;
+ newPos.z = 1000.0f;
+ if (CWorld::ProcessVerticalLine(newPos, -1000.0f, colPoint, pRoad, true, false, false, false, true, false, nil) && pRoad->IsBuilding() && ((CBuilding*)pRoad)->GetIsATreadable()) {
+ newPos.z = 0.7f + colPoint.point.z;
+ aPMPickUps[i].m_eType = type;
+ aPMPickUps[i].m_vecPosn = newPos;
+ CObject *obj = new CObject(MI_BULLION, true);
+ if (obj != nil) {
+ obj->ObjectCreatedBy = MISSION_OBJECT;
+ obj->GetPosition() = aPMPickUps[i].m_vecPosn;
+ obj->SetOrientation(0.0f, 0.0f, -HALFPI);
+ obj->GetMatrix().UpdateRW();
+ obj->UpdateRwFrame();
+
+ obj->bAffectedByGravity = false;
+ obj->bExplosionProof = true;
+ obj->bUsesCollision = false;
+ obj->bIsPickup = false;
+ CWorld::Add(obj);
+ }
+ aPMPickUps[i].m_pObject = obj;
+ bPickupCreated = true;
+ }
+ }
+ count--;
+ }
+ bPMActive = true;
+}
+
+// diablo porn mission pickups
+static const CVector aRacePoints1[] = {
+ CVector(913.62219f, -155.13692f, 4.9699469f),
+ CVector(913.92401f, -124.12943f, 4.9692569f),
+ CVector(913.27899f, -93.524231f, 7.4325991f),
+ CVector(912.60852f, -63.15905f, 7.4533591f),
+ CVector(934.22144f, -42.049122f, 7.4511471f),
+ CVector(958.88092f, -23.863735f, 7.4652338f),
+ CVector(978.50812f, -0.78458798f, 5.13515f),
+ CVector(1009.4175f, -2.1041219f, 2.4461579f),
+ CVector(1040.6313f, -2.0793829f, 2.293175f),
+ CVector(1070.7863f, -2.084095f, 2.2789791f),
+ CVector(1100.5773f, -8.468729f, 5.3248072f),
+ CVector(1119.9341f, -31.738031f, 7.1913071f),
+ CVector(1122.1664f, -62.762737f, 7.4703908f),
+ CVector(1122.814f, -93.650566f, 8.5577497f),
+ CVector(1125.8253f, -124.26616f, 9.9803305f),
+ CVector(1153.8727f, -135.47169f, 14.150617f),
+ CVector(1184.0831f, -135.82845f, 14.973998f),
+ CVector(1192.0432f, -164.57816f, 19.18627f),
+ CVector(1192.7761f, -194.28871f, 24.799675f),
+ CVector(1215.1527f, -215.0714f, 25.74975f),
+ CVector(1245.79f, -215.39304f, 28.70726f),
+ CVector(1276.2477f, -216.39485f, 33.71236f),
+ CVector(1306.5535f, -216.71007f, 39.711472f),
+ CVector(1335.0244f, -224.59329f, 46.474979f),
+ CVector(1355.4879f, -246.27664f, 49.934841f),
+ CVector(1362.6003f, -276.47064f, 49.96265f),
+ CVector(1363.027f, -307.30847f, 49.969173f),
+ CVector(1365.343f, -338.08609f, 49.967789f),
+ CVector(1367.5957f, -368.01105f, 50.092304f),
+ CVector(1368.2749f, -398.38049f, 50.061268f),
+ CVector(1366.9034f, -429.98483f, 50.057545f),
+ CVector(1356.8534f, -459.09259f, 50.035545f),
+ CVector(1335.5819f, -481.13544f, 47.217903f),
+ CVector(1306.7552f, -491.07443f, 40.202629f),
+ CVector(1275.5978f, -491.33194f, 33.969223f),
+ CVector(1244.702f, -491.46451f, 29.111021f),
+ CVector(1213.2222f, -491.8754f, 25.771168f),
+ CVector(1182.7729f, -492.19995f, 24.749964f),
+ CVector(1152.6874f, -491.42221f, 21.70038f),
+ CVector(1121.5352f, -491.94604f, 20.075182f),
+ CVector(1090.7056f, -492.63751f, 17.585758f),
+ CVector(1059.6008f, -491.65762f, 14.848632f),
+ CVector(1029.113f, -489.66031f, 14.918498f),
+ CVector(998.20679f, -486.78107f, 14.945688f),
+ CVector(968.00555f, -484.91266f, 15.001229f),
+ CVector(937.74939f, -492.09015f, 14.958629f),
+ CVector(927.17352f, -520.97736f, 14.972308f),
+ CVector(929.29749f, -552.08643f, 14.978855f),
+ CVector(950.69525f, -574.47778f, 14.972788f),
+ CVector(974.02826f, -593.56024f, 14.966445f),
+ CVector(989.04779f, -620.12854f, 14.951016f),
+ CVector(1014.1639f, -637.3905f, 14.966736f),
+ CVector(1017.5961f, -667.3736f, 14.956415f),
+ CVector(1041.9735f, -685.94391f, 15.003841f),
+ CVector(1043.3064f, -716.11298f, 14.974236f),
+ CVector(1043.5337f, -746.63855f, 14.96919f),
+ CVector(1044.142f, -776.93823f, 14.965424f),
+ CVector(1044.2657f, -807.29395f, 14.97171f),
+ CVector(1017.0797f, -820.1076f, 14.975431f),
+ CVector(986.23865f, -820.37103f, 14.972883f),
+ CVector(956.10065f, -820.23291f, 14.981133f),
+ CVector(925.86914f, -820.19049f, 14.976553f),
+ CVector(897.69702f, -831.08734f, 14.962709f),
+ CVector(868.06586f, -835.99237f, 14.970685f),
+ CVector(836.93054f, -836.84387f, 14.965049f),
+ CVector(811.63586f, -853.7915f, 15.067576f),
+ CVector(811.46344f, -884.27368f, 12.247812f),
+ CVector(811.60651f, -914.70959f, 9.2393751f),
+ CVector(811.10425f, -945.16272f, 5.817255f),
+ CVector(816.54584f, -975.64587f, 4.998558f),
+ CVector(828.2951f, -1003.3685f, 5.0471172f),
+ CVector(852.28839f, -1021.5963f, 4.9371028f),
+ CVector(882.50067f, -1025.4459f, 5.14077f),
+ CVector(912.84821f, -1026.7874f, 8.3415451f),
+ CVector(943.68274f, -1026.6914f, 11.341879f),
+ CVector(974.4129f, -1027.3682f, 14.410345f),
+ CVector(1004.1079f, -1036.0778f, 14.92961f),
+ CVector(1030.1144f, -1051.1224f, 14.850387f),
+ CVector(1058.7585f, -1060.342f, 14.821624f),
+ CVector(1087.7797f, -1068.3263f, 14.800561f),
+ CVector(1099.8807f, -1095.656f, 11.877907f),
+ CVector(1130.0005f, -1101.994f, 11.853914f),
+ CVector(1160.3809f, -1101.6355f, 11.854824f),
+ CVector(1191.8524f, -1102.1577f, 11.853843f),
+ CVector(1223.3307f, -1102.7448f, 11.852233f),
+ CVector(1253.564f, -1098.1045f, 11.853944f),
+ CVector(1262.0203f, -1069.1785f, 14.8147f),
+ CVector(1290.9998f, -1059.1882f, 14.816016f),
+ CVector(1316.246f, -1041.0635f, 14.81109f),
+ CVector(1331.7539f, -1013.835f, 14.81207f),
+ CVector(1334.0579f, -983.55402f, 14.827253f),
+ CVector(1323.2429f, -954.23083f, 14.954678f),
+ CVector(1302.7495f, -932.21216f, 14.962917f),
+ CVector(1317.418f, -905.89325f, 14.967506f),
+ CVector(1337.9503f, -883.5025f, 14.969675f),
+ CVector(1352.6929f, -855.96954f, 14.967854f),
+ CVector(1357.2388f, -826.26971f, 14.97295f),
+ CVector(1384.8668f, -812.47693f, 12.907736f),
+ CVector(1410.8983f, -795.39056f, 12.052228f),
+ CVector(1433.901f, -775.55811f, 11.96265f),
+ CVector(1443.8615f, -746.92511f, 11.976114f),
+ CVector(1457.7015f, -720.00903f, 11.971177f),
+ CVector(1481.5685f, -701.30237f, 11.977908f),
+ CVector(1511.4004f, -696.83295f, 11.972709f),
+ CVector(1542.1796f, -695.61676f, 11.970441f),
+ CVector(1570.3301f, -684.6239f, 11.969202f),
+ CVector(0.0f, 0.0f, 0.0f),
+};
+
+void
+CPacManPickups::GeneratePMPickUpsForRace(int32 race)
+{
+ const CVector *pPos = nil;
+ int i = 0;
+
+ if (race == 0) pPos = aRacePoints1; // there's only one available
+ assert(pPos != nil);
+
+ while (!pPos->IsZero()) {
+ while (aPMPickUps[i].m_eType != PACMAN_NONE)
+ i++;
+
+ aPMPickUps[i].m_eType = PACMAN_RACE;
+ aPMPickUps[i].m_vecPosn = *(pPos++);
+ if (race == 0) {
+ CObject* obj = new CObject(MI_DONKEYMAG, true);
+ if (obj != nil) {
+ obj->ObjectCreatedBy = MISSION_OBJECT;
+
+ obj->GetPosition() = aPMPickUps[i].m_vecPosn;
+ obj->SetOrientation(0.0f, 0.0f, -HALFPI);
+ obj->GetMatrix().UpdateRW();
+ obj->UpdateRwFrame();
+
+ obj->bAffectedByGravity = false;
+ obj->bExplosionProof = true;
+ obj->bUsesCollision = false;
+ obj->bIsPickup = false;
+
+ CWorld::Add(obj);
+ }
+ aPMPickUps[i].m_pObject = obj;
+ } else
+ aPMPickUps[i].m_pObject = nil;
+ }
+ bPMActive = true;
+}
+
+void
+CPacManPickups::GenerateOnePMPickUp(CVector pos)
+{
+ bPMActive = true;
+ aPMPickUps[0].m_eType = PACMAN_RACE;
+ aPMPickUps[0].m_vecPosn = pos;
+}
+
+void
+CPacManPickups::Render()
+{
+ if (!bPMActive) return;
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[6]));
+
+ RwV3d pos;
+ float w, h;
+
+ for (int i = 0; i < NUMPACMANPICKUPS; i++) {
+ switch (aPMPickUps[i].m_eType)
+ {
+ case PACMAN_SCRAMBLE:
+ case PACMAN_RACE:
+ if (CSprite::CalcScreenCoors(aPMPickUps[i].m_vecPosn, &pos, &w, &h, true) && pos.z < 100.0f) {
+ if (aPMPickUps[i].m_pObject != nil) {
+ aPMPickUps[i].m_pObject->GetMatrix().SetRotateZOnly((CTimer::GetTimeInMilliseconds() % 1024) * TWOPI / 1024.0f);
+ aPMPickUps[i].m_pObject->GetMatrix().UpdateRW();
+ aPMPickUps[i].m_pObject->UpdateRwFrame();
+ }
+ float fsin = Sin((CTimer::GetTimeInMilliseconds() % 1024) * 6.28f / 1024.0f); // yes, it is 6.28f when it was TWOPI just now...
+ CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z, 0.8f * w * fsin, 0.8f * h, 100, 50, 5, 255, 1.0f / pos.z, 255);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE);
+}
+
+void
+CPacManPickups::ClearPMPickUps()
+{
+ bPMActive = false;
+
+ for (int i = 0; i < NUMPACMANPICKUPS; i++) {
+ if (aPMPickUps[i].m_pObject != nil) {
+ CWorld::Remove(aPMPickUps[i].m_pObject);
+ delete aPMPickUps[i].m_pObject;
+ aPMPickUps[i].m_pObject = nil;
+ }
+ aPMPickUps[i].m_eType = PACMAN_NONE;
+ }
+}
+
+void
+CPacManPickups::StartPacManRace(int32 race)
+{
+ GeneratePMPickUpsForRace(race);
+ PillsEatenInRace = 0;
+}
+
+void
+CPacManPickups::StartPacManRecord()
+{
+ CollectGameState = 20;
+ LastPickUpCoors = FindPlayerCoors();
+}
+
+uint32
+CPacManPickups::QueryPowerPillsEatenInRace()
+{
+ return PillsEatenInRace;
+}
+
+void
+CPacManPickups::ResetPowerPillsEatenInRace()
+{
+ PillsEatenInRace = 0;
+}
+
+void
+CPacManPickups::CleanUpPacManStuff()
+{
+ ClearPMPickUps();
+}
+
+void
+CPacManPickups::StartPacManScramble(CVector pos, float scrambleMult, int16 count)
+{
+ GeneratePMPickUps(pos, scrambleMult, count, PACMAN_SCRAMBLE);
+}
+
+uint32
+CPacManPickups::QueryPowerPillsCarriedByPlayer()
+{
+ if (FindPlayerVehicle())
+ return FindPlayerVehicle()->m_nPacManPickupsCarried;
+ return 0;
+}
+
+void
+CPacManPickups::ResetPowerPillsCarriedByPlayer()
+{
+ if (FindPlayerVehicle() != nil) {
+ FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
+ FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
+ FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
+ FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x430220, CPickups::Init, PATCH_JUMP);
+ InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP);
+ InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP);
+ InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP);
+ InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP);
+ InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP);
+ InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP);
+ InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP);
+ InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP);
+ InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP);
+ InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP);
+ InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP);
+ InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP);
+ InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP);
+ InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP);
+ InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/
+ InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP);
+ InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP);
+ InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP);
+ InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP);
+ InjectHook(0x433F60, CPickups::Load, PATCH_JUMP);
+ InjectHook(0x433E40, CPickups::Save, PATCH_JUMP);
+ InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP);
+ InjectHook(0x430860, &CPickup::Update, PATCH_JUMP);
+ InjectHook(0x4331B0, &CPacManPickup::Update, PATCH_JUMP);
+ InjectHook(0x432760, CPacManPickups::Init, PATCH_JUMP);
+ InjectHook(0x432800, CPacManPickups::Update, PATCH_JUMP);
+ InjectHook(0x432AE0, CPacManPickups::GeneratePMPickUps, PATCH_JUMP);
+ InjectHook(0x432D50, CPacManPickups::GeneratePMPickUpsForRace, PATCH_JUMP);
+ InjectHook(0x432F20, CPacManPickups::GenerateOnePMPickUp, PATCH_JUMP);
+ InjectHook(0x432F60, CPacManPickups::Render, PATCH_JUMP);
+ InjectHook(0x433150, CPacManPickups::ClearPMPickUps, PATCH_JUMP);
+ InjectHook(0x433340, CPacManPickups::StartPacManRace, PATCH_JUMP);
+ InjectHook(0x433360, CPacManPickups::StartPacManRecord, PATCH_JUMP);
+ InjectHook(0x4333A0, CPacManPickups::QueryPowerPillsEatenInRace, PATCH_JUMP);
+ InjectHook(0x4333B0, CPacManPickups::ResetPowerPillsEatenInRace, PATCH_JUMP);
+ InjectHook(0x4333C0, CPacManPickups::CleanUpPacManStuff, PATCH_JUMP);
+ InjectHook(0x4333D0, CPacManPickups::StartPacManScramble, PATCH_JUMP);
+ InjectHook(0x4333F0, CPacManPickups::QueryPowerPillsCarriedByPlayer, PATCH_JUMP);
+ InjectHook(0x433410, CPacManPickups::ResetPowerPillsCarriedByPlayer, PATCH_JUMP);
+
+ENDPATCHES
diff --git a/src/control/Pickups.h b/src/control/Pickups.h
index 4bb0ddff..b5b4f396 100644
--- a/src/control/Pickups.h
+++ b/src/control/Pickups.h
@@ -1,124 +1,147 @@
-#pragma once
-#include "Weapon.h"
-
-enum ePickupType : uint8
-{
- PICKUP_NONE = 0,
- PICKUP_IN_SHOP,
- PICKUP_ON_STREET,
- PICKUP_ONCE,
- PICKUP_ONCE_TIMEOUT,
- PICKUP_COLLECTABLE1,
- PICKUP_IN_SHOP_OUT_OF_STOCK,
- PICKUP_MONEY,
- PICKUP_MINE_INACTIVE,
- PICKUP_MINE_ARMED,
- PICKUP_NAUTICAL_MINE_INACTIVE,
- PICKUP_NAUTICAL_MINE_ARMED,
- PICKUP_FLOATINGPACKAGE,
- PICKUP_FLOATINGPACKAGE_FLOATING,
- PICKUP_ON_STREET_SLOW,
- PICKUP_NUMOFTYPES
-};
-
-class CEntity;
-class CObject;
-class CVehicle;
-class CPlayerPed;
-
-class CPickup
-{
-public:
- ePickupType m_eType;
- bool m_bRemoved;
- uint16 m_nQuantity;
- CObject *m_pObject;
- uint32 m_nTimer;
- int16 m_eModelIndex;
- uint16 m_nIndex;
- CVector m_vecPos;
-
- CObject *GiveUsAPickUpObject(int32 handle);
- bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
-private:
- bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
- inline bool CanBePickedUp(CPlayerPed *player);
- void RemoveKeepType();
- void Remove();
-};
-
-static_assert(sizeof(CPickup) == 0x1C, "CPickup: error");
-
-struct tPickupMessage
-{
- CVector2D m_pos;
- eWeaponType m_weaponType;
- CVector2D m_dist;
- CRGBA m_color;
- uint8 m_bOutOfStock : 1;
- uint8 m_quantity;
-};
-
-class CPickups
-{
- static int32 aPickUpsCollected[NUMCOLLECTEDPICKUPS];
- static int16 CollectedPickUpIndex;
- static int16 NumMessages;
- static tPickupMessage aMessages[NUMPICKUPMESSAGES];
-public:
- static void Init();
- static void Update();
- static void RenderPickUpText();
- static void DoCollectableEffects(CEntity *ent);
- static void DoMoneyEffects(CEntity *ent);
- static void DoMineEffects(CEntity *ent);
- static void DoPickUpEffects(CEntity *ent);
- static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity);
- static int32 GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity);
- static void RemovePickUp(int32 pickupIndex);
- static void RemoveAllFloatingPickups();
- static void AddToCollectedPickupsArray(int32 index);
- static bool IsPickUpPickedUp(int32 pickupId);
- static int32 ModelForWeapon(eWeaponType weaponType);
- static enum eWeaponType WeaponForModel(int32 model);
- static int32 FindColourIndexForWeaponMI(int32 model);
- static int32 GetActualPickupIndex(int32 index);
- static int32 GetNewUniquePickupIndex(int32 slot);
- static void PassTime(uint32 time);
- static bool GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex);
- static void Load(uint8 *buf, uint32 size);
- static void Save(uint8 *buf, uint32 *size);
-
- static CPickup(&aPickUps)[NUMPICKUPS];
-
- // unused
- static bool &bPickUpcamActivated;
- static CVehicle *&pPlayerVehicle;
- static CVector &StaticCamCoors;
- static uint32 &StaticCamStartTime;
-};
-
-extern uint16 AmmoForWeapon[20];
-extern uint16 AmmoForWeapon_OnStreet[20];
-extern uint16 CostOfWeapon[20];
-
-class CPacManPickups
-{
-public:
- static void Init(void);
- static void Update(void);
- static void GeneratePMPickUps(CVector, float, int16, uint8);
- static void GeneratePMPickUpsForRace(int32);
- static void GenerateOnePMPickUp(CVector);
- static void Render(void);
- static void DoCleanUpPacManStuff(void);
- static void StartPacManRace(int32);
- static void StartPacManRecord(void);
- static uint32 QueryPowerPillsEatenInRace(void);
- static void ResetPowerPillsEatenInRace(void);
- static void CleanUpPacManStuff(void);
- static void StartPacManScramble(CVector, float, int16);
- static uint32 QueryPowerPillsCarriedByPlayer(void);
- static void ResetPowerPillsCarriedByPlayer(void);
-
-};
+#pragma once
+#include "Weapon.h"
+
+enum ePickupType : uint8
+{
+ PICKUP_NONE = 0,
+ PICKUP_IN_SHOP,
+ PICKUP_ON_STREET,
+ PICKUP_ONCE,
+ PICKUP_ONCE_TIMEOUT,
+ PICKUP_COLLECTABLE1,
+ PICKUP_IN_SHOP_OUT_OF_STOCK,
+ PICKUP_MONEY,
+ PICKUP_MINE_INACTIVE,
+ PICKUP_MINE_ARMED,
+ PICKUP_NAUTICAL_MINE_INACTIVE,
+ PICKUP_NAUTICAL_MINE_ARMED,
+ PICKUP_FLOATINGPACKAGE,
+ PICKUP_FLOATINGPACKAGE_FLOATING,
+ PICKUP_ON_STREET_SLOW,
+ PICKUP_NUMOFTYPES
+};
+
+class CEntity;
+class CObject;
+class CVehicle;
+class CPlayerPed;
+
+class CPickup
+{
+public:
+ ePickupType m_eType;
+ bool m_bRemoved;
+ uint16 m_nQuantity;
+ CObject *m_pObject;
+ uint32 m_nTimer;
+ int16 m_eModelIndex;
+ uint16 m_nIndex;
+ CVector m_vecPos;
+
+ CObject *GiveUsAPickUpObject(int32 handle);
+ bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
+private:
+ bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
+ inline bool CanBePickedUp(CPlayerPed *player);
+ void RemoveKeepType();
+ void Remove();
+};
+
+static_assert(sizeof(CPickup) == 0x1C, "CPickup: error");
+
+struct tPickupMessage
+{
+ CVector2D m_pos;
+ eWeaponType m_weaponType;
+ CVector2D m_dist;
+ CRGBA m_color;
+ uint8 m_bOutOfStock : 1;
+ uint8 m_quantity;
+};
+
+class CPickups
+{
+ static int32 aPickUpsCollected[NUMCOLLECTEDPICKUPS];
+ static int16 CollectedPickUpIndex;
+ static int16 NumMessages;
+ static tPickupMessage aMessages[NUMPICKUPMESSAGES];
+public:
+ static void Init();
+ static void Update();
+ static void RenderPickUpText();
+ static void DoCollectableEffects(CEntity *ent);
+ static void DoMoneyEffects(CEntity *ent);
+ static void DoMineEffects(CEntity *ent);
+ static void DoPickUpEffects(CEntity *ent);
+ static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity);
+ static int32 GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity);
+ static void RemovePickUp(int32 pickupIndex);
+ static void RemoveAllFloatingPickups();
+ static void AddToCollectedPickupsArray(int32 index);
+ static bool IsPickUpPickedUp(int32 pickupId);
+ static int32 ModelForWeapon(eWeaponType weaponType);
+ static enum eWeaponType WeaponForModel(int32 model);
+ static int32 FindColourIndexForWeaponMI(int32 model);
+ static int32 GetActualPickupIndex(int32 index);
+ static int32 GetNewUniquePickupIndex(int32 slot);
+ static void PassTime(uint32 time);
+ static bool GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex);
+ static void Load(uint8 *buf, uint32 size);
+ static void Save(uint8 *buf, uint32 *size);
+
+ static CPickup(&aPickUps)[NUMPICKUPS];
+
+ // unused
+ static bool &bPickUpcamActivated;
+ static CVehicle *&pPlayerVehicle;
+ static CVector &StaticCamCoors;
+ static uint32 &StaticCamStartTime;
+};
+
+extern uint16 AmmoForWeapon[20];
+extern uint16 AmmoForWeapon_OnStreet[20];
+extern uint16 CostOfWeapon[20];
+
+enum ePacmanPickupType
+{
+ PACMAN_NONE,
+ PACMAN_SCRAMBLE,
+ PACMAN_RACE,
+};
+
+class CPacManPickup
+{
+public:
+ CVector m_vecPosn;
+ CObject *m_pObject;
+ uint8 m_eType;
+
+ void Update();
+};
+
+class CPacManPickups
+{
+ friend CPacManPickup;
+
+ static CPacManPickup aPMPickUps[NUMPACMANPICKUPS];
+ static CVector LastPickUpCoors;
+ static int PillsEatenInRace;
+ static bool bPMActive;
+public:
+ static void Init(void);
+ static void Update(void);
+ static void GeneratePMPickUps(CVector, float, int16, uint8);
+ static void GeneratePMPickUpsForRace(int32);
+ static void GenerateOnePMPickUp(CVector);
+ static void Render(void);
+ static void StartPacManRace(int32);
+ static void StartPacManRecord(void);
+ static uint32 QueryPowerPillsEatenInRace(void);
+ static void ResetPowerPillsEatenInRace(void);
+ static void ClearPMPickUps(void);
+ static void CleanUpPacManStuff(void);
+ static void StartPacManScramble(CVector, float, int16);
+ static uint32 QueryPowerPillsCarriedByPlayer(void);
+ static void ResetPowerPillsCarriedByPlayer(void);
+
+};
diff --git a/src/control/PowerPoints.cpp b/src/control/PowerPoints.cpp
index 4bc773a9..9a74e8d9 100644
--- a/src/control/PowerPoints.cpp
+++ b/src/control/PowerPoints.cpp
@@ -1,22 +1,22 @@
-#include "common.h"
-#include "PowerPoints.h"
-
-// Some cut beta feature
-
-void CPowerPoint::Update()
-{}
-
-void CPowerPoints::Init()
-{}
-
-void CPowerPoints::Update()
-{}
-
-void CPowerPoints::GenerateNewOne(float, float, float, float, float, float, uint8)
-{}
-
-void CPowerPoints::Save(uint8**, uint32*)
-{}
-
-void CPowerPoints::Load(uint8*, uint32)
+#include "common.h"
+#include "PowerPoints.h"
+
+// Some cut beta feature
+
+void CPowerPoint::Update()
+{}
+
+void CPowerPoints::Init()
+{}
+
+void CPowerPoints::Update()
+{}
+
+void CPowerPoints::GenerateNewOne(float, float, float, float, float, float, uint8)
+{}
+
+void CPowerPoints::Save(uint8**, uint32*)
+{}
+
+void CPowerPoints::Load(uint8*, uint32)
{} \ No newline at end of file
diff --git a/src/control/PowerPoints.h b/src/control/PowerPoints.h
index d7478076..ee3750cd 100644
--- a/src/control/PowerPoints.h
+++ b/src/control/PowerPoints.h
@@ -1,26 +1,26 @@
-#pragma once
-
-enum
-{
- POWERPOINT_NONE = 0,
- POWERPOINT_HEALTH,
- POWERPOINT_HIDEOUT_INDUSTRIAL,
- POWERPOINT_HIDEOUT_COMMERCIAL,
- POWERPOINT_HIDEOUT_SUBURBAN
-};
-
-class CPowerPoint
-{
-public:
- void Update();
-};
-
-class CPowerPoints
-{
-public:
- static void Init();
- static void Update();
- static void GenerateNewOne(float, float, float, float, float, float, uint8);
- static void Save(uint8**, uint32*);
- static void Load(uint8*, uint32);
+#pragma once
+
+enum
+{
+ POWERPOINT_NONE = 0,
+ POWERPOINT_HEALTH,
+ POWERPOINT_HIDEOUT_INDUSTRIAL,
+ POWERPOINT_HIDEOUT_COMMERCIAL,
+ POWERPOINT_HIDEOUT_SUBURBAN
+};
+
+class CPowerPoint
+{
+public:
+ void Update();
+};
+
+class CPowerPoints
+{
+public:
+ static void Init();
+ static void Update();
+ static void GenerateNewOne(float, float, float, float, float, float, uint8);
+ static void Save(uint8**, uint32*);
+ static void Load(uint8*, uint32);
}; \ No newline at end of file
diff --git a/src/control/Record.cpp b/src/control/Record.cpp
index 7c330311..ca4128e3 100644
--- a/src/control/Record.cpp
+++ b/src/control/Record.cpp
@@ -2,18 +2,522 @@
#include "patcher.h"
#include "Record.h"
+#include "FileMgr.h"
+#include "Pad.h"
+#include "Pools.h"
+#include "Streaming.h"
+#include "Timer.h"
+#include "VehicleModelInfo.h"
+#include "World.h"
+
uint16 &CRecordDataForGame::RecordingState = *(uint16*)0x95CC24;
+uint8*& CRecordDataForGame::pDataBuffer = *(uint8**)0x8F1B70;
+uint8*& CRecordDataForGame::pDataBufferPointer = *(uint8**)0x8F1AB0;
+int& CRecordDataForGame::FId = *(int*)0x885BA4;
+tGameBuffer& CRecordDataForGame::pDataBufferForFrame = *(tGameBuffer*)0x72CED0;
+
+#define MEMORY_FOR_GAME_RECORD (150000)
+
+void CRecordDataForGame::Init(void)
+{
+ RecordingState = STATE_NONE;
+ delete[] pDataBuffer;
+ pDataBufferPointer = nil;
+ pDataBuffer = nil;
+#ifndef GTA_PS2 // this stuff is not present on PS2
+ FId = CFileMgr::OpenFile("playback.dat", "r");
+ if (FId <= 0) {
+ if ((FId = CFileMgr::OpenFile("record.dat", "r")) <= 0)
+ RecordingState = STATE_NONE;
+ else {
+ CFileMgr::CloseFile(FId);
+ FId = CFileMgr::OpenFileForWriting("record.dat");
+ RecordingState = STATE_RECORD;
+ }
+ }
+ else {
+ RecordingState = STATE_PLAYBACK;
+ }
+ if (RecordingState == STATE_PLAYBACK) {
+ pDataBufferPointer = new uint8[MEMORY_FOR_GAME_RECORD];
+ pDataBuffer = pDataBufferPointer;
+ pDataBuffer[CFileMgr::Read(FId, (char*)pDataBufferPointer, MEMORY_FOR_GAME_RECORD) + 8] = (uint8)-1;
+ CFileMgr::CloseFile(FId);
+ }
+#else
+ RecordingState = STATE_NONE; // second time to make sure
+#endif
+}
+
+void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void)
+{
+ switch (RecordingState) {
+ case STATE_RECORD:
+ {
+ pDataBufferForFrame.m_fTimeStep = CTimer::GetTimeStep();
+ pDataBufferForFrame.m_nTimeInMilliseconds = CTimer::GetTimeInMilliseconds();
+ pDataBufferForFrame.m_nSizeOfPads[0] = 0;
+ pDataBufferForFrame.m_nSizeOfPads[1] = 0;
+ pDataBufferForFrame.m_nChecksum = CalcGameChecksum();
+ uint8* pController1 = PackCurrentPadValues(pDataBufferForFrame.m_ControllerBuffer, &CPad::GetPad(0)->OldState, &CPad::GetPad(0)->NewState);
+ pDataBufferForFrame.m_nSizeOfPads[0] = (pController1 - pDataBufferForFrame.m_ControllerBuffer) / 2;
+ uint8* pController2 = PackCurrentPadValues(pController1, &CPad::GetPad(1)->OldState, &CPad::GetPad(1)->NewState);
+ pDataBufferForFrame.m_nSizeOfPads[1] = (pController2 - pController1) / 2;
+ uint8* pEndPtr = pController2;
+ if ((pDataBufferForFrame.m_nSizeOfPads[0] + pDataBufferForFrame.m_nSizeOfPads[1]) & 1)
+ pEndPtr += 2;
+ CFileMgr::Write(FId, (char*)&pDataBufferForFrame, pEndPtr - (uint8*)&pDataBufferForFrame);
+ break;
+ }
+ case STATE_PLAYBACK:
+ if (pDataBufferPointer[8] == (uint8)-1)
+ CPad::GetPad(0)->NewState.Clear();
+ else {
+ tGameBuffer* pData = (tGameBuffer*)pDataBufferPointer;
+ CTimer::SetTimeInMilliseconds(pData->m_nTimeInMilliseconds);
+ CTimer::SetTimeStep(pData->m_fTimeStep);
+ uint8 size1 = pData->m_nSizeOfPads[0];
+ uint8 size2 = pData->m_nSizeOfPads[1];
+ pDataBufferPointer = (uint8*)&pData->m_ControllerBuffer;
+ pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size1, &CPad::GetPad(0)->NewState);
+ pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size2, &CPad::GetPad(1)->NewState);
+ if ((size1 + size2) & 1)
+ pDataBufferPointer += 2;
+ if (pData->m_nChecksum != CalcGameChecksum())
+ printf("Playback out of sync\n");
+ }
+ }
+}
+
+#define PROCESS_BUTTON_STATE_STORE(buf, os, ns, field, id) \
+ do { \
+ if (os->field != ns->field){ \
+ *buf++ = id; \
+ *buf++ = ns->field; \
+ } \
+ } while (0);
+
+uint8* CRecordDataForGame::PackCurrentPadValues(uint8* buf, CControllerState* os, CControllerState* ns)
+{
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickX, 0);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickY, 1);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickX, 2);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickY, 3);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder1, 4);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder2, 5);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder1, 6);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder2, 7);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadUp, 8);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadDown, 9);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadLeft, 10);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadRight, 11);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Start, 12);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Select, 13);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Square, 14);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Triangle, 15);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Cross, 16);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, Circle, 17);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShock, 18);
+ PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShock, 19);
+ return buf;
+}
+#undef PROCESS_BUTTON_STATE_STORE
+
+#define PROCESS_BUTTON_STATE_RESTORE(buf, state, field, id) case id: state->field = *buf++; break;
+
+uint8* CRecordDataForGame::UnPackCurrentPadValues(uint8* buf, uint8 total, CControllerState* state)
+{
+ for (uint8 i = 0; i < total; i++) {
+ switch (*buf++) {
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickX, 0);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickY, 1);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickX, 2);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickY, 3);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder1, 4);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder2, 5);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder1, 6);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder2, 7);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadUp, 8);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadDown, 9);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadLeft, 10);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadRight, 11);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Start, 12);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Select, 13);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Square, 14);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Triangle, 15);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Cross, 16);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, Circle, 17);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShock, 18);
+ PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShock, 19);
+ }
+ }
+ return buf;
+}
+
+#undef PROCESS_BUTTON_STATE_RESTORE
+
+uint16 CRecordDataForGame::CalcGameChecksum(void)
+{
+ uint32 checksum = 0;
+ int i = CPools::GetPedPool()->GetSize();
+ while (i--) {
+ CPed* pPed = CPools::GetPedPool()->GetSlot(i);
+ if (!pPed)
+ continue;
+ checksum ^= pPed->GetModelIndex() ^ *(uint32*)&pPed->GetPosition().z ^ *(uint32*)&pPed->GetPosition().y ^ *(uint32*)&pPed->GetPosition().x;
+ }
+ i = CPools::GetVehiclePool()->GetSize();
+ while (i--) {
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ checksum ^= pVehicle->GetModelIndex() ^ *(uint32*)&pVehicle->GetPosition().z ^ *(uint32*)&pVehicle->GetPosition().y ^ *(uint32*)&pVehicle->GetPosition().x;
+ }
+ return checksum ^ checksum >> 16;
+}
+
+uint8& CRecordDataForChase::Status = *(uint8*)0x95CDCE;
+int& CRecordDataForChase::PositionChanges = *(int*)0x8F59C8;
+uint8& CRecordDataForChase::CurrentCar = *(uint8*)0x95CDC9;
+CAutomobile* (&CRecordDataForChase::pChaseCars)[NUM_CHASE_CARS] = *(CAutomobile * (*)[NUM_CHASE_CARS])*(uintptr*)0x6F46A8;
+uint32& CRecordDataForChase::AnimStartTime = *(uint32*)0x8F1AEC;
+float& CRecordDataForChase::AnimTime = *(float*)0x880F88;
+CCarStateEachFrame* (&CRecordDataForChase::pBaseMemForCar)[NUM_CHASE_CARS] = *(CCarStateEachFrame * (*)[NUM_CHASE_CARS])*(uintptr*)0x70EA18;
+float& CRecordDataForChase::TimeMultiplier = *(float*)0x8E2A94;
+int& CRecordDataForChase::FId2 = *(int*)0x8E2C18;
+
+#define CHASE_SCENE_LENGTH_IN_SECONDS (80)
+#define CHASE_SCENE_FRAMES_PER_SECOND (15) // skipping every second frame
+#define CHASE_SCENE_FRAMES_IN_RECORDING (CHASE_SCENE_LENGTH_IN_SECONDS * CHASE_SCENE_FRAMES_PER_SECOND)
+#define CHASE_SCENE_LENGTH_IN_FRAMES (CHASE_SCENE_FRAMES_IN_RECORDING * 2)
+
+void CRecordDataForChase::Init(void)
+{
+ Status = STATE_NONE;
+ PositionChanges = 0;
+ CurrentCar = 0;
+ for (int i = 0; i < NUM_CHASE_CARS; i++)
+ pChaseCars[i] = nil;
+ AnimStartTime = 0;
+}
+
+void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void)
+{
+ switch (Status) {
+ case STATE_NONE:
+ return;
+ case STATE_RECORD:
+ {
+ if ((CTimer::GetFrameCounter() & 1) == 0)
+ StoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2]);
+ if (CTimer::GetFrameCounter() < CHASE_SCENE_LENGTH_IN_FRAMES * 2)
+ return;
+ CFileMgr::SetDir("data\\paths");
+ sprintf(gString, "chase%d.dat", CurrentCar);
+ int fid = CFileMgr::OpenFileForWriting(gString);
+ uint32 fs = CHASE_SCENE_LENGTH_IN_FRAMES * sizeof(CCarStateEachFrame);
+ printf("FileSize:%d\n", fs);
+ CFileMgr::Write(fid, (char*)pBaseMemForCar[CurrentCar], fs);
+ CFileMgr::CloseFile(fid);
+ CFileMgr::SetDir("");
+ sprintf(gString, "car%d.max", CurrentCar);
+ int fid2 = CFileMgr::OpenFileForWriting(gString);
+ for (int i = 0; i < CHASE_SCENE_FRAMES_IN_RECORDING; i++) {
+ // WTF? Was it ever used?
+#ifdef FIX_BUGS
+ CCarStateEachFrame* pState = pBaseMemForCar[CurrentCar];
+#else
+ CCarStateEachFrame* pState = (CCarStateEachFrame*)pChaseCars[CurrentCar];
+#endif
+ CVector right = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX;
+ CVector forward = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX;
+ CVector up = CrossProduct(right, forward);
+ sprintf(gString, "%f %f %f\n", pState->pos.x, pState->pos.y, pState->pos.z);
+ CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+ sprintf(gString, "%f %f %f\n", right.x, right.y, right.z);
+ CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+ sprintf(gString, "%f %f %f\n", forward.x, forward.y, forward.z);
+ CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+ sprintf(gString, "%f %f %f\n", up.x, up.y, up.z);
+ CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+ }
+ CFileMgr::CloseFile(fid2);
+ }
+ case STATE_PLAYBACK:
+ case STATE_PLAYBACK_BEFORE_RECORDING:
+ case STATE_PLAYBACK_INIT:
+ break;
+ }
+}
+
+struct tCoors {
+ CVector pos;
+ float angle;
+};
+
+// I guess developer was filling this with actual data before running the game
+tCoors NewCoorsForRecordedCars[7];
+
+void CRecordDataForChase::SaveOrRetrieveCarPositions(void)
+{
+ switch (Status) {
+ case STATE_NONE:
+ return;
+ case STATE_RECORD:
+ case STATE_PLAYBACK_BEFORE_RECORDING:
+ for (int i = 0; i < NUM_CHASE_CARS; i++) {
+ if (i != CurrentCar && CTimer::GetFrameCounter()) {
+ RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CTimer::GetFrameCounter() / 2], false);
+ pChaseCars[i]->GetMatrix().UpdateRW();
+ pChaseCars[i]->UpdateRwFrame();
+ }
+ }
+ if (Status == STATE_PLAYBACK_BEFORE_RECORDING && CTimer::GetFrameCounter()) {
+ RestoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2], false);
+ pChaseCars[CurrentCar]->GetMatrix().UpdateRW();
+ pChaseCars[CurrentCar]->UpdateRwFrame();
+ }
+ if (CPad::GetPad(0)->GetLeftShockJustDown() && CPad::GetPad(0)->GetRightShockJustDown()) {
+ if (!CPad::GetPad(0)->GetRightShockJustDown()) {
+ pChaseCars[CurrentCar]->GetPosition() = NewCoorsForRecordedCars[PositionChanges].pos;
+ pChaseCars[CurrentCar]->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ pChaseCars[CurrentCar]->GetMatrix().SetRotateZOnly(DEGTORAD(NewCoorsForRecordedCars[PositionChanges].angle));
+ ++PositionChanges;
+ }
+ if (Status == STATE_PLAYBACK_BEFORE_RECORDING) {
+ Status = STATE_RECORD;
+ pChaseCars[CurrentCar]->m_status = STATUS_PLAYER;
+ }
+ }
+ break;
+ case STATE_PLAYBACK_INIT:
+ Status = STATE_PLAYBACK;
+ break;
+ case STATE_PLAYBACK:
+ {
+ TimeMultiplier += CTimer::GetTimeStepNonClippedInSeconds();
+ float EndOfFrameTime = CHASE_SCENE_FRAMES_PER_SECOND * min(CHASE_SCENE_LENGTH_IN_SECONDS, TimeMultiplier);
+ for (int i = 0; i < NUM_CHASE_CARS; i++) {
+ if (!pBaseMemForCar[i])
+ continue;
+ if (!pChaseCars[i])
+ continue;
+ if (EndOfFrameTime < CHASE_SCENE_FRAMES_IN_RECORDING - 1) {
+ int FlooredEOFTime = EndOfFrameTime;
+ RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][FlooredEOFTime], false);
+ CMatrix tmp;
+ float dp = EndOfFrameTime - FlooredEOFTime;
+ RestoreInfoForMatrix(tmp, &pBaseMemForCar[i][FlooredEOFTime + 1]);
+ pChaseCars[i]->GetRight() += (tmp.GetRight() - pChaseCars[i]->GetRight()) * dp;
+ pChaseCars[i]->GetForward() += (tmp.GetForward() - pChaseCars[i]->GetForward()) * dp;
+ pChaseCars[i]->GetUp() += (tmp.GetUp() - pChaseCars[i]->GetUp()) * dp;
+ pChaseCars[i]->GetPosition() += (tmp.GetPosition() - pChaseCars[i]->GetPosition()) * dp;
+ }
+ else{
+ RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CHASE_SCENE_FRAMES_IN_RECORDING - 1], true);
+ if (i == 0)
+ pChaseCars[i]->GetPosition().z += 0.2f;
+ }
+ pChaseCars[i]->GetMatrix().UpdateRW();
+ pChaseCars[i]->UpdateRwFrame();
+ pChaseCars[i]->RemoveAndAdd();
+ }
+ break;
+ }
+ }
+}
+
+void CRecordDataForChase::StoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState)
+{
+ pState->rightX = INT8_MAX * pCar->GetRight().x;
+ pState->rightY = INT8_MAX * pCar->GetRight().y;
+ pState->rightZ = INT8_MAX * pCar->GetRight().z;
+ pState->forwardX = INT8_MAX * pCar->GetForward().x;
+ pState->forwardY = INT8_MAX * pCar->GetForward().y;
+ pState->forwardZ = INT8_MAX * pCar->GetForward().z;
+ pState->pos = pCar->GetPosition();
+ pState->velX = 0.5f * INT16_MAX * pCar->GetMoveSpeed().x;
+ pState->velY = 0.5f * INT16_MAX * pCar->GetMoveSpeed().y;
+ pState->velZ = 0.5f * INT16_MAX * pCar->GetMoveSpeed().z;
+ pState->wheel = 20 * pCar->m_fSteerAngle;
+ pState->gas = 100 * pCar->m_fGasPedal;
+ pState->brake = 100 * pCar->m_fBrakePedal;
+ pState->handbrake = pCar->bIsHandbrakeOn;
+}
+
+void CRecordDataForChase::RestoreInfoForMatrix(CMatrix& matrix, CCarStateEachFrame* pState)
+{
+ matrix.GetRight() = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX;
+ matrix.GetForward() = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX;
+ matrix.GetUp() = CrossProduct(matrix.GetRight(), matrix.GetForward());
+ matrix.GetPosition() = pState->pos;
+}
+
+void CRecordDataForChase::RestoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState, bool stop)
+{
+ CVector oldPos = pCar->GetPosition();
+ RestoreInfoForMatrix(pCar->GetMatrix(), pState);
+ pCar->SetMoveSpeed(CVector(pState->velX, pState->velY, pState->velZ) / INT16_MAX / 0.5f);
+ pCar->SetTurnSpeed(0.0f, 0.0f, 0.0f);
+ pCar->m_fSteerAngle = pState->wheel / 20.0f;
+ pCar->m_fGasPedal = pState->gas / 100.0f;
+ pCar->m_fBrakePedal = pState->brake / 100.0f;
+ pCar->bIsHandbrakeOn = pState->handbrake;
+ if ((oldPos - pCar->GetPosition()).Magnitude() > 15.0f) {
+ if (pCar == pChaseCars[14]) {
+ pCar->m_currentColour1 = 58;
+ pCar->m_currentColour2 = 1;
+ }
+ else
+ pCar->GetModelInfo()->ChooseVehicleColour(pCar->m_currentColour1, pCar->m_currentColour2);
+ }
+ pCar->m_fHealth = min(pCar->m_fHealth, 500.0f);
+ if (stop) {
+ pCar->m_fGasPedal = 0.0f;
+ pCar->m_fBrakePedal = 0.0f;
+ pCar->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ pCar->bIsHandbrakeOn = false;
+ }
+}
+
+void CRecordDataForChase::ProcessControlCars(void)
+{
+ if (Status != STATE_PLAYBACK)
+ return;
+ for (int i = 0; i < NUM_CHASE_CARS; i++) {
+ if (pChaseCars[i])
+ pChaseCars[i]->ProcessControl();
+ }
+}
+
+#if (defined(GTA_PS2) || defined(FIX_BUGS))
+bool CRecordDataForChase::ShouldThisPadBeLeftAlone(uint8 pad)
+{
+ // may be wrong
+ if (Status == STATE_NONE || Status == STATE_PLAYBACK)
+ return false;
+ return pad != 0;
+}
+#endif
+
+void CRecordDataForChase::GiveUsACar(int32 mi, CVector pos, float angle, CAutomobile** ppCar, uint8 colour1, uint8 colour2)
+{
+ CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY);
+ CStreaming::LoadAllRequestedModels(false);
+ if (!CStreaming::HasModelLoaded(mi))
+ return;
+ CAutomobile* pCar = new CAutomobile(mi, MISSION_VEHICLE);
+ pCar->GetPosition() = pos;
+ pCar->m_status = STATUS_PLAYER_PLAYBACKFROMBUFFER;
+ pCar->GetMatrix().SetRotateZOnly(DEGTORAD(angle));
+ pCar->pDriver = nil;
+ pCar->m_currentColour1 = colour1;
+ pCar->m_currentColour2 = colour2;
+ CWorld::Add(pCar);
+ *ppCar = pCar;
+}
+
+void RemoveUnusedCollision(void)
+{
+ static const char* dontDeleteArray[] = {
+ "rd_SrRoad2A50", "rd_SrRoad2A20", "rd_CrossRda1w22", "rd_CrossRda1rw22",
+ "road_broadway02", "road_broadway01", "com_21way5", "com_21way50",
+ "cm1waycrosscom", "com_21way20", "com_21way10", "road_broadway04",
+ "com_rvroads52", "com_roadsrv", "com_roadkb23", "com_roadkb22"
+ };
+ for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++)
+ CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_NONE;
+ CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_NONE);
+ for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++)
+ CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_COMMERCIAL;
+}
+
+void CRecordDataForChase::StartChaseScene(float startTime)
+{
+ char filename[28];
+ SetUpCarsForChaseScene();
+ Status = STATE_PLAYBACK;
+ AnimTime = startTime;
+ AnimStartTime = CTimer::GetTimeInMilliseconds();
+ RemoveUnusedCollision();
+ CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN);
+ CGame::TidyUpMemory(true, true);
+ CStreaming::ImGonnaUseStreamingMemory();
+ CFileMgr::SetDir("data\\paths");
+ for (int i = 0; i < NUM_CHASE_CARS; i++) {
+ if (!pChaseCars[i]) {
+ pBaseMemForCar[i] = nil;
+ continue;
+ }
+ sprintf(filename, "chase%d.dat", i);
+ FId2 = CFileMgr::OpenFile(filename, "rb");
+ if (FId2 <= 0) {
+ pBaseMemForCar[i] = nil;
+ continue;
+ }
+ pBaseMemForCar[i] = new CCarStateEachFrame[CHASE_SCENE_FRAMES_IN_RECORDING];
+ for (int j = 0; j < CHASE_SCENE_FRAMES_IN_RECORDING; j++) {
+ CFileMgr::Read(FId2, (char*)&pBaseMemForCar[i][j], sizeof(CCarStateEachFrame));
+ CFileMgr::Seek(FId2, sizeof(CCarStateEachFrame), 1);
+ }
+ CFileMgr::CloseFile(FId2);
+ }
+ CFileMgr::SetDir("");
+ CStreaming::IHaveUsedStreamingMemory();
+ TimeMultiplier = 0.0f;
+}
+
+void CRecordDataForChase::CleanUpChaseScene(void)
+{
+ if (Status != STATE_PLAYBACK_INIT && Status != STATE_PLAYBACK)
+ return;
+ Status = STATE_NONE;
+ CleanUpCarsForChaseScene();
+ for (int i = 0; i < NUM_CHASE_CARS; i++) {
+ if (pBaseMemForCar[i]) {
+ delete[] pBaseMemForCar[i];
+ pBaseMemForCar[i] = nil;
+ }
+ }
+}
+
+void CRecordDataForChase::SetUpCarsForChaseScene(void)
+{
+ GiveUsACar(MI_POLICE, CVector(273.54221f, -1167.1907f, 24.880601f), 63.0f, &pChaseCars[0], 2, 1);
+ GiveUsACar(MI_ENFORCER, CVector(231.1783f, -1388.8322f, 25.978201f), 90.0f, &pChaseCars[1], 2, 1);
+ GiveUsACar(MI_TAXI, CVector(184.3156f, -1473.251f, 25.978201f), 0.0f, &pChaseCars[4], 6, 6);
+ GiveUsACar(MI_CHEETAH, CVector(173.8868f, -1377.6514f, 25.978201f), 0.0f, &pChaseCars[6], 4, 5);
+ GiveUsACar(MI_STINGER, CVector(102.5946f, -943.93628f, 25.9781f), 270.0f, &pChaseCars[7], 53, 53);
+ GiveUsACar(MI_CHEETAH, CVector(-177.7157f, -862.18652f, 25.978201f), 155.0f, &pChaseCars[10], 41, 1);
+ GiveUsACar(MI_STINGER, CVector(-170.56979f, -889.02362f, 25.978201f), 154.0f, &pChaseCars[11], 10, 10);
+ GiveUsACar(MI_KURUMA, CVector(402.60809f, -917.49628f, 37.381001f), 90.0f, &pChaseCars[14], 34, 1);
+ GiveUsACar(MI_TAXI, CVector(-33.496201f, -938.4563f, 25.9781f), 266.0f, &pChaseCars[16], 6, 6);
+ GiveUsACar(MI_KURUMA, CVector(49.363098f, -987.60498f, 25.9781f), 0.0f, &pChaseCars[18], 51, 1);
+ GiveUsACar(MI_TAXI, CVector(179.0049f, -1154.6686f, 25.9781f), 0.0f, &pChaseCars[19], 6, 76);
+ GiveUsACar(MI_RUMPO, CVector(-28.9762f, -1031.3367f, 25.990601f), 242.0f, &pChaseCars[2], 1, 75);
+ GiveUsACar(MI_PATRIOT, CVector(114.1564f, -796.69379f, 24.978201f), 180.0f, &pChaseCars[3], 0, 0);
+}
+
+void CRecordDataForChase::CleanUpCarsForChaseScene(void)
+{
+ for (int i = 0; i < NUM_CHASE_CARS; i++)
+ RemoveCarFromChase(i);
+}
-uint8 &CRecordDataForChase::Status = *(uint8*)0x95CDCE;
+void CRecordDataForChase::RemoveCarFromChase(int32 i)
+{
+ if (!pChaseCars[i])
+ return;
+ CWorld::Remove(pChaseCars[i]);
+ delete pChaseCars[i];
+ pChaseCars[i] = nil;
+}
-WRAPPER void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4341F0); }
-WRAPPER void CRecordDataForGame::Init(void) { EAXJMP(0x4340F0); }
+CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32 i)
+{
+ CVehicle* pVehicle = pChaseCars[i];
+ pChaseCars[i] = nil;
+ pVehicle->m_status = STATUS_PHYSICS;
+ return pVehicle;
+}
-WRAPPER void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4347F0); }
-WRAPPER void CRecordDataForChase::ProcessControlCars(void) { EAXJMP(0x435540); }
-WRAPPER void CRecordDataForChase::SaveOrRetrieveCarPositions(void) { EAXJMP(0x434B20); }
-WRAPPER void CRecordDataForChase::StartChaseScene(float) { EAXJMP(0x435690); }
-WRAPPER void CRecordDataForChase::CleanUpChaseScene() { EAXJMP(0x4357C0); }
-WRAPPER void CRecordDataForChase::RemoveCarFromChase(int32) { EAXJMP(0x435BC0); }
-WRAPPER CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32) { EAXJMP(0x435C00); }
-WRAPPER void CRecordDataForChase::Init(void) { EAXJMP(0x434780); }
diff --git a/src/control/Record.h b/src/control/Record.h
index e52a623e..4abeb68a 100644
--- a/src/control/Record.h
+++ b/src/control/Record.h
@@ -1,34 +1,106 @@
#pragma once
+class CAutomobile;
class CVehicle;
+class CControllerState;
-enum {
- RECORDSTATE_0,
- RECORDSTATE_1,
- RECORDSTATE_2,
+class CCarStateEachFrame
+{
+public:
+ int16 velX;
+ int16 velY;
+ int16 velZ;
+ int8 rightX;
+ int8 rightY;
+ int8 rightZ;
+ int8 forwardX;
+ int8 forwardY;
+ int8 forwardZ;
+ int8 wheel;
+ uint8 gas;
+ uint8 brake;
+ bool handbrake;
+ CVector pos;
};
+extern char* gString;
+
class CRecordDataForChase
{
-public:
+ enum {
+ NUM_CHASE_CARS = 20
+ };
+ enum {
+ STATE_NONE = 0,
+ STATE_RECORD = 1,
+ STATE_PLAYBACK_INIT = 2,
+ STATE_PLAYBACK = 3,
+ STATE_PLAYBACK_BEFORE_RECORDING = 4
+ };
static uint8 &Status;
+ static int &PositionChanges;
+ static uint8 &CurrentCar;
+ static CAutomobile*(&pChaseCars)[NUM_CHASE_CARS];
+ static float &AnimTime;
+ static uint32 &AnimStartTime;
+ static CCarStateEachFrame* (&pBaseMemForCar)[NUM_CHASE_CARS];
+ static float &TimeMultiplier;
+ static int &FId2;
+public:
+
+ static bool IsRecording(void) { return Status == STATE_RECORD; }
+ static void Init(void);
static void SaveOrRetrieveDataForThisFrame(void);
- static void ProcessControlCars(void);
static void SaveOrRetrieveCarPositions(void);
+ static void StoreInfoForCar(CAutomobile*, CCarStateEachFrame*);
+ static void RestoreInfoForMatrix(CMatrix&, CCarStateEachFrame*);
+ static void RestoreInfoForCar(CAutomobile*, CCarStateEachFrame*, bool);
+ static void ProcessControlCars(void);
+#if (defined(GTA_PS2) || defined(FIX_BUGS))
+ static bool ShouldThisPadBeLeftAlone(uint8 pad);
+#endif
+ static void GiveUsACar(int32, CVector, float, CAutomobile**, uint8, uint8);
static void StartChaseScene(float);
- static void CleanUpChaseScene();
+ static void CleanUpChaseScene(void);
+ static void SetUpCarsForChaseScene(void);
+ static void CleanUpCarsForChaseScene(void);
static void RemoveCarFromChase(int32);
static CVehicle* TurnChaseCarIntoScriptCar(int32);
- static void Init(void);
+
};
+struct tGameBuffer
+{
+ float m_fTimeStep;
+ uint32 m_nTimeInMilliseconds;
+ uint8 m_nSizeOfPads[2];
+ uint16 m_nChecksum;
+ uint8 m_ControllerBuffer[116];
+};
class CRecordDataForGame
{
+ enum {
+ STATE_NONE = 0,
+ STATE_RECORD = 1,
+ STATE_PLAYBACK = 2,
+ };
+ static uint16& RecordingState;
+ static uint8* &pDataBuffer;
+ static uint8* &pDataBufferPointer;
+ static int &FId;
+ static tGameBuffer &pDataBufferForFrame;
+
public:
- static uint16 &RecordingState;
+ static bool IsRecording() { return RecordingState == STATE_RECORD; }
+ static bool IsPlayingBack() { return RecordingState == STATE_PLAYBACK; }
static void SaveOrRetrieveDataForThisFrame(void);
static void Init(void);
+
+private:
+ static uint16 CalcGameChecksum(void);
+ static uint8* PackCurrentPadValues(uint8*, CControllerState*, CControllerState*);
+ static uint8* UnPackCurrentPadValues(uint8*, uint8, CControllerState*);
};
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 2e325249..0da32dd2 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -1107,7 +1107,7 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
CStreaming::LoadScene(ff_coord);
}
if (cam_mode == REPLAYCAMMODE_ASSTORED)
- TheCamera.CarZoomIndicator = 5.0f;
+ TheCamera.CarZoomIndicator = CAM_ZOOM_CINEMATIC;
}
void CReplay::StoreStuffInMem(void)
@@ -1129,8 +1129,8 @@ void CReplay::StoreStuffInMem(void)
pEmptyReferences = CReferences::pEmptyList;
pStoredCam = new uint8[sizeof(CCamera)];
memcpy(pStoredCam, &TheCamera, sizeof(CCamera));
- pRadarBlips = new uint8[sizeof(CBlip) * NUMRADARBLIPS];
- memcpy(pRadarBlips, CRadar::ms_RadarTrace, NUMRADARBLIPS * sizeof(CBlip));
+ pRadarBlips = new uint8[sizeof(sRadarTrace) * NUMRADARBLIPS];
+ memcpy(pRadarBlips, CRadar::ms_RadarTrace, NUMRADARBLIPS * sizeof(sRadarTrace));
PlayerWanted = *FindPlayerPed()->m_pWanted;
PlayerInfo = CWorld::Players[0];
Time1 = CTimer::GetTimeInMilliseconds();
@@ -1179,7 +1179,7 @@ void CReplay::RestoreStuffFromMem(void)
memcpy(&TheCamera, pStoredCam, sizeof(CCamera));
delete[] pStoredCam;
pStoredCam = nil;
- memcpy(CRadar::ms_RadarTrace, pRadarBlips, sizeof(CBlip) * NUMRADARBLIPS);
+ memcpy(CRadar::ms_RadarTrace, pRadarBlips, sizeof(sRadarTrace) * NUMRADARBLIPS);
delete[] pRadarBlips;
pRadarBlips = nil;
FindPlayerPed()->m_pWanted = new CWanted(PlayerWanted);
diff --git a/src/control/Restart.cpp b/src/control/Restart.cpp
index 8e983555..788a054a 100644
--- a/src/control/Restart.cpp
+++ b/src/control/Restart.cpp
@@ -21,234 +21,234 @@ CVector(&CRestart::PoliceRestartPoints)[NUM_RESTART_POINTS] = *(CVector(*)[NUM_R
float(&CRestart::PoliceRestartHeadings)[NUM_RESTART_POINTS] = *(float(*)[NUM_RESTART_POINTS])*(uintptr*)0x6F1D20;
uint16 &CRestart::NumberOfPoliceRestarts = *(uint16*)0x95CC44;
-void
-CRestart::Initialise()
-{
- OverridePoliceStationLevel = LEVEL_NONE;
- OverrideHospitalLevel = LEVEL_NONE;
- bFadeInAfterNextArrest = true;
- bFadeInAfterNextDeath = true;
- OverrideHeading = 0.0f;
- OverridePosition = CVector(0.0f, 0.0f, 0.0f);
- bOverrideRestart = false;
- NumberOfPoliceRestarts = 0;
- NumberOfHospitalRestarts = 0;
-
- for (int i = 0; i < NUM_RESTART_POINTS; i++) {
- HospitalRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
- HospitalRestartHeadings[i] = 0.0f;
- PoliceRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
- PoliceRestartHeadings[i] = 0.0f;
- }
+void
+CRestart::Initialise()
+{
+ OverridePoliceStationLevel = LEVEL_NONE;
+ OverrideHospitalLevel = LEVEL_NONE;
+ bFadeInAfterNextArrest = true;
+ bFadeInAfterNextDeath = true;
+ OverrideHeading = 0.0f;
+ OverridePosition = CVector(0.0f, 0.0f, 0.0f);
+ bOverrideRestart = false;
+ NumberOfPoliceRestarts = 0;
+ NumberOfHospitalRestarts = 0;
+
+ for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+ HospitalRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
+ HospitalRestartHeadings[i] = 0.0f;
+ PoliceRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
+ PoliceRestartHeadings[i] = 0.0f;
+ }
+}
+
+void
+CRestart::AddHospitalRestartPoint(const CVector &pos, float heading)
+{
+ HospitalRestartPoints[NumberOfHospitalRestarts] = pos;
+ HospitalRestartHeadings[NumberOfHospitalRestarts++] = heading;
+}
+
+void
+CRestart::AddPoliceRestartPoint(const CVector &pos, float heading)
+{
+ PoliceRestartPoints[NumberOfPoliceRestarts] = pos;
+ PoliceRestartHeadings[NumberOfPoliceRestarts++] = heading;
+}
+
+void
+CRestart::OverrideNextRestart(const CVector &pos, float heading)
+{
+ bOverrideRestart = true;
+ OverridePosition = pos;
+ OverrideHeading = heading;
}
-void
-CRestart::AddHospitalRestartPoint(const CVector &pos, float heading)
-{
- HospitalRestartPoints[NumberOfHospitalRestarts] = pos;
- HospitalRestartHeadings[NumberOfHospitalRestarts++] = heading;
+void
+CRestart::CancelOverrideRestart()
+{
+ bOverrideRestart = false;
}
-void
-CRestart::AddPoliceRestartPoint(const CVector &pos, float heading)
-{
- PoliceRestartPoints[NumberOfPoliceRestarts] = pos;
- PoliceRestartHeadings[NumberOfPoliceRestarts++] = heading;
+void
+CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
+{
+ if (bOverrideRestart) {
+ *outPos = OverridePosition;
+ *outHeading = OverrideHeading;
+ CancelOverrideRestart();
+ return;
+ }
+
+ eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
+ float fMinDist = 16000000.0f;
+ int closestPoint = NUM_RESTART_POINTS;
+
+ // find closest point on this level
+ for (int i = 0; i < NumberOfHospitalRestarts; i++) {
+ if (CTheZones::FindZoneForPoint(HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) {
+ float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
+ if (fMinDist >= dist) {
+ fMinDist = dist;
+ closestPoint = i;
+ }
+ }
+ }
+
+ // if we didn't find anything, find closest point on any level
+ if (closestPoint == NUM_RESTART_POINTS) {
+ for (int i = 0; i < NumberOfHospitalRestarts; i++) {
+ float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
+ if (fMinDist >= dist) {
+ fMinDist = dist;
+ closestPoint = i;
+ }
+ }
+ }
+
+ // if we still didn't find anything, find closest path node
+ if (closestPoint == NUM_RESTART_POINTS) {
+ *outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
+ *outHeading = 0.0f;
+ printf("Couldn't find a hospital restart zone near the player %f %f %f->%f %f %f\n", pos.x, pos.y, pos.z, outPos->x, outPos->y, outPos->z);
+ } else {
+ *outPos = HospitalRestartPoints[closestPoint];
+ *outHeading = HospitalRestartHeadings[closestPoint];
+ }
}
-void
-CRestart::OverrideNextRestart(const CVector &pos, float heading)
-{
- bOverrideRestart = true;
- OverridePosition = pos;
- OverrideHeading = heading;
+void
+CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
+{
+ if (bOverrideRestart) {
+ *outPos = OverridePosition;
+ *outHeading = OverrideHeading;
+ CancelOverrideRestart();
+ return;
+ }
+
+ eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
+ float fMinDist = 16000000.0f;
+ int closestPoint = NUM_RESTART_POINTS;
+
+ // find closest point on this level
+ for (int i = 0; i < NumberOfPoliceRestarts; i++) {
+ if (CTheZones::FindZoneForPoint(PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) {
+ float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
+ if (fMinDist >= dist) {
+ fMinDist = dist;
+ closestPoint = i;
+ }
+ }
+ }
+
+ // if we didn't find anything, find closest point on any level
+ if (closestPoint == NUM_RESTART_POINTS) {
+ for (int i = 0; i < NumberOfPoliceRestarts; i++) {
+ float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
+ if (fMinDist >= dist) {
+ fMinDist = dist;
+ closestPoint = i;
+ }
+ }
+ }
+
+ // if we still didn't find anything, find closest path node
+ if (closestPoint == NUM_RESTART_POINTS) {
+ printf("Couldn't find a police restart zone near the player\n");
+ *outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
+ *outHeading = 0.0f;
+ } else {
+ *outPos = PoliceRestartPoints[closestPoint];
+ *outHeading = PoliceRestartHeadings[closestPoint];
+ }
}
-void
-CRestart::CancelOverrideRestart()
-{
- bOverrideRestart = false;
+void
+CRestart::LoadAllRestartPoints(uint8 *buf, uint32 size)
+{
+ Initialise();
+
+INITSAVEBUF
+ CheckSaveHeader(buf, 'R','S','T','\0', size - SAVE_HEADER_SIZE);
+
+ for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+ HospitalRestartPoints[i] = ReadSaveBuf<CVector>(buf);
+ HospitalRestartHeadings[i] = ReadSaveBuf<float>(buf);
+ }
+
+ for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+ PoliceRestartPoints[i] = ReadSaveBuf<CVector>(buf);
+ PoliceRestartHeadings[i] = ReadSaveBuf<float>(buf);
+ }
+
+ NumberOfHospitalRestarts = ReadSaveBuf<uint16>(buf);
+ NumberOfPoliceRestarts = ReadSaveBuf<uint16>(buf);
+ bOverrideRestart = ReadSaveBuf<bool>(buf);
+
+ // skip something unused
+ ReadSaveBuf<uint8>(buf);
+ ReadSaveBuf<uint16>(buf);
+
+ OverridePosition = ReadSaveBuf<CVector>(buf);
+ OverrideHeading = ReadSaveBuf<float>(buf);
+ bFadeInAfterNextDeath = ReadSaveBuf<bool>(buf);
+ bFadeInAfterNextArrest = ReadSaveBuf<bool>(buf);
+ OverrideHospitalLevel = ReadSaveBuf<uint8>(buf);
+ OverridePoliceStationLevel = ReadSaveBuf<uint8>(buf);
+VALIDATESAVEBUF(size);
}
-void
-CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
-{
- if (bOverrideRestart) {
- *outPos = OverridePosition;
- *outHeading = OverrideHeading;
- CancelOverrideRestart();
- return;
- }
-
- eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
- float fMinDist = 16000000.0f;
- int closestPoint = NUM_RESTART_POINTS;
-
- // find closest point on this level
- for (int i = 0; i < NumberOfHospitalRestarts; i++) {
- if (CTheZones::FindZoneForPoint(HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) {
- float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
- if (fMinDist >= dist) {
- fMinDist = dist;
- closestPoint = i;
- }
- }
- }
-
- // if we didn't find anything, find closest point on any level
- if (closestPoint == NUM_RESTART_POINTS) {
- for (int i = 0; i < NumberOfHospitalRestarts; i++) {
- float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
- if (fMinDist >= dist) {
- fMinDist = dist;
- closestPoint = i;
- }
- }
- }
-
- // if we still didn't find anything, find closest path node
- if (closestPoint == NUM_RESTART_POINTS) {
- *outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
- *outHeading = 0.0f;
- printf("Couldn't find a hospital restart zone near the player %f %f %f->%f %f %f\n", pos.x, pos.y, pos.z, outPos->x, outPos->y, outPos->z);
- } else {
- *outPos = HospitalRestartPoints[closestPoint];
- *outHeading = HospitalRestartHeadings[closestPoint];
- }
+void
+CRestart::SaveAllRestartPoints(uint8 *buf, uint32 *size)
+{
+ *size = SAVE_HEADER_SIZE
+ + sizeof(HospitalRestartPoints)
+ + sizeof(HospitalRestartHeadings)
+ + sizeof(PoliceRestartPoints)
+ + sizeof(PoliceRestartHeadings)
+ + sizeof(NumberOfHospitalRestarts)
+ + sizeof(NumberOfPoliceRestarts)
+ + sizeof(bOverrideRestart)
+ + sizeof(uint8)
+ + sizeof(uint16)
+ + sizeof(OverridePosition)
+ + sizeof(OverrideHeading)
+ + sizeof(bFadeInAfterNextDeath)
+ + sizeof(bFadeInAfterNextArrest)
+ + sizeof(OverrideHospitalLevel)
+ + sizeof(OverridePoliceStationLevel); // == 292
+
+INITSAVEBUF
+ WriteSaveHeader(buf, 'R','S','T','\0', *size - SAVE_HEADER_SIZE);
+
+ for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+ WriteSaveBuf(buf, HospitalRestartPoints[i]);
+ WriteSaveBuf(buf, HospitalRestartHeadings[i]);
+ }
+
+ for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+ WriteSaveBuf(buf, PoliceRestartPoints[i]);
+ WriteSaveBuf(buf, PoliceRestartHeadings[i]);
+ }
+
+ WriteSaveBuf(buf, NumberOfHospitalRestarts);
+ WriteSaveBuf(buf, NumberOfPoliceRestarts);
+ WriteSaveBuf(buf, bOverrideRestart);
+
+ WriteSaveBuf(buf, (uint8)0);
+ WriteSaveBuf(buf, (uint16)0);
+
+ WriteSaveBuf(buf, OverridePosition);
+ WriteSaveBuf(buf, OverrideHeading);
+ WriteSaveBuf(buf, bFadeInAfterNextDeath);
+ WriteSaveBuf(buf, bFadeInAfterNextArrest);
+ WriteSaveBuf(buf, OverrideHospitalLevel);
+ WriteSaveBuf(buf, OverridePoliceStationLevel);
+VALIDATESAVEBUF(*size);
}
-void
-CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
-{
- if (bOverrideRestart) {
- *outPos = OverridePosition;
- *outHeading = OverrideHeading;
- CancelOverrideRestart();
- return;
- }
-
- eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
- float fMinDist = 16000000.0f;
- int closestPoint = NUM_RESTART_POINTS;
-
- // find closest point on this level
- for (int i = 0; i < NumberOfPoliceRestarts; i++) {
- if (CTheZones::FindZoneForPoint(PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) {
- float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
- if (fMinDist >= dist) {
- fMinDist = dist;
- closestPoint = i;
- }
- }
- }
-
- // if we didn't find anything, find closest point on any level
- if (closestPoint == NUM_RESTART_POINTS) {
- for (int i = 0; i < NumberOfPoliceRestarts; i++) {
- float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
- if (fMinDist >= dist) {
- fMinDist = dist;
- closestPoint = i;
- }
- }
- }
-
- // if we still didn't find anything, find closest path node
- if (closestPoint == NUM_RESTART_POINTS) {
- printf("Couldn't find a police restart zone near the player\n");
- *outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
- *outHeading = 0.0f;
- } else {
- *outPos = PoliceRestartPoints[closestPoint];
- *outHeading = PoliceRestartHeadings[closestPoint];
- }
-}
-
-void
-CRestart::LoadAllRestartPoints(uint8 *buf, uint32 size)
-{
- Initialise();
-
-INITSAVEBUF
- CheckSaveHeader(buf, 'R','S','T','\0', size - SAVE_HEADER_SIZE);
-
- for (int i = 0; i < NUM_RESTART_POINTS; i++) {
- HospitalRestartPoints[i] = ReadSaveBuf<CVector>(buf);
- HospitalRestartHeadings[i] = ReadSaveBuf<float>(buf);
- }
-
- for (int i = 0; i < NUM_RESTART_POINTS; i++) {
- PoliceRestartPoints[i] = ReadSaveBuf<CVector>(buf);
- PoliceRestartHeadings[i] = ReadSaveBuf<float>(buf);
- }
-
- NumberOfHospitalRestarts = ReadSaveBuf<uint16>(buf);
- NumberOfPoliceRestarts = ReadSaveBuf<uint16>(buf);
- bOverrideRestart = ReadSaveBuf<bool>(buf);
-
- // skip something unused
- ReadSaveBuf<uint8>(buf);
- ReadSaveBuf<uint16>(buf);
-
- OverridePosition = ReadSaveBuf<CVector>(buf);
- OverrideHeading = ReadSaveBuf<float>(buf);
- bFadeInAfterNextDeath = ReadSaveBuf<bool>(buf);
- bFadeInAfterNextArrest = ReadSaveBuf<bool>(buf);
- OverrideHospitalLevel = ReadSaveBuf<uint8>(buf);
- OverridePoliceStationLevel = ReadSaveBuf<uint8>(buf);
-VALIDATESAVEBUF(size);
-}
-
-void
-CRestart::SaveAllRestartPoints(uint8 *buf, uint32 *size)
-{
- *size = SAVE_HEADER_SIZE
- + sizeof(HospitalRestartPoints)
- + sizeof(HospitalRestartHeadings)
- + sizeof(PoliceRestartPoints)
- + sizeof(PoliceRestartHeadings)
- + sizeof(NumberOfHospitalRestarts)
- + sizeof(NumberOfPoliceRestarts)
- + sizeof(bOverrideRestart)
- + sizeof(uint8)
- + sizeof(uint16)
- + sizeof(OverridePosition)
- + sizeof(OverrideHeading)
- + sizeof(bFadeInAfterNextDeath)
- + sizeof(bFadeInAfterNextArrest)
- + sizeof(OverrideHospitalLevel)
- + sizeof(OverridePoliceStationLevel); // == 292
-
-INITSAVEBUF
- WriteSaveHeader(buf, 'R','S','T','\0', *size - SAVE_HEADER_SIZE);
-
- for (int i = 0; i < NUM_RESTART_POINTS; i++) {
- WriteSaveBuf(buf, HospitalRestartPoints[i]);
- WriteSaveBuf(buf, HospitalRestartHeadings[i]);
- }
-
- for (int i = 0; i < NUM_RESTART_POINTS; i++) {
- WriteSaveBuf(buf, PoliceRestartPoints[i]);
- WriteSaveBuf(buf, PoliceRestartHeadings[i]);
- }
-
- WriteSaveBuf(buf, NumberOfHospitalRestarts);
- WriteSaveBuf(buf, NumberOfPoliceRestarts);
- WriteSaveBuf(buf, bOverrideRestart);
-
- WriteSaveBuf(buf, (uint8)0);
- WriteSaveBuf(buf, (uint16)0);
-
- WriteSaveBuf(buf, OverridePosition);
- WriteSaveBuf(buf, OverrideHeading);
- WriteSaveBuf(buf, bFadeInAfterNextDeath);
- WriteSaveBuf(buf, bFadeInAfterNextArrest);
- WriteSaveBuf(buf, OverrideHospitalLevel);
- WriteSaveBuf(buf, OverridePoliceStationLevel);
-VALIDATESAVEBUF(*size);
-}
-
-
+
STARTPATCHES
InjectHook(0x435E20, &CRestart::Initialise, PATCH_JUMP);
InjectHook(0x436100, &CRestart::AddHospitalRestartPoint, PATCH_JUMP);
@@ -258,5 +258,5 @@ STARTPATCHES
InjectHook(0x4361A0, &CRestart::FindClosestHospitalRestartPoint, PATCH_JUMP);
InjectHook(0x436450, &CRestart::FindClosestPoliceRestartPoint, PATCH_JUMP);
InjectHook(0x436B20, &CRestart::LoadAllRestartPoints, PATCH_JUMP);
- InjectHook(0x436700, &CRestart::SaveAllRestartPoints, PATCH_JUMP);
+ InjectHook(0x436700, &CRestart::SaveAllRestartPoints, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index e39fe481..9548bc0a 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -2,36 +2,202 @@
#include "patcher.h"
#include "RoadBlocks.h"
#include "PathFind.h"
+#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"
int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34;
int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8;
bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810;
-WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
-WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
-
void
CRoadBlocks::Init(void)
{
- NumRoadBlocks = 0;
- for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
- if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
- if (NumRoadBlocks < 600) {
- InOrOut[NumRoadBlocks] = true;
- RoadBlockObjects[NumRoadBlocks] = objId;
- NumRoadBlocks++;
- } else {
+ NumRoadBlocks = 0;
+ for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
+ if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
+ if (NumRoadBlocks < NUMROADBLOCKS) {
+ InOrOut[NumRoadBlocks] = true;
+ RoadBlockObjects[NumRoadBlocks] = objId;
+ NumRoadBlocks++;
+ } else {
#ifndef MASTER
- printf("Not enough room for the potential roadblocks\n");
+ printf("Not enough room for the potential roadblocks\n");
#endif
- // FIX: Don't iterate loop after NUMROADBLOCKS
- return;
- }
- }
- }
+ // FIX: Don't iterate loop after NUMROADBLOCKS
+ return;
+ }
+ }
+ }
+
+}
+
+void
+CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode)
+{
+ static const CVector vecRoadBlockOffets[6] = { {-1.5, 1.8f, 0.0f}, {-1.5f, -1.8f, 0.0f}, {1.5f, 1.8f, 0.0f},
+ {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]);
+ int32 modelInfoId = MI_COP;
+ 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);
+ }
+}
+void
+CRoadBlocks::GenerateRoadBlocks(void)
+{
+ CMatrix offsetMatrix;
+ uint32 frame = CTimer::GetFrameCounter() & 0xF;
+ int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16;
+ const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16;
+ int16 numRoadBlocks = CRoadBlocks::NumRoadBlocks;
+ if (CRoadBlocks::NumRoadBlocks >= maxRoadBlocks)
+ numRoadBlocks = maxRoadBlocks;
+ for (; nRoadblockNode < numRoadBlocks; nRoadblockNode++) {
+ CTreadable *mapObject = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[nRoadblockNode]];
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ CRoadBlocks::InOrOut[nRoadblockNode] = false;
+ }
+ }
}
STARTPATCHES
InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
+ InjectHook(0x4376A0, &CRoadBlocks::GenerateRoadBlockCopsForCar, PATCH_JUMP);
+ InjectHook(0x436FA0, &CRoadBlocks::GenerateRoadBlocks, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index 3f5868e7..16e3a362 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -11,6 +11,6 @@ public:
static bool (&InOrOut)[NUMROADBLOCKS];
static void Init(void);
- static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
+ static void GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode);
static void GenerateRoadBlocks(void);
};
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index f96ec060..ff89f0fc 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -91,10 +91,10 @@ uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SP
CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08;
int32(&CTheScripts::BaseBriefIdForContact)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x880200;
int32(&CTheScripts::OnAMissionForContactFlag)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x8622F0;
-CTextLine (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(CTextLine (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68;
-CScriptRectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(CScriptRectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108;
+intro_text_line (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(intro_text_line (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68;
+intro_script_rectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(intro_script_rectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108;
CSprite2d (&CTheScripts::ScriptSprites)[MAX_NUM_SCRIPT_SRPITES] = *(CSprite2d(*)[MAX_NUM_SCRIPT_SRPITES])*(uintptr*)0x72B090;
-CScriptSphere(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(CScriptSphere(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60;
+script_sphere_struct(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(script_sphere_struct(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60;
tCollectiveData(&CTheScripts::CollectiveArray)[MAX_NUM_COLLECTIVES] = *(tCollectiveData(*)[MAX_NUM_COLLECTIVES])*(uintptr*)0x6FA008;
tUsedObject(&CTheScripts::UsedObjectArray)[MAX_NUM_USED_OBJECTS] = *(tUsedObject(*)[MAX_NUM_USED_OBJECTS])*(uintptr*)0x6E69C8;
int32(&CTheScripts::MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS] = *(int32(*)[MAX_NUM_MISSION_SCRIPTS])*(uintptr*)0x6F0558;
@@ -313,7 +313,7 @@ bool CUpsideDownCarCheck::HasCarBeenUpsideDownForAWhile(int32 id)
return false;
}
-void CStuckCarCheckEntry::Reset()
+void stuck_car_data::Reset()
{
m_nVehicleIndex = -1;
m_vecPos = CVector(-5000.0f, -5000.0f, -5000.0f);
@@ -2229,6 +2229,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command)
if (pos.z <= -100)
pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3]));
+ return 0;
}
case COMMAND_DEBUG_ON:
CTheScripts::DbgFlag = true;
@@ -7116,7 +7117,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
case COMMAND_CLOSE_GARAGE:
{
CollectParameters(&m_nIp, 1);
- CGarages::CloseGarage(ScriptParams[1]);
+ CGarages::CloseGarage(ScriptParams[0]);
return 0;
}
case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD:
@@ -7657,13 +7658,13 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
assert(pObject);
if (ScriptParams[1]) {
if (pObject->bIsStatic) {
- pObject->bIsStatic = true;
+ pObject->bIsStatic = false;
pObject->AddToMovingList();
}
}
else {
if (!pObject->bIsStatic) {
- pObject->bIsStatic = false;
+ pObject->bIsStatic = true;
pObject->RemoveFromMovingList();
}
}
@@ -8441,7 +8442,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command)
CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]];
CPad::GetPad(ScriptParams[0])->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
pPlayerInfo->MakePlayerSafe(true);
- CCutsceneMgr::SetRunning(true);
+ CCutsceneMgr::StartCutsceneProcessing();
return 0;
}
case COMMAND_USE_TEXT_COMMANDS:
@@ -9140,7 +9141,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command)
assert(pVehicle);
assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR);
CAutomobile* pCar = (CAutomobile*)pVehicle;
- pCar->bTakeLessDamage = ScriptParams[1];
+ pCar->bMoreResistantToDamage = ScriptParams[1];
return 0;
}
case COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER:
@@ -9152,6 +9153,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command)
return 0;
}
case COMMAND_LOAD_END_OF_GAME_TUNE:
+ DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
printf("Start preload end of game audio\n");
DMAudio.PreloadCutSceneMusic(STREAMED_SOUND_GAME_COMPLETED);
printf("End preload end of game audio\n");
@@ -11037,6 +11039,7 @@ void CRunningScript::DoDeatharrestCheck()
int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact];
if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) {
messageId += CTheScripts::BaseBriefIdForContact[contact];
+ found = true;
}
}
if (!found)
@@ -11331,6 +11334,7 @@ INITSAVEBUF
break;
case 4:
InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1);
+ break;
default:
assert(false);
}
@@ -11369,15 +11373,15 @@ void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntit
continue;
CEntity* pFound = aEntities[i];
int cols;
- if (CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel()->numLines <= 0)
- cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(),
- pFound->GetMatrix(), *CModelInfo::GetModelInfo(pFound->GetModelIndex())->GetColModel(), aTempColPoints, nil, nil);
+ if (pEntity->GetColModel()->numLines <= 0)
+ cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(),
+ pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints, nil, nil);
else {
float lines[4];
lines[0] = lines[1] = lines[2] = lines[3] = 1.0f;
- CColPoint tmp;
- cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(),
- pFound->GetMatrix(), *CModelInfo::GetModelInfo(pFound->GetModelIndex())->GetColModel(), aTempColPoints, &tmp, lines);
+ CColPoint tmp[4];
+ cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(),
+ pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints,tmp, lines);
}
if (cols <= 0)
continue;
diff --git a/src/control/Script.h b/src/control/Script.h
index fbcdce48..4338bd18 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -15,22 +15,25 @@ class CRunningScript;
#define KEY_LENGTH_IN_SCRIPT 8
-struct CScriptRectangle
+struct intro_script_rectangle
{
- int8 m_bIsUsed;
+ bool m_bIsUsed;
bool m_bBeforeFade;
int16 m_nTextureId;
CRect m_sRect;
CRGBA m_sColor;
+
+ intro_script_rectangle() { }
+ ~intro_script_rectangle() { }
};
-static_assert(sizeof(CScriptRectangle) == 0x18, "Script.h: error");
+static_assert(sizeof(intro_script_rectangle) == 0x18, "Script.h: error");
enum {
SCRIPT_TEXT_MAX_LENGTH = 500
};
-struct CTextLine
+struct intro_text_line
{
float m_fScaleX;
float m_fScaleY;
@@ -50,6 +53,9 @@ struct CTextLine
float m_fAtY;
wchar m_Text[SCRIPT_TEXT_MAX_LENGTH];
+ intro_text_line() { }
+ ~intro_text_line() { }
+
void Reset()
{
m_fScaleX = 0.48f;
@@ -72,15 +78,17 @@ struct CTextLine
}
};
-static_assert(sizeof(CTextLine) == 0x414, "Script.h: error");
+static_assert(sizeof(intro_text_line) == 0x414, "Script.h: error");
-struct CScriptSphere
+struct script_sphere_struct
{
bool m_bInUse;
uint16 m_Index;
uint32 m_Id;
CVector m_vecCenter;
float m_fRadius;
+
+ script_sphere_struct() { }
};
struct CStoredLine
@@ -145,7 +153,7 @@ public:
bool HasCarBeenUpsideDownForAWhile(int32);
};
-struct CStuckCarCheckEntry
+struct stuck_car_data
{
int32 m_nVehicleIndex;
CVector m_vecPos;
@@ -154,12 +162,13 @@ struct CStuckCarCheckEntry
uint32 m_nStuckTime;
bool m_bStuck;
+ stuck_car_data() { }
inline void Reset();
};
class CStuckCarCheck
{
- CStuckCarCheckEntry m_sCars[MAX_STUCK_CAR_CHECKS];
+ stuck_car_data m_sCars[MAX_STUCK_CAR_CHECKS];
public:
void Init();
@@ -235,10 +244,10 @@ class CTheScripts
static CRunningScript(&ScriptsArray)[MAX_NUM_SCRIPTS];
static int32(&BaseBriefIdForContact)[MAX_NUM_CONTACTS];
static int32(&OnAMissionForContactFlag)[MAX_NUM_CONTACTS];
- static CTextLine(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES];
- static CScriptRectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES];
+ static intro_text_line(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES];
+ static intro_script_rectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES];
static CSprite2d(&ScriptSprites)[MAX_NUM_SCRIPT_SRPITES];
- static CScriptSphere(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES];
+ static script_sphere_struct(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES];
static tCollectiveData(&CollectiveArray)[MAX_NUM_COLLECTIVES];
static tUsedObject(&UsedObjectArray)[MAX_NUM_USED_OBJECTS];
static int32(&MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS];
diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp
index 2cd09a03..ab9cd92d 100644
--- a/src/control/TrafficLights.cpp
+++ b/src/control/TrafficLights.cpp
@@ -1,23 +1,335 @@
#include "common.h"
#include "patcher.h"
-#include "TrafficLights.h"
+#include "General.h"
+#include "Camera.h"
+#include "World.h"
+#include "PathFind.h"
#include "Timer.h"
+#include "Clock.h"
+#include "Weather.h"
+#include "Timecycle.h"
+#include "Pointlights.h"
+#include "Shadows.h"
+#include "Coronas.h"
+#include "SpecialFX.h"
#include "Vehicle.h"
+#include "TrafficLights.h"
+
+// TODO: figure out the meaning of this
+enum { SOME_FLAG = 0x80 };
+
+void
+CTrafficLights::DisplayActualLight(CEntity *ent)
+{
+ if(ent->GetUp().z < 0.96f || ent->bRenderDamaged)
+ return;
+
+ int phase;
+ if(FindTrafficLightType(ent) == 1)
+ phase = LightForCars1();
+ else
+ phase = LightForCars2();
+
+ int i;
+ CBaseModelInfo *mi = CModelInfo::GetModelInfo(ent->GetModelIndex());
+ float x = mi->Get2dEffect(0)->pos.x;
+ float yMin = mi->Get2dEffect(0)->pos.y;
+ float yMax = mi->Get2dEffect(0)->pos.y;
+ float zMin = mi->Get2dEffect(0)->pos.z;
+ float zMax = mi->Get2dEffect(0)->pos.z;
+ for(i = 1; i < 6; i++){
+ assert(mi->Get2dEffect(i));
+ yMin = min(yMin, mi->Get2dEffect(i)->pos.y);
+ yMax = max(yMax, mi->Get2dEffect(i)->pos.y);
+ zMin = min(zMin, mi->Get2dEffect(i)->pos.z);
+ zMax = max(zMax, mi->Get2dEffect(i)->pos.z);
+ }
+
+ CVector pos1, pos2;
+ uint8 r, g;
+ int id;
+ switch(phase){
+ case CAR_LIGHTS_GREEN:
+ r = 0;
+ g = 255;
+ pos1 = ent->GetMatrix() * CVector(x, yMax, zMin);
+ pos2 = ent->GetMatrix() * CVector(x, yMin, zMin);
+ id = 0;
+ break;
+ case CAR_LIGHTS_YELLOW:
+ r = 255;
+ g = 128;
+ pos1 = ent->GetMatrix() * CVector(x, yMax, (zMin+zMax)/2.0f);
+ pos2 = ent->GetMatrix() * CVector(x, yMin, (zMin+zMax)/2.0f);
+ id = 1;
+ break;
+ case CAR_LIGHTS_RED:
+ default:
+ r = 255;
+ g = 0;
+ pos1 = ent->GetMatrix() * CVector(x, yMax, zMax);
+ pos2 = ent->GetMatrix() * CVector(x, yMin, zMax);
+ id = 2;
+ break;
+ }
+
+ if(CClock::GetHours() > 19 || CClock::GetHours() < 6 || CWeather::Foggyness > 0.05f)
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos1, CVector(0.0f, 0.0f, 0.0f), 8.0f,
+ r/255.0f, g/255.0f, 0/255.0f, CPointLights::FOG_NORMAL, true);
+
+ CShadows::StoreStaticShadow((uintptr)ent,
+ SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos1,
+ 8.0f, 0.0f, 0.0f, -8.0f, 128,
+ r*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+ g*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+ 0*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+ 12.0f, 1.0f, 40.0f, false, 0.0f);
+
+ if(DotProduct(TheCamera.GetForward(), ent->GetForward()) < 0.0f)
+ CCoronas::RegisterCorona((uintptr)ent + id,
+ r*CTimeCycle::GetSpriteBrightness()*0.7f,
+ g*CTimeCycle::GetSpriteBrightness()*0.7f,
+ 0*CTimeCycle::GetSpriteBrightness()*0.7f,
+ 255,
+ pos1, 1.75f*CTimeCycle::GetSpriteSize(), 50.0f,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::RegisterCorona((uintptr)ent + id + 3,
+ r*CTimeCycle::GetSpriteBrightness()*0.7f,
+ g*CTimeCycle::GetSpriteBrightness()*0.7f,
+ 0*CTimeCycle::GetSpriteBrightness()*0.7f,
+ 255,
+ pos2, 1.75f*CTimeCycle::GetSpriteSize(), 50.0f,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+
+ CBrightLights::RegisterOne(pos1, ent->GetUp(), ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
+ CBrightLights::RegisterOne(pos2, ent->GetUp(), -ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
+
+ static const float top = -0.127f;
+ static const float bot = -0.539f;
+ static const float mid = bot + (top-bot)/3.0f;
+ static const float left = 1.256f;
+ static const float right = 0.706f;
+ phase = CTrafficLights::LightForPeds();
+ if(phase == PED_LIGHTS_DONT_WALK){
+ CVector p0(2.7f, right, top);
+ CVector p1(2.7f, left, top);
+ CVector p2(2.7f, right, mid);
+ CVector p3(2.7f, left, mid);
+ CShinyTexts::RegisterOne(ent->GetMatrix()*p0, ent->GetMatrix()*p1, ent->GetMatrix()*p2, ent->GetMatrix()*p3,
+ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
+ SHINYTEXT_WALK, 255, 0, 0, 60.0f);
+ }else if(phase == PED_LIGHTS_WALK || CTimer::GetTimeInMilliseconds() & 0x100){
+ CVector p0(2.7f, right, mid);
+ CVector p1(2.7f, left, mid);
+ CVector p2(2.7f, right, bot);
+ CVector p3(2.7f, left, bot);
+ CShinyTexts::RegisterOne(ent->GetMatrix()*p0, ent->GetMatrix()*p1, ent->GetMatrix()*p2, ent->GetMatrix()*p3,
+ 1.0f, 0.5f, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f,
+ SHINYTEXT_WALK, 255, 255, 255, 60.0f);
+ }
+}
+
+void
+CTrafficLights::ScanForLightsOnMap(void)
+{
+ int x, y;
+ int i, j, l;
+ CPtrNode *node;
+
+ for(x = 0; x < NUMSECTORS_X; x++)
+ for(y = 0; y < NUMSECTORS_Y; y++){
+ CPtrList &list = CWorld::GetSector(x, y)->m_lists[ENTITYLIST_DUMMIES];
+ for(node = list.first; node; node = node->next){
+ CEntity *light = (CEntity*)node->item;
+ if(light->GetModelIndex() != MI_TRAFFICLIGHTS)
+ continue;
+
+ // Check cars
+ for(i = 0; i < ThePaths.m_numCarPathLinks; i++){
+ CVector2D dist = ThePaths.m_carPathLinks[i].pos - light->GetPosition();
+ float dotY = Abs(DotProduct2D(dist, light->GetForward())); // forward is direction of car light
+ float dotX = DotProduct2D(dist, light->GetRight()); // towards base of light
+ // it has to be on the correct side of the node and also not very far away
+ if(dotX < 0.0f && dotX > -15.0f && dotY < 3.0f){
+ float dz = ThePaths.m_pathNodes[ThePaths.m_carPathLinks[i].pathNodeIndex].pos.z -
+ light->GetPosition().z;
+ if(dz < 15.0f){
+ ThePaths.m_carPathLinks[i].trafficLightType = FindTrafficLightType(light);
+ // Find two neighbour nodes of this one
+ int n1 = -1;
+ int n2 = -1;
+ for(j = 0; j < ThePaths.m_numPathNodes; j++)
+ for(l = 0; l < ThePaths.m_pathNodes[j].numLinks; l++)
+ if(ThePaths.m_carPathConnections[ThePaths.m_pathNodes[j].firstLink + l] == i){
+ if(n1 == -1)
+ n1 = j;
+ else
+ n2 = j;
+ }
+ // What's going on here?
+ if(ThePaths.m_pathNodes[n1].numLinks <= ThePaths.m_pathNodes[n2].numLinks)
+ n1 = n2;
+ if(ThePaths.m_carPathLinks[i].pathNodeIndex != n1)
+ ThePaths.m_carPathLinks[i].trafficLightType |= SOME_FLAG;
+ }
+ }
+ }
+
+ // Check peds
+ for(i = ThePaths.m_numCarPathNodes; i < ThePaths.m_numPathNodes; i++){
+ float dist1, dist2;
+ dist1 = Abs(ThePaths.m_pathNodes[i].pos.x - light->GetPosition().x) +
+ Abs(ThePaths.m_pathNodes[i].pos.y - light->GetPosition().y);
+ if(dist1 < 50.0f){
+ for(l = 0; l < ThePaths.m_pathNodes[i].numLinks; l++){
+ j = ThePaths.m_pathNodes[i].firstLink + l;
+ if(ThePaths.m_connectionFlags[j].bCrossesRoad){
+ dist2 = Abs(ThePaths.m_pathNodes[j].pos.x - light->GetPosition().x) +
+ Abs(ThePaths.m_pathNodes[j].pos.y - light->GetPosition().y);
+ if(dist1 < 15.0f || dist2 < 15.0f)
+ ThePaths.m_connectionFlags[j].bTrafficLight = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+CTrafficLights::ShouldCarStopForLight(CVehicle *vehicle, bool alwaysStop)
+{
+ int node, type;
-WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); }
-WRAPPER void CTrafficLights::ScanForLightsOnMap(void) { EAXJMP(0x454F40); }
-WRAPPER bool CTrafficLights::ShouldCarStopForLight(CVehicle*, bool) { EAXJMP(0x455350); }
-WRAPPER bool CTrafficLights::ShouldCarStopForBridge(CVehicle*) { EAXJMP(0x456460); }
+ node = vehicle->AutoPilot.m_nNextPathNodeInfo;
+ type = ThePaths.m_carPathLinks[node].trafficLightType;
+ if(type){
+ if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nNextRouteNode) &&
+ (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nNextRouteNode))
+ if(alwaysStop ||
+ (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+ (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+ float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+ ThePaths.m_carPathLinks[node].dir);
+ if(vehicle->AutoPilot.m_nNextDirection == -1){
+ if(dist > 0.0f && dist < 8.0f)
+ return true;
+ }else{
+ if(dist < 0.0f && dist > -8.0f)
+ return true;
+ }
+ }
+ }
+
+ node = vehicle->AutoPilot.m_nCurrentPathNodeInfo;
+ type = ThePaths.m_carPathLinks[node].trafficLightType;
+ if(type){
+ if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nCurrentRouteNode) &&
+ (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nCurrentRouteNode))
+ if(alwaysStop ||
+ (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+ (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+ float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+ ThePaths.m_carPathLinks[node].dir);
+ if(vehicle->AutoPilot.m_nCurrentDirection == -1){
+ if(dist > 0.0f && dist < 8.0f)
+ return true;
+ }else{
+ if(dist < 0.0f && dist > -8.0f)
+ return true;
+ }
+ }
+ }
+
+ if(vehicle->m_status == STATUS_PHYSICS){
+ node = vehicle->AutoPilot.m_nPreviousPathNodeInfo;
+ type = ThePaths.m_carPathLinks[node].trafficLightType;
+ if(type){
+ if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nPrevRouteNode) &&
+ (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nPrevRouteNode))
+ if(alwaysStop ||
+ (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+ (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+ float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+ ThePaths.m_carPathLinks[node].dir);
+ if(vehicle->AutoPilot.m_nPreviousDirection == -1){
+ if(dist > 0.0f && dist < 6.0f)
+ return true;
+ }else{
+ if(dist < 0.0f && dist > -6.0f)
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+CTrafficLights::ShouldCarStopForBridge(CVehicle *vehicle)
+{
+ return ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nNextPathNodeInfo].bBridgeLights &&
+ !ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nCurrentPathNodeInfo].bBridgeLights;
+}
+
+int
+CTrafficLights::FindTrafficLightType(CEntity *light)
+{
+ float orientation = RADTODEG(CGeneral::GetATanOfXY(light->GetForward().x, light->GetForward().y));
+ if((orientation > 60.0f && orientation < 60.0f + 90.0f) ||
+ (orientation > 240.0f && orientation < 240.0f + 90.0f))
+ return 1;
+ return 2;
+}
uint8
CTrafficLights::LightForPeds(void)
{
- uint32 period = CTimer::GetTimeInMilliseconds() & 0x3FFF; // Equals to % 16384
+ uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
- if (period >= 15384)
- return PED_LIGHTS_WALK_BLINK;
- else if (period >= 12000)
+ if(period < 12000)
+ return PED_LIGHTS_DONT_WALK;
+ else if(period < 16384 - 1000)
return PED_LIGHTS_WALK;
else
- return PED_LIGHTS_DONT_WALK;
-} \ No newline at end of file
+ return PED_LIGHTS_WALK_BLINK;
+}
+
+uint8
+CTrafficLights::LightForCars1(void)
+{
+ uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
+
+ if(period < 5000)
+ return CAR_LIGHTS_GREEN;
+ else if(period < 5000 + 1000)
+ return CAR_LIGHTS_YELLOW;
+ else
+ return CAR_LIGHTS_RED;
+}
+
+uint8
+CTrafficLights::LightForCars2(void)
+{
+ uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
+
+ if(period < 6000)
+ return CAR_LIGHTS_RED;
+ else if(period < 12000 - 1000)
+ return CAR_LIGHTS_GREEN;
+ else if(period < 12000)
+ return CAR_LIGHTS_YELLOW;
+ else
+ return CAR_LIGHTS_RED;
+}
+
+STARTPATCHES
+ InjectHook(0x455760, &CTrafficLights::LightForCars1, PATCH_JUMP);
+ InjectHook(0x455790, &CTrafficLights::LightForCars2, PATCH_JUMP);
+ InjectHook(0x4557D0, &CTrafficLights::LightForPeds, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/TrafficLights.h b/src/control/TrafficLights.h
index 06505ed6..f3df6cd5 100644
--- a/src/control/TrafficLights.h
+++ b/src/control/TrafficLights.h
@@ -7,6 +7,10 @@ enum {
PED_LIGHTS_WALK,
PED_LIGHTS_WALK_BLINK,
PED_LIGHTS_DONT_WALK,
+
+ CAR_LIGHTS_GREEN = 0,
+ CAR_LIGHTS_YELLOW,
+ CAR_LIGHTS_RED
};
class CTrafficLights
@@ -14,7 +18,10 @@ class CTrafficLights
public:
static void DisplayActualLight(CEntity *ent);
static void ScanForLightsOnMap(void);
+ static int FindTrafficLightType(CEntity *light);
static uint8 LightForPeds(void);
+ static uint8 LightForCars1(void);
+ static uint8 LightForCars2(void);
static bool ShouldCarStopForLight(CVehicle*, bool);
static bool ShouldCarStopForBridge(CVehicle*);
};