summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/control/Script.cpp215
-rw-r--r--src/control/Script.h17
-rw-r--r--src/core/FileLoader.cpp37
-rw-r--r--src/core/FileLoader.h1
-rw-r--r--src/core/Game.cpp2
-rw-r--r--src/core/PlayerInfo.cpp4
-rw-r--r--src/core/config.h2
-rw-r--r--src/entities/Building.cpp22
-rw-r--r--src/entities/Building.h2
-rw-r--r--src/entities/Dummy.cpp15
-rw-r--r--src/entities/Dummy.h2
-rw-r--r--src/entities/Entity.cpp17
-rw-r--r--src/entities/Entity.h2
-rw-r--r--src/objects/Object.cpp15
-rw-r--r--src/objects/Object.h2
-rw-r--r--src/peds/Ped.cpp27
-rw-r--r--src/peds/Ped.h3
-rw-r--r--src/render/Occlusion.cpp36
-rw-r--r--src/render/Occlusion.h19
-rw-r--r--src/vehicles/HandlingMgr.cpp244
-rw-r--r--src/vehicles/HandlingMgr.h78
-rw-r--r--src/vehicles/Vehicle.cpp19
-rw-r--r--src/vehicles/Vehicle.h1
23 files changed, 589 insertions, 193 deletions
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index a1287d09..2ad1e9de 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -54,6 +54,7 @@
#include "Remote.h"
#include "Replay.h"
#include "Restart.h"
+#include "RoadBlocks.h"
#include "RpAnimBlend.h"
#include "Rubbish.h"
#include "Shadows.h"
@@ -92,13 +93,10 @@
uint8 CTheScripts::ScriptSpace[SIZE_SCRIPT_SPACE];
CRunningScript CTheScripts::ScriptsArray[MAX_NUM_SCRIPTS];
-int32 CTheScripts::BaseBriefIdForContact[MAX_NUM_CONTACTS];
-int32 CTheScripts::OnAMissionForContactFlag[MAX_NUM_CONTACTS];
intro_text_line CTheScripts::IntroTextLines[MAX_NUM_INTRO_TEXT_LINES];
intro_script_rectangle CTheScripts::IntroRectangles[MAX_NUM_INTRO_RECTANGLES];
CSprite2d CTheScripts::ScriptSprites[MAX_NUM_SCRIPT_SRPITES];
script_sphere_struct CTheScripts::ScriptSphereArray[MAX_NUM_SCRIPT_SPHERES];
-tCollectiveData CTheScripts::CollectiveArray[MAX_NUM_COLLECTIVES];
tUsedObject CTheScripts::UsedObjectArray[MAX_NUM_USED_OBJECTS];
int32 CTheScripts::MultiScriptArray[MAX_NUM_MISSION_SCRIPTS];
tBuildingSwap CTheScripts::BuildingSwapArray[MAX_NUM_BUILDING_SWAPS];
@@ -119,8 +117,6 @@ uint16 CTheScripts::NumberOfMissionScripts;
uint32 CTheScripts::LargestMissionScriptSize;
uint32 CTheScripts::MainScriptSize;
uint8 CTheScripts::FailCurrentMission;
-uint8 CTheScripts::CountdownToMakePlayerUnsafe;
-uint8 CTheScripts::DelayMakingPlayerUnsafeThisTime;
uint16 CTheScripts::NumScriptDebugLines;
uint16 CTheScripts::NumberOfIntroRectanglesThisFrame;
uint16 CTheScripts::NumberOfIntroTextLinesThisFrame;
@@ -131,6 +127,11 @@ CStuckCarCheck CTheScripts::StuckCars;
uint16 CTheScripts::CommandsExecuted;
uint16 CTheScripts::ScriptsUpdated;
int32 ScriptParams[32];
+uint8 CTheScripts::RiotIntensity;
+uint32 CTheScripts::LastMissionPassedTime;
+uint16 CTheScripts::NumberOfExclusiveMissionScripts;
+bool CTheScripts::bPlayerHasMetDebbieHarry;
+bool CTheScripts::bPlayerIsInTheStatium;
const uint32 CRunningScript::nSaveStructSize =
@@ -272,9 +273,19 @@ void CMissionCleanup::Process()
CPopulation::m_AllRandomPedsThisType = -1;
CPopulation::PedDensityMultiplier = 1.0f;
CCarCtrl::CarDensityMultiplier = 1.0f;
+ CPed::nThreatReactionRangeMultiplier = 1;
+ CPed::nEnterCarRangeMultiplier = 1;
FindPlayerPed()->m_pWanted->m_fCrimeSensitivity = 1.0f;
- TheCamera.Restore();
+ //CRoadBlocks::ClearScriptRoadblocks() // TODO(MIAMI)
+ CRouteNode::Initialise();
+ if (!CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
+ TheCamera.Restore();
TheCamera.SetWideScreenOff();
+ // TODO(MIAMI)
+ //CSpecialFX::bLiftCam = false;
+ //CSpecialFX::bVideoCam = false;
+ //CTimeCycle::StopExtraColour(0);
+ // TODO(MIAMI): change this to loop when it supports parameters
DMAudio.ClearMissionAudio();
CWeather::ReleaseWeather();
for (int i = 0; i < NUM_OF_SPECIAL_CHARS; i++)
@@ -283,14 +294,18 @@ void CMissionCleanup::Process()
CStreaming::SetMissionDoesntRequireModel(MI_CUTOBJ01 + i);
CStreaming::ms_disableStreaming = false;
CHud::m_ItemToFlash = -1;
- CHud::SetHelpMessage(nil, false);
+ CHud::SetHelpMessage(nil, false); // TODO(MIAMI): third parameter is false
CUserDisplay::OnscnTimer.m_bDisabled = false;
+ CTheScripts::RemoveScriptTextureDictionary();
CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByCops = false;
CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
CWorld::Players[0].MakePlayerSafe(false);
-
+ //TODO(MIAMI): drunkenness, enable drive by
+ //DMAudio::ShutUpPlayerTalking(0);
CVehicle::bDisableRemoteDetonation = false;
-
+ //CVehicle::bDisableRemoteDetonationOnContact = false; // TODO(MIAMI)
+ //CGameLogic::ClearShortCut(); // TODO(MIAMI)
+ CTheScripts::RiotIntensity = 0;
CTheScripts::StoreVehicleIndex = -1;
CTheScripts::StoreVehicleWasRandom = true;
CTheScripts::UpsideDownCars.Init();
@@ -513,7 +528,6 @@ void CRunningScript::CollectParameters(uint32* pIp, int16 total)
int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip)
{
uint32* pIp = &ip;
- float tmp;
switch (CTheScripts::Read1ByteFromScript(pIp))
{
case ARGUMENT_INT32:
@@ -527,8 +541,7 @@ int32 CRunningScript::CollectNextParameterWithoutIncreasingPC(uint32 ip)
case ARGUMENT_INT16:
return CTheScripts::Read2BytesFromScript(pIp);
case ARGUMENT_FLOAT:
- tmp = CTheScripts::ReadFloatFromScript(pIp);
- return *(int32*)&tmp;
+ return CTheScripts::Read4BytesFromScript(pIp);
default:
assert(0);
}
@@ -637,14 +650,7 @@ void CTheScripts::Init()
StoreVehicleIndex = -1;
StoreVehicleWasRandom = true;
OnAMissionFlag = 0;
- for (int i = 0; i < MAX_NUM_CONTACTS; i++){
- BaseBriefIdForContact[i] = 0;
- OnAMissionForContactFlag[i] = 0;
- }
- for (int i = 0; i < MAX_NUM_COLLECTIVES; i++){
- CollectiveArray[i].index = -1;
- CollectiveArray[i].unk_data = 0;
- }
+ LastMissionPassedTime = (uint32)-1;
NextFreeCollectiveIndex = 0;
LastRandomPedId = -1;
for (int i = 0; i < MAX_NUM_USED_OBJECTS; i++){
@@ -658,15 +664,17 @@ void CTheScripts::Init()
bUsingAMultiScriptFile = true;
for (int i = 0; i < MAX_NUM_MISSION_SCRIPTS; i++)
MultiScriptArray[i] = 0;
+ NumberOfExclusiveMissionScripts = 0;
NumberOfMissionScripts = 0;
LargestMissionScriptSize = 0;
MainScriptSize = 0;
ReadMultiScriptFileOffsetsFromScript();
FailCurrentMission = 0;
- CountdownToMakePlayerUnsafe = 0;
DbgFlag = false;
- DelayMakingPlayerUnsafeThisTime = 1;
NumScriptDebugLines = 0;
+ RiotIntensity = 0;
+ bPlayerHasMetDebbieHarry = false;
+ bPlayerIsInTheStatium = false;
for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++){
ScriptSphereArray[i].m_bInUse = false;
ScriptSphereArray[i].m_Index = 1;
@@ -687,6 +695,7 @@ void CTheScripts::Init()
IntroRectangles[i].m_sColor = CRGBA(255, 255, 255, 255);
}
NumberOfIntroRectanglesThisFrame = 0;
+ RemoveScriptTextureDictionary();
for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++){
BuildingSwapArray[i].m_pBuilding = nil;
BuildingSwapArray[i].m_nNewModel = -1;
@@ -696,6 +705,15 @@ void CTheScripts::Init()
InvisibilitySettingArray[i] = nil;
}
+void CTheScripts::RemoveScriptTextureDictionary()
+{
+ for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++)
+ CTheScripts::ScriptSprites[i].Delete();
+ int slot = CTxdStore::FindTxdSlot("script");
+ if (slot != -1)
+ CTxdStore::RemoveTxd(slot);
+}
+
void CRunningScript::RemoveScriptFromList(CRunningScript** ppScript)
{
if (prev)
@@ -739,10 +757,6 @@ void CTheScripts::Process()
DrawScriptSpheres();
if (FailCurrentMission)
--FailCurrentMission;
- if (CountdownToMakePlayerUnsafe){
- if (--CountdownToMakePlayerUnsafe == 0)
- CWorld::Players[0].MakePlayerSafe(false);
- }
if (UseTextCommands){
for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++)
IntroTextLines[i].Reset();
@@ -849,6 +863,7 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
case COMMAND_WAIT:
CollectParameters(&m_nIp, 1);
m_nWakeTime = CTimer::GetTimeInMilliseconds() + ScriptParams[0];
+ m_bSkipWakeTime = false;
return 1;
case COMMAND_GOTO:
CollectParameters(&m_nIp, 1);
@@ -1262,13 +1277,11 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
UpdateCompareFlag(*ptr1 == *ptr2);
return 0;
}
- /* Following commands are not implemented, and go to default case
- case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER:
- case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER:
- case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR:
- case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR:
- case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR:
- */
+ //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER:
+ //case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER:
+ //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR:
+ //case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR:
+ //case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR:
case COMMAND_IS_FLOAT_VAR_EQUAL_TO_NUMBER:
{
int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
@@ -1304,19 +1317,18 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2);
return 0;
}
- /* Following commands are not implemented, and go to default case
- case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER:
- case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER:
- case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR:
- case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR:
- case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR:
- */
+ //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER:
+ //case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER:
+ //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR:
+ //case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR:
+ //case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR:
+ /*
case COMMAND_GOTO_IF_TRUE:
CollectParameters(&m_nIp, 1);
if (m_bCondResult)
SetIP(ScriptParams[0] >= 0 ? ScriptParams[0] : SIZE_MAIN_SCRIPT - ScriptParams[0]);
- /* Check COMMAND_GOTO note. */
return 0;
+ */
case COMMAND_GOTO_IF_FALSE:
CollectParameters(&m_nIp, 1);
if (!m_bCondResult)
@@ -1328,12 +1340,14 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
CTheScripts::bAlreadyRunningAMissionScript = false;
RemoveScriptFromList(&CTheScripts::pActiveScripts);
AddScriptToList(&CTheScripts::pIdleScripts);
+ m_bIsActive = false;
return 1;
case COMMAND_START_NEW_SCRIPT:
{
CollectParameters(&m_nIp, 1);
assert(ScriptParams[0] >= 0);
CRunningScript* pNew = CTheScripts::StartNewScript(ScriptParams[0]);
+ m_bIsActive = true;
int8 type = CTheScripts::Read1ByteFromScript(&m_nIp);
float tmp;
for (int i = 0; type != ARGUMENT_END; type = CTheScripts::Read1ByteFromScript(&m_nIp), i++) {
@@ -1381,7 +1395,7 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
{
CollectParameters(&m_nIp, 4);
int32 index = ScriptParams[0];
- assert(index < 1); /* Constant? Also no more double player glitch */
+ assert(index < NUMPLAYERS);
printf("&&&&&&&&&&&&&Creating player: %d\n", index);
if (!CStreaming::HasModelLoaded(MI_PLAYER)) {
CStreaming::RequestSpecialModel(MI_PLAYER, "player", STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
@@ -1421,20 +1435,49 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
if (pos.z <= MAP_Z_LOW_LIMIT)
pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
CPlayerPed* ped = CWorld::Players[index].m_pPed;
- if (!ped->bInVehicle) {
- pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel();
- ped->Teleport(pos);
- CTheScripts::ClearSpaceForMissionEntity(pos, ped);
+ if (ped->bInVehicle) {
+ pos.z += ped->m_pMyVehicle->GetDistanceFromCentreOfMassToBaseOfModel();
+ ped->m_pMyVehicle->Teleport(pos); // removed dumb stuff that was present here
+ CTheScripts::ClearSpaceForMissionEntity(pos, ped->m_pMyVehicle);
return 0;
}
- pos.z += ped->m_pMyVehicle->GetDistanceFromCentreOfMassToBaseOfModel();
- if (ped->m_pMyVehicle->IsBoat())
- ped->m_pMyVehicle->Teleport(pos);
- else
- ped->m_pMyVehicle->Teleport(pos);
- /* I'll keep this condition here but obviously it is absolutely pointless */
- /* It's clearly present in disassembly so it had to be in original code */
- CTheScripts::ClearSpaceForMissionEntity(pos, ped->m_pMyVehicle);
+ pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel();
+ CVector vOldPos = ped->GetPosition();
+ ped->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, ped);
+ if (ped) { // great time to check
+ for (int i = 0; i < ped->m_numNearPeds; i++) {
+ CPed* pTestedPed = ped->m_nearPeds[i];
+ if (!pTestedPed || !IsPedPointerValid(pTestedPed))
+ continue;
+ if (pTestedPed->m_pedInObjective == ped && pTestedPed->m_objective == OBJ_15) {
+ CVector vFollowerPos = pTestedPed->GetFormationPosition();
+ CTheScripts::ClearSpaceForMissionEntity(vFollowerPos, ped);
+ bool bFound = false;
+ vFollowerPos.z = CWorld::FindGroundZFor3DCoord(vFollowerPos.x, vFollowerPos.y, vFollowerPos.z + 1.0f, &bFound) + 1.0f;
+ if (bFound) {
+ if (CWorld::GetIsLineOfSightClear(vFollowerPos, ped->GetPosition(), true, false, false, true, false, false)) {
+ pTestedPed->Teleport(vFollowerPos);
+ }
+ }
+ }
+ else if (pTestedPed->m_leader == ped) {
+ CVector vFollowerPos;
+ if (pTestedPed->m_pedFormation)
+ vFollowerPos = pTestedPed->GetFormationPosition();
+ else
+ vFollowerPos = ped->GetPosition() + pTestedPed->GetPosition() - vOldPos;
+ CTheScripts::ClearSpaceForMissionEntity(vFollowerPos, ped);
+ bool bFound = false;
+ vFollowerPos.z = CWorld::FindGroundZFor3DCoord(vFollowerPos.x, vFollowerPos.y, vFollowerPos.z + 1.0f, &bFound) + 1.0f;
+ if (bFound) {
+ if (CWorld::GetIsLineOfSightClear(vFollowerPos, ped->GetPosition(), true, false, false, true, false, false)) {
+ pTestedPed->Teleport(vFollowerPos);
+ }
+ }
+ }
+ }
+ }
return 0;
}
case COMMAND_IS_PLAYER_IN_AREA_2D:
@@ -3508,14 +3551,8 @@ int8 CRunningScript::ProcessCommands300To399(int32 command)
case COMMAND_DECLARE_MISSION_FLAG:
CTheScripts::OnAMissionFlag = CTheScripts::Read2BytesFromScript(&++m_nIp);
return 0;
- case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT:
- CollectParameters(&m_nIp, 1);
- CTheScripts::OnAMissionForContactFlag[ScriptParams[0]] = CTheScripts::Read2BytesFromScript(&++m_nIp);
- return 0;
- case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT:
- CollectParameters(&m_nIp, 2);
- CTheScripts::BaseBriefIdForContact[ScriptParams[0]] = ScriptParams[1];
- return 0;
+ //case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT:
+ //case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT:
case COMMAND_IS_PLAYER_HEALTH_GREATER:
{
CollectParameters(&m_nIp, 2);
@@ -3830,13 +3867,8 @@ int8 CRunningScript::ProcessCommands400To499(int32 command)
CollectParameters(&m_nIp, 2);
CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]];
if (ScriptParams[1]){
- if (CGame::playingIntro || CTheScripts::DelayMakingPlayerUnsafeThisTime){
- CTheScripts::CountdownToMakePlayerUnsafe = 50;
- if (CTheScripts::DelayMakingPlayerUnsafeThisTime)
- CTheScripts::DelayMakingPlayerUnsafeThisTime--;
- }else{
- pPlayer->MakePlayerSafe(false);
- }
+ pPlayer->MakePlayerSafe(false);
+ // TODO(MIAMI): Four Iron hack
}else{
pPlayer->MakePlayerSafe(true);
if (strcmp(m_abScriptName, "camera") == 0){
@@ -7720,9 +7752,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
}
case COMMAND_REMOVE_TEXTURE_DICTIONARY:
{
- for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++)
- CTheScripts::ScriptSprites[i].Delete();
- CTxdStore::RemoveTxd(CTxdStore::FindTxdSlot("script"));
+ CTheScripts::RemoveScriptTextureDictionary();
return 0;
}
case COMMAND_SET_OBJECT_DYNAMIC:
@@ -10446,7 +10476,7 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command)
char key[8];
CTheScripts::ReadTextLabelFromScript(&m_nIp, key);
m_nIp += KEY_LENGTH_IN_SCRIPT;
- debug("skipping LOAD_MISSION_TEXT\n");
+ TheText.LoadMissionText(key);
return 0;
}
case COMMAND_SET_TONIGHTS_EVENT:
@@ -12133,29 +12163,6 @@ void CRunningScript::DoDeatharrestCheck()
while (m_nStackPointer > 1)
--m_nStackPointer;
m_nIp = m_anStack[--m_nStackPointer];
- int16 messageId;
- if (pPlayer->IsRestartingAfterDeath())
- messageId = 0;
- else if (pPlayer->IsRestartingAfterArrest())
- messageId = 5;
- else
- messageId = 10;
- messageId += CGeneral::GetRandomNumberInRange(0, 5);
- bool found = false;
- for (int16 contact = 0; !found && contact < MAX_NUM_CONTACTS; contact++) {
- int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact];
- if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) {
- messageId += CTheScripts::BaseBriefIdForContact[contact];
- found = true;
- }
- }
- if (!found)
- messageId = 8001;
- char tmp[16];
- sprintf(tmp, "%d", messageId);
- CMessages::ClearSmallMessagesOnly();
- wchar* text = TheText.Get(tmp);
- // ...and do nothing about it
*(int32*)&CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 0;
m_bDeatharrestExecuted = true;
m_nWakeTime = 0;
@@ -12299,8 +12306,8 @@ void CTheScripts::RenderTheScriptDebugLines()
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)0);
}
-#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) + sizeof(CTheScripts::BaseBriefIdForContact) + sizeof(CTheScripts::OnAMissionForContactFlag) +\
- sizeof(CTheScripts::CollectiveArray) + 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32)
+#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) +\
+ 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32)
void CTheScripts::SaveAllScripts(uint8* buf, uint32* size)
{
@@ -12320,12 +12327,6 @@ INITSAVEBUF
uint32 script_data_size = SCRIPT_DATA_SIZE;
WriteSaveBuf(buf, script_data_size);
WriteSaveBuf(buf, OnAMissionFlag);
- for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) {
- WriteSaveBuf(buf, OnAMissionForContactFlag[i]);
- WriteSaveBuf(buf, BaseBriefIdForContact[i]);
- }
- for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++)
- WriteSaveBuf(buf, CollectiveArray[i]);
WriteSaveBuf(buf, NextFreeCollectiveIndex);
for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) {
CBuilding* pBuilding = BuildingSwapArray[i].m_pBuilding;
@@ -12398,12 +12399,6 @@ INITSAVEBUF
ScriptSpace[i] = ReadSaveBuf<uint8>(buf);
assert(ReadSaveBuf<uint32>(buf) == SCRIPT_DATA_SIZE);
OnAMissionFlag = ReadSaveBuf<uint32>(buf);
- for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) {
- OnAMissionForContactFlag[i] = ReadSaveBuf<uint32>(buf);
- BaseBriefIdForContact[i] = ReadSaveBuf<uint32>(buf);
- }
- for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++)
- CollectiveArray[i] = ReadSaveBuf<tCollectiveData>(buf);
NextFreeCollectiveIndex = ReadSaveBuf<uint32>(buf);
for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) {
uint32 type = ReadSaveBuf<uint32>(buf);
diff --git a/src/control/Script.h b/src/control/Script.h
index c7a6e1e6..e84e76bf 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -228,12 +228,10 @@ enum {
enum {
MAX_NUM_SCRIPTS = 128,
- MAX_NUM_CONTACTS = 16,
MAX_NUM_INTRO_TEXT_LINES = 2,
MAX_NUM_INTRO_RECTANGLES = 16,
MAX_NUM_SCRIPT_SRPITES = 16,
MAX_NUM_SCRIPT_SPHERES = 16,
- MAX_NUM_COLLECTIVES = 32,
MAX_NUM_USED_OBJECTS = 200,
MAX_NUM_MISSION_SCRIPTS = 120,
MAX_NUM_BUILDING_SWAPS = 25,
@@ -245,13 +243,10 @@ class CTheScripts
{
static uint8 ScriptSpace[SIZE_SCRIPT_SPACE];
static CRunningScript ScriptsArray[MAX_NUM_SCRIPTS];
- static int32 BaseBriefIdForContact[MAX_NUM_CONTACTS];
- static int32 OnAMissionForContactFlag[MAX_NUM_CONTACTS];
static intro_text_line IntroTextLines[MAX_NUM_INTRO_TEXT_LINES];
static intro_script_rectangle IntroRectangles[MAX_NUM_INTRO_RECTANGLES];
static CSprite2d ScriptSprites[MAX_NUM_SCRIPT_SRPITES];
static script_sphere_struct ScriptSphereArray[MAX_NUM_SCRIPT_SPHERES];
- static tCollectiveData CollectiveArray[MAX_NUM_COLLECTIVES];
static tUsedObject UsedObjectArray[MAX_NUM_USED_OBJECTS];
static int32 MultiScriptArray[MAX_NUM_MISSION_SCRIPTS];
static tBuildingSwap BuildingSwapArray[MAX_NUM_BUILDING_SWAPS];
@@ -275,14 +270,17 @@ class CTheScripts
static uint32 LargestMissionScriptSize;
static uint32 MainScriptSize;
static uint8 FailCurrentMission;
- static uint8 CountdownToMakePlayerUnsafe;
- static uint8 DelayMakingPlayerUnsafeThisTime;
static uint16 NumScriptDebugLines;
static uint16 NumberOfIntroRectanglesThisFrame;
static uint16 NumberOfIntroTextLinesThisFrame;
static uint8 UseTextCommands;
static uint16 CommandsExecuted;
static uint16 ScriptsUpdated;
+ static uint8 RiotIntensity;
+ static uint32 LastMissionPassedTime;
+ static uint16 NumberOfExclusiveMissionScripts;
+ static bool bPlayerIsInTheStatium;
+ static bool bPlayerHasMetDebbieHarry;
public:
static void Init();
@@ -306,9 +304,6 @@ public:
static int32* GetPointerToScriptVariable(int32 offset) { assert(offset >= 8 && offset < CTheScripts::GetSizeOfVariableSpace()); return (int32*)&ScriptSpace[offset]; }
- static void ResetCountdownToMakePlayerUnsafe() { CountdownToMakePlayerUnsafe = 0; }
- static bool IsCountdownToMakePlayerUnsafeOn() { return CountdownToMakePlayerUnsafe != 0; }
-
static int32 Read4BytesFromScript(uint32* pIp) {
int32 retval = ScriptSpace[*pIp + 3] << 24 | ScriptSpace[*pIp + 2] << 16 | ScriptSpace[*pIp + 1] << 8 | ScriptSpace[*pIp];
*pIp += 4;
@@ -371,6 +366,7 @@ private:
static int32 AddScriptSphere(int32 id, CVector pos, float radius);
static int32 GetNewUniqueScriptSphereIndex(int32 index);
static void RemoveScriptSphere(int32 index);
+ static void RemoveScriptTextureDictionary();
friend class CRunningScript;
friend class CHud;
@@ -414,6 +410,7 @@ class CRunningScript
uint32 m_anStack[MAX_STACK_DEPTH];
uint16 m_nStackPointer;
int32 m_anLocalVariables[NUM_LOCAL_VARS + NUM_TIMERS];
+ bool m_bIsActive;
bool m_bCondResult;
bool m_bIsMissionScript;
bool m_bSkipWakeTime;
diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp
index 612851fb..1463b4a5 100644
--- a/src/core/FileLoader.cpp
+++ b/src/core/FileLoader.cpp
@@ -1,4 +1,5 @@
#include "common.h"
+#include <ctype.h>
#include "main.h"
#include "Quaternion.h"
@@ -26,6 +27,9 @@
#include "FileLoader.h"
#include "Streaming.h"
#include "ColStore.h"
+#include "Occlusion.h"
+
+//--MIAMI: file done
char CFileLoader::ms_line[256];
@@ -159,7 +163,6 @@ struct ColHeader
uint32 size;
};
-//--MIAMI: done
void
CFileLoader::LoadCollisionFile(const char *filename, uint8 colSlot)
{
@@ -196,7 +199,6 @@ CFileLoader::LoadCollisionFile(const char *filename, uint8 colSlot)
}
-//--MIAMI: done
bool
CFileLoader::LoadCollisionFileFirstTime(uint8 *buffer, uint32 size, uint8 colSlot)
{
@@ -298,13 +300,15 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname)
model.numLines = *(int16*)buf;
buf += 4;
if(model.numLines > 0){
- model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine));
+ //model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine));
for(i = 0; i < model.numLines; i++){
- model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12));
+ //model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12));
buf += 24;
}
}else
model.lines = nil;
+ model.numLines = 0;
+ model.lines = nil;
model.numBoxes = *(int16*)buf;
buf += 4;
@@ -323,10 +327,12 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname)
model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector));
for(i = 0; i < numVertices; i++){
model.vertices[i] = *(CVector*)buf;
+#if 0
if(Abs(model.vertices[i].x) >= 256.0f ||
Abs(model.vertices[i].y) >= 256.0f ||
Abs(model.vertices[i].z) >= 256.0f)
printf("%s:Collision volume too big\n", modelname);
+#endif
buf += 12;
}
}else
@@ -349,7 +355,7 @@ GetNameAndLOD(char *nodename, char *name, int *n)
{
char *underscore = nil;
for(char *s = nodename; *s != '\0'; s++){
- if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L'))
+ if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L') && isdigit(s[2]))
underscore = s;
}
if(underscore){
@@ -1093,7 +1099,7 @@ CFileLoader::LoadScene(const char *filename)
LoadCullZone(line);
break;
case OCCL:
- // TODO(MIAMI): occlusion
+ LoadOcclusionVolume(line);
break;
case PICK:
// unused
@@ -1187,7 +1193,9 @@ CFileLoader::LoadObjectInstance(const char *line)
CColStore::GetBoundingBox(col->level).ContainRect(entity->GetBoundRect());
}else
entity->bUsesCollision = false;
- // TODO(MIAMI): set some flag here if col min is below 6
+
+ if(entity->GetPosition().z + col->boundingBox.min.z < 6.0f)
+ entity->bUnderwater = true;
}else{
entity = new CDummyObject;
entity->SetModelIndexNoCreate(id);
@@ -1241,6 +1249,21 @@ CFileLoader::LoadPickup(const char *line)
sscanf(line, "%d %f %f %f", &id, &x, &y, &z);
}
+void
+CFileLoader::LoadOcclusionVolume(const char *line)
+{
+ float x, y, z;
+ float width, length, height;
+ float angle;
+
+ sscanf(line, "%f %f %f %f %f %f %f",
+ &x, &y, &z,
+ &width, &length, &height,
+ &angle);
+ COcclusion::AddOne(x, y, z, width, length, z + height/2.0f, angle);
+}
+
+
//--MIAMI: unused
void
CFileLoader::ReloadPaths(const char *filename)
diff --git a/src/core/FileLoader.h b/src/core/FileLoader.h
index 584a2312..077e7bdd 100644
--- a/src/core/FileLoader.h
+++ b/src/core/FileLoader.h
@@ -39,6 +39,7 @@ public:
static void LoadZone(const char *line);
static void LoadCullZone(const char *line);
static void LoadPickup(const char *line);
+ static void LoadOcclusionVolume(const char *line);
static void ReloadPaths(const char *filename);
static void ReloadObjectTypes(const char *filename);
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index b96c8988..3f4a3217 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -84,6 +84,7 @@
#include "World.h"
#include "ZoneCull.h"
#include "Zones.h"
+#include "Occlusion.h"
#include "debugmenu.h"
@@ -272,6 +273,7 @@ bool CGame::Initialise(const char* datFile)
ThePaths.AllocatePathFindInfoMem(4500);
CWeather::Init();
CCullZones::Init();
+ COcclusion::Init();
CCollision::Init();
CTheZones::Init();
CUserDisplay::Init();
diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp
index f4e762c0..37a62adf 100644
--- a/src/core/PlayerInfo.cpp
+++ b/src/core/PlayerInfo.cpp
@@ -173,7 +173,6 @@ void
CPlayerInfo::MakePlayerSafe(bool toggle)
{
if (toggle) {
- CTheScripts::ResetCountdownToMakePlayerUnsafe();
m_pPed->m_pWanted->m_bIgnoredByEveryone = true;
CWorld::StopAllLawEnforcersInTheirTracks();
CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_20;
@@ -194,7 +193,8 @@ CPlayerInfo::MakePlayerSafe(bool toggle)
CWorld::ExtinguishAllCarFiresInArea(GetPos(), 4000.0f);
CReplay::DisableReplays();
- } else if (!CGame::playingIntro && !CTheScripts::IsCountdownToMakePlayerUnsafeOn()) {
+ }
+ else {
m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_20;
m_pPed->bBulletProof = false;
diff --git a/src/core/config.h b/src/core/config.h
index 83aca235..548092f7 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -66,7 +66,7 @@ enum Config {
// Cull zones
NUMATTRIBZONES = 704,
- NUMHANDLINGS = 106,
+ NUMOCCLUSIONVOLUMES = 350,
PATHNODESIZE = 4500,
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index 3c096636..3217e684 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -20,3 +20,25 @@ CBuilding::ReplaceWithNewModel(int32 id)
if(m_level == LEVEL_NONE || m_level == CGame::currLevel)
CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE);
}
+
+bool
+IsBuildingPointerValid(CBuilding* pBuilding)
+{
+ if (!pBuilding)
+ return false;
+ if (pBuilding->GetIsATreadable()) {
+ int index = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pBuilding);
+#ifdef FIX_BUGS
+ return index >= 0 && index < CPools::GetTreadablePool()->GetSize();
+#else
+ return index >= 0 && index <= CPools::GetTreadablePool()->GetSize();
+#endif
+ } else {
+ int index = CPools::GetBuildingPool()->GetJustIndex(pBuilding);
+#ifdef FIX_BUGS
+ return index >= 0 && index < CPools::GetBuildingPool()->GetSize();
+#else
+ return index >= 0 && index <= CPools::GetBuildingPool()->GetSize();
+#endif
+ }
+}
diff --git a/src/entities/Building.h b/src/entities/Building.h
index 29608c10..2c2dfb1f 100644
--- a/src/entities/Building.h
+++ b/src/entities/Building.h
@@ -16,3 +16,5 @@ public:
virtual bool GetIsATreadable(void) { return false; }
};
+
+bool IsBuildingPointerValid(CBuilding*);
diff --git a/src/entities/Dummy.cpp b/src/entities/Dummy.cpp
index 8a4bfd5f..92b69761 100644
--- a/src/entities/Dummy.cpp
+++ b/src/entities/Dummy.cpp
@@ -50,3 +50,18 @@ CDummy::Remove(void)
m_entryInfoList.DeleteNode(node);
}
}
+
+bool
+IsDummyPointerValid(CDummy* pDummy)
+{
+ if (!pDummy)
+ return false;
+ int index = CPools::GetDummyPool()->GetJustIndex(pDummy);
+#ifdef FIX_BUGS
+ if (index < 0 || index >= CPools::GetDummyPool()->GetSize())
+#else
+ if (index < 0 || index > CPools::GetDummyPool()->GetSize())
+#endif
+ return false;
+ return pDummy->m_entryInfoList.first;
+}
diff --git a/src/entities/Dummy.h b/src/entities/Dummy.h
index 7998a748..84b1ce1a 100644
--- a/src/entities/Dummy.h
+++ b/src/entities/Dummy.h
@@ -15,3 +15,5 @@ public:
static void *operator new(size_t);
static void operator delete(void*, size_t);
};
+
+bool IsDummyPointerValid(CDummy* pDummy);
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index b35ddb25..e83df204 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -28,6 +28,8 @@
#include "Bones.h"
#include "Debug.h"
#include "Renderer.h"
+#include "Ped.h"
+#include "Dummy.h"
int gBuildings;
@@ -1028,3 +1030,18 @@ CEntity::LoadEntityFlags(uint8*& buf)
}
#endif
+
+bool IsEntityPointerValid(CEntity* pEntity)
+{
+ if (!pEntity)
+ return false;
+ switch (pEntity->GetType()) {
+ case ENTITY_TYPE_NOTHING: return false;
+ case ENTITY_TYPE_BUILDING: return IsBuildingPointerValid((CBuilding*)pEntity);
+ case ENTITY_TYPE_VEHICLE: return IsVehiclePointerValid((CVehicle*)pEntity);
+ case ENTITY_TYPE_PED: return IsPedPointerValid((CPed*)pEntity);
+ case ENTITY_TYPE_OBJECT: return IsObjectPointerValid((CObject*)pEntity);
+ case ENTITY_TYPE_DUMMY: return IsDummyPointerValid((CDummy*)pEntity);
+ }
+ return false;
+}
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index fa57519e..dc5378a5 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -180,3 +180,5 @@ public:
static void AddSteamsFromGround(CPtrList& list);
};
+
+bool IsEntityPointerValid(CEntity*);
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
index 0107c75c..4a45050c 100644
--- a/src/objects/Object.cpp
+++ b/src/objects/Object.cpp
@@ -396,3 +396,18 @@ CObject::DeleteAllTempObjectsInArea(CVector point, float fRadius)
}
}
}
+
+bool
+IsObjectPointerValid(CObject* pObject)
+{
+ if (!pObject)
+ return false;
+ int index = CPools::GetObjectPool()->GetJustIndex(pObject);
+#ifdef FIX_BUGS
+ if (index < 0 || index >= CPools::GetObjectPool()->GetSize())
+#else
+ if (index < 0 || index > CPools::GetObjectPool()->GetSize())
+#endif
+ return false;
+ return pObject->bIsBIGBuilding || pObject->m_entryInfoList.first;
+}
diff --git a/src/objects/Object.h b/src/objects/Object.h
index 20c99b1b..73f710f0 100644
--- a/src/objects/Object.h
+++ b/src/objects/Object.h
@@ -113,3 +113,5 @@ public:
static void DeleteAllTempObjects();
static void DeleteAllTempObjectsInArea(CVector point, float fRadius);
};
+
+bool IsObjectPointerValid(CObject* pObject);
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index e25e592e..91dafbc2 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -18599,4 +18599,29 @@ CPed::AddInCarAnims(CVehicle* car, bool isDriver)
m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), group, anim, 100.0f);
StopNonPartialAnims();
-} \ No newline at end of file
+}
+
+bool
+IsPedPointerValid_NotInWorld(CPed* pPed)
+{
+ if (!pPed)
+ return false;
+ int index = CPools::GetPedPool()->GetJustIndex(pPed);
+#ifdef FIX_BUGS
+ if (index < 0 || index >= NUMPEDS)
+#else
+ if (index < 0 || index > NUMPEDS)
+#endif
+ return false;
+ return true;
+}
+
+bool
+IsPedPointerValid(CPed* pPed)
+{
+ if (!IsPedPointerValid_NotInWorld(pPed))
+ return false;
+ if (pPed->bInVehicle && pPed->m_pMyVehicle)
+ return IsEntityPointerValid(pPed->m_pMyVehicle);
+ return pPed->m_entryInfoList.first || pPed == FindPlayerPed();
+}
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 0e80c378..1fa36b05 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -1018,3 +1018,6 @@ void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
#ifndef PED_SKIN
VALIDATE_SIZE(CPed, 0x53C);
#endif
+
+bool IsPedPointerValid(CPed*);
+bool IsPedPointerValid_NotInWorld(CPed*);
diff --git a/src/render/Occlusion.cpp b/src/render/Occlusion.cpp
index b33b1d01..1c4e4266 100644
--- a/src/render/Occlusion.cpp
+++ b/src/render/Occlusion.cpp
@@ -2,6 +2,42 @@
#include "Occlusion.h"
+int32 COcclusion::NumOccludersOnMap;
+int16 COcclusion::FarAwayList;
+int16 COcclusion::NearbyList;
+int16 COcclusion::ListWalkThroughFA;
+int16 COcclusion::PreviousListWalkThroughFA;
+COccluder COcclusion::aOccluders[NUMOCCLUSIONVOLUMES];
+
+void
+COcclusion::Init(void)
+{
+ NumOccludersOnMap = 0;
+ FarAwayList = -1;
+ NearbyList = -1;
+ ListWalkThroughFA = -1;
+ PreviousListWalkThroughFA = -1;
+}
+
+void
+COcclusion::AddOne(float x, float y, float z, float width, float length, float height, float angle)
+{
+ if(NumOccludersOnMap >= NUMOCCLUSIONVOLUMES)
+ return;
+
+ aOccluders[NumOccludersOnMap].x = x;
+ aOccluders[NumOccludersOnMap].y = y;
+ aOccluders[NumOccludersOnMap].z = z;
+ aOccluders[NumOccludersOnMap].width = width;
+ aOccluders[NumOccludersOnMap].length = length;
+ aOccluders[NumOccludersOnMap].height = height;
+ while(angle < 0.0f) angle += 360.0f;
+ while(angle > 360.0f) angle -= 360.0f;
+ aOccluders[NumOccludersOnMap].angle = angle * UINT16_MAX/360.0f;
+ aOccluders[NumOccludersOnMap].listIndex = FarAwayList;
+ FarAwayList = NumOccludersOnMap++;
+}
+
void
COcclusion::ProcessBeforeRendering(void)
{
diff --git a/src/render/Occlusion.h b/src/render/Occlusion.h
index 977649b8..ac0ede5e 100644
--- a/src/render/Occlusion.h
+++ b/src/render/Occlusion.h
@@ -1,7 +1,26 @@
#pragma once
+class COccluder
+{
+public:
+ int16 width, length, height;
+ int16 x, y, z;
+ uint16 angle;
+ int16 listIndex;
+};
+
class COcclusion
{
public:
+ static int32 NumOccludersOnMap;
+ static int16 FarAwayList;
+ static int16 NearbyList;
+ static int16 ListWalkThroughFA;
+ static int16 PreviousListWalkThroughFA;
+
+ static COccluder aOccluders[NUMOCCLUSIONVOLUMES];
+
+ static void Init(void);
+ static void AddOne(float x, float y, float z, float width, float length, float height, float angle);
static void ProcessBeforeRendering(void);
};
diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp
index cc6428e1..51e2604c 100644
--- a/src/vehicles/HandlingMgr.cpp
+++ b/src/vehicles/HandlingMgr.cpp
@@ -127,7 +127,7 @@ cHandlingDataMgr::Initialise(void)
{
LoadHandlingData();
field_0 = 0.1f;
- field_4 = 0.9f;
+ fWheelFriction = 0.9f;
field_8 = 1.0f;
field_C = 0.8f;
field_10 = 0.98f;
@@ -143,6 +143,9 @@ cHandlingDataMgr::LoadHandlingData(void)
int field, handlingId;
int keepGoing;
tHandlingData *handling;
+ tFlyingHandlingData *flyingHandling;
+ tBoatHandlingData *boatHandling;
+ tBikeHandlingData *bikeHandling;
CFileMgr::SetDir("DATA");
CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r");
@@ -151,6 +154,9 @@ cHandlingDataMgr::LoadHandlingData(void)
start = (char*)work_buff;
end = start+1;
handling = nil;
+ flyingHandling = nil;
+ boatHandling = nil;
+ bikeHandling = nil;
keepGoing = 1;
while(keepGoing){
@@ -166,61 +172,158 @@ cHandlingDataMgr::LoadHandlingData(void)
// yeah, this is kinda crappy
if(strncmp(line, ";the end", 9) == 0)
keepGoing = 0;
-// else if(line[0] != ';'){
-// TODO(MIAMI): read boat, bike, flying values
- else if(line[0] != ';' && line[0] != '%' && line[0] != '!' && line[0] != '$'){
- field = 0;
- strcpy(delim, " \t");
- // FIX: game seems to use a do-while loop here
- for(word = strtok(line, delim); word; word = strtok(nil, delim)){
- switch(field){
- case 0:
- handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
- assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
- handling = &HandlingData[handlingId];
- handling->nIdentifier = (eHandlingId)handlingId;
- break;
- case 1: handling->fMass = strtod(word, nil); break;
- case 2: handling->Dimension.x = strtod(word, nil); break;
- case 3: handling->Dimension.y = strtod(word, nil); break;
- case 4: handling->Dimension.z = strtod(word, nil); break;
- case 5: handling->CentreOfMass.x = strtod(word, nil); break;
- case 6: handling->CentreOfMass.y = strtod(word, nil); break;
- case 7: handling->CentreOfMass.z = strtod(word, nil); break;
- case 8: handling->nPercentSubmerged = atoi(word); break;
- case 9: handling->fTractionMultiplier = strtod(word, nil); break;
- case 10: handling->fTractionLoss = strtod(word, nil); break;
- case 11: handling->fTractionBias = strtod(word, nil); break;
- case 12: handling->Transmission.nNumberOfGears = atoi(word); break;
- case 13: handling->Transmission.fMaxVelocity = strtod(word, nil); break;
- case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
- case 15: handling->Transmission.nDriveType = word[0]; break;
- case 16: handling->Transmission.nEngineType = word[0]; break;
- case 17: handling->fBrakeDeceleration = strtod(word, nil); break;
- case 18: handling->fBrakeBias = strtod(word, nil); break;
- case 19: handling->bABS = !!atoi(word); break;
- case 20: handling->fSteeringLock = strtod(word, nil); break;
- case 21: handling->fSuspensionForceLevel = strtod(word, nil); break;
- case 22: handling->fSuspensionDampingLevel = strtod(word, nil); break;
- case 23: handling->fSeatOffsetDistance = strtod(word, nil); break;
- case 24: handling->fCollisionDamageMultiplier = strtod(word, nil); break;
- case 25: handling->nMonetaryValue = atoi(word); break;
- case 26: handling->fSuspensionUpperLimit = strtod(word, nil); break;
- case 27: handling->fSuspensionLowerLimit = strtod(word, nil); break;
- case 28: handling->fSuspensionBias = strtod(word, nil); break;
- case 29:
- // TODO(MIAMI): suspension anti-dive multiplier
- break;
- case 30:
- sscanf(word, "%x", &handling->Flags);
- handling->Transmission.Flags = handling->Flags;
- break;
- case 31: handling->FrontLights = atoi(word); break;
- case 32: handling->RearLights = atoi(word); break;
+ else if(line[0] != ';'){
+ if(line[0] == '!'){
+ // Bike data
+ field = 0;
+ strcpy(delim, " \t");
+ // FIX: game seems to use a do-while loop here
+ for(word = strtok(line, delim); word; word = strtok(nil, delim)){
+ switch(field){
+ case 0: break;
+ case 1:
+ handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
+ assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
+ bikeHandling = GetBikePointer(handlingId);
+ bikeHandling->nIdentifier = (eHandlingId)handlingId;
+ break;
+ case 2: bikeHandling->fLeanFwdCOM = atof(word); break;
+ case 3: bikeHandling->fLeanFwdForce = atof(word); break;
+ case 4: bikeHandling->fLeanBakCOM = atof(word); break;
+ case 5: bikeHandling->fLeanBackForce = atof(word); break;
+ case 6: bikeHandling->fMaxLean = atof(word); break;
+ case 7: bikeHandling->fFullAnimLean = atof(word); break;
+ case 8: bikeHandling->fDesLean = atof(word); break;
+ case 9: bikeHandling->fSpeedSteer = atof(word); break;
+ case 10: bikeHandling->fSlipSteer = atof(word); break;
+ case 11: bikeHandling->fNoPlayerCOMz = atof(word); break;
+ case 12: bikeHandling->fWheelieAng = atof(word); break;
+ case 13: bikeHandling->fStoppieAng = atof(word); break;
+ case 14: bikeHandling->fWheelieSteer = atof(word); break;
+ case 15: bikeHandling->fWheelieStabMult = atof(word); break;
+ case 16: bikeHandling->fStoppieStabMult = atof(word); break;
+ }
+ field++;
}
- field++;
+ ConvertBikeDataToGameUnits(bikeHandling);
+ }else if(line[0] == '$'){
+ // Flying data
+ field = 0;
+ strcpy(delim, " \t");
+ // FIX: game seems to use a do-while loop here
+ for(word = strtok(line, delim); word; word = strtok(nil, delim)){
+ switch(field){
+ case 0: break;
+ case 1:
+ handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
+ assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
+ flyingHandling = GetFlyingPointer(handlingId);
+ flyingHandling->nIdentifier = (eHandlingId)handlingId;
+ break;
+ case 2: flyingHandling->fThrust = atof(word); break;
+ case 3: flyingHandling->fThrustFallOff = atof(word); break;
+ case 4: flyingHandling->fYaw = atof(word); break;
+ case 5: flyingHandling->fYawStab = atof(word); break;
+ case 6: flyingHandling->fSideSlip = atof(word); break;
+ case 7: flyingHandling->fRoll = atof(word); break;
+ case 8: flyingHandling->fRollStab = atof(word); break;
+ case 9: flyingHandling->fPitch = atof(word); break;
+ case 10: flyingHandling->fPitchStab = atof(word); break;
+ case 11: flyingHandling->fFormLift = atof(word); break;
+ case 12: flyingHandling->fAttackLift = atof(word); break;
+ case 13: flyingHandling->fMoveRes = atof(word); break;
+ case 14: flyingHandling->vecTurnRes.x = atof(word); break;
+ case 15: flyingHandling->vecTurnRes.y = atof(word); break;
+ case 16: flyingHandling->vecTurnRes.z = atof(word); break;
+ case 17: flyingHandling->vecSpeedRes.x = atof(word); break;
+ case 18: flyingHandling->vecSpeedRes.y = atof(word); break;
+ case 19: flyingHandling->vecSpeedRes.z = atof(word); break;
+ }
+ field++;
+ }
+ }else if(line[0] == '%'){
+ // Boat data
+ field = 0;
+ strcpy(delim, " \t");
+ // FIX: game seems to use a do-while loop here
+ for(word = strtok(line, delim); word; word = strtok(nil, delim)){
+ switch(field){
+ case 0: break;
+ case 1:
+ handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
+ assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
+ boatHandling = GetBoatPointer(handlingId);
+ boatHandling->nIdentifier = (eHandlingId)handlingId;
+ break;
+ case 2: boatHandling->fThrustY = atof(word); break;
+ case 3: boatHandling->fThrustZ = atof(word); break;
+ case 4: boatHandling->fThrustAppZ = atof(word); break;
+ case 5: boatHandling->fAqPlaneForce = atof(word); break;
+ case 6: boatHandling->fAqPlaneLimit = atof(word); break;
+ case 7: boatHandling->fAqPlaneOffset = atof(word); break;
+ case 8: boatHandling->fWaveAudioMult = atof(word); break;
+ case 9: boatHandling->vecMoveRes.x = atof(word); break;
+ case 10: boatHandling->vecMoveRes.y = atof(word); break;
+ case 11: boatHandling->vecMoveRes.z = atof(word); break;
+ case 12: boatHandling->vecTurnRes.x = atof(word); break;
+ case 13: boatHandling->vecTurnRes.y = atof(word); break;
+ case 14: boatHandling->vecTurnRes.z = atof(word); break;
+ case 15: boatHandling->fLook_L_R_BehindCamHeight = atof(word); break;
+ }
+ field++;
+ }
+ }else{
+ field = 0;
+ strcpy(delim, " \t");
+ // FIX: game seems to use a do-while loop here
+ for(word = strtok(line, delim); word; word = strtok(nil, delim)){
+ switch(field){
+ case 0:
+ handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
+ assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
+ handling = &HandlingData[handlingId];
+ handling->nIdentifier = (eHandlingId)handlingId;
+ break;
+ case 1: handling->fMass = atof(word); break;
+ case 2: handling->Dimension.x = atof(word); break;
+ case 3: handling->Dimension.y = atof(word); break;
+ case 4: handling->Dimension.z = atof(word); break;
+ case 5: handling->CentreOfMass.x = atof(word); break;
+ case 6: handling->CentreOfMass.y = atof(word); break;
+ case 7: handling->CentreOfMass.z = atof(word); break;
+ case 8: handling->nPercentSubmerged = atoi(word); break;
+ case 9: handling->fTractionMultiplier = atof(word); break;
+ case 10: handling->fTractionLoss = atof(word); break;
+ case 11: handling->fTractionBias = atof(word); break;
+ case 12: handling->Transmission.nNumberOfGears = atoi(word); break;
+ case 13: handling->Transmission.fMaxVelocity = atof(word); break;
+ case 14: handling->Transmission.fEngineAcceleration = atof(word) * 0.4f; break;
+ case 15: handling->Transmission.nDriveType = word[0]; break;
+ case 16: handling->Transmission.nEngineType = word[0]; break;
+ case 17: handling->fBrakeDeceleration = atof(word); break;
+ case 18: handling->fBrakeBias = atof(word); break;
+ case 19: handling->bABS = !!atoi(word); break;
+ case 20: handling->fSteeringLock = atof(word); break;
+ case 21: handling->fSuspensionForceLevel = atof(word); break;
+ case 22: handling->fSuspensionDampingLevel = atof(word); break;
+ case 23: handling->fSeatOffsetDistance = atof(word); break;
+ case 24: handling->fCollisionDamageMultiplier = atof(word); break;
+ case 25: handling->nMonetaryValue = atoi(word); break;
+ case 26: handling->fSuspensionUpperLimit = atof(word); break;
+ case 27: handling->fSuspensionLowerLimit = atof(word); break;
+ case 28: handling->fSuspensionBias = atof(word); break;
+ case 29: handling->fSuspensionAntidiveMultiplier = atof(word); break;
+ case 30:
+ sscanf(word, "%x", &handling->Flags);
+ handling->Transmission.Flags = handling->Flags;
+ break;
+ case 31: handling->FrontLights = atoi(word); break;
+ case 32: handling->RearLights = atoi(word); break;
+ }
+ field++;
+ }
+ ConvertDataToGameUnits(handling);
}
- ConvertDataToGameUnits(handling);
}
}
}
@@ -253,6 +356,7 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
if(handling->fTurnMass < 10.0f)
handling->fTurnMass *= 5.0f;
handling->fInvMass = 1.0f/handling->fMass;
+ handling->fCollisionDamageMultiplier *= 2000.0f/handling->fMass;
handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * 0.008f*handling->fMass;
// What the hell is going on here?
@@ -268,11 +372,16 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
if(handling->nIdentifier == HANDLING_RCBANDIT){
handling->Transmission.fUnkMaxVelocity = handling->Transmission.fMaxVelocity;
+ handling->Transmission.fMaxReverseVelocity = -handling->Transmission.fMaxVelocity;
+ }else if(handling->nIdentifier >= HANDLING_BIKE && handling->nIdentifier <= HANDLING_FREEWAY){
+ handling->Transmission.fUnkMaxVelocity = velocity;
+ handling->Transmission.fMaxVelocity = velocity * 1.2f;
+ handling->Transmission.fMaxReverseVelocity = -0.05f;
}else{
handling->Transmission.fUnkMaxVelocity = velocity;
handling->Transmission.fMaxVelocity = velocity * 1.2f;
+ handling->Transmission.fMaxReverseVelocity = -0.2f;
}
- handling->Transmission.fMaxReverseVelocity = -0.2f;
if(handling->Transmission.nDriveType == '4')
handling->Transmission.fEngineAcceleration /= 4.0f;
@@ -282,6 +391,15 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
handling->Transmission.InitGearRatios();
}
+void
+cHandlingDataMgr::ConvertBikeDataToGameUnits(tBikeHandlingData *handling)
+{
+ handling->fMaxLean = Sin(DEGTORAD(handling->fMaxLean));
+ handling->fFullAnimLean = DEGTORAD(handling->fFullAnimLean);
+ handling->fWheelieAng = Sin(DEGTORAD(handling->fWheelieAng));
+ handling->fStoppieAng = Sin(DEGTORAD(handling->fStoppieAng));
+}
+
int32
cHandlingDataMgr::GetHandlingId(const char *name)
{
@@ -291,3 +409,19 @@ cHandlingDataMgr::GetHandlingId(const char *name)
break;
return i;
}
+
+tFlyingHandlingData*
+cHandlingDataMgr::GetFlyingPointer(uint8 id)
+{
+ if(id >= HANDLING_SEAPLANE && id <= HANDLING_RCCOPTER)
+ return &FlyingHandlingData[id-HANDLING_SEAPLANE];
+ return &FlyingHandlingData[0];
+}
+
+tBoatHandlingData*
+cHandlingDataMgr::GetBoatPointer(uint8 id)
+{
+ if(id >= HANDLING_PREDATOR && id <= HANDLING_SEAPLANE)
+ return &BoatHandlingData[id-HANDLING_PREDATOR];
+ return &BoatHandlingData[0];
+}
diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h
index e629d885..663a548a 100644
--- a/src/vehicles/HandlingMgr.h
+++ b/src/vehicles/HandlingMgr.h
@@ -85,11 +85,13 @@ enum eHandlingId
HANDLING_LOVEFIST,
HANDLING_BLOODRA,
HANDLING_BLOODRB,
+
HANDLING_BIKE,
HANDLING_MOPED,
HANDLING_DIRTBIKE,
HANDLING_ANGEL,
HANDLING_FREEWAY,
+
HANDLING_PREDATOR,
HANDLING_SPEEDER,
HANDLING_REEFER,
@@ -100,7 +102,7 @@ enum eHandlingId
HANDLING_DINGHY,
HANDLING_MARQUIS,
HANDLING_CUPBOAT,
- HANDLING_SEAPLANE,
+ HANDLING_SEAPLANE, // both boat and plane!
HANDLING_SPARROW,
HANDLING_SEASPAR,
HANDLING_MAVERICK,
@@ -109,7 +111,13 @@ enum eHandlingId
HANDLING_HUNTER,
HANDLING_RCBARON,
HANDLING_RCGOBLIN,
- HANDLING_RCCOPTER
+ HANDLING_RCCOPTER,
+
+ NUMHANDLINGS,
+
+ NUMBIKEHANDLINGS = HANDLING_FREEWAY+1 - HANDLING_BIKE,
+ NUMFLYINGHANDLINGS = HANDLING_RCCOPTER+1 - HANDLING_SEAPLANE,
+ NUMBOATHANDLINGS = HANDLING_SEAPLANE+1 - HANDLING_PREDATOR,
};
enum
@@ -168,6 +176,7 @@ struct tHandlingData
float fSuspensionUpperLimit;
float fSuspensionLowerLimit;
float fSuspensionBias;
+ float fSuspensionAntidiveMultiplier;
float fCollisionDamageMultiplier;
uint32 Flags;
float fSeatOffsetDistance;
@@ -175,19 +184,74 @@ struct tHandlingData
int8 FrontLights;
int8 RearLights;
};
-VALIDATE_SIZE(tHandlingData, 0xD8);
+
+struct tBikeHandlingData
+{
+ eHandlingId nIdentifier;
+ float fLeanFwdCOM;
+ float fLeanFwdForce;
+ float fLeanBakCOM;
+ float fLeanBackForce;
+ float fMaxLean;
+ float fFullAnimLean;
+ float fDesLean;
+ float fSpeedSteer;
+ float fSlipSteer;
+ float fNoPlayerCOMz;
+ float fWheelieAng;
+ float fStoppieAng;
+ float fWheelieSteer;
+ float fWheelieStabMult;
+ float fStoppieStabMult;
+};
+
+struct tBoatHandlingData
+{
+ eHandlingId nIdentifier;
+ float fThrustY;
+ float fThrustZ;
+ float fThrustAppZ;
+ float fAqPlaneForce;
+ float fAqPlaneLimit;
+ float fAqPlaneOffset;
+ float fWaveAudioMult;
+ float fLook_L_R_BehindCamHeight;
+ CVector vecMoveRes;
+ CVector vecTurnRes;
+};
+
+struct tFlyingHandlingData
+{
+ eHandlingId nIdentifier;
+ float fThrust;
+ float fThrustFallOff;
+ float fYaw;
+ float fYawStab;
+ float fSideSlip;
+ float fRoll;
+ float fRollStab;
+ float fPitch;
+ float fPitchStab;
+ float fFormLift;
+ float fAttackLift;
+ float fMoveRes;
+ CVector vecTurnRes;
+ CVector vecSpeedRes;
+};
class cHandlingDataMgr
{
float field_0; // unused it seems
public:
- float field_4; // wheel related
+ float fWheelFriction;
private:
float field_8; //
float field_C; // unused it seems
float field_10; //
tHandlingData HandlingData[NUMHANDLINGS];
- uint32 field_302C; // unused it seems
+ tBikeHandlingData BikeHandlingData[NUMBIKEHANDLINGS];
+ tFlyingHandlingData FlyingHandlingData[NUMFLYINGHANDLINGS];
+ tBoatHandlingData BoatHandlingData[NUMBOATHANDLINGS];
public:
cHandlingDataMgr(void);
@@ -195,8 +259,12 @@ public:
void LoadHandlingData(void);
int FindExactWord(const char *word, const char *words, int wordLen, int numWords);
void ConvertDataToGameUnits(tHandlingData *handling);
+ void ConvertBikeDataToGameUnits(tBikeHandlingData *handling);
int32 GetHandlingId(const char *name);
tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; }
+ tBikeHandlingData *GetBikePointer(uint8 id) { return &BikeHandlingData[id-HANDLING_BIKE]; }
+ tFlyingHandlingData *GetFlyingPointer(uint8 id);
+ tBoatHandlingData *GetBoatPointer(uint8 id);
bool HasRearWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'R'; }
bool HasFrontWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'F'; }
};
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 4b36b3d3..c90370f6 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -528,9 +528,9 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
if(!bBraking){
if(m_fGasPedal < 0.01f){
if(GetModelIndex() == MI_RCBANDIT)
- brake = 0.2f * mod_HandlingManager.field_4 / m_fMass;
+ brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass;
else
- brake = mod_HandlingManager.field_4 / m_fMass;
+ brake = mod_HandlingManager.fWheelFriction / m_fMass;
#ifdef FIX_BUGS
brake *= CTimer::GetTimeStepFix();
#endif
@@ -1378,3 +1378,18 @@ CVehicle::GetVehicleAppearance(void)
return VEHICLE_APPEARANCE_HELI;
return VEHICLE_APPEARANCE_NONE;
}
+
+bool
+IsVehiclePointerValid(CVehicle* pVehicle)
+{
+ if (!pVehicle)
+ return false;
+ int index = CPools::GetVehiclePool()->GetJustIndex(pVehicle);
+#ifdef FIX_BUGS
+ if (index < 0 || index >= NUMVEHICLES)
+#else
+ if (index < 0 || index > NUMVEHICLES)
+#endif
+ return false;
+ return pVehicle->m_vehType == VEHICLE_TYPE_PLANE || pVehicle->m_entryInfoList.first;
+}
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 5ec20c43..c2cfa5e4 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -314,3 +314,4 @@ public:
};
void DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle);
+bool IsVehiclePointerValid(CVehicle* pVehicle);