summaryrefslogtreecommitdiffstats
path: root/src/control/Cranes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/control/Cranes.cpp')
-rw-r--r--src/control/Cranes.cpp554
1 files changed, 493 insertions, 61 deletions
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp
index 96c41f45..cbfd2a35 100644
--- a/src/control/Cranes.cpp
+++ b/src/control/Cranes.cpp
@@ -4,6 +4,8 @@
#include "Camera.h"
#include "DMAudio.h"
+#include "Garages.h"
+#include "General.h"
#include "Entity.h"
#include "ModelIndices.h"
#include "Replay.h"
@@ -15,6 +17,24 @@
#define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f)
#define CRUSHER_Z (-0.951f)
#define MILITARY_Z (10.7862f)
+#define DISTANCE_FROM_PLAYER_TO_REMOVE_VEHICLE (5.0f)
+#define DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT (0.5f)
+#define CAR_REWARD_MILITARY_CRANE (1500)
+#define CAR_MOVING_SPEED_THRESHOLD (0.01f)
+#define CRANE_SLOWDOWN_MULTIPLIER (0.3f)
+
+#define OSCILLATION_SPEED (0.002f)
+#define CAR_ROTATION_SPEED (0.0035f)
+#define CRANE_MOVEMENT_SPEED (0.001f)
+#define HOOK_ANGLE_MOVEMENT_SPEED (0.004f)
+#define HOOK_OFFSET_MOVEMENT_SPEED (0.1f)
+#define HOOK_HEIGHT_MOVEMENT_SPEED (0.06f)
+
+uint32 TimerForCamInterpolation;
+
+uint32& CCranes::CarsCollectedMilitaryCrane = *(uint32*)0x8F6248;
+int32& CCranes::NumCranes = *(int32*)0x8E28AC;
+CCrane(&CCranes::aCranes)[NUM_CRANES] = *(CCrane(*)[NUM_CRANES])*(uintptr*)0x6FA4E0;
void CCranes::InitCranes(void)
{
@@ -31,7 +51,7 @@ void CCranes::InitCranes(void)
}
}
}
- for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL).first; pNode; pNode->next) {
+ for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL).first; pNode; pNode = pNode->next) {
CEntity* pEntity = (CEntity*)pNode->item;
if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
MODELID_CRANE_2 == pEntity->GetModelIndex() ||
@@ -47,34 +67,33 @@ void CCranes::AddThisOneCrane(CEntity* pEntity)
return;
CCrane* pCrane = &aCranes[NumCranes];
pCrane->Init();
- pCrane->m_pObject = pEntity;
- pCrane->m_bCraneStatus = CCrane::NONE;
- pCrane->m_fHeight = NumCranes; // lol wtf
- while (pCrane->m_fHeight > TWOPI)
- pCrane->m_fHeight -= TWOPI;
+ pCrane->m_pCraneEntity = (CBuilding*)pEntity;
+ pCrane->m_nCraneStatus = CCrane::NONE;
+ pCrane->m_fHookAngle = NumCranes; // lol wtf
+ while (pCrane->m_fHookAngle > TWOPI)
+ pCrane->m_fHookAngle -= TWOPI;
pCrane->m_fHookOffset = 20.0f;
pCrane->m_fHookHeight = 20.0f;
- pCrane->m_nUpdateTimer = 0;
- pCrane->m_bCraneState = CCrane::IDLE;
- pCrane->m_bWasMilitaryCrane = 0;
+ pCrane->m_nTimeForNextCheck = 0;
+ pCrane->m_nCraneState = CCrane::IDLE;
+ pCrane->m_bWasMilitaryCrane = false;
pCrane->m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[NumCranes]);
if (pCrane->m_nAudioEntity >= 0)
DMAudio.SetEntityStatus(pCrane->m_nAudioEntity, 1);
pCrane->m_bIsTop = (MODELID_CRANE_1 != pEntity->GetModelIndex());
- // W T F ? ? ?
// Is this used to avoid military crane?
if (pCrane->m_bIsTop || pEntity->GetPosition().y > 0.0f) {
- CObject* pMagnet = new CObject(MI_MAGNET, false);
- pMagnet->ObjectCreatedBy = MISSION_OBJECT;
- pMagnet->bUsesCollision = false;
- pMagnet->bExplosionProof = true;
- pMagnet->bAffectedByGravity = false;
- pCrane->m_pMagnet = pMagnet;
+ CObject* pHook = new CObject(MI_MAGNET, false);
+ pHook->ObjectCreatedBy = MISSION_OBJECT;
+ pHook->bUsesCollision = false;
+ pHook->bExplosionProof = true;
+ pHook->bAffectedByGravity = false;
+ pCrane->m_pHook = pHook;
pCrane->CalcHookCoordinates(&pCrane->m_vecHookCurPos.x, &pCrane->m_vecHookCurPos.y, &pCrane->m_vecHookCurPos.z);
pCrane->SetHookMatrix();
}
else
- pCrane->m_pMagnet = nil;
+ pCrane->m_pHook = nil;
NumCranes++;
}
@@ -88,7 +107,7 @@ void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY,
}
int index = 0;
for (int i = 0; i < NumCranes; i++) {
- float distance = (CVector2D(X, Y) - aCranes[i].m_pObject->GetPosition()).Magnitude();
+ float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
fMinDistance = distance;
index = i;
@@ -98,7 +117,7 @@ void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY,
if (fMinDistance == 99999.9f)
return;
#endif
- CCrane* pCrane = &aCranes[NumCranes];
+ CCrane* pCrane = &aCranes[index];
pCrane->m_fPickupX1 = fInfX;
pCrane->m_fPickupX2 = fSupX;
pCrane->m_fPickupY1 = fInfY;
@@ -106,26 +125,27 @@ void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY,
pCrane->m_vecDropoffTarget.x = fDropOffX;
pCrane->m_vecDropoffTarget.y = fDropOffY;
pCrane->m_vecDropoffTarget.z = fDropOffZ;
- pCrane->m_bCraneStatus = CCrane::ACTIVATED;
+ pCrane->m_nCraneStatus = CCrane::ACTIVATED;
pCrane->m_pVehiclePickedUp = nil;
- pCrane->m_bVehiclesCollected = 0;
+ pCrane->m_nVehiclesCollected = 0;
+ pCrane->m_fDropoffHeading = fHeading;
pCrane->m_bIsCrusher = bIsCrusher;
pCrane->m_bIsMilitaryCrane = bIsMilitary;
bool military = true;
if (!bIsMilitary && !pCrane->m_bWasMilitaryCrane)
military = false;
pCrane->m_bWasMilitaryCrane = military;
- pCrane->m_nUpdateTimer = 0;
- pCrane->m_bCraneState = CCrane::IDLE;
+ pCrane->m_nTimeForNextCheck = 0;
+ pCrane->m_nCraneState = CCrane::IDLE;
float Z;
if (bIsCrusher)
Z = CRUSHER_Z;
else if (bIsMilitary)
Z = MILITARY_Z;
else
- Z = CWorld::FindGroundZForCoord((fInfX + fSupY) / 2, (fInfY + fSupY) / 2);
- pCrane->FindParametersForTarget((fInfX + fSupY) / 2, (fInfY + fSupY) / 2, Z, &pCrane->m_fPickupAngle, &pCrane->m_fPickupDistance, &pCrane->m_fAngle);
- pCrane->FindParametersForTarget(fDropOffX, fDropOffY, fDropOffZ, &pCrane->m_fDropoffAngle, &pCrane->m_fDropoffDistance, &pCrane->m_fDistance);
+ Z = CWorld::FindGroundZForCoord((fInfX + fSupX) / 2, (fInfY + fSupY) / 2);
+ pCrane->FindParametersForTarget((fInfX + fSupX) / 2, (fInfY + fSupY) / 2, Z, &pCrane->m_fPickupAngle, &pCrane->m_fPickupDistance, &pCrane->m_fPickupHeight);
+ pCrane->FindParametersForTarget(fDropOffX, fDropOffY, fDropOffZ, &pCrane->m_fDropoffAngle, &pCrane->m_fDropoffDistance, &pCrane->m_fDropoffHeight);
}
void CCranes::DeActivateCrane(float X, float Y)
@@ -133,7 +153,7 @@ void CCranes::DeActivateCrane(float X, float Y)
float fMinDistance = 99999.9f;
int index = 0;
for (int i = 0; i < NumCranes; i++) {
- float distance = (CVector2D(X, Y) - aCranes[i].m_pObject->GetPosition()).Magnitude();
+ float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
fMinDistance = distance;
index = i;
@@ -143,8 +163,8 @@ void CCranes::DeActivateCrane(float X, float Y)
if (fMinDistance == 99999.9f)
return;
#endif
- aCranes[index].m_bCraneStatus = CCrane::DEACTIVATED;
- aCranes[index].m_bCraneState = CCrane::IDLE;
+ aCranes[index].m_nCraneStatus = CCrane::DEACTIVATED;
+ aCranes[index].m_nCraneState = CCrane::IDLE;
}
bool CCranes::IsThisCarPickedUp(float X, float Y, CVehicle* pVehicle)
@@ -152,9 +172,9 @@ bool CCranes::IsThisCarPickedUp(float X, float Y, CVehicle* pVehicle)
int index = 0;
bool result = false;
for (int i = 0; i < NumCranes; i++) {
- float distance = (CVector2D(X, Y) - aCranes[i].m_pObject->GetPosition()).Magnitude();
+ float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
if (distance < MAX_DISTANCE_TO_FIND_CRANE && aCranes[i].m_pVehiclePickedUp == pVehicle) {
- if (aCranes[i].m_bCraneStatus == CCrane::LIFTING_TARGET || aCranes[i].m_bCraneStatus == CCrane::ROTATING_TARGET)
+ if (aCranes[i].m_nCraneStatus == CCrane::LIFTING_TARGET || aCranes[i].m_nCraneStatus == CCrane::ROTATING_TARGET)
result = true;
}
}
@@ -165,10 +185,10 @@ void CCranes::UpdateCranes(void)
{
for (int i = 0; i < NumCranes; i++) {
if (aCranes[i].m_bIsTop || aCranes[i].m_bIsCrusher ||
- (TheCamera.GetPosition().x + CRANE_UPDATE_RADIUS > aCranes[i].m_pObject->GetPosition().x &&
- TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pObject->GetPosition().x &&
- TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pObject->GetPosition().y &&
- TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pObject->GetPosition().y))
+ (TheCamera.GetPosition().x + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().x &&
+ TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().x &&
+ TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().y &&
+ TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().y))
aCranes[i].Update();
}
}
@@ -177,13 +197,14 @@ void CCrane::Update(void)
{
if (CReplay::IsPlayingBack())
return;
- if ((m_bCraneStatus == ACTIVATED || m_bCraneStatus == DEACTIVATED) &&
- Abs(TheCamera.GetGameCamPosition().x - m_pObject->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS &&
- Abs(TheCamera.GetGameCamPosition().y - m_pObject->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) {
- switch (m_bCraneState) {
+ if (((m_nCraneStatus == ACTIVATED || m_nCraneStatus == DEACTIVATED) &&
+ Abs(TheCamera.GetGameCamPosition().x - m_pCraneEntity->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS &&
+ Abs(TheCamera.GetGameCamPosition().y - m_pCraneEntity->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) ||
+ m_nCraneState != IDLE) {
+ switch (m_nCraneState) {
case IDLE:
- if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, 4.0f + m_fAngle + m_bIsCrusher ? 4.5f : 0.0f, 1.0f) &&
- CTimer::GetTimeInMilliseconds() > m_nUpdateTimer) {
+ if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, GetHeightToPickup()) &&
+ CTimer::GetTimeInMilliseconds() > m_nTimeForNextCheck) {
CWorld::AdvanceCurrentScanCode();
#ifdef FIX_BUGS
int xstart = max(0, CWorld::GetSectorIndexX(m_fPickupX1));
@@ -207,33 +228,444 @@ void CCrane::Update(void)
}
break;
case GOING_TOWARDS_TARGET:
- if (!m_pVehiclePickedUp) {
- m_bCraneState = IDLE;
- break;
+ if (m_pVehiclePickedUp){
+ if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 ||
+ m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 ||
+ m_pVehiclePickedUp->GetPosition().y < m_fPickupY1 ||
+ m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 ||
+ m_pVehiclePickedUp->pDriver ||
+ Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > CAR_MOVING_SPEED_THRESHOLD ||
+ Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > CAR_MOVING_SPEED_THRESHOLD ||
+ Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > CAR_MOVING_SPEED_THRESHOLD ||
+ FindPlayerPed()->GetPedState() == PED_ENTER_CAR && // TODO: fix carjack bug
+ FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) {
+ m_pVehiclePickedUp = nil;
+ m_nCraneState = IDLE;
+ }
+ else {
+ float fAngle, fOffset, fHeight;
+ FindParametersForTarget(
+ m_pVehiclePickedUp->GetPosition().x,
+ m_pVehiclePickedUp->GetPosition().y,
+ m_pVehiclePickedUp->GetPosition().z + m_pVehiclePickedUp->GetColModel()->boundingBox.max.z,
+ &fAngle, &fOffset, &fHeight);
+ if (GoTowardsTarget(fAngle, fOffset, fHeight)) {
+ CVector distance = m_pVehiclePickedUp->GetPosition() - m_vecHookCurPos;
+ distance.z += m_pVehiclePickedUp->GetColModel()->boundingBox.max.z;
+ if (distance.MagnitudeSqr() < SQR(DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT)) {
+ m_nCraneState = GOING_TOWARDS_TARGET_ONLY_HEIGHT;
+ m_vecHookVelocity *= 0.4f;
+ m_pVehiclePickedUp->bLightsOn = false;
+ m_pVehiclePickedUp->bUsesCollision = false;
+ if (m_bIsCrusher)
+ m_pVehiclePickedUp->bCollisionProof = true;
+ DMAudio.PlayOneShot(m_nAudioEntity, SOUND_CRANE_PICKUP, 0.0f);
+ }
+ }
+ }
}
- if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 ||
- m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 ||
- m_pVehiclePickedUp->GetPosition().y > m_fPickupY1 ||
- m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 ||
- m_pVehiclePickedUp->pDriver ||
- Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > 0.01f ||
- Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > 0.01f ||
- Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > 0.01f ||
- FindPlayerPed()->GetPedState() == PED_ENTER_CAR &&
- FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) {
+ else
+ m_nCraneState = IDLE;
+ break;
+ case LIFTING_TARGET:
+ RotateCarriedCarProperly();
+ if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoff(), 0.3f))
+ m_nCraneState = ROTATING_TARGET;
+ if (!m_pVehiclePickedUp || m_pVehiclePickedUp->pDriver) {
m_pVehiclePickedUp = nil;
- m_bCraneState = IDLE;
+ m_nCraneState = IDLE;
+ }
+ break;
+ case GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+ RotateCarriedCarProperly();
+ if (GoTowardsHeightTarget(GetHeightToPickupHeight(), CRANE_SLOWDOWN_MULTIPLIER))
+ m_nCraneState = LIFTING_TARGET;
+ TimerForCamInterpolation = CTimer::GetTimeInMilliseconds();
+ if (!m_pVehiclePickedUp || m_pVehiclePickedUp->pDriver) {
+ m_pVehiclePickedUp = nil;
+ m_nCraneState = IDLE;
+ }
+ break;
+ case ROTATING_TARGET:
+ {
+ bool bRotateFinished = RotateCarriedCarProperly();
+ bool bMovementFinished = GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, m_fDropoffHeight, 0.3f);
+ if (bMovementFinished && bRotateFinished) {
+ float fDistanceFromPlayer = m_pVehiclePickedUp ? ((CVector2D)FindPlayerCoors() - (CVector2D)m_pVehiclePickedUp->GetPosition()).Magnitude() : 0.0f;
+ if (fDistanceFromPlayer > DISTANCE_FROM_PLAYER_TO_REMOVE_VEHICLE || !m_bWasMilitaryCrane) {
+ m_nCraneState = DROPPING_TARGET;
+ if (m_pVehiclePickedUp) {
+ m_pVehiclePickedUp->bUsesCollision = true;
+ m_pVehiclePickedUp->m_nStaticFrames = 0;
+ ++m_nVehiclesCollected;
+ if (m_bIsMilitaryCrane) {
+ CCranes::RegisterCarForMilitaryCrane(m_pVehiclePickedUp->GetModelIndex());
+ if (!CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()) {
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += CAR_REWARD_MILITARY_CRANE;
+ CGarages::TriggerMessage("GA_10", CAR_REWARD_MILITARY_CRANE, 4000, -1);
+ }
+ CWorld::Remove(m_pVehiclePickedUp);
+ delete m_pVehiclePickedUp;
+ }
+ }
+ m_pVehiclePickedUp = nil;
+ }
+ }
+ break;
+ }
+ case DROPPING_TARGET:
+ if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoffHeight(), CRANE_SLOWDOWN_MULTIPLIER)) {
+ m_nCraneState = IDLE;
+ m_nTimeForNextCheck = CTimer::GetTimeInMilliseconds() + 10000;
+ }
+ break;
+ default:
+ break;
+ }
+ CVector vecHook;
+ CalcHookCoordinates(&vecHook.x, &vecHook.y, &vecHook.z);
+ m_vecHookVelocity += ((CVector2D)vecHook - (CVector2D)m_vecHookCurPos) * CTimer::GetTimeStep() * CRANE_MOVEMENT_SPEED;
+ m_vecHookVelocity *= Pow(0.98f, CTimer::GetTimeStep());
+ m_vecHookCurPos.x += m_vecHookVelocity.x * CTimer::GetTimeStep();
+ m_vecHookCurPos.y += m_vecHookVelocity.y * CTimer::GetTimeStep();
+ m_vecHookCurPos.z = vecHook.z;
+ switch (m_nCraneState) {
+ case LIFTING_TARGET:
+ case GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+ case ROTATING_TARGET:
+ if (m_pVehiclePickedUp) {
+ m_pVehiclePickedUp->GetPosition() = CVector(m_vecHookCurPos.x, m_vecHookCurPos.y, m_vecHookCurPos.z - m_pVehiclePickedUp->GetColModel()->boundingBox.max.z);
+ m_pVehiclePickedUp->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ CVector up(vecHook.x - m_vecHookCurPos.x, vecHook.y - m_vecHookCurPos.y, 20.0f);
+ up.Normalise();
+ m_pVehiclePickedUp->GetRight() = CrossProduct(m_pVehiclePickedUp->GetForward(), up);
+ m_pVehiclePickedUp->GetForward() = CrossProduct(up, m_pVehiclePickedUp->GetRight());
+ m_pVehiclePickedUp->GetUp() = up;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ int16 rnd = (m_pCraneEntity->m_randomSeed + (CTimer::GetTimeInMilliseconds() >> 11)) & 0xF;
+ // 16 options, lasting 2048 ms each
+ // a bit awkward: why there are 4 periods for -= and 6 for +=? is it a bug?
+ if (rnd < 4) {
+ m_fHookAngle -= OSCILLATION_SPEED * CTimer::GetTimeStep();
+ if (m_fHookAngle < 0.0f)
+ m_fHookAngle += TWOPI;
+ }
+ else if (rnd > 5 && rnd < 12) {
+ m_fHookAngle += OSCILLATION_SPEED * CTimer::GetTimeStep();
+ if (m_fHookAngle > TWOPI)
+ m_fHookAngle -= TWOPI;
+ }
+ CalcHookCoordinates(&m_vecHookCurPos.x, &m_vecHookCurPos.y, &m_vecHookCurPos.z);
+ m_vecHookVelocity.x = m_vecHookVelocity.y = 0.0f;
+ }
+ float fCos = Cos(m_fHookAngle);
+ float fSin = Sin(m_fHookAngle);
+ m_pCraneEntity->GetRight().x = fCos;
+ m_pCraneEntity->GetForward().y = fCos;
+ m_pCraneEntity->GetRight().y = fSin;
+ m_pCraneEntity->GetForward().x = -fSin;
+ m_pCraneEntity->GetMatrix().UpdateRW();
+ m_pCraneEntity->UpdateRwFrame();
+ SetHookMatrix();
+}
+
+bool CCrane::RotateCarriedCarProperly()
+{
+ if (m_fDropoffHeading <= 0.0f)
+ return true;
+ if (!m_pVehiclePickedUp)
+ return true;
+ float fAngleDelta = m_fDropoffHeading - CGeneral::GetATanOfXY(m_pVehiclePickedUp->GetForward().x, m_pVehiclePickedUp->GetForward().y);
+ while (fAngleDelta < -HALFPI)
+ fAngleDelta += PI;
+ while (fAngleDelta > HALFPI)
+ fAngleDelta -= PI;
+ float fDeltaThisFrame = CAR_ROTATION_SPEED * CTimer::GetTimeStep();
+ if (Abs(fAngleDelta) <= fDeltaThisFrame) // no rotation is actually applied?
+ return true;
+ m_pVehiclePickedUp->GetMatrix().RotateZ(Abs(fDeltaThisFrame));
+ return false;
+}
+
+void CCrane::FindCarInSectorList(CPtrList* pList)
+{
+ CPtrNode* node;
+ for (node = pList->first; node; node = node->next) {
+ CVehicle* pVehicle = (CVehicle*)node->item;
+ if (pVehicle->m_scanCode == CWorld::GetCurrentScanCode())
+ continue;
+ pVehicle->m_scanCode = CWorld::GetCurrentScanCode();
+ if (pVehicle->GetPosition().x < m_fPickupX1 || pVehicle->GetPosition().x > m_fPickupX2 ||
+ pVehicle->GetPosition().y < m_fPickupY1 || pVehicle->GetPosition().y > m_fPickupY2)
+ continue;
+ if (Abs(pVehicle->GetMoveSpeed().x) >= CAR_MOVING_SPEED_THRESHOLD ||
+ Abs(pVehicle->GetMoveSpeed().y) >= CAR_MOVING_SPEED_THRESHOLD ||
+ Abs(pVehicle->GetMoveSpeed().z) >= CAR_MOVING_SPEED_THRESHOLD)
+ continue;
+ if (!pVehicle->IsCar() || pVehicle->m_status == STATUS_WRECKED || pVehicle->m_fHealth < 250.0f)
+ continue;
+ if (!DoesCranePickUpThisCarType(pVehicle->GetModelIndex()) ||
+ m_bIsMilitaryCrane && CCranes::DoesMilitaryCraneHaveThisOneAlready(pVehicle->GetModelIndex())) {
+ if (!pVehicle->bCraneMessageDone) {
+ pVehicle->bCraneMessageDone = true;
+ if (!m_bIsMilitaryCrane)
+ CGarages::TriggerMessage("CR_1", -1, 4000, -1); // Crane cannot lift this vehicle.
+ else if (DoesCranePickUpThisCarType(pVehicle->GetModelIndex()))
+ CGarages::TriggerMessage("GA_20", -1, 4000, -1); // We got more of these than we can shift. Sorry man, no deal.
+ else
+ CGarages::TriggerMessage("GA_19", -1, 4000, -1); // We're not interested in that model.
+ }
+ }
+ else {
+ m_pVehiclePickedUp = pVehicle;
+ pVehicle->RegisterReference((CEntity**)&m_pVehiclePickedUp);
+ m_nCraneState = GOING_TOWARDS_TARGET;
+ }
+ }
+}
+
+bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
+{
+ if (m_bIsCrusher) {
+ return mi != MI_FIRETRUCK &&
+ mi != MI_TRASH &&
+#ifndef FIX_BUGS // why
+ mi != MI_BLISTA &&
+#endif
+ mi != MI_SECURICA &&
+ mi != MI_BUS &&
+ mi != MI_DODO &&
+ mi != MI_RHINO;
+ }
+ if (m_bIsMilitaryCrane) {
+ return mi == MI_FIRETRUCK ||
+ mi == MI_AMBULAN ||
+ mi == MI_ENFORCER ||
+ mi == MI_FBICAR ||
+ mi == MI_RHINO ||
+ mi == MI_BARRACKS ||
+ mi == MI_POLICE;
+ }
+ return true;
+}
+
+bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
+{
+ switch (mi) {
+ case MI_FIRETRUCK: return (CCranes::CarsCollectedMilitaryCrane & 1);
+ case MI_AMBULAN: return (CCranes::CarsCollectedMilitaryCrane & 2);
+ case MI_ENFORCER: return (CCranes::CarsCollectedMilitaryCrane & 4);
+ case MI_FBICAR: return (CCranes::CarsCollectedMilitaryCrane & 8);
+ case MI_RHINO: return (CCranes::CarsCollectedMilitaryCrane & 0x10);
+ case MI_BARRACKS: return (CCranes::CarsCollectedMilitaryCrane & 0x20);
+ case MI_POLICE: return (CCranes::CarsCollectedMilitaryCrane & 0x40);
+ default: break;
+ }
+ return false;
+}
+
+void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
+{
+ switch (mi) {
+ case MI_FIRETRUCK: CCranes::CarsCollectedMilitaryCrane |= 1; break;
+ case MI_AMBULAN: CCranes::CarsCollectedMilitaryCrane |= 2; break;
+ case MI_ENFORCER: CCranes::CarsCollectedMilitaryCrane |= 4; break;
+ case MI_FBICAR: CCranes::CarsCollectedMilitaryCrane |= 8; break;
+ case MI_RHINO: CCranes::CarsCollectedMilitaryCrane |= 0x10; break;
+ case MI_BARRACKS: CCranes::CarsCollectedMilitaryCrane |= 0x20; break;
+ case MI_POLICE: CCranes::CarsCollectedMilitaryCrane |= 0x40; break;
+ default: break;
+ }
+}
+
+bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()
+{
+ return (CCranes::CarsCollectedMilitaryCrane & 0x7F) == 0x7F;
+}
+
+bool CCrane::GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier)
+{
+ bool bAngleMovementFinished, bOffsetMovementFinished, bHeightMovementFinished;
+ float fHookAngleDelta = fAngleToTarget - m_fHookAngle;
+ while (fHookAngleDelta > PI)
+ fHookAngleDelta -= TWOPI;
+ while (fHookAngleDelta < -PI)
+ fHookAngleDelta += TWOPI;
+ float fHookAngleChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_ANGLE_MOVEMENT_SPEED;
+ if (Abs(fHookAngleDelta) < fHookAngleChangeThisFrame) {
+ m_fHookAngle = fAngleToTarget;
+ bAngleMovementFinished = true;
+ }
+ else {
+ if (fHookAngleDelta < 0.0f) {
+ m_fHookAngle -= fHookAngleChangeThisFrame;
+ if (m_fHookAngle < 0.0f)
+ m_fHookAngle += TWOPI;
+ }
+ else {
+ m_fHookAngle += fHookAngleChangeThisFrame;
+ if (m_fHookAngle > TWOPI)
+ m_fHookAngle -= TWOPI;
+ }
+ bAngleMovementFinished = false;
+ }
+ float fHookOffsetDelta = fDistanceToTarget - m_fHookOffset;
+ float fHookOffsetChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_OFFSET_MOVEMENT_SPEED;
+ if (Abs(fHookOffsetDelta) < fHookOffsetChangeThisFrame) {
+ m_fHookOffset = fDistanceToTarget;
+ bOffsetMovementFinished = true;
+ }
+ else {
+ if (fHookOffsetDelta < 0.0f)
+ m_fHookOffset -= fHookOffsetChangeThisFrame;
+ else
+ m_fHookOffset += fHookOffsetChangeThisFrame;
+ bOffsetMovementFinished = false;
+ }
+ float fHookHeightDelta = fTargetHeight - m_fHookHeight;
+ float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
+ if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
+ m_fHookHeight = fTargetHeight;
+ bHeightMovementFinished = true;
+ }
+ else {
+ if (fHookHeightDelta < 0.0f)
+ m_fHookHeight -= fHookHeightChangeThisFrame;
+ else
+ m_fHookHeight += fHookHeightChangeThisFrame;
+ bHeightMovementFinished = false;
+ }
+ return bAngleMovementFinished && bOffsetMovementFinished && bHeightMovementFinished;
+}
+
+bool CCrane::GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier)
+{
+ bool bHeightMovementFinished;
+ float fHookHeightDelta = fTargetHeight - m_fHookHeight;
+ float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
+ if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
+ m_fHookHeight = fTargetHeight;
+ bHeightMovementFinished = true;
+ }
+ else {
+ if (fHookHeightDelta < 0.0f)
+ m_fHookHeight -= fHookHeightChangeThisFrame;
+ else
+ m_fHookHeight += fHookHeightChangeThisFrame;
+ bHeightMovementFinished = false;
+ }
+ return bHeightMovementFinished;
+}
+
+void CCrane::FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight)
+{
+ *pAngle = CGeneral::GetATanOfXY(X - m_pCraneEntity->GetPosition().x, Y - m_pCraneEntity->GetPosition().y);
+ *pDistance = ((CVector2D(X, Y) - (CVector2D)m_pCraneEntity->GetPosition())).Magnitude();
+ *pHeight = Z;
+}
+
+void CCrane::CalcHookCoordinates(float* pX, float* pY, float* pZ)
+{
+ *pX = Cos(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().x;
+ *pY = Sin(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().y;
+ *pZ = m_fHookHeight;
+}
+
+void CCrane::SetHookMatrix()
+{
+ if (!m_pHook)
+ return;
+ m_pHook->GetPosition() = m_vecHookCurPos;
+ CVector up(m_vecHookInitPos.x - m_vecHookCurPos.x, m_vecHookInitPos.y - m_vecHookCurPos.y, 20.0f);
+ up.Normalise();
+ m_pHook->GetRight() = CrossProduct(CVector(0.0f, 1.0f, 0.0f), up);
+ m_pHook->GetForward() = CrossProduct(up, m_pHook->GetRight());
+ m_pHook->GetUp() = up;
+ m_pHook->SetOrientation(0.0f, 0.0f, -HALFPI);
+ m_pHook->GetMatrix().UpdateRW();
+ m_pHook->UpdateRwFrame();
+ CWorld::Remove(m_pHook);
+ CWorld::Add(m_pHook);
+}
+
+bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle)
+{
+ for (int i = 0; i < NumCranes; i++) {
+ if (pVehicle == aCranes[i].m_pVehiclePickedUp) {
+ switch (aCranes[i].m_nCraneState) {
+ case CCrane::GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+ case CCrane::LIFTING_TARGET:
+ case CCrane::ROTATING_TARGET:
+ return true;
+ default:
break;
}
-
}
}
+ return false;
+}
+
+bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle)
+{
+ for (int i = 0; i < NumCranes; i++) {
+ if (pVehicle == aCranes[i].m_pVehiclePickedUp)
+ return true;
+ }
+ return false;
}
-WRAPPER bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle*) { EAXJMP(0x5451E0); }
-WRAPPER bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle*) { EAXJMP(0x545190); }
-WRAPPER bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane() { EAXJMP(0x544BE0); }
+void CCranes::Save(uint8* buf, uint32* size)
+{
+ INITSAVEBUF
+
+ *size = 2 * sizeof(uint32) + NUM_CRANES * sizeof(CCrane);
+ WriteSaveBuf(buf, NumCranes);
+ WriteSaveBuf(buf, CarsCollectedMilitaryCrane);
+ for (int i = 0; i < NUM_CRANES; i++) {
+ CCrane* pCrane = WriteSaveBuf(buf, aCranes[i]);
+ if (pCrane->m_pCraneEntity)
+ pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex((CBuilding*)pCrane->m_pCraneEntity) + 1);
+ if (pCrane->m_pHook)
+ pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex((CObject*)pCrane->m_pHook) + 1);
+ if (pCrane->m_pVehiclePickedUp)
+ pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex((CVehicle*)pCrane->m_pVehiclePickedUp) + 1);
+ }
+
+ VALIDATESAVEBUF(*size);
+}
+void CranesLoad(uint8* buf, uint32 size)
+{
+ INITSAVEBUF
+
+ CCranes::NumCranes = ReadSaveBuf<int32>(buf);
+ CCranes::CarsCollectedMilitaryCrane = ReadSaveBuf<uint32>(buf);
+ for (int i = 0; i < NUM_CRANES; i++)
+ CCranes::aCranes[i] = ReadSaveBuf<CCrane>(buf);
+ for (int i = 0; i < NUM_CRANES; i++) {
+ CCrane* pCrane = &CCranes::aCranes[i];
+ if (pCrane->m_pCraneEntity)
+ pCrane->m_pCraneEntity = CPools::GetBuildingPool()->GetSlot((uint32)pCrane->m_pCraneEntity - 1);
+ if (pCrane->m_pHook)
+ pCrane->m_pHook = CPools::GetObjectPool()->GetSlot((uint32)pCrane->m_pHook - 1);
+ if (pCrane->m_pVehiclePickedUp)
+ pCrane->m_pVehiclePickedUp = CPools::GetVehiclePool()->GetSlot((uint32)pCrane->m_pVehiclePickedUp + 1);
+ }
+ for (int i = 0; i < NUM_CRANES; i++) {
+ CCranes::aCranes[i].m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &CCranes::aCranes[i]);
+ if (CCranes::aCranes[i].m_nAudioEntity)
+ DMAudio.SetEntityStatus(CCranes::aCranes[i].m_nAudioEntity, 1);
+ }
+
+ VALIDATESAVEBUF(size);
+}
-WRAPPER void CCranes::Save(uint8*, uint32*) { EAXJMP(0x545210); }
-WRAPPER void CranesLoad(uint8*, uint32) { EAXJMP(0x5454d0); }
+STARTPATCHES
+ InjectHook(0x5454D0, CranesLoad, PATCH_JUMP); // GenericLoad
+ENDPATCHES \ No newline at end of file