Compare commits

...
16 changed files with 143 additions and 77 deletions
+3 -3
View File
@@ -105,13 +105,13 @@ docker run --rm -v $(pwd):/src emscripten/emsdk:3.1.74 sh -c 'git config --globa
## Configuration
The main configuration file is `fallout2.cfg`. There are several important settings you might need to adjust for your installation. Depending on your Fallout distribution main game assets `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder might be either all lowercased, or all uppercased. You can either update `master_dat`, `critter_dat`, `master_patches` and `critter_patches` settings to match your file names, or rename files to match entries in your `fallout2.cfg`.
The main configuration file is `fallout2-ce.cfg`. There are several important settings you might need to adjust for your installation. Depending on your Fallout distribution main game assets `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder might be either all lowercased, or all uppercased. You can either update `master_dat`, `critter_dat`, `master_patches` and `critter_patches` settings to match your file names, or rename files to match entries in your `fallout2-ce.cfg`.
The `sound` folder (with `music` folder inside) might be located either in `data` folder, or be in the Fallout folder. Update `music_path1` setting to match your hierarchy, usually it's `data/sound/music/` or `sound/music/`. Make sure it matches your path exactly (so it might be `SOUND/MUSIC/` if you've installed Fallout from CD). Music files themselves (with `ACM` extension) should be all uppercased, regardless of `sound` and `music` folders.
Additional settings for screen resolution, UI customization, and map options are now integrated into the main `fallout2.cfg` file (previously part of `f2_res.ini` from Mash's HRP). When Fallout 2 CE starts, if it detects an existing `f2_res.ini` file, it automatically migrates these settings into `fallout2.cfg`. After migration, `fallout2.cfg` becomes the single source of truth for this configuration.
Additional settings for screen resolution, UI customization, and map options are now integrated into the main `fallout2-ce.cfg` file (previously part of `f2_res.ini` from Mash's HRP). When Fallout 2 CE starts, if it detects an existing `f2_res.ini` file, it automatically migrates these settings into main config. After that, `fallout2-ce.cfg` becomes the single source of truth for this configuration.
Here are some important settings in `fallout2.cfg` under the `[screen]` and `[ui]` sections. See [the example config](https://github.com/fallout2-ce/fallout2-ce/tree/refs/heads/main/files/fallout2.cfg) for a full list of settings.
Here are some important settings in `fallout2-ce.cfg` under the `[screen]` and `[ui]` sections. See [the example config](https://github.com/fallout2-ce/fallout2-ce/tree/refs/heads/main/files/ce.cfg) for a full list of settings.
```ini
[screen]
+1 -1
View File
@@ -10,7 +10,7 @@ Settings previously read from `ddraw.ini` have been moved into standard CE confi
Most settings that control game behavior (premade characters, extra message files, combat tweaks, worldmap, etc.) have been moved into [`<DAT>/config/game.cfg`](files/ce.dat/config/game.cfg), which is a content-mod config file intended to be overridden by mods. See that file for the full list with descriptions.
The following settings were moved into [`fallout2.cfg`](files/fallout2.cfg) instead:
The following settings were moved into [`fallout2-ce.cfg`](files/ce.cfg) instead:
| ddraw.ini section | ddraw.ini key | fallout2.cfg section | fallout2.cfg key |
| --- | --- | --- | --- |
+51 -21
View File
@@ -1,11 +1,11 @@
#include "debug.h"
#include <SDL.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL.h>
#include <string>
#include "memory.h"
#include "platform_compat.h"
@@ -15,11 +15,17 @@ namespace fallout {
static int _debug_puts(char* string);
static void _debug_clear();
static int _debug_mono(char* string);
static int _debug_log(char* string);
static int _debug_screen(char* string);
static int _debug_mono(const char* string);
static int _debug_log(const char* string);
static int _debug_screen(const char* string);
static void _debug_putc(int ch);
static void _debug_scroll();
static void debugFlushBuffer();
// Messages logged before any debug proc is registered are held here and
// flushed when the first proc is registered.
static std::string gDebugBuffer;
static constexpr size_t kDebugBufferMaxSize = 64 * 1024;
// 0x51DEF8
static FILE* _fd = nullptr;
@@ -35,6 +41,10 @@ static DebugPrintProc* gDebugPrintProc = nullptr;
void debugModeInit(const char* debugMode)
{
if (debugMode == nullptr) {
return;
}
// CE: Handle debug mode (exactly as seen in `mapper2.exe`).
if (compat_stricmp(debugMode, "environment") == 0) {
_debug_register_env();
@@ -47,6 +57,10 @@ void debugModeInit(const char* debugMode)
} else if (compat_stricmp(debugMode, "gnw") == 0) {
_debug_register_func(_win_debug);
}
if (gDebugPrintProc == nullptr) {
gDebugBuffer.clear();
}
}
// 0x4C6CD0
@@ -66,6 +80,7 @@ void _debug_register_mono()
gDebugPrintProc = _debug_mono;
_debug_clear();
debugFlushBuffer();
}
}
@@ -79,6 +94,7 @@ void _debug_register_log(const char* fileName, const char* mode)
_fd = compat_fopen(fileName, mode);
gDebugPrintProc = _debug_log;
debugFlushBuffer();
}
}
@@ -92,6 +108,7 @@ void _debug_register_screen()
}
gDebugPrintProc = _debug_screen;
debugFlushBuffer();
}
}
@@ -137,6 +154,7 @@ void _debug_register_func(DebugPrintProc* proc)
}
gDebugPrintProc = proc;
debugFlushBuffer();
}
}
@@ -146,25 +164,37 @@ int debugPrint(const char* format, ...)
va_list args;
va_start(args, format);
int rc;
if (gDebugPrintProc != nullptr) {
char string[260];
vsnprintf(string, sizeof(string), format, args);
rc = gDebugPrintProc(string);
} else {
#ifndef NDEBUG
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args);
#endif
rc = -1;
}
char string[260];
int len = vsnprintf(string, sizeof(string), format, args);
va_end(args);
int rc;
if (gDebugPrintProc != nullptr) {
rc = gDebugPrintProc(string);
} else {
if (len > 0 && gDebugBuffer.size() + len <= kDebugBufferMaxSize) {
gDebugBuffer += string;
}
rc = -1;
}
#ifndef NDEBUG
SDL_Log("%s", string);
#endif
return rc;
}
static void debugFlushBuffer()
{
if (gDebugBuffer.empty() || gDebugPrintProc == nullptr) {
return;
}
gDebugPrintProc(gDebugBuffer.c_str());
gDebugBuffer.clear();
}
// 0x4C6F94
static int _debug_puts(char* string)
{
@@ -203,7 +233,7 @@ static void _debug_clear()
}
// 0x4C7004
static int _debug_mono(char* string)
static int _debug_mono(const char* string)
{
if (gDebugPrintProc == _debug_mono) {
while (*string != '\0') {
@@ -215,7 +245,7 @@ static int _debug_mono(char* string)
}
// 0x4C7028
static int _debug_log(char* string)
static int _debug_log(const char* string)
{
if (gDebugPrintProc == _debug_log) {
if (_fd == nullptr) {
@@ -235,7 +265,7 @@ static int _debug_log(char* string)
}
// 0x4C7068
static int _debug_screen(char* string)
static int _debug_screen(const char* string)
{
if (gDebugPrintProc == _debug_screen) {
printf("%s", string);
+1 -1
View File
@@ -3,7 +3,7 @@
namespace fallout {
typedef int(DebugPrintProc)(char* string);
typedef int(DebugPrintProc)(const char* string);
void debugModeInit(const char* debugMode);
void _GNW_debug_init();
+2
View File
@@ -152,6 +152,8 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
settingsInit(isMapper, argc, argv);
debugModeInit(settings.debug.mode.c_str());
gIsMapper = isMapper;
if (gameDbInit() == -1) {
+31 -39
View File
@@ -26,7 +26,7 @@ constexpr char kMapperConfigFileName[] = "mapper2.cfg";
// 0x5186D0
bool gGameConfigInitialized = false;
// fallout2.cfg
// ce.cfg
//
// 0x58E950
Config gGameConfig;
@@ -47,9 +47,9 @@ char gGameConfigFilePath[COMPAT_MAX_PATH];
// additional check for [argc], so it will crash if you pass NULL, or an empty
// array into [argv].
//
// The executable path from [argv] is used resolve path to `fallout2.cfg`,
// The executable path from [argv] is used resolve path to `<executable>ce.cfg`,
// which should be in the same folder. This function provide defaults if
// `fallout2.cfg` is not present, or cannot be read for any reason.
// file is not present, or cannot be read for any reason.
//
// Finally, this function merges key-value pairs from [argv] if any, see
// [configParseCommandLineArguments] for expected format.
@@ -86,53 +86,45 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
char* customConfigFileName = nullptr;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONFIG_FILE, &customConfigFileName);
const char* configFileName = customConfigFileName != nullptr && *customConfigFileName != '\0'
? customConfigFileName
: kDefaultGameConfigFileName;
// CE: Derive config file name from executable name.
char exeDrive[COMPAT_MAX_DRIVE];
char exeDir[COMPAT_MAX_DIR];
char exeFname[COMPAT_MAX_FNAME];
compat_splitpath(argv[0], exeDrive, exeDir, exeFname, nullptr);
// Make `fallout2.cfg` file path.
char* executable = argv[0];
char* ch = strrchr(executable, '\\');
if (ch != nullptr) {
*ch = '\0';
if (isMapper) {
snprintf(gGameConfigFilePath,
sizeof(gGameConfigFilePath),
"%s\\%s",
executable,
kMapperConfigFileName);
} else {
snprintf(gGameConfigFilePath,
sizeof(gGameConfigFilePath),
"%s\\%s",
executable,
configFileName);
}
*ch = '\\';
} else {
if (isMapper) {
strcpy(gGameConfigFilePath, kMapperConfigFileName);
} else {
strcpy(gGameConfigFilePath, configFileName);
}
}
char derivedConfigFileName[COMPAT_MAX_FNAME + 5];
snprintf(derivedConfigFileName, sizeof(derivedConfigFileName), "%s.cfg", exeFname);
const char* defaultConfigFileName = isMapper ? kMapperConfigFileName : kDefaultGameConfigFileName;
const bool hasCustomConfigFileName = customConfigFileName != nullptr && *customConfigFileName != '\0';
const char* configFileName = hasCustomConfigFileName ? customConfigFileName : derivedConfigFileName;
compat_makepath(gGameConfigFilePath, exeDrive, exeDir, configFileName, nullptr);
const bool usingDerivedConfig = !hasCustomConfigFileName
&& compat_stricmp(derivedConfigFileName, defaultConfigFileName) != 0;
configRead(&gGameConfig, gGameConfigFilePath, false);
// Init debug mode ASAP to catch early debug messages.
char* debugMode;
configGetString(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, &debugMode);
debugModeInit(debugMode);
debugPrint("Game config loaded from %s.\n", gGameConfigFilePath);
if (usingDerivedConfig) {
char defaultConfigFilePath[COMPAT_MAX_PATH];
compat_makepath(defaultConfigFilePath, exeDrive, exeDir, defaultConfigFileName, nullptr);
if (gameConfigMigrateFromDefaultConfig(defaultConfigFilePath, &gGameConfig)) {
debugPrint("Migrated settings from %s.\n", defaultConfigFileName);
configWriteEx(&gGameConfig, gGameConfigFilePath, CONFIG_RETAIN_ALL);
}
}
if (!isMapper && gameConfigMigrateFromF2Res(gGameConfigFilePath, &gGameConfig)) {
debugPrint("Migrated settings from f2_res.ini.\n");
configWriteEx(&gGameConfig, gGameConfigFilePath, CONFIG_RETAIN_ALL);
}
// Add key-values from command line, which overrides both defaults and
// whatever was loaded from `fallout2.cfg`.
// whatever was loaded from cfg.
configParseCommandLineArguments(&gGameConfig, argc, argv);
// Writes default values to config, skipping keys that were already loaded.
@@ -151,7 +143,7 @@ EM_ASYNC_JS(void, do_save_idbfs_gameconfig, (), {
// clang-format on
#endif
// Saves game config into `fallout2.cfg`.
// Saves game config into cfg.
//
// 0x444C14
bool gameConfigSave()
+1
View File
@@ -10,6 +10,7 @@ namespace fallout {
#define GAME_CONFIG_SCREEN_KEY "screen"
#define GAME_CONFIG_UI_KEY "ui"
#define GAME_CONFIG_SOUND_KEY "sound"
#define GAME_CONFIG_META_KEY "meta"
#define GAME_CONFIG_MASTER_DAT_KEY "master_dat"
#define GAME_CONFIG_MASTER_PATCHES_KEY "master_patches"
+42 -2
View File
@@ -88,9 +88,9 @@ namespace {
} // namespace
// Migrate settings F2_RES.INI to fallout2.cfg
// Migrate settings F2_RES.INI to ce.cfg
//
// Only happens a single time, after which fallout2.cfg is the source of truth
// Only happens a single time, after which game config is the source of truth
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig)
{
if (gameConfigFilePath == nullptr || gameConfig == nullptr) {
@@ -129,6 +129,46 @@ bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConf
return migrated;
}
// Imports all key-value pairs from defaultConfigFilePath into gameConfig,
// overwriting any existing values. Runs once, gated by [meta] migrated=1.
bool gameConfigMigrateFromDefaultConfig(const char* defaultConfigFilePath, Config* gameConfig)
{
constexpr char kMigratedKey[] = "migrated";
if (defaultConfigFilePath == nullptr || gameConfig == nullptr) {
return false;
}
bool migrated;
if (configGetBool(gameConfig, GAME_CONFIG_META_KEY, kMigratedKey, &migrated) && migrated) {
return false;
}
Config defaultConfig;
if (!configInit(&defaultConfig)) {
return false;
}
migrated = false;
if (configRead(&defaultConfig, defaultConfigFilePath, false)) {
for (int i = 0; i < defaultConfig.entriesLength; i++) {
const char* section = defaultConfig.entries[i].key;
ConfigSection* srcSection = static_cast<ConfigSection*>(defaultConfig.entries[i].value);
for (int j = 0; j < srcSection->entriesLength; j++) {
const char* key = srcSection->entries[j].key;
const char* value = *static_cast<char**>(srcSection->entries[j].value);
configSetString(gameConfig, section, key, value);
migrated = true;
}
}
}
if (migrated) {
configSetBool(gameConfig, GAME_CONFIG_META_KEY, kMigratedKey, true);
}
configFree(&defaultConfig);
return migrated;
}
namespace {
constexpr char kSfallMisc[] = "Misc";
+1
View File
@@ -6,6 +6,7 @@
namespace fallout {
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig);
bool gameConfigMigrateFromDefaultConfig(const char* defaultConfigFilePath, Config* gameConfig);
void contentConfigTryMigrateFromSfall(const char* contentConfigPath);
} // namespace fallout
+4 -4
View File
@@ -28,7 +28,7 @@ typedef struct ProgramListNode {
static unsigned int _defaultTimerFunc();
static unsigned int getInterpreterTime();
static char* defaultFilename(char* path);
static int outputString(char* string);
static int outputString(const char* string);
static int checkWait(Program* program);
static char* programGetCurrentProcedureName(Program* program);
opcode_t stackReadInt16(unsigned char* data, int pos);
@@ -150,7 +150,7 @@ static unsigned int interpreterTimerTick = 1000;
static char* (*interpreterFilenameMangler)(char*) = defaultFilename;
// 0x51904C
static int (*interpreterOutputFunc)(char*) = outputString;
static int (*interpreterOutputFunc)(const char*) = outputString;
// 0x519050
static int interpreterCpuBurstSize = 10;
@@ -195,7 +195,7 @@ char* _interpretMangleName(char* s)
}
// 0x4670C0 (unused)
static int outputString(char* /*string*/)
static int outputString(const char*)
{
return 1;
}
@@ -207,7 +207,7 @@ static int checkWait(Program* program)
}
// 0x4670FC
void _interpretOutputFunc(int (*func)(char*))
void _interpretOutputFunc(int (*func)(const char*))
{
interpreterOutputFunc = func;
}
+1 -1
View File
@@ -216,7 +216,7 @@ extern OpcodeHandler* gInterpreterOpcodeHandlers[OPCODE_MAX_COUNT];
extern int _TimeOut;
char* _interpretMangleName(char* s);
void _interpretOutputFunc(int (*func)(char*));
void _interpretOutputFunc(int (*func)(const char*));
int _interpretOutput(const char* format, ...);
[[noreturn]] void programFatalError(const char* str, ...);
void programPrintError(const char* format, ...);
+1 -1
View File
@@ -857,7 +857,7 @@ int scriptWindowCreate(const char* windowName, int x, int y, int width, int heig
}
// 0x4B80A4
int scriptWindowOutput(char* string)
int scriptWindowOutput(const char* string)
{
if (gCurrentManagedWindowIndex == -1) {
return 0;
+1 -1
View File
@@ -72,7 +72,7 @@ bool scriptWindowDelete(const char* windowName);
int scriptWindowResize(const char* windowName, int x, int y, int width, int height);
int scriptWindowScale(const char* windowName, int x, int y, int width, int height);
int scriptWindowCreate(const char* windowName, int x, int y, int width, int height, int a6, int flags);
int scriptWindowOutput(char* string);
int scriptWindowOutput(const char* string);
bool scriptWindowGotoXY(int x, int y);
bool scriptWindowSelectId(int index);
int scriptWindowSelect(const char* windowName);
+2 -2
View File
@@ -807,7 +807,7 @@ int _create_pull_down(char** stringList, int stringListLength, int x, int y, int
}
// 0x4DC30C
int _win_debug(char* string)
int _win_debug(const char* string)
{
if (!gWindowSystemInitialized) {
return -1;
@@ -895,7 +895,7 @@ int _win_debug(char* string)
char temp[2];
temp[1] = '\0';
char* pch = string;
const char* pch = string;
while (*pch != '\0') {
int characterWidth = fontGetCharacterWidth(*pch);
if (*pch == '\n' || _currx + characterWidth > winWidth - 9) {
+1 -1
View File
@@ -20,7 +20,7 @@ int win_yes_no(const char* question, int x, int y, int color);
int _win_msg(const char* string, int x, int y, int color);
int _win_pull_down(char** items, int itemsLength, int x, int y, int color);
int _create_pull_down(char** stringList, int stringListLength, int x, int y, int foregroundColor, int backgroundColor, Rect* rect);
int _win_debug(char* string);
int _win_debug(const char* string);
void _win_debug_delete(int btn, int keyCode);
int _win_register_menu_bar(int win, int x, int y, int width, int height, int foregroundColor, int backgroundColor);
int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int foregroundColor, int backgroundColor);