mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c42bb2630 |
@@ -87,7 +87,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: os/android/app/.cxx
|
||||
key: android-cmake-v100
|
||||
key: android-cmake-v2
|
||||
|
||||
- name: Setup signing config
|
||||
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
|
||||
@@ -128,7 +128,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: out
|
||||
key: ios-cmake-v100
|
||||
key: ios-cmake-v5
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: out
|
||||
key: linux-${{ matrix.arch }}-cmake-v100
|
||||
key: linux-${{ matrix.arch }}-cmake-v3
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
@@ -288,7 +288,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: out
|
||||
key: macos-cmake-v100
|
||||
key: macos-cmake-v6
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
@@ -337,7 +337,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: out
|
||||
key: windows-${{ matrix.arch }}-cmake-v100
|
||||
key: windows-${{ matrix.arch }}-cmake-v3
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "lib.arrays.h" // For arrays_equal, len_array, etc.
|
||||
#include "test_utils.h" // For assertEquals, VALTYPE_STR, report_test_results
|
||||
|
||||
// To test: copy test.ini into the game folder before running
|
||||
procedure ini_test_suite begin
|
||||
variable result_array, expected_array, key_type, value_type, count, key_val_pair;
|
||||
|
||||
display_msg("--- Testing ini functions");
|
||||
|
||||
// Test Case 1: Valid file, valid section
|
||||
result_array := get_ini_section("test.ini", "ValidSection");
|
||||
expected_array := {"Key1": "Value1", "Key2": "2"};
|
||||
call assertEquals("TC1 Size", len_array(result_array), 2);
|
||||
call assertEquals("TC1 Content", arrays_equal(result_array, expected_array), true);
|
||||
count := 0;
|
||||
foreach key_val_pair in result_array begin
|
||||
count += 1;
|
||||
call assertEquals("TC1 Key Type " + count, typeof(key_val_pair[0]), VALTYPE_STR);
|
||||
call assertEquals("TC1 Value Type " + count, typeof(key_val_pair[1]), VALTYPE_STR);
|
||||
end
|
||||
|
||||
// basic fetchers
|
||||
call assertEquals("TC2 Specific Key1 Value", result_array["Key1"], "Value1");
|
||||
call assertEquals("TC2 get_ini_setting string", get_ini_setting("test.ini|ValidSection|Key1"), 0);
|
||||
call assertEquals("TC2 get_ini_string string", get_ini_string("test.ini|ValidSection|Key1"), "Value1");
|
||||
call assertEquals("TC2 get_ini_setting int", get_ini_setting("test.ini|ValidSection|Key2"), 2);
|
||||
call assertEquals("TC2 get_ini_string int", get_ini_string("test.ini|ValidSection|Key2"), "2");
|
||||
|
||||
// INI file not found
|
||||
result_array := get_ini_section("nonexistent.ini", "AnySection");
|
||||
call assertEquals("TC3 Size", len_array(result_array), 0);
|
||||
call assertEquals("TC3 Is Map", array_key(result_array, -1), 1); // Should still be an associative array
|
||||
call assertEquals("TC3 get_ini_setting", get_ini_setting("notexist.ini|ValidSection|Key2"), 0);
|
||||
call assertEquals("TC3 get_ini_string", get_ini_string("notexist.ini|ValidSection|Key2"), "");
|
||||
|
||||
// Valid file, section not found
|
||||
result_array := get_ini_section("test.ini", "NonExistentSection");
|
||||
call assertEquals("TC4 Size", len_array(result_array), 0);
|
||||
call assertEquals("TC4 Is Map", array_key(result_array, -1), 1);
|
||||
call assertEquals("TC4 get_ini_setting", get_ini_setting("test.ini|NonExistentSection|Key2"), 0);
|
||||
call assertEquals("TC4 get_ini_string", get_ini_string("test.ini|NonExistentSection|Key2"), "");
|
||||
|
||||
|
||||
// Valid file, empty section
|
||||
result_array := get_ini_section("test.ini", "EmptySection");
|
||||
call assertEquals("TC5 Size", len_array(result_array), 0);
|
||||
call assertEquals("TC5 Is Map", array_key(result_array, -1), 1);
|
||||
call assertEquals("TC5 get_ini_setting", get_ini_setting("test.ini|EmptySection|Key2"), 0);
|
||||
call assertEquals("TC5 get_ini_string", get_ini_string("test.ini|EmptySection|Key2"), "");
|
||||
|
||||
// set ini setting
|
||||
set_ini_setting("test_set.ini|ValidSection|Key3", "OldValue");
|
||||
call assertEquals("TC6 set_ini_setting 1", get_ini_string("test_set.ini|ValidSection|Key3"), "OldValue");
|
||||
set_ini_setting("test_set.ini|ValidSection|Key3", "NewValue");
|
||||
call assertEquals("TC6 set_ini_setting 2", get_ini_string("test_set.ini|ValidSection|Key3"), "NewValue");
|
||||
set_ini_setting("test_set.ini|ValidSection|Key3", 2);
|
||||
call assertEquals("TC6 set_ini_setting int", get_ini_setting("test_set.ini|ValidSection|Key3"), 2);
|
||||
|
||||
// get_init_sections
|
||||
result_array := get_ini_sections("test.ini");
|
||||
call assertEquals("TC7 get_ini_sections size", len_array(result_array), 3);
|
||||
call assertTrue("TC7 get_ini_sections", scan_array(result_array, "TestMisc") >= 0);
|
||||
|
||||
call report_test_results("ini");
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
call ini_test_suite();
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
[ValidSection]
|
||||
Key1=Value1
|
||||
Key2=2
|
||||
|
||||
[SectionWithSpaces]
|
||||
LeadingSpaceKey = LeadingSpaceValue
|
||||
TrailingSpaceKey = TrailingSpaceValue
|
||||
Both Sides Space Key = Both Sides Space Value
|
||||
SimpleKey=SimpleValue
|
||||
|
||||
[EmptySection]
|
||||
|
||||
; This is TestMisc, it's not empty but won't be directly tested for content here.
|
||||
[TestMisc]
|
||||
Alpha=Beta
|
||||
Gamma=Delta
|
||||
@@ -7,17 +7,6 @@ variable test_suite_errors := 0;
|
||||
variable test_suite_verbose := false;
|
||||
variable test_suite_assertions := 0;
|
||||
|
||||
procedure assertTrue(variable desc, variable a) begin
|
||||
test_suite_assertions++;
|
||||
|
||||
if (not a) then begin
|
||||
display_msg("Assertion failed \""+desc+"\": is not true");
|
||||
test_suite_errors ++;
|
||||
end else if (test_suite_verbose) then begin
|
||||
display_msg("Assert \""+desc+"\" ok");
|
||||
end
|
||||
end
|
||||
|
||||
procedure assertEquals(variable desc, variable a, variable b) begin
|
||||
test_suite_assertions++;
|
||||
|
||||
|
||||
+3
-18
@@ -6,7 +6,6 @@
|
||||
#include "color.h"
|
||||
#include "db.h"
|
||||
#include "memory_manager.h"
|
||||
#include "settings.h"
|
||||
|
||||
// The maximum number of interface fonts.
|
||||
#define INTERFACE_FONT_MAX (16)
|
||||
@@ -120,25 +119,11 @@ static int interfaceFontLoad(int font_index)
|
||||
InterfaceFontDescriptor* fontDescriptor = &(gInterfaceFontDescriptors[font_index]);
|
||||
|
||||
char path[56];
|
||||
File* stream = nullptr;
|
||||
snprintf(path, sizeof(path), "font%d.aaf", font_index);
|
||||
|
||||
// Try set language path first
|
||||
snprintf(path, sizeof(path), "text/%s/font%d.aaf", settings.system.language.c_str(), font_index);
|
||||
stream = fileOpen(path, "rb");
|
||||
|
||||
// Fallback to English if needed
|
||||
if (stream == nullptr && compat_stricmp(settings.system.language.c_str(), ENGLISH) != 0) {
|
||||
snprintf(path, sizeof(path), "text/%s/font%d.aaf", ENGLISH, font_index);
|
||||
stream = fileOpen(path, "rb");
|
||||
}
|
||||
|
||||
// Fallback to original path
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
snprintf(path, sizeof(path), "font%d.aaf", font_index);
|
||||
stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fileSize = fileGetSize(stream);
|
||||
|
||||
+2
-2
@@ -3241,12 +3241,12 @@ int _gdialog_barter_create_win()
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
// TRADE
|
||||
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 40, 163, 14, 14, -1, -1, -1, KEY_LOWERCASE_M, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
|
||||
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 40, 162, 14, 14, -1, -1, -1, KEY_LOWERCASE_M, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
|
||||
if (_gdialog_buttons[0] != -1) {
|
||||
buttonSetCallbacks(_gdialog_buttons[0], _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// TALK
|
||||
_gdialog_buttons[1] = buttonCreate(gGameDialogWindow, 583, 162, 14, 14, -1, -1, -1, KEY_LOWERCASE_T, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
|
||||
_gdialog_buttons[1] = buttonCreate(gGameDialogWindow, 583, 161, 14, 14, -1, -1, -1, KEY_LOWERCASE_T, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
|
||||
if (_gdialog_buttons[1] != -1) {
|
||||
buttonSetCallbacks(_gdialog_buttons[1], _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
|
||||
@@ -3346,21 +3346,4 @@ int ProgramValue::asInt() const
|
||||
}
|
||||
}
|
||||
|
||||
// CE
|
||||
ProgramValue programMakeString(Program* program, const char* str)
|
||||
{
|
||||
ProgramValue valuePv;
|
||||
valuePv.opcode = VALUE_TYPE_DYNAMIC_STRING;
|
||||
valuePv.integerValue = programPushString(program, str);
|
||||
return valuePv;
|
||||
}
|
||||
|
||||
ProgramValue programMakeInt(Program* program, int val)
|
||||
{
|
||||
ProgramValue valuePv;
|
||||
valuePv.opcode = VALUE_TYPE_INT;
|
||||
valuePv.integerValue = val;
|
||||
return valuePv;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -241,10 +241,6 @@ ProgramValue programReturnStackPopValue(Program* program);
|
||||
int programReturnStackPopInteger(Program* program);
|
||||
void* programReturnStackPopPointer(Program* program);
|
||||
|
||||
// CE
|
||||
ProgramValue programMakeString(Program* program, const char* str);
|
||||
ProgramValue programMakeInt(Program* program, int val);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* INTERPRETER_H */
|
||||
|
||||
+8
-25
@@ -2078,51 +2078,34 @@ static void _display_body(int fid, int inventoryWindowType)
|
||||
unsigned char* windowBuffer = windowGetBuffer(gInventoryWindow);
|
||||
int windowPitch = windowGetWidth(gInventoryWindow);
|
||||
|
||||
FrmImage backgroundFrmImage;
|
||||
int Fid = 114;
|
||||
int sourceXOffset = 0;
|
||||
|
||||
if (index == 1) {
|
||||
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) {
|
||||
rect.left = 426; // loot right cha window (or container)
|
||||
rect.left = 426;
|
||||
rect.top = 39;
|
||||
Fid = 114;
|
||||
sourceXOffset = 538;
|
||||
} else {
|
||||
rect.left = 297; // inventory data window? ?not used?
|
||||
rect.left = 297;
|
||||
rect.top = 37;
|
||||
Fid = 48;
|
||||
sourceXOffset = 229;
|
||||
}
|
||||
} else {
|
||||
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) {
|
||||
rect.left = 48; // loot left cha window
|
||||
rect.left = 48;
|
||||
rect.top = 39;
|
||||
Fid = 114;
|
||||
sourceXOffset = 0;
|
||||
} else if (inventoryWindowType == INVENTORY_WINDOW_TYPE_USE_ITEM_ON) {
|
||||
rect.left = 176; // Use item cha window
|
||||
rect.top = 37;
|
||||
Fid = 113;
|
||||
sourceXOffset = 292;
|
||||
} else {
|
||||
rect.left = 176; // inventory cha window (same as use on)
|
||||
rect.left = 176;
|
||||
rect.top = 37;
|
||||
Fid = 48;
|
||||
sourceXOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, Fid, 0, 0, 0);
|
||||
|
||||
rect.right = rect.left + INVENTORY_BODY_VIEW_WIDTH - 1;
|
||||
rect.bottom = rect.top + INVENTORY_BODY_VIEW_HEIGHT - 1;
|
||||
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 114, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + backgroundFrmImage.getWidth() * rect.top + rect.left + sourceXOffset,
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + INVENTORY_LOOT_WINDOW_WIDTH * rect.top + rect.left,
|
||||
INVENTORY_BODY_VIEW_WIDTH,
|
||||
INVENTORY_BODY_VIEW_HEIGHT,
|
||||
backgroundFrmImage.getWidth(),
|
||||
INVENTORY_LOOT_WINDOW_WIDTH,
|
||||
windowBuffer + windowPitch * rect.top + rect.left,
|
||||
windowPitch);
|
||||
}
|
||||
|
||||
+17
-190
@@ -1,14 +1,10 @@
|
||||
#include "sfall_ini.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio> // for snprintf
|
||||
#include <cstring> // for strncpy, strlen
|
||||
#include <cstring>
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "interpreter.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sfall_arrays.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
@@ -72,38 +68,6 @@ static bool is_system_file_name(const char* fileName)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads an INI file specified by 'ini_file_name' (e.g., "myconfig.ini" or "ddraw.ini")
|
||||
// into the provided 'config_out' object.
|
||||
// The 'config_out' object must be initialized by the caller (using configInit).
|
||||
// The caller is also responsible for freeing 'config_out' (using configFree).
|
||||
// Returns true if the file was successfully found and read, false otherwise.
|
||||
static bool sfall_load_named_ini_file(const char* ini_file_name, Config* config_out)
|
||||
{
|
||||
if (ini_file_name == nullptr || config_out == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
bool loaded = false;
|
||||
|
||||
if (basePath[0] != '\0' && !is_system_file_name(ini_file_name)) {
|
||||
// Attempt to load requested file in base directory.
|
||||
snprintf(path, sizeof(path), "%s\\%s", basePath, ini_file_name);
|
||||
loaded = configRead(config_out, 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.
|
||||
strncpy(path, ini_file_name, sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
loaded = configRead(config_out, path, false);
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void sfall_ini_set_base_path(const char* path)
|
||||
{
|
||||
if (path != nullptr) {
|
||||
@@ -147,7 +111,22 @@ bool sfall_ini_get_string(const char* triplet, char* value, size_t size)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loaded = sfall_load_named_ini_file(fileName, &config);
|
||||
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);
|
||||
}
|
||||
|
||||
// NOTE: Sfall's `GetIniSetting` returns error code (-1) only when it cannot
|
||||
// parse triplet. Otherwise the default for string settings is empty string.
|
||||
@@ -215,156 +194,4 @@ bool sfall_ini_set_string(const char* triplet, const char* value)
|
||||
return saved;
|
||||
}
|
||||
|
||||
static const ConfigSection* sfall_find_section_in_config(Config* config, const char* section_name)
|
||||
{
|
||||
if (config == nullptr || section_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int sectionIndex = dictionaryGetIndexByKey(config, section_name);
|
||||
if (sectionIndex == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
return static_cast<const ConfigSection*>(sectionEntry->value);
|
||||
}
|
||||
|
||||
// set_ini_setting
|
||||
void mf_set_ini_setting(Program* program, int args)
|
||||
{
|
||||
const char* triplet = programStackPopString(program);
|
||||
ProgramValue value = programStackPopValue(program);
|
||||
|
||||
if (value.isString()) {
|
||||
const char* stringValue = programGetString(program, value.opcode, value.integerValue);
|
||||
if (!sfall_ini_set_string(triplet, stringValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%s' to '%s'",
|
||||
stringValue,
|
||||
triplet);
|
||||
}
|
||||
} else {
|
||||
int integerValue = value.asInt();
|
||||
if (!sfall_ini_set_int(triplet, integerValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%d' to '%s'",
|
||||
integerValue,
|
||||
triplet);
|
||||
}
|
||||
}
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
// get_ini_section
|
||||
void mf_get_ini_section(Program* program, int args)
|
||||
{
|
||||
// Arguments: file_path (string), section_name (string)
|
||||
|
||||
const char* filePath = programStackPopString(program);
|
||||
const char* sectionName = programStackPopString(program);
|
||||
|
||||
ArrayId arrayId = CreateTempArray(-1, 0);
|
||||
|
||||
if (filePath == nullptr || sectionName == nullptr) {
|
||||
programStackPushInteger(program, arrayId);
|
||||
return;
|
||||
}
|
||||
|
||||
Config iniConfig;
|
||||
if (!configInit(&iniConfig)) {
|
||||
debugPrint("mf_get_ini_section: Failed to initialize Config structure.");
|
||||
programStackPushInteger(program, arrayId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sfall_load_named_ini_file(filePath, &iniConfig)) {
|
||||
const ConfigSection* section = sfall_find_section_in_config(&iniConfig, sectionName);
|
||||
|
||||
if (section != nullptr) {
|
||||
for (int i = 0; i < section->entriesLength; ++i) {
|
||||
DictionaryEntry* entry = &(section->entries[i]);
|
||||
const char* key = entry->key;
|
||||
const char* value = *(static_cast<char**>(entry->value));
|
||||
|
||||
if (key != nullptr && value != nullptr) {
|
||||
SetArray(arrayId, programMakeString(program, key), programMakeString(program, value), false, program);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFree(&iniConfig);
|
||||
|
||||
programStackPushInteger(program, arrayId);
|
||||
}
|
||||
|
||||
// get_ini_sections
|
||||
void mf_get_ini_sections(Program* program, int args)
|
||||
{
|
||||
// Arguments: file_path (string)
|
||||
const char* filePath = programStackPopString(program);
|
||||
ArrayId arrayId = -1;
|
||||
|
||||
if (filePath == nullptr) {
|
||||
programStackPushInteger(program, arrayId);
|
||||
return;
|
||||
}
|
||||
|
||||
Config iniConfig;
|
||||
if (!configInit(&iniConfig)) {
|
||||
debugPrint("mf_get_ini_sections: Failed to initialize Config structure.");
|
||||
programStackPushInteger(program, arrayId);
|
||||
return;
|
||||
}
|
||||
|
||||
// note: seems to load sections in random order
|
||||
if (sfall_load_named_ini_file(filePath, &iniConfig)) {
|
||||
if (iniConfig.entriesLength > 0) {
|
||||
arrayId = CreateTempArray(iniConfig.entriesLength, 0);
|
||||
for (int i = 0; i < iniConfig.entriesLength; ++i) {
|
||||
DictionaryEntry* entry = &(iniConfig.entries[i]);
|
||||
const char* sectionName = entry->key;
|
||||
|
||||
if (sectionName != nullptr) {
|
||||
SetArray(arrayId, programMakeInt(program, i), programMakeString(program, sectionName), false, program);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFree(&iniConfig);
|
||||
|
||||
if (arrayId == -1) {
|
||||
arrayId = CreateTempArray(0, 0);
|
||||
}
|
||||
|
||||
programStackPushInteger(program, arrayId);
|
||||
}
|
||||
|
||||
// get_ini_setting
|
||||
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_ini_string
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#ifndef FALLOUT_SFALL_INI_H_
|
||||
#define FALLOUT_SFALL_INI_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "dictionary.h"
|
||||
#include "interpreter.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace fallout {
|
||||
@@ -23,13 +20,6 @@ bool sfall_ini_set_int(const char* triplet, int value);
|
||||
/// Writes string key identified by "fileName|section|key" triplet.
|
||||
bool sfall_ini_set_string(const char* triplet, const char* value);
|
||||
|
||||
// metarule and opcode implementations
|
||||
void mf_set_ini_setting(Program* program, int args);
|
||||
void mf_get_ini_section(Program* program, int args);
|
||||
void mf_get_ini_sections(Program* program, int args);
|
||||
void op_get_ini_setting(Program* program);
|
||||
void op_get_ini_string(Program* program);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_SFALL_INI_H_ */
|
||||
|
||||
+33
-11
@@ -7,7 +7,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "combat.h"
|
||||
#include "config.h" // For Config, configInit, configFree
|
||||
#include "debug.h"
|
||||
#include "game.h"
|
||||
#include "game_dialog.h"
|
||||
@@ -16,7 +15,6 @@
|
||||
#include "inventory.h"
|
||||
#include "object.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sfall_arrays.h" // For CreateTempArray, SetArray
|
||||
#include "sfall_ini.h"
|
||||
#include "text_font.h"
|
||||
#include "tile.h"
|
||||
@@ -49,6 +47,7 @@ static void mf_metarule_exist(Program* program, int args);
|
||||
static void mf_outlined_object(Program* program, int args);
|
||||
static void mf_set_cursor_mode(Program* program, int args);
|
||||
static void mf_set_flags(Program* program, int args);
|
||||
static void mf_set_ini_setting(Program* program, int args);
|
||||
static void mf_set_outline(Program* program, int args);
|
||||
static void mf_show_window(Program* program, int args);
|
||||
static void mf_tile_refresh_display(Program* program, int args);
|
||||
@@ -59,7 +58,6 @@ static void mf_string_format(Program* program, int args);
|
||||
static void mf_floor2(Program* program, int args);
|
||||
|
||||
// ref. https://github.com/sfall-team/sfall/blob/42556141127895c27476cd5242a73739cbb0fade/sfall/Modules/Scripting/Handlers/Metarule.cpp#L72
|
||||
// Note: metarules should pop arguments off the stack in natural order
|
||||
constexpr MetaruleInfo kMetarules[] = {
|
||||
// {"add_extra_msg_file", mf_add_extra_msg_file, 1, 2, -1, {ARG_STRING, ARG_INT}},
|
||||
// {"add_iface_tag", mf_add_iface_tag, 0, 0},
|
||||
@@ -71,7 +69,7 @@ constexpr MetaruleInfo kMetarules[] = {
|
||||
{ "car_gas_amount", mf_car_gas_amount, 0, 0 },
|
||||
{ "combat_data", mf_combat_data, 0, 0 },
|
||||
// {"create_win", mf_create_win, 5, 6, -1, {ARG_STRING, ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
|
||||
{ "critter_inven_obj2", mf_critter_inven_obj2, 2, 2 }, // XXX: likely parameter order mismatch
|
||||
{ "critter_inven_obj2", mf_critter_inven_obj2, 2, 2 },
|
||||
// {"dialog_message", mf_dialog_message, 1, 1, -1, {ARG_STRING}},
|
||||
{ "dialog_obj", mf_dialog_obj, 0, 0 },
|
||||
// {"display_stats", mf_display_stats, 0, 0}, // refresh
|
||||
@@ -85,13 +83,13 @@ constexpr MetaruleInfo kMetarules[] = {
|
||||
{ "get_cursor_mode", mf_get_cursor_mode, 0, 0 },
|
||||
{ "get_flags", mf_get_flags, 1, 1 },
|
||||
// {"get_ini_config", mf_get_ini_config, 2, 2, 0, {ARG_STRING, ARG_INT}},
|
||||
{ "get_ini_section", mf_get_ini_section, 2, 2 },
|
||||
{ "get_ini_sections", mf_get_ini_sections, 1, 1 },
|
||||
// {"get_ini_section", mf_get_ini_section, 2, 2, -1, {ARG_STRING, ARG_STRING}},
|
||||
// {"get_ini_sections", mf_get_ini_sections, 1, 1, -1, {ARG_STRING}},
|
||||
// {"get_inven_ap_cost", mf_get_inven_ap_cost, 0, 0},
|
||||
// {"get_map_enter_position", mf_get_map_enter_position, 0, 0},
|
||||
// {"get_metarule_table", mf_get_metarule_table, 0, 0},
|
||||
// {"get_object_ai_data", mf_get_object_ai_data, 2, 2, -1, {ARG_OBJECT, ARG_INT}},
|
||||
{ "get_object_data", mf_get_object_data, 2, 2 }, // XXX: likely parameter order mismatch
|
||||
{ "get_object_data", mf_get_object_data, 2, 2 },
|
||||
// {"get_outline", mf_get_outline, 1, 1, 0, {ARG_OBJECT}},
|
||||
// {"get_sfall_arg_at", mf_get_sfall_arg_at, 1, 1, 0, {ARG_INT}},
|
||||
// {"get_stat_max", mf_get_stat_max, 1, 2, 0, {ARG_INT, ARG_INT}},
|
||||
@@ -139,7 +137,7 @@ constexpr MetaruleInfo kMetarules[] = {
|
||||
{ "set_ini_setting", mf_set_ini_setting, 2, 2 },
|
||||
// {"set_map_enter_position", mf_set_map_enter_position, 3, 3, -1, {ARG_INT, ARG_INT, ARG_INT}},
|
||||
// {"set_object_data", mf_set_object_data, 3, 3, -1, {ARG_OBJECT, ARG_INT, ARG_INT}},
|
||||
{ "set_outline", mf_set_outline, 2, 2 }, // XXX: likely parameter order mismatch
|
||||
{ "set_outline", mf_set_outline, 2, 2 },
|
||||
// {"set_quest_failure_value", mf_set_quest_failure_value, 2, 2, -1, {ARG_INT, ARG_INT}},
|
||||
// {"set_rest_heal_time", mf_set_rest_heal_time, 1, 1, -1, {ARG_INT}},
|
||||
// {"set_worldmap_heal_time", mf_set_worldmap_heal_time, 1, 1, -1, {ARG_INT}},
|
||||
@@ -300,6 +298,30 @@ void mf_set_flags(Program* program, int args)
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_set_ini_setting(Program* program, int args)
|
||||
{
|
||||
ProgramValue value = programStackPopValue(program);
|
||||
const char* triplet = programStackPopString(program);
|
||||
|
||||
if (value.isString()) {
|
||||
const char* stringValue = programGetString(program, value.opcode, value.integerValue);
|
||||
if (!sfall_ini_set_string(triplet, stringValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%s' to '%s'",
|
||||
stringValue,
|
||||
triplet);
|
||||
}
|
||||
} else {
|
||||
int integerValue = value.asInt();
|
||||
if (!sfall_ini_set_int(triplet, integerValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%d' to '%s'",
|
||||
integerValue,
|
||||
triplet);
|
||||
}
|
||||
}
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_set_outline(Program* program, int args)
|
||||
{
|
||||
int outline = programStackPopInteger(program);
|
||||
@@ -438,7 +460,7 @@ void mf_string_find(Program* program, int args)
|
||||
|
||||
const char* found = strstr(str + startPos, substr);
|
||||
if (found) {
|
||||
programStackPushInteger(program, static_cast<int>(found - str));
|
||||
programStackPushInteger(program, found - str);
|
||||
} else {
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
@@ -480,7 +502,7 @@ void sprintf_lite(Program* program, int args, const char* infoOpcodeName)
|
||||
formatArgs[index] = programStackPopValue(program);
|
||||
}
|
||||
|
||||
int fmtLen = static_cast<int>(strlen(format));
|
||||
int fmtLen = strlen(format);
|
||||
if (fmtLen == 0) {
|
||||
programStackPushString(program, "");
|
||||
return;
|
||||
@@ -536,7 +558,7 @@ void sprintf_lite(Program* program, int args, const char* infoOpcodeName)
|
||||
if (c == 'S' || c == 'Z') {
|
||||
c = 's'; // don't allow wide strings
|
||||
}
|
||||
if ((c == 's' && !arg.isString()) || // don't allow treating non-string values as string pointers
|
||||
if (c == 's' && !arg.isString() || // don't allow treating non-string values as string pointers
|
||||
c == 'n') // don't allow "n" specifier
|
||||
{
|
||||
c = 'd';
|
||||
|
||||
+47
-4
@@ -207,6 +207,22 @@ static void op_set_world_map_pos(Program* program)
|
||||
wmSetPartyWorldPos(x, y);
|
||||
}
|
||||
|
||||
// get_world_map_x_pos
|
||||
static void op_get_world_map_x_pos(Program* program)
|
||||
{
|
||||
int x;
|
||||
wmGetPartyWorldPos(&x, nullptr);
|
||||
programStackPushInteger(program, x);
|
||||
}
|
||||
|
||||
// get_world_map_y_pos
|
||||
static void op_get_world_map_y_pos(Program* program)
|
||||
{
|
||||
int y;
|
||||
wmGetPartyWorldPos(nullptr, &y);
|
||||
programStackPushInteger(program, y);
|
||||
}
|
||||
|
||||
// active_hand
|
||||
static void op_active_hand(Program* program)
|
||||
{
|
||||
@@ -256,6 +272,19 @@ static void op_get_sfall_global_int(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 op_get_game_mode(Program* program)
|
||||
{
|
||||
@@ -290,6 +319,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)
|
||||
{
|
||||
@@ -719,7 +761,7 @@ static void op_substr(Program* program)
|
||||
|
||||
char buf[5120] = { 0 };
|
||||
|
||||
int len = static_cast<int>(strlen(str));
|
||||
int len = strlen(str);
|
||||
|
||||
if (startPos < 0) {
|
||||
startPos += len; // start from end
|
||||
@@ -951,7 +993,7 @@ static void op_party_member_list(Program* program)
|
||||
{
|
||||
auto includeHidden = programStackPopInteger(program);
|
||||
auto objects = get_all_party_members_objects(includeHidden);
|
||||
auto arrayId = CreateTempArray(static_cast<int>(objects.size()), SFALL_ARRAYFLAG_RESERVED);
|
||||
auto arrayId = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED);
|
||||
for (int i = 0; i < LenArray(arrayId); i++) {
|
||||
SetArray(arrayId, ProgramValue { i }, ProgramValue { objects[i] }, false, program);
|
||||
}
|
||||
@@ -975,7 +1017,7 @@ static void op_type_of(Program* program)
|
||||
static void op_round(Program* program)
|
||||
{
|
||||
float floatValue = programStackPopValue(program).asFloat();
|
||||
programStackPushInteger(program, static_cast<int>(lroundf(floatValue)));
|
||||
programStackPushInteger(program, lroundf(floatValue));
|
||||
}
|
||||
|
||||
enum BlockType {
|
||||
@@ -1135,7 +1177,6 @@ static void op_charcode(Program* program)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: opcodes should pop arguments off the stack in reverse order
|
||||
void sfallOpcodesInit()
|
||||
{
|
||||
// ref. https://github.com/sfall-team/sfall/blob/71ecec3d405bd5e945f157954618b169e60068fe/artifacts/scripting/sfall%20opcode%20list.txt#L145
|
||||
@@ -1244,7 +1285,9 @@ void sfallOpcodesInit()
|
||||
// 0x8172 - void set_world_map_pos(int x, int y)
|
||||
interpreterRegisterOpcode(0x8172, op_set_world_map_pos);
|
||||
// 0x8173 - int get_world_map_x_pos()
|
||||
interpreterRegisterOpcode(0x8173, op_get_world_map_x_pos);
|
||||
// 0x8174 - int get_world_map_y_pos()
|
||||
interpreterRegisterOpcode(0x8174, op_get_world_map_y_pos);
|
||||
|
||||
// 0x8175 - void set_dm_model(string name)
|
||||
// 0x8176 - void set_df_model(string name)
|
||||
|
||||
+9
-23
@@ -7,7 +7,6 @@
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
@@ -152,33 +151,20 @@ int textFontLoad(int font)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
snprintf(path, sizeof(path), "font%d.fon", font);
|
||||
|
||||
// NOTE: Original code is slightly different. It uses deep nesting and
|
||||
// unwinds everything from the point of failure.
|
||||
TextFontDescriptor* textFontDescriptor = &(gTextFontDescriptors[font]);
|
||||
textFontDescriptor->data = nullptr;
|
||||
textFontDescriptor->glyphs = nullptr;
|
||||
|
||||
File* stream = nullptr;
|
||||
char path[COMPAT_MAX_PATH];
|
||||
|
||||
// Try set language path first
|
||||
snprintf(path, sizeof(path), "text/%s/font%d.fon", settings.system.language.c_str(), font);
|
||||
stream = fileOpen(path, "rb");
|
||||
|
||||
// Fallback to English if needed
|
||||
if (stream == nullptr && compat_stricmp(settings.system.language.c_str(), ENGLISH) != 0) {
|
||||
snprintf(path, sizeof(path), "text/%s/font%d.fon", ENGLISH, font);
|
||||
stream = fileOpen(path, "rb");
|
||||
}
|
||||
|
||||
// fallback to original path
|
||||
if (stream == nullptr) {
|
||||
snprintf(path, sizeof(path), "font%d.fon", font);
|
||||
stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, "rb");
|
||||
int dataSize;
|
||||
if (stream == nullptr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
// NOTE: Original code reads entire descriptor in one go. This does not work
|
||||
// in x64 because of the two pointers.
|
||||
|
||||
Vendored
+1
-1
@@ -13,7 +13,7 @@ include(FetchContent)
|
||||
|
||||
FetchContent_Declare(sdl2
|
||||
GIT_REPOSITORY "https://github.com/libsdl-org/SDL"
|
||||
GIT_TAG "release-2.32.8"
|
||||
GIT_TAG "release-2.26.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
|
||||
Reference in New Issue
Block a user