mirror of
https://github.com/halpz/re3.git
synced 2025-06-29 13:26:19 +00:00
Merge branch 'master' into game_dev
This commit is contained in:
@ -1,312 +0,0 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "CarGen.h"
|
||||
|
||||
#include "Automobile.h"
|
||||
#include "Boat.h"
|
||||
#include "Camera.h"
|
||||
#include "CarCtrl.h"
|
||||
#include "CutsceneMgr.h"
|
||||
#include "General.h"
|
||||
#include "Pools.h"
|
||||
#include "Streaming.h"
|
||||
#include "Timer.h"
|
||||
#include "Vehicle.h"
|
||||
#include "World.h"
|
||||
|
||||
uint8 &CTheCarGenerators::ProcessCounter = *(uint8*)0x95CDAF;
|
||||
uint32 &CTheCarGenerators::NumOfCarGenerators = *(uint32*)0x8E2C1C;
|
||||
CCarGenerator (&CTheCarGenerators::CarGeneratorArray)[NUM_CARGENS] = *(CCarGenerator(*)[NUM_CARGENS])*(uintptr*)0x87CB18;
|
||||
uint8 &CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = *(uint8*)0x95CDC6;
|
||||
uint32 &CTheCarGenerators::CurrentActiveCount = *(uint32*)0x8F2C5C;
|
||||
|
||||
void CCarGenerator::SwitchOff()
|
||||
{
|
||||
m_nUsesRemaining = 0;
|
||||
--CTheCarGenerators::CurrentActiveCount;
|
||||
}
|
||||
|
||||
void CCarGenerator::SwitchOn()
|
||||
{
|
||||
m_nUsesRemaining = -1;
|
||||
m_nTimer = CalcNextGen();
|
||||
++CTheCarGenerators::CurrentActiveCount;
|
||||
}
|
||||
|
||||
uint32 CCarGenerator::CalcNextGen()
|
||||
{
|
||||
return CTimer::GetTimeInMilliseconds() + 4;
|
||||
}
|
||||
|
||||
void CCarGenerator::DoInternalProcessing()
|
||||
{
|
||||
if (CheckForBlockage()) {
|
||||
m_nTimer += 4;
|
||||
if (m_nUsesRemaining == 0)
|
||||
--CTheCarGenerators::CurrentActiveCount;
|
||||
return;
|
||||
}
|
||||
if (CCarCtrl::NumParkedCars >= 10)
|
||||
return;
|
||||
CStreaming::RequestModel(m_nModelIndex, STREAMFLAGS_DEPENDENCY);
|
||||
if (!CStreaming::HasModelLoaded(m_nModelIndex))
|
||||
return;
|
||||
if (CModelInfo::IsBoatModel(m_nModelIndex)){
|
||||
CBoat* pBoat = new CBoat(m_nModelIndex, PARKED_VEHICLE);
|
||||
pBoat->bIsStatic = false;
|
||||
pBoat->bEngineOn = false;
|
||||
CVector pos = m_vecPos;
|
||||
if (pos.z <= -100.0f)
|
||||
pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
|
||||
pos.z += pBoat->GetDistanceFromCentreOfMassToBaseOfModel();
|
||||
pBoat->GetPosition() = pos;
|
||||
pBoat->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
|
||||
pBoat->m_status = STATUS_ABANDONED;
|
||||
pBoat->m_nDoorLock = CARLOCK_UNLOCKED;
|
||||
CWorld::Add(pBoat);
|
||||
if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
|
||||
pBoat->m_nAlarmState = -1;
|
||||
if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
|
||||
pBoat->m_nDoorLock = CARLOCK_LOCKED;
|
||||
if (m_nColor1 != -1 && m_nColor2){
|
||||
pBoat->m_currentColour1 = m_nColor1;
|
||||
pBoat->m_currentColour2 = m_nColor2;
|
||||
}
|
||||
m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pBoat);
|
||||
}else{
|
||||
bool groundFound = false;
|
||||
CVector pos = m_vecPos;
|
||||
if (pos.z > -100.0f){
|
||||
pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &groundFound);
|
||||
}else{
|
||||
CColPoint cp;
|
||||
CEntity* pEntity;
|
||||
groundFound = CWorld::ProcessVerticalLine(CVector(pos.x, pos.y, 1000.0f), -1000.0f,
|
||||
cp, pEntity, true, false, false, false, false, false, nil);
|
||||
if (groundFound)
|
||||
pos.z = cp.point.z;
|
||||
}
|
||||
if (!groundFound) {
|
||||
debug("CCarGenerator::DoInternalProcessing - can't find ground z for new car x = %f y = %f \n", m_vecPos.x, m_vecPos.y);
|
||||
}else{
|
||||
CAutomobile* pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE);
|
||||
pCar->bIsStatic = false;
|
||||
pCar->bEngineOn = false;
|
||||
pos.z += pCar->GetDistanceFromCentreOfMassToBaseOfModel();
|
||||
pCar->GetPosition() = pos;
|
||||
pCar->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
|
||||
pCar->m_status = STATUS_ABANDONED;
|
||||
pCar->bLightsOn = false;
|
||||
pCar->m_nDoorLock = CARLOCK_UNLOCKED;
|
||||
CWorld::Add(pCar);
|
||||
if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
|
||||
pCar->m_nAlarmState = -1;
|
||||
if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
|
||||
pCar->m_nDoorLock = CARLOCK_LOCKED;
|
||||
if (m_nColor1 != -1 && m_nColor2) {
|
||||
pCar->m_currentColour1 = m_nColor1;
|
||||
pCar->m_currentColour2 = m_nColor2;
|
||||
}
|
||||
m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pCar);
|
||||
}
|
||||
}
|
||||
if (m_nUsesRemaining < -1) /* I don't think this is a correct comparasion */
|
||||
--m_nUsesRemaining;
|
||||
m_nTimer = CalcNextGen();
|
||||
if (m_nUsesRemaining == 0)
|
||||
--CTheCarGenerators::CurrentActiveCount;
|
||||
}
|
||||
|
||||
void CCarGenerator::Process()
|
||||
{
|
||||
if (m_nVehicleHandle == -1 &&
|
||||
(CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter || CTimer::GetTimeInMilliseconds() >= m_nTimer) &&
|
||||
m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayer())
|
||||
DoInternalProcessing();
|
||||
if (m_nVehicleHandle == -1)
|
||||
return;
|
||||
CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(m_nVehicleHandle);
|
||||
if (!pVehicle){
|
||||
m_nVehicleHandle = -1;
|
||||
return;
|
||||
}
|
||||
if (pVehicle->m_status != STATUS_PLAYER)
|
||||
return;
|
||||
m_nTimer += 60000;
|
||||
m_nVehicleHandle = -1;
|
||||
m_bIsBlocking = true;
|
||||
pVehicle->bExtendedRange = false;
|
||||
}
|
||||
|
||||
void CCarGenerator::Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
|
||||
{
|
||||
CMatrix m1, m2, m3; /* Unused but present on stack, so I'll leave them. */
|
||||
m_vecPos = CVector(x, y, z);
|
||||
m_fAngle = angle;
|
||||
m_nModelIndex = mi;
|
||||
m_nColor1 = color1;
|
||||
m_nColor2 = color2;
|
||||
m_bForceSpawn = force;
|
||||
m_nAlarm = alarm;
|
||||
m_nDoorlock = lock;
|
||||
m_nMinDelay = min_delay;
|
||||
m_nMaxDelay = max_delay;
|
||||
m_nVehicleHandle = -1;
|
||||
m_nTimer = CTimer::GetTimeInMilliseconds() + 1;
|
||||
m_nUsesRemaining = 0;
|
||||
m_bIsBlocking = false;
|
||||
m_vecInf = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.min;
|
||||
m_vecSup = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.max;
|
||||
m_fSize = max(m_vecInf.Magnitude(), m_vecSup.Magnitude());
|
||||
}
|
||||
|
||||
bool CCarGenerator::CheckForBlockage()
|
||||
{
|
||||
int16 entities;
|
||||
CWorld::FindObjectsKindaColliding(CVector(m_vecPos), m_fSize, 1, &entities, 2, nil, false, true, true, false, false);
|
||||
return entities > 0;
|
||||
}
|
||||
|
||||
bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
|
||||
{
|
||||
CVector2D direction = FindPlayerCentreOfWorld(CWorld::PlayerInFocus) - m_vecPos;
|
||||
float distance = direction.Magnitude();
|
||||
float farclip = 120.0f * TheCamera.GenerationDistMultiplier;
|
||||
float nearclip = farclip - 20.0f;
|
||||
if (distance >= farclip){
|
||||
if (m_bIsBlocking)
|
||||
m_bIsBlocking = false;
|
||||
return false;
|
||||
}
|
||||
if (CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter)
|
||||
return true;
|
||||
if (m_bIsBlocking)
|
||||
return false;
|
||||
if (distance < nearclip)
|
||||
return false;
|
||||
return DotProduct2D(direction, FindPlayerSpeed()) <= 0;
|
||||
}
|
||||
|
||||
void CCarGenerator::Save(uint8 *&buffer)
|
||||
{
|
||||
WriteSaveBuf(buffer, m_nModelIndex);
|
||||
WriteSaveBuf(buffer, m_vecPos);
|
||||
WriteSaveBuf(buffer, m_fAngle);
|
||||
WriteSaveBuf(buffer, m_nColor1);
|
||||
WriteSaveBuf(buffer, m_nColor2);
|
||||
WriteSaveBuf(buffer, m_bForceSpawn);
|
||||
WriteSaveBuf(buffer, m_nAlarm);
|
||||
WriteSaveBuf(buffer, m_nDoorlock);
|
||||
WriteSaveBuf(buffer, (uint8)0);
|
||||
WriteSaveBuf(buffer, m_nMinDelay);
|
||||
WriteSaveBuf(buffer, m_nMaxDelay);
|
||||
WriteSaveBuf(buffer, m_nTimer);
|
||||
WriteSaveBuf(buffer, m_nVehicleHandle);
|
||||
WriteSaveBuf(buffer, m_nUsesRemaining);
|
||||
WriteSaveBuf(buffer, m_bIsBlocking);
|
||||
WriteSaveBuf(buffer, (uint8)0);
|
||||
WriteSaveBuf(buffer, m_vecInf);
|
||||
WriteSaveBuf(buffer, m_vecSup);
|
||||
WriteSaveBuf(buffer, m_fSize);
|
||||
|
||||
// or
|
||||
//WriteSaveBuf(buffer, *this);
|
||||
|
||||
}
|
||||
|
||||
void CCarGenerator::Load(uint8 *&buffer)
|
||||
{
|
||||
m_nModelIndex = ReadSaveBuf<uint32>(buffer);
|
||||
m_vecPos = ReadSaveBuf<CVector>(buffer);
|
||||
m_fAngle = ReadSaveBuf<float>(buffer);
|
||||
m_nColor1 = ReadSaveBuf<int16>(buffer);
|
||||
m_nColor2 = ReadSaveBuf<int16>(buffer);
|
||||
m_bForceSpawn = ReadSaveBuf<uint8>(buffer);
|
||||
m_nAlarm = ReadSaveBuf<uint8>(buffer);
|
||||
m_nDoorlock = ReadSaveBuf<uint8>(buffer);
|
||||
ReadSaveBuf<uint8>(buffer);
|
||||
m_nMinDelay = ReadSaveBuf<uint16>(buffer);
|
||||
m_nMaxDelay = ReadSaveBuf<uint16>(buffer);
|
||||
m_nTimer = ReadSaveBuf<uint32>(buffer);
|
||||
m_nVehicleHandle = ReadSaveBuf<int32>(buffer);
|
||||
m_nUsesRemaining = ReadSaveBuf<uint16>(buffer);
|
||||
m_bIsBlocking = ReadSaveBuf<bool>(buffer);
|
||||
ReadSaveBuf<uint8>(buffer);
|
||||
m_vecInf = ReadSaveBuf<CVector>(buffer);
|
||||
m_vecSup = ReadSaveBuf<CVector>(buffer);
|
||||
m_fSize = ReadSaveBuf<float>(buffer);
|
||||
|
||||
// or
|
||||
//*this = ReadSaveBuf<CCarGenerator>(buffer);
|
||||
}
|
||||
|
||||
void CTheCarGenerators::Process()
|
||||
{
|
||||
if (FindPlayerTrain() || CCutsceneMgr::IsCutsceneProcessing())
|
||||
return;
|
||||
if (++CTheCarGenerators::ProcessCounter == 4)
|
||||
CTheCarGenerators::ProcessCounter = 0;
|
||||
for (uint32 i = ProcessCounter; i < NumOfCarGenerators; i += 4)
|
||||
CTheCarGenerators::CarGeneratorArray[i].Process();
|
||||
if (GenerateEvenIfPlayerIsCloseCounter)
|
||||
GenerateEvenIfPlayerIsCloseCounter--;
|
||||
}
|
||||
|
||||
int32 CTheCarGenerators::CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
|
||||
{
|
||||
CarGeneratorArray[NumOfCarGenerators].Setup(x, y, z, angle, mi, color1, color2, force, alarm, lock, min_delay, max_delay);
|
||||
return NumOfCarGenerators++;
|
||||
}
|
||||
|
||||
void CTheCarGenerators::Init()
|
||||
{
|
||||
GenerateEvenIfPlayerIsCloseCounter = 0;
|
||||
NumOfCarGenerators = 0;
|
||||
ProcessCounter = 0;
|
||||
CurrentActiveCount = 0;
|
||||
}
|
||||
|
||||
void CTheCarGenerators::SaveAllCarGenerators(uint8 *buffer, uint32 *size)
|
||||
{
|
||||
*size = 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE;
|
||||
INITSAVEBUF
|
||||
WriteSaveHeader(buffer, 'C','G','N','\0', *size - SAVE_HEADER_SIZE);
|
||||
|
||||
WriteSaveBuf(buffer, 12); /* what is this? */
|
||||
WriteSaveBuf(buffer, NumOfCarGenerators);
|
||||
WriteSaveBuf(buffer, CurrentActiveCount);
|
||||
WriteSaveBuf(buffer, ProcessCounter);
|
||||
WriteSaveBuf(buffer, GenerateEvenIfPlayerIsCloseCounter);
|
||||
WriteSaveBuf(buffer, (int16)0);
|
||||
WriteSaveBuf(buffer, sizeof(CarGeneratorArray));
|
||||
for (int i = 0; i < NUM_CARGENS; i++){
|
||||
CarGeneratorArray[i].Save(buffer);
|
||||
}
|
||||
VALIDATESAVEBUF(*size)
|
||||
}
|
||||
|
||||
void CTheCarGenerators::LoadAllCarGenerators(uint8* buffer, uint32 size)
|
||||
{
|
||||
Init();
|
||||
INITSAVEBUF
|
||||
assert(size == 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE);
|
||||
CheckSaveHeader(buffer, 'C','G','N','\0', size - SAVE_HEADER_SIZE);
|
||||
ReadSaveBuf<uint32>(buffer);
|
||||
NumOfCarGenerators = ReadSaveBuf<uint32>(buffer);
|
||||
CurrentActiveCount = ReadSaveBuf<uint32>(buffer);
|
||||
ProcessCounter = ReadSaveBuf<uint8>(buffer);
|
||||
GenerateEvenIfPlayerIsCloseCounter = ReadSaveBuf<uint8>(buffer);
|
||||
ReadSaveBuf<int16>(buffer);
|
||||
assert(ReadSaveBuf<uint32>(buffer) == sizeof(CarGeneratorArray));
|
||||
for (int i = 0; i < NUM_CARGENS; i++) {
|
||||
CarGeneratorArray[i].Load(buffer);
|
||||
}
|
||||
VALIDATESAVEBUF(size)
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x543020, CTheCarGenerators::Init, PATCH_JUMP);
|
||||
InjectHook(0x542F40, CTheCarGenerators::Process, PATCH_JUMP);
|
||||
InjectHook(0x543050, CTheCarGenerators::SaveAllCarGenerators, PATCH_JUMP);
|
||||
InjectHook(0x5431E0, CTheCarGenerators::LoadAllCarGenerators, PATCH_JUMP);
|
||||
ENDPATCHES
|
@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
|
||||
enum {
|
||||
CARGEN_MAXACTUALLIMIT = 100
|
||||
};
|
||||
|
||||
class CCarGenerator
|
||||
{
|
||||
int32 m_nModelIndex;
|
||||
CVector m_vecPos;
|
||||
float m_fAngle;
|
||||
int16 m_nColor1;
|
||||
int16 m_nColor2;
|
||||
uint8 m_bForceSpawn;
|
||||
uint8 m_nAlarm;
|
||||
uint8 m_nDoorlock;
|
||||
int16 m_nMinDelay;
|
||||
int16 m_nMaxDelay;
|
||||
uint32 m_nTimer;
|
||||
int32 m_nVehicleHandle;
|
||||
uint16 m_nUsesRemaining;
|
||||
bool m_bIsBlocking;
|
||||
CVector m_vecInf;
|
||||
CVector m_vecSup;
|
||||
float m_fSize;
|
||||
public:
|
||||
void SwitchOff();
|
||||
void SwitchOn();
|
||||
uint32 CalcNextGen();
|
||||
void DoInternalProcessing();
|
||||
void Process();
|
||||
void Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
|
||||
bool CheckForBlockage();
|
||||
bool CheckIfWithinRangeOfAnyPlayer();
|
||||
void Save(uint8*&);
|
||||
void Load(uint8*&);
|
||||
void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
|
||||
};
|
||||
|
||||
class CTheCarGenerators
|
||||
{
|
||||
public:
|
||||
static uint8 &ProcessCounter;
|
||||
static uint32 &NumOfCarGenerators;
|
||||
static CCarGenerator (&CarGeneratorArray)[NUM_CARGENS];
|
||||
static uint8 &GenerateEvenIfPlayerIsCloseCounter;
|
||||
static uint32 &CurrentActiveCount;
|
||||
|
||||
static void Process();
|
||||
static int32 CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
|
||||
static void Init();
|
||||
static void SaveAllCarGenerators(uint8 *, uint32 *);
|
||||
static void LoadAllCarGenerators(uint8 *, uint32);
|
||||
};
|
@ -1,679 +0,0 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "Cranes.h"
|
||||
|
||||
#include "Camera.h"
|
||||
#include "DMAudio.h"
|
||||
#include "Garages.h"
|
||||
#include "General.h"
|
||||
#include "Entity.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "Replay.h"
|
||||
#include "Object.h"
|
||||
#include "World.h"
|
||||
|
||||
#define MAX_DISTANCE_TO_FIND_CRANE (10.0f)
|
||||
#define CRANE_UPDATE_RADIUS (300.0f)
|
||||
#define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f)
|
||||
#define CRUSHER_Z (-0.951f)
|
||||
#define MILITARY_Z (10.7862f)
|
||||
#define DISTANCE_FROM_PLAYER_TO_REMOVE_VEHICLE (5.0f)
|
||||
#define DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT (0.5f)
|
||||
#define CAR_REWARD_MILITARY_CRANE (1500)
|
||||
#define CAR_MOVING_SPEED_THRESHOLD (0.01f)
|
||||
#define CRANE_SLOWDOWN_MULTIPLIER (0.3f)
|
||||
|
||||
#define OSCILLATION_SPEED (0.002f)
|
||||
#define CAR_ROTATION_SPEED (0.0035f)
|
||||
#define CRANE_MOVEMENT_SPEED (0.001f)
|
||||
#define HOOK_ANGLE_MOVEMENT_SPEED (0.004f)
|
||||
#define HOOK_OFFSET_MOVEMENT_SPEED (0.1f)
|
||||
#define HOOK_HEIGHT_MOVEMENT_SPEED (0.06f)
|
||||
|
||||
#define MESSAGE_SHOW_DURATION (4000)
|
||||
|
||||
#define MAX_DISTANCE (99999.9f)
|
||||
#define MIN_VALID_POSITION (-10000.0f)
|
||||
#define DEFAULT_OFFSET (20.0f)
|
||||
|
||||
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)
|
||||
{
|
||||
CarsCollectedMilitaryCrane = 0;
|
||||
NumCranes = 0;
|
||||
for (int i = 0; i < NUMSECTORS_X; i++) {
|
||||
for (int j = 0; j < NUMSECTORS_Y; j++) {
|
||||
for (CPtrNode* pNode = CWorld::GetSector(i, j)->m_lists[ENTITYLIST_BUILDINGS].first; pNode; pNode = pNode->next) {
|
||||
CEntity* pEntity = (CEntity*)pNode->item;
|
||||
if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
|
||||
MODELID_CRANE_2 == pEntity->GetModelIndex() ||
|
||||
MODELID_CRANE_3 == pEntity->GetModelIndex())
|
||||
AddThisOneCrane(pEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL).first; pNode; pNode = pNode->next) {
|
||||
CEntity* pEntity = (CEntity*)pNode->item;
|
||||
if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
|
||||
MODELID_CRANE_2 == pEntity->GetModelIndex() ||
|
||||
MODELID_CRANE_3 == pEntity->GetModelIndex())
|
||||
AddThisOneCrane(pEntity);
|
||||
}
|
||||
}
|
||||
|
||||
void CCranes::AddThisOneCrane(CEntity* pEntity)
|
||||
{
|
||||
pEntity->GetMatrix().ResetOrientation();
|
||||
if (NumCranes >= NUM_CRANES)
|
||||
return;
|
||||
CCrane* pCrane = &aCranes[NumCranes];
|
||||
pCrane->Init();
|
||||
pCrane->m_pCraneEntity = (CBuilding*)pEntity;
|
||||
pCrane->m_nCraneStatus = CCrane::NONE;
|
||||
pCrane->m_fHookAngle = NumCranes; // lol wtf
|
||||
while (pCrane->m_fHookAngle > TWOPI)
|
||||
pCrane->m_fHookAngle -= TWOPI;
|
||||
pCrane->m_fHookOffset = DEFAULT_OFFSET;
|
||||
pCrane->m_fHookHeight = DEFAULT_OFFSET;
|
||||
pCrane->m_nTimeForNextCheck = 0;
|
||||
pCrane->m_nCraneState = CCrane::IDLE;
|
||||
pCrane->m_bWasMilitaryCrane = false;
|
||||
pCrane->m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[NumCranes]);
|
||||
if (pCrane->m_nAudioEntity >= 0)
|
||||
DMAudio.SetEntityStatus(pCrane->m_nAudioEntity, 1);
|
||||
pCrane->m_bIsTop = (MODELID_CRANE_1 != pEntity->GetModelIndex());
|
||||
// Is this used to avoid military crane?
|
||||
if (pCrane->m_bIsTop || pEntity->GetPosition().y > 0.0f) {
|
||||
CObject* pHook = new CObject(MI_MAGNET, false);
|
||||
pHook->ObjectCreatedBy = MISSION_OBJECT;
|
||||
pHook->bUsesCollision = false;
|
||||
pHook->bExplosionProof = true;
|
||||
pHook->bAffectedByGravity = false;
|
||||
pCrane->m_pHook = pHook;
|
||||
pCrane->CalcHookCoordinates(&pCrane->m_vecHookCurPos.x, &pCrane->m_vecHookCurPos.y, &pCrane->m_vecHookCurPos.z);
|
||||
pCrane->SetHookMatrix();
|
||||
}
|
||||
else
|
||||
pCrane->m_pHook = nil;
|
||||
NumCranes++;
|
||||
}
|
||||
|
||||
void CCranes::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)
|
||||
{
|
||||
float fMinDistance = MAX_DISTANCE;
|
||||
float X = fPosX, Y = fPosY;
|
||||
if (X <= MIN_VALID_POSITION || Y <= MIN_VALID_POSITION) {
|
||||
X = fDropOffX;
|
||||
Y = fDropOffY;
|
||||
}
|
||||
int index = 0;
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
|
||||
if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
|
||||
fMinDistance = distance;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
#ifdef FIX_BUGS // classic
|
||||
if (fMinDistance == MAX_DISTANCE)
|
||||
return;
|
||||
#endif
|
||||
CCrane* pCrane = &aCranes[index];
|
||||
pCrane->m_fPickupX1 = fInfX;
|
||||
pCrane->m_fPickupX2 = fSupX;
|
||||
pCrane->m_fPickupY1 = fInfY;
|
||||
pCrane->m_fPickupY2 = fSupY;
|
||||
pCrane->m_vecDropoffTarget.x = fDropOffX;
|
||||
pCrane->m_vecDropoffTarget.y = fDropOffY;
|
||||
pCrane->m_vecDropoffTarget.z = fDropOffZ;
|
||||
pCrane->m_nCraneStatus = CCrane::ACTIVATED;
|
||||
pCrane->m_pVehiclePickedUp = nil;
|
||||
pCrane->m_nVehiclesCollected = 0;
|
||||
pCrane->m_fDropoffHeading = fHeading;
|
||||
pCrane->m_bIsCrusher = bIsCrusher;
|
||||
pCrane->m_bIsMilitaryCrane = bIsMilitary;
|
||||
bool military = true;
|
||||
if (!bIsMilitary && !pCrane->m_bWasMilitaryCrane)
|
||||
military = false;
|
||||
pCrane->m_bWasMilitaryCrane = military;
|
||||
pCrane->m_nTimeForNextCheck = 0;
|
||||
pCrane->m_nCraneState = CCrane::IDLE;
|
||||
float Z;
|
||||
if (bIsCrusher)
|
||||
Z = CRUSHER_Z;
|
||||
else if (bIsMilitary)
|
||||
Z = MILITARY_Z;
|
||||
else
|
||||
Z = CWorld::FindGroundZForCoord((fInfX + fSupX) / 2, (fInfY + fSupY) / 2);
|
||||
pCrane->FindParametersForTarget((fInfX + fSupX) / 2, (fInfY + fSupY) / 2, Z, &pCrane->m_fPickupAngle, &pCrane->m_fPickupDistance, &pCrane->m_fPickupHeight);
|
||||
pCrane->FindParametersForTarget(fDropOffX, fDropOffY, fDropOffZ, &pCrane->m_fDropoffAngle, &pCrane->m_fDropoffDistance, &pCrane->m_fDropoffHeight);
|
||||
}
|
||||
|
||||
void CCranes::DeActivateCrane(float X, float Y)
|
||||
{
|
||||
float fMinDistance = MAX_DISTANCE;
|
||||
int index = 0;
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
|
||||
if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
|
||||
fMinDistance = distance;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
#ifdef FIX_BUGS // classic
|
||||
if (fMinDistance == MAX_DISTANCE)
|
||||
return;
|
||||
#endif
|
||||
aCranes[index].m_nCraneStatus = CCrane::DEACTIVATED;
|
||||
aCranes[index].m_nCraneState = CCrane::IDLE;
|
||||
}
|
||||
|
||||
bool CCranes::IsThisCarPickedUp(float X, float Y, CVehicle* pVehicle)
|
||||
{
|
||||
int index = 0;
|
||||
bool result = false;
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
|
||||
if (distance < MAX_DISTANCE_TO_FIND_CRANE && aCranes[i].m_pVehiclePickedUp == pVehicle) {
|
||||
if (aCranes[i].m_nCraneStatus == CCrane::LIFTING_TARGET || aCranes[i].m_nCraneStatus == CCrane::ROTATING_TARGET)
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCranes::UpdateCranes(void)
|
||||
{
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
if (aCranes[i].m_bIsTop || aCranes[i].m_bIsCrusher ||
|
||||
(TheCamera.GetPosition().x + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().x &&
|
||||
TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().x &&
|
||||
TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().y &&
|
||||
TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().y))
|
||||
aCranes[i].Update();
|
||||
}
|
||||
}
|
||||
|
||||
void CCrane::Update(void)
|
||||
{
|
||||
if (CReplay::IsPlayingBack())
|
||||
return;
|
||||
if (((m_nCraneStatus == ACTIVATED || m_nCraneStatus == DEACTIVATED) &&
|
||||
Abs(TheCamera.GetGameCamPosition().x - m_pCraneEntity->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS &&
|
||||
Abs(TheCamera.GetGameCamPosition().y - m_pCraneEntity->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) ||
|
||||
m_nCraneState != IDLE) {
|
||||
switch (m_nCraneState) {
|
||||
case IDLE:
|
||||
if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, GetHeightToPickup()) &&
|
||||
CTimer::GetTimeInMilliseconds() > m_nTimeForNextCheck) {
|
||||
CWorld::AdvanceCurrentScanCode();
|
||||
#ifdef FIX_BUGS
|
||||
int xstart = max(0, CWorld::GetSectorIndexX(m_fPickupX1));
|
||||
int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fPickupX2));
|
||||
int ystart = max(0, CWorld::GetSectorIndexY(m_fPickupY1));
|
||||
int yend = min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(m_fPickupY2));
|
||||
#else
|
||||
int xstart = CWorld::GetSectorIndexX(m_fPickupX1);
|
||||
int xend = CWorld::GetSectorIndexX(m_fPickupX2);
|
||||
int ystart = CWorld::GetSectorIndexY(m_fPickupY1);
|
||||
int yend = CWorld::GetSectorIndexY(m_fPickupY1);
|
||||
#endif
|
||||
assert(xstart <= xend);
|
||||
assert(ystart <= yend);
|
||||
for (int i = xstart; i <= xend; i++) {
|
||||
for (int j = ystart; j <= yend; j++) {
|
||||
FindCarInSectorList(&CWorld::GetSector(i, j)->m_lists[ENTITYLIST_VEHICLES]);
|
||||
FindCarInSectorList(&CWorld::GetSector(i, j)->m_lists[ENTITYLIST_VEHICLES_OVERLAP]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GOING_TOWARDS_TARGET:
|
||||
if (m_pVehiclePickedUp){
|
||||
if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 ||
|
||||
m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 ||
|
||||
m_pVehiclePickedUp->GetPosition().y < m_fPickupY1 ||
|
||||
m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 ||
|
||||
m_pVehiclePickedUp->pDriver ||
|
||||
Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > CAR_MOVING_SPEED_THRESHOLD ||
|
||||
Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > CAR_MOVING_SPEED_THRESHOLD ||
|
||||
Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > CAR_MOVING_SPEED_THRESHOLD ||
|
||||
FindPlayerPed()->GetPedState() == PED_ENTER_CAR && // TODO: fix carjack bug
|
||||
FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) {
|
||||
m_pVehiclePickedUp = nil;
|
||||
m_nCraneState = IDLE;
|
||||
}
|
||||
else {
|
||||
float fAngle, fOffset, fHeight;
|
||||
FindParametersForTarget(
|
||||
m_pVehiclePickedUp->GetPosition().x,
|
||||
m_pVehiclePickedUp->GetPosition().y,
|
||||
m_pVehiclePickedUp->GetPosition().z + m_pVehiclePickedUp->GetColModel()->boundingBox.max.z,
|
||||
&fAngle, &fOffset, &fHeight);
|
||||
if (GoTowardsTarget(fAngle, fOffset, fHeight)) {
|
||||
CVector distance = m_pVehiclePickedUp->GetPosition() - m_vecHookCurPos;
|
||||
distance.z += m_pVehiclePickedUp->GetColModel()->boundingBox.max.z;
|
||||
if (distance.MagnitudeSqr() < SQR(DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT)) {
|
||||
m_nCraneState = GOING_TOWARDS_TARGET_ONLY_HEIGHT;
|
||||
m_vecHookVelocity *= 0.4f;
|
||||
m_pVehiclePickedUp->bLightsOn = false;
|
||||
m_pVehiclePickedUp->bUsesCollision = false;
|
||||
if (m_bIsCrusher)
|
||||
m_pVehiclePickedUp->bCollisionProof = true;
|
||||
DMAudio.PlayOneShot(m_nAudioEntity, SOUND_CRANE_PICKUP, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_nCraneState = IDLE;
|
||||
break;
|
||||
case LIFTING_TARGET:
|
||||
RotateCarriedCarProperly();
|
||||
if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoff(), CRANE_SLOWDOWN_MULTIPLIER))
|
||||
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, MESSAGE_SHOW_DURATION, -1);
|
||||
}
|
||||
CWorld::Remove(m_pVehiclePickedUp);
|
||||
delete m_pVehiclePickedUp;
|
||||
}
|
||||
}
|
||||
m_pVehiclePickedUp = nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DROPPING_TARGET:
|
||||
if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoffHeight(), CRANE_SLOWDOWN_MULTIPLIER)) {
|
||||
m_nCraneState = IDLE;
|
||||
m_nTimeForNextCheck = CTimer::GetTimeInMilliseconds() + 10000;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CVector vecHook;
|
||||
CalcHookCoordinates(&vecHook.x, &vecHook.y, &vecHook.z);
|
||||
m_vecHookVelocity += ((CVector2D)vecHook - (CVector2D)m_vecHookCurPos) * CTimer::GetTimeStep() * CRANE_MOVEMENT_SPEED;
|
||||
m_vecHookVelocity *= Pow(0.98f, CTimer::GetTimeStep());
|
||||
m_vecHookCurPos.x += m_vecHookVelocity.x * CTimer::GetTimeStep();
|
||||
m_vecHookCurPos.y += m_vecHookVelocity.y * CTimer::GetTimeStep();
|
||||
m_vecHookCurPos.z = vecHook.z;
|
||||
switch (m_nCraneState) {
|
||||
case LIFTING_TARGET:
|
||||
case GOING_TOWARDS_TARGET_ONLY_HEIGHT:
|
||||
case ROTATING_TARGET:
|
||||
if (m_pVehiclePickedUp) {
|
||||
m_pVehiclePickedUp->GetPosition() = CVector(m_vecHookCurPos.x, m_vecHookCurPos.y, m_vecHookCurPos.z - m_pVehiclePickedUp->GetColModel()->boundingBox.max.z);
|
||||
m_pVehiclePickedUp->SetMoveSpeed(0.0f, 0.0f, 0.0f);
|
||||
CVector up(vecHook.x - m_vecHookCurPos.x, vecHook.y - m_vecHookCurPos.y, 20.0f);
|
||||
up.Normalise();
|
||||
m_pVehiclePickedUp->GetRight() = CrossProduct(m_pVehiclePickedUp->GetForward(), up);
|
||||
m_pVehiclePickedUp->GetForward() = CrossProduct(up, m_pVehiclePickedUp->GetRight());
|
||||
m_pVehiclePickedUp->GetUp() = up;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int16 rnd = (m_pCraneEntity->m_randomSeed + (CTimer::GetTimeInMilliseconds() >> 11)) & 0xF;
|
||||
// 16 options, lasting 2048 ms each
|
||||
// a bit awkward: why there are 4 periods for -= and 6 for +=? is it a bug?
|
||||
if (rnd < 4) {
|
||||
m_fHookAngle -= OSCILLATION_SPEED * CTimer::GetTimeStep();
|
||||
if (m_fHookAngle < 0.0f)
|
||||
m_fHookAngle += TWOPI;
|
||||
}
|
||||
else if (rnd > 5 && rnd < 12) {
|
||||
m_fHookAngle += OSCILLATION_SPEED * CTimer::GetTimeStep();
|
||||
if (m_fHookAngle > TWOPI)
|
||||
m_fHookAngle -= TWOPI;
|
||||
}
|
||||
CalcHookCoordinates(&m_vecHookCurPos.x, &m_vecHookCurPos.y, &m_vecHookCurPos.z);
|
||||
m_vecHookVelocity.x = m_vecHookVelocity.y = 0.0f;
|
||||
}
|
||||
float fCos = Cos(m_fHookAngle);
|
||||
float fSin = Sin(m_fHookAngle);
|
||||
m_pCraneEntity->GetRight().x = fCos;
|
||||
m_pCraneEntity->GetForward().y = fCos;
|
||||
m_pCraneEntity->GetRight().y = fSin;
|
||||
m_pCraneEntity->GetForward().x = -fSin;
|
||||
m_pCraneEntity->GetMatrix().UpdateRW();
|
||||
m_pCraneEntity->UpdateRwFrame();
|
||||
SetHookMatrix();
|
||||
}
|
||||
|
||||
bool CCrane::RotateCarriedCarProperly()
|
||||
{
|
||||
if (m_fDropoffHeading <= 0.0f)
|
||||
return true;
|
||||
if (!m_pVehiclePickedUp)
|
||||
return true;
|
||||
float fAngleDelta = m_fDropoffHeading - CGeneral::GetATanOfXY(m_pVehiclePickedUp->GetForward().x, m_pVehiclePickedUp->GetForward().y);
|
||||
while (fAngleDelta < -HALFPI)
|
||||
fAngleDelta += PI;
|
||||
while (fAngleDelta > HALFPI)
|
||||
fAngleDelta -= PI;
|
||||
float fDeltaThisFrame = CAR_ROTATION_SPEED * CTimer::GetTimeStep();
|
||||
if (Abs(fAngleDelta) <= fDeltaThisFrame) // no rotation is actually applied?
|
||||
return true;
|
||||
m_pVehiclePickedUp->GetMatrix().RotateZ(Abs(fDeltaThisFrame));
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCrane::FindCarInSectorList(CPtrList* pList)
|
||||
{
|
||||
CPtrNode* node;
|
||||
for (node = pList->first; node; node = node->next) {
|
||||
CVehicle* pVehicle = (CVehicle*)node->item;
|
||||
if (pVehicle->m_scanCode == CWorld::GetCurrentScanCode())
|
||||
continue;
|
||||
pVehicle->m_scanCode = CWorld::GetCurrentScanCode();
|
||||
if (pVehicle->GetPosition().x < m_fPickupX1 || pVehicle->GetPosition().x > m_fPickupX2 ||
|
||||
pVehicle->GetPosition().y < m_fPickupY1 || pVehicle->GetPosition().y > m_fPickupY2)
|
||||
continue;
|
||||
if (pVehicle->pDriver)
|
||||
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, MESSAGE_SHOW_DURATION, -1); // Crane cannot lift this vehicle.
|
||||
else if (DoesCranePickUpThisCarType(pVehicle->GetModelIndex()))
|
||||
CGarages::TriggerMessage("GA_20", -1, MESSAGE_SHOW_DURATION, -1); // We got more of these than we can shift. Sorry man, no deal.
|
||||
else
|
||||
CGarages::TriggerMessage("GA_19", -1, MESSAGE_SHOW_DURATION, -1); // We're not interested in that model.
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_pVehiclePickedUp = pVehicle;
|
||||
pVehicle->RegisterReference((CEntity**)&m_pVehiclePickedUp);
|
||||
m_nCraneState = GOING_TOWARDS_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
|
||||
{
|
||||
if (m_bIsCrusher) {
|
||||
return mi != MI_FIRETRUCK &&
|
||||
mi != MI_TRASH &&
|
||||
#ifndef FIX_BUGS // why
|
||||
mi != MI_BLISTA &&
|
||||
#endif
|
||||
mi != MI_SECURICA &&
|
||||
mi != MI_BUS &&
|
||||
mi != MI_DODO &&
|
||||
mi != MI_RHINO;
|
||||
}
|
||||
if (m_bIsMilitaryCrane) {
|
||||
return mi == MI_FIRETRUCK ||
|
||||
mi == MI_AMBULAN ||
|
||||
mi == MI_ENFORCER ||
|
||||
mi == MI_FBICAR ||
|
||||
mi == MI_RHINO ||
|
||||
mi == MI_BARRACKS ||
|
||||
mi == MI_POLICE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
|
||||
{
|
||||
switch (mi) {
|
||||
case MI_FIRETRUCK: return (CCranes::CarsCollectedMilitaryCrane & 1);
|
||||
case MI_AMBULAN: return (CCranes::CarsCollectedMilitaryCrane & 2);
|
||||
case MI_ENFORCER: return (CCranes::CarsCollectedMilitaryCrane & 4);
|
||||
case MI_FBICAR: return (CCranes::CarsCollectedMilitaryCrane & 8);
|
||||
case MI_RHINO: return (CCranes::CarsCollectedMilitaryCrane & 0x10);
|
||||
case MI_BARRACKS: return (CCranes::CarsCollectedMilitaryCrane & 0x20);
|
||||
case MI_POLICE: return (CCranes::CarsCollectedMilitaryCrane & 0x40);
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
|
||||
{
|
||||
switch (mi) {
|
||||
case MI_FIRETRUCK: CCranes::CarsCollectedMilitaryCrane |= 1; break;
|
||||
case MI_AMBULAN: CCranes::CarsCollectedMilitaryCrane |= 2; break;
|
||||
case MI_ENFORCER: CCranes::CarsCollectedMilitaryCrane |= 4; break;
|
||||
case MI_FBICAR: CCranes::CarsCollectedMilitaryCrane |= 8; break;
|
||||
case MI_RHINO: CCranes::CarsCollectedMilitaryCrane |= 0x10; break;
|
||||
case MI_BARRACKS: CCranes::CarsCollectedMilitaryCrane |= 0x20; break;
|
||||
case MI_POLICE: CCranes::CarsCollectedMilitaryCrane |= 0x40; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()
|
||||
{
|
||||
return (CCranes::CarsCollectedMilitaryCrane & 0x7F) == 0x7F;
|
||||
}
|
||||
|
||||
bool CCrane::GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier)
|
||||
{
|
||||
bool bAngleMovementFinished, bOffsetMovementFinished, bHeightMovementFinished;
|
||||
float fHookAngleDelta = fAngleToTarget - m_fHookAngle;
|
||||
while (fHookAngleDelta > PI)
|
||||
fHookAngleDelta -= TWOPI;
|
||||
while (fHookAngleDelta < -PI)
|
||||
fHookAngleDelta += TWOPI;
|
||||
float fHookAngleChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_ANGLE_MOVEMENT_SPEED;
|
||||
if (Abs(fHookAngleDelta) < fHookAngleChangeThisFrame) {
|
||||
m_fHookAngle = fAngleToTarget;
|
||||
bAngleMovementFinished = true;
|
||||
}
|
||||
else {
|
||||
if (fHookAngleDelta < 0.0f) {
|
||||
m_fHookAngle -= fHookAngleChangeThisFrame;
|
||||
if (m_fHookAngle < 0.0f)
|
||||
m_fHookAngle += TWOPI;
|
||||
}
|
||||
else {
|
||||
m_fHookAngle += fHookAngleChangeThisFrame;
|
||||
if (m_fHookAngle > TWOPI)
|
||||
m_fHookAngle -= TWOPI;
|
||||
}
|
||||
bAngleMovementFinished = false;
|
||||
}
|
||||
float fHookOffsetDelta = fDistanceToTarget - m_fHookOffset;
|
||||
float fHookOffsetChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_OFFSET_MOVEMENT_SPEED;
|
||||
if (Abs(fHookOffsetDelta) < fHookOffsetChangeThisFrame) {
|
||||
m_fHookOffset = fDistanceToTarget;
|
||||
bOffsetMovementFinished = true;
|
||||
}
|
||||
else {
|
||||
if (fHookOffsetDelta < 0.0f)
|
||||
m_fHookOffset -= fHookOffsetChangeThisFrame;
|
||||
else
|
||||
m_fHookOffset += fHookOffsetChangeThisFrame;
|
||||
bOffsetMovementFinished = false;
|
||||
}
|
||||
float fHookHeightDelta = fTargetHeight - m_fHookHeight;
|
||||
float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
|
||||
if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
|
||||
m_fHookHeight = fTargetHeight;
|
||||
bHeightMovementFinished = true;
|
||||
}
|
||||
else {
|
||||
if (fHookHeightDelta < 0.0f)
|
||||
m_fHookHeight -= fHookHeightChangeThisFrame;
|
||||
else
|
||||
m_fHookHeight += fHookHeightChangeThisFrame;
|
||||
bHeightMovementFinished = false;
|
||||
}
|
||||
return bAngleMovementFinished && bOffsetMovementFinished && bHeightMovementFinished;
|
||||
}
|
||||
|
||||
bool CCrane::GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier)
|
||||
{
|
||||
bool bHeightMovementFinished;
|
||||
float fHookHeightDelta = fTargetHeight - m_fHookHeight;
|
||||
float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
|
||||
if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
|
||||
m_fHookHeight = fTargetHeight;
|
||||
bHeightMovementFinished = true;
|
||||
}
|
||||
else {
|
||||
if (fHookHeightDelta < 0.0f)
|
||||
m_fHookHeight -= fHookHeightChangeThisFrame;
|
||||
else
|
||||
m_fHookHeight += fHookHeightChangeThisFrame;
|
||||
bHeightMovementFinished = false;
|
||||
}
|
||||
return bHeightMovementFinished;
|
||||
}
|
||||
|
||||
void CCrane::FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight)
|
||||
{
|
||||
*pAngle = CGeneral::GetATanOfXY(X - m_pCraneEntity->GetPosition().x, Y - m_pCraneEntity->GetPosition().y);
|
||||
*pDistance = ((CVector2D(X, Y) - (CVector2D)m_pCraneEntity->GetPosition())).Magnitude();
|
||||
*pHeight = Z;
|
||||
}
|
||||
|
||||
void CCrane::CalcHookCoordinates(float* pX, float* pY, float* pZ)
|
||||
{
|
||||
*pX = Cos(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().x;
|
||||
*pY = Sin(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().y;
|
||||
*pZ = m_fHookHeight;
|
||||
}
|
||||
|
||||
void CCrane::SetHookMatrix()
|
||||
{
|
||||
if (!m_pHook)
|
||||
return;
|
||||
m_pHook->GetPosition() = m_vecHookCurPos;
|
||||
CVector up(m_vecHookInitPos.x - m_vecHookCurPos.x, m_vecHookInitPos.y - m_vecHookCurPos.y, 20.0f);
|
||||
up.Normalise();
|
||||
m_pHook->GetRight() = CrossProduct(CVector(0.0f, 1.0f, 0.0f), up);
|
||||
m_pHook->GetForward() = CrossProduct(up, m_pHook->GetRight());
|
||||
m_pHook->GetUp() = up;
|
||||
m_pHook->SetOrientation(0.0f, 0.0f, -HALFPI);
|
||||
m_pHook->GetMatrix().UpdateRW();
|
||||
m_pHook->UpdateRwFrame();
|
||||
CWorld::Remove(m_pHook);
|
||||
CWorld::Add(m_pHook);
|
||||
}
|
||||
|
||||
bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle)
|
||||
{
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
if (pVehicle == aCranes[i].m_pVehiclePickedUp) {
|
||||
switch (aCranes[i].m_nCraneState) {
|
||||
case CCrane::GOING_TOWARDS_TARGET_ONLY_HEIGHT:
|
||||
case CCrane::LIFTING_TARGET:
|
||||
case CCrane::ROTATING_TARGET:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle)
|
||||
{
|
||||
for (int i = 0; i < NumCranes; i++) {
|
||||
if (pVehicle == aCranes[i].m_pVehiclePickedUp)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
#include "World.h"
|
||||
|
||||
class CVehicle;
|
||||
class CEntity;
|
||||
class CObject;
|
||||
class CBuilding;
|
||||
|
||||
class CCrane
|
||||
{
|
||||
public:
|
||||
enum CraneState : uint8 {
|
||||
IDLE = 0,
|
||||
GOING_TOWARDS_TARGET = 1,
|
||||
LIFTING_TARGET = 2,
|
||||
GOING_TOWARDS_TARGET_ONLY_HEIGHT = 3,
|
||||
ROTATING_TARGET = 4,
|
||||
DROPPING_TARGET = 5
|
||||
};
|
||||
enum CraneStatus : uint8 {
|
||||
NONE = 0,
|
||||
ACTIVATED = 1,
|
||||
DEACTIVATED = 2
|
||||
};
|
||||
CBuilding *m_pCraneEntity;
|
||||
CObject *m_pHook;
|
||||
int32 m_nAudioEntity;
|
||||
float m_fPickupX1;
|
||||
float m_fPickupX2;
|
||||
float m_fPickupY1;
|
||||
float m_fPickupY2;
|
||||
CVector m_vecDropoffTarget;
|
||||
float m_fDropoffHeading;
|
||||
float m_fPickupAngle;
|
||||
float m_fDropoffAngle;
|
||||
float m_fPickupDistance;
|
||||
float m_fDropoffDistance;
|
||||
float m_fPickupHeight;
|
||||
float m_fDropoffHeight;
|
||||
float m_fHookAngle;
|
||||
float m_fHookOffset;
|
||||
float m_fHookHeight;
|
||||
CVector m_vecHookInitPos;
|
||||
CVector m_vecHookCurPos;
|
||||
CVector2D m_vecHookVelocity;
|
||||
CVehicle *m_pVehiclePickedUp;
|
||||
uint32 m_nTimeForNextCheck;
|
||||
CraneStatus m_nCraneStatus;
|
||||
CraneState m_nCraneState;
|
||||
uint8 m_nVehiclesCollected;
|
||||
bool m_bIsCrusher;
|
||||
bool m_bIsMilitaryCrane;
|
||||
bool m_bWasMilitaryCrane;
|
||||
bool m_bIsTop;
|
||||
|
||||
void Init(void) { memset(this, 0, sizeof(*this)); }
|
||||
void Update(void);
|
||||
bool RotateCarriedCarProperly(void);
|
||||
void FindCarInSectorList(CPtrList* pList);
|
||||
bool DoesCranePickUpThisCarType(uint32 mi);
|
||||
bool GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier = 1.0f);
|
||||
bool GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier = 1.0f);
|
||||
void FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight);
|
||||
void CalcHookCoordinates(float* pX, float* pY, float* pZ);
|
||||
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");
|
||||
|
||||
class CCranes
|
||||
{
|
||||
public:
|
||||
static void InitCranes(void);
|
||||
static void AddThisOneCrane(CEntity* pCraneEntity);
|
||||
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 fX, float fY);
|
||||
static bool IsThisCarPickedUp(float fX, float fY, CVehicle* pVehicle);
|
||||
static void UpdateCranes(void);
|
||||
static bool DoesMilitaryCraneHaveThisOneAlready(uint32 mi);
|
||||
static void RegisterCarForMilitaryCrane(uint32 mi);
|
||||
static bool HaveAllCarsBeenCollectedByMilitaryCrane(void);
|
||||
static bool IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle);
|
||||
static bool IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle);
|
||||
static void Save(uint8* buf, uint32* size);
|
||||
|
||||
static uint32& CarsCollectedMilitaryCrane;
|
||||
static int32& NumCranes;
|
||||
static CCrane(&aCranes)[NUM_CRANES];
|
||||
};
|
||||
|
||||
void CranesLoad(uint8*, uint32); // is this really outside CCranes?
|
@ -1,89 +0,0 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "Gangs.h"
|
||||
#include "Weapon.h"
|
||||
|
||||
//CGangInfo(&CGangs::Gang)[NUM_GANGS] = *(CGangInfo(*)[NUM_GANGS])*(uintptr*)0x6EDF78;
|
||||
CGangInfo CGangs::Gang[NUM_GANGS];
|
||||
|
||||
CGangInfo::CGangInfo() :
|
||||
m_nVehicleMI(MI_BUS),
|
||||
m_nPedModelOverride(-1),
|
||||
m_Weapon1(WEAPONTYPE_UNARMED),
|
||||
m_Weapon2(WEAPONTYPE_UNARMED)
|
||||
{}
|
||||
|
||||
void CGangs::Initialise(void)
|
||||
{
|
||||
Gang[GANG_MAFIA].m_nVehicleMI = MI_MAFIA;
|
||||
Gang[GANG_TRIAD].m_nVehicleMI = MI_BELLYUP;
|
||||
Gang[GANG_DIABLOS].m_nVehicleMI = MI_DIABLOS;
|
||||
Gang[GANG_YAKUZA].m_nVehicleMI = MI_YAKUZA;
|
||||
Gang[GANG_YARDIE].m_nVehicleMI = MI_YARDIE;
|
||||
Gang[GANG_COLUMB].m_nVehicleMI = MI_COLUMB;
|
||||
Gang[GANG_HOODS].m_nVehicleMI = MI_HOODS;
|
||||
Gang[GANG_7].m_nVehicleMI = -1;
|
||||
Gang[GANG_8].m_nVehicleMI = -1;
|
||||
#ifdef FIX_BUGS
|
||||
for (int i = 0; i < NUM_GANGS; i++)
|
||||
Gang[i].m_nPedModelOverride = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGangs::SetGangVehicleModel(int16 gang, int32 model)
|
||||
{
|
||||
GetGangInfo(gang)->m_nVehicleMI = model;
|
||||
}
|
||||
|
||||
void CGangs::SetGangWeapons(int16 gang, int32 weapon1, int32 weapon2)
|
||||
{
|
||||
CGangInfo *gi = GetGangInfo(gang);
|
||||
gi->m_Weapon1 = weapon1;
|
||||
gi->m_Weapon2 = weapon2;
|
||||
}
|
||||
|
||||
void CGangs::SetGangPedModelOverride(int16 gang, int8 ovrd)
|
||||
{
|
||||
GetGangInfo(gang)->m_nPedModelOverride = ovrd;
|
||||
}
|
||||
|
||||
int8 CGangs::GetGangPedModelOverride(int16 gang)
|
||||
{
|
||||
return GetGangInfo(gang)->m_nPedModelOverride;
|
||||
}
|
||||
|
||||
void CGangs::SaveAllGangData(uint8 *buf, uint32 *size)
|
||||
{
|
||||
INITSAVEBUF
|
||||
|
||||
*size = SAVE_HEADER_SIZE + sizeof(Gang);
|
||||
WriteSaveHeader(buf, 'G','N','G','\0', *size - SAVE_HEADER_SIZE);
|
||||
for (int i = 0; i < NUM_GANGS; i++)
|
||||
WriteSaveBuf(buf, Gang[i]);
|
||||
|
||||
VALIDATESAVEBUF(*size);
|
||||
}
|
||||
|
||||
void CGangs::LoadAllGangData(uint8 *buf, uint32 size)
|
||||
{
|
||||
Initialise();
|
||||
|
||||
INITSAVEBUF
|
||||
// original: SkipSaveBuf(buf, SAVE_HEADER_SIZE);
|
||||
CheckSaveHeader(buf, 'G','N','G','\0', size - SAVE_HEADER_SIZE);
|
||||
|
||||
for (int i = 0; i < NUM_GANGS; i++)
|
||||
Gang[i] = ReadSaveBuf<CGangInfo>(buf);
|
||||
VALIDATESAVEBUF(size);
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x4C3FB0, CGangs::Initialise, PATCH_JUMP);
|
||||
InjectHook(0x4C4010, CGangs::SetGangVehicleModel, PATCH_JUMP);
|
||||
InjectHook(0x4C4030, CGangs::SetGangWeapons, PATCH_JUMP);
|
||||
InjectHook(0x4C4050, CGangs::SetGangPedModelOverride, PATCH_JUMP);
|
||||
InjectHook(0x4C4070, CGangs::GetGangPedModelOverride, PATCH_JUMP);
|
||||
InjectHook(0x4C4080, CGangs::SaveAllGangData, PATCH_JUMP);
|
||||
InjectHook(0x4C4100, CGangs::LoadAllGangData, PATCH_JUMP);
|
||||
ENDPATCHES
|
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct CGangInfo
|
||||
{
|
||||
int32 m_nVehicleMI;
|
||||
int8 m_nPedModelOverride;
|
||||
int32 m_Weapon1;
|
||||
int32 m_Weapon2;
|
||||
|
||||
CGangInfo();
|
||||
};
|
||||
|
||||
static_assert(sizeof(CGangInfo) == 0x10, "CGangInfo: error");
|
||||
|
||||
enum {
|
||||
GANG_MAFIA = 0,
|
||||
GANG_TRIAD,
|
||||
GANG_DIABLOS,
|
||||
GANG_YAKUZA,
|
||||
GANG_YARDIE,
|
||||
GANG_COLUMB,
|
||||
GANG_HOODS,
|
||||
GANG_7,
|
||||
GANG_8,
|
||||
NUM_GANGS
|
||||
};
|
||||
|
||||
class CGangs
|
||||
{
|
||||
public:
|
||||
static void Initialise(void);
|
||||
static void SetGangVehicleModel(int16, int32);
|
||||
static void SetGangWeapons(int16, int32, int32);
|
||||
static void SetGangPedModelOverride(int16, int8);
|
||||
static int8 GetGangPedModelOverride(int16);
|
||||
static void SaveAllGangData(uint8 *, uint32 *);
|
||||
static void LoadAllGangData(uint8 *, uint32);
|
||||
|
||||
static int32 GetGangVehicleModel(int16 gang) { return Gang[gang].m_nVehicleMI; }
|
||||
static CGangInfo *GetGangInfo(int16 gang) { return &Gang[gang]; }
|
||||
|
||||
private:
|
||||
static CGangInfo Gang[NUM_GANGS];
|
||||
};
|
Reference in New Issue
Block a user