Compare commits

...
Author SHA1 Message Date
jirik2077 33926467b2 remove the false guards 2026-07-16 06:04:16 +02:00
Mike Klaas c6e7c5997f more debugging 2026-07-14 22:35:44 -07:00
Mike Klaas b224eae3f7 remove heuristic logging 2026-07-14 22:35:43 -07:00
Mike Klaas 7d3766c5de Two crash fixes (#552)
* Sfall fix for > 160 maps for automap code (RPU triggers this)
* Logic fix for action menu, where actionIndex was incremented unconditionally and could go out of bounds.  This was a regression from vanilla
2026-07-14 22:35:43 -07:00
jirik2077 1b453fad7f Support for EPA gender change operation (#542)
* support for EPA gender change operation

* fix unintented return
2026-07-14 22:35:43 -07:00
Mike Klaas c81f065920 Implement Sfall npc level cap (10) (#545)
Also, fix off-by-one error that can cause proto corruption
2026-07-14 22:35:43 -07:00
Mike Klaas cd46f79b98 Implement real_dude_obj (#537)
This is used by scripts which are party-control aware.  Implementing this means they won't crash and should still work properly
2026-07-14 22:35:43 -07:00
jirik2077 0f25e3df3b Fix division by zero in objectExamineFunc (#541) 2026-07-14 22:35:43 -07:00
Mike Klaas 1265f3287c Increase animation cap (Sfall) (#539)
Fixes #538
2026-07-14 22:35:43 -07:00
jirik2077 8397c6d245 fix healing revision op_tokenize (#536) 2026-07-14 22:35:43 -07:00
Mike Klaas 2e4774c37d Normalize ini paths that start with \ to game root (#501)
* Normalize ini paths that start with `\` to game root

Sfall does this, and we were missing it. https://github.com/sfall-team/sfall/blob/master/sfall/Modules/Scripting/Handlers/IniFiles.cpp#L61-L78

An example is InventoryFilter, which starts its ini path with `\`: https://github.com/rotators/InventoryFilter/blob/master/source/gl_InvenFilter.ssl#L19

* Normalize cache key
2026-07-14 22:35:43 -07:00
Mike Klaas 4c2fbd0cc2 Fix possible double-free in animation_free (#513)
* Fix possible double-free in animation_free

Port of roughly: https://github.com/cambragol/fission-ce/commit/7fafbb11c7daf5fe7f5ae05b92a3bffaaaa7b5a4

Not sure how to trigger it in CE, but seems plausibly possible
2026-07-14 22:35:43 -07:00
Mike Klaas f58023bc2f Fix "Uncontrolled format string" Code Scanning results (#512)
* Fix "Uncontrolled format string" Code Scanning results

https://github.com/fallout2-ce/fallout2-ce/security/code-scanning

* PR comments

* fix missing early return in programExecuteProcedureAsync path
2026-07-14 22:35:43 -07:00
Mike Klaas eb3d0a28e6 Party member equipment management (#528)
Add equipment slots to the companion loot screen.

Items can be equipped directly from player or companion inventory. This also allows switching between party members so you can manage all companion's inventories easily. Does not allow equipping items that would otherwise be disallowed.

Also:

    Calls HOOK_UNWIELD when adding/removing equipment, meaning mods like npc armor work
    Uses HOOK_CANUSE for weapon use checks

Ctrl-click to equip is not implemented since it already transfers items between the two inventories. I tried making it work only for equippable items (and otherwise transfer), but that felt awkward and random. Ctrl-click unequip is implemented.
2026-07-14 22:35:43 -07:00
Mike Klaas cba4a7b711 Support Sfall extra animation codes (#535)
Fixes #534
2026-07-14 22:35:43 -07:00
Mike Klaas 733232c20d Fix blue/green channel mixup in PCX reading (#500) 2026-07-14 22:35:43 -07:00
jirik2077andgithub-actions[bot] 0542cdb3ae Handle unimplemented fs_copy/fs_create/fs_find more gracefully in scripts (#530)
* handle unimplemented fs_copy/fs_create/fs_find more gracefully from the script point of view

* chore: auto-format with clang-format

* moved to sfall_opcodes

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-14 22:35:43 -07:00
Mike Klaas 52a664f6df Add offset tracking to --scan-unimplemented (#517)
* Add offset tracking to --scan-unimplemented

* Add a bunch of missing opcodes
* Hardcode a list of implemented hooks to avoid filtering a long list of hooks that are already done
* Add tracking of specific offsets accessed in unsafe scripting so we can plan replacements

Sample output

```
OFFSET write_int (0x81d1 - 0x1d1 - 465):
  0x5190f8 (5345528):
    - ./mods/InventoryFilter.dat/scripts/gl_InvenFilter_debug.int
    - ./mods/InventoryFilter.dat/scripts/release_gl_InvenFilter.int
  0x59e95c (5892444):
    - ./mods/InventoryFilter.dat/scripts/gl_InvenFilter_debug.int
    - ./mods/InventoryFilter.dat/scripts/release_gl_InvenFilter.int
```

Then we can corrlated it with source:

```
// 0x5190F8 curr_rot
static int gInventoryWindowDudeRotation = 0;
```

* PR feedback
2026-07-14 22:35:43 -07:00
github-actions[bot] 488cf0b8e4 chore: auto-format with clang-format 2026-07-09 16:36:27 +00:00
Mike Klaas 0e5e6ce7fa Extra heap safety 2026-07-09 13:35:58 -03:00
Mike Klaas 40e7a2167b highlighting logging 2026-07-09 09:57:31 -03:00
jirik2077 16143aef74 art/cache debug info 2026-07-09 06:45:17 +02:00
jirik2077 723a8e4abb an extra heap related debugPrint 2026-07-09 06:26:20 +02:00
Mike Klaas bf8a001924 minor fix 2026-07-09 00:10:58 -03:00
Mike Klaas 212b86751c Minor heap fixes and debugging
While investigating https://github.com/fallout2-ce/fallout2-ce/issues/529, I found a few bugs to fix. Nothing that would cause corruption, though.  I added some basic safety checks here that might be useful to narrow down the crash
2026-07-08 23:45:30 -03:00
Mike Klaas 24199e916d Grow ability for ce-dat-tool to extract a list of files (#506)
* Grow ability for `ce-dat-tool` to extract a list of files

This is needed for Et Tu installation, which selectively extracts files from fo1's master.dat.  (It doesn't work if everything is extracted)

* cache entry list to avoid O(n) cost when extracting many files
2026-07-04 14:58:44 -07:00
Mike Klaas 6ee5d04f7c Deobfuscate COMBAT_STATE_* bitmask (#524) 2026-07-04 14:58:16 -07:00
jirik2077 a380a3c9e1 Merge pull request #525 from fallout2-ce/stackable_empty_weapons_fix
QoL Stackable empty weapons regardless of the previous ammo type.
2026-07-04 16:39:39 +02:00
jirik2077 c79bf5eb23 move before the ammo/money handling 2026-07-04 06:57:34 +02:00
jirik2077 7290bb4262 added the sameFlags also for empty weapon check 2026-07-04 06:32:15 +02:00
jirik2077 9a84b67ed3 comment typo fix 2026-07-03 22:54:20 +02:00
jirik2077 949458a559 empty weapons of the same type are considered the same even the ammo was originally different 2026-07-03 22:18:08 +02:00
Mike Klaas 2183c3914c Fix Goris robe/disrobe (#492)
Currently it isn't playing at all, since we're not doing renderPresent() during the animation loop.

This fixes that.  Also, it optimizes the time the animation takes by starting it before the interface combat start/end animation.  This saves half a second or so.

* Remove hidden items when trading with Goris

Also, fix the fix to allow looting with Goris
2026-07-02 19:41:16 -07:00
Mike Klaas c7e187d275 Add art drawing metarules (#507)
interface_art_draw
draw_image{_scaled}
art_frame_data
2026-07-02 19:28:14 -07:00
Mike Klaas 2c495a46ca Update gl_highlighting from sfall (#518)
* Update gl_highlighting from sfall

Pulls in NovaRain's improvement to distinguish empty containers here: https://github.com/sfall-team/sfall/commit/9fa679293269fde377cda1fc97c4668bce741af2x

* Pick up sfall fix: https://github.com/sfall-team/sfall/commit/ca3df3347d2776b83bd6edb480b8b4845731af63#diff-c2e89ad914e1b203c22d4003fb6949828e299bf9fbe46ad7ccd5a2476c053b4d
2026-07-02 06:53:05 -07:00
Mike Klaas 2ed355f8ca Fix initialized variable comparisons and fileReadInt32 (#519)
* Fix initialized variable comparisons and fileReadInt32

Also pulled in an Sfall fix for this function

Fixes https://github.com/fallout2-ce/fallout2-ce/issues/516

* approximate bytes read in xfileRead
2026-07-02 06:52:26 -07:00
Mike Klaas f3caac0bda Refactor inventory.cc (#491)
This adds major simplification and deduplication to inventory.cc, including the start of an "InventoryScroller" class that can manage inventory events without duplicate handling everywhere.  This is needed as we add more complexity to the page.
2026-06-29 21:38:38 -07:00
Mike Klaas fec5df8981 Fix missing argument to format string (#511)
* Add program->name to scriptError

This is @jirik2077 's fix for a segfault, and I agree with the fix.

Fixes #509
2026-06-29 20:41:50 -07:00
Mike Klaas 4715e0b349 Add in-game HELP menu (#498)
Also: fix alignment of skilldex, menu, charset buttons to look visibly depressed.
2026-06-28 22:23:07 -07:00
Mike Klaas 8ce4361365 Windows opcodes (#505)
* create_win / hide_window
* get_window_attributes
* get_window_under_mouse
* set_window_flag
* dialog_message
* display_stats
2026-06-28 15:18:06 -07:00
Mike Klaas 2447593e9c Fix crash due to corrupted whoHitMe (#493)
* Fix crash due to corrupted `whoHitMe`

It's possible for some object's `whoHitMe` to contain `-1`.  It's supposed to be resolved to `nullptr`, but doesn't reliably happen in all cases, esp outside of combat.  The main fix here is to normalize to nullptr when loading the object, instead of just map load, or combat paths.

At some point I thought the problem might have been attacker being a non-critter.  Added some guards against that regardless.  Also, found several bugs and messiness in `apply_damage` which are now fixed.

Fixes https://github.com/alexbatalov/fallout2-ce/issues/368
2026-06-24 20:36:55 -07:00
Mike Klaas 26d7b632fc HOOK_MOVECOST (#496) 2026-06-17 06:11:08 +00:00
c6818f0849 Fix ddraw.ini -> game.cfg migration on unix-y systems (#497)
* Fix ddraw.ini -> game.cfg migration on unix-y systems

We were using `compat_splitpath` on a windows path.  We want to work on windows paths, so that's good.  This fixes compat_splitpath so that it works with both folder separators.  Also tweak `compat_makepath` to recognize both, for consistency.

This means that filenames with `\` will be broken, but I think we can (and should) live with that)

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore: auto-format with clang-format

* fix

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-16 22:48:46 -07:00
Mike Klaas 84cac43da1 HOOK_ITEMDAMAGE (#494)
* HOOK_ITEMDAMAGE
2026-06-16 22:22:53 -07:00
Mike Klaas 261b54c603 Implement unwield_slot (#488)
* Implement `unwield_slot`

This one was surprisingly subtle.  Supports many game modes and handles things differently depending on game mode.
2026-06-08 22:25:46 -07:00
Vlad K 46b89abbd8 Merge pull request #490 from fallout2-ce/feature/mapper-edg
Mapper EDG support
2026-06-08 23:17:25 +02:00
phobos2077 1ee64988bc Guard against saving EDG when saving SAV maps in gameplay 2026-06-07 20:53:35 +02:00
Vlad KandCopilot Autofix powered by AI c78ba885d7 Guard against using dev_path out of mapper
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-07 20:44:34 +02:00
Vlad K 8c98a15ef6 sfall: get_ini_config + config cache (#489)
* sfall: get_ini_config + config cache

* Code review fixes and comment standardization
2026-06-06 22:34:37 +00:00
98 changed files with 4790 additions and 1806 deletions
+3 -2
View File
@@ -66,8 +66,9 @@ Available commands:
1. `./<BUILD_DIR>/ce-dat-tool <archive.dat> list [pattern]`
2. `ce-dat-tool <archive.dat> info [pattern]`
3. `ce-dat-tool <archive.dat> extract [--lower] <output-dir> [pattern]`
4. `ce-dat-tool <archive.dat> cat <entry>`
5. `ce-dat-tool create <input-dir> <archive.dat>`
4. `ce-dat-tool <archive.dat> extract [--lower] (--file-list|--files-from) <list-file> <output-dir>`
5. `ce-dat-tool <archive.dat> cat <entry>`
6. `ce-dat-tool create <input-dir> <archive.dat>`
Use `--lower` with `extract` when you want every extracted file and directory name forced to lowercase.
For example:
+4 -4
View File
@@ -144,13 +144,13 @@ In time this stuff will receive in-game interface, right now you have to do it m
* Expanded 4-row barter screen
* Expanded AP bar
* Party members can loot and barter in place of PC
* Increased pathfinding nodes 5x for more accurate pathfinding
* Increased pathfinding nodes 5x for more accurate pathfinding, and use accurate path length for walk vs run
* Ctrl-click to quickly move items when bartering, looting, or stealing
* _a_ to select "all" when selecting item quantity
* _a_ to `Take All` when looting
* When bartering, caps default to the right amount to balance the trade (if possible)
* _a_ to select "all" when selecting item quantity, and for `Take All` when looting
* When bartering, caps default to the right amount to balance the trade
* Music continues playing between maps
* Auto open doors
* Integrated "HELP" menu
* 44.1 kHz stereo sound/music supported, in .ogg and .wav format as well as legacy .acm
* Last used save slot is remembered
* Item/Corpse/Container/Critter highlighting (configure using [mods/sfall-mods.ini](https://github.com/sfall-team/sfall/blob/master/artifacts/config_files/sfall-mods.ini))
+11 -9
View File
@@ -53,7 +53,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Perks and traits | set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | not implemented | - |
| Virtual file system | fs_create<br>fs_copy<br>fs_find<br>fs_read/write_*<br>fs_delete<br>fs_size<br>fs_pos<br>fs_seek<br>fs_resize | đźš« | Open an issue if you have a use case for these |
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
| Maps and encounters | in_world_map<br>force_encounter<br>force_encounter_with_flags<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
| Maps and encounters | in_world_map<br>force_encounter{_with_flags}<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
| Maps and encounters / Worldmap | get_world_map_x/y_pos<br>set_world_map_pos | âś… | - |
| Audio | play_sfall_sound<br>stop_sfall_sound | âś… | `play_sfall_sound` currently supports `.acm`, `.wav`, `.ogg` formats, and can load from `.dat` archives. `.mp3` is not yet supported. |
| Combat / Weapons and ammo | get/set_weapon_ammo_pid<br>get/set_weapon_ammo_count | âś… | - |
@@ -63,7 +63,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Lists | list_begin<br>list_next<br>list_end<br>list_as_array<br>party_member_list | âś… | - |
| Explosions | set_attack_explosion_pattern<br>set_attack_explosion_art<br>set_attack_explosion_radius<br>set_attack_is_explosion_fire<br>set_explosion_radius<br>set_dynamite_damage<br>set_plastic_damage<br>get_explosion_damage<br>set_explosion_max_targets<br>item_make_explosive | âś… except item_make_explosive | - |
| Animations | reg_anim_combat_check<br>reg_anim_destroy<br>reg_anim_animate_and_hide<br>reg_anim_light<br>reg_anim_change_fid<br>reg_anim_take_out<br>reg_anim_turn_towards<br>reg_anim_callback<br>reg_anim_animate_and_move | âś… except reg_anim_callback | - |
| Art and appearance | art_exists<br>refresh_pc_art<br>art_cache_clear<br>set_hero_race<br>set_hero_style | implemented: art_exists, refresh_pc_art, art_cache_clear | - |
| Art and appearance | art_exists<br>art_frame_data<br>refresh_pc_art<br>art_cache_clear | âś… | - |
| Tiles and paths | get_tile_fid<br>tile_under_cursor<br>tile_light<br>tile_get_objs<br>tile_refresh_display<br>obj_blocking_tile<br>tile_by_position<br>get_tile_ground_fid<br>get_tile_roof_fid<br>obj_blocking_line<br>path_find_to<br>objects_in_radius | âś… | - |
| Utility | sprintf<br>typeof<br>atoi<br>atof | âś… | - |
| Utility / Strings | string_split<br>substr<br>strlen<br>charcode<br>get_string_pointer<br>string_find<br>string_find_from<br>string_format<br>string_format_array<br>string_replace<br>string_to_case<br>string_compare | âś… | `get_string_pointer` is deprecated and intentionally omitted. |
@@ -75,18 +75,20 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | âś… except available_global_script_types | - |
| Combat | attack_is_aimed<br>block_combat<br>force_aimed_shots<br>disable_aimed_shots<br>get_attack_type<br>get/set_bodypart_hit_modifier<br>combat_data<br>get/set/reset_critical_table<br>get_last_target<br>get_last_attacker<br>set_critter_burst_disable<br>get/set_critter_current_ap<br>set_spray_settings<br>get/set_combat_free_move | âś… except block_combat, force_aimed_shots, disable_aimed_shots, get_last_target, get_last_attacker, set_spray_settings | - |
| Car | set_car_current_town<br>car_gas_amount<br>set_car_intface_art | implemented: all except set_car_intface_art | - |
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window<br>create_message_window | implemented: only message_box, get_text_width, show_window, create_message_window | - |
| Interface / Windows and images | interface_art_draw<br>interface_print<br>draw_image{_scaled}<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window<br>create_message_window | âś… except interface_print, interface_overlay | - |
| Interface / Outline | outlined_object<br>get_outline<br>set_outline | âś… | - |
| Interface / Main interface | intface_is_hidden<br>intface_redraw<br>intface_hide<br>intface_show<br>set_quest_failure_value | implemented: only intface_redraw | `intface_redraw` only supports the zero-argument form; the optional-argument path is explicitly unimplemented. |
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | implemented: critter_inven_obj2, item_weight | - |
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | âś… except get_current_inven_size | - |
| Interface / Cursor | get/set_cursor_mode | âś… | - |
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… except get_ini_config, get_ini_config_db | `modified_ini` is intentionally omitted as deprecated. |
| Objects and scripts | set_self<br>set_dude_obj<br>real_dude_obj<br>remove_script<br>get/set_script<br>obj_is_carrying_obj<br>loot_obj<br>dialog_obj<br>obj_under_cursor<br>get/set_object_data<br>get/set_flags<br>set_unique_id<br>set_scr_name<br>obj_is_openable<br>get/set_proto_data<br>get_object_ai_data | implemented: set_self, get/set/remove_script, obj_is_carrying_obj, loot_obj, dialog_obj, obj_under_cursor, get_object_data, get_flags, set_flags, set_unique_id, obj_is_openable, get_proto_data, set_proto_data | - |
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… | `modified_ini` is intentionally omitted as deprecated. |
| Objects and scripts | set_self<br>set_dude_obj<br>real_dude_obj<br>remove_script<br>get/set_script<br>obj_is_carrying_obj<br>loot_obj<br>dialog_obj<br>obj_under_cursor<br>get/set_object_data<br>get/set_flags<br>set_unique_id<br>set_scr_name<br>obj_is_openable<br>get/set_proto_data<br>get_object_ai_data | implemented: set_self, real_dude_obj, get/set/remove_script, obj_is_carrying_obj, loot_obj, dialog_obj, obj_under_cursor, get_object_data, get_flags, set_flags, set_unique_id, obj_is_openable, get_proto_data, set_proto_data | get_object_data assumes raw memory offsets which may return different values in CE |
| Other / Game management | set_movie_path<br>stop/resume_game<br>mark_movie_played<br>game_loaded<br>get_game_mode<br>get_uptime<br>signal_close_game | implemented: game_loaded, get_game_mode, get_uptime, signal_close_game | - |
| Gameplay tweaks | set_pickpocket_max<br>set_hit_chance_max<br>set_xp_mod<br>set_critter_hit_chance_mod<br>set_base_hit_chance_mod<br>set_hp_per_level_mod<br>gdialog_get_barter_mod<br>get/set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>get/set_inven_ap_cost<br>set_drugs_data<br>get_kill_counter<br>mod_kill_counter<br>set_pipboy_available | implemented: gdialog_get_barter_mod, get/set_unspent_ap{_perk}_bonus, get/set_inven_ap_cost | - |
| NPCs | inc_npc_level<br>get_npc_level<br>npc_engine_level_up | not implemented | - |
| Other | get_year<br>set_dm/df_model<br>active_hand<br>toggle_active_hand<br>get/set_viewport_x/y<br>hero_select_win<br>get_light_level<br>message_str_game<br>sneak_success<br>create_spatial<br>unwield_slot<br>add_g_timer_event<br>add_extra_msg_file<br>get_metarule_table<br>metarule_exist<br>remove_timer_event<br>spatial_radius | implemented: get_year, active_hand, toggle_active_hand, get_light_level, message_str_game, add_extra_msg_file, metarule_exist | `input_funcs_available`, `nb_create_char` are deprecated in sfall and intentionally absent in CE. `add_extra_msg_file` does not support the explicit `fileNumber` form in CE. |
| Hero Appearance | set_dm/df_model<br>hero_select_win<br>set_hero_race<br>set_hero_style | not implemented | - |
| Events | add_g_timer_event<br>remove_timer_event<br>create_spatial<br>spatial_radius | not implemented | - |
| Other | get_year<br>active_hand<br>toggle_active_hand<br>get/set_viewport_x/y<br>get_light_level<br>message_str_game<br>sneak_success<br>unwield_slot<br>add_extra_msg_file<br>get_metarule_table<br>metarule_exist<br> | âś… except get/set_viewport_x/y, sneak_success | `input_funcs_available`, `nb_create_char` are deprecated in sfall and intentionally absent in CE. `add_extra_msg_file` does not support the explicit `fileNumber` form in CE. |
## Hooks
@@ -104,8 +106,8 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| UseObj | `HOOK_USEOBJ` | âś… | CE notes an sfall-matching inconsistency around return code `2` behavior between interface contexts. |
| RemoveInvenObj | `HOOK_REMOVEINVENOBJ` | đźš« | - |
| BarterPrice | `HOOK_BARTERPRICE` | âś… | - |
| MoveCost | `HOOK_MOVECOST` | đźš« | - |
| ItemDamage | `HOOK_ITEMDAMAGE` | đźš« | - |
| ItemDamage | `HOOK_ITEMDAMAGE` | âś… | - |
| MoveCost | `HOOK_MOVECOST` | âś… | - |
| AmmoCost | `HOOK_AMMOCOST` | âś… | Requires `check_weapon_ammo_cost=1` if you want pre-attack ammo validation to respect per-shot/per-round overrides. |
| KeyPress | `HOOK_KEYPRESS` | âś… | Third hook arg is currently `0`; CE doesn't use VK codes. |
| MouseClick | `HOOK_MOUSECLICK` | âś… | - |
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.
+1
View File
@@ -0,0 +1 @@
{0}{}{HELP}
+1
View File
@@ -0,0 +1 @@
{0}{}{AIDE}
+1
View File
@@ -0,0 +1 @@
{0}{}{HILFE}
+1
View File
@@ -0,0 +1 @@
{0}{}{AIUTO}
+1
View File
@@ -0,0 +1 @@
{0}{}{POMOC}
+1
View File
@@ -0,0 +1 @@
{0}{}{AJUDA}
+1
View File
@@ -0,0 +1 @@
{0}{}{ПОМОЩЬ}
+1
View File
@@ -0,0 +1 @@
{0}{}{AYUDA}
+2
View File
@@ -130,6 +130,8 @@ inventory_columns=2
;Set to 1 to scale only the main menu background image to fit the screen while maintaining aspect ratio.
;Set to 2 to also scale the main menu button panel, red buttons, and button labels with the menu art.
main_menu_scale_mode=1
;Set to 1 to show a Help option in the in-game options menu which opens the F1 help screen.
in_game_menu_help=1
[qol]
+16
View File
@@ -1,5 +1,6 @@
#include "lib.arrays.h" // For arrays_equal, len_array, etc.
#include "test_utils.h" // For assertEquals, VALTYPE_STR, report_test_results
#include "sfall.h"
// To test: copy test.ini into the game folder before running
procedure ini_test_suite begin
@@ -29,6 +30,15 @@ procedure ini_test_suite begin
call assertEquals("TC2 get_ini_setting empty int", get_ini_setting("test.ini|ValidSection|EmptyValue"), 0);
call assertEquals("TC2 get_ini_string empty string", get_ini_string("test.ini|ValidSection|EmptyValue"), "");
// Regression: sfall resolves leading-backslash paths relative to the game root.
result_array := get_ini_section("\\test.ini", "ValidSection");
call assertEquals("TC2B Size", len_array(result_array), 3);
call assertEquals("TC2B Key1", result_array["Key1"], "Value1");
call assertEquals("TC2B get_ini_setting int", get_ini_setting("\\test.ini|ValidSection|Key2"), 2);
call assertEquals("TC2B get_ini_string string", get_ini_string("\\test.ini|ValidSection|Key1"), "Value1");
result_array := get_ini_sections("\\test.ini");
call assertEquals("TC2B get_ini_sections size", len_array(result_array), 3);
// INI file not found
result_array := get_ini_section("nonexistent.ini", "AnySection");
call assertEquals("TC3 Size", len_array(result_array), 0);
@@ -65,6 +75,12 @@ procedure ini_test_suite begin
call assertEquals("TC7 get_ini_sections size", len_array(result_array), 3);
call assertTrue("TC7 get_ini_sections", scan_array(result_array, "TestMisc") >= 0);
// get_ini_config
result_array := get_ini_config_db("config\\config_from_db.cfg");
call assertEquals("TC8 get_ini_config_db size", len_array(result_array), 2);
call assertTrue("TC8 get_ini_config ValidSection", result_array.ValidSection != 0);
call assertEquals("TC8 get_ini_config_db ValidValue", result_array.ValidSection.ValidKey, "ValidValue");
call report_test_results("ini");
end
+43
View File
@@ -0,0 +1,43 @@
#include "sfall.h"
#include "dik.h"
#include "define_lite.h"
#include "define_extra.h"
#include "test_utils.h"
procedure run_unwield_slot_test(variable slot, variable slotName) begin
variable equippedItem := critter_inven_obj2(dude_obj, slot);
if (equippedItem == 0) then begin
display_msg("unwield_slot " + slotName + ": slot is empty");
return;
end
unwield_slot(dude_obj, slot);
call assertTrue("unwield_slot clears " + slotName + " slot", critter_inven_obj2(dude_obj, slot) == 0);
call report_test_results("unwield_slot");
end
procedure keypress_handler begin
variable pressed := get_sfall_arg_at(0);
variable key := get_sfall_arg_at(1);
if (not pressed) then return;
if (key == DIK_J) then begin
call run_unwield_slot_test(INVEN_TYPE_WORN, "armor");
end else if (key == DIK_K) then begin
call run_unwield_slot_test(INVEN_TYPE_RIGHT_HAND, "right");
end else if (key == DIK_L) then begin
call run_unwield_slot_test(INVEN_TYPE_LEFT_HAND, "left");
end
end
procedure start begin
if (not game_loaded) then return;
call assertEquals("unwield_slot metarule exists", metarule_exist("unwield_slot"), 1);
call assertEquals("critter_inven_obj2 metarule exists", metarule_exist("critter_inven_obj2"), 1);
display_msg("unwield_slot manual test ready: open inventory or barter, then press J armor, K right, L left");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
+98
View File
@@ -0,0 +1,98 @@
#include "sfall.h"
#include "dik.h"
#include "lib.arrays.h"
#include "../test_utils.h"
variable itemdamage_mode := 0;
variable itemdamage_seen := 0;
variable itemdamage_last_min := 0;
variable itemdamage_last_max := 0;
variable itemdamage_last_hit_mode := 0;
variable itemdamage_last_is_melee_weapon := 0;
variable itemdamage_last_weapon_pid := -1;
variable itemdamage_last_weapon_name := "<none>";
procedure itemdamage_mode_name begin
if (itemdamage_mode == 1) then return "fixed-42";
if (itemdamage_mode == 2) then return "range-30-30";
return "engine";
end
procedure itemdamage_weapon_name(variable weapon) begin
if (weapon == 0) then return "<unarmed>";
return obj_name(weapon);
end
procedure itemdamage_handler begin
variable
args := get_sfall_args,
weapon := args[2];
call assertEquals("itemdamage arg count", len_array(args), 6);
call assertTrue("itemdamage min <= max", args[0] <= args[1]);
call assertTrue("itemdamage melee flag", args[5] == 0 or args[5] == 1);
itemdamage_seen := itemdamage_seen + 1;
itemdamage_last_min := args[0];
itemdamage_last_max := args[1];
itemdamage_last_hit_mode := args[4];
itemdamage_last_is_melee_weapon := args[5];
itemdamage_last_weapon_name := itemdamage_weapon_name(weapon);
if (weapon == 0) then
itemdamage_last_weapon_pid := -1;
else
itemdamage_last_weapon_pid := obj_pid(weapon);
display_msg(string_format6("itemdamage mode=%s min=%d max=%d weapon=%s hit=%d melee=%d",
itemdamage_mode_name,
args[0],
args[1],
itemdamage_last_weapon_name,
itemdamage_last_hit_mode,
itemdamage_last_is_melee_weapon));
if (itemdamage_mode == 1) then begin
set_sfall_return(42);
end else if (itemdamage_mode == 2) then begin
set_sfall_return(30);
set_sfall_return(30);
end
end
procedure keypress_handler begin
variable
pressed := get_sfall_arg_at(0),
key := get_sfall_arg_at(1);
if (not pressed) then return;
if (key == DIK_J) then begin
itemdamage_mode := itemdamage_mode + 1;
if (itemdamage_mode > 2) then itemdamage_mode := 0;
display_msg(string_format1("itemdamage mode -> %s", itemdamage_mode_name));
end else if (key == DIK_K) then begin
display_msg(string_format7("itemdamage summary mode=%s seen=%d last=%d-%d weapon=%s pid=%d melee=%d",
itemdamage_mode_name,
itemdamage_seen,
itemdamage_last_min,
itemdamage_last_max,
itemdamage_last_weapon_name,
itemdamage_last_weapon_pid,
itemdamage_last_is_melee_weapon));
call assertTrue("itemdamage observed", itemdamage_seen > 0);
call report_test_results("itemdamage");
end
end
procedure start begin
if (not game_loaded) then return;
display_msg("itemdamage manual test ready:");
display_msg("press J to cycle engine/fixed-42/range-30-30");
display_msg("attack with fists, melee weapons, and ranged weapons");
display_msg("press K to report after HOOK_ITEMDAMAGE fires");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_ITEMDAMAGE, itemdamage_handler);
end
+70
View File
@@ -0,0 +1,70 @@
#include "sfall.h"
#include "dik.h"
variable movecost_mode := 0;
procedure movecost_mode_name(variable mode) begin
variable name := "unknown";
if (mode == 0) then name := "engine";
else if (mode == 1) then name := "plus_per_hex";
else if (mode == 2) then name := "double";
return name;
end
procedure cycle_movecost_mode begin
if (movecost_mode == 0) then movecost_mode := 1;
else if (movecost_mode == 1) then movecost_mode := 2;
else movecost_mode := 0;
display_msg(string_format1("movecost mode=%s", movecost_mode_name(movecost_mode)));
end
procedure movecost_handler begin
variable
args := get_sfall_args,
critter := args[0],
distance := args[1],
defaultCost := args[2],
modeName := movecost_mode_name(movecost_mode),
newCost := defaultCost;
if (critter != dude_obj) then return;
display_msg(string_format3("movecost dist=%d default=%d mode=%s",
distance,
defaultCost,
modeName));
if (movecost_mode == 1) then begin
newCost := defaultCost + distance;
end else if (movecost_mode == 2) then begin
newCost := defaultCost * 2;
end else begin
return;
end
set_sfall_return(newCost);
end
procedure keypress_handler begin
variable
pressed := get_sfall_arg_at(0),
key := get_sfall_arg_at(1);
if (not pressed) then return;
if (key != DIK_M) then return;
call cycle_movecost_mode;
end
procedure start begin
if (not game_loaded) then return;
display_msg("movecost manual test ready: enter combat, hover a tile, then move");
display_msg("press M to cycle hook override: engine -> plus_per_hex -> double");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_MOVECOST, movecost_handler);
end
@@ -0,0 +1,7 @@
[ValidSection]
ValidKey=ValidValue
Key2=2
[Section2]
Key1=AA
Key2=BB

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