Add ini opcodes (#293)

This commit is contained in:
Alexander Batalov 2023-05-30 12:52:55 +03:00 committed by GitHub
parent 681b7c388b
commit 03bf507893
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 221 additions and 12 deletions

View File

@ -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"

View File

@ -280,26 +280,30 @@ 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) {
// CE: Return `false` if file does not exists in database.
if (stream == NULL) {
return false;
}
while (fileReadString(string, sizeof(string), stream) != NULL) { while (fileReadString(string, sizeof(string), stream) != NULL) {
configParseLine(config, string); configParseLine(config, string);
} }
fileClose(stream); fileClose(stream);
}
} else { } else {
FILE* stream = compat_fopen(filePath, "rt"); 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) { while (compat_fgets(string, sizeof(string), stream) != NULL) {
configParseLine(config, string); configParseLine(config, string);
} }
fclose(stream); fclose(stream);
} }
// FIXME: This function returns `true` even if the file was not actually
// read. I'm pretty sure it's bug.
}
return true; return true;
} }

View File

@ -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;

View File

@ -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, '\\');

View File

@ -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

146
src/sfall_ini.cc Normal file
View File

@ -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

19
src/sfall_ini.h Normal file
View File

@ -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_ */

View File

@ -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);