From ca268ecb2cb548e3826da0908e7acaecdaeedc6f Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 3 Jun 2023 08:14:19 +0300 Subject: [PATCH 1/3] Fix global scripts on non-Windows platforms --- src/dfile.cc | 31 ++++++++++++++++++++++++++++--- src/sfall_global_scripts.cc | 16 ++++++++++------ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/dfile.cc b/src/dfile.cc index 52be55e9..39d857e0 100644 --- a/src/dfile.cc +++ b/src/dfile.cc @@ -43,6 +43,8 @@ static int dfileReadCharInternal(DFile* stream); static bool dfileReadCompressed(DFile* stream, void* ptr, size_t size); static void dfileUngetCompressed(DFile* stream, int ch); +static void dfile_normalize_path(char* path); + // Reads .DAT file contents. // // 0x4E4F58 @@ -122,6 +124,9 @@ DBase* dbaseOpen(const char* filePath) entry->path[pathLength] = '\0'; + // CE: Normalize entry path. + dfile_normalize_path(entry->path); + if (fread(&(entry->compressed), sizeof(entry->compressed), 1, stream) != 1) { break; } @@ -201,11 +206,18 @@ bool dbaseClose(DBase* dbase) // 0x4E5308 bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern) { + // CE: Normalize pattern to match entries. Underlying `fpattern` + // implementation is case-sensitive on non-Windows platforms, so both + // pattern and entries should match in case and have native path separators. + char normalizedPattern[COMPAT_MAX_PATH]; + strcpy(normalizedPattern, pattern); + dfile_normalize_path(normalizedPattern); + for (int index = 0; index < dbase->entriesLength; index++) { DBaseEntry* entry = &(dbase->entries[index]); - if (fpattern_match(pattern, entry->path)) { + if (fpattern_match(normalizedPattern, entry->path)) { strcpy(findFileData->fileName, entry->path); - strcpy(findFileData->pattern, pattern); + strcpy(findFileData->pattern, normalizedPattern); findFileData->index = index; return true; } @@ -632,7 +644,14 @@ static int dbaseFindEntryByFilePath(const void* a1, const void* a2) // 0x4E5D9C static DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, DFile* dfile) { - DBaseEntry* entry = (DBaseEntry*)bsearch(filePath, dbase->entries, dbase->entriesLength, sizeof(*dbase->entries), dbaseFindEntryByFilePath); + // CE: Normalize path to match entries. Even though + // `dbaseFindEntryByFilePath` uses case-insensitive compare, it still needs + // native path separators. + char normalizedFilePath[COMPAT_MAX_PATH]; + strcpy(normalizedFilePath, filePath); + dfile_normalize_path(normalizedFilePath); + + DBaseEntry* entry = (DBaseEntry*)bsearch(normalizedFilePath, dbase->entries, dbase->entriesLength, sizeof(*dbase->entries), dbaseFindEntryByFilePath); if (entry == NULL) { goto err; } @@ -854,4 +873,10 @@ static void dfileUngetCompressed(DFile* stream, int ch) stream->position--; } +static void dfile_normalize_path(char* path) +{ + compat_windows_path_to_native(path); + compat_strlwr(path); +} + } // namespace fallout diff --git a/src/sfall_global_scripts.cc b/src/sfall_global_scripts.cc index 067d4fb8..c6ff320a 100644 --- a/src/sfall_global_scripts.cc +++ b/src/sfall_global_scripts.cc @@ -46,17 +46,21 @@ bool sfall_gl_scr_init() *end = '\0'; } - char drive[COMPAT_MAX_DRIVE]; - char dir[COMPAT_MAX_DIR]; - compat_splitpath(curr, drive, dir, nullptr, nullptr); + char path[COMPAT_MAX_PATH]; + strcpy(path, curr); + + char *fname = strrchr(path, '\\'); + if (fname != nullptr) { + fname += 1; + } else { + fname = path; + } char** files; int filesLength = fileNameListInit(curr, &files, 0, 0); if (filesLength != 0) { for (int index = 0; index < filesLength; index++) { - char path[COMPAT_MAX_PATH]; - compat_makepath(path, drive, dir, files[index], nullptr); - + strcpy(fname, files[index]); state->paths.push_back(std::string { path }); } From 80b58bd1746fb2642d228e98a75b6a4f2a05cecb Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 3 Jun 2023 08:18:12 +0300 Subject: [PATCH 2/3] clang-format --- src/sfall_global_scripts.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfall_global_scripts.cc b/src/sfall_global_scripts.cc index c6ff320a..37d7d758 100644 --- a/src/sfall_global_scripts.cc +++ b/src/sfall_global_scripts.cc @@ -49,7 +49,7 @@ bool sfall_gl_scr_init() char path[COMPAT_MAX_PATH]; strcpy(path, curr); - char *fname = strrchr(path, '\\'); + char* fname = strrchr(path, '\\'); if (fname != nullptr) { fname += 1; } else { From 8d4057366eafa09de1322827394018a648c58166 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Mon, 12 Jun 2023 08:13:31 +0300 Subject: [PATCH 3/3] Handle objects in opGetRotationToTile Fixes #302 --- src/interpreter_extra.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index b2d32951..0da70a2c 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -4663,8 +4663,31 @@ static void opGetPartyMember(Program* program) // 0x45C6DC static void opGetRotationToTile(Program* program) { - int tile2 = programStackPopInteger(program); - int tile1 = programStackPopInteger(program); + // CE: There is a bug in Olympus (tgrdqest) - object is passed as one of the + // arguments instead of tile. Original game (x86) does not distinguish + // between integers and pointers, so one of the tiles is silently ignored + // while calculating rotation. As a workaround this opcode now accepts + // both integers and objects. + ProgramValue value2 = programStackPopValue(program); + ProgramValue value1 = programStackPopValue(program); + + int tile2; + if (value2.isInt()) { + tile2 = value2.integerValue; + } else if (value2.isPointer()) { + tile2 = static_cast(value2.pointerValue)->tile; + } else { + programFatalError("script error: %s: invalid arg 2 to rotation_to_tile", program->name); + } + + int tile1; + if (value1.isInt()) { + tile1 = value1.integerValue; + } else if (value1.isPointer()) { + tile1 = static_cast(value1.pointerValue)->tile; + } else { + programFatalError("script error: %s: invalid arg 1 to rotation_to_tile", program->name); + } int rotation = tileGetRotationTo(tile1, tile2); programStackPushInteger(program, rotation);