summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CdStreamPosix.cpp302
-rw-r--r--src/core/FileLoader.cpp4
-rw-r--r--src/core/FileMgr.cpp10
-rw-r--r--src/core/Fire.cpp118
-rw-r--r--src/core/Fire.h12
-rw-r--r--src/core/Game.cpp6
-rw-r--r--src/core/General.h2
-rw-r--r--src/core/Pad.cpp6
-rw-r--r--src/core/Streaming.cpp134
-rw-r--r--src/core/User.cpp2
-rw-r--r--src/core/Zones.cpp191
-rw-r--r--src/core/Zones.h2
-rw-r--r--src/core/common.h42
-rw-r--r--src/core/config.h10
14 files changed, 551 insertions, 290 deletions
diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp
index e114a29a..a6ab62bc 100644
--- a/src/core/CdStreamPosix.cpp
+++ b/src/core/CdStreamPosix.cpp
@@ -34,11 +34,11 @@ struct CdReadInfo
bool bReading;
int32 nStatus;
#ifdef ONE_THREAD_PER_CHANNEL
- int8 nThreadStatus; // 0: created 1:initalized 2:abort now
- pthread_t pChannelThread;
- sem_t pStartSemaphore;
+ int8 nThreadStatus; // 0: created 1:priority set up 2:abort now
+ pthread_t pChannelThread;
+ sem_t *pStartSemaphore;
#endif
- sem_t pDoneSemaphore; // used for CdStreamSync
+ sem_t *pDoneSemaphore; // used for CdStreamSync
int32 hFile;
};
@@ -51,8 +51,8 @@ char *gImgNames[MAX_CDIMAGES];
#ifndef ONE_THREAD_PER_CHANNEL
pthread_t _gCdStreamThread;
-sem_t gCdStreamSema; // released when we have new thing to read(so channel is set)
-int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now
+sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set)
+int8 gCdStreamThreadStatus; // 0: created 1:priority set up 2:abort now
Queue gChannelRequestQ;
bool _gbCdStreamOverlapped;
#endif
@@ -69,49 +69,50 @@ void
CdStreamInitThread(void)
{
int status;
-
+ char semName[20];
#ifndef ONE_THREAD_PER_CHANNEL
gChannelRequestQ.items = (int32 *)calloc(gNumChannels + 1, sizeof(int32));
gChannelRequestQ.head = 0;
gChannelRequestQ.tail = 0;
gChannelRequestQ.size = gNumChannels + 1;
ASSERT(gChannelRequestQ.items != nil );
- status = sem_init(&gCdStreamSema, 0, 0);
-#endif
+ gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1);
- if (status == -1) {
+ if (gCdStreamSema == SEM_FAILED) {
CDTRACE("failed to create stream semaphore");
ASSERT(0);
return;
}
-
+#endif
if ( gNumChannels > 0 )
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
- status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0);
+ sprintf(semName,"/semaphore_done%d",i);
+ gpReadInfo[i].pDoneSemaphore = sem_open(semName, O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pDoneSemaphore == SEM_FAILED)
{
CDTRACE("failed to create sync semaphore");
ASSERT(0);
return;
}
#ifdef ONE_THREAD_PER_CHANNEL
- status = sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0);
+ sprintf(semName,"/semaphore_start%d",i);
+ gpReadInfo[i].pStartSemaphore = sem_open(semName, O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pStartSemaphore == SEM_FAILED)
{
CDTRACE("failed to create start semaphore");
ASSERT(0);
return;
}
- gpReadInfo[i].nThreadStatus = 0;
+ gpReadInfo[i].nThreadStatus = 0;
int *channelI = (int*)malloc(sizeof(int));
*channelI = i;
- status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI);
+ status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI);
if (status == -1)
{
@@ -124,32 +125,32 @@ CdStreamInitThread(void)
}
#ifndef ONE_THREAD_PER_CHANNEL
- debug("Using one streaming thread for all channels\n");
- status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil);
- gCdStreamThreadStatus = 0;
-
- if (status == -1)
- {
- CDTRACE("failed to create sync thread");
- ASSERT(0);
- return;
- }
+ debug("Using one streaming thread for all channels\n");
+ gCdStreamThreadStatus = 0;
+ status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil);
+
+ if (status == -1)
+ {
+ CDTRACE("failed to create sync thread");
+ ASSERT(0);
+ return;
+ }
#else
- debug("Using seperate streaming threads for each channel\n");
+ debug("Using separate streaming threads for each channel\n");
#endif
}
void
CdStreamInit(int32 numChannels)
{
- struct statvfs fsInfo;
-
- if((statvfs("models/gta3.img", &fsInfo)) < 0)
- {
- CDTRACE("can't get filesystem info");
- ASSERT(0);
- return;
- }
+ struct statvfs fsInfo;
+
+ if((statvfs("models/gta3.img", &fsInfo)) < 0)
+ {
+ CDTRACE("can't get filesystem info");
+ ASSERT(0);
+ return;
+ }
#ifdef __linux__
_gdwCdStreamFlags = O_RDONLY | O_NOATIME;
#else
@@ -163,7 +164,7 @@ CdStreamInit(int32 numChannels)
debug("Using no buffered loading for streaming\n");
}
*/
- void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, fsInfo.f_bsize);
+ void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize);
ASSERT( pBuffer != nil );
gNumImages = 0;
@@ -185,27 +186,27 @@ uint32
GetGTA3ImgSize(void)
{
ASSERT( gImgFiles[0] > 0 );
- struct stat statbuf;
+ struct stat statbuf;
- char path[PATH_MAX];
- realpath(gImgNames[0], path);
- if (stat(path, &statbuf) == -1) {
+ char path[PATH_MAX];
+ realpath(gImgNames[0], path);
+ if (stat(path, &statbuf) == -1) {
// Try case-insensitivity
char* real = casepath(gImgNames[0], false);
if (real)
{
realpath(real, path);
free(real);
- if (stat(path, &statbuf) != -1)
+ if (stat(path, &statbuf) != -1)
goto ok;
}
- CDTRACE("can't get size of gta3.img");
- ASSERT(0);
- return 0;
- }
-ok:
- return statbuf.st_size;
+ CDTRACE("can't get size of gta3.img");
+ ASSERT(0);
+ return 0;
+ }
+ ok:
+ return (uint32)statbuf.st_size;
}
void
@@ -213,15 +214,13 @@ CdStreamShutdown(void)
{
// Destroying semaphores and free(gpReadInfo) will be done at threads
#ifndef ONE_THREAD_PER_CHANNEL
- gCdStreamThreadStatus = 2;
- sem_post(&gCdStreamSema);
-#endif
-
-#ifdef ONE_THREAD_PER_CHANNEL
- for ( int32 i = 0; i < gNumChannels; i++ ) {
- gpReadInfo[i].nThreadStatus = 2;
- sem_post(&gpReadInfo[i].pStartSemaphore);
- }
+ gCdStreamThreadStatus = 2;
+ sem_post(gCdStreamSema);
+#else
+ for ( int32 i = 0; i < gNumChannels; i++ ) {
+ gpReadInfo[i].nThreadStatus = 2;
+ sem_post(gpReadInfo[i].pStartSemaphore);
+ }
#endif
}
@@ -241,27 +240,33 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
- pChannel->hFile = hImage - 1;
- if ( pChannel->nSectorsToRead != 0 || pChannel->bReading )
- return STREAM_NONE;
+ if ( pChannel->nSectorsToRead != 0 || pChannel->bReading ) {
+ if (pChannel->nSectorOffset == _GET_OFFSET(offset) && pChannel->nSectorsToRead >= size)
+ return STREAM_SUCCESS;
+
+ flushStream[channel] = 1;
+ CdStreamSync(channel);
+ //return STREAM_NONE;
+ }
- pChannel->nStatus = STREAM_NONE;
- pChannel->nSectorOffset = _GET_OFFSET(offset);
- pChannel->nSectorsToRead = size;
- pChannel->pBuffer = buffer;
- pChannel->bLocked = 0;
+ pChannel->hFile = hImage - 1;
+ pChannel->nStatus = STREAM_NONE;
+ pChannel->nSectorOffset = _GET_OFFSET(offset);
+ pChannel->nSectorsToRead = size;
+ pChannel->pBuffer = buffer;
+ pChannel->bLocked = 0;
#ifndef ONE_THREAD_PER_CHANNEL
- AddToQueue(&gChannelRequestQ, channel);
- if ( sem_post(&gCdStreamSema) != 0 )
- printf("Signal Sema Error\n");
+ AddToQueue(&gChannelRequestQ, channel);
+ if ( sem_post(gCdStreamSema) != 0 )
+ printf("Signal Sema Error\n");
#else
- if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 )
- printf("Signal Sema Error\n");
+ if ( sem_post(pChannel->pStartSemaphore) != 0 )
+ printf("Signal Sema Error\n");
#endif
- return STREAM_SUCCESS;
+ return STREAM_SUCCESS;
}
int32
@@ -272,29 +277,29 @@ CdStreamGetStatus(int32 channel)
ASSERT( pChannel != nil );
#ifdef ONE_THREAD_PER_CHANNEL
- if (pChannel->nThreadStatus == 2)
- return STREAM_NONE;
+ if (pChannel->nThreadStatus == 2)
+ return STREAM_NONE;
#else
- if (gCdStreamThreadStatus == 2)
- return STREAM_NONE;
+ if (gCdStreamThreadStatus == 2)
+ return STREAM_NONE;
#endif
- if ( pChannel->bReading )
- return STREAM_READING;
+ if ( pChannel->bReading )
+ return STREAM_READING;
- if ( pChannel->nSectorsToRead != 0 )
- return STREAM_WAITING;
+ if ( pChannel->nSectorsToRead != 0 )
+ return STREAM_WAITING;
- if ( pChannel->nStatus != STREAM_NONE )
- {
- int32 status = pChannel->nStatus;
+ if ( pChannel->nStatus != STREAM_NONE )
+ {
+ int32 status = pChannel->nStatus;
- pChannel->nStatus = STREAM_NONE;
+ pChannel->nStatus = STREAM_NONE;
- return status;
- }
+ return status;
+ }
- return STREAM_NONE;
+ return STREAM_NONE;
}
int32
@@ -314,30 +319,35 @@ CdStreamSync(int32 channel)
if (flushStream[channel]) {
#ifdef ONE_THREAD_PER_CHANNEL
pChannel->nSectorsToRead = 0;
- pthread_kill(gpReadInfo[channel].pChannelThread, SIGINT);
+ pthread_kill(pChannel->pChannelThread, SIGUSR1);
+ if (pChannel->bReading) {
+ pChannel->bLocked = true;
+ sem_wait(pChannel->pDoneSemaphore);
+ }
#else
+ pChannel->nSectorsToRead = 0;
if (pChannel->bReading) {
- pChannel->nSectorsToRead = 0;
- pthread_kill(_gCdStreamThread, SIGINT);
- } else {
- pChannel->nSectorsToRead = 0;
+ pChannel->bLocked = true;
+ pthread_kill(_gCdStreamThread, SIGUSR1);
+ sem_wait(pChannel->pDoneSemaphore);
+
}
#endif
pChannel->bReading = false;
flushStream[channel] = false;
- return STREAM_NONE;
+ return STREAM_NONE;
}
- if ( pChannel->nSectorsToRead != 0 )
- {
- pChannel->bLocked = true;
+ if ( pChannel->nSectorsToRead != 0 )
+ {
+ pChannel->bLocked = true;
- sem_wait(&pChannel->pDoneSemaphore);
- }
+ sem_wait(pChannel->pDoneSemaphore);
+ }
- pChannel->bReading = false;
+ pChannel->bReading = false;
- return pChannel->nStatus;
+ return pChannel->nStatus;
}
void
@@ -382,53 +392,52 @@ void *CdStreamThread(void *param)
debug("Created cdstream thread\n");
#ifndef ONE_THREAD_PER_CHANNEL
- while (gCdStreamThreadStatus != 2) {
- sem_wait(&gCdStreamSema);
- int32 channel = GetFirstInQueue(&gChannelRequestQ);
+ while (gCdStreamThreadStatus != 2) {
+ sem_wait(gCdStreamSema);
+ int32 channel = GetFirstInQueue(&gChannelRequestQ);
#else
- int channel = *((int*)param);
- while (gpReadInfo[channel].nThreadStatus != 2){
- sem_wait(&gpReadInfo[channel].pStartSemaphore);
+ int channel = *((int*)param);
+ while (gpReadInfo[channel].nThreadStatus != 2){
+ sem_wait(gpReadInfo[channel].pStartSemaphore);
#endif
- ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
-#ifdef ONE_THREAD_PER_CHANNEL
- if (gpReadInfo[channel].nThreadStatus == 0){
- gpReadInfo[channel].nThreadStatus = 1;
-#else
- if (gCdStreamThreadStatus == 0){
- gCdStreamThreadStatus = 1;
-#endif
-
-#ifdef __linux__
- pid_t tid = syscall(SYS_gettid);
- int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1);
-#endif
- }
-
// spurious wakeup or we sent interrupt signal for flushing
if(pChannel->nSectorsToRead == 0)
- continue;
+ continue;
pChannel->bReading = true;
+ // Not standard POSIX :shrug:
+#ifdef __linux__
+#ifdef ONE_THREAD_PER_CHANNEL
+ if (gpReadInfo[channel].nThreadStatus == 0){
+ gpReadInfo[channel].nThreadStatus = 1;
+#else
+ if (gCdStreamThreadStatus == 0){
+ gCdStreamThreadStatus = 1;
+#endif
+ pid_t tid = syscall(SYS_gettid);
+ int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1);
+ }
+#endif
if ( pChannel->nStatus == STREAM_NONE )
{
- ASSERT(pChannel->hFile >= 0);
- ASSERT(pChannel->pBuffer != nil );
+ ASSERT(pChannel->hFile >= 0);
+ ASSERT(pChannel->pBuffer != nil );
lseek(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, SEEK_SET);
- if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) {
+ if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) {
// pChannel->nSectorsToRead == 0 at this point means we wanted to flush channel
- pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_NONE : STREAM_ERROR;
- } else {
- pChannel->nStatus = STREAM_NONE;
- }
+ // STREAM_WAITING is a little hack to make CStreaming not process this data
+ pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_WAITING : STREAM_ERROR;
+ } else {
+ pChannel->nStatus = STREAM_NONE;
+ }
}
-
+
#ifndef ONE_THREAD_PER_CHANNEL
RemoveFirstInQueue(&gChannelRequestQ);
#endif
@@ -437,22 +446,33 @@ void *CdStreamThread(void *param)
if ( pChannel->bLocked )
{
- sem_post(&pChannel->pDoneSemaphore);
+ sem_post(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
}
+ char semName[20];
#ifndef ONE_THREAD_PER_CHANNEL
- for ( int32 i = 0; i < gNumChannels; i++ )
- {
- sem_destroy(&gpReadInfo[i].pDoneSemaphore);
- }
- sem_destroy(&gCdStreamSema);
+ for ( int32 i = 0; i < gNumChannels; i++ )
+ {
+ sem_close(gpReadInfo[i].pDoneSemaphore);
+ sprintf(semName,"/semaphore_done%d",i);
+ sem_unlink(semName);
+ }
+ sem_close(gCdStreamSema);
+ sem_unlink("/semaphore_cd_stream");
free(gChannelRequestQ.items);
#else
- sem_destroy(&gpReadInfo[channel].pStartSemaphore);
- sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
+ sem_close(gpReadInfo[channel].pStartSemaphore);
+ sprintf(semName,"/semaphore_start%d",channel);
+ sem_unlink(semName);
+
+ sem_close(gpReadInfo[channel].pDoneSemaphore);
+ sprintf(semName,"/semaphore_done%d",channel);
+ sem_unlink(semName);
#endif
- free(gpReadInfo);
+ if (gpReadInfo)
+ free(gpReadInfo);
+ gpReadInfo = nil;
pthread_exit(nil);
}
@@ -469,7 +489,7 @@ CdStreamAddImage(char const *path)
char* real = casepath(path, false);
if (real)
{
- gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
+ gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
free(real);
}
}
@@ -502,8 +522,10 @@ CdStreamGetImageName(int32 cd)
void
CdStreamRemoveImages(void)
{
- for ( int32 i = 0; i < gNumChannels; i++ )
+ for ( int32 i = 0; i < gNumChannels; i++ ) {
+ flushStream[i] = 1;
CdStreamSync(i);
+ }
for ( int32 i = 0; i < gNumImages; i++ )
{
diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp
index 635192ea..da678fd3 100644
--- a/src/core/FileLoader.cpp
+++ b/src/core/FileLoader.cpp
@@ -1052,7 +1052,11 @@ CFileLoader::Load2dEffect(const char *line)
&effect->attractor.dir.z,
&probability);
effect->attractor.type = flags;
+#ifdef FIX_BUGS
+ effect->attractor.probability = clamp(probability, 0, 255);
+#else
effect->attractor.probability = probability;
+#endif
break;
case EFFECT_PED_ATTRACTOR:
sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f %f %f",
diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp
index 4477a190..d3695cb4 100644
--- a/src/core/FileMgr.cpp
+++ b/src/core/FileMgr.cpp
@@ -142,17 +142,17 @@ static size_t
myfread(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
- char *p;
+ unsigned char *p;
size_t i;
int c;
n *= elt;
- p = (char*)buf;
+ p = (unsigned char*)buf;
for(i = 0; i < n; i++){
c = myfgetc(fd);
if(c == EOF)
break;
- *p++ = c;
+ *p++ = (unsigned char)c;
}
return i / elt;
}
@@ -163,12 +163,12 @@ static size_t
myfwrite(void *buf, size_t elt, size_t n, int fd)
{
if(myfiles[fd].isText){
- char *p;
+ unsigned char *p;
size_t i;
int c;
n *= elt;
- p = (char*)buf;
+ p = (unsigned char*)buf;
for(i = 0; i < n; i++){
c = *p++;
myfputc(c, fd);
diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp
index a6928def..5b57cb73 100644
--- a/src/core/Fire.cpp
+++ b/src/core/Fire.cpp
@@ -16,6 +16,9 @@
#include "Ped.h"
#include "Fire.h"
#include "GameLogic.h"
+#include "CarAI.h"
+
+// --MIAMI: file done
CFireManager gFireManager;
@@ -26,14 +29,13 @@ CFire::CFire()
m_bPropagationFlag = true;
m_bAudioSet = true;
m_vecPos = CVector(0.0f, 0.0f, 0.0f);
- m_pEntity = nil;
- m_pSource = nil;
- m_nFiremenPuttingOut = 0;
m_nExtinguishTime = 0;
m_nStartTime = 0;
- field_20 = 1;
- m_nNextTimeToAddFlames = 0;
+ m_pEntity = nil;
+ m_pSource = nil;
m_fStrength = 0.8f;
+ m_fWaterExtinguishCountdown = 1.0f;
+ m_bExtinguishedWithWater = false;
}
CFire::~CFire() {}
@@ -52,6 +54,8 @@ CFire::ProcessFire(void)
CPed *ped = (CPed *)m_pEntity;
CVehicle *veh = (CVehicle*)m_pEntity;
+ m_fWaterExtinguishCountdown = Min(1.0f, 0.002f * CTimer::GetTimeStep() + m_fWaterExtinguishCountdown);
+
if (m_pEntity) {
m_vecPos = m_pEntity->GetPosition();
@@ -109,7 +113,7 @@ CFire::ProcessFire(void)
gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1);
}
if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) {
- m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80;
+ m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + (m_fWaterExtinguishCountdown < 0.3f ? 400 : (m_fWaterExtinguishCountdown < 0.7f ? 200 : 80));
firePos = m_vecPos;
if (veh && veh->IsVehicle() && veh->IsCar()) {
@@ -170,11 +174,23 @@ CFire::Extinguish(void)
m_nExtinguishTime = 0;
m_bIsOngoing = false;
+ m_bExtinguishedWithWater = false;
if (m_pEntity) {
if (m_pEntity->IsPed()) {
- ((CPed *)m_pEntity)->RestorePreviousState();
- ((CPed *)m_pEntity)->m_pFire = nil;
+ CPed *ped = (CPed*)m_pEntity;
+ if (ped->CanSetPedState()) {
+ if (ped->m_nPedState != PED_DRIVING && ped->m_nPedState != PED_FALL) {
+ if (ped->IsPlayer()) {
+ ped->SetIdle();
+ } else {
+ ped->m_nLastPedState = PED_NONE;
+ ped->SetWanderPath(0);
+ ped->SetWaitState(WAITSTATE_FINISH_FLEE, 0);
+ }
+ }
+ }
+ ped->m_pFire = nil;
} else if (m_pEntity->IsVehicle()) {
((CVehicle *)m_pEntity)->m_pCarFire = nil;
}
@@ -184,7 +200,7 @@ CFire::Extinguish(void)
}
void
-CFireManager::StartFire(CVector pos, float size, bool propagation)
+CFireManager::StartFire(CVector pos, float size, uint8 propagation)
{
CFire *fire = GetNextFreeFire();
@@ -201,11 +217,12 @@ CFireManager::StartFire(CVector pos, float size, bool propagation)
fire->m_nNextTimeToAddFlames = 0;
fire->ReportThisFire();
fire->m_fStrength = size;
+ fire->m_bExtinguishedWithWater = false;
}
}
CFire *
-CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation)
+CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, uint8 propagation)
{
CPed *ped = (CPed *)entityOnFire;
CVehicle *veh = (CVehicle *)entityOnFire;
@@ -234,10 +251,11 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength
ped->SetFlee(pos, 10000);
ped->m_fleeFrom = nil;
}
+ ped->m_fleeTimer = CTimer::GetTimeInMilliseconds() + 10000;
ped->bDrawLast = false;
ped->SetMoveState(PEDMOVE_SPRINT);
ped->SetMoveAnim();
- ped->m_nPedState = PED_ON_FIRE;
+ ped->SetPedState(PED_ON_FIRE);
}
if (fleeFrom) {
if (ped->m_nPedType == PEDTYPE_COP) {
@@ -251,6 +269,9 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength
} else {
if (entityOnFire->IsVehicle()) {
veh->m_pCarFire = fire;
+ if (CModelInfo::IsBikeModel(veh->GetModelIndex()) || CModelInfo::IsCarModel(veh->GetModelIndex()))
+ CCarAI::TellOccupantsToFleeCar(veh);
+
if (fleeFrom) {
CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE,
entityOnFire, (CPed *)fleeFrom, 10000);
@@ -259,6 +280,7 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength
}
fire->m_bIsOngoing = true;
+ fire->m_bExtinguishedWithWater = false;
fire->m_bIsScriptFire = false;
fire->m_vecPos = entityOnFire->GetPosition();
@@ -297,26 +319,23 @@ CFireManager::Update(void)
CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance)
{
- for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) {
- int fireId = -1;
- float minDistance = 999999;
- for (int j = 0; j < NUM_FIRES; j++) {
- if (!m_aFires[j].m_bIsOngoing)
- continue;
- if (m_aFires[j].m_bIsScriptFire)
- continue;
- if (m_aFires[j].m_nFiremenPuttingOut != i)
- continue;
- float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D();
- if (distance < minDistance) {
- minDistance = distance;
- fireId = j;
- }
+ int fireId = -1;
+ float minDistance = 999999;
+ for (int j = 0; j < NUM_FIRES; j++) {
+ if (!m_aFires[j].m_bIsOngoing)
+ continue;
+ if (m_aFires[j].m_bIsScriptFire)
+ continue;
+ float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D();
+ if (distance < minDistance) {
+ minDistance = distance;
+ fireId = j;
}
- *pDistance = minDistance;
- if (fireId != -1)
- return &m_aFires[fireId];
}
+ *pDistance = minDistance;
+ if (fireId != -1)
+ return &m_aFires[fireId];
+
return nil;
}
@@ -369,8 +388,39 @@ CFireManager::ExtinguishPoint(CVector point, float range)
}
}
+bool
+CFireManager::ExtinguishPointWithWater(CVector point, float range)
+{
+ int fireI = 0;
+ for (int i = 0; i < NUM_FIRES; i++) {
+ if (m_aFires[i].m_bIsOngoing) {
+ if ((point - m_aFires[i].m_vecPos).MagnitudeSqr() < sq(range)) {
+ fireI = i;
+ break;
+ }
+ }
+ }
+ if (fireI == NUM_FIRES)
+ return false;
+
+ CFire *fireToExtinguish = &m_aFires[fireI];
+ fireToExtinguish->m_fWaterExtinguishCountdown -= 0.012f * CTimer::GetTimeStep();
+ CVector steamPos = fireToExtinguish->m_vecPos +
+ CVector((CGeneral::GetRandomNumber() - 128) * 31.f / 200.f,
+ (CGeneral::GetRandomNumber() - 128) * 31.f / 200.f,
+ CGeneral::GetRandomNumber() / 200.f);
+
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, steamPos, CVector(0.f, 0.f, 0.2f), nil, 0.5f);
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, steamPos, CVector(0.f, 0.f, 0.1f), nil, 0.8f);
+ fireToExtinguish->m_bExtinguishedWithWater = true;
+ if (fireToExtinguish->m_fWaterExtinguishCountdown < 0.0f )
+ fireToExtinguish->Extinguish();
+
+ return true;
+}
+
int32
-CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation)
+CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, uint8 propagation)
{
CFire *fire;
CPed *ped = (CPed *)target;
@@ -397,12 +447,15 @@ CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strengt
fire->m_vecPos = pos;
fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
fire->m_pEntity = target;
+ fire->m_bExtinguishedWithWater = false;
if (target)
target->RegisterReference(&fire->m_pEntity);
fire->m_pSource = nil;
fire->m_nNextTimeToAddFlames = 0;
fire->m_fStrength = strength;
+ fire->m_fWaterExtinguishCountdown = 1.0f;
+
if (target) {
if (target->IsPed()) {
ped->m_pFire = fire;
@@ -410,7 +463,7 @@ CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strengt
CVector2D pos = target->GetPosition();
ped->SetFlee(pos, 10000);
ped->SetMoveAnim();
- ped->m_nPedState = PED_ON_FIRE;
+ ped->SetPedState(PED_ON_FIRE);
}
} else if (target->IsVehicle()) {
veh->m_pCarFire = fire;
@@ -430,8 +483,7 @@ CFireManager::RemoveAllScriptFires(void)
{
for (int i = 0; i < NUM_FIRES; i++) {
if (m_aFires[i].m_bIsScriptFire) {
- m_aFires[i].Extinguish();
- m_aFires[i].m_bIsScriptFire = false;
+ RemoveScriptFire(i);
}
}
}
diff --git a/src/core/Fire.h b/src/core/Fire.h
index 85e53f61..8126f830 100644
--- a/src/core/Fire.h
+++ b/src/core/Fire.h
@@ -14,10 +14,10 @@ public:
CEntity *m_pSource;
uint32 m_nExtinguishTime;
uint32 m_nStartTime;
- int32 field_20;
uint32 m_nNextTimeToAddFlames;
- uint32 m_nFiremenPuttingOut;
float m_fStrength;
+ float m_fWaterExtinguishCountdown;
+ bool m_bExtinguishedWithWater;
CFire();
~CFire();
@@ -34,15 +34,17 @@ class CFireManager
public:
uint32 m_nTotalFires;
CFire m_aFires[NUM_FIRES];
- void StartFire(CVector pos, float size, bool propagation);
- CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation);
+
+ void StartFire(CVector pos, float size, uint8 propagation);
+ CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, uint8 propagation);
void Update(void);
CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange);
CFire *FindNearestFire(CVector vecPos, float *pDistance);
CFire *GetNextFreeFire(void);
uint32 GetTotalActiveFires() const;
void ExtinguishPoint(CVector point, float range);
- int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation);
+ bool ExtinguishPointWithWater(CVector point, float range);
+ int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, uint8 propagation);
bool IsScriptFireExtinguish(int16 index);
void RemoveAllScriptFires(void);
void RemoveScriptFire(int16 index);
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index 6ba6b191..a8637980 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -90,6 +90,7 @@
#include "debugmenu.h"
#include "Ropes.h"
#include "WindModifiers.h"
+#include "WaterCreatures.h"
#include "postfx.h"
#include "custompipes.h"
@@ -478,8 +479,7 @@ bool CGame::ShutDown(void)
CPlane::Shutdown();
CTrain::Shutdown();
CScriptPaths::Shutdown();
- // TODO(Miami)
- // CWaterCreatures::RemoveAll();
+ CWaterCreatures::RemoveAll();
CSpecialFX::Shutdown();
#ifndef PS2
CGarages::Shutdown();
@@ -650,7 +650,7 @@ void CGame::ShutDownForRestart(void)
CRadar::RemoveRadarSections();
FrontEndMenuManager.UnloadTextures();
CParticleObject::RemoveAllExpireableParticleObjects();
- //CWaterCreatures::RemoveAll(); //TODO(Miami)
+ CWaterCreatures::RemoveAll();
CSetPieces::Init();
CPedType::Shutdown();
CSpecialFX::Shutdown();
diff --git a/src/core/General.h b/src/core/General.h
index 7ab444a4..7e06b96e 100644
--- a/src/core/General.h
+++ b/src/core/General.h
@@ -2,6 +2,8 @@
#include <ctype.h>
+// --MIAMI: file done
+
class CGeneral
{
public:
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index aa6e5cc8..b723eb1d 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -3209,7 +3209,7 @@ int16 CPad::SniperModeLookLeftRight(void)
if ( Abs(axis) > Abs(dpad) ) {
if ( Abs(axis) > 35.0f ) {
- return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f;
+ return (axis > 0.f ? axis - 35.f : axis + 35.f) * (128.f / (128 - 35));
} else {
return 0;
}
@@ -3231,7 +3231,7 @@ int16 CPad::SniperModeLookUpDown(void)
if ( Abs(axis) > Abs(dpad) ) {
if ( Abs(axis) > 35.0f ) {
- return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f;
+ return (axis > 0.f ? axis - 35.f : axis + 35.f) * (128.f / (128 - 35));
} else {
return 0;
}
@@ -3573,4 +3573,4 @@ void CPad::FixPadsAfterSave(void)
bObsoleteControllerMessage = false;
GetPad(0)->Phase = 0;
}
-} \ No newline at end of file
+}
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index d296496e..ddde4664 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -46,7 +46,11 @@ CStreamingInfo CStreaming::ms_endRequestedList;
int32 CStreaming::ms_oldSectorX;
int32 CStreaming::ms_oldSectorY;
int32 CStreaming::ms_streamingBufferSize;
+#ifndef ONE_THREAD_PER_CHANNEL
int8 *CStreaming::ms_pStreamingBuffer[2];
+#else
+int8 *CStreaming::ms_pStreamingBuffer[4];
+#endif
size_t CStreaming::ms_memoryUsed;
CStreamingChannel CStreaming::ms_channel[2];
int32 CStreaming::ms_channelError;
@@ -197,6 +201,10 @@ CStreaming::Init2(void)
ms_pStreamingBuffer[0] = (int8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE);
ms_streamingBufferSize /= 2;
ms_pStreamingBuffer[1] = ms_pStreamingBuffer[0] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE;
+#ifdef ONE_THREAD_PER_CHANNEL
+ ms_pStreamingBuffer[2] = (int8*)RwMallocAlign(ms_streamingBufferSize*2*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE);
+ ms_pStreamingBuffer[3] = ms_pStreamingBuffer[2] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE;
+#endif
debug("Streaming buffer size is %d sectors", ms_streamingBufferSize);
// PC only, figure out how much memory we got
@@ -2196,6 +2204,110 @@ CStreaming::LoadRequestedModels(void)
}
}
+
+// Let's load models first, then process it. Unfortunately processing models are still single-threaded.
+// Currently only supported on POSIX streamer.
+#ifdef ONE_THREAD_PER_CHANNEL
+void
+CStreaming::LoadAllRequestedModels(bool priority)
+{
+ static bool bInsideLoadAll = false;
+ int imgOffset, streamId, status;
+ int i;
+ uint32 posn, size;
+
+ if(bInsideLoadAll)
+ return;
+ bInsideLoadAll = true;
+
+ FlushChannels();
+ imgOffset = GetCdImageOffset(CdStreamGetLastPosn());
+
+ int streamIds[ARRAY_SIZE(ms_pStreamingBuffer)];
+ int streamSizes[ARRAY_SIZE(ms_pStreamingBuffer)];
+ int streamPoses[ARRAY_SIZE(ms_pStreamingBuffer)];
+ bool first = true;
+ int processI = 0;
+
+ while (true) {
+ // Enumerate files and start reading
+ for (int i=0; i<ARRAY_SIZE(ms_pStreamingBuffer); i++) {
+ if (!first && streamIds[i] != -1) {
+ processI = i;
+ continue;
+ }
+
+ if(ms_endRequestedList.m_prev != &ms_startRequestedList){
+ streamId = GetNextFileOnCd(0, priority);
+ if(streamId == -1){
+ streamIds[i] = -1;
+ break;
+ }
+
+ if (ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)) {
+ streamIds[i] = -1;
+ if (size > (uint32)ms_streamingBufferSize) {
+ if (i + 1 == ARRAY_SIZE(ms_pStreamingBuffer))
+ continue;
+ else if (!first && streamIds[i+1] != -1)
+ continue;
+ } else {
+ if (i != 0 && streamIds[i-1] != -1 && streamSizes[i-1] > (uint32)ms_streamingBufferSize)
+ continue;
+ }
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ streamIds[i] = streamId;
+ streamSizes[i] = size;
+ streamPoses[i] = posn;
+ CdStreamRead(i, ms_pStreamingBuffer[i], imgOffset+posn, size);
+ processI = i;
+ } else {
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED;
+ streamIds[i] = -1;
+ }
+ } else
+ streamIds[i] = -1;
+ }
+
+ first = false;
+
+ // Now process
+ if (streamIds[processI] == -1)
+ break;
+
+ // Try again on error
+ while (CdStreamSync(processI) != STREAM_NONE) {
+ CdStreamRead(processI, ms_pStreamingBuffer[processI], imgOffset+streamPoses[processI], streamSizes[processI]);
+ }
+ ms_aInfoForModel[streamIds[processI]].m_loadState = STREAMSTATE_READING;
+
+ MakeSpaceFor(streamSizes[processI] * CDSTREAM_SECTOR_SIZE);
+ ConvertBufferToObject(ms_pStreamingBuffer[processI], streamIds[processI]);
+ if(ms_aInfoForModel[streamIds[processI]].m_loadState == STREAMSTATE_STARTED)
+ FinishLoadingLargeFile(ms_pStreamingBuffer[processI], streamIds[processI]);
+
+ if(streamIds[processI] < STREAM_OFFSET_TXD){
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamIds[processI]);
+ if(mi->IsSimple())
+ mi->m_alpha = 255;
+ }
+ streamIds[processI] = -1;
+ }
+
+ ms_bLoadingBigModel = false;
+ for(i = 0; i < 4; i++){
+ ms_channel[1].streamIds[i] = -1;
+ ms_channel[1].offsets[i] = -1;
+ }
+ ms_channel[1].state = CHANNELSTATE_IDLE;
+ bInsideLoadAll = false;
+}
+#else
void
CStreaming::LoadAllRequestedModels(bool priority)
{
@@ -2256,6 +2368,7 @@ CStreaming::LoadAllRequestedModels(bool priority)
ms_channel[1].state = CHANNELSTATE_IDLE;
bInsideLoadAll = false;
}
+#endif
void
CStreaming::FlushChannels(void)
@@ -2287,6 +2400,14 @@ CStreaming::FlushRequestList(void)
next = si->m_next;
RemoveModel(si - ms_aInfoForModel);
}
+#ifndef _WIN32
+ if(ms_channel[0].state == CHANNELSTATE_READING) {
+ flushStream[0] = 1;
+ }
+ if(ms_channel[1].state == CHANNELSTATE_READING) {
+ flushStream[1] = 1;
+ }
+#endif
FlushChannels();
}
@@ -2815,10 +2936,15 @@ CStreaming::DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, size_t mem)
void
CStreaming::MakeSpaceFor(int32 size)
{
- // BUG: ms_memoryAvailable can be uninitialized
- // the code still happens to work in that case because ms_memoryAvailable is unsigned
- // but it's not nice....
-
+#ifdef FIX_BUGS
+#define MB (1024 * 1024)
+ if(ms_memoryAvailable == 0) {
+ extern size_t _dwMemAvailPhys;
+ ms_memoryAvailable = (_dwMemAvailPhys - 10 * MB) / 2;
+ if(ms_memoryAvailable < 65 * MB) ms_memoryAvailable = 65 * MB;
+ }
+#undef MB
+#endif
while(ms_memoryUsed >= ms_memoryAvailable - size)
if(!RemoveLeastUsedModel(STREAMFLAGS_20)){
DeleteRwObjectsBehindCamera(ms_memoryAvailable - size);
diff --git a/src/core/User.cpp b/src/core/User.cpp
index 53196d03..8d584b74 100644
--- a/src/core/User.cpp
+++ b/src/core/User.cpp
@@ -10,6 +10,8 @@
#include "World.h"
#include "Zones.h"
+// --MIAMI: file done
+
CPlaceName CUserDisplay::PlaceName;
COnscreenTimer CUserDisplay::OnscnTimer;
CPager CUserDisplay::Pager;
diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp
index 1eb1513e..288b975e 100644
--- a/src/core/Zones.cpp
+++ b/src/core/Zones.cpp
@@ -9,7 +9,7 @@
#include "World.h"
#include "Timer.h"
-//--MIAMI: file almost done (loading/saving will perhaps stay different)
+//--MIAMI: file done
eLevelName CTheZones::m_CurrLevel;
int16 CTheZones::FindIndex;
@@ -638,127 +638,132 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size)
+ sizeof(int16) // padding
+ sizeof(NavigationZoneArray) + sizeof(InfoZoneArray) + sizeof(ZoneInfoArray)
+ sizeof(TotalNumberOfNavigationZones) + sizeof(TotalNumberOfInfoZones) + sizeof(TotalNumberOfZoneInfos)
+ + sizeof(int16) // padding
+ sizeof(MapZoneArray) + sizeof(AudioZoneArray)
+ sizeof(TotalNumberOfMapZones) + sizeof(NumberOfAudioZones);
- WriteSaveHeader(buffer, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE);
+ uint32 length = 0;
+ WriteSaveHeaderWithLength(buffer, length, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE);
- WriteSaveBuf(buffer, m_CurrLevel);
- WriteSaveBuf(buffer, FindIndex);
- WriteSaveBuf(buffer, (int16)0); // padding
+ WriteSaveBuf(buffer, length, m_CurrLevel);
+ WriteSaveBuf(buffer, length, FindIndex);
+ WriteSaveBuf(buffer, length, (int16)0); // padding
-// TODO(MIAMI) ? implement SaveOneZone
- for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++){
- CZone *zone = WriteSaveBuf(buffer, NavigationZoneArray[i]);
- zone->child = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].child);
- zone->parent = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].parent);
- zone->next = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].next);
- }
+ for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++)
+ SaveOneZone(&NavigationZoneArray[i], &buffer, &length, ZONE_NAVIG);
- for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++){
- CZone *zone = WriteSaveBuf(buffer, InfoZoneArray[i]);
- /*
- The call of GetIndexForZonePointer is wrong, as it is
- meant for a different array, but the game doesn't brake
- if those fields are nil. Let's make sure they are.
- */
- assert(InfoZoneArray[i].child == nil);
- assert(InfoZoneArray[i].parent == nil);
- assert(InfoZoneArray[i].next == nil);
- zone->child = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].child);
- zone->parent = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].parent);
- zone->next = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].next);
- }
+ for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++)
+ SaveOneZone(&InfoZoneArray[i], &buffer, &length, ZONE_INFO);
for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++)
- WriteSaveBuf(buffer, ZoneInfoArray[i]);
-
- WriteSaveBuf(buffer, TotalNumberOfNavigationZones);
- WriteSaveBuf(buffer, TotalNumberOfInfoZones);
- WriteSaveBuf(buffer, TotalNumberOfZoneInfos);
-
- for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) {
- CZone* zone = WriteSaveBuf(buffer, MapZoneArray[i]);
-
- // see above
- assert(MapZoneArray[i].child == nil);
- assert(MapZoneArray[i].parent == nil);
- assert(MapZoneArray[i].next == nil);
- zone->child = (CZone*)GetIndexForZonePointer(MapZoneArray[i].child);
- zone->parent = (CZone*)GetIndexForZonePointer(MapZoneArray[i].parent);
- zone->next = (CZone*)GetIndexForZonePointer(MapZoneArray[i].next);
- }
+ WriteSaveBuf(buffer, length, ZoneInfoArray[i]);
+
+ WriteSaveBuf(buffer, length, TotalNumberOfNavigationZones);
+ WriteSaveBuf(buffer, length, TotalNumberOfInfoZones);
+ WriteSaveBuf(buffer, length, TotalNumberOfZoneInfos);
+ WriteSaveBuf(buffer, length, (int16)0); // padding
+
+ for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++)
+ SaveOneZone(&MapZoneArray[i], &buffer, &length, ZONE_MAPZONE);
for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++)
- WriteSaveBuf(buffer, AudioZoneArray[i]);
+ WriteSaveBuf(buffer, length, AudioZoneArray[i]);
- WriteSaveBuf(buffer, TotalNumberOfMapZones);
- WriteSaveBuf(buffer, NumberOfAudioZones);
+ WriteSaveBuf(buffer, length, TotalNumberOfMapZones);
+ WriteSaveBuf(buffer, length, NumberOfAudioZones);
VALIDATESAVEBUF(*size)
}
void
+CTheZones::SaveOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType)
+{
+ WriteSaveBuf(*buffer, *length, *(uint32*)&zone->name[0]);
+ WriteSaveBuf(*buffer, *length, *(uint32*)&zone->name[4]);
+
+ WriteSaveBuf(*buffer, *length, zone->minx);
+ WriteSaveBuf(*buffer, *length, zone->miny);
+ WriteSaveBuf(*buffer, *length, zone->minz);
+ WriteSaveBuf(*buffer, *length, zone->maxx);
+ WriteSaveBuf(*buffer, *length, zone->maxy);
+ WriteSaveBuf(*buffer, *length, zone->maxz);
+
+ WriteSaveBuf(*buffer, *length, zone->type);
+ WriteSaveBuf(*buffer, *length, zone->level);
+ WriteSaveBuf(*buffer, *length, zone->zoneinfoDay);
+ WriteSaveBuf(*buffer, *length, zone->zoneinfoNight);
+
+ int32 zoneId;
+ zoneId = GetIndexForZonePointer(zone->child);
+ WriteSaveBuf(*buffer, *length, zoneId);
+ zoneId = GetIndexForZonePointer(zone->parent);
+ WriteSaveBuf(*buffer, *length, zoneId);
+ zoneId = GetIndexForZonePointer(zone->next);
+ WriteSaveBuf(*buffer, *length, zoneId);
+}
+
+void
CTheZones::LoadAllZones(uint8 *buffer, uint32 size)
{
INITSAVEBUF
int i;
- CheckSaveHeader(buffer, 'Z', 'N', 'S', '\0', size - SAVE_HEADER_SIZE);
+ uint32 length = 0;
+ CheckSaveHeaderWithLength(buffer, length, 'Z', 'N', 'S', '\0', size - SAVE_HEADER_SIZE);
- m_CurrLevel = ReadSaveBuf<eLevelName>(buffer);
- FindIndex = ReadSaveBuf<int16>(buffer);
- ReadSaveBuf<int16>(buffer);
+ m_CurrLevel = ReadSaveBuf<eLevelName>(buffer, length);
+ FindIndex = ReadSaveBuf<int16>(buffer, length);
+ ReadSaveBuf<int16>(buffer, length);
-// TODO(MIAMI) ? implement LoadOneZone
- for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++){
- NavigationZoneArray[i] = ReadSaveBuf<CZone>(buffer);
+ for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++)
+ LoadOneZone(&NavigationZoneArray[i], &buffer, &length, ZONE_NAVIG);
- NavigationZoneArray[i].child = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].child);
- NavigationZoneArray[i].parent = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].parent);
- NavigationZoneArray[i].next = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].next);
- }
-
- for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++){
- InfoZoneArray[i] = ReadSaveBuf<CZone>(buffer);
-
- /*
- The call of GetPointerForZoneIndex is wrong, as it is
- meant for a different array, but the game doesn't brake
- if save data stored is -1.
- */
- InfoZoneArray[i].child = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].child);
- InfoZoneArray[i].parent = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].parent);
- InfoZoneArray[i].next = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].next);
- assert(InfoZoneArray[i].child == nil);
- assert(InfoZoneArray[i].parent == nil);
- assert(InfoZoneArray[i].next == nil);
- }
+ for (i = 0; i < ARRAY_SIZE(InfoZoneArray); i++)
+ LoadOneZone(&InfoZoneArray[i], &buffer, &length, ZONE_INFO);
for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++)
- ZoneInfoArray[i] = ReadSaveBuf<CZoneInfo>(buffer);
-
- TotalNumberOfNavigationZones = ReadSaveBuf<int16>(buffer);
- TotalNumberOfInfoZones = ReadSaveBuf<int16>(buffer);
- TotalNumberOfZoneInfos = ReadSaveBuf<int16>(buffer);
-
- for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++){
- MapZoneArray[i] = ReadSaveBuf<CZone>(buffer);
-
- // see above
- MapZoneArray[i].child = GetPointerForZoneIndex((uintptr)MapZoneArray[i].child);
- MapZoneArray[i].parent = GetPointerForZoneIndex((uintptr)MapZoneArray[i].parent);
- MapZoneArray[i].next = GetPointerForZoneIndex((uintptr)MapZoneArray[i].next);
- assert(MapZoneArray[i].child == nil);
- assert(MapZoneArray[i].parent == nil);
- assert(MapZoneArray[i].next == nil);
- }
+ ZoneInfoArray[i] = ReadSaveBuf<CZoneInfo>(buffer, length);
+
+ TotalNumberOfNavigationZones = ReadSaveBuf<int16>(buffer, length);
+ TotalNumberOfInfoZones = ReadSaveBuf<int16>(buffer, length);
+ TotalNumberOfZoneInfos = ReadSaveBuf<int16>(buffer, length);
+ ReadSaveBuf<int16>(buffer, length);
+
+ for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++)
+ LoadOneZone(&MapZoneArray[i], &buffer, &length, ZONE_MAPZONE);
for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++)
- AudioZoneArray[i] = ReadSaveBuf<int16>(buffer);
+ AudioZoneArray[i] = ReadSaveBuf<int16>(buffer, length);
- TotalNumberOfMapZones = ReadSaveBuf<uint16>(buffer);
- NumberOfAudioZones = ReadSaveBuf<uint16>(buffer);
+ TotalNumberOfMapZones = ReadSaveBuf<uint16>(buffer, length);
+ NumberOfAudioZones = ReadSaveBuf<uint16>(buffer, length);
VALIDATESAVEBUF(size)
}
+
+void
+CTheZones::LoadOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType)
+{
+ *(uint32*)&zone->name[0] = ReadSaveBuf<uint32>(*buffer, *length);
+ *(uint32*)&zone->name[4] = ReadSaveBuf<uint32>(*buffer, *length);
+
+ zone->minx = ReadSaveBuf<float>(*buffer, *length);
+ zone->miny = ReadSaveBuf<float>(*buffer, *length);
+ zone->minz = ReadSaveBuf<float>(*buffer, *length);
+ zone->maxx = ReadSaveBuf<float>(*buffer, *length);
+ zone->maxy = ReadSaveBuf<float>(*buffer, *length);
+ zone->maxz = ReadSaveBuf<float>(*buffer, *length);
+
+ zone->type = ReadSaveBuf<eZoneType>(*buffer, *length);
+ zone->level = ReadSaveBuf<eLevelName>(*buffer, *length);
+ zone->zoneinfoDay = ReadSaveBuf<int16>(*buffer, *length);
+ zone->zoneinfoNight = ReadSaveBuf<int16>(*buffer, *length);
+
+ int32 zoneId;
+ zoneId = ReadSaveBuf<int32>(*buffer, *length);
+ zone->child = GetPointerForZoneIndex(zoneId);
+ zoneId = ReadSaveBuf<int32>(*buffer, *length);
+ zone->parent = GetPointerForZoneIndex(zoneId);
+ zoneId = ReadSaveBuf<int32>(*buffer, *length);
+ zone->next = GetPointerForZoneIndex(zoneId);
+} \ No newline at end of file
diff --git a/src/core/Zones.h b/src/core/Zones.h
index 92e292b8..3a74427d 100644
--- a/src/core/Zones.h
+++ b/src/core/Zones.h
@@ -108,5 +108,7 @@ public:
static void AddZoneToAudioZoneArray(CZone *zone);
static void InitialiseAudioZoneArray(void);
static void SaveAllZones(uint8 *buffer, uint32 *length);
+ static void SaveOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType);
static void LoadAllZones(uint8 *buffer, uint32 length);
+ static void LoadOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType);
};
diff --git a/src/core/common.h b/src/core/common.h
index 16d32b32..0e6bd60f 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -106,7 +106,7 @@ typedef uint16_t wchar;
inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w)
{
uint32 m = MASK(p,s);
- return w & ~m | b<<p & m;
+ return (w & ~m) | ((b<<p) & m);
}
inline uint32 ldb(uint32 p, uint32 s, uint32 w)
{
@@ -412,6 +412,15 @@ inline void SkipSaveBuf(uint8 *&buf, int32 skip)
#endif
}
+inline void SkipSaveBuf(uint8*& buf, uint32 &length, int32 skip)
+{
+ buf += skip;
+ length += skip;
+#ifdef VALIDATE_SAVE_SIZE
+ _saveBufCount += skip;
+#endif
+}
+
template<typename T>
inline const T ReadSaveBuf(uint8 *&buf)
{
@@ -421,6 +430,14 @@ inline const T ReadSaveBuf(uint8 *&buf)
}
template<typename T>
+inline const T ReadSaveBuf(uint8 *&buf, uint32 &length)
+{
+ T &value = *(T*)buf;
+ SkipSaveBuf(buf, length, sizeof(T));
+ return value;
+}
+
+template<typename T>
inline T *WriteSaveBuf(uint8 *&buf, const T &value)
{
T *p = (T*)buf;
@@ -429,6 +446,15 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
return p;
}
+template<typename T>
+inline T *WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value)
+{
+ T *p = (T*)buf;
+ *p = value;
+ SkipSaveBuf(buf, length, sizeof(T));
+ return p;
+}
+
#define SAVE_HEADER_SIZE (4*sizeof(char)+sizeof(uint32))
@@ -439,6 +465,13 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
WriteSaveBuf(buf, d);\
WriteSaveBuf<uint32>(buf, size);
+#define WriteSaveHeaderWithLength(buf,len,a,b,c,d,size) \
+ WriteSaveBuf(buf, len, a);\
+ WriteSaveBuf(buf, len, b);\
+ WriteSaveBuf(buf, len, c);\
+ WriteSaveBuf(buf, len, d);\
+ WriteSaveBuf<uint32>(buf, len, size);
+
#define CheckSaveHeader(buf,a,b,c,d,size)\
assert(ReadSaveBuf<char>(buf) == a);\
assert(ReadSaveBuf<char>(buf) == b);\
@@ -446,5 +479,12 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
assert(ReadSaveBuf<char>(buf) == d);\
assert(ReadSaveBuf<uint32>(buf) == size);
+#define CheckSaveHeaderWithLength(buf,len,a,b,c,d,size)\
+ assert(ReadSaveBuf<char>(buf,len) == a);\
+ assert(ReadSaveBuf<char>(buf,len) == b);\
+ assert(ReadSaveBuf<char>(buf,len) == c);\
+ assert(ReadSaveBuf<char>(buf,len) == d);\
+ assert(ReadSaveBuf<uint32>(buf,len) == size);
+
void cprintf(char*, ...); \ No newline at end of file
diff --git a/src/core/config.h b/src/core/config.h
index 475a63f8..3f077f4c 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -87,7 +87,8 @@ enum Config {
NUMMBLURSTREAKS = 4,
NUMSKIDMARKS = 32,
- NUMONSCREENTIMERENTRIES = 1,
+ NUMONSCREENCLOCKS = 1,
+ NUMONSCREENCOUNTERS = 3,
NUMRADARBLIPS = 75,
NUMGENERALPICKUPS = 320,
NUMSCRIPTEDPICKUPS = 16,
@@ -137,6 +138,7 @@ enum Config {
NUM_CRANES = 8,
NUM_ESCALATORS = 22,
+ NUM_WATER_CREATURES = 8,
NUM_EXPLOSIONS = 48,
@@ -248,6 +250,9 @@ enum Config {
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
#endif
+#if !defined(_WIN32) && !defined(__SWITCH__)
+#define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list.
+#endif
#define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
#define KANGAROO_CHEAT
#define RESTORE_ALLCARSHELI_CHEAT
@@ -257,7 +262,6 @@ enum Config {
//#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls
// Hud, frontend and radar
-#define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better.
//#define BETA_SLIDING_TEXT
#define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC
#define PC_MENU
@@ -323,4 +327,4 @@ enum Config {
#undef NO_ISLAND_LOADING
#define PC_PARTICLE
#define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial
-#endif \ No newline at end of file
+#endif