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_global_vars.cc"
|
||||
"src/sfall_global_vars.h"
|
||||
"src/sfall_ini.cc"
|
||||
"src/sfall_ini.h"
|
||||
"src/sfall_lists.cc"
|
||||
"src/sfall_lists.h"
|
||||
"src/sfall_opcodes.cc"
|
||||
|
|
|
@ -280,26 +280,30 @@ bool configRead(Config* config, const char* filePath, bool isDb)
|
|||
|
||||
if (isDb) {
|
||||
File* stream = fileOpen(filePath, "rb");
|
||||
if (stream != NULL) {
|
||||
|
||||
// CE: Return `false` if file does not exists in database.
|
||||
if (stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (fileReadString(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
fileClose(stream);
|
||||
}
|
||||
} else {
|
||||
FILE* stream = compat_fopen(filePath, "rt");
|
||||
if (stream != NULL) {
|
||||
|
||||
// CE: Return `false` if file does not exists on the file system.
|
||||
if (stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (compat_fgets(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
// FIXME: This function returns `true` even if the file was not actually
|
||||
// read. I'm pretty sure it's bug.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "sfall_arrays.h"
|
||||
#include "sfall_config.h"
|
||||
#include "sfall_global_vars.h"
|
||||
#include "sfall_ini.h"
|
||||
#include "sfall_lists.h"
|
||||
#include "skill.h"
|
||||
#include "skilldex.h"
|
||||
|
@ -354,6 +355,10 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
|||
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);
|
||||
|
||||
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_ARTIMER4, 360);
|
||||
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, "");
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
char* executable = argv[0];
|
||||
char* ch = strrchr(executable, '\\');
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace fallout {
|
|||
#define SFALL_CONFIG_FILE_NAME "ddraw.ini"
|
||||
|
||||
#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_FEMALE_KEY "FemaleDefaultModel"
|
||||
|
@ -68,6 +69,7 @@ namespace fallout {
|
|||
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix"
|
||||
#define SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY "ExtraGameMsgFileList"
|
||||
#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_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 "sfall_arrays.h"
|
||||
#include "sfall_global_vars.h"
|
||||
#include "sfall_ini.h"
|
||||
#include "sfall_lists.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
|
@ -147,6 +148,19 @@ static void opGetGlobalInt(Program* program)
|
|||
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
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
static void op_sqrt(Program* program)
|
||||
{
|
||||
|
@ -785,11 +812,13 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
||||
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
||||
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
||||
interpreterRegisterOpcode(0x81AC, op_get_ini_setting);
|
||||
interpreterRegisterOpcode(0x81AF, opGetGameMode);
|
||||
interpreterRegisterOpcode(0x81B3, op_get_uptime);
|
||||
interpreterRegisterOpcode(0x81B6, op_set_car_current_town);
|
||||
interpreterRegisterOpcode(0x81DF, op_get_bodypart_hit_modifier);
|
||||
interpreterRegisterOpcode(0x81E0, op_set_bodypart_hit_modifier);
|
||||
interpreterRegisterOpcode(0x81EB, op_get_ini_string);
|
||||
interpreterRegisterOpcode(0x81EC, op_sqrt);
|
||||
interpreterRegisterOpcode(0x81ED, op_abs);
|
||||
interpreterRegisterOpcode(0x8204, op_get_proto_data);
|
||||
|
|
Loading…
Reference in New Issue