summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Camera.cpp1
-rw-r--r--src/CdStream.cpp529
-rw-r--r--src/CdStream.h47
-rw-r--r--src/FileLoader.cpp1182
-rw-r--r--src/FileLoader.h42
-rw-r--r--src/Game.cpp1
-rw-r--r--src/Game.h1
-rw-r--r--src/Pad.cpp3
-rw-r--r--src/RwHelper.cpp28
-rw-r--r--src/RwHelper.h3
-rw-r--r--src/Timecycle.cpp1
-rw-r--r--src/World.cpp2
-rw-r--r--src/World.h1
-rw-r--r--src/animation/AnimBlendAssocGroup.cpp2
-rw-r--r--src/animation/AnimBlendAssociation.cpp6
-rw-r--r--src/animation/AnimBlendClumpData.cpp4
-rw-r--r--src/common.h11
-rw-r--r--src/control/CarCtrl.cpp3
-rw-r--r--src/control/CarCtrl.h1
-rw-r--r--src/control/Garages.cpp1
-rw-r--r--src/control/HandlingDataMgr.cpp7
-rw-r--r--src/control/HandlingDataMgr.h8
-rw-r--r--src/control/ObjectData.cpp5
-rw-r--r--src/control/ObjectData.h7
-rw-r--r--src/control/PathFind.cpp41
-rw-r--r--src/control/PathFind.h9
-rw-r--r--src/control/PedStats.cpp5
-rw-r--r--src/control/PedStats.h (renamed from src/PedStat.h)6
-rw-r--r--src/control/PedType.cpp5
-rw-r--r--src/control/PedType.h7
-rw-r--r--src/entities/Building.h5
-rw-r--r--src/entities/CutsceneHead.cpp1
-rw-r--r--src/entities/CutsceneObject.cpp1
-rw-r--r--src/entities/Dummy.h3
-rw-r--r--src/entities/DummyObject.cpp13
-rw-r--r--src/entities/DummyObject.h7
-rw-r--r--src/entities/Entity.cpp2
-rw-r--r--src/entities/Entity.h2
-rw-r--r--src/entities/Ped.cpp1
-rw-r--r--src/main.cpp27
-rw-r--r--src/main.h18
-rw-r--r--src/modelinfo/BaseModelInfo.h3
-rw-r--r--src/modelinfo/ModelIndices.h5
-rw-r--r--src/modelinfo/ModelInfo.cpp68
-rw-r--r--src/modelinfo/ModelInfo.h4
-rw-r--r--src/modelinfo/PedModelInfo.h2
-rw-r--r--src/modelinfo/SimpleModelInfo.cpp12
-rw-r--r--src/modelinfo/SimpleModelInfo.h6
-rw-r--r--src/modelinfo/TimeModelInfo.h2
-rw-r--r--src/modelinfo/VehicleModelInfo.h11
-rw-r--r--src/re3.cpp2
-rw-r--r--src/render/2dEffect.h28
-rw-r--r--src/render/Coronas.cpp1
-rw-r--r--src/render/Hud.cpp2
-rw-r--r--src/render/ParticleMgr.cpp1
-rw-r--r--src/render/PointLights.cpp1
-rw-r--r--src/render/Renderer.cpp1
-rw-r--r--src/render/Sprite.cpp1
-rw-r--r--src/render/Sprite2d.cpp1
-rw-r--r--src/skel/win/win.cpp1
-rw-r--r--src/templates.h4
61 files changed, 2147 insertions, 58 deletions
diff --git a/src/Camera.cpp b/src/Camera.cpp
index 1b4b1db6..3af5d953 100644
--- a/src/Camera.cpp
+++ b/src/Camera.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Draw.h"
#include "World.h"
#include "Vehicle.h"
diff --git a/src/CdStream.cpp b/src/CdStream.cpp
new file mode 100644
index 00000000..506e14e9
--- /dev/null
+++ b/src/CdStream.cpp
@@ -0,0 +1,529 @@
+#include <Windows.h>
+#include "common.h"
+#include "patcher.h"
+#include "CdStream.h"
+#include "rwcore.h"
+#include "RwHelper.h"
+
+#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
+#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", __VA_ARGS__)
+
+struct CdReadInfo
+{
+ uint32 nSectorOffset;
+ uint32 nSectorsToRead;
+ void *pBuffer;
+ char field_C;
+ bool bLocked;
+ bool bInUse;
+ char _pad0;
+ int32 nStatus;
+ HANDLE hSemaphore;
+ HANDLE hFile;
+ OVERLAPPED Overlapped;
+};
+VALIDATE_SIZE(CdReadInfo, 0x30);
+
+char gCdImageNames[MAX_CDIMAGES+1][64];
+int32 gNumImages;
+int32 gNumChannels;
+
+HANDLE gImgFiles[MAX_CDIMAGES];
+
+HANDLE _gCdStreamThread;
+HANDLE gCdStreamSema;
+DWORD _gCdStreamThreadId;
+
+CdReadInfo *gpReadInfo;
+Queue gChannelRequestQ;
+
+int32 lastPosnRead;
+
+BOOL _gbCdStreamOverlapped;
+BOOL _gbCdStreamAsync;
+DWORD _gdwCdStreamFlags;
+
+
+void
+CdStreamInitThread(void)
+{
+ SetLastError(0);
+
+ if ( gNumChannels > 0 )
+ {
+ for ( int32 i = 0; i < gNumChannels; i++ )
+ {
+ gpReadInfo[i].hSemaphore = CreateSemaphore(NULL, 0, 2, NULL);
+
+ if ( gpReadInfo[i].hSemaphore == NULL )
+ {
+ CDTRACE("failed to create sync semaphore");
+ ASSERT(0);
+ return;
+ }
+ }
+ }
+
+ gChannelRequestQ.items = (int32 *)LocalAlloc(LMEM_ZEROINIT, sizeof(int32) * (gNumChannels + 1));
+ gChannelRequestQ.head = 0;
+ gChannelRequestQ.tail = 0;
+ gChannelRequestQ.size = gNumChannels + 1;
+ ASSERT(gChannelRequestQ.items != NULL );
+
+ gCdStreamSema = CreateSemaphore(NULL, 0, 5, "CdStream");
+
+ if ( gCdStreamSema == NULL )
+ {
+ CDTRACE("failed to create stream semaphore");
+ ASSERT(0);
+ return;
+ }
+
+ _gCdStreamThread = CreateThread(NULL, 64*1024/*64KB*/, CdStreamThread, NULL, CREATE_SUSPENDED, &_gCdStreamThreadId);
+
+ if ( _gCdStreamThread == NULL )
+ {
+ CDTRACE("failed to create streaming thread");
+ ASSERT(0);
+ return;
+ }
+
+ SetThreadPriority(_gCdStreamThread, GetThreadPriority(GetCurrentThread()) - 1);
+
+ ResumeThread(_gCdStreamThread);
+}
+
+void
+CdStreamInit(int32 numChannels)
+{
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD NumberOfFreeClusters;
+ DWORD TotalNumberOfClusters;
+
+ GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
+
+ _gdwCdStreamFlags = 0;
+
+ if ( BytesPerSector <= CDSTREAM_SECTOR_SIZE )
+ {
+ _gdwCdStreamFlags |= FILE_FLAG_NO_BUFFERING;
+ debug("Using no buffered loading for streaming\n");
+ }
+
+ _gbCdStreamOverlapped = TRUE;
+
+ _gdwCdStreamFlags |= FILE_FLAG_OVERLAPPED;
+
+ _gbCdStreamAsync = FALSE;
+
+ void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, BytesPerSector);
+ ASSERT( pBuffer != NULL );
+
+ SetLastError(0);
+
+ gNumImages = 0;
+
+ gNumChannels = numChannels;
+
+ gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels);
+ ASSERT( gpReadInfo != NULL );
+
+ CDDEBUG("read info %p", gpReadInfo);
+
+ CdStreamAddImage("MODELS\\GTA3.IMG");
+
+ int32 nStatus = CdStreamRead(0, pBuffer, 0, 1);
+
+ CdStreamRemoveImages();
+
+ if ( nStatus == STREAM_SUCCESS )
+ {
+ _gbCdStreamAsync = TRUE;
+
+ debug("Using async loading for streaming\n");
+ }
+ else
+ {
+ _gdwCdStreamFlags &= ~FILE_FLAG_OVERLAPPED;
+
+ _gbCdStreamOverlapped = FALSE;
+
+ _gbCdStreamAsync = TRUE;
+
+ debug("Using sync loading for streaming\n");
+ }
+
+ CdStreamInitThread();
+
+ ASSERT( pBuffer != NULL );
+ RwFreeAlign(pBuffer);
+}
+
+uint32
+GetGTA3ImgSize(void)
+{
+ ASSERT( gImgFiles[0] != NULL );
+ return (uint32)GetFileSize(gImgFiles[0], NULL);
+}
+
+void
+CdStreamShutdown(void)
+{
+ if ( _gbCdStreamAsync )
+ {
+ LocalFree(gChannelRequestQ.items);
+ CloseHandle(gCdStreamSema);
+ CloseHandle(_gCdStreamThread);
+
+ for ( int32 i = 0; i < gNumChannels; i++ )
+ CloseHandle(gpReadInfo[i].hSemaphore);
+ }
+
+ LocalFree(gpReadInfo);
+}
+
+
+
+int32
+CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
+{
+ ASSERT( channel < gNumChannels );
+ ASSERT( buffer != NULL );
+
+ lastPosnRead = size + offset;
+
+ ASSERT( _GET_INDEX(offset) < MAX_CDIMAGES );
+ HANDLE hImage = gImgFiles[_GET_INDEX(offset)];
+ ASSERT( hImage != NULL );
+
+
+ CdReadInfo *pChannel = &gpReadInfo[channel];
+ ASSERT( pChannel != NULL );
+
+ pChannel->hFile = hImage;
+
+ SetLastError(0);
+
+ if ( _gbCdStreamAsync )
+ {
+ if ( pChannel->nSectorsToRead != 0 || pChannel->bInUse )
+ return STREAM_NONE;
+
+ pChannel->nStatus = STREAM_NONE;
+ pChannel->nSectorOffset = _GET_OFFSET(offset);
+ pChannel->nSectorsToRead = size;
+ pChannel->pBuffer = buffer;
+ pChannel->bLocked = 0;
+
+ AddToQueue(&gChannelRequestQ, channel);
+
+ if ( !ReleaseSemaphore(gCdStreamSema, 1, NULL) )
+ printf("Signal Sema Error\n");
+
+ return STREAM_SUCCESS;
+ }
+
+ if ( _gbCdStreamOverlapped )
+ {
+ ASSERT( channel < gNumChannels );
+ CdReadInfo *pChannel = &gpReadInfo[channel];
+ ASSERT( pChannel != NULL );
+
+ pChannel->Overlapped.Offset = _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE;
+
+ if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, NULL, &pChannel->Overlapped)
+ && GetLastError() != ERROR_IO_PENDING )
+ return STREAM_NONE;
+ else
+ return STREAM_SUCCESS;
+ }
+
+ SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, NULL, FILE_BEGIN);
+
+ DWORD NumberOfBytesRead;
+
+ if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, &NumberOfBytesRead, NULL) )
+ return STREAM_NONE;
+ else
+ return STREAM_SUCCESS;
+}
+
+int32
+CdStreamGetStatus(int32 channel)
+{
+ ASSERT( channel < gNumChannels );
+ CdReadInfo *pChannel = &gpReadInfo[channel];
+ ASSERT( pChannel != NULL );
+
+ if ( _gbCdStreamAsync )
+ {
+ if ( pChannel->bInUse )
+ return STREAM_READING;
+
+ if ( pChannel->nSectorsToRead != 0 )
+ return STREAM_WAITING;
+
+ if ( pChannel->nStatus != STREAM_NONE )
+ {
+ int32 status = pChannel->nStatus;
+
+ pChannel->nStatus = STREAM_NONE;
+
+ return status;
+ }
+
+ return STREAM_NONE;
+ }
+
+ if ( _gbCdStreamOverlapped )
+ {
+ ASSERT( pChannel->hFile != NULL );
+ if ( WaitForSingleObjectEx(pChannel->hFile, 0, TRUE) == WAIT_OBJECT_0 )
+ return STREAM_NONE;
+ else
+ return STREAM_READING;
+ }
+
+ return STREAM_NONE;
+}
+
+int32
+CdStreamGetLastPosn(void)
+{
+ return lastPosnRead;
+}
+
+int32
+CdStreamSync(int32 channel)
+{
+ ASSERT( channel < gNumChannels );
+ CdReadInfo *pChannel = &gpReadInfo[channel];
+ ASSERT( pChannel != NULL );
+
+ if ( _gbCdStreamAsync )
+ {
+ if ( pChannel->nSectorsToRead != 0 )
+ {
+ pChannel->bLocked = true;
+
+ ASSERT( pChannel->hSemaphore != NULL );
+
+ WaitForSingleObject(pChannel->hSemaphore, INFINITE);
+ }
+
+ pChannel->bInUse = false;
+
+ return pChannel->nStatus;
+ }
+
+ DWORD NumberOfBytesTransferred;
+
+ if ( _gbCdStreamOverlapped && pChannel->hFile )
+ {
+ ASSERT(pChannel->hFile != NULL );
+ if ( GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) )
+ return STREAM_NONE;
+ else
+ return STREAM_ERROR;
+ }
+
+ return STREAM_NONE;
+}
+
+void
+AddToQueue(Queue *queue, int32 item)
+{
+ ASSERT( queue != NULL );
+ ASSERT( queue->items != NULL );
+ queue->items[queue->tail] = item;
+
+ queue->tail = (queue->tail + 1) % queue->size;
+
+ if ( queue->head == queue->tail )
+ debug("Queue is full\n");
+}
+
+int32
+GetFirstInQueue(Queue *queue)
+{
+ ASSERT( queue != NULL );
+ if ( queue->head == queue->tail )
+ return -1;
+
+ ASSERT( queue->items != NULL );
+ return queue->items[queue->head];
+}
+
+void
+RemoveFirstInQueue(Queue *queue)
+{
+ ASSERT( queue != NULL );
+ if ( queue->head == queue->tail )
+ {
+ debug("Queue is empty\n");
+ return;
+ }
+
+ queue->head = (queue->head + 1) % queue->size;
+}
+
+DWORD
+WINAPI CdStreamThread(LPVOID lpThreadParameter)
+{
+ debug("Created cdstream thread\n");
+
+ while ( true )
+ {
+ WaitForSingleObject(gCdStreamSema, INFINITE);
+
+ int32 channel = GetFirstInQueue(&gChannelRequestQ);
+ ASSERT( channel < gNumChannels );
+
+ CdReadInfo *pChannel = &gpReadInfo[channel];
+ ASSERT( pChannel != NULL );
+
+ pChannel->bInUse = true;
+
+ if ( pChannel->nStatus == STREAM_NONE )
+ {
+ if ( _gbCdStreamOverlapped )
+ {
+ pChannel->Overlapped.Offset = pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE;
+
+ ASSERT(pChannel->hFile != NULL );
+ ASSERT(pChannel->pBuffer != NULL );
+
+ DWORD NumberOfBytesTransferred;
+
+ if ( ReadFile(pChannel->hFile,
+ pChannel->pBuffer,
+ pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE,
+ NULL,
+ &pChannel->Overlapped) )
+ {
+ pChannel->nStatus = STREAM_NONE;
+ }
+ else if ( GetLastError() == ERROR_IO_PENDING
+ && GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) )
+ {
+ pChannel->nStatus = STREAM_NONE;
+ }
+ else
+ {
+ pChannel->nStatus = STREAM_ERROR;
+ }
+ }
+ else
+ {
+ ASSERT(pChannel->hFile != NULL );
+ ASSERT(pChannel->pBuffer != NULL );
+
+ SetFilePointer(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, NULL, FILE_BEGIN);
+
+ DWORD NumberOfBytesRead;
+ if ( ReadFile(pChannel->hFile,
+ pChannel->pBuffer,
+ pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE,
+ &NumberOfBytesRead,
+ NULL) )
+ {
+ pChannel->nStatus = STREAM_NONE;
+ }
+ }
+ }
+
+ RemoveFirstInQueue(&gChannelRequestQ);
+
+ pChannel->nSectorsToRead = 0;
+
+ if ( pChannel->bLocked )
+ {
+ ASSERT( pChannel->hSemaphore != NULL );
+ ReleaseSemaphore(pChannel->hSemaphore, 1, NULL);
+ }
+
+ pChannel->bInUse = false;
+ }
+}
+
+bool
+CdStreamAddImage(char const *path)
+{
+ ASSERT(path != NULL);
+ ASSERT(gNumImages < MAX_CDIMAGES);
+
+ SetLastError(0);
+
+ gImgFiles[gNumImages] = CreateFile(path,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ _gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY,
+ NULL);
+
+ ASSERT( gImgFiles[gNumImages] != NULL );
+ if ( gImgFiles[gNumImages] == NULL )
+ return false;
+
+ strcpy(gCdImageNames[gNumImages], path);
+
+ gNumImages++;
+
+ return true;
+}
+
+char *
+CdStreamGetImageName(int32 cd)
+{
+ ASSERT(cd < MAX_CDIMAGES);
+ if ( gImgFiles[cd] != NULL )
+ return gCdImageNames[cd];
+
+ return NULL;
+}
+
+void
+CdStreamRemoveImages(void)
+{
+ for ( int32 i = 0; i < gNumChannels; i++ )
+ CdStreamSync(i);
+
+ for ( int32 i = 0; i < gNumImages; i++ )
+ {
+ SetLastError(0);
+
+ CloseHandle(gImgFiles[i]);
+ gImgFiles[i] = NULL;
+ }
+
+ gNumImages = 0;
+}
+
+int32
+CdStreamGetNumImages(void)
+{
+ return gNumImages;
+}
+
+
+STARTPATCHES
+ InjectHook(0x405B50, CdStreamInitThread, PATCH_JUMP);
+ InjectHook(0x405C80, CdStreamInit, PATCH_JUMP);
+ //InjectHook(0x405DB0, debug, PATCH_JUMP);
+ InjectHook(0x405DC0, GetGTA3ImgSize, PATCH_JUMP);
+ InjectHook(0x405DD0, CdStreamShutdown, PATCH_JUMP);
+ InjectHook(0x405E40, CdStreamRead, PATCH_JUMP);
+ InjectHook(0x405F90, CdStreamGetStatus, PATCH_JUMP);
+ InjectHook(0x406000, CdStreamGetLastPosn, PATCH_JUMP);
+ InjectHook(0x406010, CdStreamSync, PATCH_JUMP);
+ InjectHook(0x4060B0, AddToQueue, PATCH_JUMP);
+ InjectHook(0x4060F0, GetFirstInQueue, PATCH_JUMP);
+ InjectHook(0x406110, RemoveFirstInQueue, PATCH_JUMP);
+ InjectHook(0x406140, CdStreamThread, PATCH_JUMP);
+ InjectHook(0x406270, CdStreamAddImage, PATCH_JUMP);
+ InjectHook(0x4062E0, CdStreamGetImageName, PATCH_JUMP);
+ InjectHook(0x406300, CdStreamRemoveImages, PATCH_JUMP);
+ InjectHook(0x406370, CdStreamGetNumImages, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/CdStream.h b/src/CdStream.h
new file mode 100644
index 00000000..80c7874f
--- /dev/null
+++ b/src/CdStream.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#define MAX_CDIMAGES 8
+#define CDSTREAM_SECTOR_SIZE 2048
+
+#define _GET_INDEX(a) (a >> 24)
+#define _GET_OFFSET(a) (a & 0xFFFFFF)
+
+enum
+{
+ STREAM_NONE = uint8( 0),
+ STREAM_SUCCESS = uint8( 1),
+ STREAM_READING = uint8(-1), // 0xFF,
+ STREAM_ERROR = uint8(-2), // 0xFE,
+ STREAM_ERROR_NOCD = uint8(-3), // 0xFD,
+ STREAM_ERROR_WRONGCD = uint8(-4), // 0xFC,
+ STREAM_ERROR_OPENCD = uint8(-5), // 0xFB,
+ STREAM_WAITING = uint8(-6) // 0xFA,
+};
+
+struct Queue
+{
+ int32 *items;
+ int32 head;
+ int32 tail;
+ int32 size;
+};
+
+VALIDATE_SIZE(Queue, 0x10);
+
+
+void CdStreamInitThread(void);
+void CdStreamInit(int32 numChannels);
+uint32 GetGTA3ImgSize(void);
+void CdStreamShutdown(void);
+int32 CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size);
+int32 CdStreamGetStatus(int32 channel);
+int32 CdStreamGetLastPosn(void);
+int32 CdStreamSync(int32 channel);
+void AddToQueue(Queue *queue, int32 item);
+int32 GetFirstInQueue(Queue *queue);
+void RemoveFirstInQueue(Queue *queue);
+DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
+bool CdStreamAddImage(char const *path);
+char *CdStreamGetImageName(int32 cd);
+void CdStreamRemoveImages(void);
+int32 CdStreamGetNumImages(void); \ No newline at end of file
diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp
new file mode 100644
index 00000000..7dfb1cd2
--- /dev/null
+++ b/src/FileLoader.cpp
@@ -0,0 +1,1182 @@
+#include "common.h"
+#include "main.h"
+#include "patcher.h"
+#include "math/Quaternion.h"
+#include "ModelInfo.h"
+#include "ModelIndices.h"
+#include "TempColModels.h"
+#include "VisibilityPlugins.h"
+#include "FileMgr.h"
+#include "HandlingDataMgr.h"
+#include "CarCtrl.h"
+#include "PedType.h"
+#include "PedStats.h"
+#include "AnimManager.h"
+#include "Game.h"
+#include "RwHelper.h"
+#include "NodeName.h"
+#include "TxdStore.h"
+#include "PathFind.h"
+#include "ObjectData.h"
+#include "DummyObject.h"
+#include "World.h"
+#include "Zones.h"
+#include "CullZones.h"
+#include "CdStream.h"
+#include "FileLoader.h"
+
+char CFileLoader::ms_line[256];
+
+const char*
+GetFilename(const char *filename)
+{
+ char *s = strrchr((char*)filename, '\\');
+ return s ? s+1 : filename;
+}
+
+void
+LoadingScreenLoadingFile(const char *filename)
+{
+ sprintf(gString, "Loading %s", GetFilename(filename));
+ LoadingScreen("Loading the Game", gString, 0);
+}
+
+void
+CFileLoader::LoadLevel(const char *filename)
+{
+ int fd;
+ RwTexDictionary *savedTxd;
+ int savedLevel;
+ bool objectsLoaded;
+ char *line;
+ char txdname[64];
+
+ savedTxd = RwTexDictionaryGetCurrent();
+ objectsLoaded = false;
+ savedLevel = CGame::currLevel;
+ if(savedTxd == nil){
+ savedTxd = RwTexDictionaryCreate();
+ RwTexDictionarySetCurrent(savedTxd);
+ }
+ fd = CFileMgr::OpenFile(filename, "r");
+ assert(fd > 0);
+
+ for(line = LoadLine(fd); line; line = LoadLine(fd)){
+ if(*line == '#')
+ continue;
+
+ if(strncmp(line, "EXIT", 9) == 0) // BUG: 9?
+ break;
+
+ if(strncmp(line, "IMAGEPATH", 9) == 0){
+ RwImageSetPath(line + 10);
+ }else if(strncmp(line, "TEXDICTION", 10) == 0){
+ strcpy(txdname, line+11);
+ LoadingScreenLoadingFile(txdname);
+ RwTexDictionary *txd = LoadTexDictionary(txdname);
+ AddTexDictionaries(savedTxd, txd);
+ RwTexDictionaryDestroy(txd);
+ }else if(strncmp(line, "COLFILE", 7) == 0){
+ int level;
+ sscanf(line+8, "%d", &level);
+ CGame::currLevel = level;
+ LoadingScreenLoadingFile(line+10);
+ LoadCollisionFile(line+10);
+ CGame::currLevel = savedLevel;
+ }else if(strncmp(line, "MODELFILE", 9) == 0){
+ LoadingScreenLoadingFile(line + 10);
+ LoadModelFile(line + 10);
+ }else if(strncmp(line, "HIERFILE", 8) == 0){
+ LoadingScreenLoadingFile(line + 9);
+ LoadClumpFile(line + 9);
+ }else if(strncmp(line, "IDE", 3) == 0){
+ LoadingScreenLoadingFile(line + 4);
+ LoadObjectTypes(line + 4);
+ }else if(strncmp(line, "IPL", 3) == 0){
+ if(!objectsLoaded){
+ // CModelInfo::ConstructMloClumps();
+ CObjectData::Initialise("DATA\\OBJECT.DAT");
+ objectsLoaded = true;
+ }
+ LoadingScreenLoadingFile(line + 4);
+ LoadScene(line + 4);
+ }else if(strncmp(line, "MAPZONE", 7) == 0){
+ LoadingScreenLoadingFile(line + 8);
+ LoadMapZones(line + 8);
+ }else if(strncmp(line, "SPLASH", 6) == 0){
+ LoadSplash(GetRandomSplashScreen());
+ }else if(strncmp(line, "CDIMAGE", 7) == 0){
+ CdStreamAddImage(line + 8);
+ }
+ }
+
+ CFileMgr::CloseFile(fd);
+ RwTexDictionarySetCurrent(savedTxd);
+}
+
+void
+CFileLoader::LoadCollisionFromDatFile(int currlevel)
+{
+ int fd;
+ char *line;
+
+ fd = CFileMgr::OpenFile(CGame::aDatFile, "r");
+ assert(fd > 0);
+
+ for(line = LoadLine(fd); line; line = LoadLine(fd)){
+ if(*line == '#')
+ continue;
+
+ if(strncmp(line, "COLFILE", 7) == 0){
+ int level;
+ sscanf(line+8, "%d", &level);
+ if(currlevel == level)
+ LoadCollisionFile(line+10);
+ }
+ }
+
+ CFileMgr::CloseFile(fd);
+}
+
+char*
+CFileLoader::LoadLine(int fd)
+{
+ int i;
+ char *line;
+
+ if(CFileMgr::ReadLine(fd, ms_line, 256) == nil)
+ return nil;
+ for(i = 0; ms_line[i] != '\0'; i++)
+ if(ms_line[i] < ' ' || ms_line[i] == ',')
+ ms_line[i] = ' ';
+ for(line = ms_line; *line <= ' ' && *line != '\0'; line++);
+ return line;
+}
+
+RwTexDictionary*
+CFileLoader::LoadTexDictionary(const char *filename)
+{
+ RwTexDictionary *txd;
+ RwStream *stream;
+
+ txd = nil;
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
+ debug("Loading texture dictionary file %s\n", filename);
+ if(stream){
+ if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil))
+ txd = RwTexDictionaryGtaStreamRead(stream);
+ RwStreamClose(stream, nil);
+ }
+ if(txd == nil)
+ txd = RwTexDictionaryCreate();
+ return txd;
+}
+
+void
+CFileLoader::LoadCollisionFile(const char *filename)
+{
+ int fd;
+ char modelname[24];
+ CBaseModelInfo *mi;
+ struct {
+ char ident[4];
+ uint32 size;
+ } header;
+
+ debug("Loading collision file %s\n", filename);
+ fd = CFileMgr::OpenFile(filename, "rb");
+
+ while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){
+ assert(strncmp(header.ident, "COLL", 4) == 0);
+ CFileMgr::Read(fd, (char*)work_buff, header.size);
+ memcpy(modelname, work_buff, 24);
+
+ mi = CModelInfo::GetModelInfo(modelname, nil);
+ if(mi){
+ if(mi->GetColModel()){
+ LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname);
+ }else{
+ CColModel *model = new CColModel;
+ LoadCollisionModel(work_buff+24, *model, modelname);
+ mi->SetColModel(model, true);
+ }
+ }else{
+ debug("colmodel %s can't find a modelinfo\n", modelname);
+ }
+ }
+
+ CFileMgr::CloseFile(fd);
+}
+
+void
+CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname)
+{
+ int i;
+
+ model.boundingSphere.radius = *(float*)(buf);
+ model.boundingSphere.center.x = *(float*)(buf+4);
+ model.boundingSphere.center.y = *(float*)(buf+8);
+ model.boundingSphere.center.z = *(float*)(buf+12);
+ model.boundingBox.min.x = *(float*)(buf+16);
+ model.boundingBox.min.y = *(float*)(buf+20);
+ model.boundingBox.min.z = *(float*)(buf+24);
+ model.boundingBox.max.x = *(float*)(buf+28);
+ model.boundingBox.max.y = *(float*)(buf+32);
+ model.boundingBox.max.z = *(float*)(buf+36);
+ model.numSpheres = *(int16*)(buf+40);
+ buf += 44;
+ if(model.numSpheres > 0){
+ model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere));
+ for(i = 0; i < model.numSpheres; i++){
+ model.spheres[i].Set(*(float*)buf, *(CVector*)(buf+4), buf[16], buf[17]);
+ buf += 20;
+ }
+ }else
+ model.spheres = nil;
+
+ model.numLines = *(int16*)buf;
+ buf += 4;
+ if(model.numLines > 0){
+ model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine));
+ for(i = 0; i < model.numLines; i++){
+ model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12));
+ buf += 24;
+ }
+ }else
+ model.lines = nil;
+
+ model.numBoxes = *(int16*)buf;
+ buf += 4;
+ if(model.numBoxes > 0){
+ model.boxes = (CColBox*)RwMalloc(model.numBoxes*sizeof(CColBox));
+ for(i = 0; i < model.numBoxes; i++){
+ model.boxes[i].Set(*(CVector*)buf, *(CVector*)(buf+12), buf[24], buf[25]);
+ buf += 28;
+ }
+ }else
+ model.boxes = nil;
+
+ int32 numVertices = *(int16*)buf;
+ buf += 4;
+ if(numVertices > 0){
+ model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector));
+ for(i = 0; i < numVertices; i++){
+ model.vertices[i] = *(CVector*)buf;
+ if(fabs(model.vertices[i].x) >= 256.0f ||
+ fabs(model.vertices[i].y) >= 256.0f ||
+ fabs(model.vertices[i].z) >= 256.0f)
+ printf("%s:Collision volume too big\n", modelname);
+ buf += 12;
+ }
+ }else
+ model.vertices = nil;
+
+ model.numTriangles = *(int16*)buf;
+ buf += 4;
+ if(model.numTriangles > 0){
+ model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle));
+ for(i = 0; i < model.numTriangles; i++){
+ model.triangles[i].Set(model.vertices, *(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12], buf[13]);
+ buf += 16;
+ }
+ }else
+ model.triangles = nil;
+}
+
+static void
+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'))
+ underscore = s;
+ }
+ if(underscore){
+ strncpy(name, nodename, underscore - nodename);
+ name[underscore - nodename] = '\0';
+ *n = atoi(underscore + 2);
+ }else{
+ strncpy(name, nodename, 24);
+ *n = 0;
+ }
+}
+
+RpAtomic*
+CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data)
+{
+ CSimpleModelInfo *mi;
+ char *nodename, name[24];
+ int n;
+ RpClump *clump = (RpClump*)data;
+
+ nodename = GetFrameNodeName(RpClumpGetFrame(atomic));
+ GetNameAndLOD(nodename, name, &n);
+ mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, 0);
+ if(mi){
+ assert(mi->IsSimple());
+ mi->SetAtomic(n, atomic);
+ RpClumpRemoveAtomic(clump, atomic);
+ RpAtomicSetFrame(atomic, RwFrameCreate());
+ CVisibilityPlugins::SetAtomicModelInfo(atomic, mi);
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ }else{
+ debug("Can't find Atomic %s\n", name);
+ }
+
+ return atomic;
+}
+
+void
+CFileLoader::LoadModelFile(const char *filename)
+{
+ RwStream *stream;
+ RpClump *clump;
+
+ debug("Loading model file %s\n", filename);
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
+ if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
+ clump = RpClumpStreamRead(stream);
+ if(clump){
+ RpClumpForAllAtomics(clump, FindRelatedModelInfoCB, clump);
+ RpClumpDestroy(clump);
+ }
+ }
+ RwStreamClose(stream, nil);
+}
+
+void
+CFileLoader::LoadClumpFile(const char *filename)
+{
+ RwStream *stream;
+ RpClump *clump;
+ char *nodename, name[24];
+ int n;
+ CClumpModelInfo *mi;
+
+ debug("Loading model file %s\n", filename);
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
+ while(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
+ clump = RpClumpStreamRead(stream);
+ if(clump){
+ nodename = GetFrameNodeName(RpClumpGetFrame(clump));
+ GetNameAndLOD(nodename, name, &n);
+ mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, 0);
+ assert(mi->IsClump());
+ if(mi)
+ mi->SetClump(clump);
+ else
+ RpClumpDestroy(clump);
+ }
+ }
+ RwStreamClose(stream, nil);
+}
+
+bool
+CFileLoader::LoadClumpFile(RwStream *stream, uint32 id)
+{
+ RpClump *clump;
+ CClumpModelInfo *mi;
+
+ if(!RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
+ return false;
+ clump = RpClumpStreamRead(stream);
+ if(clump == nil)
+ return false;
+ mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id);
+ mi->SetClump(clump);
+ if(mi->m_type == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
+ // Read LOD ped
+ clump = RpClumpStreamRead(stream);
+ if(clump){
+ ((CPedModelInfo*)mi)->SetLowDetailClump(clump);
+ RpClumpDestroy(clump);
+ }
+ }
+ return true;
+}
+
+bool
+CFileLoader::StartLoadClumpFile(RwStream *stream, uint32 id)
+{
+ if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
+ printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetName());
+ return RpClumpGtaStreamRead1(stream);
+ }else{
+ printf("FAILED\n");
+ return false;
+ }
+}
+
+bool
+CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id)
+{
+ RpClump *clump;
+ CClumpModelInfo *mi;
+
+ printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetName());
+ clump = RpClumpGtaStreamRead2(stream);
+
+ if(clump){
+ mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id);
+ mi->SetClump(clump);
+ return true;
+ }else{
+ printf("FAILED\n");
+ return false;
+ }
+}
+
+CSimpleModelInfo *gpRelatedModelInfo;
+
+bool
+CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id)
+{
+ RpClump *clump;
+
+ if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
+ clump = RpClumpStreamRead(stream);
+ if(clump == nil)
+ return false;
+ gpRelatedModelInfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
+ RpClumpForAllAtomics(clump, SetRelatedModelInfoCB, clump);
+ RpClumpDestroy(clump);
+ }
+ return true;
+}
+
+RpAtomic*
+CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data)
+{
+ char *nodename, name[24];
+ int n;
+ RpClump *clump = (RpClump*)data;
+
+ nodename = GetFrameNodeName(RpAtomicGetFrame(atomic));
+ GetNameAndLOD(nodename, name, &n);
+ gpRelatedModelInfo->SetAtomic(n, atomic);
+ RpClumpRemoveAtomic(clump, atomic);
+ RpAtomicSetFrame(atomic, RwFrameCreate());
+ CVisibilityPlugins::SetAtomicModelInfo(atomic, gpRelatedModelInfo);
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, 0);
+ return atomic;
+}
+
+RpClump*
+CFileLoader::LoadAtomicFile2Return(const char *filename)
+{
+ RwStream *stream;
+ RpClump *clump;
+
+ clump = nil;
+ debug("Loading model file %s\n", filename);
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
+ if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
+ clump = RpClumpStreamRead(stream);
+ RwStreamClose(stream, nil);
+ return clump;
+}
+
+static RwTexture*
+MoveTexturesCB(RwTexture *texture, void *pData)
+{
+ RwTexDictionaryAddTexture((RwTexDictionary*)pData, texture);
+ return texture;
+}
+
+void
+CFileLoader::AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src)
+{
+ RwTexDictionaryForAllTextures(src, MoveTexturesCB, dst);
+}
+
+void
+CFileLoader::LoadObjectTypes(const char *filename)
+{
+ enum {
+ NONE,
+ OBJS,
+ MLO,
+ TOBJ,
+ HIER,
+ CARS,
+ PEDS,
+ PATH,
+ TWO2FX
+ };
+ char *line;
+ int fd;
+ int section;
+ int pathIndex;
+ char pathTypeStr[20];
+ int id, pathType;
+// int mlo;
+
+ section = NONE;
+ pathIndex = -1;
+// mlo = 0;
+ debug("Loading object types from %s...\n", filename);
+
+ fd = CFileMgr::OpenFile(filename, "rb");
+ for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
+ if(*line == '\0' || *line == '#')
+ continue;
+
+ if(section == NONE){
+ if(strncmp(line, "objs", 4) == 0) section = OBJS;
+ else if(strncmp(line, "tobj", 4) == 0) section = TOBJ;
+ else if(strncmp(line, "hier", 4) == 0) section = HIER;
+ else if(strncmp(line, "cars", 4) == 0) section = CARS;
+ else if(strncmp(line, "peds", 4) == 0) section = PEDS;
+ else if(strncmp(line, "path", 4) == 0) section = PATH;
+ else if(strncmp(line, "2dfx", 4) == 0) section = TWO2FX;
+ }else if(strncmp(line, "end", 3) == 0){
+ section = section == MLO ? OBJS : NONE;
+ }else switch(section){
+ case OBJS:
+ if(strncmp(line, "sta", 3) == 0)
+ assert(0); // LoadMLO
+ else
+ LoadObject(line);
+ break;
+ case MLO:
+ assert(0); // LoadMLOInstance
+ break;
+ case TOBJ:
+ LoadTimeObject(line);
+ break;
+ case HIER:
+ LoadClumpObject(line);
+ break;
+ case CARS:
+ LoadVehicleObject(line);
+ break;
+ case PEDS:
+ LoadPedObject(line);
+ break;
+ case PATH:
+ if(pathIndex == -1){
+ id = LoadPathHeader(line, pathTypeStr);
+ if(strncmp(pathTypeStr, "ped", 4) == 0)
+ pathType = 1;
+ else if(strncmp(pathTypeStr, "car", 4) == 0)
+ pathType = 0;
+ pathIndex = 0;
+ }else{
+ if(pathType == 1)
+ LoadPedPathNode(line, id, pathIndex);
+ else if(pathType == 0)
+ LoadCarPathNode(line, id, pathIndex);
+ pathIndex++;
+ if(pathIndex == 12)
+ pathIndex = -1;
+ }
+ break;
+ case TWO2FX:
+ Load2dEffect(line);
+ break;
+ }
+ }
+ CFileMgr::CloseFile(fd);
+
+ for(id = 0; id < MODELINFOSIZE; id++){
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
+ if(mi && mi->IsSimple())
+ mi->SetupBigBuilding();
+ }
+}
+
+void
+SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags)
+{
+ mi->m_normalCull = !!(flags & 1);
+ mi->m_noFade = !!(flags & 2);
+ mi->m_drawLast = !!(flags & (4|8));
+ mi->m_additive = !!(flags & 8);
+ mi->m_isSubway = !!(flags & 0x10);
+ mi->m_ignoreLight = !!(flags & 0x20);
+ mi->m_noZwrite = !!(flags & 0x40);
+}
+
+void
+CFileLoader::LoadObject(const char *line)
+{
+ int id, numObjs;
+ char model[24], txd[24];
+ float dist[3];
+ uint32 flags;
+ int damaged;
+ CSimpleModelInfo *mi;
+
+ if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
+ return;
+
+ switch(numObjs){
+ case 1:
+ sscanf(line, "%d %s %s %d %f %d",
+ &id, model, txd, &numObjs, &dist[0], &flags);
+ damaged = 0;
+ break;
+ case 2:
+ sscanf(line, "%d %s %s %d %f %f %d",
+ &id, model, txd, &numObjs, &dist[0], &dist[1], &flags);
+ damaged = dist[0] < dist[1] ? // Are distances increasing?
+ 0 : // Yes, no damage model
+ 1; // No, 1 is damaged
+ break;
+ case 3:
+ sscanf(line, "%d %s %s %d %f %f %f %d",
+ &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags);
+ damaged = dist[0] < dist[1] ? // Are distances increasing?
+ (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model
+ 1; // No, 1 and 2 are damaged
+ break;
+ }
+
+ mi = CModelInfo::AddSimpleModel(id);
+ mi->SetName(model);
+ mi->SetNumAtomics(numObjs);
+ mi->SetLodDistances(dist);
+ SetModelInfoFlags(mi, flags);
+ mi->m_firstDamaged = damaged;
+ mi->SetTexDictionary(txd);
+ MatchModelString(model, id);
+}
+
+void
+CFileLoader::LoadTimeObject(const char *line)
+{
+ int id, numObjs;
+ char model[24], txd[24];
+ float dist[3];
+ uint32 flags;
+ int timeOn, timeOff;
+ int damaged;
+ CTimeModelInfo *mi, *other;
+
+ if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
+ return;
+
+ switch(numObjs){
+ case 1:
+ sscanf(line, "%d %s %s %d %f %d %d %d",
+ &id, model, txd, &numObjs, &dist[0], &flags, &timeOn, &timeOff);
+ damaged = 0;
+ break;
+ case 2:
+ sscanf(line, "%d %s %s %d %f %f %d %d %d",
+ &id, model, txd, &numObjs, &dist[0], &dist[1], &flags, &timeOn, &timeOff);
+ damaged = dist[0] < dist[1] ? // Are distances increasing?
+ 0 : // Yes, no damage model
+ 1; // No, 1 is damaged
+ break;
+ case 3:
+ sscanf(line, "%d %s %s %d %f %f %f %d %d %d",
+ &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags, &timeOn, &timeOff);
+ damaged = dist[0] < dist[1] ? // Are distances increasing?
+ (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model
+ 1; // No, 1 and 2 are damaged
+ break;
+ }
+
+ mi = CModelInfo::AddTimeModel(id);
+ mi->SetName(model);
+ mi->SetNumAtomics(numObjs);
+ mi->SetLodDistances(dist);
+ SetModelInfoFlags(mi, flags);
+ mi->m_firstDamaged = damaged;
+ mi->SetTimes(timeOn, timeOff);
+ mi->SetTexDictionary(txd);
+ other = mi->FindOtherTimeModel();
+ if(other)
+ other->SetOtherTimeModel(id);
+ MatchModelString(model, id);
+}
+
+void
+CFileLoader::LoadClumpObject(const char *line)
+{
+ int id;
+ char model[24], txd[24];
+ CClumpModelInfo *mi;
+
+ if(sscanf(line, "%d %s %s", &id, &model, &txd) == 3){
+ mi = CModelInfo::AddClumpModel(id);
+ mi->SetName(model);
+ mi->SetTexDictionary(txd);
+ mi->SetColModel(&CTempColModels::ms_colModelBBox);
+ }
+}
+
+void
+CFileLoader::LoadVehicleObject(const char *line)
+{
+ int id;
+ char model[24], txd[24];
+ char type[8], handlingId[16], gamename[32], vehclass[12];
+ uint32 frequency, comprules;
+ int32 level, misc;
+ float wheelScale;
+ CVehicleModelInfo *mi;
+ char *p;
+
+ sscanf(line, "%d %s %s %s %s %s %s %d %d %x %d %f",
+ &id, model, txd,
+ type, handlingId, gamename, vehclass,
+ &frequency, &level, &comprules, &misc, &wheelScale);
+
+ mi = CModelInfo::AddVehicleModel(id);
+ mi->SetName(model);
+ mi->SetTexDictionary(txd);
+ for(p = gamename; *p; p++)
+ if(*p == '_') *p = ' ';
+ strncpy(mi->m_gameName, gamename, 32);
+ mi->m_level = level;
+ mi->m_compRules = comprules;
+
+ if(strncmp(type, "car", 4) == 0){
+ mi->m_wheelId = misc;
+ mi->m_wheelScale = wheelScale;
+ mi->m_vehicleType = VEHICLE_TYPE_CAR;
+ }else if(strncmp(type, "boat", 5) == 0){
+ mi->m_vehicleType = VEHICLE_TYPE_BOAT;
+ }else if(strncmp(type, "train", 6) == 0){
+ mi->m_vehicleType = VEHICLE_TYPE_TRAIN;
+ }else if(strncmp(type, "heli", 5) == 0){
+ mi->m_vehicleType = VEHICLE_TYPE_HELI;
+ }else if(strncmp(type, "plane", 6) == 0){
+ mi->m_wheelId = misc;
+ mi->m_wheelScale = 1.0f;
+ mi->m_vehicleType = VEHICLE_TYPE_PLANE;
+ }else if(strncmp(type, "bike", 5) == 0){
+ mi->m_bikeSteerAngle = misc;
+ mi->m_wheelScale = wheelScale;
+ mi->m_vehicleType = VEHICLE_TYPE_BIKE;
+ }else
+ assert(0);
+
+ mi->m_handlingId = mod_HandlingManager.GetHandlingId(handlingId);
+
+ // Well this is kinda dumb....
+ if(strncmp(vehclass, "poorfamily", 11) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_POOR;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_POOR);
+ }else if(strncmp(vehclass, "richfamily", 11) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_RICH;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_RICH);
+ }else if(strncmp(vehclass, "executive", 10) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_EXECUTIVE;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_EXECUTIVE);
+ }else if(strncmp(vehclass, "worker", 7) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_WORKER;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_WORKER);
+ }else if(strncmp(vehclass, "special", 8) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_SPECIAL;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_SPECIAL);
+ }else if(strncmp(vehclass, "big", 4) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_BIG;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_BIG);
+ }else if(strncmp(vehclass, "taxi", 5) == 0){
+ mi->m_vehicleClass = VEHICLE_CLASS_TAXI;
+ while(frequency-- > 0)
+ CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_TAXI);
+ }
+}
+
+void
+CFileLoader::LoadPedObject(const char *line)
+{
+ int id;
+ char model[24], txd[24];
+ char pedType[24], pedStats[24], animGroup[24];
+ int carsCanDrive;
+ CPedModelInfo *mi;
+ int animGroupId;
+
+ if(sscanf(line, "%d %s %s %s %s %s %x",
+ &id, model, txd,
+ pedType, pedStats, animGroup, &carsCanDrive) != 7)
+ return;
+
+ mi = CModelInfo::AddPedModel(id);
+ mi->SetName(model);
+ mi->SetTexDictionary(txd);
+ mi->SetColModel(&CTempColModels::ms_colModelPed1);
+ mi->m_pedType = CPedType::FindPedType(pedType);
+ mi->m_pedStatType = CPedStats::GetPedStatType(pedStats);
+ for(animGroupId = 0; animGroupId < NUM_ANIM_ASSOC_GROUPS; animGroupId++)
+ if(strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)animGroupId)) == 0)
+ break;
+ mi->m_animGroup = animGroupId;
+
+ // ???
+ CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1);
+}
+
+int
+CFileLoader::LoadPathHeader(const char *line, char *type)
+{
+ int id;
+ char modelname[32];
+
+ sscanf(line, "%s %d %s", type, &id, modelname);
+ return id;
+}
+
+void
+CFileLoader::LoadPedPathNode(const char *line, int id, int node)
+{
+ int type, next, cross;
+ float x, y, z, width;
+
+ sscanf(line, "%d %d %d %f %f %f %f", &type, &next, &cross, &x, &y, &z, &width);
+ ThePaths.StoreNodeInfoPed(id, node, type, next, x, y, z, 0, !!cross);
+}
+
+void
+CFileLoader::LoadCarPathNode(const char *line, int id, int node)
+{
+ int type, next, cross, numLeft, numRight;
+ float x, y, z, width;
+
+ sscanf(line, "%d %d %d %f %f %f %f %d %d", &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight);
+ ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight);
+}
+
+void
+CFileLoader::Load2dEffect(const char *line)
+{
+ int id, r, g, b, a, type;
+ float x, y, z;
+ char corona[32], shadow[32];
+ int shadowIntens, flash, roadReflection, flare, flags, probability;
+ CBaseModelInfo *mi;
+ C2dEffect *effect;
+ char *p;
+
+ sscanf(line, "%d %f %f %f %d %d %d %d %d", &id, &x, &y, &z, &r, &g, &b, &a, &type);
+
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
+
+ mi = CModelInfo::GetModelInfo(id);
+ effect = CModelInfo::Get2dEffectStore().alloc();
+ mi->Add2dEffect(effect);
+ effect->pos = CVector(x, y, z);
+ effect->col = CRGBA(r, g, b, a);
+ effect->type = type;
+
+ switch(effect->type){
+ case EFFECT_LIGHT:
+ while(*line++ != '"');
+ p = corona;
+ while(*line != '"') *p++ = *line++;
+ *p = '\0';
+ line++;
+
+ while(*line++ != '"');
+ p = shadow;
+ while(*line != '"') *p++ = *line++;
+ *p = '\0';
+ line++;
+
+ sscanf(line, "%f %f %f %f %d %d %d %d %d",
+ &effect->light.dist,
+ &effect->light.outerRange,
+ &effect->light.size,
+ &effect->light.innerRange,
+ &shadowIntens, &flash, &roadReflection, &flare, &flags);
+ effect->light.corona = RwTextureRead(corona, nil);
+ effect->light.shadow = RwTextureRead(shadow, nil);
+ effect->light.shadowIntensity = shadowIntens;
+ effect->light.flash = flash;
+ effect->light.roadReflection = roadReflection;
+ effect->light.flareType = flare;
+ // TODO: check out the flags
+ if(flags & 4)
+ flags &= ~2;
+ effect->light.flags = flags;
+ break;
+
+ case EFFECT_PARTICLE:
+ sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f",
+ &id, &x, &y, &z, &r, &g, &b, &a, &type,
+ &effect->particle.particleType,
+ &effect->particle.dir.x,
+ &effect->particle.dir.y,
+ &effect->particle.dir.z,
+ &effect->particle.scale);
+ break;
+
+ case EFFECT_ATTRACTOR:
+ sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %d",
+ &id, &x, &y, &z, &r, &g, &b, &a, &type,
+ &flags,
+ &effect->attractor.dir.x,
+ &effect->attractor.dir.y,
+ &effect->attractor.dir.z,
+ &probability);
+ effect->attractor.flags = flags;
+ effect->attractor.probability = probability;
+ break;
+ }
+
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CFileLoader::LoadScene(const char *filename)
+{
+ enum {
+ NONE,
+ INST,
+ ZONE,
+ CULL,
+ PICK,
+ PATH,
+ };
+ char *line;
+ int fd;
+ int section;
+ int pathIndex;
+ char pathTypeStr[20];
+
+ section = NONE;
+ pathIndex = -1;
+ debug("Creating objects from %s...\n", filename);
+
+ fd = CFileMgr::OpenFile(filename, "rb");
+ for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
+ if(*line == '\0' || *line == '#')
+ continue;
+
+ if(section == NONE){
+ if(strncmp(line, "inst", 4) == 0) section = INST;
+ else if(strncmp(line, "zone", 4) == 0) section = ZONE;
+ else if(strncmp(line, "cull", 4) == 0) section = CULL;
+ else if(strncmp(line, "pick", 4) == 0) section = PICK;
+ else if(strncmp(line, "path", 4) == 0) section = PATH;
+ }else if(strncmp(line, "end", 3) == 0){
+ section = NONE;
+ }else switch(section){
+ case INST:
+ LoadObjectInstance(line);
+ break;
+ case ZONE:
+ LoadZone(line);
+ break;
+ case CULL:
+ LoadCullZone(line);
+ break;
+ case PICK:
+ // unused
+ LoadPickup(line);
+ break;
+ case PATH:
+ // unfinished in the game
+ if(pathIndex == -1){
+ LoadPathHeader(line, pathTypeStr);
+ // type not set
+ pathIndex = 0;
+ }else{
+ // nodes not loaded
+ pathIndex++;
+ if(pathIndex == 12)
+ pathIndex = -1;
+ }
+ break;
+ }
+ }
+ CFileMgr::CloseFile(fd);
+
+ debug("Finished loading IPL\n");
+}
+
+void
+CFileLoader::LoadObjectInstance(const char *line)
+{
+ int id;
+ char name[24];
+ RwV3d trans, scale, axis;
+ float angle;
+ CSimpleModelInfo *mi;
+ RwMatrix *xform;
+ CEntity *entity;
+
+ if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f",
+ &id, name,
+ &trans.x, &trans.y, &trans.z,
+ &scale.x, &scale.y, &scale.z,
+ &axis.x, &axis.y, &axis.z, &angle) != 12)
+ return;
+
+ mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
+ if(mi == nil)
+ return;
+ assert(mi->IsSimple());
+
+ angle = -RADTODEG(2.0f * acosf(angle));
+ xform = RwMatrixCreate();
+ RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE);
+ RwMatrixTranslate(xform, &trans, rwCOMBINEPOSTCONCAT);
+
+ if(mi->GetObjectID() == -1){
+ if(ThePaths.IsPathObject(id)){
+ entity = new CTreadable;
+ ThePaths.RegisterMapObject((CTreadable*)entity);
+ }else
+ entity = new CBuilding;
+ entity->SetModelIndexNoCreate(id);
+ entity->GetMatrix() = CMatrix(xform);
+ entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition());
+ if(mi->IsSimple()){
+ if(mi->m_isBigBuilding)
+ entity->SetupBigBuilding();
+ if(mi->m_isSubway)
+ entity->bIsSubway = true;
+ }
+ if(mi->GetLargestLodDistance() < 2.0f)
+ entity->bIsVisible = false;
+ CWorld::Add(entity);
+ }else{
+ entity = new CDummyObject;
+ entity->SetModelIndexNoCreate(id);
+ entity->GetMatrix() = CMatrix(xform);
+ CWorld::Add(entity);
+ if(IsGlass(entity->GetModelIndex()))
+ entity->bIsVisible = false;
+ entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition());
+ }
+
+ RwMatrixDestroy(xform);
+}
+
+void
+CFileLoader::LoadZone(const char *line)
+{
+ char name[24];
+ int type, level;
+ float minx, miny, minz;
+ float maxx, maxy, maxz;
+
+ if(sscanf(line, "%s %d %f %f %f %f %f %f %d", name, &type, &minx, &miny, &minz, &maxx, &maxy, &maxz, &level) == 9)
+ CTheZones::CreateZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level);
+}
+
+void
+CFileLoader::LoadCullZone(const char *line)
+{
+ CVector pos;
+ float minx, miny, minz;
+ float maxx, maxy, maxz;
+ int flags;
+ int wantedLevelDrop = 0;
+
+ sscanf(line, "%f %f %f %f %f %f %f %f %f %d %d",
+ &pos.x, &pos.y, &pos.z,
+ &minx, &miny, &minz,
+ &maxx, &maxy, &maxz,
+ &flags, &wantedLevelDrop);
+ CCullZones::AddCullZone(pos, minx, maxx, miny, maxy, minz, maxy, flags, wantedLevelDrop);
+}
+
+// unused
+void
+CFileLoader::LoadPickup(const char *line)
+{
+ int id;
+ float x, y, z;
+
+ sscanf(line, "%d %f %f %f", &id, &x, &y, &z);
+}
+
+void
+CFileLoader::LoadMapZones(const char *filename)
+{
+ enum {
+ NONE,
+ INST,
+ ZONE,
+ CULL,
+ PICK,
+ PATH,
+ };
+ char *line;
+ int fd;
+ int section;
+
+ section = NONE;
+ debug("Creating zones from %s...\n", filename);
+
+ fd = CFileMgr::OpenFile(filename, "rb");
+ for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
+ if(*line == '\0' || *line == '#')
+ continue;
+
+ if(section == NONE){
+ if(strncmp(line, "zone", 4) == 0) section = ZONE;
+ }else if(strncmp(line, "end", 3) == 0){
+ section = NONE;
+ }else switch(section){
+ case ZONE: {
+ char name[24];
+ int type, level;
+ float minx, miny, minz;
+ float maxx, maxy, maxz;
+ if(sscanf(line, "%s %d %f %f %f %f %f %f %d",
+ &name, &type,
+ &minx, &miny, &minz,
+ &maxx, &maxy, &maxz,
+ &level) == 9)
+ CTheZones::CreateMapZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level);
+ }
+ break;
+ }
+ }
+ CFileMgr::CloseFile(fd);
+
+ debug("Finished loading IPL\n");
+}
+
+
+STARTPATCHES
+ // this makes my game crash in CGarage!
+ InjectHook(0x476290, CFileLoader::LoadLevel, PATCH_JUMP);
+
+ InjectHook(0x476520, CFileLoader::LoadCollisionFromDatFile, PATCH_JUMP);
+ InjectHook(0x4761D0, CFileLoader::LoadLine, PATCH_JUMP);
+ InjectHook(0x4765B0, CFileLoader::LoadTexDictionary, PATCH_JUMP);
+ InjectHook(0x478B20, CFileLoader::LoadCollisionFile, PATCH_JUMP);
+ InjectHook(0x478C20, CFileLoader::LoadCollisionModel, PATCH_JUMP);
+ InjectHook(0x476750, CFileLoader::LoadModelFile, PATCH_JUMP);
+ InjectHook(0x476810, (void (*)(const char*))CFileLoader::LoadClumpFile, PATCH_JUMP);
+ InjectHook(0x476990, (bool (*)(RwStream*,uint32))CFileLoader::LoadClumpFile, PATCH_JUMP);
+ InjectHook(0x476A20, CFileLoader::StartLoadClumpFile, PATCH_JUMP);
+ InjectHook(0x476A70, CFileLoader::FinishLoadClumpFile, PATCH_JUMP);
+ InjectHook(0x476930, CFileLoader::LoadAtomicFile, PATCH_JUMP);
+ InjectHook(0x4767C0, CFileLoader::LoadAtomicFile2Return, PATCH_JUMP);
+ InjectHook(0x476630, CFileLoader::AddTexDictionaries, PATCH_JUMP);
+
+ InjectHook(0x476AC0, CFileLoader::LoadObjectTypes, PATCH_JUMP);
+ InjectHook(0x477040, CFileLoader::LoadObject, PATCH_JUMP);
+ InjectHook(0x4774B0, CFileLoader::LoadTimeObject, PATCH_JUMP);
+ InjectHook(0x477920, CFileLoader::LoadClumpObject, PATCH_JUMP);
+ InjectHook(0x477990, CFileLoader::LoadVehicleObject, PATCH_JUMP);
+ InjectHook(0x477DE0, CFileLoader::LoadPedObject, PATCH_JUMP);
+ InjectHook(0x477ED0, CFileLoader::LoadPathHeader, PATCH_JUMP);
+ InjectHook(0x477FF0, CFileLoader::LoadCarPathNode, PATCH_JUMP);
+ InjectHook(0x477F00, CFileLoader::LoadPedPathNode, PATCH_JUMP);
+ InjectHook(0x4780E0, CFileLoader::Load2dEffect, PATCH_JUMP);
+
+ InjectHook(0x478370, CFileLoader::LoadScene, PATCH_JUMP);
+ InjectHook(0x4786B0, CFileLoader::LoadObjectInstance, PATCH_JUMP);
+ InjectHook(0x478A00, CFileLoader::LoadZone, PATCH_JUMP);
+ InjectHook(0x478A90, CFileLoader::LoadCullZone, PATCH_JUMP);
+
+ InjectHook(0x478550, CFileLoader::LoadMapZones, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/FileLoader.h b/src/FileLoader.h
new file mode 100644
index 00000000..f9121ace
--- /dev/null
+++ b/src/FileLoader.h
@@ -0,0 +1,42 @@
+#pragma once
+
+class CFileLoader
+{
+ static char ms_line[256];
+public:
+ static void LoadLevel(const char *filename);
+ static void LoadCollisionFromDatFile(int currlevel);
+ static char *LoadLine(int fd);
+ static RwTexDictionary *LoadTexDictionary(const char *filename);
+ static void LoadCollisionFile(const char *filename);
+ static void LoadCollisionModel(uint8 *buf, CColModel &model, char *name);
+ static void LoadModelFile(const char *filename);
+ static RpAtomic *FindRelatedModelInfoCB(RpAtomic *atomic, void *data);
+ static void LoadClumpFile(const char *filename);
+ static bool LoadClumpFile(RwStream *stream, uint32 id);
+ static bool StartLoadClumpFile(RwStream *stream, uint32 id);
+ static bool FinishLoadClumpFile(RwStream *stream, uint32 id);
+ static bool LoadAtomicFile(RwStream *stream, uint32 id);
+ static RpAtomic *SetRelatedModelInfoCB(RpAtomic *atomic, void *data);
+ static RpClump *LoadAtomicFile2Return(const char *filename);
+ static void AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src);
+
+ static void LoadObjectTypes(const char *filename);
+ static void LoadObject(const char *line);
+ static void LoadTimeObject(const char *line);
+ static void LoadClumpObject(const char *line);
+ static void LoadVehicleObject(const char *line);
+ static void LoadPedObject(const char *line);
+ static int LoadPathHeader(const char *line, char *type);
+ static void LoadPedPathNode(const char *line, int id, int node);
+ static void LoadCarPathNode(const char *line, int id, int node);
+ static void Load2dEffect(const char *line);
+
+ static void LoadScene(const char *filename);
+ static void LoadObjectInstance(const char *line);
+ static void LoadZone(const char *line);
+ static void LoadCullZone(const char *line);
+ static void LoadPickup(const char *line);
+
+ static void LoadMapZones(const char *filename);
+};
diff --git a/src/Game.cpp b/src/Game.cpp
index 5073eed1..f158e9db 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -9,6 +9,7 @@ bool &CGame::frenchGame = *(bool*)0x95CDCB;
bool &CGame::germanGame = *(bool*)0x95CD1E;
bool &CGame::noProstitutes = *(bool*)0x95CDCF;
bool &CGame::playingIntro = *(bool*)0x95CDC2;
+char *CGame::aDatFile = (char*)0x773A48;
WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); }
WRAPPER bool CGame::InitialiseOnceBeforeRW(void) { EAXJMP(0x48BB80); }
diff --git a/src/Game.h b/src/Game.h
index ab881484..6b071125 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -18,6 +18,7 @@ public:
static bool &germanGame;
static bool &noProstitutes;
static bool &playingIntro;
+ static char *aDatFile; //[32];
static void Process(void);
static bool InitialiseOnceBeforeRW(void);
diff --git a/src/Pad.cpp b/src/Pad.cpp
index ab00e88f..a563e26c 100644
--- a/src/Pad.cpp
+++ b/src/Pad.cpp
@@ -1995,7 +1995,10 @@ STARTPATCHES
InjectHook(0x492720, CPad::UpdatePads, PATCH_JUMP);
InjectHook(0x492C60, &CPad::ProcessPCSpecificStuff, PATCH_JUMP);
InjectHook(0x492C70, &CPad::Update, PATCH_JUMP);
+#pragma warning( push )
+#pragma warning( disable : 4573)
InjectHook(0x492F00, (void (*)())CPad::DoCheats, PATCH_JUMP);
+#pragma warning( pop )
InjectHook(0x492F20, (void (CPad::*)(int16))&CPad::DoCheats, PATCH_JUMP);
InjectHook(0x492F30, CPad::StopPadsShaking, PATCH_JUMP);
InjectHook(0x492F50, &CPad::StopShaking, PATCH_JUMP);
diff --git a/src/RwHelper.cpp b/src/RwHelper.cpp
index 6a8c7530..5aa31e92 100644
--- a/src/RwHelper.cpp
+++ b/src/RwHelper.cpp
@@ -4,6 +4,34 @@
#include "TimeCycle.h"
#include "skeleton.h"
+void *
+RwMallocAlign(RwUInt32 size, RwUInt32 align)
+{
+ void *mem = (void *)malloc(size + align);
+
+ ASSERT(mem != NULL);
+
+ void *addr = (void *)((((RwUInt32)mem) + align) & ~(align - 1));
+
+ ASSERT(addr != NULL);
+
+ *(((void **)addr) - 1) = mem;
+
+ return addr;
+}
+
+void
+RwFreeAlign(void *mem)
+{
+ ASSERT(mem != NULL);
+
+ void *addr = *(((void **)mem) - 1);
+
+ ASSERT(addr != NULL);
+
+ free(addr);
+}
+
void
DefinedState(void)
{
diff --git a/src/RwHelper.h b/src/RwHelper.h
index 2dbfd3ce..e0ec00a3 100644
--- a/src/RwHelper.h
+++ b/src/RwHelper.h
@@ -1,5 +1,8 @@
#pragma once
+void *RwMallocAlign(RwUInt32 size, RwUInt32 align);
+void RwFreeAlign(void *mem);
+
void DefinedState(void);
RwFrame *GetFirstChild(RwFrame *frame);
RwObject *GetFirstObject(RwFrame *frame);
diff --git a/src/Timecycle.cpp b/src/Timecycle.cpp
index 56341e32..c04295dd 100644
--- a/src/Timecycle.cpp
+++ b/src/Timecycle.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Clock.h"
#include "Weather.h"
#include "Camera.h"
diff --git a/src/World.cpp b/src/World.cpp
index 1d45dcc8..b5b7ae5c 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -7,6 +7,8 @@
#include "TempColModels.h"
#include "World.h"
+WRAPPER void CWorld::Add(CEntity *entity) { EAXJMP(0x4AE930); }
+
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608;
diff --git a/src/World.h b/src/World.h
index 77e0fd99..c1d870e2 100644
--- a/src/World.h
+++ b/src/World.h
@@ -55,6 +55,7 @@ public:
static bool &bForceProcessControl;
static bool &bProcessCutsceneOnly;
+ static void Add(CEntity *entity);
static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; }
static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; }
diff --git a/src/animation/AnimBlendAssocGroup.cpp b/src/animation/AnimBlendAssocGroup.cpp
index 8b0001ac..fbca92b7 100644
--- a/src/animation/AnimBlendAssocGroup.cpp
+++ b/src/animation/AnimBlendAssocGroup.cpp
@@ -139,7 +139,7 @@ CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump,
DestroyAssociations();
animBlock = CAnimManager::GetAnimationBlock(blockName);
- assocList = new CAnimBlendAssociation[animBlock->numAnims];
+ assocList = new CAnimBlendAssociation[numAssocs];
numAssociations = 0;
for(i = 0; i < numAssocs; i++){
diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp
index eb7019ab..d94fe2c1 100644
--- a/src/animation/AnimBlendAssociation.cpp
+++ b/src/animation/AnimBlendAssociation.cpp
@@ -5,10 +5,7 @@
#include "RpAnimBlend.h"
#include "AnimManager.h"
#include "AnimBlendAssociation.h"
-
-// TODO: implement those
-#define RwFreeAlign RwFree
-#define RwMallocAlign(sz, algn) RwMalloc(sz)
+#include "RwHelper.h"
CAnimBlendAssociation::CAnimBlendAssociation(void)
{
@@ -57,6 +54,7 @@ CAnimBlendAssociation::AllocateAnimBlendNodeArray(int n)
void
CAnimBlendAssociation::FreeAnimBlendNodeArray(void)
{
+ assert(nodes != nil);
RwFreeAlign(nodes);
}
diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp
index 73e71246..06625eb5 100644
--- a/src/animation/AnimBlendClumpData.cpp
+++ b/src/animation/AnimBlendClumpData.cpp
@@ -1,10 +1,8 @@
#include "common.h"
#include "patcher.h"
#include "AnimBlendClumpData.h"
+#include "RwHelper.h"
-// TODO: implement those
-#define RwFreeAlign RwFree
-#define RwMallocAlign(sz, algn) RwMalloc(sz)
CAnimBlendClumpData::CAnimBlendClumpData(void)
{
diff --git a/src/common.h b/src/common.h
index ee6ceadd..46c22c20 100644
--- a/src/common.h
+++ b/src/common.h
@@ -76,13 +76,6 @@ extern void **rwengine;
#define HUD_FROM_RIGHT(a) (SCREEN_WIDTH - HUD_STRETCH_X(a))
#define HUD_FROM_BOTTOM(a) (SCREEN_HEIGHT - HUD_STRETCH_Y(a))
-struct GlobalScene
-{
- RpWorld *world;
- RwCamera *camera;
-};
-extern GlobalScene &Scene;
-
#include "math/Vector.h"
#include "math/Vector2D.h"
#include "math/Matrix.h"
@@ -136,10 +129,6 @@ inline float sq(float x) { return x*x; }
int myrand(void);
void mysrand(unsigned int seed);
-extern uint8 work_buff[55000];
-extern char gString[256];
-extern wchar *gUString;
-
void re3_debug(char *format, ...);
void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...);
void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func);
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 54491cd2..d59ae2d0 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -2,4 +2,5 @@
#include "patcher.h"
#include "CarCtrl.h"
-WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); } \ No newline at end of file
+WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
+WRAPPER void CCarCtrl::AddToCarArray(int id, int vehclass) { EAXJMP(0x4182F0); }
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index fbe36f28..1f468475 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -6,4 +6,5 @@ class CCarCtrl
{
public:
static void SwitchVehicleToRealPhysics(CVehicle*);
+ static void AddToCarArray(int id, int vehclass);
};
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 2994eb49..b8469e5f 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "ModelIndices.h"
#include "Garages.h"
#include "Timer.h"
diff --git a/src/control/HandlingDataMgr.cpp b/src/control/HandlingDataMgr.cpp
new file mode 100644
index 00000000..94824358
--- /dev/null
+++ b/src/control/HandlingDataMgr.cpp
@@ -0,0 +1,7 @@
+#include "common.h"
+#include "patcher.h"
+#include "HandlingDatamgr.h"
+
+cHandlingDataMgr &mod_HandlingManager = *(cHandlingDataMgr*)0x728060;
+
+WRAPPER int32 cHandlingDataMgr::GetHandlingId(const char *name){ EAXJMP(0x546B70); }
diff --git a/src/control/HandlingDataMgr.h b/src/control/HandlingDataMgr.h
new file mode 100644
index 00000000..00e62b59
--- /dev/null
+++ b/src/control/HandlingDataMgr.h
@@ -0,0 +1,8 @@
+#pragma once
+
+class cHandlingDataMgr
+{
+public:
+ int32 GetHandlingId(const char *name);
+};
+extern cHandlingDataMgr &mod_HandlingManager;
diff --git a/src/control/ObjectData.cpp b/src/control/ObjectData.cpp
new file mode 100644
index 00000000..28c34658
--- /dev/null
+++ b/src/control/ObjectData.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "ObjectData.h"
+
+WRAPPER void CObjectData::Initialise(const char *filename) { EAXJMP(0x4BC0E0); }
diff --git a/src/control/ObjectData.h b/src/control/ObjectData.h
new file mode 100644
index 00000000..7df1c845
--- /dev/null
+++ b/src/control/ObjectData.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CObjectData
+{
+public:
+ static void Initialise(const char *filename);
+};
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index 8857f8c9..c3af2e30 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -46,6 +46,43 @@ CTempDetachedNode *&DetachedNodesCars = *(CTempDetachedNode**)0x8E2824;
CTempDetachedNode *&DetachedNodesPeds = *(CTempDetachedNode**)0x8E28A0;
void
+CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing)
+{
+ int i;
+
+ i = id*12 + node;
+ InfoForTilePeds[i].type = type;
+ InfoForTilePeds[i].next = next;
+ InfoForTilePeds[i].x = x;
+ InfoForTilePeds[i].y = y;
+ InfoForTilePeds[i].z = z;
+ InfoForTilePeds[i].numLeftLanes = 0;
+ InfoForTilePeds[i].numRightLanes = 0;
+ InfoForTilePeds[i].crossing = crossing;
+}
+
+void
+CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight)
+{
+ int i;
+
+ i = id*12 + node;
+ InfoForTileCars[i].type = type;
+ InfoForTileCars[i].next = next;
+ InfoForTileCars[i].x = x;
+ InfoForTileCars[i].y = y;
+ InfoForTileCars[i].z = z;
+ InfoForTileCars[i].numLeftLanes = numLeft;
+ InfoForTileCars[i].numRightLanes = numRight;
+}
+
+void
+CPathFind::RegisterMapObject(CTreadable *mapObject)
+{
+ m_mapObjects[m_numMapObjects++] = mapObject;
+}
+
+void
CPathFind::PreparePathData(void)
{
int i, j, k;
@@ -457,8 +494,8 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
}
}else{
// Crosses road
- if(objectpathinfo[istart + iseg].next == jseg && objectpathinfo[istart + iseg].flag & 1 ||
- objectpathinfo[jstart + jseg].next == iseg && objectpathinfo[jstart + jseg].flag & 1)
+ if(objectpathinfo[istart + iseg].next == jseg && objectpathinfo[istart + iseg].crossing ||
+ objectpathinfo[jstart + jseg].next == iseg && objectpathinfo[jstart + jseg].crossing)
m_connectionFlags[m_numConnections] |= ConnectionCrossRoad;
else
m_connectionFlags[m_numConnections] &= ~ConnectionCrossRoad;
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index 495c4a73..83b89953 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -65,8 +65,10 @@ struct CPathInfoForObject
int8 next;
int8 numLeftLanes;
int8 numRightLanes;
- uint8 flag;
+ uint8 crossing : 1;
};
+extern CPathInfoForObject *&InfoForTileCars;
+extern CPathInfoForObject *&InfoForTilePeds;
struct CTempNode
{
@@ -123,6 +125,11 @@ public:
void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo,
float unk, CTempDetachedNode *detachednodes, int unused);
void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out);
+ void StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing);
+ void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight);
+ void RegisterMapObject(CTreadable *mapObject);
+
+ bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); }
};
static_assert(sizeof(CPathFind) == 0x4c8f4, "CPathFind: error");
diff --git a/src/control/PedStats.cpp b/src/control/PedStats.cpp
new file mode 100644
index 00000000..3cb40d76
--- /dev/null
+++ b/src/control/PedStats.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "PedStats.h"
+
+WRAPPER int32 CPedStats::GetPedStatType(char *type) { EAXJMP(0x4EF780); }
diff --git a/src/PedStat.h b/src/control/PedStats.h
index 3045e494..12ebdbc2 100644
--- a/src/PedStat.h
+++ b/src/control/PedStats.h
@@ -15,3 +15,9 @@ struct PedStat
int16 m_flags;
};
static_assert(sizeof(PedStat) == 0x34, "PedStat: error");
+
+class CPedStats
+{
+public:
+ static int32 GetPedStatType(char *type);
+};
diff --git a/src/control/PedType.cpp b/src/control/PedType.cpp
new file mode 100644
index 00000000..587aa815
--- /dev/null
+++ b/src/control/PedType.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "PedType.h"
+
+WRAPPER int32 CPedType::FindPedType(char *type) { EAXJMP(0x4EEC10); }
diff --git a/src/control/PedType.h b/src/control/PedType.h
new file mode 100644
index 00000000..563dc294
--- /dev/null
+++ b/src/control/PedType.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CPedType
+{
+public:
+ static int32 FindPedType(char *type);
+};
diff --git a/src/entities/Building.h b/src/entities/Building.h
index d33aaa4f..612e0fb3 100644
--- a/src/entities/Building.h
+++ b/src/entities/Building.h
@@ -6,7 +6,10 @@ class CBuilding : public CEntity
{
public:
// TODO: ReplaceWithNewModel
- // TODO: ctor
+ CBuilding(void) {
+ m_type = ENTITY_TYPE_BUILDING;
+ bUsesCollision = true;
+ }
static void *operator new(size_t);
static void operator delete(void*, size_t);
diff --git a/src/entities/CutsceneHead.cpp b/src/entities/CutsceneHead.cpp
index 766befb0..a9c47777 100644
--- a/src/entities/CutsceneHead.cpp
+++ b/src/entities/CutsceneHead.cpp
@@ -1,6 +1,7 @@
#include "common.h"
#include <rpskin.h>
#include "patcher.h"
+#include "main.h"
#include "RwHelper.h"
#include "RpAnimBlend.h"
#include "AnimBlendClumpData.h"
diff --git a/src/entities/CutsceneObject.cpp b/src/entities/CutsceneObject.cpp
index d00a668b..1e665dd6 100644
--- a/src/entities/CutsceneObject.cpp
+++ b/src/entities/CutsceneObject.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "lights.h"
#include "PointLights.h"
#include "RpAnimBlend.h"
diff --git a/src/entities/Dummy.h b/src/entities/Dummy.h
index e7506617..034d4c57 100644
--- a/src/entities/Dummy.h
+++ b/src/entities/Dummy.h
@@ -8,6 +8,9 @@ class CDummy : public CEntity
public:
CEntryInfoList m_entryInfoList;
+ CDummy(void) { m_type = ENTITY_TYPE_DUMMY; }
+ // TODO: Add, Remove
+
static void *operator new(size_t);
static void operator delete(void*, size_t);
};
diff --git a/src/entities/DummyObject.cpp b/src/entities/DummyObject.cpp
new file mode 100644
index 00000000..083ad6c6
--- /dev/null
+++ b/src/entities/DummyObject.cpp
@@ -0,0 +1,13 @@
+#include "common.h"
+#include "patcher.h"
+#include "DummyObject.h"
+#include "Pools.h"
+
+CDummyObject::CDummyObject(CObject *obj)
+{
+ SetModelIndexNoCreate(obj->GetModelIndex());
+ if(obj->m_rwObject)
+ AttachToRwObject(obj->m_rwObject);
+ obj->DetachFromRwObject();
+ m_level = obj->m_level;
+}
diff --git a/src/entities/DummyObject.h b/src/entities/DummyObject.h
index 7bfe3a57..d4dce609 100644
--- a/src/entities/DummyObject.h
+++ b/src/entities/DummyObject.h
@@ -2,7 +2,12 @@
#include "Dummy.h"
-class CDummyObject : CDummy
+class CObject;
+
+class CDummyObject : public CDummy
{
+public:
+ CDummyObject(void) {}
+ CDummyObject(CObject *obj);
};
static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error");
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 2338f627..0ab1488d 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -48,7 +48,7 @@ CEntity::CEntity(void)
bHasHitWall = false;
bImBeingRendered = false;
m_flagD8 = false;
- m_flagD10 = false;
+ bIsSubway = false;
bDrawLast = false;
m_flagD40 = false;
m_flagD80 = false;
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index 73a2c668..95294ed8 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -79,7 +79,7 @@ public:
uint32 bHasHitWall : 1;
uint32 bImBeingRendered : 1;
uint32 m_flagD8 : 1;
- uint32 m_flagD10 : 1;
+ uint32 bIsSubway : 1; // set when subway, but maybe different meaning?
uint32 bDrawLast : 1;
uint32 m_flagD40 : 1;
uint32 m_flagD80 : 1; // CObject visibility?
diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp
index 181ba5b7..f6d9f4b2 100644
--- a/src/entities/Ped.cpp
+++ b/src/entities/Ped.cpp
@@ -4,7 +4,6 @@
#include "Particle.h"
#include "Stats.h"
#include "World.h"
-#include "PedStat.h"
#include "DMaudio.h"
#include "Ped.h"
#include "PedType.h"
diff --git a/src/main.cpp b/src/main.cpp
index 655cc106..9bdb41fc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,7 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
+#include "General.h"
#include "RwHelper.h"
#include "Clouds.h"
#include "Draw.h"
@@ -55,6 +57,8 @@
#endif
+GlobalScene &Scene = *(GlobalScene*)0x726768;
+
uint8 work_buff[55000];
char gString[256];
wchar *gUString = (wchar*)0x74B018;
@@ -576,6 +580,29 @@ ResetLoadingScreenBar(void)
NumberOfChunksLoaded = 0.0f;
}
+char*
+GetRandomSplashScreen(void)
+{
+ int index;
+ static int index2 = 0;
+ static char splashName[128];
+ static int splashIndex[24] = {
+ 25, 22, 4, 13,
+ 1, 21, 14, 16,
+ 10, 12, 5, 9,
+ 11, 18, 3, 2,
+ 19, 23, 7, 17,
+ 15, 6, 8, 20
+ };
+
+ index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)];
+ index2++;
+ if(index2 == 6)
+ index2 = 0;
+ sprintf(splashName, "loadsc%d", index);
+ return splashName;
+}
+
#include "rwcore.h"
#include "rpworld.h"
#include "rpmatfx.h"
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 00000000..45948b34
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,18 @@
+#pragma once
+
+struct GlobalScene
+{
+ RpWorld *world;
+ RwCamera *camera;
+};
+extern GlobalScene &Scene;
+
+extern uint8 work_buff[55000];
+extern char gString[256];
+extern wchar *gUString;
+
+class CSprite2d;
+
+void LoadingScreen(const char *str1, const char *str2, const char *splashscreen);
+CSprite2d *LoadSplash(const char *name);
+char *GetRandomSplashScreen(void);
diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h
index fadea18a..b6c6c62e 100644
--- a/src/modelinfo/BaseModelInfo.h
+++ b/src/modelinfo/BaseModelInfo.h
@@ -41,6 +41,9 @@ public:
virtual RwObject *GetRwObject(void) = 0;
bool IsSimple(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME; }
+ bool IsClump(void) { return m_type == MITYPE_CLUMP || m_type == MITYPE_PED || m_type == MITYPE_VEHICLE ||
+ m_type == MITYPE_MLO || m_type == MITYPE_XTRACOMPS; // unused but what the heck
+ }
char *GetName(void) { return m_name; }
void SetName(const char *name) { strncpy(m_name, name, 24); }
void SetColModel(CColModel *col, bool free = false){
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 7567c0db..be091e9b 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -320,9 +320,12 @@ enum
MI_CAR_PANEL,
MI_CAR_BONNET,
MI_CAR_BOOT,
- MI_CAR_WEEL,
+ MI_CAR_WHEEL,
MI_BODYPARTA,
MI_BODYPARTB,
+
+ MI_AIRTRAIN_VLO = 198,
+ MI_LOPOLYGUY,
};
void InitModelIndices(void);
diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp
index 89fcdee5..ca36aa61 100644
--- a/src/modelinfo/ModelInfo.cpp
+++ b/src/modelinfo/ModelInfo.cpp
@@ -1,5 +1,7 @@
#include "common.h"
#include "patcher.h"
+#include "TempColModels.h"
+#include "ModelIndices.h"
#include "ModelInfo.h"
CBaseModelInfo **CModelInfo::ms_modelInfoPtrs = (CBaseModelInfo**)0x83D408;
@@ -18,6 +20,8 @@ void
CModelInfo::Initialise(void)
{
int i;
+ CSimpleModelInfo *m;
+
for(i = 0; i < MODELINFOSIZE; i++)
ms_modelInfoPtrs[i] = nil;
ms_2dEffectStore.clear();
@@ -26,10 +30,58 @@ CModelInfo::Initialise(void)
ms_clumpModelStore.clear();
ms_pedModelStore.clear();
ms_vehicleModelStore.clear();
+
+ m = AddSimpleModel(MI_CAR_DOOR);
+ m->SetColModel(&CTempColModels::ms_colModelDoor1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BUMPER);
+ m->SetColModel(&CTempColModels::ms_colModelBumper1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_PANEL);
+ m->SetColModel(&CTempColModels::ms_colModelPanel1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BONNET);
+ m->SetColModel(&CTempColModels::ms_colModelBonnet1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BOOT);
+ m->SetColModel(&CTempColModels::ms_colModelBoot1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_WHEEL);
+ m->SetColModel(&CTempColModels::ms_colModelWheel1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_BODYPARTA);
+ m->SetColModel(&CTempColModels::ms_colModelBodyPart1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_BODYPARTB);
+ m->SetColModel(&CTempColModels::ms_colModelBodyPart2);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
}
void
-CModelInfo::Shutdown(void)
+CModelInfo::ShutDown(void)
{
int i;
for(i = 0; i < ms_simpleModelStore.allocPtr; i++)
@@ -42,6 +94,8 @@ CModelInfo::Shutdown(void)
ms_pedModelStore.store[i].Shutdown();
for(i = 0; i < ms_vehicleModelStore.allocPtr; i++)
ms_vehicleModelStore.store[i].Shutdown();
+ for(i = 0; i < ms_2dEffectStore.allocPtr; i++)
+ ms_2dEffectStore.store[i].Shutdown();
}
CSimpleModelInfo*
@@ -115,10 +169,12 @@ CModelInfo::GetModelInfo(const char *name, int *id)
}
STARTPATCHES
-// InjectHook(0x50B920, CModelInfo::AddSimpleModel, PATCH_JUMP);
-// InjectHook(0x50B9C0, CModelInfo::AddTimeModel, PATCH_JUMP);
-// InjectHook(0x50BA10, CModelInfo::AddClumpModel, PATCH_JUMP);
-// InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP);
-// InjectHook(0x50BA60, CModelInfo::AddPedModel, PATCH_JUMP);
+ InjectHook(0x50B310, CModelInfo::Initialise, PATCH_JUMP);
+ InjectHook(0x50B5B0, CModelInfo::ShutDown, PATCH_JUMP);
+ InjectHook(0x50B920, CModelInfo::AddSimpleModel, PATCH_JUMP);
+ InjectHook(0x50B9C0, CModelInfo::AddTimeModel, PATCH_JUMP);
+ InjectHook(0x50BA10, CModelInfo::AddClumpModel, PATCH_JUMP);
+ InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP);
+ InjectHook(0x50BA60, CModelInfo::AddVehicleModel, PATCH_JUMP);
InjectHook(0x50B860, (CBaseModelInfo *(*)(const char*, int*))CModelInfo::GetModelInfo, PATCH_JUMP);
ENDPATCHES
diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h
index a0d30dea..4ab633bf 100644
--- a/src/modelinfo/ModelInfo.h
+++ b/src/modelinfo/ModelInfo.h
@@ -20,7 +20,7 @@ class CModelInfo
public:
static void Initialise(void);
- static void Shutdown(void);
+ static void ShutDown(void);
static CSimpleModelInfo *AddSimpleModel(int id);
static CTimeModelInfo *AddTimeModel(int id);
@@ -28,6 +28,8 @@ public:
static CPedModelInfo *AddPedModel(int id);
static CVehicleModelInfo *AddVehicleModel(int id);
+ static CStore<C2dEffect, TWODFXSIZE> &Get2dEffectStore(void) { return ms_2dEffectStore; }
+
static CBaseModelInfo *GetModelInfo(const char *name, int *id);
static CBaseModelInfo *GetModelInfo(int id){
return ms_modelInfoPtrs[id];
diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h
index 95d49090..d0b93323 100644
--- a/src/modelinfo/PedModelInfo.h
+++ b/src/modelinfo/PedModelInfo.h
@@ -21,7 +21,7 @@ enum PedNode {
class CPedModelInfo : public CClumpModelInfo
{
public:
- void *m_animGroup; // TODO
+ int32 m_animGroup;
int32 m_pedType;
int32 m_pedStatType;
uint32 m_carsCanDrive;
diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp
index a5853d6f..ea7a3f9e 100644
--- a/src/modelinfo/SimpleModelInfo.cpp
+++ b/src/modelinfo/SimpleModelInfo.cpp
@@ -53,7 +53,7 @@ CSimpleModelInfo::Init(void)
m_atomics[1] = nil;
m_atomics[2] = nil;
m_numAtomics = 0;
- m_furthest = 0;
+ m_firstDamaged = 0;
m_normalCull = 0;
m_isDamaged = 0;
m_isBigBuilding = 0;
@@ -103,11 +103,10 @@ float
CSimpleModelInfo::GetLargestLodDistance(void)
{
float d;
- // TODO: what exactly is going on here?
- if(m_furthest != 0 && !m_isDamaged)
- d = m_lodDistances[m_furthest-1];
- else
+ if(m_firstDamaged == 0 || m_isDamaged)
d = m_lodDistances[m_numAtomics-1];
+ else
+ d = m_lodDistances[m_firstDamaged-1];
return d * TheCamera.LODDistMultiplier;
}
@@ -116,9 +115,8 @@ CSimpleModelInfo::GetAtomicFromDistance(float dist)
{
int i;
i = 0;
- // TODO: what exactly is going on here?
if(m_isDamaged)
- i = m_furthest;
+ i = m_firstDamaged;
for(; i < m_numAtomics; i++)
if(dist < m_lodDistances[i] *TheCamera.LODDistMultiplier)
return m_atomics[i];
diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h
index 186a517c..d5b572a6 100644
--- a/src/modelinfo/SimpleModelInfo.h
+++ b/src/modelinfo/SimpleModelInfo.h
@@ -11,9 +11,9 @@ public:
float m_lodDistances[3];
uint8 m_numAtomics;
uint8 m_alpha;
- uint16 m_furthest : 2; // 0: numAtomics-1 is furthest visible
- // 1: atomic 0 is furthest
- // 2: atomic 1 is furthest
+ uint16 m_firstDamaged : 2; // 0: no damage model
+ // 1: 1 and 2 are damage models
+ // 2: 2 is damage model
uint16 m_normalCull : 1;
uint16 m_isDamaged : 1;
uint16 m_isBigBuilding : 1;
diff --git a/src/modelinfo/TimeModelInfo.h b/src/modelinfo/TimeModelInfo.h
index 08e46bd3..f8b7c8ff 100644
--- a/src/modelinfo/TimeModelInfo.h
+++ b/src/modelinfo/TimeModelInfo.h
@@ -12,7 +12,9 @@ public:
int32 GetTimeOn(void) { return m_timeOn; }
int32 GetTimeOff(void) { return m_timeOff; }
+ void SetTimes(int32 on, int32 off) { m_timeOn = on; m_timeOff = off; }
int32 GetOtherTimeModel(void) { return m_otherTimeModelID; }
+ void SetOtherTimeModel(int32 other) { m_otherTimeModelID = other; }
CTimeModelInfo *FindOtherTimeModel(void);
};
static_assert(sizeof(CTimeModelInfo) == 0x58, "CTimeModelInfo: error");
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
index f69760b8..3f89414d 100644
--- a/src/modelinfo/VehicleModelInfo.h
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -35,6 +35,17 @@ enum {
NUM_VEHICLE_TYPES
};
+enum {
+ VEHICLE_CLASS_POOR,
+ VEHICLE_CLASS_RICH,
+ VEHICLE_CLASS_EXECUTIVE,
+ VEHICLE_CLASS_WORKER,
+ VEHICLE_CLASS_SPECIAL,
+ VEHICLE_CLASS_BIG,
+ VEHICLE_CLASS_TAXI,
+ NUM_VEHICLE_CLASSES
+};
+
class CVehicleModelInfo : public CClumpModelInfo
{
public:
diff --git a/src/re3.cpp b/src/re3.cpp
index 905aa992..7fa9eedb 100644
--- a/src/re3.cpp
+++ b/src/re3.cpp
@@ -10,8 +10,6 @@
void **rwengine = *(void***)0x5A10E1;
-GlobalScene &Scene = *(GlobalScene*)0x726768;
-
DebugMenuAPI gDebugMenuAPI;
WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); }
diff --git a/src/render/2dEffect.h b/src/render/2dEffect.h
index 6cba85d1..780d9b4f 100644
--- a/src/render/2dEffect.h
+++ b/src/render/2dEffect.h
@@ -1,3 +1,9 @@
+enum {
+ EFFECT_LIGHT,
+ EFFECT_PARTICLE,
+ EFFECT_ATTRACTOR
+};
+
class C2dEffect
{
public:
@@ -7,26 +13,26 @@ public:
float size;
float innerRange;
uint8 flash;
- uint8 wet;
- uint8 flare;
- uint8 shadowIntens;
- uint8 flag;
+ uint8 roadReflection;
+ uint8 flareType;
+ uint8 shadowIntensity;
+ uint8 flags;
RwTexture *corona;
RwTexture *shadow;
};
struct Particle {
int particleType;
- float dir[3];
+ CVector dir;
float scale;
};
struct Attractor {
CVector dir;
- uint8 flag;
+ uint8 flags;
uint8 probability;
};
CVector pos;
- RwRGBA col;
+ CRGBA col;
uint8 type;
union {
Light light;
@@ -35,5 +41,13 @@ public:
};
C2dEffect(void) {}
+ void Shutdown(void){
+ if(type == 0){ // TODO: enum
+ if(light.corona)
+ RwTextureDestroy(light.corona);
+ if(light.shadow)
+ RwTextureDestroy(light.shadow);
+ }
+ }
};
static_assert(sizeof(C2dEffect) == 0x34, "C2dEffect: error");
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index 5947a77f..64053007 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "General.h"
#include "TxdStore.h"
#include "Camera.h"
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index bd8cee51..5bf78521 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -432,7 +432,7 @@ void CHud::Draw()
if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_fHealth >= 10
|| CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_fHealth < 10 && CTimer::GetFrameCounter() & 8) {
- AsciiToUnicode("[", sPrintIcon);
+ AsciiToUnicode("{", sPrintIcon);
sprintf(sTemp, "%03d", (int32)CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_fHealth);
AsciiToUnicode(sTemp, sPrint);
diff --git a/src/render/ParticleMgr.cpp b/src/render/ParticleMgr.cpp
index 15370b47..440ea9cb 100644
--- a/src/render/ParticleMgr.cpp
+++ b/src/render/ParticleMgr.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "FileMgr.h"
#include "ParticleMgr.h"
diff --git a/src/render/PointLights.cpp b/src/render/PointLights.cpp
index 0eb41821..2b840314 100644
--- a/src/render/PointLights.cpp
+++ b/src/render/PointLights.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Lights.h"
#include "Camera.h"
#include "Weather.h"
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 5a27ab32..bd16922c 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Lights.h"
#include "ModelInfo.h"
#include "Treadable.h"
diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp
index 92c3e8a6..57a8a22f 100644
--- a/src/render/Sprite.cpp
+++ b/src/render/Sprite.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Draw.h"
#include "Camera.h"
#include "Sprite.h"
diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp
index 3dc1d989..4ed27fa1 100644
--- a/src/render/Sprite2d.cpp
+++ b/src/render/Sprite2d.cpp
@@ -1,5 +1,6 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "Draw.h"
#include "Camera.h"
#include "Sprite2d.h"
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index e1090f72..a8abe1dd 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -83,6 +83,7 @@ static psGlobalType &PsGlobal = *(psGlobalType*)0x72CF60;
#include "common.h"
#include "patcher.h"
+#include "main.h"
#include "FileMgr.h"
#include "Text.h"
#include "Pad.h"
diff --git a/src/templates.h b/src/templates.h
index 03e41a64..3ac0bc90 100644
--- a/src/templates.h
+++ b/src/templates.h
@@ -8,8 +8,10 @@ public:
T store[n];
T *alloc(void){
- if(this->allocPtr >= n)
+ if(this->allocPtr >= n){
printf("Size of this thing:%d needs increasing\n", n);
+ assert(0);
+ }
return &this->store[this->allocPtr++];
}
void clear(void){