Add ini opcodes (#293)
This commit is contained in:
parent
681b7c388b
commit
03bf507893
|
@ -267,6 +267,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||||
"src/sfall_config.h"
|
"src/sfall_config.h"
|
||||||
"src/sfall_global_vars.cc"
|
"src/sfall_global_vars.cc"
|
||||||
"src/sfall_global_vars.h"
|
"src/sfall_global_vars.h"
|
||||||
|
"src/sfall_ini.cc"
|
||||||
|
"src/sfall_ini.h"
|
||||||
"src/sfall_lists.cc"
|
"src/sfall_lists.cc"
|
||||||
"src/sfall_lists.h"
|
"src/sfall_lists.h"
|
||||||
"src/sfall_opcodes.cc"
|
"src/sfall_opcodes.cc"
|
||||||
|
|
|
@ -280,24 +280,28 @@ bool configRead(Config* config, const char* filePath, bool isDb)
|
||||||
|
|
||||||
if (isDb) {
|
if (isDb) {
|
||||||
File* stream = fileOpen(filePath, "rb");
|
File* stream = fileOpen(filePath, "rb");
|
||||||
if (stream != NULL) {
|
|
||||||
while (fileReadString(string, sizeof(string), stream) != NULL) {
|
// CE: Return `false` if file does not exists in database.
|
||||||
configParseLine(config, string);
|
if (stream == NULL) {
|
||||||
}
|
return false;
|
||||||
fileClose(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (fileReadString(string, sizeof(string), stream) != NULL) {
|
||||||
|
configParseLine(config, string);
|
||||||
|
}
|
||||||
|
fileClose(stream);
|
||||||
} else {
|
} else {
|
||||||
FILE* stream = compat_fopen(filePath, "rt");
|
FILE* stream = compat_fopen(filePath, "rt");
|
||||||
if (stream != NULL) {
|
|
||||||
while (compat_fgets(string, sizeof(string), stream) != NULL) {
|
|
||||||
configParseLine(config, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(stream);
|
// CE: Return `false` if file does not exists on the file system.
|
||||||
|
if (stream == NULL) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This function returns `true` even if the file was not actually
|
while (compat_fgets(string, sizeof(string), stream) != NULL) {
|
||||||
// read. I'm pretty sure it's bug.
|
configParseLine(config, string);
|
||||||
|
}
|
||||||
|
fclose(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "sfall_arrays.h"
|
#include "sfall_arrays.h"
|
||||||
#include "sfall_config.h"
|
#include "sfall_config.h"
|
||||||
#include "sfall_global_vars.h"
|
#include "sfall_global_vars.h"
|
||||||
|
#include "sfall_ini.h"
|
||||||
#include "sfall_lists.h"
|
#include "sfall_lists.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "skilldex.h"
|
#include "skilldex.h"
|
||||||
|
@ -354,6 +355,10 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* customConfigBasePath;
|
||||||
|
configGetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, &customConfigBasePath);
|
||||||
|
sfall_ini_set_base_path(customConfigBasePath);
|
||||||
|
|
||||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList);
|
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -58,6 +58,8 @@ bool sfallConfigInit(int argc, char** argv)
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270);
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360);
|
||||||
|
|
||||||
|
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, "");
|
||||||
|
|
||||||
char path[COMPAT_MAX_PATH];
|
char path[COMPAT_MAX_PATH];
|
||||||
char* executable = argv[0];
|
char* executable = argv[0];
|
||||||
char* ch = strrchr(executable, '\\');
|
char* ch = strrchr(executable, '\\');
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace fallout {
|
||||||
#define SFALL_CONFIG_FILE_NAME "ddraw.ini"
|
#define SFALL_CONFIG_FILE_NAME "ddraw.ini"
|
||||||
|
|
||||||
#define SFALL_CONFIG_MISC_KEY "Misc"
|
#define SFALL_CONFIG_MISC_KEY "Misc"
|
||||||
|
#define SFALL_CONFIG_SCRIPTS_KEY "Scripts"
|
||||||
|
|
||||||
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY "MaleDefaultModel"
|
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY "MaleDefaultModel"
|
||||||
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY "FemaleDefaultModel"
|
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY "FemaleDefaultModel"
|
||||||
|
@ -68,6 +69,7 @@ namespace fallout {
|
||||||
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix"
|
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix"
|
||||||
#define SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY "ExtraGameMsgFileList"
|
#define SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY "ExtraGameMsgFileList"
|
||||||
#define SFALL_CONFIG_NUMBERS_IS_DIALOG_KEY "NumbersInDialogue"
|
#define SFALL_CONFIG_NUMBERS_IS_DIALOG_KEY "NumbersInDialogue"
|
||||||
|
#define SFALL_CONFIG_INI_CONFIG_FOLDER "IniConfigFolder"
|
||||||
|
|
||||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
||||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include "sfall_ini.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "platform_compat.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
/// The max length of `fileName` chunk in the triplet.
|
||||||
|
static constexpr size_t kFileNameMaxSize = 63;
|
||||||
|
|
||||||
|
/// The max length of `section` chunk in the triplet.
|
||||||
|
static constexpr size_t kSectionMaxSize = 32;
|
||||||
|
|
||||||
|
/// Special .ini file names which are accessed without adding base path.
|
||||||
|
static constexpr const char* kSystemConfigFileNames[] = {
|
||||||
|
"ddraw.ini",
|
||||||
|
"f2_res.ini",
|
||||||
|
};
|
||||||
|
|
||||||
|
static char basePath[COMPAT_MAX_PATH];
|
||||||
|
|
||||||
|
/// Parses "fileName|section|key" triplet into parts. `fileName` and `section`
|
||||||
|
/// chunks are copied into appropriate variables. Returns the pointer to `key`,
|
||||||
|
/// or `nullptr` on any error.
|
||||||
|
static const char* parse_ini_triplet(const char* triplet, char* fileName, char* section)
|
||||||
|
{
|
||||||
|
const char* fileNameSectionSep = strchr(triplet, '|');
|
||||||
|
if (fileNameSectionSep == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fileNameLength = fileNameSectionSep - triplet;
|
||||||
|
if (fileNameLength > kFileNameMaxSize) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sectionKeySep = strchr(fileNameSectionSep + 1, '|');
|
||||||
|
if (sectionKeySep == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sectionLength = sectionKeySep - fileNameSectionSep - 1;
|
||||||
|
if (sectionLength > kSectionMaxSize) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fileName, triplet, fileNameLength);
|
||||||
|
fileName[fileNameLength] = '\0';
|
||||||
|
|
||||||
|
strncpy(section, fileNameSectionSep + 1, sectionLength);
|
||||||
|
section[sectionLength] = '\0';
|
||||||
|
|
||||||
|
return sectionKeySep + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if given `fileName` is a special system .ini file name.
|
||||||
|
static bool is_system_file_name(const char* fileName)
|
||||||
|
{
|
||||||
|
for (auto& systemFileName : kSystemConfigFileNames) {
|
||||||
|
if (compat_stricmp(systemFileName, fileName) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfall_ini_set_base_path(const char* path)
|
||||||
|
{
|
||||||
|
if (path != nullptr) {
|
||||||
|
strcpy(basePath, path);
|
||||||
|
|
||||||
|
size_t length = strlen(basePath);
|
||||||
|
if (length > 0) {
|
||||||
|
if (basePath[length - 1] == '\\' || basePath[length - 1] == '/') {
|
||||||
|
basePath[length - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
basePath[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sfall_ini_get_int(const char* triplet, int* value)
|
||||||
|
{
|
||||||
|
char string[20];
|
||||||
|
if (!sfall_ini_get_string(triplet, string, sizeof(string))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = atol(string);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sfall_ini_get_string(const char* triplet, char* value, size_t size)
|
||||||
|
{
|
||||||
|
char fileName[kFileNameMaxSize];
|
||||||
|
char section[kSectionMaxSize];
|
||||||
|
|
||||||
|
const char* key = parse_ini_triplet(triplet, fileName, section);
|
||||||
|
if (key == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config config;
|
||||||
|
if (!configInit(&config)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[COMPAT_MAX_PATH];
|
||||||
|
bool loaded = false;
|
||||||
|
|
||||||
|
if (basePath[0] != '\0' && !is_system_file_name(fileName)) {
|
||||||
|
// Attempt to load requested file in base directory.
|
||||||
|
snprintf(path, sizeof(path), "%s\\%s", basePath, fileName);
|
||||||
|
loaded = configRead(&config, path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
// There was no base path set, requested file is a system config, or
|
||||||
|
// non-system config file was not found the base path - attempt to load
|
||||||
|
// from current working directory.
|
||||||
|
strcpy(path, fileName);
|
||||||
|
loaded = configRead(&config, path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
if (loaded) {
|
||||||
|
char* stringValue;
|
||||||
|
if (configGetString(&config, section, key, &stringValue)) {
|
||||||
|
strncpy(value, stringValue, size - 1);
|
||||||
|
value[size - 1] = '\0';
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configFree(&config);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fallout
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef FALLOUT_SFALL_INI_H_
|
||||||
|
#define FALLOUT_SFALL_INI_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
/// Sets base directory to lookup .ini files.
|
||||||
|
void sfall_ini_set_base_path(const char* path);
|
||||||
|
|
||||||
|
/// Reads integer key identified by "fileName|section|key" triplet into `value`.
|
||||||
|
bool sfall_ini_get_int(const char* triplet, int* value);
|
||||||
|
|
||||||
|
/// Reads string key identified by "fileName|section|key" triplet into `value`.
|
||||||
|
bool sfall_ini_get_string(const char* triplet, char* value, size_t size);
|
||||||
|
|
||||||
|
} // namespace fallout
|
||||||
|
|
||||||
|
#endif /* FALLOUT_SFALL_INI_H_ */
|
|
@ -19,6 +19,7 @@
|
||||||
#include "scripts.h"
|
#include "scripts.h"
|
||||||
#include "sfall_arrays.h"
|
#include "sfall_arrays.h"
|
||||||
#include "sfall_global_vars.h"
|
#include "sfall_global_vars.h"
|
||||||
|
#include "sfall_ini.h"
|
||||||
#include "sfall_lists.h"
|
#include "sfall_lists.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
|
@ -147,6 +148,19 @@ static void opGetGlobalInt(Program* program)
|
||||||
programStackPushInteger(program, value);
|
programStackPushInteger(program, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_ini_setting
|
||||||
|
static void op_get_ini_setting(Program* program)
|
||||||
|
{
|
||||||
|
const char* string = programStackPopString(program);
|
||||||
|
|
||||||
|
int value;
|
||||||
|
if (sfall_ini_get_int(string, &value)) {
|
||||||
|
programStackPushInteger(program, value);
|
||||||
|
} else {
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get_game_mode
|
// get_game_mode
|
||||||
static void opGetGameMode(Program* program)
|
static void opGetGameMode(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -181,6 +195,19 @@ static void op_set_bodypart_hit_modifier(Program* program)
|
||||||
combat_set_hit_location_penalty(hit_location, penalty);
|
combat_set_hit_location_penalty(hit_location, penalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_ini_string
|
||||||
|
static void op_get_ini_string(Program* program)
|
||||||
|
{
|
||||||
|
const char* string = programStackPopString(program);
|
||||||
|
|
||||||
|
char value[256];
|
||||||
|
if (sfall_ini_get_string(string, value, sizeof(value))) {
|
||||||
|
programStackPushString(program, value);
|
||||||
|
} else {
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sqrt
|
// sqrt
|
||||||
static void op_sqrt(Program* program)
|
static void op_sqrt(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -785,11 +812,13 @@ void sfallOpcodesInit()
|
||||||
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
||||||
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
||||||
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
||||||
|
interpreterRegisterOpcode(0x81AC, op_get_ini_setting);
|
||||||
interpreterRegisterOpcode(0x81AF, opGetGameMode);
|
interpreterRegisterOpcode(0x81AF, opGetGameMode);
|
||||||
interpreterRegisterOpcode(0x81B3, op_get_uptime);
|
interpreterRegisterOpcode(0x81B3, op_get_uptime);
|
||||||
interpreterRegisterOpcode(0x81B6, op_set_car_current_town);
|
interpreterRegisterOpcode(0x81B6, op_set_car_current_town);
|
||||||
interpreterRegisterOpcode(0x81DF, op_get_bodypart_hit_modifier);
|
interpreterRegisterOpcode(0x81DF, op_get_bodypart_hit_modifier);
|
||||||
interpreterRegisterOpcode(0x81E0, op_set_bodypart_hit_modifier);
|
interpreterRegisterOpcode(0x81E0, op_set_bodypart_hit_modifier);
|
||||||
|
interpreterRegisterOpcode(0x81EB, op_get_ini_string);
|
||||||
interpreterRegisterOpcode(0x81EC, op_sqrt);
|
interpreterRegisterOpcode(0x81EC, op_sqrt);
|
||||||
interpreterRegisterOpcode(0x81ED, op_abs);
|
interpreterRegisterOpcode(0x81ED, op_abs);
|
||||||
interpreterRegisterOpcode(0x8204, op_get_proto_data);
|
interpreterRegisterOpcode(0x8204, op_get_proto_data);
|
||||||
|
|
Loading…
Reference in New Issue