Cranes done

This commit is contained in:
Nikolay Korolev 2020-04-06 02:01:03 +03:00
parent 9436b5a8a5
commit 7f8a78e5de
8 changed files with 565 additions and 117 deletions

View File

@ -3515,9 +3515,9 @@ cAudioManager::ProcessCrane()
static const int intensity = 80; static const int intensity = 80;
if(crane) { if(crane) {
if(crane->m_bCraneActive == 1) { if(crane->m_nCraneStatus == CCrane::ACTIVATED) {
if(crane->m_bCraneStatus) { if(crane->m_nCraneState != CCrane::IDLE) {
m_sQueueSample.m_vecPos = crane->m_pObject->GetPosition(); m_sQueueSample.m_vecPos = crane->m_pCraneEntity->GetPosition();
distSquared = GetDistanceSquared(&this->m_sQueueSample.m_vecPos); distSquared = GetDistanceSquared(&this->m_sQueueSample.m_vecPos);
if(distSquared < SQR(intensity)) { if(distSquared < SQR(intensity)) {
CalculateDistance(distCalculated, distSquared); CalculateDistance(distCalculated, distSquared);

View File

@ -61,7 +61,7 @@ cAudioScriptObject::SaveAllAudioScriptObjects(uint8 *buf, uint32 *size)
INITSAVEBUF INITSAVEBUF
int32 pool_size = CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces(); int32 pool_size = CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces();
*size = SAVE_HEADER_SIZE + pool_size * (sizeof(cAudioScriptObject) + sizeof(int32)); *size = SAVE_HEADER_SIZE + sizeof(int32) + pool_size * (sizeof(cAudioScriptObject) + sizeof(int32));
WriteSaveHeader(buf, 'A', 'U', 'D', '\0', *size - SAVE_HEADER_SIZE); WriteSaveHeader(buf, 'A', 'U', 'D', '\0', *size - SAVE_HEADER_SIZE);
WriteSaveBuf(buf, pool_size); WriteSaveBuf(buf, pool_size);

View File

@ -4,6 +4,8 @@
#include "Camera.h" #include "Camera.h"
#include "DMAudio.h" #include "DMAudio.h"
#include "Garages.h"
#include "General.h"
#include "Entity.h" #include "Entity.h"
#include "ModelIndices.h" #include "ModelIndices.h"
#include "Replay.h" #include "Replay.h"
@ -15,6 +17,24 @@
#define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f) #define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f)
#define CRUSHER_Z (-0.951f) #define CRUSHER_Z (-0.951f)
#define MILITARY_Z (10.7862f) #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) 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; CEntity* pEntity = (CEntity*)pNode->item;
if (MODELID_CRANE_1 == pEntity->GetModelIndex() || if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
MODELID_CRANE_2 == pEntity->GetModelIndex() || MODELID_CRANE_2 == pEntity->GetModelIndex() ||
@ -47,34 +67,33 @@ void CCranes::AddThisOneCrane(CEntity* pEntity)
return; return;
CCrane* pCrane = &aCranes[NumCranes]; CCrane* pCrane = &aCranes[NumCranes];
pCrane->Init(); pCrane->Init();
pCrane->m_pObject = pEntity; pCrane->m_pCraneEntity = (CBuilding*)pEntity;
pCrane->m_bCraneStatus = CCrane::NONE; pCrane->m_nCraneStatus = CCrane::NONE;
pCrane->m_fHeight = NumCranes; // lol wtf pCrane->m_fHookAngle = NumCranes; // lol wtf
while (pCrane->m_fHeight > TWOPI) while (pCrane->m_fHookAngle > TWOPI)
pCrane->m_fHeight -= TWOPI; pCrane->m_fHookAngle -= TWOPI;
pCrane->m_fHookOffset = 20.0f; pCrane->m_fHookOffset = 20.0f;
pCrane->m_fHookHeight = 20.0f; pCrane->m_fHookHeight = 20.0f;
pCrane->m_nUpdateTimer = 0; pCrane->m_nTimeForNextCheck = 0;
pCrane->m_bCraneState = CCrane::IDLE; pCrane->m_nCraneState = CCrane::IDLE;
pCrane->m_bWasMilitaryCrane = 0; pCrane->m_bWasMilitaryCrane = false;
pCrane->m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[NumCranes]); pCrane->m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[NumCranes]);
if (pCrane->m_nAudioEntity >= 0) if (pCrane->m_nAudioEntity >= 0)
DMAudio.SetEntityStatus(pCrane->m_nAudioEntity, 1); DMAudio.SetEntityStatus(pCrane->m_nAudioEntity, 1);
pCrane->m_bIsTop = (MODELID_CRANE_1 != pEntity->GetModelIndex()); pCrane->m_bIsTop = (MODELID_CRANE_1 != pEntity->GetModelIndex());
// W T F ? ? ?
// Is this used to avoid military crane? // Is this used to avoid military crane?
if (pCrane->m_bIsTop || pEntity->GetPosition().y > 0.0f) { if (pCrane->m_bIsTop || pEntity->GetPosition().y > 0.0f) {
CObject* pMagnet = new CObject(MI_MAGNET, false); CObject* pHook = new CObject(MI_MAGNET, false);
pMagnet->ObjectCreatedBy = MISSION_OBJECT; pHook->ObjectCreatedBy = MISSION_OBJECT;
pMagnet->bUsesCollision = false; pHook->bUsesCollision = false;
pMagnet->bExplosionProof = true; pHook->bExplosionProof = true;
pMagnet->bAffectedByGravity = false; pHook->bAffectedByGravity = false;
pCrane->m_pMagnet = pMagnet; pCrane->m_pHook = pHook;
pCrane->CalcHookCoordinates(&pCrane->m_vecHookCurPos.x, &pCrane->m_vecHookCurPos.y, &pCrane->m_vecHookCurPos.z); pCrane->CalcHookCoordinates(&pCrane->m_vecHookCurPos.x, &pCrane->m_vecHookCurPos.y, &pCrane->m_vecHookCurPos.z);
pCrane->SetHookMatrix(); pCrane->SetHookMatrix();
} }
else else
pCrane->m_pMagnet = nil; pCrane->m_pHook = nil;
NumCranes++; NumCranes++;
} }
@ -88,7 +107,7 @@ void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY,
} }
int index = 0; int index = 0;
for (int i = 0; i < NumCranes; i++) { 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) { if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
fMinDistance = distance; fMinDistance = distance;
index = i; index = i;
@ -98,7 +117,7 @@ void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY,
if (fMinDistance == 99999.9f) if (fMinDistance == 99999.9f)
return; return;
#endif #endif
CCrane* pCrane = &aCranes[NumCranes]; CCrane* pCrane = &aCranes[index];
pCrane->m_fPickupX1 = fInfX; pCrane->m_fPickupX1 = fInfX;
pCrane->m_fPickupX2 = fSupX; pCrane->m_fPickupX2 = fSupX;
pCrane->m_fPickupY1 = fInfY; 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.x = fDropOffX;
pCrane->m_vecDropoffTarget.y = fDropOffY; pCrane->m_vecDropoffTarget.y = fDropOffY;
pCrane->m_vecDropoffTarget.z = fDropOffZ; pCrane->m_vecDropoffTarget.z = fDropOffZ;
pCrane->m_bCraneStatus = CCrane::ACTIVATED; pCrane->m_nCraneStatus = CCrane::ACTIVATED;
pCrane->m_pVehiclePickedUp = nil; pCrane->m_pVehiclePickedUp = nil;
pCrane->m_bVehiclesCollected = 0; pCrane->m_nVehiclesCollected = 0;
pCrane->m_fDropoffHeading = fHeading;
pCrane->m_bIsCrusher = bIsCrusher; pCrane->m_bIsCrusher = bIsCrusher;
pCrane->m_bIsMilitaryCrane = bIsMilitary; pCrane->m_bIsMilitaryCrane = bIsMilitary;
bool military = true; bool military = true;
if (!bIsMilitary && !pCrane->m_bWasMilitaryCrane) if (!bIsMilitary && !pCrane->m_bWasMilitaryCrane)
military = false; military = false;
pCrane->m_bWasMilitaryCrane = military; pCrane->m_bWasMilitaryCrane = military;
pCrane->m_nUpdateTimer = 0; pCrane->m_nTimeForNextCheck = 0;
pCrane->m_bCraneState = CCrane::IDLE; pCrane->m_nCraneState = CCrane::IDLE;
float Z; float Z;
if (bIsCrusher) if (bIsCrusher)
Z = CRUSHER_Z; Z = CRUSHER_Z;
else if (bIsMilitary) else if (bIsMilitary)
Z = MILITARY_Z; Z = MILITARY_Z;
else else
Z = CWorld::FindGroundZForCoord((fInfX + fSupY) / 2, (fInfY + fSupY) / 2); Z = CWorld::FindGroundZForCoord((fInfX + fSupX) / 2, (fInfY + fSupY) / 2);
pCrane->FindParametersForTarget((fInfX + fSupY) / 2, (fInfY + fSupY) / 2, Z, &pCrane->m_fPickupAngle, &pCrane->m_fPickupDistance, &pCrane->m_fAngle); 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_fDistance); pCrane->FindParametersForTarget(fDropOffX, fDropOffY, fDropOffZ, &pCrane->m_fDropoffAngle, &pCrane->m_fDropoffDistance, &pCrane->m_fDropoffHeight);
} }
void CCranes::DeActivateCrane(float X, float Y) void CCranes::DeActivateCrane(float X, float Y)
@ -133,7 +153,7 @@ void CCranes::DeActivateCrane(float X, float Y)
float fMinDistance = 99999.9f; float fMinDistance = 99999.9f;
int index = 0; int index = 0;
for (int i = 0; i < NumCranes; i++) { 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) { if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
fMinDistance = distance; fMinDistance = distance;
index = i; index = i;
@ -143,8 +163,8 @@ void CCranes::DeActivateCrane(float X, float Y)
if (fMinDistance == 99999.9f) if (fMinDistance == 99999.9f)
return; return;
#endif #endif
aCranes[index].m_bCraneStatus = CCrane::DEACTIVATED; aCranes[index].m_nCraneStatus = CCrane::DEACTIVATED;
aCranes[index].m_bCraneState = CCrane::IDLE; aCranes[index].m_nCraneState = CCrane::IDLE;
} }
bool CCranes::IsThisCarPickedUp(float X, float Y, CVehicle* pVehicle) 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; int index = 0;
bool result = false; bool result = false;
for (int i = 0; i < NumCranes; i++) { 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 (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; result = true;
} }
} }
@ -165,10 +185,10 @@ void CCranes::UpdateCranes(void)
{ {
for (int i = 0; i < NumCranes; i++) { for (int i = 0; i < NumCranes; i++) {
if (aCranes[i].m_bIsTop || aCranes[i].m_bIsCrusher || 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_pCraneEntity->GetPosition().x &&
TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pObject->GetPosition().x && TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().x &&
TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pObject->GetPosition().y && TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().y &&
TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pObject->GetPosition().y)) TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().y))
aCranes[i].Update(); aCranes[i].Update();
} }
} }
@ -177,13 +197,14 @@ void CCrane::Update(void)
{ {
if (CReplay::IsPlayingBack()) if (CReplay::IsPlayingBack())
return; return;
if ((m_bCraneStatus == ACTIVATED || m_bCraneStatus == DEACTIVATED) && if (((m_nCraneStatus == ACTIVATED || m_nCraneStatus == DEACTIVATED) &&
Abs(TheCamera.GetGameCamPosition().x - m_pObject->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS && Abs(TheCamera.GetGameCamPosition().x - m_pCraneEntity->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS &&
Abs(TheCamera.GetGameCamPosition().y - m_pObject->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) { Abs(TheCamera.GetGameCamPosition().y - m_pCraneEntity->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) ||
switch (m_bCraneState) { m_nCraneState != IDLE) {
switch (m_nCraneState) {
case IDLE: case IDLE:
if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, 4.0f + m_fAngle + m_bIsCrusher ? 4.5f : 0.0f, 1.0f) && if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, GetHeightToPickup()) &&
CTimer::GetTimeInMilliseconds() > m_nUpdateTimer) { CTimer::GetTimeInMilliseconds() > m_nTimeForNextCheck) {
CWorld::AdvanceCurrentScanCode(); CWorld::AdvanceCurrentScanCode();
#ifdef FIX_BUGS #ifdef FIX_BUGS
int xstart = max(0, CWorld::GetSectorIndexX(m_fPickupX1)); int xstart = max(0, CWorld::GetSectorIndexX(m_fPickupX1));
@ -207,33 +228,444 @@ void CCrane::Update(void)
} }
break; break;
case GOING_TOWARDS_TARGET: case GOING_TOWARDS_TARGET:
if (!m_pVehiclePickedUp) { if (m_pVehiclePickedUp){
m_bCraneState = IDLE;
break;
}
if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 || if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 ||
m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 || m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 ||
m_pVehiclePickedUp->GetPosition().y > m_fPickupY1 || m_pVehiclePickedUp->GetPosition().y < m_fPickupY1 ||
m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 || m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 ||
m_pVehiclePickedUp->pDriver || m_pVehiclePickedUp->pDriver ||
Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > 0.01f || Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > CAR_MOVING_SPEED_THRESHOLD ||
Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > 0.01f || Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > CAR_MOVING_SPEED_THRESHOLD ||
Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > 0.01f || Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > CAR_MOVING_SPEED_THRESHOLD ||
FindPlayerPed()->GetPedState() == PED_ENTER_CAR && FindPlayerPed()->GetPedState() == PED_ENTER_CAR && // TODO: fix carjack bug
FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) { FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) {
m_pVehiclePickedUp = nil; m_pVehiclePickedUp = nil;
m_bCraneState = IDLE; 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);
}
}
}
}
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_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; 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;
} }
} }
} }
WRAPPER bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle*) { EAXJMP(0x5451E0); } bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
WRAPPER bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle*) { EAXJMP(0x545190); } {
WRAPPER bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane() { EAXJMP(0x544BE0); } 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;
}
WRAPPER void CCranes::Save(uint8*, uint32*) { EAXJMP(0x545210); } void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
WRAPPER void CranesLoad(uint8*, uint32) { EAXJMP(0x5454d0); } {
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;
}
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);
}
STARTPATCHES
InjectHook(0x5454D0, CranesLoad, PATCH_JUMP); // GenericLoad
ENDPATCHES

View File

@ -6,6 +6,7 @@
class CVehicle; class CVehicle;
class CEntity; class CEntity;
class CObject; class CObject;
class CBuilding;
class CCrane class CCrane
{ {
@ -14,7 +15,7 @@ public:
IDLE = 0, IDLE = 0,
GOING_TOWARDS_TARGET = 1, GOING_TOWARDS_TARGET = 1,
LIFTING_TARGET = 2, LIFTING_TARGET = 2,
GOING_TOWARDS_HEIGHT_TARGET = 3, GOING_TOWARDS_TARGET_ONLY_HEIGHT = 3,
ROTATING_TARGET = 4, ROTATING_TARGET = 4,
DROPPING_TARGET = 5 DROPPING_TARGET = 5
}; };
@ -23,8 +24,8 @@ public:
ACTIVATED = 1, ACTIVATED = 1,
DEACTIVATED = 2 DEACTIVATED = 2
}; };
CEntity *m_pObject; CBuilding *m_pCraneEntity;
CObject *m_pMagnet; CObject *m_pHook;
int32 m_nAudioEntity; int32 m_nAudioEntity;
float m_fPickupX1; float m_fPickupX1;
float m_fPickupX2; float m_fPickupX2;
@ -36,20 +37,19 @@ public:
float m_fDropoffAngle; float m_fDropoffAngle;
float m_fPickupDistance; float m_fPickupDistance;
float m_fDropoffDistance; float m_fDropoffDistance;
float m_fAngle; float m_fPickupHeight;
float m_fDistance; float m_fDropoffHeight;
float m_fHeight; float m_fHookAngle;
float m_fHookOffset; float m_fHookOffset;
float m_fHookHeight; float m_fHookHeight;
CVector m_vecHookInitPos; CVector m_vecHookInitPos;
CVector m_vecHookCurPos; CVector m_vecHookCurPos;
float m_fHookVelocityX; CVector2D m_vecHookVelocity;
float m_fHookVelocityY;
CVehicle *m_pVehiclePickedUp; CVehicle *m_pVehiclePickedUp;
uint32 m_nUpdateTimer; uint32 m_nTimeForNextCheck;
CraneStatus m_bCraneStatus; CraneStatus m_nCraneStatus;
CraneState m_bCraneState; CraneState m_nCraneState;
uint8 m_bVehiclesCollected; uint8 m_nVehiclesCollected;
bool m_bIsCrusher; bool m_bIsCrusher;
bool m_bIsMilitaryCrane; bool m_bIsMilitaryCrane;
bool m_bWasMilitaryCrane; bool m_bWasMilitaryCrane;
@ -57,14 +57,19 @@ public:
void Init(void) { memset(this, 0, sizeof(*this)); } void Init(void) { memset(this, 0, sizeof(*this)); }
void Update(void); void Update(void);
bool RotateCarriedCarProperly(); bool RotateCarriedCarProperly(void);
void FindCarInSectorList(CPtrList*); void FindCarInSectorList(CPtrList* pList);
bool DoesCranePickUpThisCarType(uint32); bool DoesCranePickUpThisCarType(uint32 mi);
bool GoTowardsTarget(float, float, float, float); bool GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier = 1.0f);
bool GoTowardsHeightTarget(float, float); bool GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier = 1.0f);
void FindParametersForTarget(float, float, float, float*, float*, float*); void FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight);
void CalcHookCoordinates(float*, float*, float*); void CalcHookCoordinates(float* pX, float* pY, float* pZ);
void SetHookMatrix(); void SetHookMatrix(void);
float GetHeightToPickup() { return 4.0f + m_fPickupHeight + (m_bIsCrusher ? 4.5f : 0.0f); };
float GetHeightToDropoff() { return m_bIsCrusher ? (2.0f + m_fDropoffHeight + 3.0f) : (2.0f + m_fDropoffHeight); }
float GetHeightToPickupHeight() { return m_fPickupHeight + (m_bIsCrusher ? 7.0f : 4.0f); }
float GetHeightToDropoffHeight() { return m_fDropoffHeight + (m_bIsCrusher ? 7.0f : 2.0f); }
}; };
static_assert(sizeof(CCrane) == 128, "CCrane: error"); static_assert(sizeof(CCrane) == 128, "CCrane: error");
@ -73,19 +78,19 @@ class CCranes
{ {
public: public:
static void InitCranes(void); static void InitCranes(void);
static void AddThisOneCrane(CEntity*); static void AddThisOneCrane(CEntity* pCraneEntity);
static void ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float); static void ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY, float fDropOffX, float fDropOffY, float fDropOffZ, float fHeading, bool bIsCrusher, bool bIsMilitary, float fPosX, float fPosY);
static void DeActivateCrane(float, float); static void DeActivateCrane(float fX, float fY);
static bool IsThisCarPickedUp(float, float, CVehicle*); static bool IsThisCarPickedUp(float fX, float fY, CVehicle* pVehicle);
static void UpdateCranes(void); static void UpdateCranes(void);
static bool DoesMilitaryCraneHaveThisOneAlready(uint32); static bool DoesMilitaryCraneHaveThisOneAlready(uint32 mi);
static void RegisterCarForMilitaryCrane(uint32); static void RegisterCarForMilitaryCrane(uint32 mi);
static bool HaveAllCarsBeenCollectedByMilitaryCrane(); static bool HaveAllCarsBeenCollectedByMilitaryCrane(void);
static bool IsThisCarBeingCarriedByAnyCrane(CVehicle*); static bool IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle);
static bool IsThisCarBeingTargettedByAnyCrane(CVehicle*); static bool IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle);
static void Save(uint8*, uint32*); static void Save(uint8* buf, uint32* size);
static int32& CarsCollectedMilitaryCrane; static uint32& CarsCollectedMilitaryCrane;
static int32& NumCranes; static int32& NumCranes;
static CCrane(&aCranes)[NUM_CRANES]; static CCrane(&aCranes)[NUM_CRANES];
}; };

View File

@ -126,7 +126,6 @@ uint32& CGarages::MessageEndTime = *(uint32*)0x8F597C;
uint32& CGarages::NumGarages = *(uint32*)0x8F29F4; uint32& CGarages::NumGarages = *(uint32*)0x8F29F4;
bool& CGarages::PlayerInGarage = *(bool*)0x95CD83; bool& CGarages::PlayerInGarage = *(bool*)0x95CD83;
int32& CGarages::PoliceCarsCollected = *(int32*)0x941444; 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::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::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; 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) if (m_bDeactivated && m_eGarageState == GS_FULLYCLOSED)
@ -408,11 +410,11 @@ void CGarage::Update()
if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) { if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) {
uint8 colour1, colour2; uint8 colour1, colour2;
uint16 attempt; uint16 attempt;
((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2); FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
for (attempt = 0; attempt < 10; attempt++) { for (attempt = 0; attempt < 10; attempt++) {
if (colour1 != FindPlayerVehicle()->m_currentColour1 || colour2 != FindPlayerVehicle()->m_currentColour2) if (colour1 != FindPlayerVehicle()->m_currentColour1 || colour2 != FindPlayerVehicle()->m_currentColour2)
break; break;
((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2); FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
} }
bChangedColour = (attempt < 10); bChangedColour = (attempt < 10);
FindPlayerVehicle()->m_currentColour1 = colour1; FindPlayerVehicle()->m_currentColour1 = colour1;
@ -490,7 +492,7 @@ void CGarage::Update()
break; break;
} }
if (!CGarages::BombsAreFree && CWorld::Players[CWorld::PlayerInFocus].m_nMoney < BOMB_PRICE) { 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; m_eGarageState = GS_OPENEDCONTAINSCAR;
DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1); DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1);
break; break;
@ -1184,7 +1186,7 @@ bool CGarage::IsEntityEntirelyInside(CEntity * pEntity)
if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 || if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 ||
pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2) pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2)
return false; return false;
CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(); CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; 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().y < m_fY1 - fMargin || pEntity->GetPosition().y > m_fY2 + fMargin ||
pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin) pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin)
return false; return false;
CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(); CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; 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 && 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) pEntity->GetPosition().y > m_fY1 - fMargin && pEntity->GetPosition().y < m_fY2 + fMargin)
return false; return false;
CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(); CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; 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().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 ||
pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2) pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2)
return false; return false;
CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(); CColModel* pColModel = pEntity->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
radius = pColModel->spheres[i].radius; radius = pColModel->spheres[i].radius;
@ -1264,7 +1266,7 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity)
bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin) 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++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center; CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; float radius = pColModel->spheres[i].radius;
@ -1285,7 +1287,7 @@ bool CGarage::IsAnyOtherCarTouchingGarage(CVehicle * pException)
continue; continue;
if (!IsEntityTouching3D(pVehicle)) if (!IsEntityTouching3D(pVehicle))
continue; continue;
CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel(); CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; float radius = pColModel->spheres[i].radius;
@ -1307,7 +1309,7 @@ bool CGarage::IsAnyOtherPedTouchingGarage(CPed * pException)
continue; continue;
if (!IsEntityTouching3D(pPed)) if (!IsEntityTouching3D(pPed))
continue; continue;
CColModel* pColModel = CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetColModel(); CColModel* pColModel = pException->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center; CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; float radius = pColModel->spheres[i].radius;
@ -1329,7 +1331,7 @@ bool CGarage::IsAnyCarBlockingDoor()
continue; continue;
if (!IsEntityTouching3D(pVehicle)) if (!IsEntityTouching3D(pVehicle))
continue; continue;
CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel(); CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; float radius = pColModel->spheres[i].radius;
@ -1698,8 +1700,8 @@ float CGarage::CalcSmallestDistToGarageDoorSquared(float X, float Y)
void CGarage::FindDoorsEntities() void CGarage::FindDoorsEntities()
{ {
m_pDoor1 = false; m_pDoor1 = nil;
m_pDoor2 = false; m_pDoor2 = nil;
int xstart = max(0, CWorld::GetSectorIndexX(m_fX1)); int xstart = max(0, CWorld::GetSectorIndexX(m_fX1));
int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2)); int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2));
int ystart = max(0, CWorld::GetSectorIndexY(m_fY1)); int ystart = max(0, CWorld::GetSectorIndexY(m_fY1));
@ -1992,7 +1994,7 @@ void CGarage::TidyUpGarageClose()
continue; continue;
bool bRemove = false; bool bRemove = false;
if (m_eGarageState != GS_FULLYCLOSED) { if (m_eGarageState != GS_FULLYCLOSED) {
CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel(); CColModel* pColModel = pVehicle->GetColModel();
for (int i = 0; i < pColModel->numSpheres; i++) { for (int i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center; CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
float radius = pColModel->spheres[i].radius; float radius = pColModel->spheres[i].radius;
@ -2227,6 +2229,7 @@ void CGarages::SetAllDoorsBackToOriginalHeight()
void CGarages::Save(uint8 * buf, uint32 * size) void CGarages::Save(uint8 * buf, uint32 * size)
{ {
#ifdef FIX_GARAGE_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)); *size = (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
#else #else
* size = 5484; * size = 5484;
@ -2248,6 +2251,9 @@ void CGarages::Save(uint8 * buf, uint32 * size)
} }
for (int i = 0; i < NUM_GARAGES; i++) for (int i = 0; i < NUM_GARAGES; i++)
WriteSaveBuf(buf, aGarages[i]); WriteSaveBuf(buf, aGarages[i]);
#ifdef FIX_GARAGE_SIZE
VALIDATESAVEBUF(*size);
#endif
} }
CStoredCar::CStoredCar(const CStoredCar & other) CStoredCar::CStoredCar(const CStoredCar & other)
@ -2271,6 +2277,7 @@ CStoredCar::CStoredCar(const CStoredCar & other)
void CGarages::Load(uint8* buf, uint32 size) void CGarages::Load(uint8* buf, uint32 size)
{ {
#ifdef FIX_GARAGE_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)); assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
#else #else
assert(size == 5484); assert(size == 5484);
@ -2303,6 +2310,9 @@ void CGarages::Load(uint8* buf, uint32 size)
else else
aGarages[i].UpdateDoorsHeight(); aGarages[i].UpdateDoorsHeight();
} }
#ifdef FIX_GARAGE_SIZE
VALIDATESAVEBUF(size);
#endif
} }
bool bool
@ -2345,7 +2355,6 @@ CGarages::IsModelIndexADoor(uint32 id)
STARTPATCHES STARTPATCHES
InjectHook(0x426B20, CGarages::TriggerMessage, PATCH_JUMP); // CCrane::Update, CCrane::FindCarInSectorList
InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl
InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl
InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad

View File

@ -192,7 +192,6 @@ class CGarages
static uint32 &NumGarages; static uint32 &NumGarages;
static bool &PlayerInGarage; static bool &PlayerInGarage;
static int32 &PoliceCarsCollected; static int32 &PoliceCarsCollected;
static uint32 &GarageToBeTidied;
static CGarage(&aGarages)[NUM_GARAGES]; static CGarage(&aGarages)[NUM_GARAGES];
static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS]; static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS];
static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS]; static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS];

View File

@ -2229,6 +2229,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command)
if (pos.z <= -100) if (pos.z <= -100)
pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3])); UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3]));
return 0;
} }
case COMMAND_DEBUG_ON: case COMMAND_DEBUG_ON:
CTheScripts::DbgFlag = true; CTheScripts::DbgFlag = true;
@ -7657,13 +7658,13 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
assert(pObject); assert(pObject);
if (ScriptParams[1]) { if (ScriptParams[1]) {
if (pObject->bIsStatic) { if (pObject->bIsStatic) {
pObject->bIsStatic = true; pObject->bIsStatic = false;
pObject->AddToMovingList(); pObject->AddToMovingList();
} }
} }
else { else {
if (!pObject->bIsStatic) { if (!pObject->bIsStatic) {
pObject->bIsStatic = false; pObject->bIsStatic = true;
pObject->RemoveFromMovingList(); pObject->RemoveFromMovingList();
} }
} }
@ -11037,6 +11038,7 @@ void CRunningScript::DoDeatharrestCheck()
int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact]; int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact];
if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) { if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) {
messageId += CTheScripts::BaseBriefIdForContact[contact]; messageId += CTheScripts::BaseBriefIdForContact[contact];
found = true;
} }
} }
if (!found) if (!found)
@ -11331,6 +11333,7 @@ INITSAVEBUF
break; break;
case 4: case 4:
InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1); InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1);
break;
default: default:
assert(false); assert(false);
} }

View File

@ -17,7 +17,7 @@ class CRunningScript;
struct CScriptRectangle struct CScriptRectangle
{ {
int8 m_bIsUsed; bool m_bIsUsed;
bool m_bBeforeFade; bool m_bBeforeFade;
int16 m_nTextureId; int16 m_nTextureId;
CRect m_sRect; CRect m_sRect;