From b60fe43b0623ec1d8697e3f5ab07c66e4e65081b Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Tue, 25 Oct 2022 08:04:42 +0200 Subject: [PATCH 01/31] Refactor: use enum instead of magic numbers (#176) --- src/actions.cc | 2 +- src/animation.cc | 6 +++--- src/character_editor.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/actions.cc b/src/actions.cc index 8f202bf..1c4daab 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -1396,7 +1396,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; case SKILL_SNEAK: - dudeToggleState(0); + dudeToggleState(DUDE_STATE_SNEAKING); return 0; default: debugPrint("\nskill_use: invalid skill used."); diff --git a/src/animation.cc b/src/animation.cc index 36b27d2..7abcebb 100644 --- a/src/animation.cc +++ b/src/animation.cc @@ -690,7 +690,7 @@ int animationRegisterRunToObject(Object* owner, Object* destination, int actionP animationDescription->destination = destination; if ((FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) != 0) - || (owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING)) + || (owner == gDude && dudeHasState(DUDE_STATE_SNEAKING) && !perkGetRank(gDude, PERK_SILENT_RUNNING)) || !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) { animationDescription->anim = ANIM_WALK; } else { @@ -786,7 +786,7 @@ int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actio animationDescription->elevation = elevation; if ((FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) != 0) - || (owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING)) + || (owner == gDude && dudeHasState(DUDE_STATE_SNEAKING) && !perkGetRank(gDude, PERK_SILENT_RUNNING)) || !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) { animationDescription->anim = ANIM_WALK; } else { @@ -3043,7 +3043,7 @@ int _dude_run(int a1) } if (!perkGetRank(gDude, PERK_SILENT_RUNNING)) { - dudeDisableState(0); + dudeDisableState(DUDE_STATE_SNEAKING); } reg_anim_begin(ANIMATION_REQUEST_RESERVED); diff --git a/src/character_editor.cc b/src/character_editor.cc index eaac82f..f557852 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -1186,8 +1186,8 @@ int characterEditorShow(bool isCreationMode) characterEditorRestorePlayer(); } - if (dudeHasState(0x03)) { - dudeDisableState(0x03); + if (dudeHasState(DUDE_STATE_LEVEL_UP_AVAILABLE)) { + dudeDisableState(DUDE_STATE_LEVEL_UP_AVAILABLE); } interfaceRenderHitPoints(false); From 7627092478e9f3b382435bbc7878433deb5aa1a2 Mon Sep 17 00:00:00 2001 From: Martin Janiczek Date: Tue, 25 Oct 2022 08:05:09 +0200 Subject: [PATCH 02/31] Make sfall key naming consistent (#172) --- src/sfall_config.h | 2 +- src/worldmap.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfall_config.h b/src/sfall_config.h index 7b4f83e..b2c8859 100644 --- a/src/sfall_config.h +++ b/src/sfall_config.h @@ -58,7 +58,7 @@ namespace fallout { #define SFALL_CONFIG_GAME_DIALOG_FIX_KEY "DialogueFix" #define SFALL_CONFIG_TWEAKS_FILE_KEY "TweaksFile" #define SFALL_CONFIG_GAME_DIALOG_GENDER_WORDS_KEY "DialogGenderWords" -#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX "TownMapHotkeysFix" +#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix" #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1 #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3 diff --git a/src/worldmap.cc b/src/worldmap.cc index 481ca00..2a46d59 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -847,7 +847,7 @@ int wmWorldMap_init() // SFALL gTownMapHotkeysFix = true; - configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX, &gTownMapHotkeysFix); + configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY, &gTownMapHotkeysFix); return 0; } From 5b151634a5136945609e2c5adb5ab951b37f636e Mon Sep 17 00:00:00 2001 From: sonilyan <286258386@qq.com> Date: Tue, 25 Oct 2022 14:12:54 +0800 Subject: [PATCH 03/31] Fix memory alignment (#187) --- src/heap.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/heap.cc b/src/heap.cc index 51236c2..e4a61f6 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -307,6 +307,8 @@ bool heapBlockAllocate(Heap* heap, int* handleIndexPtr, int size, int a4) int blockSize; HeapHandle* handle; + size += 4 - size % 4; + if (heap == NULL || handleIndexPtr == NULL || size == 0) { goto err; } From ad9b8586e9f701ea59c426420ebccadb88ecc8c9 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Tue, 25 Oct 2022 09:57:13 +0300 Subject: [PATCH 04/31] Fix testing pointers for nulls in Nevada Closes #178 --- src/interpreter.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/interpreter.cc b/src/interpreter.cc index c24b0e3..c196823 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -1127,6 +1127,16 @@ static void opConditionalOperatorLessThanEquals(Program* program) assert(false && "Should be unreachable"); } break; + // Nevada folks tend to use "object <= 0" to test objects for nulls. + case VALUE_TYPE_PTR: + switch (value[0].opcode) { + case VALUE_TYPE_INT: + result = (intptr_t)value[1].pointerValue <= (intptr_t)value[0].integerValue; + break; + default: + assert(false && "Should be unreachable"); + } + break; default: assert(false && "Should be unreachable"); } From c47113ca2991109f5623094d83b0f1acec323a18 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Tue, 25 Oct 2022 13:05:09 +0300 Subject: [PATCH 05/31] Force screen redraw after playing movies Fixes #180 --- src/game_movie.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/game_movie.cc b/src/game_movie.cc index a89bc45..7d9f899 100644 --- a/src/game_movie.cc +++ b/src/game_movie.cc @@ -284,6 +284,10 @@ int gameMoviePlay(int movie, int flags) windowDestroy(win); + // CE: Destroying a window redraws only content it was covering (centered + // 640x480). This leads to everything outside this rect to remain black. + windowRefreshAll(&_scr_size); + if ((flags & GAME_MOVIE_PAUSE_MUSIC) != 0) { backgroundSoundResume(); } From 40510539eea9676f87988577e8910fcaee9abbf7 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Tue, 25 Oct 2022 15:57:31 +0300 Subject: [PATCH 06/31] Fix interface font loading --- src/font_manager.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/font_manager.cc b/src/font_manager.cc index a9c5a1a..85d8f2d 100644 --- a/src/font_manager.cc +++ b/src/font_manager.cc @@ -159,12 +159,12 @@ static int interfaceFontLoad(int font_index) interfaceFontByteSwapInt32(&(glyph->offset)); } - fileSize -= sizeof(InterfaceFontDescriptor); + int glyphDataSize = fileSize - 2060; - fontDescriptor->data = (unsigned char*)internal_malloc_safe(fileSize, __FILE__, __LINE__); // FONTMGR.C, 259 + fontDescriptor->data = (unsigned char*)internal_malloc_safe(glyphDataSize, __FILE__, __LINE__); // FONTMGR.C, 259 if (fontDescriptor->data == NULL) goto err; - if (fileRead(fontDescriptor->data, fileSize, 1, stream) != 1) { + if (fileRead(fontDescriptor->data, glyphDataSize, 1, stream) != 1) { internal_free_safe(fontDescriptor->data, __FILE__, __LINE__); // FONTMGR.C, 268 goto err; } From 223930c4643ca43cc5ea31d80d14d439a23c54c1 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Tue, 25 Oct 2022 17:37:45 +0300 Subject: [PATCH 07/31] Get rid of goto --- src/font_manager.cc | 61 ++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/font_manager.cc b/src/font_manager.cc index 85d8f2d..85c163e 100644 --- a/src/font_manager.cc +++ b/src/font_manager.cc @@ -123,60 +123,85 @@ static int interfaceFontLoad(int font_index) File* stream = fileOpen(path, "rb"); if (stream == NULL) { - return false; + return -1; } int fileSize = fileGetSize(stream); int sig; - if (fileRead(&sig, 4, 1, stream) != 1) goto err; + if (fileRead(&sig, 4, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt32(&sig); - if (sig != 0x41414646) goto err; + if (sig != 0x41414646) { + fileClose(stream); + return -1; + } - if (fileRead(&(fontDescriptor->maxHeight), 2, 1, stream) != 1) goto err; + if (fileRead(&(fontDescriptor->maxHeight), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(fontDescriptor->maxHeight)); - if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) goto err; + if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(fontDescriptor->letterSpacing)); - if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) goto err; + if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(fontDescriptor->wordSpacing)); - if (fileRead(&(fontDescriptor->lineSpacing), 2, 1, stream) != 1) goto err; + if (fileRead(&(fontDescriptor->lineSpacing), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(fontDescriptor->lineSpacing)); for (int index = 0; index < 256; index++) { InterfaceFontGlyph* glyph = &(fontDescriptor->glyphs[index]); - if (fileRead(&(glyph->width), 2, 1, stream) != 1) goto err; + if (fileRead(&(glyph->width), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(glyph->width)); - if (fileRead(&(glyph->height), 2, 1, stream) != 1) goto err; + if (fileRead(&(glyph->height), 2, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt16(&(glyph->height)); - if (fileRead(&(glyph->offset), 4, 1, stream) != 1) goto err; + if (fileRead(&(glyph->offset), 4, 1, stream) != 1) { + fileClose(stream); + return -1; + } interfaceFontByteSwapInt32(&(glyph->offset)); } int glyphDataSize = fileSize - 2060; fontDescriptor->data = (unsigned char*)internal_malloc_safe(glyphDataSize, __FILE__, __LINE__); // FONTMGR.C, 259 - if (fontDescriptor->data == NULL) goto err; + if (fontDescriptor->data == NULL) { + fileClose(stream); + return -1; + } if (fileRead(fontDescriptor->data, glyphDataSize, 1, stream) != 1) { internal_free_safe(fontDescriptor->data, __FILE__, __LINE__); // FONTMGR.C, 268 - goto err; + fileClose(stream); + return -1; } fileClose(stream); - return 0; - -err: - fileClose(stream); - - return -1; } // 0x442120 From 1bbd586cbb8e37a71d658603cd4f0b861c90f25a Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Wed, 26 Oct 2022 10:17:39 +0300 Subject: [PATCH 08/31] Fix trimming line ending in .lst files --- src/proto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proto.cc b/src/proto.cc index 0ca04e0..40fe210 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -239,7 +239,7 @@ int _proto_list_str(int pid, char* proto_path) *pch = '\0'; } - pch = strchr(string, '\n'); + pch = strpbrk(string, "\r\n"); if (pch != NULL) { *pch = '\0'; } From 01f264e0c2e4445a2c3c3bf84a1d1c028708b32e Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Fri, 28 Oct 2022 10:35:22 +0300 Subject: [PATCH 09/31] Fix color setters --- src/interpreter_lib.cc | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/interpreter_lib.cc b/src/interpreter_lib.cc index 47a9152..ca61997 100644 --- a/src/interpreter_lib.cc +++ b/src/interpreter_lib.cc @@ -1465,8 +1465,9 @@ static void opSetTextColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) - || value[arg].floatValue == 0.0) { + if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT + && (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT + && value[arg].integerValue != 0) { programFatalError("Invalid type given to settextcolor"); } } @@ -1492,8 +1493,9 @@ static void opSayOptionColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) - || value[arg].floatValue == 0.0) { + if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT + && (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT + && value[arg].integerValue != 0) { programFatalError("Invalid type given to sayoptioncolor"); } } @@ -1519,8 +1521,9 @@ static void opSayReplyColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) - || value[arg].floatValue == 0.0) { + if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT + && (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT + && value[arg].integerValue != 0) { programFatalError("Invalid type given to sayreplycolor"); } } @@ -1546,8 +1549,9 @@ static void opSetHighlightColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) - || value[arg].floatValue == 0.0) { + if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT + && (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT + && value[arg].integerValue != 0) { programFatalError("Invalid type given to sayreplycolor"); } } From 9c6daa4abe18e290be1259e5914d9a28f5b594b9 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Fri, 28 Oct 2022 10:59:38 +0300 Subject: [PATCH 10/31] Fix selecting managed window --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index 5c1ce52..3357852 100644 --- a/src/window.cc +++ b/src/window.cc @@ -887,7 +887,7 @@ int _selectWindow(const char* windowName) } } - if (!_selectWindowID(index)) { + if (_selectWindowID(index)) { return index; } From 8ee0f478adf15efbc59574580684cae323b8b3c7 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Fri, 28 Oct 2022 11:02:53 +0300 Subject: [PATCH 11/31] Fix setting managed button procs --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index 3357852..f9beff1 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1725,7 +1725,7 @@ bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* no // 0x4BA11C bool _windowAddButtonProc(const char* buttonName, Program* program, int mouseEnterProc, int mouseExitProc, int mouseDownProc, int mouseUpProc) { - if (gCurrentManagedWindowIndex != -1) { + if (gCurrentManagedWindowIndex == -1) { return false; } From 8dd8d1c312aca775c322d8cc0eef7099b23e214c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 17:21:54 +0300 Subject: [PATCH 12/31] Replace random generator --- src/random.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/random.cc b/src/random.cc index 427679e..82f47b3 100644 --- a/src/random.cc +++ b/src/random.cc @@ -3,6 +3,8 @@ #include #include +#include + #include "debug.h" #include "platform_compat.h" #include "scripts.h" @@ -37,7 +39,7 @@ static int _idum; void randomInit() { unsigned int randomSeed = randomGetSeed(); - srand(randomSeed); + std::srand(randomSeed); int pseudorandomSeed = randomInt32(); randomSeedPrerandomInternal(pseudorandomSeed); @@ -183,10 +185,7 @@ void randomSeedPrerandom(int seed) // 0x4A31C4 static int randomInt32() { - int high = rand() << 16; - int low = rand(); - - return (high + low) & INT_MAX; + return std::rand(); } // 0x4A31E0 From 2b63360b95b3614f06108229c93129f098022630 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 17:26:46 +0300 Subject: [PATCH 13/31] Fix memory alignment --- src/memory.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/memory.cc b/src/memory.cc index 75e9ca9..5f15047 100644 --- a/src/memory.cc +++ b/src/memory.cc @@ -81,6 +81,7 @@ static void* memoryBlockMallocImpl(size_t size) if (size != 0) { size += sizeof(MemoryBlockHeader) + sizeof(MemoryBlockFooter); + size += sizeof(int) - size % sizeof(int); unsigned char* block = (unsigned char*)malloc(size); if (block != NULL) { @@ -123,6 +124,7 @@ static void* memoryBlockReallocImpl(void* ptr, size_t size) if (size != 0) { size += sizeof(MemoryBlockHeader) + sizeof(MemoryBlockFooter); + size += sizeof(int) - size % sizeof(int); } unsigned char* newBlock = (unsigned char*)realloc(block, size); From caa8b06d4f17a7aaca5e956ce9d83263c9d463d2 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 18:14:49 +0300 Subject: [PATCH 14/31] Fix UB when parsing encounter table --- src/worldmap.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/worldmap.cc b/src/worldmap.cc index 2a46d59..2821c4f 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -1397,7 +1397,17 @@ static int wmParseEncounterTableIndex(EncounterEntry* entry, char* string) if (strstr(string, "special")) { entry->flags |= ENCOUNTER_ENTRY_SPECIAL; - string += 8; + + // CE: Original code unconditionally consumes 8 characters, which is + // right when "special" is followed by conditions (separated with + // comma). However when "special" is the last keyword (which I guess + // is wrong, but present in worldmap.txt), consuming 8 characters + // sets pointer past NULL terminator, which can lead to many bad + // things (UB). + string += 7; + if (*string != '\0') { + string++; + } } if (string != NULL) { From 12367acb33263b811f173ce330e21c6f26e07900 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 18:17:57 +0300 Subject: [PATCH 15/31] Fix byte swapping warnings --- src/db.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db.cc b/src/db.cc index 3cf178b..f724772 100644 --- a/src/db.cc +++ b/src/db.cc @@ -338,7 +338,7 @@ int fileReadInt32(File* stream, int* valuePtr) return -1; } - *valuePtr = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000); + *valuePtr = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24); return 0; } @@ -511,7 +511,7 @@ int fileReadInt32List(File* stream, int* arr, int count) for (int index = 0; index < count; index++) { int value = arr[index]; - arr[index] = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000); + arr[index] = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24); } return 0; From 2f42818a332f33bca3733ba956ef0300dd03e011 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 18:23:53 +0300 Subject: [PATCH 16/31] Review square coords math --- src/tile.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tile.cc b/src/tile.cc index 624cf44..d265281 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -1149,9 +1149,7 @@ void squareTileScreenToCoord(int screenX, int screenY, int elevation, int* coord *coordX = v6 >= 0 ? (v6 / 192) : ((v6 + 1) / 192 - 1); v8 = 4 * v5 + v4; - *coordY = v8 >= 0 - ? ((v8 - ((v8 >> 31) << 7)) >> 7) - : ((((v8 + 1) - (((v8 + 1) >> 31) << 7)) >> 7) - 1); + *coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1); *coordX += _square_x; *coordY += _square_rect; @@ -1174,9 +1172,7 @@ void squareTileScreenToCoordRoof(int screenX, int screenY, int elevation, int* c *coordX = (v6 >= 0) ? (v6 / 192) : ((v6 + 1) / 192 - 1); v8 = 4 * v5 + v4; - *coordY = (v8 >= 0) - ? ((v8 - ((v8 >> 31) << 7)) >> 7) - : ((((v8 + 1) - (((v8 + 1) >> 31) << 7)) >> 7) - 1); + *coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1); *coordX += _square_x; *coordY += _square_rect; From 0851354c8afc76791075434a130b2c61c6a3c066 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 18:25:28 +0300 Subject: [PATCH 17/31] Rename _square_y --- src/tile.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tile.cc b/src/tile.cc index d265281..1ce2e77 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -207,7 +207,7 @@ static Rect gTileWindowRect; static unsigned char _tile_grid[32 * 16]; // 0x66BDE4 -static int _square_rect; +static int _square_y; // 0x66BDE8 static int _square_x; @@ -579,7 +579,7 @@ int tileSetCenter(int tile, int flags) } _square_x = _tile_x / 2; - _square_rect = _tile_y / 2; + _square_y = _tile_y / 2; _square_offx = _tile_offx - 16; _square_offy = _tile_offy - 2; @@ -1080,7 +1080,7 @@ int squareTileToScreenXY(int squareTile, int* coordX, int* coordY, int elevation *coordX += 48 * v8; *coordY -= 12 * v8; - v9 = v6 - _square_rect; + v9 = v6 - _square_y; *coordX += 32 * v9; *coordY += 24 * v9; @@ -1111,7 +1111,7 @@ int squareTileToRoofScreenXY(int squareTile, int* screenX, int* screenY, int ele *screenX += 48 * v8; *screenY -= 12 * v8; - v9 = v6 - _square_rect; + v9 = v6 - _square_y; *screenX += 32 * v9; v10 = 24 * v9 + *screenY; *screenY = v10; @@ -1152,7 +1152,7 @@ void squareTileScreenToCoord(int screenX, int screenY, int elevation, int* coord *coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1); *coordX += _square_x; - *coordY += _square_rect; + *coordY += _square_y; *coordX = gSquareGridWidth - 1 - *coordX; } @@ -1175,7 +1175,7 @@ void squareTileScreenToCoordRoof(int screenX, int screenY, int elevation, int* c *coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1); *coordX += _square_x; - *coordY += _square_rect; + *coordY += _square_y; *coordX = gSquareGridWidth - 1 - *coordX; } From 4821cab724b2125d1b11bf4d8cd6c0201c1fe935 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 18:52:22 +0300 Subject: [PATCH 18/31] Review tileSetCenter flags --- src/game.cc | 2 +- src/interpreter_extra.cc | 10 +++++----- src/map.cc | 6 +++--- src/object.cc | 6 +++--- src/tile.cc | 42 +++++++++++++++++++++------------------- src/tile.h | 4 ++-- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/game.cc b/src/game.cc index 5ea3043..3d8c859 100644 --- a/src/game.cc +++ b/src/game.cc @@ -693,7 +693,7 @@ int gameHandleKey(int eventCode, bool isInCombatMode) } if (gIsMapper) { - tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01); + tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW); } else { _tile_scroll_to(gDude->tile, 2); } diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index 9626648..312ca56 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -545,7 +545,7 @@ static void opSetMapStart(Program* program) } int tile = 200 * y + x; - if (tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02) != 0) { + if (tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) != 0) { scriptError("\nScript Error: %s: op_set_map_start: tile_set_center failed", program->name); return; } @@ -584,7 +584,7 @@ static void opOverrideMapStart(Program* program) } } - tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01); + tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW); tileWindowRefresh(); } @@ -866,7 +866,7 @@ static void opMoveTo(Program* program) Rect rect; newTile = objectSetLocation(object, tile, elevation, &rect); if (newTile != -1) { - tileSetCenter(object->tile, TILE_SET_CENTER_FLAG_0x01); + tileSetCenter(object->tile, TILE_SET_CENTER_REFRESH_WINDOW); } if (tileLimitingEnabled) { @@ -2061,7 +2061,7 @@ static void opMetarule3(Program* program) } break; case METARULE3_TILE_SET_CENTER: - result.integerValue = tileSetCenter(param1.integerValue, TILE_SET_CENTER_FLAG_0x01); + result.integerValue = tileSetCenter(param1.integerValue, TILE_SET_CENTER_REFRESH_WINDOW); break; case METARULE3_109: result.integerValue = aiGetChemUse(static_cast(param1.pointerValue)); @@ -3158,7 +3158,7 @@ static void opFloatMessage(Program* program) color = _colorTable[31744]; a5 = _colorTable[0]; font = 103; - tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01); + tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW); break; case FLOATING_MESSAGE_TYPE_NORMAL: case FLOATING_MESSAGE_TYPE_YELLOW: diff --git a/src/map.cc b/src/map.cc index 369e6fb..87990e1 100644 --- a/src/map.cc +++ b/src/map.cc @@ -707,7 +707,7 @@ int mapSetEnteringLocation(int elevation, int tile_num, int orientation) void mapNewMap() { mapSetElevation(0); - tileSetCenter(20100, TILE_SET_CENTER_FLAG_0x02); + tileSetCenter(20100, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS); memset(&gMapTransition, 0, sizeof(gMapTransition)); gMapHeader.enteringElevation = 0; gMapHeader.enteringRotation = 0; @@ -894,7 +894,7 @@ static int mapLoad(File* stream) } error = "Error setting tile center"; - if (tileSetCenter(gEnteringTile, TILE_SET_CENTER_FLAG_0x02) != 0) { + if (tileSetCenter(gEnteringTile, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) != 0) { goto err; } @@ -1240,7 +1240,7 @@ int mapHandleTransition() objectSetRotation(gDude, gMapTransition.rotation, NULL); } - if (tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01) == -1) { + if (tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW) == -1) { debugPrint("\nError: map: attempt to center out-of-bounds!"); } diff --git a/src/object.cc b/src/object.cc index 44e50f9..9cbf55a 100644 --- a/src/object.cc +++ b/src/object.cc @@ -1530,7 +1530,7 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) if (elevation != oldElevation) { mapSetElevation(elevation); - tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02); + tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS); if (isInCombat()) { _game_user_wants_to_quit = 1; } @@ -3335,7 +3335,7 @@ static int _obj_offset_table_init() } } - if (tileSetCenter(gCenterTile + 1, 2) == -1) { + if (tileSetCenter(gCenterTile + 1, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == -1) { goto err; } } @@ -3753,7 +3753,7 @@ int _obj_load_dude(File* stream) return -1; } - tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02); + tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS); return rc; } diff --git a/src/tile.cc b/src/tile.cc index 1ce2e77..2354bc5 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -433,7 +433,7 @@ int tileInit(TileData** a1, int squareGridWidth, int squareGridHeight, int hexGr gTileWindowWidth = ORIGINAL_ISO_WINDOW_WIDTH; gTileWindowHeight = ORIGINAL_ISO_WINDOW_HEIGHT; - tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2); + tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS); tileSetBorder(windowWidth, windowHeight, hexGridWidth, hexGridHeight); // Restore actual window size and set center one more time to calculate @@ -442,7 +442,7 @@ int tileInit(TileData** a1, int squareGridWidth, int squareGridHeight, int hexGr gTileWindowWidth = windowWidth; gTileWindowHeight = windowHeight; - tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2); + tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS); if (compat_stricmp(settings.system.executable.c_str(), "mapper") == 0) { gTileWindowRefreshElevationProc = tileRefreshMapper; @@ -533,29 +533,31 @@ int tileSetCenter(int tile, int flags) return -1; } - if ((gTileScrollLimitingEnabled & ((flags & TILE_SET_CENTER_FLAG_0x02) == 0)) != 0) { - int tileScreenX; - int tileScreenY; - tileToScreenXY(tile, &tileScreenX, &tileScreenY, gElevation); + if ((flags & TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == 0) { + if (gTileScrollLimitingEnabled) { + int tileScreenX; + int tileScreenY; + tileToScreenXY(tile, &tileScreenX, &tileScreenY, gElevation); - int dudeScreenX; - int dudeScreenY; - tileToScreenXY(gDude->tile, &dudeScreenX, &dudeScreenY, gElevation); + int dudeScreenX; + int dudeScreenY; + tileToScreenXY(gDude->tile, &dudeScreenX, &dudeScreenY, gElevation); - int dx = abs(dudeScreenX - tileScreenX); - int dy = abs(dudeScreenY - tileScreenY); + int dx = abs(dudeScreenX - tileScreenX); + int dy = abs(dudeScreenY - tileScreenY); - if (dx > abs(dudeScreenX - _tile_offx) - || dy > abs(dudeScreenY - _tile_offy)) { - if (dx >= 480 || dy >= 400) { - return -1; + if (dx > abs(dudeScreenX - _tile_offx) + || dy > abs(dudeScreenY - _tile_offy)) { + if (dx >= 480 || dy >= 400) { + return -1; + } } } - } - if ((gTileScrollBlockingEnabled & ((flags & TILE_SET_CENTER_FLAG_0x02) == 0)) != 0) { - if (_obj_scroll_blocking_at(tile, gElevation) == 0) { - return -1; + if (gTileScrollBlockingEnabled) { + if (_obj_scroll_blocking_at(tile, gElevation) == 0) { + return -1; + } } } @@ -590,7 +592,7 @@ int tileSetCenter(int tile, int flags) gCenterTile = tile; - if (flags & TILE_SET_CENTER_FLAG_0x01) { + if ((flags & TILE_SET_CENTER_REFRESH_WINDOW) != 0) { // NOTE: Uninline. tileWindowRefresh(); } diff --git a/src/tile.h b/src/tile.h index 83f2070..54f20a0 100644 --- a/src/tile.h +++ b/src/tile.h @@ -6,8 +6,8 @@ namespace fallout { -#define TILE_SET_CENTER_FLAG_0x01 0x01 -#define TILE_SET_CENTER_FLAG_0x02 0x02 +#define TILE_SET_CENTER_REFRESH_WINDOW 0x01 +#define TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS 0x02 typedef void(TileWindowRefreshProc)(Rect* rect); typedef void(TileWindowRefreshElevationProc)(Rect* rect, int elevation); From 3488833c2e0a1fdbf1be4945628c2c16912fe9f1 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 20:57:11 +0300 Subject: [PATCH 19/31] Use SDL for logging --- src/debug.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index fe17a60..6d03c8a 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -5,10 +5,7 @@ #include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif +#include #include "memory.h" #include "platform_compat.h" @@ -148,13 +145,7 @@ int debugPrint(const char* format, ...) rc = gDebugPrintProc(string); } else { #ifdef _DEBUG - char string[260]; - vsprintf(string, format, args); -#ifdef _WIN32 - OutputDebugStringA(string); -#else - printf("%s", string); -#endif + SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args); #endif rc = -1; } From bdf2c219aba48a656c25c6053818d61937e32e9c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 21:09:53 +0300 Subject: [PATCH 20/31] Fix error check --- src/loadsave.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loadsave.cc b/src/loadsave.cc index a23c01f..1fccaef 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -2435,7 +2435,7 @@ static int _SlotMap2Game(File* stream) debugPrint("LOADSAVE: in SlotMap2Game\n"); int v2; - if (fileReadInt32(stream, &v2) == 1) { + if (fileReadInt32(stream, &v2) == -1) { debugPrint("LOADSAVE: returning 1\n"); return -1; } From 37f7ecc1c3de18714fa314e3a803e0d2583ea3a0 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 29 Oct 2022 21:27:08 +0300 Subject: [PATCH 21/31] Review SlotMap2Game --- src/loadsave.cc | 60 +++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/loadsave.cc b/src/loadsave.cc index 1fccaef..7329cf8 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -2434,13 +2434,13 @@ static int _SlotMap2Game(File* stream) { debugPrint("LOADSAVE: in SlotMap2Game\n"); - int v2; - if (fileReadInt32(stream, &v2) == -1) { + int fileNameListLength; + if (fileReadInt32(stream, &fileNameListLength) == -1) { debugPrint("LOADSAVE: returning 1\n"); return -1; } - if (v2 == 0) { + if (fileNameListLength == 0) { debugPrint("LOADSAVE: returning 2\n"); return -1; } @@ -2467,46 +2467,42 @@ static int _SlotMap2Game(File* stream) sprintf(_str0, "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB"); compat_remove(_str0); - if (gPartyMemberDescriptionsLength > 1) { - for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) { - int pid = gPartyMemberPids[index]; - if (pid != -2) { - char protoPath[COMPAT_MAX_PATH]; - if (_proto_list_str(pid, protoPath) == 0) { - const char* basePath = pid >> 24 == OBJ_TYPE_CRITTER - ? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME - : PROTO_DIR_NAME "\\" ITEMS_DIR_NAME; - sprintf(_str0, "%s\\%s\\%s", _patches, basePath, protoPath); - sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath); + for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) { + int pid = gPartyMemberPids[index]; + if (pid != -2) { + char protoPath[COMPAT_MAX_PATH]; + if (_proto_list_str(pid, protoPath) == 0) { + const char* basePath = PID_TYPE(pid) == OBJ_TYPE_CRITTER + ? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME + : PROTO_DIR_NAME "\\" ITEMS_DIR_NAME; + sprintf(_str0, "%s\\%s\\%s", _patches, basePath, protoPath); + sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath); - if (_gzdecompress_file(_str1, _str0) == -1) { - debugPrint("LOADSAVE: returning 6\n"); - return -1; - } + if (_gzdecompress_file(_str1, _str0) == -1) { + debugPrint("LOADSAVE: returning 6\n"); + return -1; } } } } - if (v2 > 0) { - for (int index = 0; index < v2; index += 1) { - char v11[64]; // TODO: Size is probably wrong. - if (_mygets(v11, stream) == -1) { - break; - } + for (int index = 0; index < fileNameListLength; index += 1) { + char fileName[COMPAT_MAX_PATH]; + if (_mygets(fileName, stream) == -1) { + break; + } - sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, v11); - sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", v11); + sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, fileName); + sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", fileName); - if (_gzdecompress_file(_str0, _str1) == -1) { - debugPrint("LOADSAVE: returning 7\n"); - return -1; - } + if (_gzdecompress_file(_str0, _str1) == -1) { + debugPrint("LOADSAVE: returning 7\n"); + return -1; } } - const char* v9 = _strmfe(_str1, "AUTOMAP.DB", "SAV"); - sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, v9); + const char* automapFileName = _strmfe(_str1, "AUTOMAP.DB", "SAV"); + sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, automapFileName); sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB"); if (fileCopyDecompressed(_str0, _str1) == -1) { debugPrint("LOADSAVE: returning 8\n"); From 3015f39368c8ff0244a601932227492a53fdf061 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 08:41:00 +0300 Subject: [PATCH 22/31] Review interfaceFontGetStringWidthImpl --- src/font_manager.cc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/font_manager.cc b/src/font_manager.cc index 85c163e..67df34d 100644 --- a/src/font_manager.cc +++ b/src/font_manager.cc @@ -236,26 +236,22 @@ static int interfaceFontGetStringWidthImpl(const char* string) return 0; } - const char* pch = string; - int width = 0; + int stringWidth = 0; - while (*pch != '\0') { - int v3; - int v4; + while (*string != '\0') { + unsigned char ch = static_cast(*string++); - if (*pch == ' ') { - v3 = gCurrentInterfaceFontDescriptor->letterSpacing; - v4 = gCurrentInterfaceFontDescriptor->wordSpacing; + int characterWidth; + if (ch == ' ') { + characterWidth = gCurrentInterfaceFontDescriptor->wordSpacing; } else { - v3 = gCurrentInterfaceFontDescriptor->glyphs[*pch & 0xFF].width; - v4 = gCurrentInterfaceFontDescriptor->letterSpacing; + characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch].width; } - width += v3 + v4; - pch++; + stringWidth += characterWidth + gCurrentInterfaceFontDescriptor->letterSpacing; } - return width; + return stringWidth; } // 0x4421DC From 1342fd3ecf27362857ed035585d710e36d0c0b57 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 08:45:04 +0300 Subject: [PATCH 23/31] Fix warning --- src/font_manager.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/font_manager.cc b/src/font_manager.cc index 67df34d..7a17baa 100644 --- a/src/font_manager.cc +++ b/src/font_manager.cc @@ -343,13 +343,13 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le unsigned char* ptr = buf; while (*string != '\0') { - char ch = *string++; + unsigned char ch = static_cast(*string++); int characterWidth; if (ch == ' ') { characterWidth = gCurrentInterfaceFontDescriptor->wordSpacing; } else { - characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF].width; + characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch].width; } unsigned char* end; @@ -364,7 +364,7 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le break; } - InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF]); + InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch]); unsigned char* glyphDataPtr = gCurrentInterfaceFontDescriptor->data + glyph->offset; // Skip blank pixels (difference between font's line height and glyph height). From 4e98093d6cc8d9e4874eb975c598775eda33d854 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 09:03:24 +0300 Subject: [PATCH 24/31] Fix crash when removing all scripts --- src/scripts.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/scripts.cc b/src/scripts.cc index d5bf37c..ddb3ac5 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -2354,6 +2354,11 @@ int _scr_remove_all() } else { next = scriptListExtent->next; scriptRemove(script->sid); + + // CE: Current extent is freed in |scriptRemove|. Break + // to prevent next iteration which needs to dereference + // extent to obtain it's length. + break; } } } From e5aa4a3518ac24c62de2b10c4f2b6fce2d427fc3 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 09:31:09 +0300 Subject: [PATCH 25/31] Fix square tiles initial lookup --- src/object.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/object.cc b/src/object.cc index 9cbf55a..3c09abf 100644 --- a/src/object.cc +++ b/src/object.cc @@ -1497,7 +1497,10 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) if (v14 != _obj_last_roof_x || v15 != _obj_last_roof_y || elevation != _obj_last_elev) { int v16 = _square[elevation]->field_0[v14 + 100 * v15]; int v31 = buildFid(OBJ_TYPE_TILE, (v16 >> 16) & 0xFFF, 0, 0, 0); - int v32 = _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y]; + // CE: Add additional checks for -1 to prevent array lookup at index -101. + int v32 = _obj_last_roof_x != -1 && _obj_last_roof_y != -1 + ? _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y] + : 0; int v34 = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == v31; if (v34 != _obj_last_is_empty || (((v16 >> 16) & 0xF000) >> 12) != (((v32 >> 16) & 0xF000) >> 12)) { From bc43bdc99c65d1094e118566cd13316fbfd5fda8 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 09:39:43 +0300 Subject: [PATCH 26/31] Rename some variables in objectSetLocation --- src/object.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/object.cc b/src/object.cc index 3c09abf..eb078ee 100644 --- a/src/object.cc +++ b/src/object.cc @@ -185,7 +185,7 @@ static int _obj_last_roof_y = -1; static int _obj_last_elev = -1; // 0x51977C -static int _obj_last_is_empty = 1; +static bool _obj_last_is_empty = true; // 0x519780 unsigned char* _wallBlendTable = NULL; @@ -1492,24 +1492,24 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) // NOTE: Uninline. obj_set_seen(tile); - int v14 = tile % 200 / 2; - int v15 = tile / 200 / 2; - if (v14 != _obj_last_roof_x || v15 != _obj_last_roof_y || elevation != _obj_last_elev) { - int v16 = _square[elevation]->field_0[v14 + 100 * v15]; - int v31 = buildFid(OBJ_TYPE_TILE, (v16 >> 16) & 0xFFF, 0, 0, 0); + int roofX = tile % 200 / 2; + int roofY = tile / 200 / 2; + if (roofX != _obj_last_roof_x || roofY != _obj_last_roof_y || elevation != _obj_last_elev) { + int currentSquare = _square[elevation]->field_0[roofX + 100 * roofY]; + int currentSquareFid = buildFid(OBJ_TYPE_TILE, (currentSquare >> 16) & 0xFFF, 0, 0, 0); // CE: Add additional checks for -1 to prevent array lookup at index -101. - int v32 = _obj_last_roof_x != -1 && _obj_last_roof_y != -1 + int previousSquare = _obj_last_roof_x != -1 && _obj_last_roof_y != -1 ? _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y] : 0; - int v34 = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == v31; + bool isEmpty = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == currentSquareFid; - if (v34 != _obj_last_is_empty || (((v16 >> 16) & 0xF000) >> 12) != (((v32 >> 16) & 0xF000) >> 12)) { - if (_obj_last_is_empty == 0) { + if (isEmpty != _obj_last_is_empty || (((currentSquare >> 16) & 0xF000) >> 12) != (((previousSquare >> 16) & 0xF000) >> 12)) { + if (!_obj_last_is_empty) { _tile_fill_roof(_obj_last_roof_x, _obj_last_roof_y, elevation, 1); } - if (v34 == 0) { - _tile_fill_roof(v14, v15, elevation, 0); + if (!isEmpty) { + _tile_fill_roof(roofX, roofY, elevation, 0); } if (rect != NULL) { @@ -1517,10 +1517,10 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) } } - _obj_last_roof_x = v14; - _obj_last_roof_y = v15; + _obj_last_roof_x = roofX; + _obj_last_roof_y = roofY; _obj_last_elev = elevation; - _obj_last_is_empty = v34; + _obj_last_is_empty = isEmpty; } if (rect != NULL) { @@ -2186,7 +2186,7 @@ void _obj_remove_all() _obj_last_roof_y = -1; _obj_last_elev = -1; - _obj_last_is_empty = 1; + _obj_last_is_empty = true; _obj_last_roof_x = -1; } From e7d68c4f722512ece31778d3bfc8dcf4ef793d26 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 30 Oct 2022 13:00:43 +0300 Subject: [PATCH 27/31] Get rid of PreferenceDescription packing Fixes pointer alignment warnings. --- src/options.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/options.cc b/src/options.cc index 9cb1142..a288d89 100644 --- a/src/options.cc +++ b/src/options.cc @@ -107,7 +107,6 @@ typedef enum PreferencesWindowFrm { PREFERENCES_WINDOW_FRM_COUNT, } PreferencesWindowFrm; -#pragma pack(2) typedef struct PreferenceDescription { // The number of options. short valuesCount; @@ -129,7 +128,6 @@ typedef struct PreferenceDescription { double maxValue; int* valuePtr; } PreferenceDescription; -#pragma pack() static int optionsWindowInit(); static int optionsWindowFree(); From b689b3a757e2a75bb4f8d5b6bdff1adbdf963183 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Thu, 3 Nov 2022 17:48:34 +0300 Subject: [PATCH 28/31] Fix combat control fields not being cleared Closes #194 --- src/game_dialog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game_dialog.cc b/src/game_dialog.cc index b14066f..d3a5bb6 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -3498,7 +3498,7 @@ void partyMemberControlWindowUpdate() FrmImage backgroundFrmImage; int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0); - if (!backgroundFrmImage.lock(backgroundFid)) { + if (backgroundFrmImage.lock(backgroundFid)) { int width = backgroundFrmImage.getWidth(); unsigned char* buffer = backgroundFrmImage.getData(); From a38151bf2cb29c52cda7f5ad9806c11d8dca8566 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Thu, 3 Nov 2022 18:08:49 +0300 Subject: [PATCH 29/31] Reorganize control flow in gdCustomSelect Fixes #198 --- src/game_dialog.cc | 134 +++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 71 deletions(-) diff --git a/src/game_dialog.cc b/src/game_dialog.cc index d3a5bb6..99d226b 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -4104,86 +4104,78 @@ int _gdCustomSelect(int a1) sharedFpsLimiter.mark(); int keyCode = inputGetInput(); - if (keyCode == -1) { - continue; - } - - if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) { - showQuitConfirmationDialog(); - } - - if (_game_user_wants_to_quit != 0) { - break; - } - - if (keyCode == KEY_RETURN) { - STRUCT_5189E4* ptr = &(_custom_settings[a1][value]); - _custom_current_selected[a1] = value; - _gdCustomUpdateSetting(a1, ptr->value); - done = true; - } else if (keyCode == KEY_ESCAPE) { - done = true; - } else if (keyCode == -2) { - if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) == 0) { - continue; + if (keyCode != -1) { + if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) { + showQuitConfirmationDialog(); } - // No need to use mouseHitTestInWindow as these values are already - // in screen coordinates. - if (!_mouse_click_in(minX, minY, maxX, maxY)) { - continue; + if (_game_user_wants_to_quit != 0) { + break; } - int mouseX; - int mouseY; - mouseGetPosition(&mouseX, &mouseY); + if (keyCode == KEY_RETURN) { + STRUCT_5189E4* ptr = &(_custom_settings[a1][value]); + _custom_current_selected[a1] = value; + _gdCustomUpdateSetting(a1, ptr->value); + done = true; + } else if (keyCode == KEY_ESCAPE) { + done = true; + } else if (keyCode == -2) { + if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) != 0) { + // No need to use mouseHitTestInWindow as these values are already + // in screen coordinates. + if (_mouse_click_in(minX, minY, maxX, maxY)) { + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); - int lineHeight = fontGetLineHeight(); - int newValue = (mouseY - minY) / lineHeight; - if (newValue >= 6) { - continue; - } + int lineHeight = fontGetLineHeight(); + int newValue = (mouseY - minY) / lineHeight; + if (newValue < 6) { + unsigned int timestamp = getTicks(); + if (newValue == value) { + if (getTicksBetween(timestamp, v53) < 250) { + _custom_current_selected[a1] = newValue; + _gdCustomUpdateSetting(a1, newValue); + done = true; + } + } else { + STRUCT_5189E4* ptr = &(_custom_settings[a1][newValue]); + if (ptr->messageId != -1) { + bool enabled = false; + switch (a1) { + case PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE: + enabled = partyMemberSupportsAreaAttackMode(gGameDialogSpeaker, ptr->value); + break; + case PARTY_MEMBER_CUSTOMIZATION_OPTION_RUN_AWAY_MODE: + enabled = partyMemberSupportsRunAwayMode(gGameDialogSpeaker, ptr->value); + break; + case PARTY_MEMBER_CUSTOMIZATION_OPTION_BEST_WEAPON: + enabled = partyMemberSupportsBestWeapon(gGameDialogSpeaker, ptr->value); + break; + case PARTY_MEMBER_CUSTOMIZATION_OPTION_DISTANCE: + enabled = partyMemberSupportsDistance(gGameDialogSpeaker, ptr->value); + break; + case PARTY_MEMBER_CUSTOMIZATION_OPTION_ATTACK_WHO: + enabled = partyMemberSupportsAttackWho(gGameDialogSpeaker, ptr->value); + break; + case PARTY_MEMBER_CUSTOMIZATION_OPTION_CHEM_USE: + enabled = partyMemberSupportsChemUse(gGameDialogSpeaker, ptr->value); + break; + } - unsigned int timestamp = getTicks(); - if (newValue == value) { - if (getTicksBetween(timestamp, v53) < 250) { - _custom_current_selected[a1] = newValue; - _gdCustomUpdateSetting(a1, newValue); - done = true; - } - } else { - STRUCT_5189E4* ptr = &(_custom_settings[a1][newValue]); - if (ptr->messageId != -1) { - bool enabled = false; - switch (a1) { - case PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE: - enabled = partyMemberSupportsAreaAttackMode(gGameDialogSpeaker, ptr->value); - break; - case PARTY_MEMBER_CUSTOMIZATION_OPTION_RUN_AWAY_MODE: - enabled = partyMemberSupportsRunAwayMode(gGameDialogSpeaker, ptr->value); - break; - case PARTY_MEMBER_CUSTOMIZATION_OPTION_BEST_WEAPON: - enabled = partyMemberSupportsBestWeapon(gGameDialogSpeaker, ptr->value); - break; - case PARTY_MEMBER_CUSTOMIZATION_OPTION_DISTANCE: - enabled = partyMemberSupportsDistance(gGameDialogSpeaker, ptr->value); - break; - case PARTY_MEMBER_CUSTOMIZATION_OPTION_ATTACK_WHO: - enabled = partyMemberSupportsAttackWho(gGameDialogSpeaker, ptr->value); - break; - case PARTY_MEMBER_CUSTOMIZATION_OPTION_CHEM_USE: - enabled = partyMemberSupportsChemUse(gGameDialogSpeaker, ptr->value); - break; - } - - if (enabled) { - value = newValue; - _gdCustomSelectRedraw(windowBuffer, backgroundFrmWidth, a1, newValue); - windowRefresh(win); + if (enabled) { + value = newValue; + _gdCustomSelectRedraw(windowBuffer, backgroundFrmWidth, a1, newValue); + windowRefresh(win); + } + } + } + v53 = timestamp; + } } } } - v53 = timestamp; } renderPresent(); From c692fc91af34b121e31dcc00b5f9e89e73773456 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Thu, 3 Nov 2022 18:16:50 +0300 Subject: [PATCH 30/31] Fix error check Closes #196 --- src/options.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.cc b/src/options.cc index a288d89..d66a458 100644 --- a/src/options.cc +++ b/src/options.cc @@ -494,7 +494,7 @@ int showOptionsWithInitialKeyCode(int initialKeyCode) case KEY_UPPERCASE_S: case KEY_LOWERCASE_S: case 500: - if (lsgSaveGame(1) != 1) { + if (lsgSaveGame(LOAD_SAVE_MODE_NORMAL) == 1) { rc = 1; } break; From 3ec827d5c1f0f04eddc56b64b8678f1e308d0966 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Mon, 7 Nov 2022 10:59:16 +0300 Subject: [PATCH 31/31] Fix worldmap position calculation Closes #192 --- src/worldmap.cc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/worldmap.cc b/src/worldmap.cc index 2821c4f..3d81704 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -849,6 +849,15 @@ int wmWorldMap_init() gTownMapHotkeysFix = true; configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY, &gTownMapHotkeysFix); + // CE: City size fids should be initialized during startup. They are used + // during |wmTeleportToArea| to calculate worldmap position when jumping + // from Temple to Arroyo - before giving a chance to |wmInterfaceInit| to + // initialize it. + for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) { + CitySizeDescription* citySizeDescription = &(wmSphereData[citySize]); + citySizeDescription->fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0); + } + return 0; } @@ -4469,11 +4478,7 @@ static int wmInterfaceInit() for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) { CitySizeDescription* citySizeDescription = &(wmSphereData[citySize]); - - fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0); - citySizeDescription->fid = fid; - - if (!citySizeDescription->frmImage.lock(fid)) { + if (!citySizeDescription->frmImage.lock(citySizeDescription->fid)) { return -1; } } @@ -6540,9 +6545,21 @@ int wmTeleportToArea(int areaIdx) // locations. // CE: See `wmWorldMapFunc` for explanation. CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]); + + // CE: This function might be called outside |wmWorldmapFunc|, so it's + // image might not be locked. + bool wasLocked = citySizeDescription->frmImage.isLocked(); + if (!wasLocked) { + citySizeDescription->frmImage.lock(citySizeDescription->fid); + } + wmGenData.worldPosX = city->x + citySizeDescription->frmImage.getWidth() / 2 - WM_VIEW_X; wmGenData.worldPosY = city->y + citySizeDescription->frmImage.getHeight() / 2 - WM_VIEW_Y; + if (!wasLocked) { + citySizeDescription->frmImage.unlock(); + } + return 0; }