mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
114
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
342fbdd3ae | ||
|
|
0adc9c9e77 | ||
|
|
af413125bd | ||
|
|
ea0afc84fa | ||
|
|
c663d79b97 | ||
|
|
eaa9091bcd | ||
|
|
76ab99cf73 | ||
|
|
bed9555f9a | ||
|
|
9c5294ca88 | ||
|
|
781d8ab282 | ||
|
|
afd99fa01b | ||
|
|
34ef1c2f26 | ||
|
|
fdc54cfd0b | ||
|
|
3e469ea8e8 | ||
|
|
ddefda32e7 | ||
|
|
0334b8de05 | ||
|
|
1cab275037 | ||
|
|
7eb269bab8 | ||
|
|
c18d7ab25e | ||
|
|
59bf337583 | ||
|
|
88179574e8 | ||
|
|
0733acfad7 | ||
|
|
a63aff09ce | ||
|
|
1388ca1f83 | ||
|
|
3d2aced2f7 | ||
|
|
1d6111b89f | ||
|
|
21c906cc5c | ||
|
|
a67fe7ead1 | ||
|
|
f0691d2c24 | ||
|
|
fb30648e2e | ||
|
|
216cbb3861 | ||
|
|
be63df4bf6 | ||
|
|
4cf35fd946 | ||
|
|
dd418ee0f5 | ||
|
|
eb5cc7be4f | ||
|
|
8c6f28b018 | ||
|
|
2e36030389 | ||
|
|
a88ca9f7e7 | ||
|
|
72d9ae85c8 | ||
|
|
a8f2de1a56 | ||
|
|
51b82ac1ac | ||
|
|
0d97222797 | ||
|
|
b30463ab01 | ||
|
|
9d932b0d2c | ||
|
|
8d76b9655c | ||
|
|
0e6c4d9684 | ||
|
|
02c5efac26 | ||
|
|
b7933f6b80 | ||
|
|
fcb1680db2 | ||
|
|
ea4d978bc1 | ||
|
|
22548a3c70 | ||
|
|
3dc89d49e2 | ||
|
|
822d5dfd7d | ||
|
|
879634bf9c | ||
|
|
795ef54d70 | ||
|
|
14b06d2dcc | ||
|
|
ed959edbbb | ||
|
|
7940ea791c | ||
|
|
3f270aa4cc | ||
|
|
b8769fded1 | ||
|
|
43d5b6028d | ||
|
|
da3f1cc426 | ||
|
|
a892461dac | ||
|
|
209d2d027b | ||
|
|
b8385d7775 | ||
|
|
a3c365f9fe | ||
|
|
87d4a4b8ca | ||
|
|
1aa53a4720 | ||
|
|
6bcf2952f6 | ||
|
|
e2927e1d0e | ||
|
|
bb839cd6c1 | ||
|
|
caa0e1bf1a | ||
|
|
f3759d07a5 | ||
|
|
604fde895f | ||
|
|
f46c391e5d | ||
|
|
1e45b0184b | ||
|
|
447ea23862 | ||
|
|
72786c4d43 | ||
|
|
3d3e47c9db | ||
|
|
a9726cab56 | ||
|
|
400aa4d8a3 | ||
|
|
599d3ab392 | ||
|
|
84336d4655 | ||
|
|
696e926177 | ||
|
|
30babd7e1f | ||
|
|
6ff0b411e4 | ||
|
|
9f623f3f3e | ||
|
|
d8bee457f4 | ||
|
|
fcabd63561 | ||
|
|
73c024c705 | ||
|
|
27da084b65 | ||
|
|
dfa610f352 | ||
|
|
a0a597725a | ||
|
|
7ae194a8ee | ||
|
|
7f7e103465 | ||
|
|
721e40f784 | ||
|
|
59c64451ff | ||
|
|
965f360578 | ||
|
|
3f79d79f25 | ||
|
|
cad023a73e | ||
|
|
7490c900b3 | ||
|
|
67a6119f34 | ||
|
|
aa036c574e | ||
|
|
a17d7fb7d5 | ||
|
|
8ed777ba83 | ||
|
|
7c182b66a6 | ||
|
|
f6320d3a66 | ||
|
|
ec2ecd17d9 | ||
|
|
de06827c01 | ||
|
|
e3437a8d0e | ||
|
|
f12babe525 | ||
|
|
cb990ac154 | ||
|
|
a3fc8d21be | ||
|
|
cc805db194 |
@@ -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
|
||||
|
||||
@@ -290,6 +290,7 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/sfall_arrays.h"
|
||||
"src/touch.cc"
|
||||
"src/touch.h"
|
||||
"src/scan_unimplemented.cc"
|
||||
)
|
||||
|
||||
if(IOS)
|
||||
|
||||
@@ -96,16 +96,32 @@ The main configuration file is `fallout2.cfg`. There are several important setti
|
||||
|
||||
The `sound` folder (with `music` folder inside) might be located either in `data` folder, or be in the Fallout folder. Update `music_path1` setting to match your hierarchy, usually it's `data/sound/music/` or `sound/music/`. Make sure it matches your path exactly (so it might be `SOUND/MUSIC/` if you've installed Fallout from CD). Music files themselves (with `ACM` extension) should be all uppercased, regardless of `sound` and `music` folders.
|
||||
|
||||
The second configuration file is `f2_res.ini`. Use it to change game window size, enable/disable fullscreen mode and configure IFACE settings (the control bar at the bottom of the game screen).
|
||||
Additionally, the [graphics] section provides options for fine tuning the appearence of the game. The included settings are:
|
||||
|
||||
```ini
|
||||
[MAIN]
|
||||
SCR_WIDTH=1280
|
||||
SCR_HEIGHT=720
|
||||
WINDOWED=1 ; 0 = fullscreen
|
||||
SCALE_2X=1 ; 0 = original scale, 1 = 2x - requires increasing the minimum resolution from 640x480 to 1280x960.
|
||||
```
|
||||
[graphics]
|
||||
fullscreen=0 ; 1 = fullscreeen, 0 = windowed
|
||||
game_height=480 ; main play area height
|
||||
game_width=640 ; main play area width
|
||||
scale2x=0 ; 0 = original scale, 1 = 2x - requires increasing the minimum resolution from 640x480 to 1280x960.
|
||||
splash_size=0 ; 0 = normal, 1 = aspect stretch, 2 = fullscreen stretch
|
||||
```
|
||||
|
||||
[IFACE]
|
||||
Recommendations:
|
||||
- **Desktops**: Use any size you see fit.
|
||||
- **Tablets**: Set these values to logical resolution of your device, for example iPad Pro 11 is 1668x2388 (pixels), but it's logical resolution is 834x1194 (points).
|
||||
- **Mobile phones**: Set height to 480, calculate width according to your device screen (aspect) ratio, for example Samsung S21 is 20:9 device, so the width should be 480 * 20 / 9 = 1067.
|
||||
|
||||
In time this graphcs settings will receive an in-game interface. For the time being it must be configured manually.
|
||||
|
||||
The second configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users.
|
||||
|
||||
For a sample ddraw.ini configuration file, containing all currently working settings use this link: [ddraw.ini](https://raw.githubusercontent.com/fallout2-ce/fallout2-ce/refs/heads/main/files/ddraw.ini)
|
||||
|
||||
Further, Fallout2-CE supports the following additional settings in ddraw.ini:
|
||||
|
||||
```
|
||||
[Misc]
|
||||
; if IFACE_BAR_MODE=0 - the bottom of the map view window sits at the top of the IFACE Bar.
|
||||
; if IFACE_BAR_MODE=1 - the bottom of the map view window extends to the base of the screen and is overlapped by the IFACE Bar.
|
||||
IFACE_BAR_MODE=0
|
||||
@@ -128,22 +144,11 @@ IFACE_BAR_SIDES_ORI=0
|
||||
;IFACE_BAR_WIDTH=640
|
||||
```
|
||||
|
||||
Recommendations:
|
||||
- **Desktops**: Use any size you see fit.
|
||||
- **Tablets**: Set these values to logical resolution of your device, for example iPad Pro 11 is 1668x2388 (pixels), but it's logical resolution is 834x1194 (points).
|
||||
- **Mobile phones**: Set height to 480, calculate width according to your device screen (aspect) ratio, for example Samsung S21 is 20:9 device, so the width should be 480 * 20 / 9 = 1067.
|
||||
|
||||
In time this stuff will receive in-game interface, right now you have to do it manually. For a sample f2_res.ini configuration file, containing all currently working settings use this link: [f2_res.ini](https://raw.githubusercontent.com/fallout2-ce/fallout2-ce/refs/heads/mainmenu/files/f2_res.ini)
|
||||
|
||||
*Note*: use of the IFACE_BAR settings requires the f2_res.dat file, which contains graphical assets. Various versions are available, but one compatible with the above f2_res.ini be found here: [f2_res.dat](https://github.com/fallout2-ce/fallout2-ce/raw/refs/heads/mainmenu/files/f2_res.dat)
|
||||
|
||||
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users.
|
||||
|
||||
For a sample ddraw.ini configuration file, containing all currently working settings use this link: [ddraw.ini](https://raw.githubusercontent.com/fallout2-ce/fallout2-ce/refs/heads/main/files/ddraw.ini)
|
||||
*Note*: use of the IFACE_BAR settings requires the f2_res.dat file, which contains graphical assets. Various versions are available, but one compatible with the above settings be found here: [f2_res.dat](https://github.com/fallout2-ce/fallout2-ce/raw/refs/heads/mainmenu/files/f2_res.dat)
|
||||
|
||||
## Quality of life benefits over vanilla Fallout
|
||||
|
||||
* High resolution support
|
||||
* Large game area support (through HiResMode=1 in ddraw.ini and game_height=480 and game_width=640 settings in fallout2.cfg)
|
||||
* Increased pathfinding nodes 5x for more accurate pathfinding
|
||||
* Ctrl-click to quickly move items when bartering, looting, or stealing
|
||||
* _a_ to select "all" when selecting item quantity
|
||||
|
||||
@@ -10,6 +10,33 @@
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
[Misc]
|
||||
|
||||
; if IFACE_BAR_MODE=0 - the bottom of the map view window sits at the top of the IFACE Bar.
|
||||
; if IFACE_BAR_MODE=1 - the bottom of the map view window extends to the base of the screen and is overlapped by the IFACE Bar.
|
||||
IFACE_BAR_MODE=0
|
||||
|
||||
;if IFACE_BAR_SIDE_ART=0 - Black, No Iface-bar side art used.
|
||||
;if IFACE_BAR_SIDE_ART=1 - Metal (grey) look Iface-bar side art used.
|
||||
;if IFACE_BAR_SIDE_ART=2 - Leather look Iface-bar side art used.
|
||||
;if IFACE_BAR_SIDE_ART=3-6 - Alternative Metal look Iface-bar side art used.
|
||||
;if IFACE_BAR_SIDE_ART=7 - Alternative Leather look Iface-bar side art used.
|
||||
;if IFACE_BAR_SIDE_ART=8 - Metal (brown) look Iface-bar side art used.
|
||||
IFACE_BAR_SIDE_ART=5
|
||||
|
||||
|
||||
;if IFACE_BAR_SIDES_ORI=0 - Iface-bar side graphics extend from the Iface-Bar to the Screen edges.
|
||||
;if IFACE_BAR_SIDES_ORI=1 - Iface-bar side graphics extend from the Screen edges to the Iface-Bar.
|
||||
IFACE_BAR_SIDES_ORI=1
|
||||
|
||||
;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.
|
||||
IFACE_BAR_WIDTH=800
|
||||
|
||||
;Adds Fallout 1 style travel/trail dots
|
||||
WorldMapTravelMarkers=0
|
||||
|
||||
;Prevents pausing music between map areas with the same music
|
||||
GaplessMusic=0
|
||||
|
||||
;Uncomment these lines to change the timers of how many days after the game starts Hakunin dream sequences will occur
|
||||
;MovieTimer_artimer1=5000
|
||||
;MovieTimer_artimer2=5000
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
#include "constants.h"
|
||||
#include "headers/define_extra.h" // For sfall functions if not in constants
|
||||
|
||||
procedure start;
|
||||
procedure description_proc; // For visual checks during game
|
||||
|
||||
variable new_tag1_id = -1;
|
||||
variable new_tag2_id = -1;
|
||||
variable max_tags_test_id = -1;
|
||||
|
||||
procedure start begin
|
||||
// Test Predefined Tags
|
||||
debug_msg("Testing Predefined Interface Tags...");
|
||||
|
||||
// SNEAK (0)
|
||||
debug_msg("Activating SNEAK (0)...");
|
||||
show_iface_tag(0);
|
||||
if (is_iface_tag_active(0)) then
|
||||
debug_msg("SNEAK is active. (Visual check needed)");
|
||||
else
|
||||
debug_msg("ERROR: SNEAK failed to activate or is_iface_tag_active(0) failed.");
|
||||
hide_iface_tag(0);
|
||||
if (not is_iface_tag_active(0)) then
|
||||
debug_msg("SNEAK is inactive.");
|
||||
else
|
||||
debug_msg("ERROR: SNEAK failed to deactivate or is_iface_tag_active(0) failed after hide.");
|
||||
|
||||
// POISONED (1) - Test requires making the player poisoned by other means to truly verify show/hide effect on game state
|
||||
// For now, just test is_iface_tag_active if it reflects direct calls or underlying state.
|
||||
// The opcodes show_iface_tag/hide_iface_tag are not meant to directly poison/cure the player for tags 1 and 2.
|
||||
// They are for custom tags or the specific PC flags (0,3,4). is_iface_tag_active *should* work for 1 and 2.
|
||||
debug_msg("Checking POISONED (1) (depends on game state): " + is_iface_tag_active(1));
|
||||
// Similar for RADIATED (2)
|
||||
debug_msg("Checking RADIATED (2) (depends on game state): " + is_iface_tag_active(2));
|
||||
|
||||
|
||||
// LEVEL (3)
|
||||
debug_msg("Activating LEVEL (3)...");
|
||||
show_iface_tag(3);
|
||||
if (is_iface_tag_active(3)) then
|
||||
debug_msg("LEVEL is active. (Visual check needed)");
|
||||
else
|
||||
debug_msg("ERROR: LEVEL failed to activate or is_iface_tag_active(3) failed.");
|
||||
hide_iface_tag(3);
|
||||
if (not is_iface_tag_active(3)) then
|
||||
debug_msg("LEVEL is inactive.");
|
||||
else
|
||||
debug_msg("ERROR: LEVEL failed to deactivate or is_iface_tag_active(3) failed after hide.");
|
||||
|
||||
// ADDICT (4)
|
||||
debug_msg("Activating ADDICT (4)...");
|
||||
show_iface_tag(4);
|
||||
if (is_iface_tag_active(4)) then
|
||||
debug_msg("ADDICT is active. (Visual check needed)");
|
||||
else
|
||||
debug_msg("ERROR: ADDICT failed to activate or is_iface_tag_active(4) failed.");
|
||||
hide_iface_tag(4);
|
||||
if (not is_iface_tag_active(4)) then
|
||||
debug_msg("ADDICT is inactive.");
|
||||
else
|
||||
debug_msg("ERROR: ADDICT failed to deactivate or is_iface_tag_active(4) failed after hide.");
|
||||
|
||||
debug_msg("Predefined tag tests complete.");
|
||||
debug_msg("---");
|
||||
|
||||
// Test Custom Tags
|
||||
debug_msg("Testing Custom Interface Tags...");
|
||||
|
||||
// Add first custom tag
|
||||
new_tag1_id = add_iface_tag;
|
||||
if (new_tag1_id != -1) then
|
||||
debug_msg("Added custom tag 1 with ID: " + new_tag1_id + " (expected 5 if first)");
|
||||
else
|
||||
debug_msg("ERROR: Failed to add custom tag 1.");
|
||||
return; // Stop if first add fails
|
||||
|
||||
// Show it
|
||||
show_iface_tag(new_tag1_id);
|
||||
if (is_iface_tag_active(new_tag1_id)) then
|
||||
debug_msg("Custom tag 1 is active. (Visual check: should show 'NEW' in green)");
|
||||
else
|
||||
debug_msg("ERROR: Custom tag 1 failed to activate or is_iface_tag_active failed.");
|
||||
|
||||
// Set its text and color
|
||||
set_iface_tag_text(new_tag1_id, "HELLO TAG1", 2); // Color 2 (White from issue description's reference)
|
||||
debug_msg("Set text for custom tag 1 to 'HELLO TAG1' (color white). (Visual check needed)");
|
||||
// Verify text length truncation (19 chars)
|
||||
set_iface_tag_text(new_tag1_id, "ThisIsAVeryLongTextStringIndeed", 3); // Color 3 (Yellow)
|
||||
debug_msg("Set text for custom tag 1 to 'ThisIsAVeryLongTextStringIndeed' (color yellow) - should be truncated. (Visual check needed)");
|
||||
|
||||
|
||||
// Add second custom tag
|
||||
new_tag2_id = add_iface_tag;
|
||||
if (new_tag2_id != -1) then
|
||||
debug_msg("Added custom tag 2 with ID: " + new_tag2_id + " (expected 6 if second)");
|
||||
else
|
||||
debug_msg("ERROR: Failed to add custom tag 2.");
|
||||
// Continue to test tag1 hide
|
||||
|
||||
if (new_tag2_id != -1) then
|
||||
show_iface_tag(new_tag2_id);
|
||||
set_iface_tag_text(new_tag2_id, "AWESOME", 6); // Color 6 (GoodColor/Green)
|
||||
debug_msg("Custom tag 2 ('AWESOME', green) should be active. (Visual check needed)");
|
||||
end
|
||||
|
||||
// Hide first custom tag
|
||||
hide_iface_tag(new_tag1_id);
|
||||
if (not is_iface_tag_active(new_tag1_id)) then
|
||||
debug_msg("Custom tag 1 is now inactive.");
|
||||
else
|
||||
debug_msg("ERROR: Custom tag 1 failed to deactivate.");
|
||||
|
||||
if (new_tag2_id != -1 and is_iface_tag_active(new_tag2_id)) then
|
||||
debug_msg("Custom tag 2 should still be active. (Visual check needed)");
|
||||
else if (new_tag2_id != -1) then
|
||||
debug_msg("ERROR: Custom tag 2 became inactive or failed check.");
|
||||
end
|
||||
|
||||
// Test max tags
|
||||
debug_msg("Attempting to add maximum custom tags (up to 126)...");
|
||||
variable i;
|
||||
variable current_tags = 2; // Assuming new_tag1_id and new_tag2_id were successful (IDs 5 and 6)
|
||||
if (new_tag1_id == -1) then current_tags = 0;
|
||||
if (new_tag1_id != -1 and new_tag2_id == -1) then current_tags = 1;
|
||||
|
||||
|
||||
for (i = current_tags; i < 126; i++) begin
|
||||
max_tags_test_id = add_iface_tag;
|
||||
if (max_tags_test_id == -1) then begin
|
||||
debug_msg("ERROR: Failed to add tag at iteration " + i + ". Max tags might be less than 126 or error in add_iface_tag.");
|
||||
break;
|
||||
end
|
||||
// Minimal show/set_text to ensure they are processed
|
||||
show_iface_tag(max_tags_test_id);
|
||||
set_iface_tag_text(max_tags_test_id, "Tag " + max_tags_test_id, 0); // Default color
|
||||
end
|
||||
if (i == 126) then
|
||||
debug_msg("Successfully added up to 126 custom tags (IDs 5 through 130). Last ID: " + max_tags_test_id);
|
||||
else
|
||||
debug_msg("Stopped adding tags at count " + i + ". Last successful ID: " + max_tags_test_id);
|
||||
end
|
||||
|
||||
// Test adding one more tag (should fail if 126 was the limit)
|
||||
max_tags_test_id = add_iface_tag;
|
||||
if (max_tags_test_id == -1) then
|
||||
debug_msg("Correctly failed to add tag beyond limit (127th attempt).");
|
||||
else
|
||||
debug_msg("ERROR: Added tag beyond 126 limit! ID: " + max_tags_test_id);
|
||||
end
|
||||
|
||||
// Test invalid IDs
|
||||
debug_msg("Testing invalid tag IDs...");
|
||||
show_iface_tag(-1); // Invalid
|
||||
show_iface_tag(1000); // Likely invalid (beyond max added)
|
||||
hide_iface_tag(-2);
|
||||
hide_iface_tag(1001);
|
||||
debug_msg("is_iface_tag_active(-3): " + is_iface_tag_active(-3));
|
||||
debug_msg("is_iface_tag_active(1002): " + is_iface_tag_active(1002));
|
||||
set_iface_tag_text(-4, "INVALID", 0);
|
||||
set_iface_tag_text(1003, "INVALID", 0);
|
||||
debug_msg("Invalid ID tests complete (check console for debug prints from C++).");
|
||||
|
||||
debug_msg("---");
|
||||
debug_msg("Interface Tag testing complete. Check console and game screen.");
|
||||
debug_msg("Will keep some tags active for 10 seconds for visual check then clear...");
|
||||
|
||||
// Keep some tags visible for a moment if run in game
|
||||
// This part is for easier visual checking if you load a game with this script.
|
||||
// For automated testing, the debug_msg output is key.
|
||||
if (game_loaded) then begin
|
||||
if (new_tag1_id != -1) then hide_iface_tag(new_tag1_id); // ensure it's hidden from previous test
|
||||
if (new_tag2_id != -1) then show_iface_tag(new_tag2_id); // ensure tag2 is visible
|
||||
set_iface_tag_text(new_tag2_id, "Testing Done!", 4); // Peanut butter color
|
||||
game_time_advance(game_ticks(10)); // Wait 10 seconds
|
||||
if (new_tag2_id != -1) then hide_iface_tag(new_tag2_id);
|
||||
debug_msg("Visual check period ended.");
|
||||
end
|
||||
end
|
||||
|
||||
// This can be used with `debug_map_scripts` or similar to run on map enter
|
||||
// procedure map_enter_p_proc begin call start; end
|
||||
// procedure map_update_p_proc begin call start; end // If you want it to run repeatedly (not recommended for this test script)
|
||||
|
||||
// For `description_proc` usage with `debug(F5)`:
|
||||
// Create a global script that calls `start` from `description_proc`
|
||||
// Example:
|
||||
// procedure description_proc begin
|
||||
// if (game_loaded) then call start;
|
||||
// end
|
||||
@@ -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
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "sfall.h"
|
||||
|
||||
procedure start begin
|
||||
// this isn't a unit test, just a way to easily test different values manually
|
||||
display_msg("Setting world map mult");
|
||||
set_map_time_multi(1.0);
|
||||
end
|
||||
@@ -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
|
||||
@@ -7,6 +7,17 @@ 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++;
|
||||
|
||||
|
||||
+18
-3
@@ -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);
|
||||
|
||||
+9
-18
@@ -168,6 +168,14 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
|
||||
int skipOpeningMovies = 0;
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies);
|
||||
|
||||
// load preferences before Splash screen to get proper brightness
|
||||
if (_init_options_menu() != 0) {
|
||||
debugPrint("Failed on init_options_menu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debugPrint(">init_options_menu\n");
|
||||
|
||||
if (!gIsMapper && skipOpeningMovies < 2) {
|
||||
showSplash();
|
||||
}
|
||||
@@ -341,13 +349,6 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
|
||||
|
||||
debugPrint(">scr_disable\t");
|
||||
|
||||
if (_init_options_menu() != 0) {
|
||||
debugPrint("Failed on init_options_menu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debugPrint(">init_options_menu\n");
|
||||
|
||||
if (endgameDeathEndingInit() != 0) {
|
||||
debugPrint("Failed on endgameDeathEndingInit");
|
||||
return -1;
|
||||
@@ -1469,17 +1470,7 @@ static void showSplash()
|
||||
}
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
|
||||
// TODO: Move to settings.
|
||||
Config config;
|
||||
if (configInit(&config)) {
|
||||
if (configRead(&config, "f2_res.ini", false)) {
|
||||
configGetInt(&config, "STATIC_SCREENS", "SPLASH_SCRN_SIZE", &size);
|
||||
}
|
||||
|
||||
configFree(&config);
|
||||
}
|
||||
int size = settings.graphics.splash_size;
|
||||
|
||||
int screenWidth = screenGetWidth();
|
||||
int screenHeight = screenGetHeight();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "db.h"
|
||||
#include "main.h"
|
||||
#include "platform_compat.h"
|
||||
#include "scan_unimplemented.h"
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#include <emscripten.h>
|
||||
@@ -66,6 +67,8 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY, "critter.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FALLOUTCE_DAT_KEY, "falloutce.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FALLOUTCE_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, ENGLISH);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SCROLL_LOCK_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_INTERRUPT_WALK_KEY, 1);
|
||||
@@ -74,6 +77,7 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_HASHING_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FREE_SPACE_KEY, 20480);
|
||||
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, 3);
|
||||
@@ -112,6 +116,16 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_LOAD_INFO_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY, 0);
|
||||
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_GAME_WIDTH, 640);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_GAME_HEIGHT, 480);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_SCALE_2X, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_SPLASH_SIZE, 0);
|
||||
configSetBool(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_FULLSCREEN, true);
|
||||
configSetBool(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_STRETCH_ENABLED, true);
|
||||
configSetBool(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_PRESERVE_ASPECT, true);
|
||||
configSetBool(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_HIGH_QUALITY, false);
|
||||
configSetBool(&gGameConfig, GAME_CONFIG_GRAPHICS_KEY, GAME_CONFIG_ENABLE_HIRES_STENCIL, true);
|
||||
|
||||
if (isMapper) {
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, "mapper");
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY, 0);
|
||||
@@ -179,9 +193,11 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
auto configChecker = ConfigChecker(gGameConfig, gGameConfigFilePath);
|
||||
// Read contents of `fallout2.cfg` into config. The values from the file
|
||||
// will override the defaults above.
|
||||
configRead(&gGameConfig, gGameConfigFilePath, false);
|
||||
configChecker.check(gGameConfig);
|
||||
|
||||
// Add key-values from command line, which overrides both defaults and
|
||||
// whatever was loaded from `fallout2.cfg`.
|
||||
|
||||
@@ -13,12 +13,15 @@ namespace fallout {
|
||||
#define GAME_CONFIG_SOUND_KEY "sound"
|
||||
#define GAME_CONFIG_MAPPER_KEY "mapper"
|
||||
#define GAME_CONFIG_DEBUG_KEY "debug"
|
||||
#define GAME_CONFIG_GRAPHICS_KEY "graphics"
|
||||
|
||||
#define GAME_CONFIG_EXECUTABLE_KEY "executable"
|
||||
#define GAME_CONFIG_MASTER_DAT_KEY "master_dat"
|
||||
#define GAME_CONFIG_MASTER_PATCHES_KEY "master_patches"
|
||||
#define GAME_CONFIG_CRITTER_DAT_KEY "critter_dat"
|
||||
#define GAME_CONFIG_CRITTER_PATCHES_KEY "critter_patches"
|
||||
#define GAME_CONFIG_FALLOUTCE_DAT_KEY "falloutce_dat"
|
||||
#define GAME_CONFIG_FALLOUTCE_PATCHES_KEY "falloutce_patches"
|
||||
#define GAME_CONFIG_LANGUAGE_KEY "language"
|
||||
#define GAME_CONFIG_SCROLL_LOCK_KEY "scroll_lock"
|
||||
#define GAME_CONFIG_INTERRUPT_WALK_KEY "interrupt_walk"
|
||||
@@ -28,6 +31,15 @@ namespace fallout {
|
||||
#define GAME_CONFIG_HASHING_KEY "hashing"
|
||||
#define GAME_CONFIG_SPLASH_KEY "splash"
|
||||
#define GAME_CONFIG_FREE_SPACE_KEY "free_space"
|
||||
#define GAME_CONFIG_GAME_WIDTH "game_width"
|
||||
#define GAME_CONFIG_GAME_HEIGHT "game_height"
|
||||
#define GAME_CONFIG_FULLSCREEN "fullscreen"
|
||||
#define GAME_CONFIG_SCALE_2X "scale2x"
|
||||
#define GAME_CONFIG_SPLASH_SIZE "splash_size"
|
||||
#define GAME_CONFIG_STRETCH_ENABLED "stretch_enabled"
|
||||
#define GAME_CONFIG_PRESERVE_ASPECT "preserve_aspect"
|
||||
#define GAME_CONFIG_HIGH_QUALITY "high_quality"
|
||||
#define GAME_CONFIG_ENABLE_HIRES_STENCIL "highres_stencil"
|
||||
#define GAME_CONFIG_TIMES_RUN_KEY "times_run"
|
||||
#define GAME_CONFIG_GAME_DIFFICULTY_KEY "game_difficulty"
|
||||
#define GAME_CONFIG_RUNNING_BURNING_GUY_KEY "running_burning_guy"
|
||||
|
||||
+8
-175
@@ -258,9 +258,6 @@ static unsigned char* gInterfaceWindowBuffer;
|
||||
// 0x59D40C
|
||||
static unsigned char gInterfaceActionPointsBarBackground[90 * 5];
|
||||
|
||||
CustomIndicatorBox gCustomIndicatorBoxes[MAX_CUSTOM_INDICATOR_BOXES];
|
||||
static int gActiveCustomTagsCount = 0;
|
||||
|
||||
// Should the game window stretch all the way to the bottom or sit at the top of the interface bar (default)
|
||||
bool gInterfaceBarMode = false;
|
||||
|
||||
@@ -584,13 +581,6 @@ int interfaceInit()
|
||||
// SFALL
|
||||
sidePanelsInit();
|
||||
|
||||
for (int i = 0; i < MAX_CUSTOM_INDICATOR_BOXES; ++i) {
|
||||
gCustomIndicatorBoxes[i].isActive = false;
|
||||
gCustomIndicatorBoxes[i].text[0] = '\0';
|
||||
gCustomIndicatorBoxes[i].color = 0;
|
||||
}
|
||||
gActiveCustomTagsCount = 0;
|
||||
|
||||
gInterfaceBarEnabled = true;
|
||||
gInterfaceBarInitialized = false;
|
||||
gInterfaceBarHidden = true;
|
||||
@@ -707,10 +697,6 @@ void interfaceFree()
|
||||
customInterfaceBarExit();
|
||||
|
||||
interfaceBarFree();
|
||||
// TODO: Consider if a dedicated function to free custom tag resources is needed.
|
||||
// For now, gCustomIndicatorBoxes is a global static array, so no dynamic memory to free.
|
||||
// Resetting active tags count.
|
||||
gActiveCustomTagsCount = 0;
|
||||
}
|
||||
|
||||
// 0x45E860
|
||||
@@ -2376,64 +2362,6 @@ int indicatorBarRefresh()
|
||||
windowRefresh(gIndicatorBarWindow);
|
||||
}
|
||||
|
||||
// START Custom Tag Handling in indicatorBarRefresh
|
||||
int customTagStartSlot = count; // Where to start adding custom tags in gIndicatorSlots
|
||||
for (int i = 0; i < gActiveCustomTagsCount && customTagStartSlot < INDICATOR_SLOTS_COUNT; ++i) {
|
||||
if (gCustomIndicatorBoxes[i].isActive) {
|
||||
// Using a convention: custom tag IDs are INDICATOR_COUNT + i
|
||||
gIndicatorSlots[customTagStartSlot++] = INDICATOR_COUNT + i;
|
||||
}
|
||||
}
|
||||
count = customTagStartSlot; // Update total count of displayed indicators
|
||||
|
||||
if (count > 1 && (gIndicatorSlots[0] < INDICATOR_COUNT || (count > 0 && gIndicatorSlots[0] >= INDICATOR_COUNT && gIndicatorSlots[1] < INDICATOR_COUNT))) { // Only sort if there are standard indicators or a mix
|
||||
// qsort might behave unexpectedly if all elements are custom tags due to how IDs are structured.
|
||||
// Custom tags are already ordered by their addition.
|
||||
// We only need to sort the standard part, or if custom tags are mixed in a way that needs sorting relative to standard ones.
|
||||
// For simplicity, if there are any standard tags, sort the whole array up to the original count.
|
||||
// Custom tags will be appended after this sorted list of standard tags.
|
||||
// This logic might need refinement if standard and custom tags need to interleave based on some criteria.
|
||||
// For now, custom tags are appended after standard ones.
|
||||
int standardIndicatorsCount = 0;
|
||||
for(int i=0; i < count; ++i) {
|
||||
if(gIndicatorSlots[i] < INDICATOR_COUNT) standardIndicatorsCount++;
|
||||
}
|
||||
if(standardIndicatorsCount > 1) {
|
||||
qsort(gIndicatorSlots, standardIndicatorsCount, sizeof(*gIndicatorSlots), indicatorBoxCompareByPosition);
|
||||
}
|
||||
// After sorting standard indicators, append custom ones.
|
||||
// This re-iterates the custom tag addition logic, but ensures they come after sorted standard tags.
|
||||
customTagStartSlot = standardIndicatorsCount;
|
||||
for (int i = 0; i < gActiveCustomTagsCount && customTagStartSlot < INDICATOR_SLOTS_COUNT; ++i) {
|
||||
if (gCustomIndicatorBoxes[i].isActive) {
|
||||
gIndicatorSlots[customTagStartSlot++] = INDICATOR_COUNT + i;
|
||||
}
|
||||
}
|
||||
count = customTagStartSlot;
|
||||
}
|
||||
|
||||
|
||||
if (gIndicatorBarWindow != -1 && count == 0) { // If no indicators (standard or custom), destroy window.
|
||||
windowDestroy(gIndicatorBarWindow);
|
||||
gIndicatorBarWindow = -1;
|
||||
} else if (count > 0) {
|
||||
if (gIndicatorBarWindow == -1) { // Create window if it doesn't exist and there are indicators
|
||||
Rect interfaceBarWindowRect;
|
||||
windowGetRect(gInterfaceBarWindow, &interfaceBarWindowRect);
|
||||
gIndicatorBarWindow = windowCreate(interfaceBarWindowRect.left,
|
||||
screenGetHeight() - INTERFACE_BAR_HEIGHT - INDICATOR_BOX_HEIGHT,
|
||||
(INDICATOR_BOX_WIDTH - INDICATOR_BOX_CONNECTOR_WIDTH) * count, // Adjust width based on actual count
|
||||
INDICATOR_BOX_HEIGHT,
|
||||
_colorTable[0],
|
||||
0);
|
||||
} else { // If window exists, adjust its width if necessary
|
||||
windowResize(gIndicatorBarWindow, (INDICATOR_BOX_WIDTH - INDICATOR_BOX_CONNECTOR_WIDTH) * count, INDICATOR_BOX_HEIGHT);
|
||||
}
|
||||
indicatorBarRender(count); // Render all (standard + custom)
|
||||
windowRefresh(gIndicatorBarWindow);
|
||||
}
|
||||
// END Custom Tag Handling in indicatorBarRefresh
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -2493,62 +2421,17 @@ static void indicatorBarRender(int count)
|
||||
int connectorWidthCompensation = INDICATOR_BOX_CONNECTOR_WIDTH;
|
||||
|
||||
for (int index = 0; index < count; index++) {
|
||||
int indicatorId = gIndicatorSlots[index];
|
||||
int indicator = gIndicatorSlots[index];
|
||||
IndicatorDescription* indicatorDescription = &(gIndicatorDescriptions[indicator]);
|
||||
|
||||
if (indicatorId >= INDICATOR_COUNT) { // This is a custom tag
|
||||
int customTagIndex = indicatorId - INDICATOR_COUNT;
|
||||
if (customTagIndex < gActiveCustomTagsCount && gCustomIndicatorBoxes[customTagIndex].isActive) {
|
||||
CustomIndicatorBox* customBox = &gCustomIndicatorBoxes[customTagIndex];
|
||||
|
||||
// Prepare a temporary IndicatorDescription-like structure or directly use customBox properties
|
||||
// For simplicity, let's assume a generic background for custom tags for now
|
||||
// and render text directly. A more advanced approach might involve
|
||||
// creating a temporary prerendered box similar to standard indicators.
|
||||
|
||||
// Fallback generic box (e.g. using SNEAK's background, but ideally a new generic one)
|
||||
// This is a placeholder. Proper handling would involve a generic custom box graphic.
|
||||
unsigned char* boxArt = gIndicatorDescriptions[INDICATOR_SNEAK].data; // Placeholder
|
||||
|
||||
// Create a temporary buffer for this custom tag's rendering
|
||||
unsigned char tempBoxData[INDICATOR_BOX_WIDTH * INDICATOR_BOX_HEIGHT];
|
||||
memcpy(tempBoxData, boxArt, INDICATOR_BOX_WIDTH * INDICATOR_BOX_HEIGHT);
|
||||
|
||||
// Render custom text onto this temporary buffer
|
||||
// Need to set font and color appropriately
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(101); // Assuming same font as standard indicators
|
||||
|
||||
// Calculate text position (centering)
|
||||
int textY = (INDICATOR_BOX_HEIGHT - fontGetLineHeight()) / 2; // Adjusted for actual box height
|
||||
int textX = (INDICATOR_BOX_WIDTH - fontGetStringWidth(customBox->text)) / 2;
|
||||
|
||||
// Ensure textX is not negative if text is too long (it should be truncated already, but as a safeguard)
|
||||
if (textX < 0) textX = 0;
|
||||
|
||||
fontDrawText(tempBoxData + INDICATOR_BOX_WIDTH * textY + textX,
|
||||
customBox->text,
|
||||
INDICATOR_BOX_WIDTH, // Max width for text area
|
||||
INDICATOR_BOX_WIDTH, // Stride
|
||||
customBox->color); // Use color from custom tag
|
||||
|
||||
fontSetCurrent(oldFont); // Restore original font
|
||||
|
||||
blitBufferToBufferTrans(tempBoxData + connectorWidthCompensation,
|
||||
INDICATOR_BOX_WIDTH - connectorWidthCompensation,
|
||||
INDICATOR_BOX_HEIGHT,
|
||||
INDICATOR_BOX_WIDTH, // Source buffer stride
|
||||
windowBuffer + x, windowWidth);
|
||||
}
|
||||
} else { // This is a standard indicator
|
||||
IndicatorDescription* indicatorDescription = &(gIndicatorDescriptions[indicatorId]);
|
||||
blitBufferToBufferTrans(indicatorDescription->data + connectorWidthCompensation,
|
||||
INDICATOR_BOX_WIDTH - connectorWidthCompensation,
|
||||
INDICATOR_BOX_HEIGHT,
|
||||
INDICATOR_BOX_WIDTH,
|
||||
windowBuffer + x, windowWidth);
|
||||
}
|
||||
blitBufferToBufferTrans(indicatorDescription->data + connectorWidthCompensation,
|
||||
INDICATOR_BOX_WIDTH - connectorWidthCompensation,
|
||||
INDICATOR_BOX_HEIGHT,
|
||||
INDICATOR_BOX_WIDTH,
|
||||
windowBuffer + x, windowWidth);
|
||||
|
||||
connectorWidthCompensation = 0;
|
||||
|
||||
unconnectedIndicatorsWidth += INDICATOR_BOX_WIDTH;
|
||||
x = unconnectedIndicatorsWidth - INDICATOR_BOX_CONNECTOR_WIDTH * connections;
|
||||
connections++;
|
||||
@@ -2770,54 +2653,4 @@ bool interface_get_current_attack_mode(int* hit_mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
int interfaceAddCustomTag() {
|
||||
if (gActiveCustomTagsCount >= MAX_CUSTOM_INDICATOR_BOXES) {
|
||||
return -1; // No slot available
|
||||
}
|
||||
// Find the first non-active slot conceptually, but since we use gActiveCustomTagsCount,
|
||||
// we just append to the current list of active ones.
|
||||
// The actual "slot" in gCustomIndicatorBoxes is gActiveCustomTagsCount.
|
||||
int tagId = gActiveCustomTagsCount;
|
||||
|
||||
gCustomIndicatorBoxes[tagId].isActive = true; // Mark as active conceptually
|
||||
// Default text/color can be set here if desired, e.g.:
|
||||
strncpy(gCustomIndicatorBoxes[tagId].text, "NEW", 19);
|
||||
gCustomIndicatorBoxes[tagId].text[19] = '\0';
|
||||
gCustomIndicatorBoxes[tagId].color = _colorTable[992]; // Default to green, like SNEAK
|
||||
|
||||
gActiveCustomTagsCount++;
|
||||
// Note: indicatorBarRefresh() is not called here;
|
||||
// it's typically called after a batch of changes or by show/hide.
|
||||
return tagId;
|
||||
}
|
||||
|
||||
void interfaceShowCustomTag(int tagId) {
|
||||
if (tagId < 0 || tagId >= gActiveCustomTagsCount) return;
|
||||
gCustomIndicatorBoxes[tagId].isActive = true;
|
||||
indicatorBarRefresh();
|
||||
}
|
||||
|
||||
void interfaceHideCustomTag(int tagId) {
|
||||
if (tagId < 0 || tagId >= gActiveCustomTagsCount) return;
|
||||
gCustomIndicatorBoxes[tagId].isActive = false;
|
||||
indicatorBarRefresh();
|
||||
}
|
||||
|
||||
bool interfaceIsCustomTagActive(int tagId) {
|
||||
if (tagId < 0 || tagId >= gActiveCustomTagsCount) return false;
|
||||
return gCustomIndicatorBoxes[tagId].isActive;
|
||||
}
|
||||
|
||||
void interfaceSetCustomTagText(int tagId, const char* text, int color) {
|
||||
if (tagId < 0 || tagId >= gActiveCustomTagsCount) return;
|
||||
|
||||
strncpy(gCustomIndicatorBoxes[tagId].text, text, 19);
|
||||
gCustomIndicatorBoxes[tagId].text[19] = '\0'; // Ensure null termination
|
||||
gCustomIndicatorBoxes[tagId].color = color;
|
||||
|
||||
if (gCustomIndicatorBoxes[tagId].isActive) {
|
||||
indicatorBarRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -12,22 +12,6 @@ namespace fallout {
|
||||
#define INTERFACE_BAR_WIDTH 640
|
||||
#define INTERFACE_BAR_HEIGHT 100
|
||||
|
||||
// Minimum radiation amount to display RADIATED indicator.
|
||||
#define RADATION_INDICATOR_THRESHOLD 65
|
||||
// Minimum poison amount to display POISONED indicator.
|
||||
#define POISON_INDICATOR_THRESHOLD 0
|
||||
|
||||
#define MAX_CUSTOM_INDICATOR_BOXES 126
|
||||
|
||||
typedef struct CustomIndicatorBox {
|
||||
char text[20]; // 19 chars + null terminator
|
||||
int color; // Could be an enum or int mapped to color values
|
||||
bool isActive;
|
||||
// Potentially add a specific ID if needed, though array index might suffice
|
||||
} CustomIndicatorBox;
|
||||
|
||||
extern CustomIndicatorBox gCustomIndicatorBoxes[MAX_CUSTOM_INDICATOR_BOXES];
|
||||
|
||||
typedef enum InterfaceItemAction {
|
||||
INTERFACE_ITEM_ACTION_DEFAULT = -1,
|
||||
INTERFACE_ITEM_ACTION_USE,
|
||||
@@ -79,12 +63,6 @@ bool indicatorBarShow();
|
||||
bool indicatorBarHide();
|
||||
bool interface_get_current_attack_mode(int* hit_mode);
|
||||
|
||||
int interfaceAddCustomTag();
|
||||
void interfaceShowCustomTag(int tagId);
|
||||
void interfaceHideCustomTag(int tagId);
|
||||
bool interfaceIsCustomTagActive(int tagId);
|
||||
void interfaceSetCustomTagText(int tagId, const char* text, int color);
|
||||
|
||||
unsigned char* customInterfaceBarGetBackgroundImageData();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
+22
-5
@@ -30,8 +30,8 @@ static char* _defaultFilename_(char* s);
|
||||
static int _outputStr(char* a1);
|
||||
static int _checkWait(Program* program);
|
||||
static char* programGetCurrentProcedureName(Program* s);
|
||||
static opcode_t stackReadInt16(unsigned char* data, int pos);
|
||||
static int stackReadInt32(unsigned char* data, int pos);
|
||||
opcode_t stackReadInt16(unsigned char* data, int pos);
|
||||
int stackReadInt32(unsigned char* data, int pos);
|
||||
static void stackWriteInt16(int value, unsigned char* data, int pos);
|
||||
static void stackWriteInt32(int value, unsigned char* data, int pos);
|
||||
static void stackPushInt16(unsigned char* data, int* pointer, int value);
|
||||
@@ -155,7 +155,7 @@ static int (*_outputFunc)(char*) = _outputStr;
|
||||
static int _cpuBurstSize = 10;
|
||||
|
||||
// 0x59E230
|
||||
static OpcodeHandler* gInterpreterOpcodeHandlers[OPCODE_MAX_COUNT];
|
||||
OpcodeHandler* gInterpreterOpcodeHandlers[OPCODE_MAX_COUNT];
|
||||
|
||||
// 0x59E78C
|
||||
static Program* gInterpreterCurrentProgram;
|
||||
@@ -276,7 +276,7 @@ static char* programGetCurrentProcedureName(Program* program)
|
||||
}
|
||||
|
||||
// 0x467290
|
||||
static opcode_t stackReadInt16(unsigned char* data, int pos)
|
||||
opcode_t stackReadInt16(unsigned char* data, int pos)
|
||||
{
|
||||
// TODO: The return result is probably short.
|
||||
opcode_t value = 0;
|
||||
@@ -286,7 +286,7 @@ static opcode_t stackReadInt16(unsigned char* data, int pos)
|
||||
}
|
||||
|
||||
// 0x4672A4
|
||||
static int stackReadInt32(unsigned char* data, int pos)
|
||||
int stackReadInt32(unsigned char* data, int pos)
|
||||
{
|
||||
int value = 0;
|
||||
value |= data[pos++] << 24;
|
||||
@@ -3346,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
|
||||
|
||||
@@ -241,6 +241,14 @@ ProgramValue programReturnStackPopValue(Program* program);
|
||||
int programReturnStackPopInteger(Program* program);
|
||||
void* programReturnStackPopPointer(Program* program);
|
||||
|
||||
opcode_t stackReadInt16(unsigned char* data, int pos);
|
||||
int stackReadInt32(unsigned char* data, int pos);
|
||||
|
||||
extern OpcodeHandler* gInterpreterOpcodeHandlers[OPCODE_MAX_COUNT];
|
||||
|
||||
ProgramValue programMakeString(Program* program, const char* str);
|
||||
ProgramValue programMakeInt(Program* program, int val);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* INTERPRETER_H */
|
||||
|
||||
+79
-57
@@ -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);
|
||||
}
|
||||
@@ -2286,23 +2303,23 @@ static void _inven_pickup(int buttonCode, int indexOffset)
|
||||
Rect rect;
|
||||
|
||||
switch (buttonCode) {
|
||||
case 1006:
|
||||
rect.left = 245;
|
||||
rect.top = 286;
|
||||
case 1006: // right hand slot
|
||||
rect.left = INVENTORY_RIGHT_HAND_SLOT_X;
|
||||
rect.top = INVENTORY_RIGHT_HAND_SLOT_Y;
|
||||
if (_inven_dude == gDude && interfaceGetCurrentHand() != HAND_LEFT) {
|
||||
itemInHand = item;
|
||||
}
|
||||
break;
|
||||
case 1007:
|
||||
rect.left = 154;
|
||||
rect.top = 286;
|
||||
case 1007: // left hand slot
|
||||
rect.left = INVENTORY_LEFT_HAND_SLOT_X;
|
||||
rect.top = INVENTORY_LEFT_HAND_SLOT_Y;
|
||||
if (_inven_dude == gDude && interfaceGetCurrentHand() == HAND_LEFT) {
|
||||
itemInHand = item;
|
||||
}
|
||||
break;
|
||||
case 1008:
|
||||
rect.left = 154;
|
||||
rect.top = 183;
|
||||
case 1008: // armor slot
|
||||
rect.left = INVENTORY_ARMOR_SLOT_X;
|
||||
rect.top = INVENTORY_ARMOR_SLOT_Y;
|
||||
break;
|
||||
default:
|
||||
// NOTE: Original code a little bit different, this code path
|
||||
@@ -2313,50 +2330,39 @@ static void _inven_pickup(int buttonCode, int indexOffset)
|
||||
break;
|
||||
}
|
||||
|
||||
// fix for disappearing/not disappearing inventory items
|
||||
if (itemIndex == -1 || _pud->items[_pud->length - (itemIndex + indexOffset + 1)].quantity <= 1) { // slots
|
||||
bool pickUpFromSlot = itemIndex == -1; // true if item was picked up from armor or weapon slots
|
||||
if (pickUpFromSlot || _pud->items[_pud->length - (itemIndex + indexOffset + 1)].quantity <= 1) {
|
||||
// erase background unless item is part of a 2+ quantity stack
|
||||
unsigned char* windowBuffer = windowGetBuffer(gInventoryWindow);
|
||||
int width, height;
|
||||
if (gInventoryRightHandItem != gInventoryLeftHandItem || item != gInventoryLeftHandItem) {
|
||||
int height;
|
||||
int width;
|
||||
if (itemIndex == -1) {
|
||||
if (pickUpFromSlot) {
|
||||
height = INVENTORY_LARGE_SLOT_HEIGHT;
|
||||
width = INVENTORY_LARGE_SLOT_WIDTH;
|
||||
} else {
|
||||
height = INVENTORY_SLOT_HEIGHT;
|
||||
width = INVENTORY_SLOT_WIDTH;
|
||||
}
|
||||
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + INVENTORY_WINDOW_WIDTH * rect.top + rect.left,
|
||||
width,
|
||||
height,
|
||||
INVENTORY_WINDOW_WIDTH,
|
||||
windowBuffer + INVENTORY_WINDOW_WIDTH * rect.top + rect.left,
|
||||
INVENTORY_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
rect.right = rect.left + width - 1;
|
||||
rect.bottom = rect.top + height - 1;
|
||||
} else {
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + INVENTORY_WINDOW_WIDTH * 286 + 154,
|
||||
180,
|
||||
61,
|
||||
INVENTORY_WINDOW_WIDTH,
|
||||
windowBuffer + INVENTORY_WINDOW_WIDTH * 286 + 154,
|
||||
INVENTORY_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
rect.left = 154;
|
||||
rect.top = 286;
|
||||
rect.right = rect.left + 180 - 1;
|
||||
rect.bottom = rect.top + 61 - 1;
|
||||
// seems to wipe both hand slots at once, but I don't know how to trigger this in game
|
||||
height = INVENTORY_LARGE_SLOT_HEIGHT;
|
||||
width = 180;
|
||||
rect.left = INVENTORY_LEFT_HAND_SLOT_X;
|
||||
rect.top = INVENTORY_LEFT_HAND_SLOT_Y;
|
||||
}
|
||||
rect.right = rect.left + width - 1;
|
||||
rect.bottom = rect.top + height - 1;
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + INVENTORY_WINDOW_WIDTH * rect.top + rect.left,
|
||||
width,
|
||||
height,
|
||||
INVENTORY_WINDOW_WIDTH,
|
||||
windowBuffer + INVENTORY_WINDOW_WIDTH * rect.top + rect.left,
|
||||
INVENTORY_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
windowRefreshRect(gInventoryWindow, &rect);
|
||||
} else {
|
||||
_display_inventory(indexOffset, itemIndex, INVENTORY_WINDOW_TYPE_NORMAL);
|
||||
@@ -2366,11 +2372,12 @@ static void _inven_pickup(int buttonCode, int indexOffset)
|
||||
_inven_update_lighting(nullptr);
|
||||
}
|
||||
|
||||
// SFALL: allow ctrl-click to unequip
|
||||
bool immediate = itemIndex == -1 && _ctrl_pressed();
|
||||
// allow ctrl-click to quick unequip or equip item
|
||||
bool immediate = _ctrl_pressed();
|
||||
_drag_item_loop(item, immediate);
|
||||
|
||||
if (immediate || mouseHitTestInWindow(gInventoryWindow, INVENTORY_SCROLLER_X, INVENTORY_SCROLLER_Y, INVENTORY_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_SCROLLER_Y)) {
|
||||
// drag into inventory list, or ctrl-click from slot
|
||||
if (pickUpFromSlot && (immediate || mouseHitTestInWindow(gInventoryWindow, INVENTORY_SCROLLER_X, INVENTORY_SCROLLER_Y, INVENTORY_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_SCROLLER_Y))) {
|
||||
int x;
|
||||
int y;
|
||||
mouseGetPositionInWindow(gInventoryWindow, &x, &y);
|
||||
@@ -2392,7 +2399,7 @@ static void _inven_pickup(int buttonCode, int indexOffset)
|
||||
}
|
||||
}
|
||||
|
||||
if (immediate || itemIndex == -1) {
|
||||
if (immediate || pickUpFromSlot) {
|
||||
// TODO: Holy shit, needs refactoring.
|
||||
*itemSlot = nullptr;
|
||||
if (itemAdd(_inven_dude, item, 1)) {
|
||||
@@ -2404,19 +2411,34 @@ static void _inven_pickup(int buttonCode, int indexOffset)
|
||||
gInventoryRightHandItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!pickUpFromSlot && immediate && itemGetType(item) != ITEM_TYPE_ARMOR) {
|
||||
// ctrl-click non-armor to quick-equip:
|
||||
// default to first empty hand, or left hand if both are full
|
||||
bool left = gInventoryLeftHandItem == nullptr || gInventoryRightHandItem != nullptr;
|
||||
if (left) {
|
||||
_switch_hand(item, &gInventoryLeftHandItem, itemSlot, buttonCode);
|
||||
} else {
|
||||
_switch_hand(item, &gInventoryRightHandItem, itemSlot, buttonCode);
|
||||
}
|
||||
|
||||
// drop in left hand slot
|
||||
} else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_LEFT_HAND_SLOT_X, INVENTORY_LEFT_HAND_SLOT_Y, INVENTORY_LEFT_HAND_SLOT_MAX_X, INVENTORY_LEFT_HAND_SLOT_MAX_Y)) {
|
||||
if (gInventoryLeftHandItem != nullptr && itemGetType(gInventoryLeftHandItem) == ITEM_TYPE_CONTAINER && gInventoryLeftHandItem != item) {
|
||||
_drop_into_container(gInventoryLeftHandItem, item, itemIndex, itemSlot, count);
|
||||
} else if (gInventoryLeftHandItem == nullptr || _drop_ammo_into_weapon(gInventoryLeftHandItem, item, itemSlot, count, buttonCode)) {
|
||||
_switch_hand(item, &gInventoryLeftHandItem, itemSlot, buttonCode);
|
||||
}
|
||||
|
||||
// drop in right hand slot
|
||||
} else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_RIGHT_HAND_SLOT_X, INVENTORY_RIGHT_HAND_SLOT_Y, INVENTORY_RIGHT_HAND_SLOT_MAX_X, INVENTORY_RIGHT_HAND_SLOT_MAX_Y)) {
|
||||
if (gInventoryRightHandItem != nullptr && itemGetType(gInventoryRightHandItem) == ITEM_TYPE_CONTAINER && gInventoryRightHandItem != item) {
|
||||
_drop_into_container(gInventoryRightHandItem, item, itemIndex, itemSlot, count);
|
||||
} else if (gInventoryRightHandItem == nullptr || _drop_ammo_into_weapon(gInventoryRightHandItem, item, itemSlot, count, buttonCode)) {
|
||||
_switch_hand(item, &gInventoryRightHandItem, itemSlot, itemIndex);
|
||||
}
|
||||
} else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_ARMOR_SLOT_X, INVENTORY_ARMOR_SLOT_Y, INVENTORY_ARMOR_SLOT_MAX_X, INVENTORY_ARMOR_SLOT_MAX_Y)) {
|
||||
|
||||
} else if ((immediate && itemGetType(item) == ITEM_TYPE_ARMOR) || mouseHitTestInWindow(gInventoryWindow, INVENTORY_ARMOR_SLOT_X, INVENTORY_ARMOR_SLOT_Y, INVENTORY_ARMOR_SLOT_MAX_X, INVENTORY_ARMOR_SLOT_MAX_Y)) {
|
||||
if (itemGetType(item) == ITEM_TYPE_ARMOR) {
|
||||
Object* currentArmor = gInventoryArmor;
|
||||
int itemAddResult = 0;
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ typedef struct Region {
|
||||
} Region;
|
||||
|
||||
void _regionSetBound(Region* region);
|
||||
Region* regionCreate(int a1);
|
||||
Region* regionCreate(int initialCapacity);
|
||||
void regionAddPoint(Region* region, int x, int y);
|
||||
void regionDelete(Region* region);
|
||||
void regionSetName(Region* region, const char* src);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "scan_unimplemented.h"
|
||||
#include "config.h"
|
||||
#include "dfile.h"
|
||||
#include "dictionary.h"
|
||||
#include "interpreter.h"
|
||||
#include "platform_compat.h"
|
||||
#include "scan_unimplemented_configs.h"
|
||||
#include "scan_unimplemented_opcodes.h"
|
||||
#include "scan_unimplemented_sfall.h"
|
||||
#include "scan_unimplemented_utils.h"
|
||||
#include "sfall_metarules.h"
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool gScanUnimplementedEnabled = false;
|
||||
|
||||
void scanUnimplementdParseCommandLineArguments(int argc, char** argv)
|
||||
{
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--scan-unimplemented") == 0) {
|
||||
gScanUnimplementedEnabled = true;
|
||||
printf("== Scanning of unimplemented is enabled == \n");
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user