diff options
Diffstat (limited to '')
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); } @@ -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){ |