Merge pull request #1 from GTAmodding/miami

Miami
This commit is contained in:
Fire_Head
2020-07-29 12:20:02 +03:00
committed by GitHub
267 changed files with 23832 additions and 29992 deletions

View File

@ -1349,7 +1349,7 @@ CAutomobile::ProcessControl(void)
if(!IsAlarmOn())
ReduceHornCounter();
}else{
if(UsesSiren(GetModelIndex())){
if(UsesSiren()){
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
@ -1559,7 +1559,7 @@ CAutomobile::ProcessControl(void)
if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 &&
UsesSiren(GetModelIndex()) && GetModelIndex() != MI_MRWHOOP)
UsesSiren() && GetModelIndex() != MI_MRWHOOP)
CCarAI::MakeWayForCarWithSiren(this);
@ -2527,7 +2527,7 @@ CAutomobile::PreRender(void)
if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
radius = 3.0f;
if(GetPosition().z - groundZ < radius)
HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, ceilf(rnd));
HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, Ceil(rnd));
}
CMatrix mat;
@ -3800,7 +3800,7 @@ void
CAutomobile::DoDriveByShootings(void)
{
CAnimBlendAssociation *anim = nil;
CPlayerInfo* playerInfo = ((CPlayerPed*)this)->GetPlayerInfoForThisPlayerPed();
CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
if (playerInfo && !playerInfo->m_bDriveByAllowed)
return;

View File

@ -1989,7 +1989,7 @@ void
CBike::DoDriveByShootings(void)
{
CAnimBlendAssociation *anim;
CPlayerInfo* playerInfo = ((CPlayerPed*)this)->GetPlayerInfoForThisPlayerPed();
CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
if (playerInfo && !playerInfo->m_bDriveByAllowed)
return;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
#pragma once
#include "Vehicle.h"
#include "Door.h"
enum eBoatNodes
{
@ -10,33 +11,34 @@ enum eBoatNodes
BOAT_FLAP_LEFT,
BOAT_FLAP_RIGHT,
BOAT_REARFLAP_LEFT,
BOAT_REARFLAP_RIGHT
BOAT_REARFLAP_RIGHT,
NUM_BOAT_NODES
};
class CBoat : public CVehicle
{
public:
// 0x288
float m_fPropellerZ;
float m_fPropellerY;
CVector m_waterMoveDrag;
CVector m_waterTurnDrag;
float m_fMovingHiRotation;
int32 _unk0;
RwFrame *m_aBoatNodes[4];
float m_fMovingRotation;
float m_fMovingSpeed;
int32 m_boat_unused1;
RwFrame *m_aBoatNodes[NUM_BOAT_NODES];
CDoor m_boom;
tBoatHandlingData *pBoatHandling;
uint8 bBoatInWater : 1;
uint8 bPropellerInWater : 1;
bool m_bIsAnchored;
float m_fOrientation;
int32 _unk1;
uint32 m_nPoliceShoutTimer;
int32 m_boat_unused2;
float m_fDamage;
CEntity *m_pSetOnFireEntity;
bool _unk2;
float m_skimmerThingTimer;
bool m_boat_unused3;
float m_fAccelerate;
float m_fBrake;
float m_fSteeringLeftRight;
uint8 m_nPadID;
int32 _unk3;
int32 m_boat_unused4;
float m_fVolumeUnderWater;
CVector m_vecBuoyancePoint;
float m_fPrevVolumeUnderWater;
@ -54,7 +56,7 @@ public:
virtual void SetModelIndex(uint32 id);
virtual void ProcessControl();
virtual void Teleport(CVector v);
virtual void PreRender(void) {};
virtual void PreRender(void);
virtual void Render(void);
virtual void ProcessControlInputs(uint8);
virtual void GetComponentWorldPosition(int32 component, CVector &pos);

View File

@ -16,6 +16,7 @@
#include "VisibilityPlugins.h"
#include "World.h"
#include "Zones.h"
#include "Occlusion.h"
uint8 CTheCarGenerators::ProcessCounter;
uint32 CTheCarGenerators::NumOfCarGenerators;
@ -31,7 +32,7 @@ void CCarGenerator::SwitchOff()
void CCarGenerator::SwitchOn()
{
m_nUsesRemaining = -1;
m_nUsesRemaining = 255;
m_nTimer = CalcNextGen();
++CTheCarGenerators::CurrentActiveCount;
}
@ -140,8 +141,14 @@ void CCarGenerator::DoInternalProcessing()
}
CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0);
m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pVehicle);
if (m_nUsesRemaining < -1) /* I don't think this is a correct comparasion */
/* I don't think this is a correct comparasion */
#ifdef FIX_BUGS
if (m_nUsesRemaining != 0)
--m_nUsesRemaining;
#else
if (m_nUsesRemaining < -1)
--m_nUsesRemaining;
#endif
m_nTimer = CalcNextGen();
if (m_nUsesRemaining == 0)
--CTheCarGenerators::CurrentActiveCount;
@ -151,7 +158,7 @@ void CCarGenerator::Process()
{
if (m_nVehicleHandle == -1 &&
(CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter || CTimer::GetTimeInMilliseconds() >= m_nTimer) &&
m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayer())
m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayers())
DoInternalProcessing();
if (m_nVehicleHandle == -1)
return;
@ -203,14 +210,14 @@ bool CCarGenerator::CheckForBlockage(int32 mi)
return false;
}
bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
bool CCarGenerator::CheckIfWithinRangeOfAnyPlayers()
{
CVector2D direction = FindPlayerCentreOfWorld(CWorld::PlayerInFocus) - m_vecPos;
float distance = direction.Magnitude();
float farclip = 110.0f * TheCamera.GenerationDistMultiplier;
float nearclip = farclip - 20.0f;
bool canBeRemoved = (m_nModelIndex > 0 && CModelInfo::IsBoatModel(m_nModelIndex) && 165.0f * TheCamera.GenerationDistMultiplier > distance &&
TheCamera.IsSphereVisible(m_vecPos, 0.0f)); // TODO(MIAMI) COcclision::IsPositionOccluded(m_vecPos, 0.0f)
TheCamera.IsSphereVisible(m_vecPos, 0.0f) && COcclusion::IsPositionOccluded(m_vecPos, 0.0f));
if (distance >= farclip || canBeRemoved){
if (m_bIsBlocking)
m_bIsBlocking = false;

View File

@ -30,7 +30,7 @@ public:
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(int32 mi);
bool CheckIfWithinRangeOfAnyPlayer();
bool CheckIfWithinRangeOfAnyPlayers();
void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
};

View File

@ -460,7 +460,7 @@ bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
return mi == MI_FIRETRUCK ||
mi == MI_AMBULAN ||
mi == MI_ENFORCER ||
mi == MI_FBICAR ||
mi == MI_FBIRANCH ||
mi == MI_RHINO ||
mi == MI_BARRACKS ||
mi == MI_POLICE;
@ -474,7 +474,7 @@ bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
case MI_FIRETRUCK: return (CarsCollectedMilitaryCrane & 1);
case MI_AMBULAN: return (CarsCollectedMilitaryCrane & 2);
case MI_ENFORCER: return (CarsCollectedMilitaryCrane & 4);
case MI_FBICAR: return (CarsCollectedMilitaryCrane & 8);
case MI_FBIRANCH: return (CarsCollectedMilitaryCrane & 8);
case MI_RHINO: return (CarsCollectedMilitaryCrane & 0x10);
case MI_BARRACKS: return (CarsCollectedMilitaryCrane & 0x20);
case MI_POLICE: return (CarsCollectedMilitaryCrane & 0x40);
@ -489,7 +489,7 @@ void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
case MI_FIRETRUCK: CarsCollectedMilitaryCrane |= 1; break;
case MI_AMBULAN: CarsCollectedMilitaryCrane |= 2; break;
case MI_ENFORCER: CarsCollectedMilitaryCrane |= 4; break;
case MI_FBICAR: CarsCollectedMilitaryCrane |= 8; break;
case MI_FBIRANCH: CarsCollectedMilitaryCrane |= 8; break;
case MI_RHINO: CarsCollectedMilitaryCrane |= 0x10; break;
case MI_BARRACKS: CarsCollectedMilitaryCrane |= 0x20; break;
case MI_POLICE: CarsCollectedMilitaryCrane |= 0x40; break;

View File

@ -7,18 +7,40 @@
#include "Vehicle.h"
#include "Floater.h"
//--MIAMI: done
cBuoyancy mod_Buoyancy;
static float fVolMultiplier = 1.0f;
float fVolMultiplier = 1.0f;
// amount of boat volume in bounding box
// 1.0-volume is the empty space in the bbox
static float fBoatVolumeDistribution[9] = {
float fBoatVolumeDistribution[9] = {
// rear
0.75f, 0.9f, 0.75f,
0.95f, 1.0f, 0.95f,
0.3f, 0.7f, 0.3f
0.4f, 0.7f, 0.4f
// bow
};
float fBoatVolumeDistributionCat[9] = {
0.9f, 0.3f, 0.9f,
1.0f, 0.5f, 1.0f,
0.95f, 0.4f, 0.95f
};
float fBoatVolumeDistributionSail[9] = {
0.55f, 0.95f, 0.55f,
0.75f, 1.1f, 0.75f,
0.3f, 0.8f, 0.3f
};
float fBoatVolumeDistributionDinghy[9] = {
0.65f, 0.85f, 0.65f,
0.85f, 1.1f, 0.85f,
0.65f, 0.95f, 0.65f
};
float fBoatVolumeDistributionSpeed[9] = {
0.7f, 0.9f, 0.7f,
0.95f, 1.0f, 0.95f,
0.6f, 0.7f, 0.6f
};
bool
cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse)
@ -37,6 +59,76 @@ cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVec
return f != 0.0f;
}
bool
cBuoyancy::ProcessBuoyancyBoat(CVehicle *veh, float buoyancy, CVector *point, CVector *impulse, bool bNoTurnForce)
{
m_numSteps = 2.0f;
if(!CWaterLevel::GetWaterLevel(veh->GetPosition(), &m_waterlevel, veh->bTouchingWater))
return false;
m_matrix = veh->GetMatrix();
PreCalcSetup(veh, buoyancy);
float x, y;
int ix, i;
tWaterLevel waterPosition;
CVector waterNormal;
// Floater is divided into 3x3 parts. Process and sum each of them
float volDiv = 1.0f/((m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f));
ix = 0;
for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
i = ix;
for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
CVector waterLevel(x, y, 0.0f);
FindWaterLevelNorm(m_positionZ, &waterLevel, &waterPosition, &waterNormal);
switch(veh->GetModelIndex()){
case MI_RIO:
fVolMultiplier = fBoatVolumeDistributionCat[i];
break;
case MI_SQUALO:
case MI_SPEEDER:
case MI_JETMAX:
fVolMultiplier = fBoatVolumeDistributionSpeed[i];
break;
case MI_COASTG:
case MI_DINGHY:
fVolMultiplier = fBoatVolumeDistributionDinghy[i];
break;
case MI_MARQUIS:
fVolMultiplier = fBoatVolumeDistributionSail[i];
break;
case MI_PREDATOR:
case MI_SKIMMER:
case MI_REEFER:
case MI_TROPIC:
default:
fVolMultiplier = fBoatVolumeDistribution[i];
break;
}
if(waterPosition != FLOATER_ABOVE_WATER){
float volume = SimpleSumBuoyancyData(waterLevel, waterPosition);
float upImpulse = volume * volDiv * buoyancy * CTimer::GetTimeStep();
CVector speed = veh->GetSpeed(Multiply3x3(veh->GetMatrix(), CVector(x, y, 0.0f)));
float damp = 1.0f - DotProduct(speed, waterNormal)*veh->pHandling->fSuspensionDampingLevel;
float finalImpulse = upImpulse*Max(damp, 0.0f);
impulse->z += finalImpulse;
if(!bNoTurnForce)
veh->ApplyTurnForce(finalImpulse*waterNormal, Multiply3x3(m_matrix, waterLevel));
}
i += 3;
}
ix++;
}
m_volumeUnderWater *= volDiv;
*point = Multiply3x3(m_matrix, m_impulsePoint);
return m_isBoat || m_haveVolume;
}
void
cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
{
@ -48,17 +140,55 @@ cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
m_dimMax = colModel->boundingBox.max;
if(m_isBoat){
if(phys->GetModelIndex() == MI_PREDATOR){
switch(phys->GetModelIndex()){
case MI_PREDATOR:
default:
m_dimMax.y *= 1.05f;
m_dimMin.y *= 0.9f;
break;
case MI_SPEEDER:
m_dimMax.y *= 1.25f;
m_dimMin.y *= 0.83f;
break;
case MI_REEFER:
m_dimMin.y *= 0.9f;
break;
case MI_RIO:
m_dimMax.y *= 0.9f;
m_dimMin.y *= 0.9f;
}else if(phys->GetModelIndex() == MI_SPEEDER){
m_dimMax.z += 0.25f;
m_dimMin.z -= 0.2f;
break;
case MI_SQUALO:
m_dimMax.y *= 0.9f;
m_dimMin.y *= 0.9f;
break;
case MI_TROPIC:
m_dimMax.y *= 1.3f;
m_dimMin.y *= 0.82f;
m_dimMin.z -= 0.2f;
break;
case MI_SKIMMER:
m_dimMin.y = -m_dimMax.y;
m_dimMax.y *= 1.2f;
break;
case MI_COASTG:
m_dimMax.y *= 1.1f;
m_dimMin.y *= 0.9f;
}else if(phys->GetModelIndex() == MI_REEFER){
m_dimMin.z -= 0.3f;
break;
case MI_DINGHY:
m_dimMax.y *= 1.3f;
m_dimMin.y *= 0.9f;
}else{
m_dimMax.y *= 0.9f;
m_dimMin.z -= 0.2f;
break;
case MI_MARQUIS:
m_dimMax.y *= 1.3f;
m_dimMin.y *= 0.9f;
break;
case MI_JETMAX:
m_dimMin.y *= 0.9f;
break;
}
}
@ -92,22 +222,17 @@ void
cBuoyancy::SimpleCalcBuoyancy(void)
{
float x, y;
int ix, i;
tWaterLevel waterPosition;
// Floater is divided into 3x3 parts. Process and sum each of them
ix = 0;
for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
i = ix;
for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
CVector waterLevel(x, y, 0.0f);
FindWaterLevel(m_positionZ, &waterLevel, &waterPosition);
fVolMultiplier = m_isBoat ? fBoatVolumeDistribution[i] : 1.0f;
fVolMultiplier = 1.0f;
if(waterPosition != FLOATER_ABOVE_WATER)
SimpleSumBuoyancyData(waterLevel, waterPosition);
i += 3;
}
ix++;
}
m_volumeUnderWater /= (m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f);
@ -129,10 +254,6 @@ cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition)
if(m_isBoat){
fThisVolume *= fVolMultiplier;
if(fThisVolume < 0.5f)
fThisVolume = 2.0f*sq(fThisVolume);
if(fThisVolume < 1.0f)
fThisVolume = sq(fThisVolume);
fThisVolume = sq(fThisVolume);
}
@ -173,6 +294,26 @@ cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel
}
}
// Same as above but also get normal
void
cBuoyancy::FindWaterLevelNorm(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition, CVector *normal)
{
*waterPosition = FLOATER_IN_WATER;
CVector xWaterLevel = Multiply3x3(m_matrix, *waterLevel);
CWaterLevel::GetWaterLevel(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y, m_position.z,
&waterLevel->z, true);
waterLevel->z -= xWaterLevel.z + zpos.z; // make local
if(waterLevel->z >= m_dimMin.z)
*normal = CWaterLevel::GetWaterNormal(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y);
if(waterLevel->z > m_dimMax.z){
waterLevel->z = m_dimMax.z;
*waterPosition = FLOATER_UNDER_WATER;
}else if(waterLevel->z < m_dimMin.z){
waterLevel->z = m_dimMin.z;
*waterPosition = FLOATER_ABOVE_WATER;
}
}
bool
cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *point, CVector *impulse)
{

View File

@ -36,10 +36,12 @@ public:
CVector m_impulsePoint;
bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse);
bool ProcessBuoyancyBoat(CVehicle *phys, float buoyancy, CVector *point, CVector *impulse, bool bNoTurnForce);
void PreCalcSetup(CPhysical *phys, float buoyancy);
void SimpleCalcBuoyancy(void);
float SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition);
void FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition);
void FindWaterLevelNorm(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition, CVector *normal);
bool CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point);
};
extern cBuoyancy mod_Buoyancy;

View File

@ -14,20 +14,26 @@
#include "Shadows.h"
#include "Coronas.h"
#include "Explosion.h"
#include "WindModifiers.h"
#include "Timecycle.h"
#include "TempColModels.h"
#include "World.h"
#include "WaterLevel.h"
#include "Population.h"
#include "PlayerPed.h"
#include "CopPed.h"
#include "Wanted.h"
#include "DMAudio.h"
#include "Object.h"
#include "HandlingMgr.h"
#include "Ropes.h"
#include "Heli.h"
#ifdef FIX_BUGS
#include "Replay.h"
#endif
//--MIAMI: done
enum
{
HELI_STATUS_HOVER,
@ -40,7 +46,6 @@ enum
CHeli *CHeli::pHelis[NUM_HELIS];
int16 CHeli::NumRandomHelis;
uint32 CHeli::TestForNewRandomHelisTimer;
int16 CHeli::NumScriptHelis; // unused
bool CHeli::CatalinaHeliOn;
bool CHeli::CatalinaHasBeenShotDown;
bool CHeli::ScriptHeliOn;
@ -67,6 +72,9 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_nBulletDamage = 0;
m_fAngularSpeed = 0.0f;
m_fRotation = 0.0f;
m_numSwat = 4;
m_nSearchLightTimer = CTimer::GetTimeInMilliseconds();
for(i = 0; i < 6; i++){
m_aSearchLightHistoryX[i] = 0.0f;
@ -82,6 +90,8 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_fTargetOffset = 0.0f;
m_fSearchLightX = m_fSearchLightY = 0.0f;
m_aSwatState[0] = m_aSwatState[1] = m_aSwatState[2] = m_aSwatState[3] = 0;
// BUG: not in game but gets initialized to CDCDCDCD in debug
m_nLastShotTime = 0;
}
@ -120,6 +130,8 @@ CHeli::ProcessControl(void)
if(gbModelViewer)
return;
CWindModifiers::RegisterOne(GetPosition(), 1);
// Find target
CVector target(0.0f, 0.0f, 0.0f);
CVector2D vTargetDist;
@ -266,7 +278,9 @@ CHeli::ProcessControl(void)
if(fTargetDist > targetHeight)
m_heliStatus = HELI_STATUS_CHASE_PLAYER;
}
// fall through, BUG?
if(m_numSwat)
SendDownSwat();
break;
case HELI_STATUS_CHASE_PLAYER:{
float targetHeight;
if(m_heliType == HELI_TYPE_CATALINA)
@ -277,6 +291,7 @@ CHeli::ProcessControl(void)
fTargetDist < targetHeight && CWorld::GetIsLineOfSightClear(GetPosition(), FindPlayerCoors(), true, false, false, false, false, false))
m_heliStatus = HELI_STATUS_HOVER;
}
break;
}
// Find xy speed
@ -346,13 +361,6 @@ CHeli::ProcessControl(void)
if(m_fTargetOffset >= 2.0f)
m_fTargetOffset -= 2.0f;
if(m_heliType == HELI_TYPE_CATALINA)
if(m_pathState == 9 || m_pathState == 11 || m_pathState == 10){
float f = Pow(0.997f, CTimer::GetTimeStep());
m_vecMoveSpeed.x *= f;
m_vecMoveSpeed.y *= f;
}
CVector2D speedDir = targetSpeed - m_vecMoveSpeed;
float speedDiff = speedDir.Magnitude();
if(speedDiff != 0.0f)
@ -457,7 +465,7 @@ CHeli::ProcessControl(void)
else if (searchLightDist < 40.0f)
m_fSearchLightIntensity = 1.0f;
else
m_fSearchLightIntensity = 1.0f - (40.0f - searchLightDist) / 40.0f;
m_fSearchLightIntensity = 1.0f - (40.0f - searchLightDist) / (60.0f-40.0f);
if (m_fSearchLightIntensity < 0.9f || sq(FindPlayerCoors().x - m_fSearchLightX) + sq(FindPlayerCoors().y - m_fSearchLightY) > sq(7.0f))
m_nShootTimer = CTimer::GetTimeInMilliseconds();
@ -524,28 +532,17 @@ CHeli::ProcessControl(void)
}
}
// Drop Catalina's bombs
if(m_heliType == HELI_TYPE_CATALINA && m_pathState > 8 && (CTimer::GetTimeInMilliseconds()>>9) != (CTimer::GetPreviousTimeInMilliseconds()>>9)){
CVector bombPos = GetPosition() - 60.0f*m_vecMoveSpeed;
if(sq(FindPlayerCoors().x-bombPos.x) + sq(FindPlayerCoors().y-bombPos.y) < sq(35.0f)){
bool found;
float groundZ = CWorld::FindGroundZFor3DCoord(bombPos.x, bombPos.y, bombPos.z, &found);
float waterZ;
if(!CWaterLevel::GetWaterLevelNoWaves(bombPos.x, bombPos.y, bombPos.z, &waterZ))
waterZ = 0.0f;
if(groundZ > waterZ){
bombPos.z = groundZ + 2.0f;
CExplosion::AddExplosion(nil, this, EXPLOSION_HELI_BOMB, bombPos, 0);
}else{
bombPos.z = waterZ;
CVector dir;
for(i = 0; i < 16; i++){
dir.x = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
dir.y = ((CGeneral::GetRandomNumber()&0xFF)-127)*0.001f;
dir.z = 0.5f;
CParticle::AddParticle(PARTICLE_BOAT_SPLASH, bombPos, dir, nil, 0.2f);
}
}
// Process ropes
for(i = 0; i < 4; i++){
if(m_aSwatState[i] == 0)
continue;
m_aSwatState[i]--;
CRopes::RegisterRope((uintptr)this + i, GetMatrix()*FindSwatPositionRelativeToHeli(i), false);
if(m_aSwatState[i] == 0){
CVector speed = Multiply3x3(GetMatrix(), 0.05f*FindSwatPositionRelativeToHeli(i));
speed.z = 0.0f;
CRopes::SetSpeedOfTopNode((uintptr)this + i, speed);
}
}
@ -665,6 +662,7 @@ CHeli::SpawnFlyingComponent(int32 component)
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
obj->bDontStream = true;
// init object
obj->m_fMass = 10.0f;
@ -710,6 +708,42 @@ CHeli::SpawnFlyingComponent(int32 component)
return obj;
}
CVector
CHeli::FindSwatPositionRelativeToHeli(int n)
{
switch(n){
case 0: return CVector(-1.2f, -1.0f, -0.5f);
case 1: return CVector( 1.2f, -1.0f, -0.5f);
case 2: return CVector(-1.2f, 1.0f, -0.5f);
case 3: return CVector( 1.2f, 1.0f, -0.5f);
default: return CVector(0.0f, 0.0f, 0.0f);
}
}
bool
CHeli::SendDownSwat(void)
{
if(m_numSwat == 0 || !CStreaming::HasModelLoaded(MI_SWAT) ||
CGeneral::GetRandomNumber() & 0x7F || (GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
return false;
CMatrix mat(GetMatrix());
CVector pos = Multiply3x3(mat, FindSwatPositionRelativeToHeli(m_numSwat-1)) + GetPosition();
float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, nil);
if(Abs(FindPlayerCoors().z - groundZ) < 2.5f && CRopes::RegisterRope((uintptr)this + m_numSwat-1, pos, false)){
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_HELI_SWAT, pos);
swat->bUsesCollision = false;
swat->m_pRopeEntity = this;
RegisterReference(&swat->m_pRopeEntity);
m_numSwat--;
swat->m_nRopeID = (uintptr)this + m_numSwat;
m_aSwatState[m_numSwat] = 255;
CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
return true;
}
return false;
}
void
@ -719,7 +753,6 @@ CHeli::InitHelis(void)
NumRandomHelis = 0;
TestForNewRandomHelisTimer = 0;
NumScriptHelis = 0;
CatalinaHeliOn = false;
ScriptHeliOn = false;
for(i = 0; i < NUM_HELIS; i++)
@ -735,17 +768,20 @@ GenerateHeli(bool catalina)
CVector heliPos;
int i;
heli = new CHeli(MI_CHOPPER, PERMANENT_VEHICLE);
if(catalina)
assert(0 && "can't create catalina's heli");
else
heli = new CHeli(MI_CHOPPER, PERMANENT_VEHICLE);
if(catalina)
heliPos = CVector(-224.0f, 201.0f, 83.0f);
else{
heliPos = FindPlayerCoors();
float angle = (float)(CGeneral::GetRandomNumber() & 0xFF)/0xFF * 6.28f;
float angle = (float)(CGeneral::GetRandomNumber() & 0xFF)/0x100 * 6.28f;
heliPos.x += 250.0f*Sin(angle);
heliPos.y += 250.0f*Cos(angle);
if(heliPos.x < -2000.0f || heliPos.x > 2000.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
// directly above player
if(heliPos.x < -2000.0f-400.0f || heliPos.x > 2000.0f-400.0f || heliPos.y < -2000.0f || heliPos.y > 2000.0f){
heliPos = FindPlayerCoors();
heliPos.x -= 250.0f*Sin(angle);
heliPos.y -= 250.0f*Cos(angle);
}
@ -756,6 +792,7 @@ GenerateHeli(bool catalina)
heli->GetMatrix().SetRotateZOnly(DEGTORAD(270.0f)); // game actually uses 3.14 here
heli->SetStatus(STATUS_ABANDONED);
heli->bIsLocked = true;
int id = -1;
bool found = false;
@ -784,6 +821,8 @@ CHeli::UpdateHelis(void)
CReplay::IsPlayingBack() ? 0 :
#endif
FindPlayerPed()->m_pWanted->NumOfHelisRequired();
if(CCullZones::PlayerNoRain() || CGame::IsInInterior())
numHelisRequired = 0;
if(CStreaming::HasModelLoaded(MI_CHOPPER) && CTimer::GetTimeInMilliseconds() > TestForNewRandomHelisTimer){
// Spawn a police heli
TestForNewRandomHelisTimer = CTimer::GetTimeInMilliseconds() + 15000;
@ -832,7 +871,7 @@ CHeli::UpdateHelis(void)
TheCamera.CamShake(0.7f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
colors[0] = CRGBA(0, 0, 0, 255);
colors[1] = CRGBA(224, 230, 238, 255);
colors[1] = CRGBA(224, 224, 224, 255);
colors[2] = CRGBA(0, 0, 0, 255);
colors[3] = CRGBA(0, 0, 0, 255);
colors[4] = CRGBA(66, 162, 252, 255);
@ -852,7 +891,7 @@ CHeli::UpdateHelis(void)
int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, pos, dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
colors[nFrameGen], rotSpeed, 0, f, 0);
colors[nFrameGen&7], rotSpeed, 0, f, 0);
}
CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
@ -870,8 +909,7 @@ CHeli::UpdateHelis(void)
if(i == HELI_CATALINA)
CatalinaHasBeenShotDown = true;
CStats::HelisDestroyed++;
CStats::PeopleKilledByOthers += 2;
CStats::PeopleKilledByPlayer += 2;
CStats::PedsKilledOfThisType[PEDTYPE_COP] += 2;
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250;
pos = CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition();
@ -889,8 +927,8 @@ CHeli::UpdateHelis(void)
TheCamera.CamShake(0.4f, pHelis[i]->GetPosition().x, pHelis[i]->GetPosition().y, pHelis[i]->GetPosition().z);
CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetUp();
CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI, pos, 0);
CVector pos = pHelis[i]->GetPosition() - 2.5f*pHelis[i]->GetForward();
CExplosion::AddExplosion(nil, nil, EXPLOSION_HELI2, pos, 0);
}else
pHelis[i]->m_fAngularSpeed *= 1.03f;
}
@ -905,7 +943,7 @@ CHeli::UpdateHelis(void)
pHelis[i]->m_heliStatus = HELI_STATUS_FLY_AWAY;
}
// Remove all helis if in a tunnel
// Remove all helis if in a tunnel or under water
if(FindPlayerCoors().z < - 2.0f)
for(i = 0; i < NUM_HELIS; i++)
if(pHelis[i] && pHelis[i]->m_heliStatus != HELI_STATUS_SHOT_DOWN)
@ -950,7 +988,7 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
float distToHeli = (pHelis[i]->GetPosition() - *line0).Magnitude();
CVector line = (*line1 - *line0);
float lineLength = line.Magnitude();
*bulletPos = *line0 + line*Max(1.0f, distToHeli-5.0f);
*bulletPos = *line0 + line*Max(1.0f, distToHeli-5.0f)/lineLength;
pHelis[i]->m_nBulletDamage += damage;
@ -966,6 +1004,26 @@ CHeli::TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, i
return hit;
}
bool
CHeli::TestSniperCollision(CVector *line0, CVector *line1)
{
int i;
bool hit = false;
for(i = 0; i < NUM_HELIS; i++){
CVector pilotPos = pHelis[i]->GetMatrix() * CVector(-0.43f, 1.49f, 1.5f);
if(pHelis[i] && !pHelis[i]->bBulletProof && CCollision::DistToLine(line0, line1, &pilotPos) < 0.8f){
pHelis[i]->m_fAngularSpeed = CGeneral::GetRandomTrueFalse() ? 0.05f : -0.05f;
pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN;
pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 9999999;
pHelis[i]->m_numSwat = 0;
hit = true;
}
}
return hit;
}
void CHeli::StartCatalinaFlyBy(void)
{
CatalinaHeliOn = true;

View File

@ -21,7 +21,7 @@ enum
HELI_RANDOM0,
HELI_RANDOM1,
HELI_SCRIPT,
HELI_CATALINA,
HELI_CATALINA, // TODO 2 in VC
NUM_HELIS
};
@ -36,7 +36,6 @@ enum
class CHeli : public CVehicle
{
public:
// 0x288
RwFrame *m_aHeliNodes[NUM_HELI_NODES];
int8 m_heliStatus;
float m_fSearchLightX;
@ -49,6 +48,8 @@ public:
int8 m_nHeliId;
int8 m_heliType;
int8 m_pathState;
int8 m_numSwat;
uint8 m_aSwatState[4];
float m_aSearchLightHistoryX[6];
float m_aSearchLightHistoryY[6];
uint32 m_nSearchLightTimer;
@ -64,7 +65,6 @@ public:
static CHeli *pHelis[NUM_HELIS];
static int16 NumRandomHelis;
static uint32 TestForNewRandomHelisTimer;
static int16 NumScriptHelis; // unused
static bool CatalinaHeliOn;
static bool CatalinaHasBeenShotDown;
static bool ScriptHeliOn;
@ -79,12 +79,15 @@ public:
void PreRenderAlways(void);
CObject *SpawnFlyingComponent(int32 component);
CVector FindSwatPositionRelativeToHeli(int n);
bool SendDownSwat(void);
static void InitHelis(void);
static void UpdateHelis(void);
static void SpecialHeliPreRender(void);
static bool TestRocketCollision(CVector *coors);
static bool TestBulletCollision(CVector *line0, CVector *line1, CVector *bulletPos, int32 damage);
static bool TestSniperCollision(CVector *line0, CVector *line1);
static void StartCatalinaFlyBy(void);
static void RemoveCatalinaHeli(void);

View File

@ -2,6 +2,7 @@
#include "main.h"
#include "General.h"
#include "CutsceneMgr.h"
#include "ModelIndices.h"
#include "FileMgr.h"
#include "Streaming.h"
@ -12,10 +13,14 @@
#include "Coronas.h"
#include "Particle.h"
#include "Explosion.h"
#include "Fluff.h"
#include "World.h"
#include "HandlingMgr.h"
#include "Heli.h"
#include "Plane.h"
//--MIAMI: file done
CPlaneNode *pPathNodes;
CPlaneNode *pPath2Nodes;
CPlaneNode *pPath3Nodes;
@ -39,12 +44,10 @@ CPlaneInterpolationLine aPlaneLineBits[6];
float PlanePathPosition[3];
float OldPlanePathPosition[3];
float PlanePathSpeed[3];
float PlanePath2Position[3];
float PlanePath3Position;
float PlanePath4Position;
float PlanePath2Speed[3];
float PlanePath3Speed;
float PlanePath4Speed;
float PlanePath2Position[5];
float PlanePath3Position[4];
float PlanePath2Speed[5];
float PlanePath3Speed[4];
enum
@ -62,7 +65,6 @@ int32 DropOffCesnaMissionStatus;
int32 DropOffCesnaMissionStartTime;
CPlane *pDropOffCesna;
CPlane::CPlane(int32 id, uint8 CreatedBy)
: CVehicle(CreatedBy)
{
@ -80,13 +82,15 @@ CPlane::CPlane(int32 id, uint8 CreatedBy)
m_bHasBeenHit = false;
m_bIsDrugRunCesna = false;
m_bIsDropOffCesna = false;
m_bTempPlane = false;
SetStatus(STATUS_PLANE);
bIsBIGBuilding = true;
m_level = LEVEL_NONE;
m_level = LEVEL_GENERIC;
#ifdef FIX_BUGS
m_isFarAway = true;
m_isFarAway = false;
#ifdef CPLANE_ROTORS
m_fRotorRotation = 0.0f;
#endif
}
@ -99,6 +103,21 @@ void
CPlane::SetModelIndex(uint32 id)
{
CVehicle::SetModelIndex(id);
#ifdef CPLANE_ROTORS
int i;
for(i = 0; i < NUM_PLANE_NODES; i++)
m_aPlaneNodes[i] = nil;
if(GetModelIndex() == MI_CHOPPER){
// This is surprisingly annoying...
RwFrame *heliNodes[NUM_HELI_NODES];
for(i = 0; i < NUM_HELI_NODES; i++)
heliNodes[i] = nil;
CClumpModelInfo::FillFrameArray(GetClump(), heliNodes);
m_aPlaneNodes[PLANE_TOPROTOR] = heliNodes[HELI_TOPROTOR];
m_aPlaneNodes[PLANE_BACKROTOR] = heliNodes[HELI_BACKROTOR];
}else
CClumpModelInfo::FillFrameArray(GetClump(), m_aPlaneNodes);
#endif
}
void
@ -123,6 +142,15 @@ CPlane::ProcessControl(void)
int i;
CVector pos;
if(CReplay::IsPlayingBack())
return;
if(GetModelIndex() == MI_AIRTRAIN){
if(GetPosition().z > 100.0f)
CPlaneTrails::RegisterPoint(GetPosition(), m_nPlaneId);
}else if(GetModelIndex() == MI_DEADDODO)
CPlaneBanners::RegisterPoint(GetPosition(), m_nPlaneId);
// Explosion
if(m_bHasBeenHit){
// BUG: since this is all based on frames, you can skip the explosion processing when you go into the menu
@ -154,7 +182,7 @@ CPlane::ProcessControl(void)
int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
colors[nFrameGen], rotSpeed, 0, f, 0);
colors[nFrameGen&7], rotSpeed, 0, f, 0);
}
}
if(frm >= 40 && frm <= 80 && frm & 1){
@ -197,17 +225,18 @@ CPlane::ProcessControl(void)
colors[6] = CRGBA(0, 0, 0, 255);
colors[7] = CRGBA(252, 66, 66, 255);
CVector dir;
for(i = 0; i < 40; i++){
dir.x = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
dir.y = CGeneral::GetRandomNumberInRange(-2.0f, 2.0f);
dir.z = CGeneral::GetRandomNumberInRange(0.0f, 2.0f);
int rotSpeed = CGeneral::GetRandomNumberInRange(30.0f, 20.0f);
if(CGeneral::GetRandomNumber() & 1)
rotSpeed = -rotSpeed;
int f = ++nFrameGen & 3;
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f),
CVector(CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
CGeneral::GetRandomNumberInRange(-2.0f, 2.0f),
CGeneral::GetRandomNumberInRange(0.0f, 2.0f)),
CParticle::AddParticle(PARTICLE_HELI_DEBRIS, GetMatrix() * CVector(0.0f, 0.0f, 0.0f), dir,
nil, CGeneral::GetRandomNumberInRange(0.1f, 1.0f),
colors[nFrameGen], rotSpeed, 0, f, 0);
colors[nFrameGen&7], rotSpeed, 0, f, 0);
}
}
if(frm >= 40 && frm <= 60 && frm & 1){
@ -226,7 +255,7 @@ CPlane::ProcessControl(void)
}
if(frm == 30)
bRenderScorched = true;
if(frm == 61){
if(frm == 62){
TheCamera.SetFadeColour(200, 200, 200);
TheCamera.Fade(0.0f, FADE_OUT);
TheCamera.ProcessFade();
@ -363,7 +392,7 @@ CPlane::ProcessControl(void)
CVector posFront2 = (1.0f - f)*pPathNodes[curPathNodeFront2].p + f*pPathNodes[nextPathNodeFront2].p;
// Now set matrix
GetMatrix().GetPosition() = (posRear + posFront) / 2.0f;
GetMatrix().SetTranslateOnly((posRear + posFront) / 2.0f);
GetMatrix().GetPosition().z += 4.3f;
CVector fwd = posFront - posRear;
fwd.Normalise();
@ -382,13 +411,12 @@ CPlane::ProcessControl(void)
GetMatrix().GetRight() = right;
GetMatrix().GetUp() = up;
GetMatrix().GetForward() = fwd;
// Set speed
m_vecMoveSpeed = fwd*PlanePathSpeed[m_nPlaneId]/60.0f;
m_fSpeed = PlanePathSpeed[m_nPlaneId]/60.0f;
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
m_isFarAway = !((posFront - TheCamera.GetPosition()).MagnitudeSqr2D() < sq(300.0f));
}else{
float planePathPosition;
float totalLengthOfFlightPath;
@ -396,26 +424,12 @@ CPlane::ProcessControl(void)
float planePathSpeed;
int numPathNodes;
if(m_bIsDrugRunCesna){
planePathPosition = PlanePath3Position;
if(GetModelIndex() == MI_CHOPPER){
planePathPosition = PlanePath3Position[m_nPlaneId];
totalLengthOfFlightPath = TotalLengthOfFlightPath3;
pathNodes = pPath3Nodes;
planePathSpeed = PlanePath3Speed;
planePathSpeed = PlanePath3Speed[m_nPlaneId];
numPathNodes = NumPath3Nodes;
if(CesnaMissionStatus == CESNA_STATUS_LANDED){
pDrugRunCesna = nil;
FlagToDestroyWhenNextProcessed();
}
}else if(m_bIsDropOffCesna){
planePathPosition = PlanePath4Position;
totalLengthOfFlightPath = TotalLengthOfFlightPath4;
pathNodes = pPath4Nodes;
planePathSpeed = PlanePath4Speed;
numPathNodes = NumPath4Nodes;
if(DropOffCesnaMissionStatus == CESNA_STATUS_LANDED){
pDropOffCesna = nil;
FlagToDestroyWhenNextProcessed();
}
}else{
planePathPosition = PlanePath2Position[m_nPlaneId];
totalLengthOfFlightPath = TotalLengthOfFlightPath2;
@ -484,7 +498,7 @@ CPlane::ProcessControl(void)
f = (pathPositionFront - pathNodes[curPathNodeFront].t)/dist;
CVector posFront = (1.0f - f)*pathNodes[curPathNodeFront].p + f*pathNodes[nextPathNodeFront].p;
// And for another point 60 units in front of the plane, used to calculate roll
// And for another point 30 units in front of the plane, used to calculate roll
float pathPositionFront2 = pathPositionFront + 30.0f;
if(pathPositionFront2 > totalLengthOfFlightPath)
pathPositionFront2 -= totalLengthOfFlightPath;
@ -515,7 +529,7 @@ CPlane::ProcessControl(void)
CVector posFront2 = (1.0f - f)*pathNodes[curPathNodeFront2].p + f*pathNodes[nextPathNodeFront2].p;
// Now set matrix
GetMatrix().GetPosition() = (posRear + posFront) / 2.0f;
GetMatrix().SetTranslateOnly((posRear + posFront) / 2.0f);
GetMatrix().GetPosition().z += 1.0f;
CVector fwd = posFront - posRear;
fwd.Normalise();
@ -535,7 +549,7 @@ CPlane::ProcessControl(void)
m_fSpeed = planePathSpeed/60.0f;
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(300.0f));
m_isFarAway = !((posFront - TheCamera.GetPosition()).MagnitudeSqr2D() < sq(300.0f));
}
}
@ -634,12 +648,36 @@ CPlane::PreRender(void)
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
}
#ifdef CPLANE_ROTORS
CMatrix mat;
CVector pos;
m_fRotorRotation += 3.14f/6.5f;
if(m_fRotorRotation > 6.28f)
m_fRotorRotation -= 6.28f;
if(m_aPlaneNodes[PLANE_TOPROTOR]){
mat.Attach(RwFrameGetMatrix(m_aPlaneNodes[PLANE_TOPROTOR]));
pos = mat.GetPosition();
mat.SetRotateZ(m_fRotorRotation);
mat.Translate(pos);
mat.UpdateRW();
}
if(m_aPlaneNodes[PLANE_BACKROTOR]){
mat.Attach(RwFrameGetMatrix(m_aPlaneNodes[PLANE_BACKROTOR]));
pos = mat.GetPosition();
mat.SetRotateX(m_fRotorRotation);
mat.Translate(pos);
mat.UpdateRW();
}
#endif
}
void
CPlane::Render(void)
{
CEntity::Render();
if(!CCutsceneMgr::IsRunning())
CEntity::Render();
}
#define CRUISE_SPEED (50.0f)
@ -657,11 +695,9 @@ CPlane::InitPlanes(void)
pPathNodes = LoadPath("data\\paths\\flight.dat", NumPathNodes, TotalLengthOfFlightPath, true);
// Figure out which nodes are on ground
CColPoint colpoint;
CEntity *entity;
for(i = 0; i < NumPathNodes; i++){
if(CWorld::ProcessVerticalLine(pPathNodes[i].p, 1000.0f, colpoint, entity, true, false, false, false, true, false, nil)){
pPathNodes[i].p.z = colpoint.point.z;
if(pPathNodes[i].p.z < 14.0f){
pPathNodes[i].p.z = 14.0f;
pPathNodes[i].bOnGround = true;
}else
pPathNodes[i].bOnGround = false;
@ -688,7 +724,7 @@ CPlane::InitPlanes(void)
aPlaneLineBits[0].position = position;
aPlaneLineBits[0].speed = TAXI_SPEED;
aPlaneLineBits[0].acceleration = 0.0f;
float dist = (TakeOffPoint-600.0f) - position;
float dist = (TakeOffPoint-500.0f) - position;
time += dist/TAXI_SPEED;
position += dist;
@ -697,9 +733,9 @@ CPlane::InitPlanes(void)
aPlaneLineBits[1].time = time;
aPlaneLineBits[1].position = position;
aPlaneLineBits[1].speed = TAXI_SPEED;
aPlaneLineBits[1].acceleration = 33.0f/32.0f;
time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
position += 600.0f;
aPlaneLineBits[1].acceleration = 618.75f/500.0f;
time += 500.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
position += 500.0f;
// Fly at cruise speed
aPlaneLineBits[2].type = 1;
@ -716,9 +752,9 @@ CPlane::InitPlanes(void)
aPlaneLineBits[3].time = time;
aPlaneLineBits[3].position = position;
aPlaneLineBits[3].speed = CRUISE_SPEED;
aPlaneLineBits[3].acceleration = -33.0f/32.0f;
time += 600.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
position += 600.0f;
aPlaneLineBits[3].acceleration = -618.75f/500.0f;
time += 500.0f/((CRUISE_SPEED+TAXI_SPEED)/2.0f);
position += 500.0f;
// Taxi
aPlaneLineBits[4].type = 1;
@ -739,24 +775,17 @@ CPlane::InitPlanes(void)
TotalDurationOfFlightPath2 = TotalLengthOfFlightPath2/CRUISE_SPEED;
}
/*
// Mission Cesna
// Heli
if(pPath3Nodes == nil){
pPath3Nodes = LoadPath("data\\paths\\flight3.dat", NumPath3Nodes, TotalLengthOfFlightPath3, false);
TotalDurationOfFlightPath3 = TotalLengthOfFlightPath3/CRUISE_SPEED;
}
// Mission Cesna
if(pPath4Nodes == nil){
pPath4Nodes = LoadPath("data\\paths\\flight4.dat", NumPath4Nodes, TotalLengthOfFlightPath4, false);
TotalDurationOfFlightPath4 = TotalLengthOfFlightPath4/CRUISE_SPEED;
}
*/
CStreaming::LoadAllRequestedModels(false);
CStreaming::RequestModel(MI_AIRTRAIN, 0);
CStreaming::LoadAllRequestedModels(false);
// NB: 3 hardcoded also in CPlaneTrails
for(i = 0; i < 3; i++){
CPlane *plane = new CPlane(MI_AIRTRAIN, PERMANENT_VEHICLE);
plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
@ -766,20 +795,6 @@ CPlane::InitPlanes(void)
plane->m_nCurPathNode = 0;
CWorld::Add(plane);
}
CStreaming::RequestModel(MI_DEADDODO, 0);
CStreaming::LoadAllRequestedModels(false);
for(i = 0; i < 3; i++){
CPlane *plane = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
plane->SetStatus(STATUS_ABANDONED);
plane->bIsLocked = true;
plane->m_nPlaneId = i;
plane->m_nCurPathNode = 0;
CWorld::Add(plane);
}
}
void
@ -811,7 +826,6 @@ CPlane::LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool
CPlaneNode *nodes = new CPlaneNode[numNodes];
for(i = 0; i < numNodes; i++){
*gString = '\0';
for(lp = 0; work_buff[bp] != '\n' && work_buff[bp] != '\0'; bp++, lp++)
gString[lp] = work_buff[bp];
bp++;
@ -833,6 +847,10 @@ CPlane::LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool
return nodes;
}
int32 LastTimeInPlane, LastTimeNotInPlane;
bool bCesnasActivated;
bool bHelisActivated;
void
CPlane::UpdatePlanes(void)
{
@ -875,25 +893,87 @@ CPlane::UpdatePlanes(void)
t = TotalDurationOfFlightPath2/0x80000;
PlanePath2Position[0] = CRUISE_SPEED * (time & 0x7FFFF)*t;
PlanePath2Position[1] = CRUISE_SPEED * ((time + 0x80000/3) & 0x7FFFF)*t;
PlanePath2Position[2] = CRUISE_SPEED * ((time + 0x80000/3*2) & 0x7FFFF)*t;
PlanePath2Position[1] = CRUISE_SPEED * ((time + 0x80000/5) & 0x7FFFF)*t;
PlanePath2Position[2] = CRUISE_SPEED * ((time + 0x80000/5*2) & 0x7FFFF)*t;
PlanePath2Position[3] = CRUISE_SPEED * ((time + 0x80000/5*3) & 0x7FFFF)*t;
PlanePath2Position[4] = CRUISE_SPEED * ((time + 0x80000/5*4) & 0x7FFFF)*t;
PlanePath2Speed[0] = CRUISE_SPEED*t;
PlanePath2Speed[1] = CRUISE_SPEED*t;
PlanePath2Speed[2] = CRUISE_SPEED*t;
PlanePath2Speed[3] = CRUISE_SPEED*t;
PlanePath2Speed[4] = CRUISE_SPEED*t;
if(CesnaMissionStatus == CESNA_STATUS_FLYING){
PlanePath3Speed = CRUISE_SPEED*TotalDurationOfFlightPath3/0x20000;
PlanePath3Position = PlanePath3Speed * ((time - CesnaMissionStartTime) & 0x1FFFF);
if(time - CesnaMissionStartTime >= 128072)
CesnaMissionStatus = CESNA_STATUS_LANDED;
}
t = TotalDurationOfFlightPath3/0x80000;
PlanePath3Position[0] = CRUISE_SPEED * (time & 0x7FFFF)*t;
PlanePath3Position[1] = CRUISE_SPEED * ((time + 0x80000/4) & 0x7FFFF)*t;
PlanePath3Position[2] = CRUISE_SPEED * ((time + 0x80000/4*2) & 0x7FFFF)*t;
PlanePath3Position[3] = CRUISE_SPEED * ((time + 0x80000/4*3) & 0x7FFFF)*t;
PlanePath3Speed[0] = CRUISE_SPEED*t;
PlanePath3Speed[1] = CRUISE_SPEED*t;
PlanePath3Speed[2] = CRUISE_SPEED*t;
PlanePath3Speed[3] = CRUISE_SPEED*t;
if(DropOffCesnaMissionStatus == CESNA_STATUS_FLYING){
PlanePath4Speed = CRUISE_SPEED*TotalDurationOfFlightPath4/0x80000;
PlanePath4Position = PlanePath4Speed * ((time - DropOffCesnaMissionStartTime) & 0x7FFFF);
if(time - DropOffCesnaMissionStartTime >= 521288)
DropOffCesnaMissionStatus = CESNA_STATUS_LANDED;
if(FindPlayerVehicle() && (FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI ||
FindPlayerVehicle()->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE))
LastTimeInPlane = CTimer::GetTimeInMilliseconds();
else
LastTimeNotInPlane = CTimer::GetTimeInMilliseconds();
if(CTimer::GetTimeInMilliseconds() - LastTimeNotInPlane > 10000){
if(!bCesnasActivated){
if(CStreaming::HasModelLoaded(MI_DEADDODO)){
for(i = 0; i < 5; i++){
CPlane *plane = new CPlane(MI_DEADDODO, PERMANENT_VEHICLE);
plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
plane->SetStatus(STATUS_ABANDONED);
plane->bIsLocked = true;
plane->m_nPlaneId = i;
plane->m_nCurPathNode = 0;
plane->m_bTempPlane = true;
CWorld::Add(plane);
}
bCesnasActivated = true;
}else
CStreaming::RequestModel(MI_DEADDODO, 0);
}
if(!bHelisActivated){
if(CStreaming::HasModelLoaded(MI_CHOPPER)){
for(i = 0; i < 4; i++){
CPlane *plane = new CPlane(MI_CHOPPER, PERMANENT_VEHICLE);
plane->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
plane->SetStatus(STATUS_ABANDONED);
plane->bIsLocked = true;
plane->m_nPlaneId = i;
plane->m_nCurPathNode = 0;
plane->m_bTempPlane = true;
CWorld::Add(plane);
}
bHelisActivated = true;
}else
CStreaming::RequestModel(MI_CHOPPER, 0);
}
}else if(CTimer::GetTimeInMilliseconds() - LastTimeInPlane > 10000)
RemoveTemporaryPlanes();
}
void
CPlane::RemoveTemporaryPlanes(void)
{
int i;
if(!bHelisActivated && !bCesnasActivated)
return;
i = CPools::GetVehiclePool()->GetSize();
while(--i >= 0){
CPlane *plane = (CPlane*)CPools::GetVehiclePool()->GetSlot(i);
if(plane && plane->IsPlane() && plane->m_bTempPlane){
CWorld::Remove(plane);
delete plane;
}
}
bCesnasActivated = false;
bHelisActivated = false;
}
bool
@ -921,6 +1001,7 @@ CPlane::TestRocketCollision(CVector *rocketPos)
return false;
}
//--MIAMI: unused
// BUG: not in CPlane in the game
void
CPlane::CreateIncomingCesna(void)
@ -944,6 +1025,7 @@ CPlane::CreateIncomingCesna(void)
printf("CPlane::CreateIncomingCesna(void)\n");
}
//--MIAMI: unused
void
CPlane::CreateDropOffCesna(void)
{
@ -966,8 +1048,21 @@ CPlane::CreateDropOffCesna(void)
printf("CPlane::CreateDropOffCesna(void)\n");
}
//--MIAMI: all unused
const CVector CPlane::FindDrugPlaneCoordinates(void) { return pDrugRunCesna->GetPosition(); }
const CVector CPlane::FindDropOffCesnaCoordinates(void) { return pDropOffCesna->GetPosition(); }
bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LANDED; }
bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; }
bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; }
void
CPlane::Load(void)
{
RemoveTemporaryPlanes();
}
void
CPlane::Save(void)
{
RemoveTemporaryPlanes();
}

View File

@ -4,6 +4,11 @@
enum ePlaneNodes
{
#ifdef CPLANE_ROTORS
// for heli
PLANE_TOPROTOR,
PLANE_BACKROTOR,
#endif
PLANE_WHEEL_FRONT = 2,
PLANE_WHEEL_READ,
NUM_PLANE_NODES
@ -29,7 +34,10 @@ struct CPlaneInterpolationLine
class CPlane : public CVehicle
{
public:
// 0x288
#ifdef CPLANE_ROTORS
RwFrame *m_aPlaneNodes[NUM_PLANE_NODES];
float m_fRotorRotation;
#endif
int16 m_nPlaneId;
int16 m_isFarAway;
int16 m_nCurPathNode;
@ -38,6 +46,7 @@ public:
bool m_bHasBeenHit;
bool m_bIsDrugRunCesna;
bool m_bIsDropOffCesna;
bool m_bTempPlane;
CPlane(int32 id, uint8 CreatedBy);
~CPlane(void);
@ -53,6 +62,7 @@ public:
static void InitPlanes(void);
static void Shutdown(void);
static CPlaneNode *LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool loop);
static void RemoveTemporaryPlanes(void);
static void UpdatePlanes(void);
static bool TestRocketCollision(CVector *rocketPos);
static void CreateIncomingCesna(void);
@ -62,6 +72,8 @@ public:
static bool HasCesnaLanded(void);
static bool HasCesnaBeenDestroyed(void);
static bool HasDropOffCesnaBeenShotDown(void);
static void Load(void);
static void Save(void);
};
extern float LandingPoint;

View File

@ -232,7 +232,7 @@ CVehicle::SetupLighting(void)
}else{
CVector coors = GetPosition();
float lighting = CPointLights::GenerateLightsAffectingObject(&coors);
if(!bHasBlip && lighting != 1.0f){
if(lighting != 1.0f){
SetAmbientAndDirectionalColours(lighting);
return true;
}
@ -1512,7 +1512,7 @@ CVehicle::MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&pl
for(i = 0; i < numPeds2; i++)
if(peds2[i]->IsFemale() || CGeneral::GetRandomTrueFalse()){
peds2[i]->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 10000;
peds2[i]->b156_8 = true;
peds2[i]->bHeldHostageInCar = true;
peds2[i]->bFleeAfterExitingCar = true;
}
}
@ -1557,9 +1557,9 @@ CVehicle::IsLawEnforcementVehicle(void)
}
bool
CVehicle::UsesSiren(uint32 id)
CVehicle::UsesSiren(void)
{
switch(id){
switch(GetModelIndex()){
case MI_FIRETRUCK:
case MI_AMBULAN:
case MI_FBICAR:
@ -2239,7 +2239,7 @@ CVehicle::DoSunGlare(void)
int a2 = colmodel->triangles[i+1].a;
int b2 = colmodel->triangles[i+1].b;
int c2 = colmodel->triangles[i+1].c;
CVector vert1 = colmodel->vertices[a1];
CVector vert1 = colmodel->vertices[a1].Get();
CVector vert4;
// Need an upward surface
if(vert1.z <= 0.0f)
@ -2250,23 +2250,23 @@ CVehicle::DoSunGlare(void)
if(a2 != a1 && a2 != b1 && a2 != c1){
// a2 is not in tri1
numTri2Verts++;
vert4 = colmodel->vertices[a2];
vert4 = colmodel->vertices[a2].Get();
}
if(b2 != a1 && b2 != b1 && b2 != c1){
// b2 is not in tri1
numTri2Verts++;
vert4 = colmodel->vertices[b2];
vert4 = colmodel->vertices[b2].Get();
}
if(c2 != a1 && c2 != b1 && c2 != c1){
// c2 is not in tri1
numTri2Verts++;
vert4 = colmodel->vertices[c2];
vert4 = colmodel->vertices[c2].Get();
}
// Need exactly one vertex from tri2 for a quad with tri1
if(numTri2Verts != 1)
continue;
CVector mid = (vert1 + colmodel->vertices[b1] + colmodel->vertices[c1] + vert4)/4.0f;
CVector mid = (vert1 + colmodel->vertices[b1].Get() + colmodel->vertices[c1].Get() + vert4)/4.0f;
float dy = mid.y - vert1.y;
float dx = mid.x - vert1.x;
float dist = 1.4f * Min(Abs(dx), Abs(dy));

View File

@ -345,7 +345,7 @@ public:
int FindTyreNearestPoint(float x, float y);
bool IsLawEnforcementVehicle(void);
void ChangeLawEnforcerState(uint8 enable);
bool UsesSiren(uint32 id);
bool UsesSiren(void);
bool IsVehicleNormal(void);
bool CarHasRoof(void);
bool IsUpsideDown(void);