mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e3cd38a8f | ||
|
|
50d6b14ff3 | ||
|
|
4c53a5b85f |
@@ -399,3 +399,7 @@ FodyWeavers.xsd
|
||||
# versioning header
|
||||
src/platform/git_version.h
|
||||
CMakeUserPresets.json
|
||||
|
||||
# Local configs for AI agents
|
||||
.aider*
|
||||
.gemini
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Fallout 2 Community Edition - Gemini Instructions
|
||||
|
||||
## Project Overview
|
||||
Fallout 2 Community Edition is a re-implementation of Fallout 2. It is written in C++ and uses CMake as its build system.
|
||||
|
||||
## Project Rules
|
||||
- Only search for source code and symbols inside the `src/` directory.
|
||||
|
||||
## Coding Standards & Conventions
|
||||
- **Language**: C++17.
|
||||
- **Style**: Follow WebKit style as defined in `.clang-format`.
|
||||
- Use `clang-format` before committing any changes.
|
||||
- Short `if` statements without `else` can be on a single line.
|
||||
- Fix namespace comments.
|
||||
- **File Naming**:
|
||||
- Source files: `.cc`
|
||||
- Header files: `.h`
|
||||
- **Architectural Constraint**:
|
||||
- Don't use complicated and rarely used C++ features, unless they are well encapsulated within reusable code.
|
||||
- Avoid large-scale refactorings. The project aims to reconcile changes from the Reference Edition, and major structural changes make this difficult.
|
||||
- **Integration Priority**: Integrating features and fixes from Sfall is a top priority.
|
||||
|
||||
## Build System (CMake)
|
||||
- **Version**: Requires CMake 3.18 or higher.
|
||||
- **Dependencies**: Uses vendored third-party libraries by default (`FALLOUT_VENDORED=ON`).
|
||||
- **Target**: The main executable is `fallout2-ce`.
|
||||
- **Platforms**: Supports Windows, Linux, macOS, Android, iOS, and Emscripten (WebAssembly).
|
||||
|
||||
## Project Structure
|
||||
- `src/`: Contains all core game logic and engine implementation.
|
||||
- `third_party/`: Vendored dependencies (zlib, SDL2, etc.).
|
||||
- `os/`: Platform-specific assets and configuration (icons, plists, etc.).
|
||||
- `cmake/`: Custom CMake scripts.
|
||||
- `files/`: Default configuration files and data assets.
|
||||
- `sfall_testing/`: SSL scripts for testing Sfall-related functionality.
|
||||
|
||||
## Tool Usage
|
||||
- **Prioritize CLion MCP**: Always use the CLion MCP tools (e.g., `mcp_clion_search_symbols`, `mcp_clion_get_symbol_info`) for finding code definitions and symbols instead of performing manual text-based searches with `grep_search` or `glob`. Use manual text searches only when symbol-based search is not applicable (e.g., searching for non-code text or specific patterns).
|
||||
|
||||
## Development Workflow
|
||||
1. **Research**: Understand how a feature was implemented in the original engine or Sfall before attempting to port or fix it.
|
||||
2. **Strategy**: Maintain compatibility with original game data and savegames.
|
||||
3. **Execution**: Apply surgical changes to `src/`.
|
||||
4. **Validation**: Ensure changes compile across platforms if possible, or at least don't break the build for the current platform.
|
||||
@@ -0,0 +1,15 @@
|
||||
[main]
|
||||
RadiationEffectCount=8
|
||||
RadiationLevelCount=6
|
||||
RadiationEffectPrimaryStatCount=6
|
||||
RadiationThresholds=99,199,399,599,999
|
||||
RadiationEnduranceModifiers=2,0,-2,-4,-6,-8
|
||||
RadiationEffectStats=0,1,2,3,4,5,6,7
|
||||
|
||||
[RadiationEffectPenalties]
|
||||
Level0=0,0,0,0,0,0,0,0
|
||||
Level1=-1,0,0,0,0,0,0,0
|
||||
Level2=-1,0,0,0,0,-1,0,-3
|
||||
Level3=-2,0,-1,0,0,-2,-5,-5
|
||||
Level4=-4,-3,-3,-3,-1,-5,-15,-10
|
||||
Level5=-6,-5,-5,-5,-3,-6,-20,-10
|
||||
+67
-92
@@ -1,3 +1,4 @@
|
||||
#include "config.h"
|
||||
#include "critter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -37,37 +38,25 @@ namespace fallout {
|
||||
#define DUDE_NAME_MAX_LENGTH (32)
|
||||
|
||||
// The number of effects caused by radiation.
|
||||
//
|
||||
// A radiation effect is an identifier and does not have it's own name. It's
|
||||
// stat is specified in [gRadiationEffectStats], and it's amount is specified
|
||||
// in [gRadiationEffectPenalties] for every [RadiationLevel].
|
||||
#define RADIATION_EFFECT_COUNT 8
|
||||
static int gRadiationEffectCount = 8;
|
||||
|
||||
// Radiation levels.
|
||||
//
|
||||
// The names of levels are taken from Fallout 3, comments from Fallout 2.
|
||||
typedef enum RadiationLevel {
|
||||
// Very nauseous.
|
||||
RADIATION_LEVEL_NONE,
|
||||
// The number of radiation levels.
|
||||
static int gRadiationLevelCount = 6;
|
||||
|
||||
// Slightly fatigued.
|
||||
RADIATION_LEVEL_MINOR,
|
||||
// Radiation thresholds.
|
||||
static int* gRadiationThresholds = nullptr;
|
||||
|
||||
// Vomiting does not stop.
|
||||
RADIATION_LEVEL_ADVANCED,
|
||||
// Modifiers to endurance for performing radiation damage check.
|
||||
static int* gRadiationEnduranceModifiers = nullptr;
|
||||
|
||||
// Hair is falling out.
|
||||
RADIATION_LEVEL_CRITICAL,
|
||||
// List of stats affected by radiation.
|
||||
static int* gRadiationEffectStats = nullptr;
|
||||
|
||||
// Skin is falling off.
|
||||
RADIATION_LEVEL_DEADLY,
|
||||
// List of stat modifiers caused by radiation at different radiation levels.
|
||||
static int** gRadiationEffectPenalties = nullptr;
|
||||
|
||||
// Intense agony.
|
||||
RADIATION_LEVEL_FATAL,
|
||||
|
||||
// The number of radiation levels.
|
||||
RADIATION_LEVEL_COUNT,
|
||||
} RadiationLevel;
|
||||
// Denotes how many primary stats at the top of [gRadiationEffectStats] array.
|
||||
static int gRadiationEffectPrimaryStatCount = 6;
|
||||
|
||||
static int _get_rad_damage_level(Object* obj, void* data);
|
||||
static int critter_kill_count_clear();
|
||||
@@ -82,58 +71,6 @@ static char byte_501494[] = "";
|
||||
// 0x51833C
|
||||
static char* _name_critter = _aCorpse;
|
||||
|
||||
// Modifiers to endurance for performing radiation damage check.
|
||||
//
|
||||
// 0x518340
|
||||
static const int gRadiationEnduranceModifiers[RADIATION_LEVEL_COUNT] = {
|
||||
2,
|
||||
0,
|
||||
-2,
|
||||
-4,
|
||||
-6,
|
||||
-8,
|
||||
};
|
||||
|
||||
// List of stats affected by radiation.
|
||||
//
|
||||
// The values of this list specify stats that can be affected by radiation.
|
||||
// The amount of penalty to every stat (identified by index) is stored
|
||||
// separately in [gRadiationEffectPenalties] per radiation level.
|
||||
//
|
||||
// The order of stats is important - primary stats must be at the top. See
|
||||
// [RADIATION_EFFECT_PRIMARY_STAT_COUNT] for more info.
|
||||
//
|
||||
// 0x518358
|
||||
static const int gRadiationEffectStats[RADIATION_EFFECT_COUNT] = {
|
||||
STAT_STRENGTH,
|
||||
STAT_PERCEPTION,
|
||||
STAT_ENDURANCE,
|
||||
STAT_CHARISMA,
|
||||
STAT_INTELLIGENCE,
|
||||
STAT_AGILITY,
|
||||
STAT_CURRENT_HIT_POINTS,
|
||||
STAT_HEALING_RATE,
|
||||
};
|
||||
|
||||
// Denotes how many primary stats at the top of [gRadiationEffectStats] array.
|
||||
// These stats are used to determine if critter is alive after applying
|
||||
// radiation effects.
|
||||
#define RADIATION_EFFECT_PRIMARY_STAT_COUNT 6
|
||||
|
||||
// List of stat modifiers caused by radiation at different radiation levels.
|
||||
//
|
||||
// 0x518378
|
||||
static const int gRadiationEffectPenalties[RADIATION_LEVEL_COUNT][RADIATION_EFFECT_COUNT] = {
|
||||
// clang-format off
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ -1, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ -1, 0, 0, 0, 0, -1, 0, -3 },
|
||||
{ -2, 0, -1, 0, 0, -2, -5, -5 },
|
||||
{ -4, -3, -3, -3, -1, -5, -15, -10 },
|
||||
{ -6, -5, -5, -5, -3, -6, -20, -10 },
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// 0x518438
|
||||
static Object* _critterClearObj = nullptr;
|
||||
|
||||
@@ -160,6 +97,10 @@ static int oldRadLevel;
|
||||
// 0x42CF50
|
||||
int critterInit()
|
||||
{
|
||||
if (critterInitRadiationEffectPenalties() == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dudeResetName();
|
||||
|
||||
// NOTE: Uninline;
|
||||
@@ -183,6 +124,46 @@ int critterInit()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x42CF50
|
||||
int critterInitRadiationEffectPenalties()
|
||||
{
|
||||
Config config;
|
||||
if (!configInit(&config)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!configRead(&config, "data/radiation.txt", false)) {
|
||||
debugPrint("\nError: Could not load radiation.txt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!configGetInt(&config, "main", "RadiationEffectCount", &gRadiationEffectCount)) gRadiationEffectCount = 8;
|
||||
if (!configGetInt(&config, "main", "RadiationLevelCount", &gRadiationLevelCount)) gRadiationLevelCount = 6;
|
||||
if (!configGetInt(&config, "main", "RadiationEffectPrimaryStatCount", &gRadiationEffectPrimaryStatCount)) gRadiationEffectPrimaryStatCount = 6;
|
||||
|
||||
gRadiationThresholds = (int*)malloc(gRadiationLevelCount * sizeof(int));
|
||||
gRadiationEnduranceModifiers = (int*)malloc(gRadiationLevelCount * sizeof(int));
|
||||
gRadiationEffectStats = (int*)malloc(gRadiationEffectCount * sizeof(int));
|
||||
gRadiationEffectPenalties = (int**)malloc(gRadiationLevelCount * sizeof(int*));
|
||||
for (int i = 0; i < gRadiationLevelCount; ++i) {
|
||||
gRadiationEffectPenalties[i] = (int*)malloc(gRadiationEffectCount * sizeof(int));
|
||||
}
|
||||
|
||||
// Load arrays...
|
||||
configGetIntList(&config, "main", "RadiationThresholds", gRadiationThresholds, gRadiationLevelCount);
|
||||
configGetIntList(&config, "main", "RadiationEnduranceModifiers", gRadiationEnduranceModifiers, gRadiationLevelCount);
|
||||
configGetIntList(&config, "main", "RadiationEffectStats", gRadiationEffectStats, gRadiationEffectCount);
|
||||
|
||||
for (int i = 0; i < gRadiationLevelCount; ++i) {
|
||||
char key[20];
|
||||
snprintf(key, sizeof(key), "Level%d", i);
|
||||
configGetIntList(&config, "RadiationEffectPenalties", key, gRadiationEffectPenalties[i], gRadiationEffectCount);
|
||||
}
|
||||
|
||||
configFree(&config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x42CFE4
|
||||
void critterReset()
|
||||
{
|
||||
@@ -505,18 +486,11 @@ int critterCheckRadiationEvent(Object* obj)
|
||||
int radiation = critterGetRadiation(obj);
|
||||
|
||||
int radiationLevel;
|
||||
if (radiation > 999)
|
||||
radiationLevel = RADIATION_LEVEL_FATAL;
|
||||
else if (radiation > 599)
|
||||
radiationLevel = RADIATION_LEVEL_DEADLY;
|
||||
else if (radiation > 399)
|
||||
radiationLevel = RADIATION_LEVEL_CRITICAL;
|
||||
else if (radiation > 199)
|
||||
radiationLevel = RADIATION_LEVEL_ADVANCED;
|
||||
else if (radiation > 99)
|
||||
radiationLevel = RADIATION_LEVEL_MINOR;
|
||||
else
|
||||
radiationLevel = RADIATION_LEVEL_NONE;
|
||||
for (radiationLevel = gRadiationLevelCount - 1; radiationLevel >= 0; --radiationLevel) {
|
||||
if (radiation > gRadiationThresholds[radiationLevel]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (statRoll(obj, STAT_ENDURANCE, gRadiationEnduranceModifiers[radiationLevel], nullptr) <= ROLL_FAILURE) {
|
||||
radiationLevel++;
|
||||
@@ -568,7 +542,7 @@ void radiationProcess(Object* obj, int radiationLevel, bool isHealing)
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
if (radiationLevel == RADIATION_LEVEL_NONE) {
|
||||
if (radiationLevel == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -577,6 +551,7 @@ void radiationProcess(Object* obj, int radiationLevel, bool isHealing)
|
||||
|
||||
if (obj == gDude) {
|
||||
// Radiation level message, higher is worse.
|
||||
// Assuming original behavior that message indices follow the level order.
|
||||
messageListItem.num = 1000 + radiationLevelIndex;
|
||||
|
||||
// SFALL: Fix radiation message when removing radiation effects.
|
||||
@@ -590,7 +565,7 @@ void radiationProcess(Object* obj, int radiationLevel, bool isHealing)
|
||||
}
|
||||
}
|
||||
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_COUNT; effect++) {
|
||||
for (int effect = 0; effect < gRadiationEffectCount; effect++) {
|
||||
int value = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
value += modifier * gRadiationEffectPenalties[radiationLevelIndex][effect];
|
||||
critterSetBonusStat(obj, gRadiationEffectStats[effect], value);
|
||||
@@ -601,7 +576,7 @@ void radiationProcess(Object* obj, int radiationLevel, bool isHealing)
|
||||
if ((obj->data.critter.combat.results & DAM_DEAD) == 0) {
|
||||
// Loop thru effects affecting primary stats. If any of the primary stat
|
||||
// dropped below minimal value, kill it.
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_PRIMARY_STAT_COUNT; effect++) {
|
||||
for (int effect = 0; effect < gRadiationEffectPrimaryStatCount; effect++) {
|
||||
int base = critterGetBaseStatWithTraitModifier(obj, gRadiationEffectStats[effect]);
|
||||
int bonus = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
if (base + bonus < PRIMARY_STAT_MIN) {
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef enum DudeState {
|
||||
} DudeState;
|
||||
|
||||
int critterInit();
|
||||
int critterInitRadiationEffectPenalties();
|
||||
void critterReset();
|
||||
void critterExit();
|
||||
int critterLoad(File* stream);
|
||||
|
||||
+20
-75
@@ -1,3 +1,4 @@
|
||||
#include "settings.h"
|
||||
#include "game_config.h"
|
||||
#include "debug.h"
|
||||
#include "game_config_migration.h"
|
||||
@@ -63,74 +64,7 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: consolidate settings setup in one place; not sure if this is needed when we have settings field initializers
|
||||
// Initialize defaults.
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, "game");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY, "master.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY, "critter.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, ENGLISH);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SCROLL_LOCK_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_INTERRUPT_WALK_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, 8);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_HASHING_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FREE_SPACE_KEY, 20480);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, 3);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TARGET_HIGHLIGHT_KEY, 2);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_ITEM_HIGHLIGHT_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_MESSAGES_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_TAUNTS_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_LANGUAGE_FILTER_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_SUBTITLES_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_SPEED_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_PLAYER_SPEED_KEY, 0);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_BASE_DELAY_KEY, 3.5);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_LINE_DELAY_KEY, 1.399994);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_BRIGHTNESS_KEY, 1.0);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_MOUSE_SENSITIVITY_KEY, 1.0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_INITIALIZE_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEVICE_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_PORT_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_IRQ_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DMA_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SOUNDS_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MASTER_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SNDFX_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_CACHE_SIZE_KEY, 448);
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY, "sound\\music\\");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY, "sound\\music\\");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, "environment");
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_TILE_NUM_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_SCRIPT_MESSAGES_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_LOAD_INFO_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY, 0);
|
||||
|
||||
if (isMapper) {
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, "mapper");
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_LIBRARIAN_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_USE_ART_NOT_PROTOS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_REBUILD_PROTOS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_OBJECTS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_INVENTORY_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_IGNORE_REBUILD_ERRORS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SHOW_PID_NUMBERS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SAVE_TEXT_MAPS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_RUN_MAPPER_AS_GAME_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_DEFAULT_F8_AS_GAME_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, 0);
|
||||
}
|
||||
initSettingsRegistry();
|
||||
|
||||
// CE: Detect alternative default music directory.
|
||||
char alternativeMusicPath[COMPAT_MAX_PATH];
|
||||
@@ -142,11 +76,14 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
int acmsLength = fileNameListInit(alternativeMusicPath, &acms);
|
||||
if (acmsLength != -1) {
|
||||
if (acmsLength > 0) {
|
||||
// TODO: apply these to settings directly instead of config
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY, "data\\sound\\music\\");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY, "data\\sound\\music\\");
|
||||
}
|
||||
fileNameListFree(&acms, 0);
|
||||
}
|
||||
|
||||
settingsApplyDefaultsToConfig();
|
||||
|
||||
// SFALL: Custom config file name.
|
||||
char* customConfigFileName = nullptr;
|
||||
@@ -198,13 +135,21 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
configParseCommandLineArguments(&gGameConfig, argc, argv);
|
||||
|
||||
// CE: Normalize and resolve asset bundle paths.
|
||||
gameConfigResolvePath(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY);
|
||||
gameConfigResolvePath(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY);
|
||||
static const struct {
|
||||
const char* section;
|
||||
const char* key;
|
||||
} pathsToResolve[] = {
|
||||
{GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY},
|
||||
{GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY},
|
||||
{GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY},
|
||||
{GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY},
|
||||
{GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY},
|
||||
{GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY},
|
||||
};
|
||||
|
||||
for (const auto& path : pathsToResolve) {
|
||||
gameConfigResolvePath(path.section, path.key);
|
||||
}
|
||||
|
||||
gGameConfigInitialized = true;
|
||||
|
||||
|
||||
+210
-218
@@ -1,228 +1,39 @@
|
||||
#include "settings.h"
|
||||
#include "game_config.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
static void settingsFromConfig();
|
||||
static void settingsToConfig();
|
||||
static void settingsRead(const char* section, const char* key, std::string& value);
|
||||
static void settingsRead(const char* section, const char* key, int& value);
|
||||
static void settingsRead(const char* section, const char* key, int& value, int minValue, int maxValue);
|
||||
static void settingsRead(const char* section, const char* key, bool& value);
|
||||
static void settingsRead(const char* section, const char* key, double& value);
|
||||
static void settingsRead(const char* section, const char* key, double& value, double minValue, double maxValue);
|
||||
static void settingsWrite(const char* section, const char* key, const std::string& value);
|
||||
static void settingsWrite(const char* section, const char* key, int value);
|
||||
static void settingsWrite(const char* section, const char* key, bool value);
|
||||
static void settingsWrite(const char* section, const char* key, double value);
|
||||
struct SettingDescriptor {
|
||||
std::function<void()> read;
|
||||
std::function<void()> write;
|
||||
};
|
||||
|
||||
static std::vector<SettingDescriptor> settingsRegistry;
|
||||
|
||||
|
||||
template<typename T>
|
||||
void registerSetting(const char* section, const char* key, T& variable) {
|
||||
settingsRegistry.push_back({
|
||||
[&, section, key]() { settingsRead(section, key, variable); },
|
||||
[&, section, key]() { settingsWrite(section, key, variable); }
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void registerSetting(const char* section, const char* key, T& variable, T min, T max) {
|
||||
settingsRegistry.push_back({
|
||||
[&, section, key, min, max]() { settingsRead(section, key, variable, min, max); },
|
||||
[&, section, key]() { settingsWrite(section, key, variable); }
|
||||
});
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
|
||||
bool settingsInit(bool isMapper, int argc, char** argv)
|
||||
{
|
||||
if (!gameConfigInit(isMapper, argc, argv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
settingsFromConfig();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool settingsSave()
|
||||
{
|
||||
settingsToConfig();
|
||||
return gameConfigSave();
|
||||
}
|
||||
|
||||
bool settingsExit(bool shouldSave)
|
||||
{
|
||||
if (shouldSave) {
|
||||
settingsToConfig();
|
||||
}
|
||||
|
||||
return gameConfigExit(shouldSave);
|
||||
}
|
||||
|
||||
static void settingsFromConfig()
|
||||
{
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, settings.system.executable);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY, settings.system.master_dat_path);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, settings.system.master_patches_path);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY, settings.system.critter_dat_path);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY, settings.system.critter_patches_path);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, settings.system.language);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SCROLL_LOCK_KEY, settings.system.scroll_lock);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_INTERRUPT_WALK_KEY, settings.system.interrupt_walk);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, settings.system.art_cache_size);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, settings.system.color_cycling);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, settings.system.cycle_speed_factor);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_HASHING_KEY, settings.system.hashing);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, settings.system.splash);
|
||||
settingsRead(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FREE_SPACE_KEY, settings.system.free_space);
|
||||
|
||||
settingsRead(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_X_KEY, settings.screen.resolution_x, 640, 7680);
|
||||
settingsRead(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_Y_KEY, settings.screen.resolution_y, 480, 4320);
|
||||
settingsRead(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_WINDOWED_KEY, settings.screen.windowed);
|
||||
settingsRead(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_SCALE_KEY, settings.screen.scale, 1, 4);
|
||||
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_MODE_KEY, settings.ui.iface_bar_mode);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_WIDTH_KEY, settings.ui.iface_bar_width, 640, 4320);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_SIDE_ART_KEY, settings.ui.iface_bar_side_art, 0, 999);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_SIDES_ORI_KEY, settings.ui.iface_bar_sides_ori);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_SPLASH_SCREEN_SIZE_KEY, settings.ui.splash_screen_size, 0, 2);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IGNORE_MAP_EDGES_KEY, settings.ui.ignore_map_edges);
|
||||
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, settings.preferences.game_difficulty);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, settings.preferences.combat_difficulty);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, settings.preferences.violence_level);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TARGET_HIGHLIGHT_KEY, settings.preferences.target_highlight);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_ITEM_HIGHLIGHT_KEY, settings.preferences.item_highlight);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, settings.preferences.combat_looks);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_MESSAGES_KEY, settings.preferences.combat_messages);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_TAUNTS_KEY, settings.preferences.combat_taunts);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_LANGUAGE_FILTER_KEY, settings.preferences.language_filter);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_KEY, settings.preferences.running);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_SUBTITLES_KEY, settings.preferences.subtitles);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_SPEED_KEY, settings.preferences.combat_speed);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_PLAYER_SPEED_KEY, settings.preferences.player_speedup);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_BASE_DELAY_KEY, settings.preferences.text_base_delay);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_LINE_DELAY_KEY, settings.preferences.text_line_delay);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_BRIGHTNESS_KEY, settings.preferences.brightness);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_MOUSE_SENSITIVITY_KEY, settings.preferences.mouse_sensitivity);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_BURNING_GUY_KEY, settings.preferences.running_burning_guy);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_UI_ANIM_SPEED_KEY, settings.preferences.ui_anim_speed, 0.1, 100.0);
|
||||
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_INITIALIZE_KEY, settings.sound.initialize);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEBUG_KEY, settings.sound.debug);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEBUG_SFXC_KEY, settings.sound.debug_sfxc);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEVICE_KEY, settings.sound.device);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_PORT_KEY, settings.sound.port);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_IRQ_KEY, settings.sound.irq);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DMA_KEY, settings.sound.dma);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SOUNDS_KEY, settings.sound.sounds);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_KEY, settings.sound.music);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_KEY, settings.sound.speech);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MASTER_VOLUME_KEY, settings.sound.master_volume);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_VOLUME_KEY, settings.sound.music_volume);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SNDFX_VOLUME_KEY, settings.sound.sndfx_volume);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_VOLUME_KEY, settings.sound.speech_volume);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_CACHE_SIZE_KEY, settings.sound.cache_size);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY, settings.sound.music_path1);
|
||||
settingsRead(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY, settings.sound.music_path2);
|
||||
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, settings.debug.mode);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_TILE_NUM_KEY, settings.debug.show_tile_num);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_SCRIPT_MESSAGES_KEY, settings.debug.show_script_messages);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_LOAD_INFO_KEY, settings.debug.show_load_info);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY, settings.debug.output_map_data_info);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_DEBUG_WINDOW_WIDTH_KEY, settings.debug.debug_window_width, 200, 1920);
|
||||
settingsRead(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_DEBUG_WINDOW_HEIGHT_KEY, settings.debug.debug_window_height, 100, 1080);
|
||||
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY, settings.mapper.override_librarian);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_LIBRARIAN_KEY, settings.mapper.librarian);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_USE_ART_NOT_PROTOS_KEY, settings.mapper.user_art_not_protos);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_REBUILD_PROTOS_KEY, settings.mapper.rebuild_protos);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_OBJECTS_KEY, settings.mapper.fix_map_objects);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_INVENTORY_KEY, settings.mapper.fix_map_inventory);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_IGNORE_REBUILD_ERRORS_KEY, settings.mapper.rebuild_protos);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SHOW_PID_NUMBERS_KEY, settings.mapper.show_pid_numbers);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SAVE_TEXT_MAPS_KEY, settings.mapper.save_text_maps);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_RUN_MAPPER_AS_GAME_KEY, settings.mapper.run_mapper_as_game);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_DEFAULT_F8_AS_GAME_KEY, settings.mapper.default_f8_as_game);
|
||||
settingsRead(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, settings.mapper.sort_script_list);
|
||||
}
|
||||
|
||||
static void settingsToConfig()
|
||||
{
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, settings.system.executable);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY, settings.system.master_dat_path);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, settings.system.master_patches_path);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY, settings.system.critter_dat_path);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY, settings.system.critter_patches_path);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, settings.system.language);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SCROLL_LOCK_KEY, settings.system.scroll_lock);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_INTERRUPT_WALK_KEY, settings.system.interrupt_walk);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, settings.system.art_cache_size);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, settings.system.color_cycling);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, settings.system.cycle_speed_factor);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_HASHING_KEY, settings.system.hashing);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, settings.system.splash);
|
||||
settingsWrite(GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FREE_SPACE_KEY, settings.system.free_space);
|
||||
|
||||
settingsWrite(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_X_KEY, settings.screen.resolution_x);
|
||||
settingsWrite(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_Y_KEY, settings.screen.resolution_y);
|
||||
settingsWrite(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_WINDOWED_KEY, settings.screen.windowed);
|
||||
settingsWrite(GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_SCALE_KEY, settings.screen.scale);
|
||||
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_MODE_KEY, settings.ui.iface_bar_mode);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_WIDTH_KEY, settings.ui.iface_bar_width);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_SIDE_ART_KEY, settings.ui.iface_bar_side_art);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IFACE_BAR_SIDES_ORI_KEY, settings.ui.iface_bar_sides_ori);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_SPLASH_SCREEN_SIZE_KEY, settings.ui.splash_screen_size);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IGNORE_MAP_EDGES_KEY, settings.ui.ignore_map_edges);
|
||||
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, settings.preferences.game_difficulty);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, settings.preferences.combat_difficulty);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, settings.preferences.violence_level);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TARGET_HIGHLIGHT_KEY, settings.preferences.target_highlight);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_ITEM_HIGHLIGHT_KEY, settings.preferences.item_highlight);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, settings.preferences.combat_looks);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_MESSAGES_KEY, settings.preferences.combat_messages);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_TAUNTS_KEY, settings.preferences.combat_taunts);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_LANGUAGE_FILTER_KEY, settings.preferences.language_filter);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_KEY, settings.preferences.running);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_SUBTITLES_KEY, settings.preferences.subtitles);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_SPEED_KEY, settings.preferences.combat_speed);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_PLAYER_SPEED_KEY, settings.preferences.player_speedup);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_BASE_DELAY_KEY, settings.preferences.text_base_delay);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_LINE_DELAY_KEY, settings.preferences.text_line_delay);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_BRIGHTNESS_KEY, settings.preferences.brightness);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_MOUSE_SENSITIVITY_KEY, settings.preferences.mouse_sensitivity);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_BURNING_GUY_KEY, settings.preferences.running_burning_guy);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_UI_ANIM_SPEED_KEY, settings.preferences.ui_anim_speed);
|
||||
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_INITIALIZE_KEY, settings.sound.initialize);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEBUG_KEY, settings.sound.debug);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEBUG_SFXC_KEY, settings.sound.debug_sfxc);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEVICE_KEY, settings.sound.device);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_PORT_KEY, settings.sound.port);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_IRQ_KEY, settings.sound.irq);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DMA_KEY, settings.sound.dma);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SOUNDS_KEY, settings.sound.sounds);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_KEY, settings.sound.music);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_KEY, settings.sound.speech);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MASTER_VOLUME_KEY, settings.sound.master_volume);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_VOLUME_KEY, settings.sound.music_volume);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SNDFX_VOLUME_KEY, settings.sound.sndfx_volume);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_VOLUME_KEY, settings.sound.speech_volume);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_CACHE_SIZE_KEY, settings.sound.cache_size);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY, settings.sound.music_path1);
|
||||
settingsWrite(GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY, settings.sound.music_path2);
|
||||
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, settings.debug.mode);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_TILE_NUM_KEY, settings.debug.show_tile_num);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_SCRIPT_MESSAGES_KEY, settings.debug.show_script_messages);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_LOAD_INFO_KEY, settings.debug.show_load_info);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY, settings.debug.output_map_data_info);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_DEBUG_WINDOW_WIDTH_KEY, settings.debug.debug_window_width);
|
||||
settingsWrite(GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_DEBUG_WINDOW_HEIGHT_KEY, settings.debug.debug_window_height);
|
||||
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY, settings.mapper.override_librarian);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_LIBRARIAN_KEY, settings.mapper.librarian);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_USE_ART_NOT_PROTOS_KEY, settings.mapper.user_art_not_protos);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_REBUILD_PROTOS_KEY, settings.mapper.rebuild_protos);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_OBJECTS_KEY, settings.mapper.fix_map_objects);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_INVENTORY_KEY, settings.mapper.fix_map_inventory);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_IGNORE_REBUILD_ERRORS_KEY, settings.mapper.rebuild_protos);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SHOW_PID_NUMBERS_KEY, settings.mapper.show_pid_numbers);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SAVE_TEXT_MAPS_KEY, settings.mapper.save_text_maps);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_RUN_MAPPER_AS_GAME_KEY, settings.mapper.run_mapper_as_game);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_DEFAULT_F8_AS_GAME_KEY, settings.mapper.default_f8_as_game);
|
||||
settingsWrite(GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, settings.mapper.sort_script_list);
|
||||
}
|
||||
|
||||
static void settingsRead(const char* section, const char* key, std::string& value)
|
||||
{
|
||||
char* v;
|
||||
@@ -239,7 +50,7 @@ static void settingsRead(const char* section, const char* key, int& value)
|
||||
}
|
||||
}
|
||||
|
||||
void settingsRead(const char* section, const char* key, int& value, int minValue, int maxValue)
|
||||
static void settingsRead(const char* section, const char* key, int& value, int minValue, int maxValue)
|
||||
{
|
||||
settingsRead(section, key, value);
|
||||
value = std::clamp(value, minValue, maxValue);
|
||||
@@ -261,7 +72,7 @@ static void settingsRead(const char* section, const char* key, double& value)
|
||||
}
|
||||
}
|
||||
|
||||
void settingsRead(const char* section, const char* key, double& value, double minValue, double maxValue)
|
||||
static void settingsRead(const char* section, const char* key, double& value, double minValue, double maxValue)
|
||||
{
|
||||
settingsRead(section, key, value);
|
||||
value = std::clamp(value, minValue, maxValue);
|
||||
@@ -287,4 +98,185 @@ static void settingsWrite(const char* section, const char* key, double value)
|
||||
configSetDouble(&gGameConfig, section, key, value);
|
||||
}
|
||||
|
||||
struct SettingEntry {
|
||||
std::function<void(const char*)> registerFunc;
|
||||
|
||||
SettingEntry(const char* key, std::string& variable)
|
||||
: registerFunc([key, &variable](const char* section) { registerSetting(section, key, variable); })
|
||||
{
|
||||
}
|
||||
|
||||
SettingEntry(const char* key, int& variable)
|
||||
: registerFunc([key, &variable](const char* section) { registerSetting(section, key, variable); })
|
||||
{
|
||||
}
|
||||
|
||||
SettingEntry(const char* key, int& variable, int min, int max)
|
||||
: registerFunc([key, &variable, min, max](const char* section) { registerSetting(section, key, variable, min, max); })
|
||||
{
|
||||
}
|
||||
|
||||
SettingEntry(const char* key, bool& variable)
|
||||
: registerFunc([key, &variable](const char* section) { registerSetting(section, key, variable); })
|
||||
{
|
||||
}
|
||||
|
||||
SettingEntry(const char* key, double& variable)
|
||||
: registerFunc([key, &variable](const char* section) { registerSetting(section, key, variable); })
|
||||
{
|
||||
}
|
||||
|
||||
SettingEntry(const char* key, double& variable, double min, double max)
|
||||
: registerFunc([key, &variable, min, max](const char* section) { registerSetting(section, key, variable, min, max); })
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void initSettingsRegistry()
|
||||
{
|
||||
if (!settingsRegistry.empty()) return;
|
||||
|
||||
auto addSection = [](const char* section, std::initializer_list<SettingEntry> entries) {
|
||||
for (const auto& entry : entries) {
|
||||
entry.registerFunc(section);
|
||||
}
|
||||
};
|
||||
|
||||
addSection("system", {
|
||||
{"executable", settings.system.executable},
|
||||
{"master_dat", settings.system.master_dat_path},
|
||||
{"master_patches", settings.system.master_patches_path},
|
||||
{"critter_dat", settings.system.critter_dat_path},
|
||||
{"critter_patches", settings.system.critter_patches_path},
|
||||
{"language", settings.system.language},
|
||||
{"scroll_lock", settings.system.scroll_lock},
|
||||
{"interrupt_walk", settings.system.interrupt_walk},
|
||||
{"art_cache_size", settings.system.art_cache_size},
|
||||
{"color_cycling", settings.system.color_cycling},
|
||||
{"cycle_speed_factor", settings.system.cycle_speed_factor},
|
||||
{"hashing", settings.system.hashing},
|
||||
{"splash", settings.system.splash},
|
||||
{"free_space", settings.system.free_space},
|
||||
});
|
||||
|
||||
addSection("screen", {
|
||||
{"resolution_x", settings.screen.resolution_x, 640, 7680},
|
||||
{"resolution_y", settings.screen.resolution_y, 480, 4320},
|
||||
{"windowed", settings.screen.windowed},
|
||||
{"scale", settings.screen.scale, 1, 4},
|
||||
});
|
||||
|
||||
addSection("ui", {
|
||||
{"iface_bar_mode", settings.ui.iface_bar_mode},
|
||||
{"iface_bar_width", settings.ui.iface_bar_width, 640, 4320},
|
||||
{"iface_bar_side_art", settings.ui.iface_bar_side_art, 0, 999},
|
||||
{"iface_bar_sides_ori", settings.ui.iface_bar_sides_ori},
|
||||
{"splash_screen_size", settings.ui.splash_screen_size, 0, 2},
|
||||
{"ignore_map_edges", settings.ui.ignore_map_edges},
|
||||
});
|
||||
|
||||
addSection("preferences", {
|
||||
{"game_difficulty", settings.preferences.game_difficulty},
|
||||
{"combat_difficulty", settings.preferences.combat_difficulty},
|
||||
{"violence_level", settings.preferences.violence_level},
|
||||
{"target_highlight", settings.preferences.target_highlight},
|
||||
{"item_highlight", settings.preferences.item_highlight},
|
||||
{"combat_looks", settings.preferences.combat_looks},
|
||||
{"combat_messages", settings.preferences.combat_messages},
|
||||
{"combat_taunts", settings.preferences.combat_taunts},
|
||||
{"language_filter", settings.preferences.language_filter},
|
||||
{"running", settings.preferences.running},
|
||||
{"subtitles", settings.preferences.subtitles},
|
||||
{"combat_speed", settings.preferences.combat_speed},
|
||||
{"player_speed", settings.preferences.player_speedup},
|
||||
{"text_base_delay", settings.preferences.text_base_delay},
|
||||
{"text_line_delay", settings.preferences.text_line_delay},
|
||||
{"brightness", settings.preferences.brightness},
|
||||
{"mouse_sensitivity", settings.preferences.mouse_sensitivity},
|
||||
{"running_burning_guy", settings.preferences.running_burning_guy},
|
||||
{"ui_anim_speed", settings.preferences.ui_anim_speed, 0.1, 100.0},
|
||||
});
|
||||
|
||||
addSection("sound", {
|
||||
{"initialize", settings.sound.initialize},
|
||||
{"debug", settings.sound.debug},
|
||||
{"debug_sfxc", settings.sound.debug_sfxc},
|
||||
{"device", settings.sound.device},
|
||||
{"port", settings.sound.port},
|
||||
{"irq", settings.sound.irq},
|
||||
{"dma", settings.sound.dma},
|
||||
{"sounds", settings.sound.sounds},
|
||||
{"music", settings.sound.music},
|
||||
{"speech", settings.sound.speech},
|
||||
{"master_volume", settings.sound.master_volume},
|
||||
{"music_volume", settings.sound.music_volume},
|
||||
{"sndfx_volume", settings.sound.sndfx_volume},
|
||||
{"speech_volume", settings.sound.speech_volume},
|
||||
{"cache_size", settings.sound.cache_size},
|
||||
{"music_path1", settings.sound.music_path1},
|
||||
{"music_path2", settings.sound.music_path2},
|
||||
});
|
||||
|
||||
addSection("debug", {
|
||||
{"mode", settings.debug.mode},
|
||||
{"show_tile_num", settings.debug.show_tile_num},
|
||||
{"show_script_messages", settings.debug.show_script_messages},
|
||||
{"show_load_info", settings.debug.show_load_info},
|
||||
{"output_map_data_info", settings.debug.output_map_data_info},
|
||||
{"window_width", settings.debug.debug_window_width, 200, 1920},
|
||||
{"window_height", settings.debug.debug_window_height, 100, 1080},
|
||||
});
|
||||
|
||||
addSection("mapper", {
|
||||
{"override_librarian", settings.mapper.override_librarian},
|
||||
{"librarian", settings.mapper.librarian},
|
||||
{"use_art_not_protos", settings.mapper.user_art_not_protos},
|
||||
{"rebuild_protos", settings.mapper.rebuild_protos},
|
||||
{"fix_map_objects", settings.mapper.fix_map_objects},
|
||||
{"fix_map_inventory", settings.mapper.fix_map_inventory},
|
||||
{"ignore_rebuild_errors", settings.mapper.rebuild_protos},
|
||||
{"show_pid_numbers", settings.mapper.show_pid_numbers},
|
||||
{"save_text_maps", settings.mapper.save_text_maps},
|
||||
{"run_mapper_as_game", settings.mapper.run_mapper_as_game},
|
||||
{"default_f8_as_game", settings.mapper.default_f8_as_game},
|
||||
{"sort_script_list", settings.mapper.sort_script_list},
|
||||
});
|
||||
}
|
||||
|
||||
bool settingsInit(bool isMapper, int argc, char** argv)
|
||||
{
|
||||
if (!gameConfigInit(isMapper, argc, argv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
initSettingsRegistry();
|
||||
for (const auto& descriptor : settingsRegistry) {
|
||||
descriptor.read();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void settingsApplyDefaultsToConfig()
|
||||
{
|
||||
for (const auto& descriptor : settingsRegistry) {
|
||||
descriptor.write();
|
||||
}
|
||||
}
|
||||
|
||||
bool settingsSave()
|
||||
{
|
||||
settingsApplyDefaultsToConfig();
|
||||
return gameConfigSave();
|
||||
}
|
||||
|
||||
bool settingsExit(bool shouldSave)
|
||||
{
|
||||
if (shouldSave) {
|
||||
settingsSave();
|
||||
}
|
||||
|
||||
return gameConfigExit(shouldSave);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -136,6 +136,8 @@ extern Settings settings;
|
||||
|
||||
bool settingsInit(bool isMapper, int argc, char** argv);
|
||||
bool settingsSave();
|
||||
void settingsApplyDefaultsToConfig();
|
||||
void initSettingsRegistry();
|
||||
bool settingsExit(bool shouldSave);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
Reference in New Issue
Block a user