Compare commits

...

3 Commits

Author SHA1 Message Date
Alexander Batalov 8d4057366e Handle objects in opGetRotationToTile
Fixes #302
2023-06-12 08:13:31 +03:00
Alexander Batalov 80b58bd174 clang-format 2023-06-03 08:18:12 +03:00
Alexander Batalov ca268ecb2c Fix global scripts on non-Windows platforms 2023-06-03 08:14:19 +03:00
3 changed files with 63 additions and 11 deletions

View File

@ -43,6 +43,8 @@ static int dfileReadCharInternal(DFile* stream);
static bool dfileReadCompressed(DFile* stream, void* ptr, size_t size); static bool dfileReadCompressed(DFile* stream, void* ptr, size_t size);
static void dfileUngetCompressed(DFile* stream, int ch); static void dfileUngetCompressed(DFile* stream, int ch);
static void dfile_normalize_path(char* path);
// Reads .DAT file contents. // Reads .DAT file contents.
// //
// 0x4E4F58 // 0x4E4F58
@ -122,6 +124,9 @@ DBase* dbaseOpen(const char* filePath)
entry->path[pathLength] = '\0'; entry->path[pathLength] = '\0';
// CE: Normalize entry path.
dfile_normalize_path(entry->path);
if (fread(&(entry->compressed), sizeof(entry->compressed), 1, stream) != 1) { if (fread(&(entry->compressed), sizeof(entry->compressed), 1, stream) != 1) {
break; break;
} }
@ -201,11 +206,18 @@ bool dbaseClose(DBase* dbase)
// 0x4E5308 // 0x4E5308
bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern) 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++) { for (int index = 0; index < dbase->entriesLength; index++) {
DBaseEntry* entry = &(dbase->entries[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->fileName, entry->path);
strcpy(findFileData->pattern, pattern); strcpy(findFileData->pattern, normalizedPattern);
findFileData->index = index; findFileData->index = index;
return true; return true;
} }
@ -632,7 +644,14 @@ static int dbaseFindEntryByFilePath(const void* a1, const void* a2)
// 0x4E5D9C // 0x4E5D9C
static DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, DFile* dfile) 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) { if (entry == NULL) {
goto err; goto err;
} }
@ -854,4 +873,10 @@ static void dfileUngetCompressed(DFile* stream, int ch)
stream->position--; stream->position--;
} }
static void dfile_normalize_path(char* path)
{
compat_windows_path_to_native(path);
compat_strlwr(path);
}
} // namespace fallout } // namespace fallout

View File

@ -4663,8 +4663,31 @@ static void opGetPartyMember(Program* program)
// 0x45C6DC // 0x45C6DC
static void opGetRotationToTile(Program* program) static void opGetRotationToTile(Program* program)
{ {
int tile2 = programStackPopInteger(program); // CE: There is a bug in Olympus (tgrdqest) - object is passed as one of the
int tile1 = programStackPopInteger(program); // 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<Object*>(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<Object*>(value1.pointerValue)->tile;
} else {
programFatalError("script error: %s: invalid arg 1 to rotation_to_tile", program->name);
}
int rotation = tileGetRotationTo(tile1, tile2); int rotation = tileGetRotationTo(tile1, tile2);
programStackPushInteger(program, rotation); programStackPushInteger(program, rotation);

View File

@ -46,17 +46,21 @@ bool sfall_gl_scr_init()
*end = '\0'; *end = '\0';
} }
char drive[COMPAT_MAX_DRIVE]; char path[COMPAT_MAX_PATH];
char dir[COMPAT_MAX_DIR]; strcpy(path, curr);
compat_splitpath(curr, drive, dir, nullptr, nullptr);
char* fname = strrchr(path, '\\');
if (fname != nullptr) {
fname += 1;
} else {
fname = path;
}
char** files; char** files;
int filesLength = fileNameListInit(curr, &files, 0, 0); int filesLength = fileNameListInit(curr, &files, 0, 0);
if (filesLength != 0) { if (filesLength != 0) {
for (int index = 0; index < filesLength; index++) { for (int index = 0; index < filesLength; index++) {
char path[COMPAT_MAX_PATH]; strcpy(fname, files[index]);
compat_makepath(path, drive, dir, files[index], nullptr);
state->paths.push_back(std::string { path }); state->paths.push_back(std::string { path });
} }