TRX/src/config.c

486 lines
17 KiB
C
Raw Normal View History

#include "config.h"
2021-03-14 13:50:30 +01:00
2021-03-18 16:14:28 +01:00
#include "filesystem.h"
#include "game/input.h"
#include "game/music.h"
#include "game/sound.h"
2021-03-21 21:17:46 +01:00
#include "global/const.h"
#include "global/types.h"
#include "json/json_base.h"
#include "json/json_parse.h"
#include "json/json_write.h"
2021-10-31 18:29:50 +01:00
#include "log.h"
2021-11-16 11:49:49 +01:00
#include "memory.h"
#include "util.h"
2021-03-14 13:50:30 +01:00
#include <stdio.h>
#include <string.h>
2021-02-22 21:36:00 +01:00
#define Q(x) #x
#define QUOTE(x) Q(x)
2021-03-07 15:59:00 +01:00
#define READ_PRIMITIVE(func, opt, default_value) \
do { \
g_Config.opt = \
func(root_obj, Config_ProcessKey(QUOTE(opt)), default_value); \
2021-03-07 15:59:00 +01:00
} while (0)
#define READ_BOOL(opt, default_value) \
2021-03-18 20:53:12 +01:00
READ_PRIMITIVE(json_object_get_bool, opt, default_value)
2021-03-07 15:59:00 +01:00
#define READ_INTEGER(opt, default_value) \
2022-02-05 01:34:21 +01:00
READ_PRIMITIVE(json_object_get_int, opt, default_value)
2021-10-23 21:31:03 +02:00
#define READ_FLOAT(opt, default_value) \
2022-02-05 01:34:21 +01:00
READ_PRIMITIVE(json_object_get_double, opt, default_value)
2021-03-07 15:59:00 +01:00
#define READ_ENUM(opt, default_value, enum_map) \
2021-02-22 21:36:00 +01:00
do { \
g_Config.opt = Config_ReadEnum( \
root_obj, Config_ProcessKey(QUOTE(opt)), default_value, enum_map); \
2021-02-22 21:36:00 +01:00
} while (0)
#define WRITE_PRIMITIVE(func, opt) \
do { \
func(root_obj, Config_ProcessKey(QUOTE(opt)), g_Config.opt); \
} while (0)
#define WRITE_BOOL(opt) WRITE_PRIMITIVE(json_object_append_bool, opt)
#define WRITE_INTEGER(opt) WRITE_PRIMITIVE(json_object_append_int, opt)
#define WRITE_FLOAT(opt) WRITE_PRIMITIVE(json_object_append_double, opt)
#define WRITE_ENUM(opt, enum_map) \
do { \
Config_WriteEnum( \
root_obj, Config_ProcessKey(QUOTE(opt)), g_Config.opt, enum_map); \
} while (0)
2021-11-24 17:37:21 +01:00
CONFIG g_Config = { 0 };
2021-10-14 12:56:43 +02:00
2021-11-24 16:48:16 +01:00
static const char *m_T1MGlobalSettingsPath = "cfg/Tomb1Main.json5";
2021-11-04 21:41:33 +01:00
typedef struct ENUM_MAP {
const char *text;
int value;
} ENUM_MAP;
2022-06-30 21:20:48 -04:00
const ENUM_MAP m_UIStyles[] = {
{ "ps1", UI_STYLE_PS1 },
{ "pc", UI_STYLE_PC },
{ NULL, -1 },
};
const ENUM_MAP m_BarShowingModes[] = {
{ "default", BSM_DEFAULT },
{ "flashing-or-default", BSM_FLASHING_OR_DEFAULT },
{ "flashing-only", BSM_FLASHING_ONLY },
{ "always", BSM_ALWAYS },
{ "never", BSM_NEVER },
{ "ps1", BSM_PS1 },
{ NULL, -1 },
};
const ENUM_MAP m_BarLocations[] = {
{ "top-left", BL_TOP_LEFT },
{ "top-center", BL_TOP_CENTER },
{ "top-right", BL_TOP_RIGHT },
{ "bottom-left", BL_BOTTOM_LEFT },
{ "bottom-center", BL_BOTTOM_CENTER },
{ "bottom-right", BL_BOTTOM_RIGHT },
{ NULL, -1 },
};
const ENUM_MAP m_BarColors[] = {
{ "gold", BC_GOLD }, { "blue", BC_BLUE }, { "grey", BC_GREY },
{ "red", BC_RED }, { "silver", BC_SILVER }, { "green", BC_GREEN },
{ "gold2", BC_GOLD2 }, { "blue2", BC_BLUE2 }, { "pink", BC_PINK },
{ NULL, -1 },
};
const ENUM_MAP m_ScreenshotFormats[] = {
{ "jpg", SCREENSHOT_FORMAT_JPEG },
{ "jpeg", SCREENSHOT_FORMAT_JPEG },
{ "png", SCREENSHOT_FORMAT_PNG },
{ NULL, -1 },
};
static const char *Config_ProcessKey(const char *key);
static int Config_ReadEnum(
struct json_object_s *obj, const char *name, int8_t default_value,
const ENUM_MAP *enum_map);
static void Config_WriteEnum(
struct json_object_s *obj, const char *name, int8_t value,
const ENUM_MAP *enum_map);
static const char *Config_ProcessKey(const char *key)
{
return strchr(key, '.') ? strrchr(key, '.') + 1 : key;
}
static int Config_ReadEnum(
struct json_object_s *obj, const char *name, int8_t default_value,
const ENUM_MAP *enum_map)
{
2021-03-18 20:53:12 +01:00
const char *value_str = json_object_get_string(obj, name, NULL);
if (value_str) {
while (enum_map->text) {
if (!strcmp(value_str, enum_map->text)) {
return enum_map->value;
}
enum_map++;
2021-03-07 15:59:00 +01:00
}
}
return default_value;
}
static void Config_WriteEnum(
struct json_object_s *obj, const char *name, int8_t value,
const ENUM_MAP *enum_map)
{
while (enum_map->text) {
if (enum_map->value == value) {
json_object_append_string(obj, name, enum_map->text);
break;
}
enum_map++;
}
}
2021-11-30 12:25:56 +01:00
bool Config_ReadFromJSON(const char *cfg_data)
2021-03-07 15:59:00 +01:00
{
2021-11-24 18:20:05 +01:00
bool result = false;
2021-03-18 20:53:12 +01:00
struct json_value_s *root;
2021-03-11 14:54:59 +01:00
struct json_parse_result_s parse_result;
2021-03-18 20:53:12 +01:00
root = json_parse_ex(
2021-03-07 15:59:00 +01:00
cfg_data, strlen(cfg_data), json_parse_flags_allow_json5, NULL, NULL,
2021-03-11 14:54:59 +01:00
&parse_result);
2021-11-24 18:20:05 +01:00
if (root) {
result = true;
} else {
2021-03-25 18:18:18 +01:00
LOG_ERROR(
2021-03-11 14:54:59 +01:00
"failed to parse config file: %s in line %d, char %d",
2021-03-18 20:53:12 +01:00
json_get_error_description(parse_result.error),
2021-03-11 14:54:59 +01:00
parse_result.error_line_no, parse_result.error_row_no);
2021-03-19 01:09:02 +01:00
// continue to supply the default values
2021-03-11 14:54:59 +01:00
}
2021-03-07 15:59:00 +01:00
2021-03-18 20:53:12 +01:00
struct json_object_s *root_obj = json_value_as_object(root);
2021-11-02 21:03:42 +01:00
READ_BOOL(disable_healing_between_levels, false);
READ_BOOL(disable_medpacks, false);
READ_BOOL(disable_magnums, false);
READ_BOOL(disable_uzis, false);
READ_BOOL(disable_shotgun, false);
READ_BOOL(enable_detailed_stats, true);
2022-02-09 22:58:57 +01:00
READ_BOOL(enable_deaths_counter, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(enable_enemy_healthbar, true);
READ_BOOL(enable_enhanced_look, true);
READ_BOOL(enable_shotgun_flash, true);
READ_BOOL(fix_shotgun_targeting, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(enable_cheats, false);
READ_BOOL(enable_numeric_keys, true);
READ_BOOL(enable_tr3_sidesteps, true);
READ_BOOL(enable_braid, false);
READ_BOOL(enable_compass_stats, true);
READ_BOOL(enable_total_stats, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(enable_timer_in_inventory, true);
READ_BOOL(enable_smooth_bars, true);
READ_BOOL(enable_fade_effects, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(fix_tihocan_secret_sound, true);
READ_BOOL(fix_floor_data_issues, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(fix_secrets_killing_music, true);
READ_BOOL(fix_speeches_killing_music, true);
READ_BOOL(fix_descending_glitch, false);
READ_BOOL(fix_wall_jump_glitch, false);
READ_BOOL(fix_bridge_collision, true);
READ_BOOL(fix_qwop_glitch, false);
READ_BOOL(fix_alligator_ai, true);
READ_BOOL(change_pierre_spawn, true);
READ_BOOL(fix_bear_ai, true);
2021-03-07 15:59:00 +01:00
READ_INTEGER(fov_value, 65);
READ_INTEGER(resolution_width, -1);
READ_INTEGER(resolution_height, -1);
2021-11-02 21:03:42 +01:00
READ_BOOL(fov_vertical, true);
READ_BOOL(enable_demo, true);
READ_BOOL(enable_fmv, true);
READ_BOOL(enable_cine, true);
READ_BOOL(enable_music_in_menu, true);
READ_BOOL(enable_music_in_inventory, true);
2021-11-02 21:03:42 +01:00
READ_BOOL(enable_round_shadow, true);
READ_BOOL(enable_3d_pickups, true);
READ_FLOAT(rendering.anisotropy_filter, 16.0f);
READ_BOOL(walk_to_items, false);
READ_BOOL(disable_trex_collision, false);
READ_INTEGER(start_lara_hitpoints, LARA_HITPOINTS);
READ_ENUM(
healthbar_showing_mode, BSM_FLASHING_OR_DEFAULT, m_BarShowingModes);
READ_ENUM(airbar_showing_mode, BSM_DEFAULT, m_BarShowingModes);
READ_ENUM(healthbar_location, BL_TOP_LEFT, m_BarLocations);
READ_ENUM(airbar_location, BL_TOP_RIGHT, m_BarLocations);
READ_ENUM(enemy_healthbar_location, BL_BOTTOM_LEFT, m_BarLocations);
READ_ENUM(healthbar_color, BC_RED, m_BarColors);
READ_ENUM(airbar_color, BC_BLUE, m_BarColors);
READ_ENUM(enemy_healthbar_color, BC_GREY, m_BarColors);
READ_ENUM(screenshot_format, SCREENSHOT_FORMAT_JPEG, m_ScreenshotFormats);
2022-06-30 21:20:48 -04:00
READ_ENUM(ui.menu_style, UI_STYLE_PC, m_UIStyles);
2022-05-30 23:17:48 +02:00
READ_INTEGER(maximum_save_slots, 25);
READ_BOOL(revert_to_pistols, false);
READ_BOOL(enable_enhanced_saves, true);
READ_BOOL(enable_pitched_sounds, true);
READ_BOOL(enable_ps_uzi_sfx, false);
READ_BOOL(enable_jump_twists, true);
READ_BOOL(enabled_inverted_look, false);
READ_INTEGER(camera_speed, 5);
READ_BOOL(fix_texture_issues, true);
READ_BOOL(enable_swing_cancel, true);
READ_BOOL(enable_tr2_jumping, false);
READ_BOOL(load_current_music, true);
READ_BOOL(load_music_triggers, true);
READ_BOOL(fix_item_rots, true);
READ_BOOL(restore_ps1_enemies, false);
READ_BOOL(enable_game_modes, true);
READ_BOOL(enable_save_crystals, false);
2021-03-07 15:59:00 +01:00
CLAMP(g_Config.start_lara_hitpoints, 1, LARA_HITPOINTS);
2021-11-24 17:37:21 +01:00
CLAMP(g_Config.fov_value, 30, 255);
CLAMP(g_Config.camera_speed, 1, 10);
2021-03-07 15:59:00 +01:00
// User settings
READ_INTEGER(rendering.render_mode, GFX_RM_LEGACY);
READ_BOOL(rendering.enable_bilinear_filter, true);
READ_BOOL(rendering.enable_perspective_filter, true);
READ_BOOL(rendering.enable_vsync, true);
READ_INTEGER(music_volume, 8);
CLAMP(g_Config.music_volume, 0, 10);
READ_INTEGER(sound_volume, 8);
CLAMP(g_Config.sound_volume, 0, 10);
READ_INTEGER(input.layout, 0);
CLAMP(g_Config.input.layout, 0, INPUT_LAYOUT_NUMBER_OF - 1);
READ_INTEGER(input.cntlr_layout, 0);
CLAMP(g_Config.input.cntlr_layout, 0, INPUT_LAYOUT_NUMBER_OF - 1);
READ_FLOAT(brightness, DEFAULT_BRIGHTNESS);
CLAMP(g_Config.brightness, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
READ_FLOAT(ui.text_scale, DEFAULT_UI_SCALE);
CLAMP(g_Config.ui.text_scale, MIN_TEXT_SCALE, MAX_TEXT_SCALE);
READ_FLOAT(ui.bar_scale, DEFAULT_UI_SCALE);
CLAMP(g_Config.ui.bar_scale, MIN_BAR_SCALE, MAX_BAR_SCALE);
READ_BOOL(profile.new_game_plus_unlock, false);
char layout_name[50];
for (INPUT_LAYOUT layout = INPUT_LAYOUT_CUSTOM_1;
layout < INPUT_LAYOUT_NUMBER_OF; layout++) {
sprintf(layout_name, "layout_%d", layout);
struct json_array_s *layout_arr =
json_object_get_array(root_obj, layout_name);
for (INPUT_ROLE role = 0; role < INPUT_ROLE_NUMBER_OF; role++) {
INPUT_SCANCODE scancode = Input_GetAssignedScancode(layout, role);
scancode = json_array_get_int(layout_arr, role, scancode);
Input_AssignScancode(layout, role, scancode);
}
}
Input_CheckConflicts(CM_KEYBOARD, g_Config.input.layout);
for (INPUT_LAYOUT layout = INPUT_LAYOUT_CUSTOM_1;
layout < INPUT_LAYOUT_NUMBER_OF; layout++) {
sprintf(layout_name, "cntlr_layout_%d", layout);
struct json_array_s *cntlr_arr =
json_object_get_array(root_obj, layout_name);
INPUT_ROLE role = 0;
int i = 0;
for (INPUT_ROLE role = 0; role < INPUT_ROLE_NUMBER_OF; role++) {
int16_t type = Input_GetAssignedButtonType(layout, role);
type = json_array_get_int(cntlr_arr, i, type);
i++;
int16_t bind = Input_GetAssignedBind(layout, role);
bind = json_array_get_int(cntlr_arr, i, bind);
i++;
int16_t axis_dir = Input_GetAssignedAxisDir(layout, role);
axis_dir = json_array_get_int(cntlr_arr, i, axis_dir);
i++;
if (type == BT_BUTTON) {
Input_AssignButton(layout, role, bind);
} else {
Input_AssignAxis(layout, role, bind, axis_dir);
}
}
}
Input_CheckConflicts(CM_CONTROLLER, g_Config.input.cntlr_layout);
2021-03-18 20:53:12 +01:00
if (root) {
json_value_free(root);
2021-03-11 14:54:59 +01:00
}
return result;
2021-03-07 15:59:00 +01:00
}
bool Config_Read(void)
{
2021-11-24 18:20:05 +01:00
bool result = false;
2021-03-11 14:54:59 +01:00
char *cfg_data = NULL;
2021-11-24 18:20:05 +01:00
if (!File_Load(m_T1MGlobalSettingsPath, &cfg_data, NULL)) {
2022-10-18 18:14:11 +01:00
LOG_WARNING(
"'%s' not loaded - default settings will apply",
m_T1MGlobalSettingsPath);
result = Config_ReadFromJSON("{}");
} else {
result = Config_ReadFromJSON(cfg_data);
}
2022-01-07 03:14:07 +01:00
Memory_FreePointer(&cfg_data);
2021-03-11 14:54:59 +01:00
return result;
}
void Config_Init(void)
{
GFX_Context_SetVSync(g_Config.rendering.enable_vsync);
Music_SetVolume(g_Config.music_volume);
Sound_SetMasterVolume(g_Config.sound_volume);
}
bool Config_Write(void)
{
LOG_INFO("Saving user settings");
MYFILE *fp = File_Open(m_T1MGlobalSettingsPath, FILE_OPEN_WRITE);
if (!fp) {
return false;
}
size_t size;
struct json_object_s *root_obj = json_object_new();
WRITE_BOOL(disable_healing_between_levels);
WRITE_BOOL(disable_medpacks);
WRITE_BOOL(disable_magnums);
WRITE_BOOL(disable_uzis);
WRITE_BOOL(disable_shotgun);
WRITE_BOOL(enable_detailed_stats);
WRITE_BOOL(enable_deaths_counter);
WRITE_BOOL(enable_enemy_healthbar);
WRITE_BOOL(enable_enhanced_look);
WRITE_BOOL(enable_shotgun_flash);
WRITE_BOOL(fix_shotgun_targeting);
WRITE_BOOL(enable_cheats);
WRITE_BOOL(enable_numeric_keys);
WRITE_BOOL(enable_tr3_sidesteps);
WRITE_BOOL(enable_braid);
WRITE_BOOL(enable_compass_stats);
WRITE_BOOL(enable_total_stats);
WRITE_BOOL(enable_timer_in_inventory);
WRITE_BOOL(enable_smooth_bars);
WRITE_BOOL(enable_fade_effects);
WRITE_BOOL(fix_tihocan_secret_sound);
WRITE_BOOL(fix_floor_data_issues);
WRITE_BOOL(fix_secrets_killing_music);
WRITE_BOOL(fix_speeches_killing_music);
WRITE_BOOL(fix_descending_glitch);
WRITE_BOOL(fix_wall_jump_glitch);
WRITE_BOOL(fix_bridge_collision);
WRITE_BOOL(fix_qwop_glitch);
WRITE_BOOL(fix_alligator_ai);
WRITE_BOOL(change_pierre_spawn);
WRITE_BOOL(fix_bear_ai);
WRITE_INTEGER(fov_value);
WRITE_INTEGER(resolution_width);
WRITE_INTEGER(resolution_height);
WRITE_BOOL(fov_vertical);
WRITE_BOOL(enable_demo);
WRITE_BOOL(enable_fmv);
WRITE_BOOL(enable_cine);
WRITE_BOOL(enable_music_in_menu);
WRITE_BOOL(enable_music_in_inventory);
WRITE_BOOL(enable_round_shadow);
WRITE_BOOL(enable_3d_pickups);
WRITE_FLOAT(rendering.anisotropy_filter);
WRITE_BOOL(walk_to_items);
WRITE_BOOL(disable_trex_collision);
WRITE_INTEGER(start_lara_hitpoints);
WRITE_ENUM(healthbar_showing_mode, m_BarShowingModes);
WRITE_ENUM(airbar_showing_mode, m_BarShowingModes);
WRITE_ENUM(healthbar_location, m_BarLocations);
WRITE_ENUM(airbar_location, m_BarLocations);
WRITE_ENUM(enemy_healthbar_location, m_BarLocations);
WRITE_ENUM(healthbar_color, m_BarColors);
WRITE_ENUM(airbar_color, m_BarColors);
WRITE_ENUM(enemy_healthbar_color, m_BarColors);
WRITE_ENUM(screenshot_format, m_ScreenshotFormats);
WRITE_ENUM(ui.menu_style, m_UIStyles);
WRITE_INTEGER(maximum_save_slots);
WRITE_BOOL(revert_to_pistols);
WRITE_BOOL(enable_enhanced_saves);
WRITE_BOOL(enable_pitched_sounds);
WRITE_BOOL(enable_ps_uzi_sfx);
WRITE_BOOL(enable_jump_twists);
WRITE_BOOL(enabled_inverted_look);
WRITE_INTEGER(camera_speed);
WRITE_BOOL(fix_texture_issues);
WRITE_BOOL(enable_swing_cancel);
WRITE_BOOL(enable_tr2_jumping);
WRITE_BOOL(load_current_music);
WRITE_BOOL(load_music_triggers);
WRITE_BOOL(fix_item_rots);
WRITE_BOOL(restore_ps1_enemies);
WRITE_BOOL(enable_game_modes);
WRITE_BOOL(enable_save_crystals);
// User settings
WRITE_INTEGER(rendering.render_mode);
WRITE_BOOL(rendering.enable_bilinear_filter);
WRITE_BOOL(rendering.enable_perspective_filter);
WRITE_BOOL(rendering.enable_vsync);
WRITE_INTEGER(music_volume);
WRITE_INTEGER(sound_volume);
WRITE_INTEGER(input.layout);
WRITE_INTEGER(input.cntlr_layout);
WRITE_FLOAT(brightness);
WRITE_FLOAT(ui.text_scale);
WRITE_FLOAT(ui.bar_scale);
WRITE_BOOL(profile.new_game_plus_unlock);
char layout_name[20];
for (INPUT_LAYOUT layout = INPUT_LAYOUT_CUSTOM_1;
layout < INPUT_LAYOUT_NUMBER_OF; layout++) {
struct json_array_s *layout_arr = json_array_new();
sprintf(layout_name, "layout_%d", layout);
for (INPUT_ROLE role = 0; role < INPUT_ROLE_NUMBER_OF; role++) {
json_array_append_int(
layout_arr, Input_GetAssignedScancode(layout, role));
}
json_object_append_array(root_obj, layout_name, layout_arr);
}
for (INPUT_LAYOUT layout = INPUT_LAYOUT_CUSTOM_1;
layout < INPUT_LAYOUT_NUMBER_OF; layout++) {
struct json_array_s *cntlr_arr = json_array_new();
sprintf(layout_name, "cntlr_layout_%d", layout);
for (INPUT_ROLE role = 0; role < INPUT_ROLE_NUMBER_OF; role++) {
json_array_append_int(
cntlr_arr, Input_GetAssignedButtonType(layout, role));
json_array_append_int(
cntlr_arr, Input_GetAssignedBind(layout, role));
json_array_append_int(
cntlr_arr, Input_GetAssignedAxisDir(layout, role));
}
json_object_append_array(root_obj, layout_name, cntlr_arr);
}
struct json_value_s *root = json_value_from_object(root_obj);
char *data = json_write_pretty(root, " ", "\n", &size);
json_value_free(root);
File_Write(data, sizeof(char), size - 1, fp);
File_Close(fp);
Memory_FreePointer(&data);
return true;
}