* Implement `set_unique_id`
* save/load watermark, including compat with previous saves (would be `0`)
* metarule to set and reset unique_id
* inventory stacking rules
* Sfall-like sound system
(I would like a better name for this system, but the opcodes themselves are called `play|stop_sfall_sound` and I can't think of a better name)
This is a sound management system very similar to Sfall's. With a few differences:
* No support for new sound formats yet. Support for at least ogg+wav will come next
* Does support reading from .dat files, hence playing any sound effect in the base game
* Support mode=3 for speech volume. This exists in Sfall but is ignored when called from the opcode.
Also, change GaplessMusic to use this system to play the "wind2" loading sound. This restores the "vanilla" feel map transitions, so I think it's reasonable to make GaplessMusic=1 the default. I can't imagine someone wanting to change it to 0 unless they are ultra purists
* Sfall saved arrays support
* Add "...all_arrays..." special case for a list of saved arrays
* Adjust error message on load fail
* Fix crash in GetArrayKey when index == size
* chore: auto-format with clang-format
* Update sfall compatibility md
* Add keyIndex for Assoc Arrays for O(1) key lookups
* Review feedback, more error logging
* Fix build, increase ARRAY_MAX_STRING to 1024 to match sfall, fix gl_test_arrays triggering dynamic string block merge failure, prevent potential string buffer corruption on very long strings
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Implement HOOK_RESTTIMER
Et tu + other mods use this
* PR comments + missing doc for ce-dat-tool
* chore: auto-format with clang-format
* document timer wrap
* cleanups
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* `set/remove_script` and `HOOK_STDPROCEDURE{_END}`
These were implemented together as I thought HOOK_STDPROCEDURE would be useful for testing set_script.
* Implement HOOK_CALCAPCOST
An opcode a day keeps the stimpak away.
https://sfall-team.github.io/sfall/hook-types/#calcapcost
Same as Sfall, but also calls the hook on game load to display the correct AP cost on load.
Also fix a minor bug where the attack mode of the current hand sometimes leaked when loading a save game. Normally attack mode (burst/reload/&c) isn't saved. But if you are in aimed mode (say), and load a game with the same weapon equipped, the attack mode will persist. This is pretty weird, so changed it to always be in the default mode when loading a save.
* test script
* PR comments
* doc tweaks
* Implement sfall `signal_close_game`
Used by Et tu, but might be useful for LLMs too to quit the game after running a test case.
Also added enum for `_user_wants_to_quit`, and did minor reformatting of SFALL_COMPATIBILITY.md
* Fix `list_as_array(LIST_CRITTERS)` returning objects with pid=-1
When using gl_highlighting, I saw:
```
2026-04-01 12:42:52.824 Fallout II Community Edition[34437:20111056] INFO: Current script: scripts\gl_highlighting.int, procedure ToggleHighlight
2026-04-01 12:42:52.950 Fallout II Community Edition[34437:20111056] INFO: Script Error: scripts\gl_highlighting.int: op_critter_state: obj is NULL
2026-04-01 12:42:52.950 Fallout II Community Edition[34437:20111056] INFO:
Error during execution: get_proto_data: bad proto -1
```
We missed checking that pidType < -1, so we indexed kObjectTypeToListType[-1] which is UB. Either we were lucky and this OOB memory matched, or the compiler was getting cheeky. This fixes the bug and stops the error.
* PR feedback
* Fix global script loading on non-Windows
Previously, global scripts in .dats and in local FS didn't work due to path separator confusion.
Now:
* Hardcode global script path to "scripts\gl*.int" (windows separator)
* Use Windows fpattern matching inside of dFile (.dats, which always use windows separators)
* Use \-paths when listing found global scripts
The awkward part is having to vendor a copy of fpattern to force it to use "windows mode". It's possible that we could use this everywhere since windows allows / as separator, but that could cause bugs where we're using fpattern on the native FS. For now keeping the dFile implementation separate makes sense.