diff options
Diffstat (limited to 'src/core/FileLoader.cpp')
-rw-r--r-- | src/core/FileLoader.cpp | 1004 |
1 files changed, 311 insertions, 693 deletions
diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index afa2a66f..dbf2cad9 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include <ctype.h> #include "main.h" #include "General.h" @@ -25,6 +26,9 @@ #include "CdStream.h" #include "FileLoader.h" #include "MemoryHeap.h" +#include "Streaming.h" +#include "ColStore.h" +#include "Occlusion.h" char CFileLoader::ms_line[256]; @@ -47,36 +51,24 @@ CFileLoader::LoadLevel(const char *filename) { int fd; RwTexDictionary *savedTxd; - eLevelName savedLevel; bool objectsLoaded; char *line; char txdname[64]; savedTxd = RwTexDictionaryGetCurrent(); objectsLoaded = false; - savedLevel = CGame::currLevel; if(savedTxd == nil){ savedTxd = RwTexDictionaryCreate(); RwTexDictionarySetCurrent(savedTxd); } -#if GTA_VERSION <= GTA3_PS2_160 - CFileMgr::ChangeDir("\\DATA\\"); - fd = CFileMgr::OpenFile(filename, "r"); - CFileMgr::ChangeDir("\\"); -#else fd = CFileMgr::OpenFile(filename, "r"); -#endif assert(fd > 0); for(line = LoadLine(fd); line; line = LoadLine(fd)){ if(*line == '#') continue; -#ifdef FIX_BUGS if(strncmp(line, "EXIT", 4) == 0) -#else - if(strncmp(line, "EXIT", 9) == 0) -#endif break; if(strncmp(line, "IMAGEPATH", 9) == 0){ @@ -90,12 +82,8 @@ CFileLoader::LoadLevel(const char *filename) RwTexDictionaryDestroy(txd); POP_MEMID(); }else if(strncmp(line, "COLFILE", 7) == 0){ - int level; - sscanf(line+8, "%d", &level); - CGame::currLevel = (eLevelName)level; LoadingScreenLoadingFile(line+10); - LoadCollisionFile(line+10); - CGame::currLevel = savedLevel; + LoadCollisionFile(line+10, 0); }else if(strncmp(line, "MODELFILE", 9) == 0){ LoadingScreenLoadingFile(line + 10); LoadModelFile(line + 10); @@ -107,19 +95,23 @@ CFileLoader::LoadLevel(const char *filename) LoadObjectTypes(line + 4); }else if(strncmp(line, "IPL", 3) == 0){ if(!objectsLoaded){ - PUSH_MEMID(MEMID_DEF_MODELS); - CModelInfo::ConstructMloClumps(); - POP_MEMID(); + LoadingScreenLoadingFile("Collision"); + PUSH_MEMID(MEMID_WORLD); CObjectData::Initialise("DATA\\OBJECT.DAT"); + CStreaming::Init(); + POP_MEMID(); + PUSH_MEMID(MEMID_COLLISION); + CColStore::LoadAllCollision(); + POP_MEMID(); + for(int i = 0; i < MODELINFOSIZE; i++) + if(CModelInfo::GetModelInfo(i)) + CModelInfo::GetModelInfo(i)->ConvertAnimFileIndex(); objectsLoaded = true; } PUSH_MEMID(MEMID_WORLD); LoadingScreenLoadingFile(line + 4); LoadScene(line + 4); POP_MEMID(); - }else if(strncmp(line, "MAPZONE", 7) == 0){ - LoadingScreenLoadingFile(line + 8); - LoadMapZones(line + 8); }else if(strncmp(line, "SPLASH", 6) == 0){ #ifndef DISABLE_LOADING_SCREEN LoadSplash(GetRandomSplashScreen()); @@ -133,30 +125,13 @@ CFileLoader::LoadLevel(const char *filename) 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); + int i; + for(i = 1; i < COLSTORESIZE; i++) + if(CColStore::GetSlot(i)) + CColStore::GetBoundingBox(i).Grow(120.0f); + CWorld::RepositionCertainDynamicObjects(); + CColStore::RemoveAllCollision(); } char* @@ -200,7 +175,7 @@ struct ColHeader }; void -CFileLoader::LoadCollisionFile(const char *filename) +CFileLoader::LoadCollisionFile(const char *filename, uint8 colSlot) { int fd; char modelname[24]; @@ -211,6 +186,7 @@ CFileLoader::LoadCollisionFile(const char *filename) debug("Loading collision file %s\n", filename); fd = CFileMgr::OpenFile(filename, "rb"); + assert(fd > 0); while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){ assert(header.ident == 'LLOC'); @@ -219,10 +195,11 @@ CFileLoader::LoadCollisionFile(const char *filename) mi = CModelInfo::GetModelInfo(modelname, nil); if(mi){ - if(mi->GetColModel()){ + if(mi->GetColModel() && mi->DoesOwnColModel()){ LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname); }else{ CColModel *model = new CColModel; + model->level = colSlot; LoadCollisionModel(work_buff+24, *model, modelname); mi->SetColModel(model, true); } @@ -236,6 +213,79 @@ CFileLoader::LoadCollisionFile(const char *filename) POP_MEMID(); } + +bool +CFileLoader::LoadCollisionFileFirstTime(uint8 *buffer, uint32 size, uint8 colSlot) +{ + uint32 modelsize; + char modelname[24]; + CBaseModelInfo *mi; + ColHeader *header; + int modelIndex; + + while(size > 8){ + header = (ColHeader*)buffer; + modelsize = header->size; + if(header->ident != 'LLOC') + return size-8 < CDSTREAM_SECTOR_SIZE; + memcpy(modelname, buffer+8, 24); + memcpy(work_buff, buffer+32, modelsize-24); + size -= 32 + (modelsize-24); + buffer += 32 + (modelsize-24); + if(modelsize > 15*1024) + debug("colmodel %s is huge, size %d\n", modelname, modelsize); + + mi = CModelInfo::GetModelInfo(modelname, &modelIndex); + if(mi){ + CColStore::IncludeModelIndex(colSlot, modelIndex); + CColModel *model = new CColModel; + model->level = colSlot; + LoadCollisionModel(work_buff, *model, modelname); + mi->SetColModel(model, true); + }else{ + debug("colmodel %s can't find a modelinfo\n", modelname); + } + } + return true; +} + +bool +CFileLoader::LoadCollisionFile(uint8 *buffer, uint32 size, uint8 colSlot) +{ + uint32 modelsize; + char modelname[24]; + CBaseModelInfo *mi; + ColHeader *header; + + while(size > 8){ + header = (ColHeader*)buffer; + modelsize = header->size; + if(header->ident != 'LLOC') + return size-8 < CDSTREAM_SECTOR_SIZE; + memcpy(modelname, buffer+8, 24); + memcpy(work_buff, buffer+32, modelsize-24); + size -= 32 + (modelsize-24); + buffer += 32 + (modelsize-24); + if(modelsize > 15*1024) + debug("colmodel %s is huge, size %d\n", modelname, modelsize); + + mi = CModelInfo::GetModelInfo(modelname, CColStore::GetSlot(colSlot)->minIndex, CColStore::GetSlot(colSlot)->maxIndex); + if(mi){ + if(mi->GetColModel()){ + LoadCollisionModel(work_buff, *mi->GetColModel(), modelname); + }else{ + CColModel *model = new CColModel; + model->level = colSlot; + LoadCollisionModel(work_buff, *model, modelname); + mi->SetColModel(model, true); + } + }else{ + debug("colmodel %s can't find a modelinfo\n", modelname); + } + } + return true; +} + void CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) { @@ -266,14 +316,16 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) model.numLines = *(int16*)buf; buf += 4; if(model.numLines > 0){ - model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine)); + //model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine)); REGISTER_MEMPTR(&model.lines); for(i = 0; i < model.numLines; i++){ - model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12)); + //model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12)); buf += 24; } }else model.lines = nil; + model.numLines = 0; + model.lines = nil; model.numBoxes = *(int16*)buf; buf += 4; @@ -294,10 +346,12 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) REGISTER_MEMPTR(&model.vertices); for(i = 0; i < numVertices; i++){ model.vertices[i].Set(*(float*)buf, *(float*)(buf+4), *(float*)(buf+8)); +#if 0 if(Abs(*(float*)buf) >= 256.0f || Abs(*(float*)(buf+4)) >= 256.0f || Abs(*(float*)(buf+8)) >= 256.0f) printf("%s:Collision volume too big\n", modelname); +#endif buf += 12; } }else @@ -309,7 +363,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle)); REGISTER_MEMPTR(&model.triangles); 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]); + model.triangles[i].Set(*(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12]); buf += 16; } }else @@ -321,7 +375,7 @@ GetNameAndLOD(char *nodename, char *name, int *n) { char *underscore = nil; for(char *s = nodename; *s != '\0'; s++){ - if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L')) + if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L') && isdigit(s[2])) underscore = s; } if(underscore){ @@ -347,11 +401,11 @@ CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data) mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, nil); if(mi){ assert(mi->IsSimple()); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); 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); } @@ -427,17 +481,9 @@ CFileLoader::LoadClumpFile(RwStream *stream, uint32 id) clump = RpClumpStreamRead(stream); if(clump == nil) return false; + InitClump(clump); mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); mi->SetClump(clump); - if (mi->GetModelType() == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) { - // Read LOD ped - clump = RpClumpStreamRead(stream); - InitClump(clump); - if(clump){ - ((CPedModelInfo*)mi)->SetLowDetailClump(clump); - RpClumpDestroy(clump); - } - } return true; } @@ -492,425 +538,6 @@ CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id) return true; } -#ifdef HARDCODED_MODEL_FLAGS -char *DoubleSidedNames[] = { - "chnabankdoor", - "Security_Hut", - "Hospital_Sub", - "phonebooth1", - "trafficlight1", - "sub_roadbarrier", - "redlightbuild09", - "doublestreetlght1", - "doc_shedbig31", - "com_land_128", - "garage7", - "proj_garage01", - "buildingground2", - "buildingground3", - "ch_roof_kb", - "overpassind", - "casino", - "ind_land100", - "fuckedup_skewlbus", - "Police_Station_ind", - "flagsitaly", - "sidebarrier_gaz1", - "bar_barrier12", - "bar_barrier10b", - "sidebarrier_gaz2", - "doc_shedbig3", - "doc_shedbig4", - "verticalift_bridge", - "verticalift_bridg2", - "usdcrdlrbuild01", - "apairporthanger", - "apairporthangerA", - "porthangerclosed", - "redlightbuild13", - "doc_rave", - "const_woodfence", - "const_woodfence2", - "const_woodfence3", - "subfraightback01", - "subfraightback02", - "subfraightback03", - "subfraightback04", - "subind_build03", - "chinabanner1", - "chinabanner2", - "chinabanner3", - "chinabanner4", - "Pumpfirescape", - "Pumphouse", - "amcounder", - "barrel1", - "barrel2", - "barrel3", - "barrel4", - "com_1way50", - "com_1way20", - "overpasscom01", - "overpasscom02", - "overpasscom03", - "overpasscom04", - "overpass_comse", - "newdockbuilding", - "newdockbuilding2", - "policeballhall", - "fuzballdoor", - "ind_land106", - "PoliceBallSigns", - "amcoudet", - "rustship_structure", - "impexpgrgesub", - "ind_land128", - "fshfctry_dstryd", - "railtrax_bentl", - "railtrax_lo4b", - "railtrax_straight", - "railtrax_bentrb", - "railtrax_skew", - "newtrackaaa", - "railtrax_skew5", - // these they forgot: - "railtrax_skewp", - "railtrax_ske2b", - "railtrax_strtshort", - "railtrax_2b", - "railtrax_straightss", - "railtrax_bentr", - "ind_land125", - "salvstrans", - "bridge_liftsec", - "subsign1", - "carparkfence", - "newairportwall4", - "apair_terminal", - "Helipad", - "bar_barrier10", - "damissionfence", - "sub_floodlite", - "suburbbridge1", - "damfencing", - "demfence08", - "damfence07", - "damfence06", - "damfence05", - "damfence04", - "damfence03", - "damfence02", - "damfence01", - "Dam_pod2", - "Dam_pod1", - "columansion_wall", - "wrckdhse020", - "wrckdhse01", - "arc_bridge", - "gRD_overpass19kbc", - "gRD_overpass19bkb", - "gRD_overpass19kb", - "gRD_overpass18kb", - "road_under", - "com_roadkb23", - "com_roadkb22", - "nbbridgerda", - "nbbridgerdb", - "policetenkb1", - "block3_scraper2", - "Clnm_cthdrlfcde", - "broadwaybuild", - "combillboard03", - "com_park3b", - "com_docksaa", - "newdockbuilding2", - "com_roadkb22", - "sidebarrier_gaz2", - "tunnelsupport1", - "skyscrpunbuilt2", - "cons_buid02", - "rail_platformw", - "railtrax_bent1", - "nrailstepswest", - "building_fucked", - "franksclb02", - "salvsdetail", - "crgoshp01", - "shp_wlkway", - "bar_barriergate1", - "plnt_pylon01", - "fishfctory", - "doc_crane_cab", - "nrailsteps", - "iten_club01", - "mak_Watertank", - "basketballcourt" - "carlift01", - "carlift02", - "iten_chinatown4", - "iten_details7", - "ind_customroad002" - "ind_brgrd1way", - "ind_customroad060", - "ind_customroad002", - "ind_land108", - "ind_customroad004", - "ind_customroad003", - "nbbridgcabls01", - "sbwy_tunl_bit", - "sbwy_tunl_bend", - "sbwy_tunl_cstm11", - "sbwy_tunl_cstm10", - "sbwy_tunl_cstm9", - "sbwy_tunl_cstm8", - "sbwy_tunl_cstm7", - "sbwy_tunl_cstm6", - "sbwy_tunl_cstm5", - "sbwy_tunl_cstm4", - "sbwy_tunl_cstm3", - "sbwy_tunl_cstm2", - "sbwy_tunl_cstm1", - "tenmnt6ad", - "" - -}; -char *TreeNames[] = { - "coast_treepatch", - "comparknewtrees", - "comtreepatchprk", - "condotree01", - "condotree1", - "indatree03", - "indtreepatch5", - "indtreepatch06f", - "new_carprktrees", - "new_carprktrees4", - "newcoasttrees1", - "newcoasttrees2", - "newcoasttrees3", - "newtreepatch_sub", - "newtrees1_sub", - "newunitrepatch", - "pinetree_narrow", - "pinetree_wide", - "treencom2", - "treepatch", - "treepatch01_sub", - "treepatch02_sub", - "treepatch2", - "treepatch2b", - "treepatch03", - "treepatch03_sub", - "treepatch04_sub", - "treepatch05_sub", - "treepatch06_sub", - "treepatch07_sub", - "treepatch08_sub", - "treepatch09_sub", - "treepatch10_sub", - "treepatch11_sub", - "treepatch12_sub", - "treepatch13_sub", - "treepatch14_sub", - "treepatch15_sub", - "treepatch16_sub", - "treepatch17_sub", - "treepatch18_sub", - "treepatch19_sub", - "treepatch20_sub", - "treepatch21_sub", - "treepatch22_sub", - "treepatch23_sub", - "treepatch24_sub", - "treepatch25_sub", - "treepatch26_sub", - "treepatch27_sub", - "treepatch28_sub", - "treepatch29_sub", - "treepatch30_sub", - "treepatch31_sub", - "treepatch32_sub", - "treepatch33_sub", - "treepatch34_sub", - "treepatch35_sub", - "treepatch69", - "treepatch152_sub", - "treepatch153_sub", - "treepatch171_sub", - "treepatch172_sub", - "treepatch173_sub", - "treepatch212_sub", - "treepatch213_sub", - "treepatch214_sub", - "treepatcha", - "treepatchb", - "treepatchcomtop1", - "treepatchd", - "treepatche", - "treepatchh", - "treepatchindaa2", - "treepatchindnew", - "treepatchindnew2", - "treepatchk", - "treepatchkb4", - "treepatchkb5", - "treepatchkb6", - "treepatchkb7", - "treepatchkb9", - "treepatchl", - "treepatchm", - "treepatchnew_sub", - "treepatchttwrs", - "treesuni1", - "trepatchindaa1", - "veg_bush2", - "veg_bush14", - "veg_tree1", - "veg_tree3", - "veg_treea1", - "veg_treea3", - "veg_treeb1", - "veg_treenew01", - "veg_treenew03", - "veg_treenew05", - "veg_treenew06", - "veg_treenew08", - "veg_treenew09", - "veg_treenew10", - "veg_treenew16", - "veg_treenew17", - "vegclubtree01", - "vegclubtree02", - "vegclubtree03", - "vegpathtree", - "" -}; -char *OptimizedNames[] = { - "coast_treepatch", - "comparknewtrees", - "comtreepatchprk", - "indtreepatch5", - "indtreepatch06f", - "new_carprktrees", - "new_carprktrees4", - "newcoasttrees1", - "newcoasttrees2", - "newcoasttrees3", - "newtreepatch_sub", - "newtrees1_sub", - "newunitrepatch", - "treepatch", - "treepatch01_sub", - "treepatch02_sub", - "treepatch2", - "treepatch2b", - "treepatch03", - "treepatch03_sub", - "treepatch04_sub", - "treepatch05_sub", - "treepatch06_sub", - "treepatch07_sub", - "treepatch08_sub", - "treepatch09_sub", - "treepatch10_sub", - "treepatch11_sub", - "treepatch12_sub", - "treepatch13_sub", - "treepatch14_sub", - "treepatch15_sub", - "treepatch16_sub", - "treepatch17_sub", - "treepatch18_sub", - "treepatch19_sub", - "treepatch20_sub", - "treepatch21_sub", - "treepatch22_sub", - "treepatch23_sub", - "treepatch24_sub", - "treepatch25_sub", - "treepatch26_sub", - "treepatch27_sub", - "treepatch28_sub", - "treepatch29_sub", - "treepatch30_sub", - "treepatch31_sub", - "treepatch32_sub", - "treepatch33_sub", - "treepatch34_sub", - "treepatch35_sub", - "treepatch69", - "treepatch152_sub", - "treepatch153_sub", - "treepatch171_sub", - "treepatch172_sub", - "treepatch173_sub", - "treepatch212_sub", - "treepatch213_sub", - "treepatch214_sub", - "treepatcha", - "treepatchb", - "treepatchcomtop1", - "treepatchd", - "treepatche", - "treepatchh", - "treepatchindaa2", - "treepatchindnew", - "treepatchindnew2", - "treepatchk", - "treepatchkb4", - "treepatchkb5", - "treepatchkb6", - "treepatchkb7", - "treepatchkb9", - "treepatchl", - "treepatchm", - "treepatchnew_sub", - "treepatchttwrs", - "treesuni1", - "trepatchindaa1", - "combtm_treeshad01", - "combtm_treeshad02", - "combtm_treeshad03", - "combtm_treeshad04", - "combtm_treeshad05", - "combtm_treeshad06", - "comtop_tshad", - "comtop_tshad2", - "comtop_tshad3", - "comtop_tshad4", - "comtop_tshad5", - "comtop_tshad6", - "se_treeshad01", - "se_treeshad02", - "se_treeshad03", - "se_treeshad04", - "se_treeshad05", - "se_treeshad06", - "treeshads01", - "treeshads02", - "treeshads03", - "treeshads04", - "treeshads05", - "" -}; -// not from mobile -static bool -MatchModelName(char *name, char **list) -{ - int i; - char *s; - for(i = 0; *list[i] != '\0'; i++) - if(strncmp(name, "LOD", 3) == 0){ - if(!CGeneral::faststricmp(name+3, list[i]+3)) - return true; - }else{ - if(!CGeneral::faststricmp(name, list[i])) - return true; - } - return false; -} -#endif - RpAtomic* CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data) { @@ -920,11 +547,11 @@ CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data) nodename = GetFrameNodeName(RpAtomicGetFrame(atomic)); GetNameAndLOD(nodename, name, &n); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); gpRelatedModelInfo->SetAtomic(n, atomic); RpClumpRemoveAtomic(clump, atomic); RpAtomicSetFrame(atomic, RwFrameCreate()); CVisibilityPlugins::SetAtomicModelInfo(atomic, gpRelatedModelInfo); - CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); return atomic; } @@ -967,8 +594,9 @@ CFileLoader::LoadObjectTypes(const char *filename) enum { NONE, OBJS, - MLO, + MLO, // unused but enum still has it TOBJ, + WEAP, HIER, CARS, PEDS, @@ -979,16 +607,17 @@ CFileLoader::LoadObjectTypes(const char *filename) int fd; int section; int pathIndex; - char pathTypeStr[20]; int id, pathType; - int mlo; + int minID, maxID; section = NONE; + minID = INT32_MAX; + maxID = -1; pathIndex = -1; - mlo = 0; debug("Loading object types from %s...\n", filename); fd = CFileMgr::OpenFile(filename, "rb"); + assert(fd > 0); for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ if(*line == '\0' || *line == '#') continue; @@ -996,25 +625,27 @@ CFileLoader::LoadObjectTypes(const char *filename) if(section == NONE){ if(isLine4(line, 'o','b','j','s')) section = OBJS; else if(isLine4(line, 't','o','b','j')) section = TOBJ; + else if(isLine4(line, 'w','e','a','p')) section = WEAP; else if(isLine4(line, 'h','i','e','r')) section = HIER; else if(isLine4(line, 'c','a','r','s')) section = CARS; else if(isLine4(line, 'p','e','d','s')) section = PEDS; else if(isLine4(line, 'p','a','t','h')) section = PATH; else if(isLine4(line, '2','d','f','x')) section = TWODFX; }else if(isLine3(line, 'e','n','d')){ - section = section == MLO ? OBJS : NONE; + section = NONE; }else switch(section){ case OBJS: - if(isLine3(line, 's','t','a')) - mlo = LoadMLO(line); - else - LoadObject(line); - break; - case MLO: - LoadMLOInstance(mlo, line); + id = LoadObject(line); + if(id > maxID) maxID = id; + if(id < minID) minID = id; break; case TOBJ: - LoadTimeObject(line); + id = LoadTimeObject(line); + if(id > maxID) maxID = id; + if(id < minID) minID = id; + break; + case WEAP: + LoadWeaponObject(line); break; case HIER: LoadClumpObject(line); @@ -1027,17 +658,15 @@ CFileLoader::LoadObjectTypes(const char *filename) break; case PATH: if(pathIndex == -1){ - id = LoadPathHeader(line, pathTypeStr); - if(strcmp(pathTypeStr, "ped") == 0) - pathType = 1; - else if(strcmp(pathTypeStr, "car") == 0) - pathType = 0; + id = LoadPathHeader(line, pathType); pathIndex = 0; }else{ - if(pathType == 1) + if(pathType == 0) LoadPedPathNode(line, id, pathIndex); - else if(pathType == 0) - LoadCarPathNode(line, id, pathIndex); + else if (pathType == 1) + LoadCarPathNode(line, id, pathIndex, false); + else if (pathType == 2) + LoadCarPathNode(line, id, pathIndex, true); pathIndex++; if(pathIndex == 12) pathIndex = -1; @@ -1050,41 +679,30 @@ CFileLoader::LoadObjectTypes(const char *filename) } CFileMgr::CloseFile(fd); - for(id = 0; id < MODELINFOSIZE; id++){ + for(id = minID; id <= maxID; id++){ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); - if(mi && mi->IsSimple()) - mi->SetupBigBuilding(); + if(mi && mi->IsBuilding()) + mi->SetupBigBuilding(minID, maxID); } } void SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags) { - mi->m_normalCull = !!(flags & 1); + mi->m_wetRoadReflection = !!(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); -#ifdef EXTRA_MODEL_FLAGS - // same flag values as SA - mi->m_bIsTree = !!(flags & 0x2000); - mi->m_bIsDoubleSided = !!(flags & 0x200000); - // new value otherwise unused - mi->m_bCanBeIgnored = !!(flags & 0x10000); - -#ifdef HARDCODED_MODEL_FLAGS - // mobile sets these flags in CFileLoader::SetRelatedModelInfoCB, but that's stupid - if(MatchModelName(mi->GetModelName(), DoubleSidedNames)) mi->m_bIsDoubleSided = true; - if(MatchModelName(mi->GetModelName(), TreeNames)) mi->m_bIsTree = true; - if(MatchModelName(mi->GetModelName(), OptimizedNames)) mi->m_bCanBeIgnored = true; -#endif - -#endif + mi->m_noShadows = !!(flags & 0x80); + mi->m_ignoreDrawDist = !!(flags & 0x100); + mi->m_isCodeGlass = !!(flags & 0x200); + mi->m_isArtistGlass = !!(flags & 0x400); } -void +int CFileLoader::LoadObject(const char *line) { int id, numObjs; @@ -1095,7 +713,7 @@ CFileLoader::LoadObject(const char *line) CSimpleModelInfo *mi; if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) - return; + return 0; // game returns return value switch(numObjs){ case 1: @@ -1127,60 +745,11 @@ CFileLoader::LoadObject(const char *line) mi->m_firstDamaged = damaged; mi->SetTexDictionary(txd); MatchModelString(model, id); -} - -int -CFileLoader::LoadMLO(const char *line) -{ - char smth[8]; - char name[24]; - int modelIndex; - float drawDist; - - sscanf(line, "%s %s %d %f", smth, name, &modelIndex, &drawDist); - CMloModelInfo *minfo = CModelInfo::AddMloModel(modelIndex); - minfo->SetModelName(name); - minfo->drawDist = drawDist; - int instId = CModelInfo::GetMloInstanceStore().allocPtr; - minfo->firstInstance = instId; - minfo->lastInstance = instId; - minfo->SetTexDictionary("generic"); - return modelIndex; -} - -void -CFileLoader::LoadMLOInstance(int id, const char *line) -{ - char name[24]; - RwV3d pos, scale, rot; - float angle; - int modelIndex; - - CMloModelInfo *minfo = (CMloModelInfo*)CModelInfo::GetModelInfo(id); - sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f", - &modelIndex, - name, - &pos.x, &pos.y, &pos.z, - &scale.x, &scale.y, &scale.z, - &rot.x, &rot.y, &rot.z, - &angle); - float rad = Acos(angle) * 2.0f; - CInstance *inst = CModelInfo::GetMloInstanceStore().Alloc(); - minfo->lastInstance++; - - RwMatrix *matrix = RwMatrixCreate(); - RwMatrixScale(matrix, &scale, rwCOMBINEREPLACE); - RwMatrixRotate(matrix, &rot, -RADTODEG(rad), rwCOMBINEPOSTCONCAT); - RwMatrixTranslate(matrix, &pos, rwCOMBINEPOSTCONCAT); - inst->GetMatrix() = CMatrix(matrix); - inst->GetMatrix().UpdateRW(); - - inst->m_modelIndex = modelIndex; - RwMatrixDestroy(matrix); + return id; } -void +int CFileLoader::LoadTimeObject(const char *line) { int id, numObjs; @@ -1192,7 +761,7 @@ CFileLoader::LoadTimeObject(const char *line) CTimeModelInfo *mi, *other; if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) - return; + return 0; // game returns return value switch(numObjs){ case 1: @@ -1228,6 +797,29 @@ CFileLoader::LoadTimeObject(const char *line) if(other) other->SetOtherTimeModel(id); MatchModelString(model, id); + + return id; +} + +int +CFileLoader::LoadWeaponObject(const char *line) +{ + int id, numObjs; + char model[24], txd[24], animFile[16]; + float dist; + CWeaponModelInfo *mi; + + sscanf(line, "%d %s %s %s %d %f", &id, model, txd, animFile, &numObjs, &dist); + + mi = CModelInfo::AddWeaponModel(id); + mi->SetModelName(model); + mi->SetNumAtomics(1); + mi->m_lodDistances[0] = dist; + mi->SetTexDictionary(txd); + mi->SetAnimFile(animFile); + mi->SetColModel(&CTempColModels::ms_colModelWeapon); + MatchModelString(model, id); + return id; } void @@ -1250,21 +842,22 @@ CFileLoader::LoadVehicleObject(const char *line) { int id; char model[24], txd[24]; - char type[8], handlingId[16], gamename[32], vehclass[12]; + char type[8], handlingId[16], gamename[32], animFile[16], 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", + sscanf(line, "%d %s %s %s %s %s %s %s %d %d %x %d %f", &id, model, txd, - type, handlingId, gamename, vehclass, + type, handlingId, gamename, animFile, vehclass, &frequency, &level, &comprules, &misc, &wheelScale); mi = CModelInfo::AddVehicleModel(id); mi->SetModelName(model); mi->SetTexDictionary(txd); + mi->SetAnimFile(animFile); for(p = gamename; *p; p++) if(*p == '_') *p = ' '; strcpy(mi->m_gameName, gamename); @@ -1294,36 +887,34 @@ CFileLoader::LoadVehicleObject(const char *line) mi->m_handlingId = mod_HandlingManager.GetHandlingId(handlingId); - // Well this is kinda dumb.... - if(strcmp(vehclass, "poorfamily") == 0){ + if(strcmp(vehclass, "normal") == 0) + mi->m_vehicleClass = CCarCtrl::NORMAL; + else if(strcmp(vehclass, "poorfamily") == 0) mi->m_vehicleClass = CCarCtrl::POOR; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::POOR); - }else if(strcmp(vehclass, "richfamily") == 0){ + else if(strcmp(vehclass, "richfamily") == 0) mi->m_vehicleClass = CCarCtrl::RICH; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::RICH); - }else if(strcmp(vehclass, "executive") == 0){ + else if(strcmp(vehclass, "executive") == 0) mi->m_vehicleClass = CCarCtrl::EXEC; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::EXEC); - }else if(strcmp(vehclass, "worker") == 0){ + else if(strcmp(vehclass, "worker") == 0) mi->m_vehicleClass = CCarCtrl::WORKER; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::WORKER); - }else if(strcmp(vehclass, "special") == 0){ - mi->m_vehicleClass = CCarCtrl::SPECIAL; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::SPECIAL); - }else if(strcmp(vehclass, "big") == 0){ + else if(strcmp(vehclass, "big") == 0) mi->m_vehicleClass = CCarCtrl::BIG; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::BIG); - }else if(strcmp(vehclass, "taxi") == 0){ + else if(strcmp(vehclass, "taxi") == 0) mi->m_vehicleClass = CCarCtrl::TAXI; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, CCarCtrl::TAXI); + else if(strcmp(vehclass, "moped") == 0) + mi->m_vehicleClass = CCarCtrl::MOPED; + else if(strcmp(vehclass, "motorbike") == 0) + mi->m_vehicleClass = CCarCtrl::MOTORBIKE; + else if(strcmp(vehclass, "leisureboat") == 0) + mi->m_vehicleClass = CCarCtrl::LEISUREBOAT; + else if(strcmp(vehclass, "workerboat") == 0) + mi->m_vehicleClass = CCarCtrl::WORKERBOAT; + else if(strcmp(vehclass, "ignore") == 0) { + mi->m_vehicleClass = -1; + return; } + CCarCtrl::AddToCarArray(id, mi->m_vehicleClass); + mi->m_frequency = frequency; } void @@ -1331,67 +922,87 @@ CFileLoader::LoadPedObject(const char *line) { int id; char model[24], txd[24]; - char pedType[24], pedStats[24], animGroup[24]; + char pedType[24], pedStats[24], animGroup[24], animFile[16]; int carsCanDrive; CPedModelInfo *mi; int animGroupId; + int radio1, radio2; - if(sscanf(line, "%d %s %s %s %s %s %x", + sscanf(line, "%d %s %s %s %s %s %x %s %d %d", &id, model, txd, - pedType, pedStats, animGroup, &carsCanDrive) != 7) - return; + pedType, pedStats, animGroup, &carsCanDrive, + animFile, &radio1, &radio2); mi = CModelInfo::AddPedModel(id); mi->SetModelName(model); mi->SetTexDictionary(txd); + mi->SetAnimFile(animFile); 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; + assert(animGroupId < NUM_ANIM_ASSOC_GROUPS); mi->m_animGroup = animGroupId; mi->m_carsCanDrive = carsCanDrive; - - // ??? - CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1); + mi->radio1 = radio1; + mi->radio2 = radio2; } int -CFileLoader::LoadPathHeader(const char *line, char *type) +CFileLoader::LoadPathHeader(const char *line, int &type) { int id; char modelname[32]; - sscanf(line, "%s %d %s", type, &id, modelname); + sscanf(line, "%d %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); + int type, next, cross, numLeft, numRight, speed, flags; + float x, y, z, width, spawnRate; + + if(sscanf(line, "%d %d %d %f %f %f %f %d %d %d %d %f", + &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight, + &speed, &flags, &spawnRate) != 12) + spawnRate = 1.0f; + + if(id == -1) + ThePaths.StoreDetachedNodeInfoPed(node, type, next, x, y, z, + width, !!cross, !!(flags&1), !!(flags&4), spawnRate*15.0f); + else + ThePaths.StoreNodeInfoPed(id, node, type, next, x, y, z, + width, !!cross, spawnRate*15.0f); } void -CFileLoader::LoadCarPathNode(const char *line, int id, int node) +CFileLoader::LoadCarPathNode(const char *line, int id, int node, bool waterPath) { - 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); + int type, next, cross, numLeft, numRight, speed, flags; + float x, y, z, width, spawnRate; + + if(sscanf(line, "%d %d %d %f %f %f %f %d %d %d %d %f", + &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight, + &speed, &flags, &spawnRate) != 12) + spawnRate = 1.0f; + + if(id == -1) + ThePaths.StoreDetachedNodeInfoCar(node, type, next, x, y, z, width, numLeft, numRight, + !!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate * 15, false); + else + ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight, + !!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate * 15); } void CFileLoader::Load2dEffect(const char *line) { - int id, r, g, b, a, type; + int id, r, g, b, a, type, ptype; float x, y, z; char corona[32], shadow[32]; int shadowIntens, lightType, roadReflection, flare, flags, probability; @@ -1468,6 +1079,18 @@ CFileLoader::Load2dEffect(const char *line) effect->attractor.probability = probability; #endif break; + case EFFECT_PED_ATTRACTOR: + sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f %f %f", + &id, &x, &y, &z, &r, &g, &b, &a, &type, + &ptype, + &effect->pedattr.queueDir.x, + &effect->pedattr.queueDir.y, + &effect->pedattr.queueDir.z, + &effect->pedattr.useDir.x, + &effect->pedattr.useDir.y, + &effect->pedattr.useDir.z); + effect->pedattr.type = ptype; + break; } CTxdStore::PopCurrentTxd(); @@ -1481,20 +1104,21 @@ CFileLoader::LoadScene(const char *filename) INST, ZONE, CULL, + OCCL, PICK, PATH, }; char *line; int fd; int section; - int pathIndex; - char pathTypeStr[20]; + int pathType, pathIndex; section = NONE; pathIndex = -1; debug("Creating objects from %s...\n", filename); fd = CFileMgr::OpenFile(filename, "rb"); + assert(fd > 0); for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ if(*line == '\0' || *line == '#') continue; @@ -1505,6 +1129,7 @@ CFileLoader::LoadScene(const char *filename) else if(isLine4(line, 'c','u','l','l')) section = CULL; else if(isLine4(line, 'p','i','c','k')) section = PICK; else if(isLine4(line, 'p','a','t','h')) section = PATH; + else if(isLine4(line, 'o','c','c','l')) section = OCCL; }else if(isLine3(line, 'e','n','d')){ section = NONE; }else switch(section){ @@ -1517,19 +1142,24 @@ CFileLoader::LoadScene(const char *filename) case CULL: LoadCullZone(line); break; + case OCCL: + LoadOcclusionVolume(line); + break; case PICK: // unused LoadPickup(line); break; case PATH: - // unfinished in the game if(pathIndex == -1){ - LoadPathHeader(line, pathTypeStr); - strcmp(pathTypeStr, "ped"); - // type not set + LoadPathHeader(line, pathType); pathIndex = 0; }else{ - // nodes not loaded + if(pathType == 0) + LoadPedPathNode(line, -1, pathIndex); + else if (pathType == 1) + LoadCarPathNode(line, -1, pathIndex, false); + else if (pathType == 2) + LoadCarPathNode(line, -1, pathIndex, true); pathIndex++; if(pathIndex == 12) pathIndex = -1; @@ -1552,19 +1182,31 @@ CFileLoader::LoadObjectInstance(const char *line) CSimpleModelInfo *mi; RwMatrix *xform; CEntity *entity; - if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f", - &id, name, + float area; + + if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f %f", + &id, name, &area, &trans.x, &trans.y, &trans.z, &scale.x, &scale.y, &scale.z, - &axis.x, &axis.y, &axis.z, &angle) != 12) - return; + &axis.x, &axis.y, &axis.z, &angle) != 13){ + 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; + area = 0; + } mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); if(mi == nil) return; assert(mi->IsSimple()); - angle = -RADTODEG(2.0f * acosf(angle)); + if(!CStreaming::IsObjectInCdImage(id)) + debug("Not in cdimage %s\n", mi->GetModelName()); + + angle = -RADTODEG(2.0f * Acos(angle)); xform = RwMatrixCreate(); RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE); RwMatrixTranslate(xform, &trans, rwCOMBINEPOSTCONCAT); @@ -1578,7 +1220,8 @@ CFileLoader::LoadObjectInstance(const char *line) entity->SetModelIndexNoCreate(id); entity->GetMatrix() = CMatrix(xform); entity->m_level = CTheZones::GetLevelFromPosition(&entity->GetPosition()); - if(mi->IsSimple()){ + entity->m_area = area; + if(mi->IsBuilding()){ if(mi->m_isBigBuilding) entity->SetupBigBuilding(); if(mi->m_isSubway) @@ -1587,14 +1230,25 @@ CFileLoader::LoadObjectInstance(const char *line) if(mi->GetLargestLodDistance() < 2.0f) entity->bIsVisible = false; CWorld::Add(entity); + + CColModel *col = entity->GetColModel(); + if(col->numSpheres || col->numBoxes || col->numTriangles){ + if(col->level != 0) + CColStore::GetBoundingBox(col->level).ContainRect(entity->GetBoundRect()); + }else + entity->bUsesCollision = false; + + if(entity->GetPosition().z + col->boundingBox.min.z < 6.0f) + entity->bUnderwater = true; }else{ entity = new CDummyObject; entity->SetModelIndexNoCreate(id); entity->GetMatrix() = CMatrix(xform); CWorld::Add(entity); - if(IsGlass(entity->GetModelIndex())) + if(IsGlass(entity->GetModelIndex()) && !mi->m_isArtistGlass) entity->bIsVisible = false; entity->m_level = CTheZones::GetLevelFromPosition(&entity->GetPosition()); + entity->m_area = area; } RwMatrixDestroy(xform); @@ -1640,53 +1294,21 @@ CFileLoader::LoadPickup(const char *line) } void -CFileLoader::LoadMapZones(const char *filename) +CFileLoader::LoadOcclusionVolume(const char *line) { - 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(isLine4(line, 'z','o','n','e')) section = ZONE; - }else if(isLine3(line, 'e','n','d')){ - 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); + float x, y, z; + float width, length, height; + float angle; - debug("Finished loading IPL\n"); + sscanf(line, "%f %f %f %f %f %f %f", + &x, &y, &z, + &width, &length, &height, + &angle); + COcclusion::AddOne(x, y, z + height/2.0f, width, length, height, angle); } + +// unused void CFileLoader::ReloadPaths(const char *filename) { @@ -1697,10 +1319,10 @@ CFileLoader::ReloadPaths(const char *filename) char *line; int section = NONE; int id, pathType, pathIndex = -1; - char pathTypeStr[20]; debug("Reloading paths from %s...\n", filename); int fd = CFileMgr::OpenFile(filename, "r"); + assert(fd > 0); for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) { if (*line == '\0' || *line == '#') continue; @@ -1716,17 +1338,15 @@ CFileLoader::ReloadPaths(const char *filename) switch (section) { case PATH: if (pathIndex == -1) { - id = LoadPathHeader(line, pathTypeStr); - if (strcmp(pathTypeStr, "ped") == 0) - pathType = 1; - else if (strcmp(pathTypeStr, "car") == 0) - pathType = 0; + id = LoadPathHeader(line, pathType); pathIndex = 0; } else { - if (pathType == 1) + if(pathType == 0) LoadPedPathNode(line, id, pathIndex); - else if (pathType == 0) - LoadCarPathNode(line, id, pathIndex); + else if (pathType == 1) + LoadCarPathNode(line, id, pathIndex, false); + else if (pathType == 2) + LoadCarPathNode(line, id, pathIndex, true); pathIndex++; if (pathIndex == 12) pathIndex = -1; @@ -1756,6 +1376,7 @@ CFileLoader::ReloadObjectTypes(const char *filename) CFileMgr::ChangeDir("\\DATA\\MAPS\\"); int fd = CFileMgr::OpenFile(filename, "r"); + assert(fd > 0); CFileMgr::ChangeDir("\\"); for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) { if (*line == '\0' || *line == '#') @@ -1831,17 +1452,14 @@ CFileLoader::ReLoadScene(const char *filename) char *line; CFileMgr::ChangeDir("\\DATA\\"); int fd = CFileMgr::OpenFile(filename, "r"); + assert(fd > 0); CFileMgr::ChangeDir("\\"); for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) { if (*line == '#') continue; -#ifdef FIX_BUGS if (strncmp(line, "EXIT", 4) == 0) -#else - if (strncmp(line, "EXIT", 9) == 0) -#endif break; if (strncmp(line, "IDE", 3) == 0) { |