Compare commits

...
Author SHA1 Message Date
cambragol a032915aa3 Update game_dialog.cc
Correct fix to match Fallout 2 vanilla assets.
2025-06-11 07:47:59 +09:00
Vasilii Rogin 8c6f28b018 Merge pull request #193 from fallout2-ce/update_sdl2_into_2_32_8
Update SDL2 into 2.32.8
2025-06-10 11:17:26 +03:00
Vasilii Rogin 2e36030389 Merge branch 'main' into update_sdl2_into_2_32_8 2025-06-09 23:19:02 +03:00
Mike Klaas a88ca9f7e7 Fix build warnings introduced by sfall opcodes/metarules (#201) 2025-06-09 08:26:47 -07:00
Mike Klaas 72d9ae85c8 sfall: get_ini_section(s) (#199)
Implements get_ini_section, needed for Et Tu, and get_ini_sections. Fixes buggy set_ini_setting.

Also includes tests for existing ini functions, and moves them all to sfall_init.cc. (opcodes and metarules files were getting long, and this matches sfall's structure)
2025-06-09 08:26:30 -07:00
cambragol b7933f6b80 Merge pull request #159 from fallout2-ce/inventory-character-display-fix
Fix Backgrounds on Spinning Characters
2025-06-09 17:03:46 +09:00
cambragol fcb1680db2 Merge pull request #144 from fallout2-ce/Localize-Fonts
Localize fonts
2025-06-09 17:03:23 +09:00
Vasilii Rogin 7767aabdce Merge pull request #197 from fallout2-ce/change_stencil_option
Change high resolution stencil option
2025-06-08 09:46:34 +03:00
Vasilii Rogin 9cb2b83db1 Merge pull request #185 from fallout2-ce/improve_tests_report
Use global variables and arrays to show tests summary
2025-06-07 20:45:11 +03:00
Vasilii Rogin 75ca12e07c Improve tests reporting 2025-06-07 19:06:48 +03:00
Vasilii Rogin f85e8ba67b Use lowercase for test results 2025-06-07 18:54:56 +03:00
Vasilii Rogin 07876ddaf9 Use arrays for sharing data between tests 2025-06-07 18:51:56 +03:00
Vasilii Rogin 7288f8eeb7 Merge remote-tracking branch 'fallout2-ce/main' into improve_tests_report 2025-06-07 18:27:45 +03:00
Vasilii Rogin 1a46d0f59f Make EnableHighResolutionStencil enabled by default in proper place 2025-06-07 17:40:11 +03:00
Vasilii Rogin 7c2dfa9af1 Change HiResMode into EnableHighResolutionStencil 2025-06-07 17:38:12 +03:00
Vasilii Rogin d681e7be69 Merge pull request #192 from fallout2-ce/toggle-active-hand
Add `toggle_active_hand` (sfall)
2025-06-07 12:23:06 +03:00
Mike Klaas 8294e15d3c Default to 800px interface bar (#181)
(still can be overriden by config)

Will fall back to 640px version if screen is narrower than 800px or asset doesn't exist
2025-06-06 21:07:11 -07:00
Mike Klaas 4278d1a1d0 fix crash 2025-06-06 20:54:24 -07:00
Vasilii Rogin b8769fded1 Bump CI cache 2025-06-06 21:30:38 +03:00
Vasilii Rogin 43d5b6028d Update SDL2 into 2.32.8 2025-06-06 21:21:53 +03:00
Mike Klaas b2675ad1ac Add toggle_active_hand (sfall) 2025-06-06 00:34:36 -07:00
Vasilii Rogin 5dafa019c9 Merge pull request #190 from fallout2-ce/all-opcodes
Reformat sfall opcode list to contain all opcodes
2025-06-03 20:10:25 +03:00
Mike Klaas 8888fc46d6 Reformat sfall opcode list to contain all opcodes
This pulls in every sfall opcode, including param types and returnval.  It is grouped in a more "natural" order (i.e. what the sfall doc lists) instead of numeric order, which helps see which opcodes from a logical group are missing
2025-06-03 08:56:16 -07:00
Mike Klaas 001bdbee5c Add all remaining sfall math functions (#187)
* Add all remaining sfall math functions

* Fix op_round
2025-06-03 08:06:29 -07:00
Vasilii Rogin 190906bb5f Use global variables to show tests summary 2025-06-02 18:31:40 +03:00
cambragol 721e40f784 Merge branch 'main' into inventory-character-display-fix 2025-05-31 09:56:20 +09:00
github-actions[bot] 67a6119f34 chore: auto-format with clang-format 2025-05-26 07:36:34 +00:00
cambragol aa036c574e Update inventory.cc
Added some comments regarding which window is which
2025-05-26 16:36:06 +09:00
github-actions[bot] a17d7fb7d5 chore: auto-format with clang-format 2025-05-25 11:07:47 +00:00
cambragol 8ed777ba83 Merge branch 'main' into Localize-Fonts 2025-05-25 19:53:57 +09:00
cambragol ec2ecd17d9 Update inventory.cc
First pass on fix for #148 

Adds correct blitting backgrounds for behind the spinning character
2025-05-23 15:13:07 +09:00
cambragol e3437a8d0e Merge branch 'main' into Localize-Fonts 2025-05-21 09:26:38 +09:00
cambragol f12babe525 Update text_font.cc 2025-05-20 14:45:07 +09:00
cambragol cb990ac154 Update font_manager.cc 2025-05-20 14:44:33 +09:00
cambragol a3fc8d21be Update text_font.cc 2025-05-20 14:36:33 +09:00
cambragol cc805db194 Update font_manager.cc 2025-05-20 14:35:37 +09:00
25 changed files with 1099 additions and 262 deletions
+5 -5
View File
@@ -87,7 +87,7 @@ jobs:
uses: actions/cache@v4
with:
path: os/android/app/.cxx
key: android-cmake-v2
key: android-cmake-v100
- 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-v5
key: ios-cmake-v100
- name: Configure
run: |
@@ -183,7 +183,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: linux-${{ matrix.arch }}-cmake-v3
key: linux-${{ matrix.arch }}-cmake-v100
- name: Configure
run: |
@@ -288,7 +288,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: macos-cmake-v6
key: macos-cmake-v100
- name: Configure
run: |
@@ -337,7 +337,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: windows-${{ matrix.arch }}-cmake-v3
key: windows-${{ matrix.arch }}-cmake-v100
- name: Configure
shell: cmd
+1 -1
View File
@@ -125,7 +125,7 @@ IFACE_BAR_SIDES_ORI=0
;This will increase the width of the interface bar expanding the area used to display text.
;if IFACE_BAR_WIDTH=640 - Interface bar will remain at it's original width.
;if IFACE_BAR_WIDTH=800 - Interface bar will use 800pix wide asset from f2_res.dat.
IFACE_BAR_WIDTH=640
;IFACE_BAR_WIDTH=640
```
Recommendations:
+2 -1
View File
@@ -4,7 +4,8 @@
[Main]
;Set to one to hide areas outside map bounds when using higher than 640x480 resolution, and to zero to disable
;HiResMode=1
;EnableHighResolutionStencil=1
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Misc]
+1 -1
View File
@@ -166,7 +166,7 @@ procedure array_test_suite begin
display_msg("All tests finished with "+test_suite_errors+" errors.");
call report_test_results("Arrays");
call report_test_results("arrays");
end
+69
View File
@@ -0,0 +1,69 @@
#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
+71
View File
@@ -0,0 +1,71 @@
#include "test_utils.h"
#include "sfall.h"
procedure start begin
display_msg("Testing math functions...");
call assertFloat("sin(0)", sin(0), 0.0);
call assertFloat("sin(PI/2)", sin(1.5708), 1.0);
call assertFloat("sin(PI)", sin(3.1416), 0.0);
call assertFloat("sin(-PI/2)", sin(-1.5708), -1.0);
call assertFloat("cos(0)", cos(0), 1.0);
call assertFloat("cos(PI/2)", cos(1.5708), 0.0);
call assertFloat("cos(PI)", cos(3.1416), -1.0);
call assertFloat("cos(-PI)", cos(-3.1416), -1.0);
call assertFloat("tan(0)", tan(0), 0.0);
call assertFloat("tan(PI/4)", tan(0.7854), 1.0);
call assertFloat("tan(-PI/4)", tan(-0.7854), -1.0);
call assertFloat("arctan(0, 1)", arctan(0, 1), 0.0);
call assertFloat("arctan(1, 1)", arctan(1, 1), 0.7854);
call assertFloat("arctan(-1, 1)", arctan(-1, 1), -0.7854);
call assertFloat("arctan(1, 0)", arctan(1, 0), 1.5708);
call assertFloat("log(1)", log(1), 0.0);
call assertFloat("log(e)", log(2.7183), 1.0);
call assertFloat("log(10)", log(10), 2.3026);
call assertFloat("exponent(0)", exponent(0), 1.0);
call assertFloat("exponent(1)", exponent(1), 2.7183);
call assertFloat("exponent(2)", exponent(2), 7.3891);
call assertFloat("exponent(-1)", exponent(-1), 0.3679);
call assertEquals("ceil(2.1)", ceil(2.1), 3);
call assertEquals("ceil(2.0)", ceil(2.0), 2);
call assertEquals("ceil(-2.1)", ceil(-2.1), -2);
call assertEquals("ceil(-2.9)", ceil(-2.9), -2);
call assertEquals("floor2(2.1)", floor2(2.1), 2);
call assertEquals("floor2(2.9)", floor2(2.9), 2);
call assertEquals("floor2(-2.1)", floor2(-2.1), -3);
call assertEquals("floor2(-2.9)", floor2(-2.9), -3);
call assertEquals("2^3", 2^3, 8);
call assertEquals("4^2", 4^2, 16);
call assertEquals("3^0", 3^0, 1);
call assertFloat("2^-1", 2^-1, 0); // note: int truncation
call assertFloat("2^-1", 2^-1.0, 0.5);
call assertFloat("4^0.5", 4^0.5, 2.0);
call assertFloat("8^(1/3)", 8^(1.0/3.0), 2.0);
call assertFloat("2.5^2", 2.5^2, 6.25);
call assertEquals("round(2.3)", round(2.3), 2);
call assertEquals("round(2.5)", round(2.5), 3);
call assertEquals("round(2.7)", round(2.7), 3);
call assertEquals("round(-2.3)", round(-2.3), -2);
call assertEquals("round(-2.5)", round(-2.5), -3);
call assertEquals("round(-2.7)", round(-2.7), -3);
call assertEquals("round(0.0)", round(0.0), 0);
call assertEquals("round(1.0)", round(1.0), 1);
call assertEquals("round(<int>)", round(1), 1);
call assertFloat("sin(arctan(1, 1))", sin(arctan(1, 1)), 0.7071);
call assertFloat("cos(arctan(1, 1))", cos(arctan(1, 1)), 0.7071);
call assertFloat("log(ceil(2.7))", log(ceil(2.7)), 1.0986);
call assertFloat("exponent(log(5))", exponent(log(5)), 5.0);
call report_test_results("math");
end
+15
View File
@@ -0,0 +1,15 @@
#include "test_utils.h"
#include "sfall.h"
procedure start begin
// TODO: move this to a more suitable place, once we have more functions implemented
// These are in the "Other" category in the sfall documentation
display_msg("Testing misc functions...");
variable hand := active_hand;
toggle_active_hand;
call assertEquals("active_hand toggled", active_hand, 1 - hand);
toggle_active_hand;
call assertEquals("active_hand toggled", active_hand, hand);
call report_test_results("misc");
end
+1 -1
View File
@@ -154,7 +154,7 @@ procedure start begin
call test_derived_base_stat_critter(dude_obj);
call test_derived_base_stat_critter(closest_critter);
call report_test_results("Stats");
call report_test_results("stats");
// set_pc_base_stat(STAT_lu, 10);
+16
View File
@@ -0,0 +1,16 @@
[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
+85 -9
View File
@@ -7,14 +7,25 @@ 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++;
if (a != b or typeof(a) != typeof(b)) then begin
display_msg("Assertion failed \""+desc+"\": "+a+" != "+b);
display_msg("FAIL \""+desc+"\": "+a+" != "+b);
test_suite_errors ++;
end else if (test_suite_verbose) then begin
display_msg("Assert \""+desc+"\" ok");
display_msg("ok \""+desc+"\"");
end
end
@@ -22,10 +33,23 @@ procedure assertNotEquals(variable desc, variable a, variable b) begin
test_suite_assertions++;
if (a == b) then begin
display_msg("Assertion failed \""+desc+"\": "+a+" == "+b);
display_msg("FAIL \""+desc+"\": "+a+" == "+b);
test_suite_errors ++;
end else if (test_suite_verbose) then begin
display_msg("Assert \""+desc+"\" ok");
display_msg("ok \""+desc+"\"");
end
end
procedure assertFloat(variable desc, variable a, variable b, variable tolerance = 0.001) begin
test_suite_assertions++;
variable diff := abs(a - b);
if (diff > tolerance) then begin
display_msg("FAIL \""+desc+"\": "+a+" != "+b+" (diff: "+diff+")");
test_suite_errors ++;
end else if (test_suite_verbose) then begin
display_msg("ok \""+desc+"\"");
end
end
@@ -35,12 +59,64 @@ procedure report_test_results(variable desc) begin
(test_suite_assertions-test_suite_errors) + "/" + test_suite_assertions + "");
display_msg("================");
if (test_suite_errors == 0) then begin
float_msg(dude_obj, desc + " tests passed " +
(test_suite_assertions-test_suite_errors) + "/" +test_suite_assertions + "!", FLOAT_MSG_GREEN);
#define GL_VAR_TESTING_INFO_ARRAY_ID "TestArra"
#define TEST_ARR_IDENTIFIER_KEY "__testing_info_array__"
variable arr_id = get_sfall_global_int(GL_VAR_TESTING_INFO_ARRAY_ID);
if arr_id != 0 then begin
// Let's check that it is actually our testing array
if array_key(arr_id, -1) == 0 then begin
// It is not even associative array, so it is not our testing array
arr_id = 0;
end else begin
if arr_id[TEST_ARR_IDENTIFIER_KEY] != 1 then begin
// It is associative array, but it is not our testing array
arr_id = 0;
end
end
end
if arr_id == 0 then begin
arr_id = create_array(-1, 0);
arr_id[TEST_ARR_IDENTIFIER_KEY] = 1;
set_sfall_global(GL_VAR_TESTING_INFO_ARRAY_ID, arr_id);
end
#define TEST_SUITES "Test suites"
#define TEST_ASSERTIONS_TOTAL "Tests assertings total"
#define TEST_ASSERTIONS_FAILED "Tests assertings failed"
if arr_id[TEST_SUITES] == 0 then begin
arr_id[TEST_SUITES] = create_array(-1, 0);
end
//set_sfall_global("test_suite_errors", test_suite_errors);
arr_id[TEST_ASSERTIONS_TOTAL] += test_suite_assertions;
arr_id[TEST_ASSERTIONS_FAILED] += test_suite_errors;
arr_id[TEST_SUITES][desc] += 1;
variable total_suites_names = "";
variable total_suites_count = 0;
variable key, item;
foreach (key: item in arr_id[TEST_SUITES]) begin
total_suites_count += item;
if (total_suites_names != "") then begin
total_suites_names += ", ";
end
total_suites_names += key;
end
variable assertions_stats_str = (arr_id[TEST_ASSERTIONS_TOTAL]-arr_id[TEST_ASSERTIONS_FAILED]) +
"/" + arr_id[TEST_ASSERTIONS_TOTAL];
if (arr_id[TEST_ASSERTIONS_FAILED] == 0) then begin
float_msg(dude_obj, "Tested " + total_suites_count + " cases: " + total_suites_names + ". " +
assertions_stats_str + " assertions passed!", FLOAT_MSG_GREEN);
end else begin
float_msg(dude_obj, desc + " failed " + test_suite_errors + " tests from " +
test_suite_assertions + "!", FLOAT_MSG_RED);
float_msg(dude_obj, "Tested " + total_suites_count + " cases: " + total_suites_names + ". " +
assertions_stats_str + " assertions passed", FLOAT_MSG_RED);
end
end
+18 -3
View File
@@ -6,6 +6,7 @@
#include "color.h"
#include "db.h"
#include "memory_manager.h"
#include "settings.h"
// The maximum number of interface fonts.
#define INTERFACE_FONT_MAX (16)
@@ -119,11 +120,25 @@ static int interfaceFontLoad(int font_index)
InterfaceFontDescriptor* fontDescriptor = &(gInterfaceFontDescriptors[font_index]);
char path[56];
snprintf(path, sizeof(path), "font%d.aaf", font_index);
File* stream = nullptr;
File* stream = fileOpen(path, "rb");
// 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
if (stream == nullptr) {
return -1;
snprintf(path, sizeof(path), "font%d.aaf", font_index);
stream = fileOpen(path, "rb");
if (stream == nullptr) {
return -1;
}
}
int fileSize = fileGetSize(stream);
+2 -2
View File
@@ -3241,12 +3241,12 @@ int _gdialog_barter_create_win()
backgroundFrmImage.unlock();
// TRADE
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 40, 162, 14, 14, -1, -1, -1, KEY_LOWERCASE_M, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 40, 163, 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, 161, 14, 14, -1, -1, -1, KEY_LOWERCASE_T, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
_gdialog_buttons[1] = buttonCreate(gGameDialogWindow, 583, 162, 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);
+1 -1
View File
@@ -291,7 +291,7 @@ static FrmImage _yellowLightFrmImage;
static FrmImage _redLightFrmImage;
int gInterfaceBarContentOffset = 0;
int gInterfaceBarWidth = -1;
int gInterfaceBarWidth = 800; // will fall back to 640 if screen width is too narrow or asset is absent
bool gInterfaceBarIsCustom = false;
static Art* gCustomInterfaceBarBackground = nullptr;
+17 -9
View File
@@ -3183,15 +3183,6 @@ int programStackPopInteger(Program* program)
return programValue.integerValue;
}
float programStackPopFloat(Program* program)
{
ProgramValue programValue = programStackPopValue(program);
if (programValue.opcode != VALUE_TYPE_INT) {
programFatalError("float expected, got %x", programValue.opcode);
}
return programValue.floatValue;
}
char* programStackPopString(Program* program)
{
ProgramValue programValue = programStackPopValue(program);
@@ -3355,4 +3346,21 @@ 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
+4 -1
View File
@@ -230,7 +230,6 @@ void programStackPushPointer(Program* program, void* value);
ProgramValue programStackPopValue(Program* program);
int programStackPopInteger(Program* program);
float programStackPopFloat(Program* program);
char* programStackPopString(Program* program);
void* programStackPopPointer(Program* program);
@@ -242,6 +241,10 @@ 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 */
+26 -9
View File
@@ -2078,34 +2078,51 @@ 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;
rect.left = 426; // loot right cha window (or container)
rect.top = 39;
Fid = 114;
sourceXOffset = 538;
} else {
rect.left = 297;
rect.left = 297; // inventory data window? ?not used?
rect.top = 37;
Fid = 48;
sourceXOffset = 229;
}
} else {
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) {
rect.left = 48;
rect.left = 48; // loot left cha window
rect.top = 39;
} else {
rect.left = 176;
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.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() + INVENTORY_LOOT_WINDOW_WIDTH * rect.top + rect.left,
blitBufferToBuffer(backgroundFrmImage.getData() + backgroundFrmImage.getWidth() * rect.top + rect.left + sourceXOffset,
INVENTORY_BODY_VIEW_WIDTH,
INVENTORY_BODY_VIEW_HEIGHT,
INVENTORY_LOOT_WINDOW_WIDTH,
backgroundFrmImage.getWidth(),
windowBuffer + windowPitch * rect.top + rect.left,
windowPitch);
}
+2
View File
@@ -70,6 +70,8 @@ bool sfallConfigInit(int argc, char** argv)
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_AUTO_OPEN_DOORS, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, 0);
configSetBool(&gSfallConfig, SFALL_CONFIG_MAIN_KEY, SFALL_CONFIG_ENABLE_HIRES_STENCIL, true);
char path[COMPAT_MAX_PATH];
char* executable = argv[0];
char* ch = strrchr(executable, '\\');
+1
View File
@@ -77,6 +77,7 @@ namespace fallout {
#define SFALL_CONFIG_CONFIG_FILE "ConfigFile"
#define SFALL_CONFIG_PATCH_FILE "PatchFile"
#define SFALL_CONFIG_HIRES_MODE "HiResMode"
#define SFALL_CONFIG_ENABLE_HIRES_STENCIL "EnableHighResolutionStencil"
#define SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART "PipBoyAvailableAtGameStart"
#define SFALL_CONFIG_USE_WALK_DISTANCE "UseWalkDistance"
#define SFALL_CONFIG_AUTO_OPEN_DOORS "AutoOpenDoors"
+190 -17
View File
@@ -1,10 +1,14 @@
#include "sfall_ini.h"
#include <algorithm>
#include <cstring>
#include <cstdio> // for snprintf
#include <cstring> // for strncpy, strlen
#include "config.h"
#include "debug.h"
#include "interpreter.h"
#include "platform_compat.h"
#include "sfall_arrays.h"
namespace fallout {
@@ -68,6 +72,38 @@ 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) {
@@ -111,22 +147,7 @@ bool sfall_ini_get_string(const char* triplet, char* value, size_t size)
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 loaded = sfall_load_named_ini_file(fileName, &config);
// NOTE: Sfall's `GetIniSetting` returns error code (-1) only when it cannot
// parse triplet. Otherwise the default for string settings is empty string.
@@ -194,4 +215,156 @@ 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
+10
View File
@@ -1,6 +1,9 @@
#ifndef FALLOUT_SFALL_INI_H_
#define FALLOUT_SFALL_INI_H_
#include "config.h"
#include "dictionary.h"
#include "interpreter.h"
#include <cstddef>
namespace fallout {
@@ -20,6 +23,13 @@ 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_ */

Some files were not shown because too many files have changed in this diff Show More