Compare commits

..
Author SHA1 Message Date
IronKing24 8a4469cc57 Merge branch 'main' into platform_compat 2026-07-22 11:58:01 +03:00
Mike Klaas 94a7e7207c Solidify opcode_exists (#579)
* Solidify opcode_exists

* add arg validation
2026-07-21 08:54:38 -07:00
alpacacommunist-cmd b8988b69a8 combatAi: heap fragmentation fix, free previously initialized lists before init (#569)
* free previously initialized lists before init

* adds reasoning comment, safer verification
2026-07-21 13:36:18 +03:00
Mike Klaas 9467f4f778 Allow compat_resolve_path to handle duplicate path separators (#575)
Alternate fix for https://github.com/fallout2-ce/fallout2-ce/pull/563.
2026-07-20 21:49:04 -07:00
V4nnura 447cf6edff Unify linux-armhf and linux-arm64 yaml code. (#574)
* Unify linux-armhf and linux-arm64.
2026-07-20 20:56:26 -07:00
alpacacommunist-cmd c9bcb719ee adds combatSave OBJECT_NO_SAVE predicate + combat list filters (#553)
* adds combatSave OBJECT_NO_SAVE predicate + combat list filters
2026-07-20 20:43:16 -07:00
IronKing24 8bf7064a08 update android ndk version to current lts to support std::fs 2026-07-11 00:02:02 +03:00
IronKing24 dfea73105c Merge remote-tracking branch 'upstream/HEAD' into platform_compat 2026-07-10 23:33:26 +03:00
IronKing24 dd604b22b6 update the new functions 2026-07-06 14:17:14 +03:00
IronKing24 e1426a40c6 pump cmake ios and mac versions 2026-05-29 15:23:15 +03:00
IronKing24 ae6c7aba6e pump mac & ios version 2026-05-29 14:41:34 +03:00
IronKing24 e5387bef63 Merge branch 'main' into platform_compat 2026-05-26 23:02:04 +03:00
github-actions[bot] 76080a4878 chore: auto-format with clang-format 2026-05-26 14:33:23 +00:00
IronKing24 12314cd5d7 fix includes 2026-05-21 01:52:36 +03:00
IronKing24 a0e1b73116 update compat_access 2026-05-20 21:32:16 +03:00
IronKing24 23c38f60f1 update compat_rename 2026-05-20 21:31:13 +03:00
IronKing24 0c1ecfc3ac update compat_remove 2026-05-20 21:30:44 +03:00
IronKing24 45676bcc05 update compat_timeGetTime 2026-05-20 21:15:47 +03:00
IronKing24 46152f7e86 update compat_file_exists 2026-05-20 21:15:16 +03:00
IronKing24 b6d1a29411 update compat_mkdir_recursive 2026-05-20 21:14:28 +03:00
IronKing24 6bbd1a48cc update compat_mkdir 2026-05-20 21:13:47 +03:00
IronKing24 3b7e1d8916 update compat_filelength and header 2026-05-20 21:12:06 +03:00
IronKing24 1f05d0b690 update compat_makepath 2026-05-20 21:10:21 +03:00
IronKing24 444565e8a1 update compat_splitpath 2026-05-20 21:08:46 +03:00
20 changed files with 234 additions and 583 deletions
+31 -54
View File
@@ -142,7 +142,7 @@ jobs:
ios:
name: iOS
runs-on: macos-14
runs-on: macos-15
needs: [ce-dat]
steps:
@@ -255,23 +255,38 @@ jobs:
path: out/dist/fallout2-ce-linux-${{ matrix.arch }}.tar.gz
retention-days: 7
linux-armhf:
name: Linux (armhf)
linux-arm:
name: Linux (${{ matrix.arch }})
runs-on: ubuntu-22.04-arm
needs: [ce-dat]
strategy:
fail-fast: false
matrix:
arch:
- armhf
- arm64
steps:
- name: Clone
uses: actions/checkout@v4
- name: Dependencies
- name: Dependencies (armhf)
if: matrix.arch == 'armhf'
run: |
sudo dpkg --add-architecture armhf
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libsdl2-dev:armhf zlib1g-dev:armhf
- name: Configure
- name: Dependencies (arm64)
if: matrix.arch == 'arm64'
run: |
sudo apt update
sudo apt install libsdl2-dev zlib1g-dev
- name: Configure (armhf)
if: matrix.arch == 'armhf'
run: |
cmake \
-B build \
@@ -282,46 +297,8 @@ jobs:
-D CMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \
# EOL
- name: Build
run: cmake --build build
- name: Download ce.dat
uses: actions/download-artifact@v4
with:
name: ce-dat
path: out/dist
- name: Package
run: |
mkdir -p out/dist/fallout2-ce-linux-armhf
cp build/fallout2-ce out/dist/fallout2-ce-linux-armhf/fallout2-ce
cp out/dist/ce.dat out/dist/fallout2-ce-linux-armhf/ce.dat
cp files/fallout2.cfg out/dist/fallout2-ce-linux-armhf/EXAMPLE_fallout2.cfg
tar -czvf out/dist/fallout2-ce-linux-armhf.tar.gz -C out/dist fallout2-ce-linux-armhf
- name: Upload
uses: actions/upload-artifact@v4
with:
name: fallout2-ce-linux-armhf
path: out/dist/fallout2-ce-linux-armhf.tar.gz
retention-days: 7
linux-arm64:
name: Linux (arm64)
runs-on: ubuntu-22.04-arm
needs: [ce-dat]
steps:
- name: Clone
uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update
sudo apt install libsdl2-dev zlib1g-dev
- name: Configure
- name: Configure (arm64)
if: matrix.arch == 'arm64'
run: cmake -B build -D CMAKE_BUILD_TYPE=Debug -D FALLOUT_VENDORED=OFF
- name: Build
@@ -335,23 +312,23 @@ jobs:
- name: Package
run: |
mkdir -p out/dist/fallout2-ce-linux-arm64
cp build/fallout2-ce out/dist/fallout2-ce-linux-arm64/fallout2-ce
cp out/dist/ce.dat out/dist/fallout2-ce-linux-arm64/ce.dat
cp files/fallout2.cfg out/dist/fallout2-ce-linux-arm64/EXAMPLE_fallout2.cfg
tar -czvf out/dist/fallout2-ce-linux-arm64.tar.gz -C out/dist fallout2-ce-linux-arm64
mkdir -p out/dist/fallout2-ce-linux-${{ matrix.arch }}
cp build/fallout2-ce out/dist/fallout2-ce-linux-${{ matrix.arch }}/fallout2-ce
cp out/dist/ce.dat out/dist/fallout2-ce-linux-${{ matrix.arch }}/ce.dat
cp files/fallout2.cfg out/dist/fallout2-ce-linux-${{ matrix.arch }}/EXAMPLE_fallout2.cfg
tar -czvf out/dist/fallout2-ce-linux-${{ matrix.arch }}.tar.gz -C out/dist fallout2-ce-linux-${{ matrix.arch }}
- name: Upload
uses: actions/upload-artifact@v4
with:
name: fallout2-ce-linux-arm64
path: out/dist/fallout2-ce-linux-arm64.tar.gz
name: fallout2-ce-linux-${{ matrix.arch }}
path: out/dist/fallout2-ce-linux-${{ matrix.arch }}.tar.gz
retention-days: 7
macos:
name: macOS
runs-on: macos-14
runs-on: macos-15
steps:
- name: Clone
@@ -451,7 +428,7 @@ jobs:
release:
name: Release Continuous build
runs-on: ubuntu-latest
needs: [android, ios, linux, linux-armhf, linux-arm64, macos, windows]
needs: [android, ios, linux, linux-arm, macos, windows]
permissions:
contents: write
steps:
+2 -2
View File
@@ -6,10 +6,10 @@ set(EXECUTABLE_NAME fallout2-ce)
if(APPLE)
if(IOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12" CACHE STRING "")
set(CMAKE_OSX_DEPLOYMENT_TARGET "13" CACHE STRING "")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
else()
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "")
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
endif()
endif()
-3
View File
@@ -161,9 +161,6 @@ inventory_columns=2
; Set to 1 to scale only the main menu background image to fit the screen while maintaining aspect ratio.
; Set to 2 to also scale the main menu button panel, red buttons, and button labels with the menu art.
main_menu_scale_mode=1
;Set to 1 to keep the main menu visible behind the 640x480 New Game, Load Game, and Options screens,
;but only when the effective main menu background is larger than 640x480.
main_menu_overlay_subscreens=1
; Set to 1 to show a Help option in the in-game options menu which opens the F1 help screen.
in_game_menu_help=1
+1
View File
@@ -89,6 +89,7 @@ def assertSdlJavaBindingsMatch = { String variantName ->
android {
compileSdk 32
ndkVersion "27.3.13750724"
defaultConfig {
applicationId 'com.alexbatalov.fallout2ce'
+2 -1
View File
@@ -21,10 +21,11 @@ procedure start begin
call assertEquals("opcode_exists OP_NOOP", opcode_exists(OP_NOOP), 1);
// Probably will never be implemented on fallout2-ce
call assertEquals("opcode_exists OP_WRITE_INT", opcode_exists(OP_WRITE_INT), 0);
call assertEquals("opcode_exists bare index", opcode_exists(0x1B3), 0);
call assertEquals("opcode_exists 0xFFFF", opcode_exists(0xFFFF), 0);
end else begin
display_msg("Opcode exists metarule is not available, skipping tests.");
end
call report_test_results("metarule_exist");
end
end
+6 -13
View File
@@ -28,7 +28,6 @@
#include "interface.h"
#include "item.h"
#include "kb.h"
#include "mainmenu.h"
#include "map.h"
#include "memory.h"
#include "message.h"
@@ -233,7 +232,6 @@ typedef struct KillInfo {
static int characterEditorWindowInit();
static void characterEditorWindowFree();
static int characterEditorGetModalWindowFlags();
static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, int x, int y, int textColor, int backgroundColor, int flags);
static void characterEditorDrawFolders();
static void characterEditorDrawPerksFolder();
@@ -1206,11 +1204,6 @@ int characterEditorShow(bool isCreationMode)
return rc;
}
static int characterEditorGetModalWindowFlags()
{
return mainMenuSubscreenWindowFlags(WINDOW_MODAL | WINDOW_DONT_MOVE_TOP, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
}
// 0x4329EC CharEditStart
static int characterEditorWindowInit()
{
@@ -1385,7 +1378,7 @@ static int characterEditorWindowInit()
EDITOR_WINDOW_WIDTH,
EDITOR_WINDOW_HEIGHT,
256,
characterEditorGetModalWindowFlags());
WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (gCharacterEditorWindow == -1) {
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
if (gCharacterEditorFrmShouldCopy[i]) {
@@ -3218,7 +3211,7 @@ static int characterEditorEditName()
int nameWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + 17;
int nameWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
int win = windowCreate(nameWindowX, nameWindowY, windowWidth, windowHeight, 256, characterEditorGetModalWindowFlags());
int win = windowCreate(nameWindowX, nameWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (win == -1) {
return -1;
}
@@ -3350,7 +3343,7 @@ static int characterEditorEditAge()
int ageWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth() + 9;
int ageWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
win = windowCreate(ageWindowX, ageWindowY, windowWidth, windowHeight, 256, characterEditorGetModalWindowFlags());
win = windowCreate(ageWindowX, ageWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (win == -1) {
return -1;
}
@@ -3589,7 +3582,7 @@ static void characterEditorEditGender()
+ _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth()
+ _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth();
int genderWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
int win = windowCreate(genderWindowX, genderWindowY, windowWidth, windowHeight, 256, characterEditorGetModalWindowFlags());
int win = windowCreate(genderWindowX, genderWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (win == -1) {
return;
@@ -3832,7 +3825,7 @@ static int characterEditorShowOptions()
int optionsWindowY = (screenGetHeight() != 480)
? (screenGetHeight() - _editorFrmImages[41].getHeight()) / 2
: 90;
int win = windowCreate(optionsWindowX, optionsWindowY, _editorFrmImages[41].getWidth(), _editorFrmImages[41].getHeight(), 256, characterEditorGetModalWindowFlags());
int win = windowCreate(optionsWindowX, optionsWindowY, _editorFrmImages[41].getWidth(), _editorFrmImages[41].getHeight(), 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (win == -1) {
return -1;
}
@@ -5837,7 +5830,7 @@ static int perkDialogShow()
int perkWindowY = screenGetHeight() != 480
? (screenGetHeight() - PERK_WINDOW_HEIGHT) / 2
: PERK_WINDOW_Y;
gPerkDialogWindow = windowCreate(perkWindowX, perkWindowY, PERK_WINDOW_WIDTH, PERK_WINDOW_HEIGHT, 256, characterEditorGetModalWindowFlags());
gPerkDialogWindow = windowCreate(perkWindowX, perkWindowY, PERK_WINDOW_WIDTH, PERK_WINDOW_HEIGHT, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (gPerkDialogWindow == -1) {
_perkDialogBackgroundFrmImage.unlock();
debugPrint("\n *** Error running perks dialog window ***\n");
+4 -9
View File
@@ -18,7 +18,6 @@
#include "game_sound.h"
#include "input.h"
#include "kb.h"
#include "mainmenu.h"
#include "memory.h"
#include "message.h"
#include "mouse.h"
@@ -161,7 +160,8 @@ int characterSelectorOpen()
mouseShowCursor();
}
mainMenuShowSubscreen(true);
colorPaletteLoad("color.pal");
paletteFadeTo(_cmap);
int rc = 0;
bool done = false;
@@ -247,11 +247,7 @@ int characterSelectorOpen()
sharedFpsLimiter.throttle();
}
if (rc == 2) {
mainMenuFadeOutAfterSubscreen(true);
} else {
mainMenuRestoreAfterSubscreen(true);
}
paletteFadeTo(gPaletteBlack);
characterSelectorWindowFree();
if (cursorWasHidden) {
@@ -273,8 +269,7 @@ static bool characterSelectorWindowInit()
int characterSelectorWindowX = (screenGetWidth() - CS_WINDOW_WIDTH) / 2;
int characterSelectorWindowY = (screenGetHeight() - CS_WINDOW_HEIGHT) / 2;
int characterSelectorWindowFlags = mainMenuSubscreenWindowFlags(0, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
gCharacterSelectorWindow = windowCreate(characterSelectorWindowX, characterSelectorWindowY, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, _colorTable[0], characterSelectorWindowFlags);
gCharacterSelectorWindow = windowCreate(characterSelectorWindowX, characterSelectorWindowY, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, COLOR_BLACK, 0);
if (gCharacterSelectorWindow == -1) {
return characterSelectorWindowFatalError(false);
}
+53 -13
View File
@@ -2221,36 +2221,76 @@ int combatLoad(File* stream)
return 0;
}
static bool _combatShouldSaveObject(Object* obj)
{
if (obj == nullptr) return false;
if (obj == gDude) return true;
if (objectIsPartyMember(obj)) return true;
return (obj->flags & OBJECT_NO_SAVE) == 0;
}
// 0x421244
int combatSave(File* stream)
{
if (fileWriteInt32(stream, gCombatState) == -1) return -1;
if (!isInCombat()) return 0;
if (fileWriteInt32(stream, _combat_turn_running) == -1) return -1;
if (fileWriteInt32(stream, _combat_free_move) == -1) return -1;
if (fileWriteInt32(stream, _combat_exps) == -1) return -1;
if (fileWriteInt32(stream, _list_com) == -1) return -1;
if (fileWriteInt32(stream, _list_noncom) == -1) return -1;
if (fileWriteInt32(stream, _list_total) == -1) return -1;
int valid_total = 0;
int valid_noncom = 0;
int valid_com = 0;
for (int index = 0; index < _list_com; index++) {
if (_combatShouldSaveObject(_combat_list[index])) {
valid_com++;
valid_total++;
}
}
for (int index = _list_com; index < _list_total; index++) {
if (_combatShouldSaveObject(_combat_list[index])) {
valid_noncom++;
valid_total++;
}
}
if (fileWriteInt32(stream, valid_com) == -1) return -1;
if (fileWriteInt32(stream, valid_noncom) == -1) return -1;
if (fileWriteInt32(stream, valid_total) == -1) return -1;
if (fileWriteInt32(stream, gDude->cid) == -1) return -1;
for (int index = 0; index < _list_total; index++) {
if (fileWriteInt32(stream, _combat_list[index]->cid) == -1) return -1;
}
if (_aiInfoList == nullptr) return -1;
if (_aiInfoList == nullptr) {
return -1;
for (int index = 0; index < _list_total; index++) {
Object* obj = _combat_list[index];
if (_combatShouldSaveObject(obj)) {
if (fileWriteInt32(stream, obj->cid) == -1) return -1;
}
}
for (int index = 0; index < _list_total; index++) {
Object* obj = _combat_list[index];
if (!_combatShouldSaveObject(obj)) continue;
int friendlyId = -1;
int targetId = -1;
int itemId = -1;
int lastMove = 0;
CombatAiInfo* aiInfo = &(_aiInfoList[index]);
if (fileWriteInt32(stream, aiInfo->friendlyDead != nullptr ? aiInfo->friendlyDead->id : -1) == -1) return -1;
if (fileWriteInt32(stream, aiInfo->lastTarget != nullptr ? aiInfo->lastTarget->id : -1) == -1) return -1;
if (fileWriteInt32(stream, aiInfo->lastItem != nullptr ? aiInfo->lastItem->id : -1) == -1) return -1;
if (fileWriteInt32(stream, aiInfo->lastMove) == -1) return -1;
friendlyId = _combatShouldSaveObject(aiInfo->friendlyDead) ? aiInfo->friendlyDead->id : -1;
targetId = _combatShouldSaveObject(aiInfo->lastTarget) ? aiInfo->lastTarget->id : -1;
itemId = aiInfo->lastItem != nullptr ? aiInfo->lastItem->id : -1;
lastMove = aiInfo->lastMove;
if (fileWriteInt32(stream, friendlyId) == -1) return -1;
if (fileWriteInt32(stream, targetId) == -1) return -1;
if (fileWriteInt32(stream, itemId) == -1) return -1;
if (fileWriteInt32(stream, lastMove) == -1) return -1;
}
return 0;
+9
View File
@@ -3593,6 +3593,15 @@ bool isWithinPerception(Object* watcher, Object* target)
// 0x42BB34
static int aiMessageListInit()
{
// Prevent chronic memory leak on preference/language filter reloads.
// If gCombatAiMessageList was already populated from a previous init cascade,
// we must deeply free its entries before re-initializing the layout,
// otherwise the subsequent load will overwrite active pointers and isolate strings in the heap.
if (gCombatAiMessageList.entries != nullptr && gCombatAiMessageList.entries_num > 0) {
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_COMBAT_AI, nullptr);
messageListFree(&gCombatAiMessageList);
}
if (!messageListInit(&gCombatAiMessageList)) {
return -1;
}
-1
View File
@@ -24,7 +24,6 @@ namespace fallout {
#define GAME_CONFIG_WINDOWED_KEY "windowed"
#define GAME_CONFIG_SCALE_KEY "scale"
#define GAME_CONFIG_MAIN_MENU_SCALE_MODE_KEY "main_menu_scale_mode"
#define GAME_CONFIG_MAIN_MENU_OVERLAY_SUBSCREENS_KEY "main_menu_overlay_subscreens"
#define GAME_CONFIG_IFACE_BAR_MODE_KEY "iface_bar_mode"
#define GAME_CONFIG_IFACE_BAR_WIDTH_KEY "iface_bar_width"
#define GAME_CONFIG_IFACE_BAR_SIDE_ART_KEY "iface_bar_side_art"
+3 -3
View File
@@ -32,7 +32,6 @@
#include "interface.h"
#include "item.h"
#include "kb.h"
#include "mainmenu.h"
#include "map.h"
#include "memory.h"
#include "message.h"
@@ -1203,7 +1202,8 @@ int lsgLoadGame(int mode)
windowRefresh(gLoadSaveWindow);
renderPresent();
if (mode == LOAD_SAVE_MODE_FROM_MAIN_MENU) {
mainMenuShowSubscreen(true);
colorPaletteLoad("color.pal");
paletteFadeTo(_cmap);
}
_dbleclkcntr = 24;
@@ -1554,7 +1554,7 @@ int lsgLoadGame(int mode)
}
if (mode == LOAD_SAVE_MODE_FROM_MAIN_MENU && rc == 0) {
mainMenuRestoreAfterSubscreen(true);
paletteFadeTo(gPaletteBlack);
}
lsgWindowFree(mode == LOAD_SAVE_MODE_FROM_MAIN_MENU
+56 -53
View File
@@ -57,7 +57,6 @@ static void main_unload_new();
static void mainParseCommandLineArguments(int argc, char** argv);
static bool mainTryParseDevLoadGameSlot(const char* value, int* slotPtr);
static void mainLoop();
static void mainRunGameLoopAndCleanup();
static void showDeath();
static void _main_death_voiceover_callback();
static int _mainDeathGrabTextFile(const char* fileName, char* dest);
@@ -126,11 +125,10 @@ int falloutMain(int argc, char** argv)
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_STOP_MUSIC);
gameMoviePlay(MOVIE_CREDITS, 0);
break;
case MAIN_MENU_NEW_GAME: {
mainMenuBeginSubscreen();
case MAIN_MENU_NEW_GAME:
mainMenuWindowHide(true);
mainMenuWindowFree();
if (characterSelectorOpen() == 2) {
mainMenuFinishSubscreen();
gameMoviePlay(MOVIE_ELDER, GAME_MOVIE_STOP_MUSIC);
randomSeedPrerandom(-1);
@@ -152,38 +150,62 @@ int falloutMain(int argc, char** argv)
sfallOnAfterGameStarted();
gGameLoaded = true;
mainRunGameLoopAndCleanup();
mainMenuWindowInit();
} else {
mainMenuCancelSubscreen();
}
break;
}
case MAIN_MENU_LOAD_GAME: {
mainMenuBeginSubscreen();
mainLoop();
paletteFadeTo(gPaletteWhite);
// NOTE: Uninline.
main_loadgame_new();
if (devLoadGameSlot != -1) {
lsgDevSetLoadGameSlot(devLoadGameSlot);
}
int loadGameRc = lsgLoadGame(LOAD_SAVE_MODE_FROM_MAIN_MENU);
if (loadGameRc == -1) {
debugPrint("\n ** Error running LoadGame()! **\n");
}
if (loadGameRc > 0) {
mainMenuFinishSubscreen();
mainRunGameLoopAndCleanup();
mainMenuWindowInit();
} else {
// NOTE: Uninline.
main_unload_new();
// NOTE: Uninline.
main_reset_system();
mainMenuCancelSubscreen();
if (_main_show_death_scene != 0) {
showDeath();
_main_show_death_scene = 0;
}
}
mainMenuWindowInit();
break;
case MAIN_MENU_LOAD_GAME:
if (1) {
int win = windowCreate(0, 0, screenGetWidth(), screenGetHeight(), COLOR_BLACK, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
mainMenuWindowHide(true);
mainMenuWindowFree();
// NOTE: Uninline.
main_loadgame_new();
if (devLoadGameSlot != -1) {
lsgDevSetLoadGameSlot(devLoadGameSlot);
}
int loadGameRc = lsgLoadGame(LOAD_SAVE_MODE_FROM_MAIN_MENU);
if (loadGameRc == -1) {
debugPrint("\n ** Error running LoadGame()! **\n");
} else if (loadGameRc != 0) {
windowDestroy(win);
win = -1;
mainLoop();
paletteFadeTo(gPaletteWhite);
}
if (win != -1) {
windowDestroy(win);
}
// NOTE: Uninline.
main_unload_new();
// NOTE: Uninline.
main_reset_system();
if (_main_show_death_scene != 0) {
showDeath();
_main_show_death_scene = 0;
}
mainMenuWindowInit();
}
break;
}
case MAIN_MENU_TIMEOUT:
debugPrint("Main menu timed-out\n");
// FALLTHROUGH
@@ -191,12 +213,10 @@ int falloutMain(int argc, char** argv)
mainMenuWindowHide(true);
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
break;
case MAIN_MENU_OPTIONS: {
mainMenuBeginSubscreen();
case MAIN_MENU_OPTIONS:
mainMenuWindowHide(true);
doPreferences(true);
mainMenuCancelSubscreen();
break;
}
case MAIN_MENU_CREDITS:
mainMenuWindowHide(true);
creditsOpen("credits.txt", -1, false);
@@ -394,23 +414,6 @@ static void mainLoop()
}
}
static void mainRunGameLoopAndCleanup()
{
mainLoop();
paletteFadeTo(gPaletteWhite);
// NOTE: Uninline.
main_unload_new();
// NOTE: Uninline.
main_reset_system();
if (_main_show_death_scene != 0) {
showDeath();
_main_show_death_scene = 0;
}
}
// 0x48118C
static void showDeath()
{
-221
View File
@@ -1,14 +1,11 @@
#include "mainmenu.h"
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include "art.h"
#include "color.h"
#include "content_config.h"
#include "debug.h"
#include "delay.h"
#include "draw.h"
#include "font_manager.h"
#include "game.h"
@@ -51,12 +48,6 @@ namespace fallout {
#define MAIN_MENU_VERSION_Y 440
#define MAIN_MENU_BUILD_HASH_Y 450
#define MAIN_MENU_BUILD_DATE_Y 460
#define MAIN_MENU_OVERLAY_WINDOW_WIDTH 640
#define MAIN_MENU_OVERLAY_WINDOW_HEIGHT 480
#define MAIN_MENU_OVERLAY_DIM_TARGET_INTENSITY 0x8000
#define MAIN_MENU_OVERLAY_DIM_CLEAR_INTENSITY 0x10000
#define MAIN_MENU_OVERLAY_DIM_ANIMATION_STEPS 8
#define MAIN_MENU_OVERLAY_DIM_FRAME_DELAY 20
typedef enum MainMenuButton {
MAIN_MENU_BUTTON_INTRO,
@@ -114,20 +105,12 @@ static int gMainMenuButtons[MAIN_MENU_BUTTON_COUNT];
// 0x614858 main_menu_is_hidden
static bool gMainMenuWindowHidden;
static int gMainMenuOverlayCount = 0;
static bool gMainMenuOverlayBackgroundEnabled = false;
static FrmImage mainMenuBackgroundFrmImage;
static FrmImage mainMenuButtonPanelFrmImage;
static FrmImage mainMenuButtonNormalFrmImage;
static FrmImage mainMenuButtonPressedFrmImage;
static std::vector<unsigned char> mainMenuScaledButtonData;
static std::vector<unsigned char> mainMenuOverlayDimmedBackup;
static void mainMenuSetButtonsEnabled(bool enabled);
static void mainMenuApplyOverlayDim();
static void mainMenuRemoveOverlayDim();
static void mainMenuSetOverlayDimIntensity(int intensity);
static void mainMenuAnimateOverlayDim(int startIntensity, int endIntensity);
struct MainMenuLayout {
int screenWidth;
@@ -164,14 +147,9 @@ static int mainMenuScaleX(const MainMenuLayout& layout, int value);
static int mainMenuScaleY(const MainMenuLayout& layout, int value);
static int mainMenuGetAnchoredY(const MainMenuLayout& layout, int value);
static int mainMenuGetAnchoredRightX(const MainMenuLayout& layout, int rightMargin, int width);
static bool mainMenuShouldEnableOverlayBackground(const MainMenuLayout& layout);
static void mainMenuDrawBuildInfo(const MainMenuLayout& layout, const MainMenuOffsets& offsets);
static bool mainMenuCreateButtons(const MainMenuLayout& layout, const MainMenuOffsets& offsets);
static void mainMenuDrawButtonLabels(const MainMenuLayout& layout, const MainMenuOffsets& offsets);
static bool mainMenuWindowIsOverlayActive();
static void mainMenuWindowEnterOverlay();
static void mainMenuWindowLeaveOverlay();
static void mainMenuWindowShowOverlayDim();
static void mainMenuComputeAspectFit(int srcWidth, int srcHeight, int& outX, int& outY, int& outWidth, int& outHeight)
{
@@ -374,13 +352,6 @@ static int mainMenuGetAnchoredRightX(const MainMenuLayout& layout, int rightMarg
return layout.backgroundX + layout.backgroundWidth - rightMargin - width;
}
static bool mainMenuShouldEnableOverlayBackground(const MainMenuLayout& layout)
{
return settings.ui.main_menu_overlay_subscreens
&& (layout.backgroundWidth > MAIN_MENU_OVERLAY_WINDOW_WIDTH
|| layout.backgroundHeight > MAIN_MENU_OVERLAY_WINDOW_HEIGHT);
}
static void mainMenuDrawBuildInfo(const MainMenuLayout& layout, const MainMenuOffsets& offsets)
{
MessageListItem msg;
@@ -538,7 +509,6 @@ int mainMenuWindowInit()
}
MainMenuLayout layout = mainMenuBuildLayout();
gMainMenuOverlayBackgroundEnabled = mainMenuShouldEnableOverlayBackground(layout);
MainMenuOffsets offsets = mainMenuReadOffsets(layout);
mainMenuDrawBackground(layout);
@@ -561,8 +531,6 @@ int mainMenuWindowInit()
gMainMenuWindowInitialized = true;
gMainMenuWindowHidden = true;
gMainMenuOverlayCount = 0;
mainMenuOverlayDimmedBackup.clear();
return 0;
}
@@ -578,7 +546,6 @@ void mainMenuWindowFree()
}
mainMenuScaledButtonData.clear();
mainMenuOverlayDimmedBackup.clear();
mainMenuButtonPanelFrmImage.unlock();
mainMenuButtonPressedFrmImage.unlock();
mainMenuButtonNormalFrmImage.unlock();
@@ -592,8 +559,6 @@ void mainMenuWindowFree()
gMainMenuWindow = -1;
gMainMenuWindowBuffer = nullptr;
gMainMenuWindowHidden = true;
gMainMenuOverlayCount = 0;
gMainMenuOverlayBackgroundEnabled = false;
}
// 0x481A00 main_menu_hide
@@ -616,8 +581,6 @@ void mainMenuWindowHide(bool animate)
windowHide(gMainMenuWindow);
touch_set_touchscreen_mode(false);
mainMenuOverlayDimmedBackup.clear();
gMainMenuOverlayCount = 0;
gMainMenuWindowHidden = true;
}
@@ -644,119 +607,6 @@ void mainMenuWindowUnhide(bool animate)
gMainMenuWindowHidden = false;
}
static void mainMenuWindowEnterOverlay()
{
if (!gMainMenuWindowInitialized || gMainMenuWindowHidden) {
return;
}
if (gMainMenuOverlayCount == 0) {
mainMenuSetButtonsEnabled(false);
}
gMainMenuOverlayCount += 1;
}
static void mainMenuWindowLeaveOverlay()
{
if (!gMainMenuWindowInitialized || gMainMenuWindowHidden) {
gMainMenuOverlayCount = 0;
return;
}
assert(gMainMenuOverlayCount > 0);
if (gMainMenuOverlayCount <= 0) {
gMainMenuOverlayCount = 0;
return;
}
gMainMenuOverlayCount -= 1;
if (gMainMenuOverlayCount == 0) {
mainMenuRemoveOverlayDim();
mainMenuSetButtonsEnabled(true);
touch_set_touchscreen_mode(true);
}
}
static bool mainMenuWindowIsOverlayActive()
{
return gMainMenuWindowInitialized && !gMainMenuWindowHidden && gMainMenuOverlayCount > 0;
}
static bool mainMenuWindowShouldUseOverlayBackground()
{
return gMainMenuOverlayBackgroundEnabled;
}
static void mainMenuWindowShowOverlayDim()
{
if (!mainMenuWindowIsOverlayActive() || !mainMenuOverlayDimmedBackup.empty()) {
return;
}
mainMenuApplyOverlayDim();
}
void mainMenuBeginSubscreen()
{
if (mainMenuWindowShouldUseOverlayBackground()) {
mainMenuWindowEnterOverlay();
return;
}
mainMenuWindowHide(true);
}
void mainMenuCancelSubscreen()
{
if (mainMenuWindowIsOverlayActive()) {
mainMenuWindowLeaveOverlay();
}
}
void mainMenuFinishSubscreen()
{
if (mainMenuWindowIsOverlayActive()) {
mainMenuWindowHide(false);
}
mainMenuWindowFree();
}
int mainMenuSubscreenWindowFlags(int defaultFlags, int overlayFlags)
{
return mainMenuWindowIsOverlayActive() ? overlayFlags : defaultFlags;
}
void mainMenuShowSubscreen(bool animate)
{
if (mainMenuWindowIsOverlayActive()) {
renderPresent();
mainMenuWindowShowOverlayDim();
} else if (animate) {
colorPaletteLoad("color.pal");
paletteFadeTo(_cmap);
}
}
void mainMenuRestoreAfterSubscreen(bool animate)
{
if (!animate || mainMenuWindowIsOverlayActive()) {
return;
}
paletteFadeTo(gPaletteBlack);
}
void mainMenuFadeOutAfterSubscreen(bool animate)
{
if (!animate) {
return;
}
paletteFadeTo(gPaletteBlack);
}
// 0x481AA8 main_menu_is_enabled
int _main_menu_is_enabled()
{
@@ -872,75 +722,4 @@ static void main_menu_play_sound(const char* fileName)
soundPlayFile(fileName);
}
static void mainMenuSetButtonsEnabled(bool enabled)
{
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
if (gMainMenuButtons[index] == -1) {
continue;
}
if (enabled) {
buttonEnable(gMainMenuButtons[index]);
} else {
buttonDisable(gMainMenuButtons[index]);
}
}
}
static void mainMenuApplyOverlayDim()
{
if (gMainMenuWindow == -1 || gMainMenuWindowBuffer == nullptr) {
return;
}
int width = windowGetWidth(gMainMenuWindow);
int height = windowGetHeight(gMainMenuWindow);
int size = width * height;
mainMenuOverlayDimmedBackup.assign(gMainMenuWindowBuffer, gMainMenuWindowBuffer + size);
mainMenuAnimateOverlayDim(MAIN_MENU_OVERLAY_DIM_CLEAR_INTENSITY, MAIN_MENU_OVERLAY_DIM_TARGET_INTENSITY);
}
static void mainMenuRemoveOverlayDim()
{
if (gMainMenuWindow == -1 || gMainMenuWindowBuffer == nullptr || mainMenuOverlayDimmedBackup.empty()) {
return;
}
int width = windowGetWidth(gMainMenuWindow);
int height = windowGetHeight(gMainMenuWindow);
int size = width * height;
if (static_cast<int>(mainMenuOverlayDimmedBackup.size()) != size) {
mainMenuOverlayDimmedBackup.clear();
return;
}
mainMenuAnimateOverlayDim(MAIN_MENU_OVERLAY_DIM_TARGET_INTENSITY, MAIN_MENU_OVERLAY_DIM_CLEAR_INTENSITY);
memcpy(gMainMenuWindowBuffer, mainMenuOverlayDimmedBackup.data(), size);
mainMenuOverlayDimmedBackup.clear();
windowRefresh(gMainMenuWindow);
}
static void mainMenuSetOverlayDimIntensity(int intensity)
{
if (gMainMenuWindow == -1 || gMainMenuWindowBuffer == nullptr || mainMenuOverlayDimmedBackup.empty()) {
return;
}
int width = windowGetWidth(gMainMenuWindow);
int height = windowGetHeight(gMainMenuWindow);
_dark_trans_buf_to_buf(mainMenuOverlayDimmedBackup.data(), width, height, width, gMainMenuWindowBuffer, 0, 0, width, intensity);
windowRefresh(gMainMenuWindow);
renderPresent();
}
static void mainMenuAnimateOverlayDim(int startIntensity, int endIntensity)
{
for (int step = 0; step < MAIN_MENU_OVERLAY_DIM_ANIMATION_STEPS; step++) {
int intensity = startIntensity + (endIntensity - startIntensity) * (step + 1) / MAIN_MENU_OVERLAY_DIM_ANIMATION_STEPS;
mainMenuSetOverlayDimIntensity(intensity);
delay_ms(MAIN_MENU_OVERLAY_DIM_FRAME_DELAY);
}
}
} // namespace fallout
-7
View File
@@ -20,13 +20,6 @@ int mainMenuWindowInit();
void mainMenuWindowFree();
void mainMenuWindowHide(bool animate);
void mainMenuWindowUnhide(bool animate);
void mainMenuBeginSubscreen();
void mainMenuCancelSubscreen();
void mainMenuFinishSubscreen();
int mainMenuSubscreenWindowFlags(int defaultFlags, int overlayFlags);
void mainMenuShowSubscreen(bool animate);
void mainMenuRestoreAfterSubscreen(bool animate);
void mainMenuFadeOutAfterSubscreen(bool animate);
int _main_menu_is_enabled();
int mainMenuWindowHandleEvents();
void mainMenuRequestExit();
+49 -189
View File
@@ -1,6 +1,5 @@
#include "platform_compat.h"
#include <string.h>
#include <filesystem>
#ifdef _WIN32
#include <direct.h>
@@ -14,17 +13,6 @@
#include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#ifdef _WIN64
#include <timeapi.h>
#else
#include <mmsystem.h>
#endif
#else
#include <chrono>
#endif
#include <SDL.h>
namespace fallout {
@@ -69,138 +57,46 @@ char* compat_itoa(int value, char* buffer, int radix)
void compat_splitpath(const char* path, char* drive, char* dir, char* fname, char* ext)
{
#ifdef _WIN32
_splitpath(path, drive, dir, fname, ext);
#else
const char* driveStart = path;
const char* pathAfterDrive = path;
if (pathAfterDrive[0] != '\0'
&& pathAfterDrive[1] != '\0'
&& compatIsPathSeparator(pathAfterDrive[0])
&& compatIsPathSeparator(pathAfterDrive[1])) {
pathAfterDrive += 2;
while (*pathAfterDrive != '\0' && !compatIsPathSeparator(*pathAfterDrive) && *pathAfterDrive != '.') {
pathAfterDrive++;
}
}
std::filesystem::path fsPath(path);
if (drive != nullptr) {
size_t driveSize = pathAfterDrive - driveStart;
if (driveSize > COMPAT_MAX_DRIVE - 1) {
driveSize = COMPAT_MAX_DRIVE - 1;
}
strncpy(drive, driveStart, driveSize);
drive[driveSize] = '\0';
}
const char* fnameStart = pathAfterDrive;
for (const char* pch = pathAfterDrive; *pch != '\0'; pch++) {
if (compatIsPathSeparator(*pch)) {
fnameStart = pch + 1;
}
}
const char* end = pathAfterDrive + strlen(pathAfterDrive);
const char* extStart = end;
for (const char* pch = end; pch != fnameStart; pch--) {
if (pch[-1] == '.') {
extStart = pch - 1;
break;
}
strncpy(drive, fsPath.root_name().string().c_str(), COMPAT_MAX_DRIVE - 1);
}
if (dir != nullptr) {
size_t dirSize = fnameStart - pathAfterDrive;
if (dirSize > COMPAT_MAX_DIR - 1) {
dirSize = COMPAT_MAX_DIR - 1;
}
strncpy(dir, pathAfterDrive, dirSize);
dir[dirSize] = '\0';
strncpy(dir, fsPath.parent_path().string().c_str(), COMPAT_MAX_DIR - 1);
}
if (fname != nullptr) {
size_t fileNameSize = extStart - fnameStart;
if (fileNameSize > COMPAT_MAX_FNAME - 1) {
fileNameSize = COMPAT_MAX_FNAME - 1;
}
strncpy(fname, fnameStart, fileNameSize);
fname[fileNameSize] = '\0';
strncpy(fname, fsPath.stem().string().c_str(), COMPAT_MAX_FNAME - 1);
}
if (ext != nullptr) {
size_t extSize = end - extStart;
if (extSize > COMPAT_MAX_EXT - 1) {
extSize = COMPAT_MAX_EXT - 1;
}
strncpy(ext, extStart, extSize);
ext[extSize] = '\0';
strncpy(ext, fsPath.extension().string().c_str(), COMPAT_MAX_EXT - 1);
}
#endif
}
void compat_makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext)
{
#ifdef _WIN32
_makepath(path, drive, dir, fname, ext);
#else
path[0] = '\0';
std::filesystem::path fsPath;
if (drive != nullptr) {
if (*drive != '\0') {
strcpy(path, drive);
path = strchr(path, '\0');
if (compatIsPathSeparator(path[-1])) {
path--;
} else {
*path = '/';
}
}
if (drive != nullptr && *drive != '\0') {
fsPath /= drive;
}
if (dir != nullptr) {
if (*dir != '\0') {
if (!compatIsPathSeparator(*dir) && compatIsPathSeparator(*path)) {
path++;
}
strcpy(path, dir);
path = strchr(path, '\0');
if (compatIsPathSeparator(path[-1])) {
path--;
} else {
*path = '/';
}
}
if (dir != nullptr && *dir != '\0') {
fsPath /= dir;
}
if (fname != nullptr && *fname != '\0') {
if (!compatIsPathSeparator(*fname) && compatIsPathSeparator(*path)) {
path++;
}
strcpy(path, fname);
path = strchr(path, '\0');
} else {
if (compatIsPathSeparator(*path)) {
path++;
}
fsPath /= fname;
}
if (ext != nullptr) {
if (*ext != '\0') {
if (*ext != '.') {
*path++ = '.';
}
strcpy(path, ext);
path = strchr(path, '\0');
}
if (ext != nullptr && *ext != '\0') {
fsPath += ext;
}
*path = '\0';
#endif
strncpy(path, fsPath.string().c_str(), COMPAT_MAX_PATH - 1);
}
long compat_tell(int fd)
@@ -208,100 +104,48 @@ long compat_tell(int fd)
return lseek(fd, 0, SEEK_CUR);
}
long compat_filelength(int fd)
long compat_filelength(const char* path)
{
long originalOffset = lseek(fd, 0, SEEK_CUR);
lseek(fd, 0, SEEK_SET);
long filesize = lseek(fd, 0, SEEK_END);
lseek(fd, originalOffset, SEEK_SET);
return filesize;
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
return std::filesystem::file_size(nativePath);
}
int compat_mkdir(const char* path)
{
std::error_code ec;
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
#ifdef _WIN32
return mkdir(nativePath);
#else
return mkdir(nativePath, 0755);
#endif
std::filesystem::create_directory(nativePath, ec);
return ec.value();
}
int compat_mkdir_recursive(const char* path)
{
char drive[COMPAT_MAX_DRIVE];
compat_splitpath(path, drive, nullptr, nullptr, nullptr);
char pathCopy[COMPAT_MAX_PATH];
strcpy(pathCopy, path);
// Skip drive root (e.g. "C:\\" or leading "/") to avoid mkdir("") or mkdir("C:").
char* sep = pathCopy + strlen(drive);
if (*sep == '\\' || *sep == '/') sep++;
for (; *sep != '\0'; sep++) {
if (*sep == '\\' || *sep == '/') {
char saved = *sep;
*sep = '\0';
if (compat_mkdir(pathCopy) < 0) {
break;
}
*sep = saved;
}
}
return compat_mkdir(path);
std::error_code ec;
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
std::filesystem::create_directories(nativePath, ec);
return ec.value();
}
bool compat_is_dir(const char* path)
{
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
#ifdef _WIN32
struct _stat info;
if (_stat(nativePath, &info) != 0) {
return false;
}
return (info.st_mode & _S_IFDIR) != 0;
#else
struct stat info;
if (stat(nativePath, &info) != 0) {
return false;
}
return S_ISDIR(info.st_mode);
#endif
return std::filesystem::is_directory(nativePath);
}
bool compat_file_exists(const char* filePath)
{
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, filePath);
#ifdef _WIN32
struct _stat info;
if (_stat(nativePath, &info) != 0) {
return false;
}
return (info.st_mode & _S_IFDIR) == 0;
#else
struct stat info;
if (stat(nativePath, &info) != 0) {
return false;
}
return !S_ISDIR(info.st_mode);
#endif
return std::filesystem::exists(nativePath);
}
unsigned int compat_timeGetTime()
{
#ifdef _WIN32
return timeGetTime();
#else
static auto start = std::chrono::steady_clock::now();
auto now = std::chrono::steady_clock::now();
return static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count());
#endif
return SDL_GetTicks64();
}
FILE* compat_fopen(const char* path, const char* mode)
@@ -350,20 +194,25 @@ char* compat_gzgets(gzFile stream, char* buffer, int maxCount)
int compat_remove(const char* path)
{
std::error_code err;
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
return remove(nativePath);
std::filesystem::remove(nativePath, err);
return err.value();
}
int compat_rename(const char* oldFileName, const char* newFileName)
{
std::error_code err;
char nativeOldFileName[COMPAT_MAX_PATH];
compat_prepare_native_path(nativeOldFileName, oldFileName);
char nativeNewFileName[COMPAT_MAX_PATH];
compat_prepare_native_path(nativeNewFileName, newFileName);
return rename(nativeOldFileName, nativeNewFileName);
std::filesystem::rename(nativeOldFileName, nativeNewFileName, err);
return err.value();
}
void compat_windows_path_to_native(char* path)
@@ -393,6 +242,15 @@ void compat_resolve_path(char* path)
}
while (dir != nullptr) {
while (*pch == '/') {
pch++;
}
if (*pch == '\0') {
closedir(dir);
break;
}
char* sep = strchr(pch, '/');
size_t length;
if (sep != nullptr) {
@@ -437,7 +295,9 @@ int compat_access(const char* path, int mode)
{
char nativePath[COMPAT_MAX_PATH];
compat_prepare_native_path(nativePath, path);
return access(nativePath, mode);
std::filesystem::perms targetPrms = static_cast<std::filesystem::perms>(mode);
std::filesystem::perms fsPrms = std::filesystem::status(nativePath).permissions();
return targetPrms == fsPrms;
}
char* compat_strdup(const char* string)
+4 -1
View File
@@ -1,8 +1,11 @@
#ifndef PLATFORM_COMPAT_H
#define PLATFORM_COMPAT_H
#include <errno.h>
#include <filesystem>
#include <stddef.h>
#include <stdio.h>
#include <string>
#include <zlib.h>
@@ -30,7 +33,7 @@ char* compat_itoa(int value, char* buffer, int radix);
void compat_splitpath(const char* path, char* drive, char* dir, char* fname, char* ext);
void compat_makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext);
long compat_tell(int fileHandle);
long compat_filelength(int fd);
long compat_filelength(const char* path);
int compat_mkdir(const char* path);
int compat_mkdir_recursive(const char* path);
bool compat_is_dir(const char* path);
+8 -6
View File
@@ -15,7 +15,6 @@
#include "graph_lib.h"
#include "input.h"
#include "kb.h"
#include "mainmenu.h"
#include "message.h"
#include "mouse.h"
#include "palette.h"
@@ -1010,14 +1009,12 @@ static int preferencesWindowInit()
int preferencesWindowX = (screenGetWidth() - PREFERENCES_WINDOW_WIDTH) / 2;
int preferencesWindowY = (screenGetHeight() - PREFERENCES_WINDOW_HEIGHT) / 2;
int preferencesWindowFlags = mainMenuSubscreenWindowFlags(WINDOW_MODAL | WINDOW_DONT_MOVE_TOP, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
gPreferencesWindow = windowCreate(preferencesWindowX,
preferencesWindowY,
PREFERENCES_WINDOW_WIDTH,
PREFERENCES_WINDOW_HEIGHT,
256,
preferencesWindowFlags);
WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
if (gPreferencesWindow == -1) {
for (i = 0; i < PREFERENCES_WINDOW_FRM_COUNT; i++) {
_preferencesFrmImages[i].unlock();
@@ -1236,7 +1233,10 @@ int doPreferences(bool animated)
touch_set_touchscreen_mode(true);
mainMenuShowSubscreen(animated);
if (animated) {
colorPaletteLoad("color.pal");
paletteFadeTo(_cmap);
}
int rc = -1;
while (rc == -1) {
@@ -1286,7 +1286,9 @@ int doPreferences(bool animated)
sharedFpsLimiter.throttle();
}
mainMenuRestoreAfterSubscreen(animated);
if (animated) {
paletteFadeTo(gPaletteBlack);
}
if (cursorWasHidden) {
mouseHideCursor();
-1
View File
@@ -152,7 +152,6 @@ void initSettingsRegistry(bool isMapper)
#define SECT ui
SETTING_P(main_menu_scale_mode, clamp(0, 2));
SETTING(in_game_menu_help);
SETTING(main_menu_overlay_subscreens);
SETTING(iface_bar_mode);
SETTING_P(iface_bar_width, clamp(640, 4320));
SETTING_P(iface_bar_side_art, clamp(0, 999));
-3
View File
@@ -45,9 +45,6 @@ struct UISettings {
// Show the Help option in the in-game options menu.
bool in_game_menu_help = true;
// Whether to keep the main menu visible behind 640x480 main-menu subwindows
// like load, options, and new game when the effective menu background is larger.
bool main_menu_overlay_subscreens = true;
// Should the game window stretch all the way to the bottom or sit at the top of the interface bar (default).
bool iface_bar_mode = false;
+6 -3
View File
@@ -919,7 +919,7 @@ const MetaruleInfo kMetarules[] = {
// {"unjam_lock", mf_unjam_lock, 1, 1, -1, {ARG_OBJECT}},
{ "unwield_slot", mf_unwield_slot, 2, 2, -1, { ARG_OBJECT, ARG_INT } },
{ "win_fill_color", mf_win_fill_color, 0, 5, -1, { ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT } },
{ "opcode_exists", mf_opcode_exists, 1, 1 },
{ "opcode_exists", mf_opcode_exists, 1, 1, 0, { ARG_INT } },
};
const std::size_t kMetarulesCount = sizeof(kMetarules) / sizeof(kMetarules[0]);
@@ -1707,12 +1707,15 @@ void mf_add_extra_msg_file(OpcodeContext& ctx)
void mf_opcode_exists(OpcodeContext& ctx)
{
constexpr int kOpcodeStart = RAW_VALUE_TYPE_OPCODE; // 0x8000
int opcode = ctx.arg(0).asInt();
int opcodeIndex = opcode & 0x3FFF;
if (opcodeIndex < 0 || opcodeIndex >= OPCODE_MAX_COUNT) {
if (opcode < kOpcodeStart || opcode >= kOpcodeStart + OPCODE_MAX_COUNT) {
ctx.setReturn(0);
return;
}
int opcodeIndex = opcode - kOpcodeStart;
auto opcodeHandler = gInterpreterOpcodeHandlers[opcodeIndex];
int opcodeExists = opcodeHandler != nullptr ? 1 : 0;
ctx.setReturn(opcodeExists);