Compare commits

...
Author SHA1 Message Date
phobos2077 a4a929f620 mapper: reworked writing paths logic
- Drop "target_path_base" and other references to BIS "fallout/dev/" folder in favor of new dev_temp_path setting
- Clear separation between "mapper temp assets" (.cfg, .txt, .tgt), "shipped assets" (.map, .edg, .pro) and "runtime temp assets" (.sav)
- dev_temp_path is mounted as highest priority xbase, so all saved data goes there by default
- as a consequence, play-mode assets (maps with .sav extension and party member .pro files) are explicitly saved to master_patches_path instead of implicitly by using xfileOpen in write mode
2026-06-14 13:29:22 +02:00
phobos2077 f5ba58f27a mapper: proto edit: fix bugs, light refactor and use correct colors 2026-06-13 00:29:09 +02:00
phobos2077 9bd179167c mapper: move proto TXT handling to separate file 2026-06-12 14:50:33 +02:00
phobos2077 9e88b16d71 mapper: fix incorrect strings 2026-06-12 00:37:21 +02:00
phobos2077 15a4f4275b mapper: critter proto editing + wire up all editors 2026-06-12 00:05:34 +02:00
phobos2077 466f12b22e mapper: proto TXT support 2026-06-11 23:45:48 +02:00
phobos2077 26622f3596 mapper: name/description editing 2026-06-11 23:41:07 +02:00
phobos2077 629d1f2b7b mapper: item proto editing 2026-06-11 21:37:20 +02:00
phobos2077 1453a3e294 mapper: scenery proto editing 2026-06-11 21:13:06 +02:00
phobos2077 b5c0fbdf86 mapper: simple proto editing 2026-06-11 21:02:42 +02:00
phobos2077 948558c64c mapper: misc proto editing functions 2026-06-07 11:52:53 +02:00
phobos2077 6412d14a28 mapper: proto_edit_init, proto_remove 2026-06-07 11:15:44 +02:00
phobos2077 6835d10590 mapper: fix TMP map files not being deleted, fix edg not loading when changing maps in play mode 2026-06-07 02:05:57 +02:00
phobos2077 20ad8d8778 mapper: fix SAV files being created in the dev_path 2026-06-07 01:17:01 +02:00
github-actions[bot] 6782a21185 chore: auto-format with clang-format 2026-06-06 21:33:20 +00:00
phobos2077 d12dbca951 mapper: EDG angled edges (squareRect) editing 2026-06-06 23:27:51 +02:00
phobos2077 823858f275 mapper: fix selected object being deleted when opening map 2026-06-06 23:27:50 +02:00
phobos2077 b93591f5d7 EDG: fix incorrect image corruption when scroll limiting kicks in right at the edge border 2026-06-06 23:27:50 +02:00
phobos2077 a91e40e3cc mapper: EDG support (edges only) 2026-06-06 23:27:50 +02:00
phobos2077 7da7d75f30 mapper: move common utility functions to mp_utils.cc 2026-06-06 23:27:50 +02:00
phobos2077 72b4680ff5 mapper: implement dev_path, a path override where saved files will go 2026-06-06 23:27:50 +02:00
Mike Klaas 99a762b649 frm2png can convert to/from indexed pngs (#487)
* frm2png can convert to/from indexed pngs
2026-06-05 20:39:56 -07:00
Mike KlaasandCopilot Autofix powered by AI 1afe925cbf Better fix for directory detection (#486)
* Better fix for directory detection

A couple places we used compat_file_exists to distinguish between files and folders/dirs, but this breaks on POSIX.  This attempts to fix it more holistically

* Make compat_file_exists to be consistent

All platforms now return false for folders/dirs

* Apply suggestions from code review

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

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-05 20:24:59 -07:00
Mike Klaas 95c07dba9f Fix compile warnings (#482)
Most are of this type

```
warning: 'size' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]

sfall_arrays.cc:313:26: note: overridden virtual function is here
    313 |     virtual ProgramValue GetArrayKey(int index, Program* program) = 0;
        |
```
2026-06-04 08:27:48 -07:00
Mike Klaas 0fc042ef84 Fix save games being missing on Mac OS (#484) 2026-06-03 22:46:57 -07:00
Mike Klaas 29df63dd99 [HRP] Scale movies (#478)
SDL Surface for performance and nice scaling
2026-06-03 21:16:16 -07:00
Mike Klaas 6f2693edf7 Change use_walk_distance to match sfall setting (#481)
* Change `use_walk_distance` to match sfall setting

It's pointless to set this to 0,1 because you don't move if the target is adjacent or yourself, so sfall changes this to "number of spaces" between player and target.  We were reading the old ddraw.ini setting before, incorrectly.

Also add a small optimization to not compute path for adjacent targets

* add comment

* return true when distance is self/adjacent
2026-06-03 15:34:55 -07:00
Mike Klaas e51004a3d1 Ability to use indexed pngs as interface art (#454)
* Ability to load indexed pngs in game

* Switch 2-col inventory .frms to .png
2026-06-02 23:48:08 -07:00
Vlad K 9aa2ae4bbc ZIP DB archive support (#480)
* ZIP: inital support (directly in DBase)

* ZIP: log and bail on any unsupported feature

* dfile.cc compile error fix

* ZIP: minor refactoring

* ZIP: code review fixes and refactoring

* ZIP: simpler and more robust code

* Formatting

* ZIP: remove unnecessary dataOffset normalization
2026-06-02 18:30:20 +02:00
Vlad K 968534314d gameDbInit: change load order to keep master_patches at the top and to match sfall (#479) 2026-06-01 16:57:31 +02:00
Mike Klaas a38f3436f8 A few combat opcodes (#477)
* set_critter_burst_disable

* get/set/reset_critical_table

* `attack_is_aimed`
2026-05-31 16:28:00 -07:00
Mike Klaas 15c22ccdfc HRP/Sfall main menu scaling (#457)
Similar to HRP/Sfall, except:

    Does not support non-aspect-ratio-preserving scale mode
    Uses vanilla art if it fits without scaling (e.g. 640x480 or non-scaling res like 800x480). The scaled-down HR assets looks considerably worse.
2026-05-28 19:49:29 -07:00
Mike Klaas f263075abf Bundle Sfall's gl_highlighting.ssl (#461)
* Bundle Sfall's gl_highlight.ssl

Most mods/distributions assume this is exists since it is bundled with Sfall.  It's also a highly requested feature

I decided to merge this as a first-class game config instead of continuing to read mods/sfall-mods.ini.  I think most people to this to be a default capability that can be toggled in-engine.  Open to other thoughts on the matter.  Lost of people will already have sfall-mods.ini configured, which is a reason to keep it the way it was.

* PR feedback
2026-05-27 23:15:09 -07:00
Mike Klaas c95f91c2ff Fix returnval of critter_mod_skill (#476)
Fixes #474
2026-05-27 22:14:16 -07:00
Vlad K db86e53af2 Fix crash in opTokenize when prev is not null but not present in the source string (#473) 2026-05-27 18:40:54 +02:00
Vlad K 349af8fbb8 Fix aiPacketRead inducing crash when loading saves in certain order (#472)
* Fix aiPacketRead overwriting packet_num from savegames, leading to corrupted state on subsequent loads and crash

* Mark variable as unused and add comment
2026-05-27 10:21:45 +02:00
Mike Klaas 9423a2c289 Sfall: save/restore last savegame page/slot (#464)
* Sfall: save/restore last savegame page/slot

* ScopedConfig for RAII convenience
2026-05-26 23:38:02 -07:00
Mike Klaas dc4753cde9 Improve music/sound system to allow .ogg/.wav map music + 44.1 kHz output (#465)
* Change output sound buffer to 44.1 kHz

This allow CE to play 44.1 kHz input files without loss of precision.  In particular, it plays HQ music that ships with RPU.

There is a very similar fix in Sfall

* use generic sound loading path to allow .ogg/.wav music files

* rm a few dangling references

* PR feedback

* rm references to audio file

* rm audio_file.cc/h

* restore default audio io

* PR fixes
2026-05-26 23:12:42 -07:00
Mike Klaas cd3adf1621 Implement set_unique_id (#466)
* 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
2026-05-26 22:38:40 -07:00
Mike Klaas d42c8456dd Custom iface tags + metarules (#463)
* custom iface tag

* add_iface_tag, set_iface_tag_text

Used by FO2Tweaks and other mods
2026-05-26 22:30:42 -07:00
Vlad K c574812f1d EDG: fix getIsoWindowSize returning (1, 1) in release builds (#471) 2026-05-26 18:46:08 +02:00
Mike Klaas 8afe4b3061 Use in-game gamma when generating screenshots (#469)
This fixes the slight darkening effect that currently exists
2026-05-26 09:23:14 -07:00
Vlad Kandgithub-actions[bot] c423d475c5 EDG support (#450)
* HRP's edg file support (WIP)

* Update docs and fix bug

* chore: auto-format with clang-format

* EDG: proper scroll blocking based on pre-calculated rects, exactly as in HRP

* chore: auto-format with clang-format

* EDG: fix scrolling past pixel-space bounds with sub-hex map edge mod

* EDG: review fixes

* EDG: proper edge clipping matching HRP logic

* chore: auto-format with clang-format

* EDG: code review fixes and refactoring

* chore: auto-format with clang-format

* EDG: fix clamping

* EDG: show arrow cursor and block events when over clipped area

* chore: auto-format with clang-format

* EDG: option to disable

* EDG: deobfuscate code

* chore: auto-format with clang-format

* EDG: get rid of rect2 and simplify algebra

* EDG: update docs, clarify that squareRect is not implemented

* EDG: square mask support

* chore: auto-format with clang-format

* Code review fixes

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-26 07:25:40 +00:00
Mike Klaas 06d7f09728 Implement HOOK_USESKILL, HOOK_USESKILLON (#456)
* Implement HOOK_USESKILL, HOOK_USESKILLON

* make comment more accurate
2026-05-19 22:40:33 -07:00
Mike Klaas 81164465cf Load f2_res.dat after master.dat (#462)
This bring CE much closer to sfall's load order, and fixes RPU install.

 master_patches > critter_patches > mods_order.txt > PatchFileXX > patchXXX.dat > sfall.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat

Also fixed typo in `showMessageBox`, and added a debugPrint in that function, so errors are visible in the log (LLMs otherwise find it hard to figure out what happened)
2026-05-19 22:20:13 -07:00
IronKing24 0a7834f81b Merge pull request #459 from fallout2-ce/mingw
Add Mingw build system
2026-05-17 01:15:07 +03:00
IronKing24 f76e310f10 Fix mapper compilation 2026-05-16 19:45:00 +03:00
IronKing24 303e7573ca Merge branch 'main' into mingw 2026-05-16 18:30:39 +03:00
Mike Klaas 16ae69fa5a HOOK_ENCOUNTER (#453)
* HOOK_ENCOUNTER

Pretty much 1:1 with Sfall except adding extra validation that the mapId returns belongs to an area
2026-05-13 15:09:43 -07:00
Mike Klaas 6d2d9d6ef3 Add "trade/loot" context menu for party members. (#449)
* Add "trade/loot" context menu for party members.

This was an idea I saw listed on NMA. Veterans of classic Fallout know you can trade with your companions much more easily using the steal skill, But this would be difficult for most new players to discover. This replaces the dialogue option in the long press (which is redundant since it is the default action) with the hand, which is normally used to loot from containers and corpses.

This does introduce a slight inconsistency in the default action, not being present when you long press. how almost everyone will be single-clicking to talk to NPCs.

Also, "you plant..." and "you steal..." messages when trading with companions this way. Put this behind the same flag in case someone wants the original experience.

* Full context menu

* container -> target

* PR feedback

* rebase on main

* rename function
2026-05-12 23:03:43 -07:00
Mike Klaas 7ae0452e1a Add original symbol beside all function and symbol offsets (#332)
* Add original symbol beside all function offsets

e.g.

```
// 0x414E98 register_object_call
int animationRegisterCallback(

// 0x414E20 register_object_must_erase
int animationRegisterHideObjectForced(
```

This was programmatically generated so there could be errors.  Spot checking looks pretty good though
2026-05-11 19:49:15 -07:00
Vlad Kandgithub-actions[bot] f63c113d77 Mapper: Playmode & misc features (#448)
* Mapper: fixed playmode, added some mapper features

* mapper: save map corrections + some stubs

* mapper: fix playmode and cleanup discrepancy

* mapper: edit_mapper inacuracies and tidying up some code

* mapper: corrected Delete Spatial, minor fixes

* mapper: implement debug.show_tile_num, Mark Exit Grid, toolbar name drawing fix and refactoring

* chore: auto-format with clang-format

* mapper: fix inaccuracies after AI review, round 1

* mapper: fix inaccuracies after AI review, round 2

* chore: auto-format with clang-format

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-12 03:00:19 +02:00
EvgeniyandZoschukEN f8ad77061b Refactoring datafile: (#445)
* Refactoring datafile:

Description

1. Removed unused extern variables from the header file.
2. Replaced magic numbers with constants.
3. Added stdint types

* Emty commit for start clang formatter

* Used clang format

---------

Co-authored-by: ZoschukEN <ZoschukEN@RTK-CD.RU>
2026-05-11 10:10:23 -07:00
IronKing24 471ebbf417 Merge branch 'main' into mingw 2026-05-11 10:37:26 +03:00
Mike Klaas 924e12b94c [HRP] Enable HR dialog screen (#441)
* [HRP] Enable HR dialog screen

(It's not really "hi resolution", just adds a border so it looks less funny.)

Also, picked up @NovaRain's suggestion of centering dialog on the play area if it is large enough, which matches Sfall.
2026-05-10 22:35:35 -07:00
Mike Klaas 706785d60e Implement a few AP opcodes (#443)
* get/set_unspent_ap{_perk}_bonus

* get/set_inven_ap_cost
2026-05-10 21:48:22 -07:00
Mike Klaas 1175efd379 Implement HOOK_STEAL (#442)
* Implement HOOK_STEAL
2026-05-10 10:15:50 -07:00
Mike Klaas ab2a09610d Party members can barter (#436)
Very simple party barter support. Builds upon the loot screen so is very little code:

    Switch party members with left/right arrow keys
    When leaving barter with items on the table (canceling), all items go to the PC's inventory
    No special handling of money (yet)

The mod pins the player's money stack on top of the inventory list for all party members. That's nice, but also feels a little odd, but likely just because I'm used to the money stack being stuck at bottom. We can iterate on that.

Adding an interface will require art. I considered enabling mouse use triggered by clicking on the avatar which would be quite simple.
2026-05-07 06:02:37 +00:00
Mike Klaas cef24823f4 Speed up Fallout1 .dat reader (#439)
* Speed up Fallout1 .dat reader

It was reallocating a buffer on a loop, which caused large files to take minutes.  Fixing this reduced it to a reasonable time, but still ~120s for the entire Fallout1 master.dat.

Also, bump the F2 gzip buffer to 4kB. It was only 400 bytes
2026-05-06 13:36:11 -07:00
Mike Klaas 63d79e4bfd Fix high pitch voiced dialog (#440)
In 8b2ead8a2b, soundLoad started honoring AudioFileInfo.channels, but the ACM decoder path historically only propagated sample rate.  This changes playback in a way that caused the bug.

Verified by talking to good ol' Sulik
2026-05-05 22:55:53 -07:00
Vlad Kandgithub-actions[bot] e42d8021c1 WIP Mapper implementation (#438)
* Add mapper CMakeTarget, tool for mapping function names to originals, load/save toolbar & update_art implemented

* edit_mapper function + stubs

* Rename exe to mapper-ce

* load_lbm_to_buf

* Add comments for read/write functions in db.h

* load_dialog, save_dialog, save_as, info_dialog and some other functions

* Fix LBM loading

* Fix mouse input not working on initial empty map, changed error in partyMemberRecoverLoadInstance to print to log, matching vanilla

* mapper.cc: basic hi-res support, NULL->nullptr

* load_lbm_to_buf rewrite, print_toolbar_name background fix

* Stubs for enter/exit playmode, art slot indexes fix, map_scr_toggle_hexes

* Fix memory corruption on screen_width > 640, fix various UI offset bugs

* mapper.cc: UI code style, toggle button fixes, rotation keys, edit button placeholders, PAGEUP key fix

* Elevation display fix, object type switching

* Spatial script placement and display, basic object selection

* Fixed dragging objects, block object showing, add all missing cases in edit_mapper with stubs, move all keys codes to constants

* chore: auto-format with clang-format

* Fix non-win builds

* Add stub calls from edit_mapper, fix objects being incorrectly deleted when unselected, fix tile number display

* Fix compile on Linux

* Attempt to fix iOS signing error

* Placing of objects and tiles, F12 to erase map, bug fixes

* Fixed block object toggling logic and add missing switch cases to edit_mapper

* Object editing added, 'p' to scroll palette fixed

* Add new files to CMakeLists

* Attempt to fix some colors + alignment in critter edit window

* chore: auto-format with clang-format

* Linux build fix attempt

* Critter inventory editing

* Vanilla grid-based inventory item picker

* Review fixes

* More review fixes and const correctness

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-05 18:47:16 +00:00
8254c758fe HOOK_INVENWIELD, HOOK_CANUSEWEAPON, HOOK_ADJUSTFID (#437)
* Add support for new talking heads

Add [Heads] config section in ddraw.ini that maps critter PIDs to talking
head indices in art\heads\heads.lst. When a dialog script starts with
headId=-1, the engine now checks the critter proto's headFid first, then
falls back to the [Heads] mapping. This lets mods add talking heads
without patching dialog scripts.

Includes Cassidy mapping (PID 16777305 → head index 13) for use with
cassidy_head.dat mod.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement HOOK_INVENWIELD, HOOK_CANUSEWEAPON and fix HOOK_ADJUSTFID

Wire the sfall hooks that npc_armor.mod relies on so party-member sprites
actually change when armor is equipped:

- HOOK_INVENWIELD fires from inventoryEquipFunc/inventoryUnequipFunc with
  (critter, item, slot, isWield). Script may veto by returning 0. Slot
  values mirror interpreter_extra.cc: WORN=0, RIGHT_HAND=1, LEFT_HAND=2.
- HOOK_CANUSEWEAPON fires from _ai_search_inven_weap so the mod's
  weapon-anim restriction can veto AI weapon picks.
- HOOK_ADJUSTFID arg list corrected to match sfall (single currFid arg,
  critter resolved via dude_obj).
- ProgramValue::isEmpty no longer treats string values as empty — sfall
  scripts like npc_armor's `while (sect.PID)` loop depend on a non-empty
  string being truthy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* enum class

* chore: auto-format with clang-format

* bad merge

* PR feedback

* restore isEmpty() to vanilla while fixing bug

* fixes

* minor fixes

* extra

* Potential fix for pull request finding

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

---------

Co-authored-by: tectiv3 <tectiv3@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-04 21:36:50 -07:00
Mike Klaas 8b2ead8a2b Sfall-like sound system (#429)
* 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
2026-05-04 07:21:37 -07:00
Mike Klaas 4f89bb7d77 Companions can be the "looter" in loot screen (#435) 2026-05-03 09:57:25 -07:00
Vlad K 0d8741e082 Debug logging improvements (#434)
* debug log buffering to catch early logs, always duplicate log to stdout, const char* for debug fns

* AI nitpicking fixes
2026-05-03 09:15:13 +00:00
IronKing24 bc7ab1ecb2 Merge branch 'main' into mingw 2026-05-03 11:04:19 +03:00
Vlad Kandgithub-actions[bot] 6ce6bea309 Sfall Saved Arrays (#431)
* 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>
2026-05-03 01:24:30 +02:00
IronKing24 a0a6091bd0 add package dependency fix 2026-05-02 20:56:29 +03:00
IronKing24 f2b2127709 fix processor name typo 2026-05-02 20:53:19 +03:00
IronKing24 ec6647968b Merge branch 'main' into mingw 2026-05-02 19:15:08 +03:00
IronKing24 f97ceff645 add x86 build and move presets to the public 2026-05-02 19:07:27 +03:00
IronKing24 4247d7ac3f - Set correct checks for msvc or win
- change SDL2 cmake for mingw to link correctly
2026-05-02 15:56:41 +03:00
IronKing24 bd3358709f add toolchain file 2026-05-01 20:28:30 +03:00
212 changed files with 25860 additions and 5956 deletions
+176 -6
View File
@@ -25,6 +25,9 @@ if(MSVC)
endif()
option(FALLOUT_VENDORED "Use vendored third-party libraries" ON)
option(FALLOUT_AUDIO_OGG "Enable OGG decoding with stb_vorbis when available" ON)
set(FALLOUT_STB_VORBIS_DIR "" CACHE PATH "Directory containing stb_vorbis.c")
if(ANDROID)
add_library(${EXECUTABLE_NAME} SHARED)
@@ -35,15 +38,15 @@ endif()
# Git Info
include("cmake/gitver.cmake")
target_sources(${EXECUTABLE_NAME} PUBLIC
# Shared engine sources — used by both game and mapper targets.
# Excludes main.cc/main.h (game-only entry logic).
set(FALLOUT_ENGINE_SOURCES
"src/actions.cc"
"src/actions.h"
"src/animation.cc"
"src/animation.h"
"src/art.cc"
"src/art.h"
"src/audio_file.cc"
"src/audio_file.h"
"src/audio.cc"
"src/audio.h"
"src/automap.cc"
@@ -151,13 +154,13 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/lips.h"
"src/loadsave.cc"
"src/loadsave.h"
"src/main.cc"
"src/main.h"
"src/mainmenu.cc"
"src/mainmenu.h"
"src/map_defs.h"
"src/map.cc"
"src/map.h"
"src/map_edge.cc"
"src/map_edge.h"
"src/memory_defs.h"
"src/memory_manager.cc"
"src/memory_manager.h"
@@ -180,6 +183,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/obj_types.h"
"src/object.cc"
"src/object.h"
"src/ogg_decoder.cc"
"src/ogg_decoder.h"
"src/opcode_context.cc"
"src/opcode_context.h"
"src/options.cc"
@@ -263,7 +268,7 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/xfile.h"
)
target_sources(${EXECUTABLE_NAME} PUBLIC
set(FALLOUT_PLATFORM_SOURCES
"src/audio_engine.cc"
"src/audio_engine.h"
"src/delay.cc"
@@ -297,6 +302,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/sfall_opcodes.cc"
"src/sfall_opcodes.h"
"src/sfall_script_hooks.cc"
"src/script_sound.cc"
"src/script_sound.h"
"src/sfall_arrays.cc"
"src/sfall_arrays.h"
"src/sfall_animation.cc"
@@ -309,8 +316,43 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"third_party/lodepng/lodepng.cpp"
)
target_sources(${EXECUTABLE_NAME} PUBLIC
${FALLOUT_ENGINE_SOURCES}
"src/main.cc"
"src/main.h"
)
target_sources(${EXECUTABLE_NAME} PUBLIC ${FALLOUT_PLATFORM_SOURCES})
target_include_directories(${EXECUTABLE_NAME} PUBLIC "third_party/lodepng")
set(FALLOUT_HAVE_STB_VORBIS OFF)
if(FALLOUT_AUDIO_OGG)
if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis/stb_vorbis.c")
set(_fallout_stb_vorbis_dir "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis")
else()
set(_fallout_stb_vorbis_dir "${FALLOUT_STB_VORBIS_DIR}")
if(NOT _fallout_stb_vorbis_dir)
find_path(_fallout_stb_vorbis_dir
NAMES "stb_vorbis.c"
DOC "Directory containing stb_vorbis.c")
endif()
endif()
if(_fallout_stb_vorbis_dir AND EXISTS "${_fallout_stb_vorbis_dir}/stb_vorbis.c")
set(FALLOUT_HAVE_STB_VORBIS ON)
target_include_directories(${EXECUTABLE_NAME} PRIVATE "${_fallout_stb_vorbis_dir}")
else()
message(STATUS "OGG support disabled: stb_vorbis.c not found")
endif()
endif()
if(FALLOUT_HAVE_STB_VORBIS)
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=1)
else()
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=0)
endif()
if(IOS)
target_sources(${EXECUTABLE_NAME} PUBLIC
"src/platform/ios/paths.h"
@@ -330,14 +372,33 @@ if(WIN32)
)
endif()
if(MINGW)
target_compile_definitions(${EXECUTABLE_NAME} PUBLIC
_USE_MATH_DEFINES
)
endif()
if(WIN32)
target_link_libraries(${EXECUTABLE_NAME}
winmm
)
endif()
if(MSVC)
target_link_libraries(${EXECUTABLE_NAME}
debug libcpmtd
optimized libcpmt
)
endif()
if(MINGW)
target_link_options(${EXECUTABLE_NAME} PRIVATE
-static
-static-libgcc
-static-libstdc++
)
endif()
if(WIN32)
target_sources(${EXECUTABLE_NAME} PUBLIC
"os/windows/fallout2-ce.ico"
@@ -454,6 +515,7 @@ target_link_libraries(${EXECUTABLE_NAME} ${ZLIB_LIBRARIES})
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${ZLIB_INCLUDE_DIRS})
target_link_libraries(${EXECUTABLE_NAME} ${SDL2_LIBRARIES})
target_link_libraries(${EXECUTABLE_NAME} ${SDL2_MAIN_LIBRARIES})
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${SDL2_INCLUDE_DIRS})
if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
@@ -480,6 +542,13 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
if(WIN32)
target_link_libraries(ce-dat-tool winmm)
endif()
if(MINGW)
target_link_options(ce-dat-tool PRIVATE
-static
-static-libgcc
-static-libstdc++
)
endif()
target_include_directories(ce-dat-tool PRIVATE "src")
target_include_directories(ce-dat-tool PRIVATE ${ZLIB_INCLUDE_DIRS})
target_include_directories(ce-dat-tool PRIVATE ${SDL2_INCLUDE_DIRS})
@@ -503,6 +572,14 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
target_include_directories(ce-frm2png PRIVATE ${ZLIB_INCLUDE_DIRS})
target_link_libraries(ce-frm2png ${SDL2_LIBRARIES})
target_link_libraries(ce-frm2png ${ZLIB_LIBRARIES})
if(MINGW)
target_link_options(ce-frm2png PRIVATE
-static
-static-libgcc
-static-libstdc++
)
endif()
if(APPLE)
file(GLOB_RECURSE CE_DAT_INPUTS CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/files/ce.dat/*")
@@ -527,6 +604,99 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
endif()
endif()
if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
if(WIN32)
add_executable(mapper-ce WIN32)
else()
add_executable(mapper-ce)
endif()
target_sources(mapper-ce PUBLIC
${FALLOUT_ENGINE_SOURCES}
${FALLOUT_PLATFORM_SOURCES}
"src/proto_txt.cc"
"src/proto_txt.h"
"src/mapper/map_edge_setup.cc"
"src/mapper/map_edge_setup.h"
"src/mapper/map_func.cc"
"src/mapper/map_func.h"
"src/mapper/mapper.cc"
"src/mapper/mapper.h"
"src/mapper/mp_instance.cc"
"src/mapper/mp_instance.h"
"src/mapper/mp_proto.cc"
"src/mapper/mp_proto.h"
"src/mapper/mp_scrpt.cc"
"src/mapper/mp_scrpt.h"
"src/mapper/mp_targt.cc"
"src/mapper/mp_targt.h"
"src/mapper/mp_utils.cc"
"src/mapper/mp_utils.h"
"src/mapper/mp_text.cc"
"src/mapper/mp_text.h"
)
target_compile_definitions(mapper-ce PUBLIC FALLOUT_MAPPER)
if(WIN32)
target_compile_definitions(mapper-ce PUBLIC
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
NOMINMAX
WIN32_LEAN_AND_MEAN
_STATIC_CPPLIB
)
if(MINGW)
target_compile_definitions(mapper-ce PUBLIC
_USE_MATH_DEFINES
)
target_link_options(mapper-ce PRIVATE
-static
-static-libgcc
-static-libstdc++
)
endif()
target_link_libraries(mapper-ce
winmm
)
if(MSVC)
target_link_libraries(mapper-ce
debug libcpmtd
optimized libcpmt
)
endif()
target_sources(mapper-ce PUBLIC
"os/windows/fallout2-ce.rc"
)
endif()
if(APPLE)
target_link_libraries(mapper-ce "-framework CoreFoundation")
set_target_properties(mapper-ce PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
)
endif()
target_include_directories(mapper-ce PUBLIC "third_party/lodepng")
target_include_directories(mapper-ce PRIVATE "src")
target_include_directories(mapper-ce PRIVATE ${ZLIB_INCLUDE_DIRS})
target_include_directories(mapper-ce PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(mapper-ce
fpattern::fpattern
fpattern_windows::fpattern_windows
${ZLIB_LIBRARIES}
${SDL2_LIBRARIES}
${SDL2_MAIN_LIBRARIES}
)
endif()
if(APPLE)
if(IOS)
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
+91
View File
@@ -139,6 +139,77 @@
"cacheVariables": {
"CMAKE_SYSTEM_NAME": "iOS"
}
},
{
"name": "Mingw-base",
"hidden": true,
"description": "Base preset for all MinGW builds.",
"inherits":[
"base"
],
"generator": "Ninja",
"toolchainFile": "${sourceDir}/cmake/toolchain/mingw.cmake",
"cacheVariables": {
"CMAKE_SYSTEM_NAME": "Windows"
}
},
{
"name": "Mingw-x86-base",
"hidden": true,
"description": "Base preset for all MinGW x86 builds.",
"inherits": [
"Mingw-base"
],
"cacheVariables": {
"CMAKE_C_FLAGS": "-m32",
"CMAKE_CXX_FLAGS": "-m32",
"CMAKE_SYSTEM_PROCESSOR": "i686"
}
},
{
"name": "Mingw-x86-debug",
"displayName": "MinGW x86 Debug",
"description": "Cross-compile a Debug Windows x86 build with MinGW-w64 and Ninja.",
"inherits": [
"Mingw-x86-base"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Mingw-x86-release",
"displayName": "MinGW x86 Release",
"description": "Cross-compile a RelWithDebInfo Windows x86 build with MinGW-w64 and Ninja.",
"inherits": [
"Mingw-x86-debug"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "Mingw-x64-debug",
"displayName": "MinGW x64 Debug",
"description": "Cross-compile a Debug Windows x64 build with MinGW-w64 and Ninja.",
"inherits": [
"Mingw-base"
],
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "x86_64",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Mingw-x64-release",
"displayName": "MinGW x64 Release",
"description": "Cross-compile a RelWithDebInfo Windows x64 build with MinGW-w64 and Ninja.",
"inherits": [
"Mingw-x64-debug"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
}
],
"buildPresets": [
@@ -197,6 +268,26 @@
"name": "ios-release",
"configurePreset": "ios",
"configuration": "RelWithDebInfo"
},
{
"name": "Mingw-x86-Debug",
"displayName": "MinGW x86 Debug",
"configurePreset": "Mingw-x86-debug"
},
{
"name": "Mingw-x86-Release",
"displayName": "MinGW x86 Release",
"configurePreset": "Mingw-x86-release"
},
{
"name": "Mingw-x64-Debug",
"displayName": "MinGW x64 Debug",
"configurePreset": "Mingw-x64-debug"
},
{
"name": "Mingw-x64-Release",
"displayName": "MinGW x64 Release",
"configurePreset": "Mingw-x64-release"
}
]
}
+13 -5
View File
@@ -76,7 +76,7 @@ For example:
## `ce-frm2png` CLI Tool
There is also a small FRM conversion tool in this repo for exporting Fallout `.frm` art to `.png`.
There is also a small FRM conversion tool in this repo for converting Fallout art between `.frm` and `.png`.
From the repo root, build it with your normal CMake workflow, targeting `ce-frm2png`:
@@ -89,18 +89,26 @@ Basic usage:
1. `./<BUILD_DIR>/ce-frm2png <input.frm> [output.png]`
2. `./<BUILD_DIR>/ce-frm2png <input.frm> [output.png] --palette <path-to-color.pal>`
3. `./<BUILD_DIR>/ce-frm2png <input.frm> [output.png] --frame <index> --direction <index>`
4. `./<BUILD_DIR>/ce-frm2png - [output.png|-] --palette <path-to-color.pal>`
4. `./<BUILD_DIR>/ce-frm2png <input.png> [output.frm] --palette <path-to-color.pal>`
5. `./<BUILD_DIR>/ce-frm2png <input.png> [output.frm] --fps 10 --action-frame 0 --x-offset 0 --y-offset 0`
6. `./<BUILD_DIR>/ce-frm2png <input.png> <output.png> --palette <path-to-color.pal>`
7. `./<BUILD_DIR>/ce-frm2png - [output.png|-] --from-frm --palette <path-to-color.pal>`
8. `./<BUILD_DIR>/ce-frm2png - [output.frm|-] --from-png --palette <path-to-color.pal>`
`-` can be used to take input from stdin (e.g. from `ce-dat-tool cat` or write to stdout).
`-` can be used to take input from stdin (e.g. from `ce-dat-tool cat`) or write to stdout. When reading from stdin, pass `--from-frm` or `--from-png`. Output defaults to PNG for FRM input and FRM for PNG input when output is omitted or `-`; use `--to-png` for PNG output to stdout from PNG input.
If `--palette` isn't specified, it will pick up `color.pal` in the .frm's directory or cwd.
Output file extensions are validated against the selected conversion. For example, PNG-to-FRM output must use `.frm`, and PNG output must use `.png`.
If `--palette` isn't specified, it will pick up `color.pal` in the input file's directory or cwd.
Notes:
- The tool expects a raw `color.pal` file. It does not read palettes directly from `master.dat`, so extract `color.pal` first if needed.
- A typical extraction flow is: `ce-dat-tool master.dat extract --lower . 'color.pal'`
- By default palette index `0` becomes transparent in the output PNG. Pass `--opaque` to keep it opaque.
- The current implementation writes RGBA PNGs. It does not preserve the original Fallout palette indices as a palette-indexed PNG.
- PNG output is always palette-indexed and preserves Fallout palette indices when possible.
- For `png -> frm`, transparent pixels (alpha below 128) map to palette index `0` by default. Pass `--opaque` to quantize every pixel instead.
- The current `png -> frm` implementation writes a single-frame FRM and points all six direction slots at the same frame payload.
## Updating SDL
+12
View File
@@ -143,6 +143,7 @@ In time this stuff will receive in-game interface, right now you have to do it m
* Expanded 2-column inventory
* 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
* Ctrl-click to quickly move items when bartering, looting, or stealing
* _a_ to select "all" when selecting item quantity
@@ -150,6 +151,9 @@ In time this stuff will receive in-game interface, right now you have to do it m
* When bartering, caps default to the right amount to balance the trade (if possible)
* Music continues playing between maps
* Auto open doors
* 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))
## Contributing
@@ -159,6 +163,14 @@ Integrating Sfall goodies is the top priority. Quality of life updates are OK to
For current sfall compatibility status and the remaining work needed to close gaps, see [SFALL_COMPATIBILITY.md](SFALL_COMPATIBILITY.md).
## For modders
* Robust (though not 100%) Sfall opcode and hook support
* .ogg/.wav support for map music
* .png support for static assets (must be 8bit indexed)
* .zip support for .dat archives
* Working BIS mapper
## License
The source code is this repository is available under the [Sustainable Use License](LICENSE.md).
+25 -13
View File
@@ -4,6 +4,18 @@ This document tracks Fallout 2 CE compatibility with sfall. This is for modders
For now, this covers opcodes/metarules, and hooks. In the future, it will include other ways of modifying the engine (like ini files), and other Sfall-specific behaviour.
## HRP EDG Scroll-Blocker Support
CE supports the `.edg` file format from the HRP (High Resolution Patch), which defines per-map scroll boundaries and square-level render clipping.
**How it works in CE:**
- On map load, `maps/<mapname>.edg` is read if present. Missing file = silent fallback to the scroll-blocker object system.
- The `.edg` file defines per-elevation rectangle boundary zones. Multiple chained zones per elevation are supported.
- When loaded, these zones are used for both scroll blocking and visible area clipping (black bars), replacing both vanilla scroll blocking and CE hi-res stencil system.
- v2 EDG files also contain a `SquareRect` that defines "Angled edges", or square-grid stencil. This is also supported.
## Settings (ddraw.ini → fallout2.cfg / game.cfg)
Settings previously read from `ddraw.ini` have been moved into standard CE config files.
@@ -43,7 +55,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| 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 / Worldmap | get_world_map_x/y_pos<br>set_world_map_pos | âś… | - |
| Audio | eax_available<br>set_eax_environment<br>play_sfall_sound<br>stop_sfall_sound | not implemented | *eax* opcodes will not be implemented |
| 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 | âś… | - |
| Sfall / Version | sfall_ver_major<br>sfall_ver_minor<br>sfall_ver_build | âś… | CE currently reports `4.3.4` |
| Utility / Math | log, exponent, round, sqrt, abs, sin, cos, tan, arctan, ceil, ^, floor2, div | âś… | - |
@@ -55,13 +67,13 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| 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. |
| Interface / Tags | show_iface_tag<br>hide_iface_tag<br>is_iface_tag_active<br>set_iface_tag_text<br>add_iface_tag | âś… except set_iface_tag_text, add_iface_tag | CE only handles built-in interface tags here; custom tag creation/text is not supported yet. |
| Interface / Tags | show_iface_tag<br>hide_iface_tag<br>is_iface_tag_active<br>set_iface_tag_text<br>add_iface_tag | âś… | Legacy `BoxBarCount`, `BoxBarColors` ddraw.ini settings not supported. |
| Global variables | set_sfall_global<br>get_sfall_global_int<br>get_sfall_global_float | âś… except get_sfall_global_float | Current CE storage is int-backed; `set_sfall_global` stores integer values |
| Hooks / Hook functions | init_hook<br>get_sfall_arg<br>get_sfall_args<br>get_sfall_arg_at<br>set_sfall_return<br>set_sfall_arg<br>register_hook<br>register_hook_proc<br>register_hook_proc_spec | âś… | See below for implemented hooks. `init_hook` is deprecated and will not be implemented. register_hook_proc and register_hook_proc_spec both add hooks to the *end* of the hook list, instead of beginning and end, respectively. |
| Arrays / Array functions | create_array<br>temp_array<br>fix_array<br>get/set_array<br>resize_array<br>free_array<br>scan_array<br>len_array<br>save/load_array<br>array_key<br>arrayexpr | âś… except save_array, load_array | - |
| Arrays / Array functions | create_array<br>temp_array<br>fix_array<br>get/set_array<br>resize_array<br>free_array<br>scan_array<br>len_array<br>save/load_array<br>array_key<br>arrayexpr | âś… | - |
| Perks and traits / NPC perks | set_fake_perk_npc<br>set_fake_trait_npc<br>set_selectable_perk_npc<br>has_fake_perk_npc<br>has_fake_trait_npc | not implemented | - |
| 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 | implemented: get_attack_type, get/set_bodypart_hit_modifier, combat_data, get/set_critter_current_ap, get/set_combat_free_move | - |
| 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 / Outline | outlined_object<br>get_outline<br>set_outline | âś… | - |
@@ -70,9 +82,9 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| 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, obj_is_openable, get_proto_data, set_proto_data | - |
| 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 | - |
| 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/<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 | - |
| 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. |
@@ -97,12 +109,12 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| 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` | âś… | - |
| UseSkill | `HOOK_USESKILL` | đźš« | - |
| Steal | `HOOK_STEAL` | đźš« | Et tu |
| UseSkill | `HOOK_USESKILL` | âś… | - |
| Steal | `HOOK_STEAL` | âś… | - |
| WithinPerception | `HOOK_WITHINPERCEPTION` | âś… | - |
| InventoryMove | `HOOK_INVENTORYMOVE` | âś… | - |
| InvenWield | `HOOK_INVENWIELD` | đźš« | - |
| AdjustFID | `HOOK_ADJUSTFID` | đźš« | - |
| InvenWield | `HOOK_INVENWIELD` | âś… | - |
| AdjustFID | `HOOK_ADJUSTFID` | âś… | Second hook arg currently matches the first because CE has no internal FID modifiers like Hero Appearance. |
| CombatTurn | `HOOK_COMBATTURN` | âś… | - |
| StdProcedure | `HOOK_STDPROCEDURE` | âś… | - |
| StdProcedureEnd | `HOOK_STDPROCEDURE_END` | âś… | - |
@@ -113,16 +125,16 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| UseAnimObj | `HOOK_USEANIMOBJ` | đźš« | Et tu; (maybe) |
| ExplosiveTimer | `HOOK_EXPLOSIVETIMER` | âś… | - |
| DescriptionObj | `HOOK_DESCRIPTIONOBJ` | đźš« | Et tu |
| UseSkillOn | `HOOK_USESKILLON` | đźš« | Et tu |
| UseSkillOn | `HOOK_USESKILLON` | âś… | - |
| OnExplosion | `HOOK_ONEXPLOSION` | đźš« | (maybe) |
| SubCombatDamage | `HOOK_SUBCOMBATDAMAGE` | đźš« | (maybe) |
| SetLighting | `HOOK_SETLIGHTING` | đźš« | Et tu; (maybe) |
| Sneak | `HOOK_SNEAK` | đźš« | - |
| TargetObject | `HOOK_TARGETOBJECT` | đźš« | (maybe) |
| Encounter | `HOOK_ENCOUNTER` | đźš« | Et tu |
| Encounter | `HOOK_ENCOUNTER` | âś… | - |
| AdjustPoison | `HOOK_ADJUSTPOISON` | đźš« | (maybe) |
| AdjustRads | `HOOK_ADJUSTRADS` | đźš« | (maybe) |
| RollCheck | `HOOK_ROLLCHECK` | đźš« | - |
| BestWeapon | `HOOK_BESTWEAPON` | đźš« | - |
| CanUseWeapon | `HOOK_CANUSEWEAPON` | đźš« | - |
| CanUseWeapon | `HOOK_CANUSEWEAPON` | âś… | - |
| BuildSfxWeapon | `HOOK_BUILDSFXWEAPON` | đźš« | - |
+18
View File
@@ -0,0 +1,18 @@
# specify the cross compiler
set(CMAKE_C_COMPILER ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-g++)
set(CMAKE_RC_COMPILER ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-windres)
# where is the target environment
set(CMAKE_FIND_ROOT_PATH /usr/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32)
# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# CMake determines how to examine dependencies based on the *host* system, leading to
# a `file unknown error` unless the target platform is explicitly specified.
set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM "windows+pe")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
+24 -2
View File
@@ -22,6 +22,10 @@ save_text_maps=0
show_pid_numbers=0
sort_script_list=0
use_art_not_protos=0
; Allows to load a certain map right away after loading the mapper.
map=denbus2
; Allows to disable grid item picker and use a simpler list-based picker.
use_grid_item_picker=1
[preferences]
brightness=1.000000
@@ -94,6 +98,8 @@ auto_quick_save=3
display_bonus_damage=1
;Set to 1 to get notification of karma changes in the notification window
display_karma_changes=0
;Set to 1 to use the hi-res dialog border/background at resolutions above 640x480. Requires art\intrface\HR_ALLTLK.FRM (for example from f2_res.dat)
dialog_border=1
;Set to one to hide areas outside map bounds when using higher than 640x480 resolution, and to zero to disable
enable_high_resolution_stencil=1
;Set to 1 to extend the action points bar to show up to 16 AP instead of 10 (requires iface_apbar_e.frm)
@@ -104,6 +110,8 @@ iface_bar_mode=0
iface_bar_side_art=2
iface_bar_sides_ori=0
iface_bar_width=800
;Whether to load EDG files (HRP format) when loading maps. If loaded, they override default edge clipping and scroll blocking behavior.
edg_support=1
ignore_map_edges=0
;Set to 1 to display numbered dialogue options
numbers_in_dialogue=0
@@ -111,12 +119,26 @@ numbers_in_dialogue=0
;Set to 2 to also skip the splash screen
skip_opening_movies=0
splash_screen_size=1
;Set to 1 to scale movies to fit the screen while preserving aspect ratio.
;Set to 0 to keep movies at their native size, centered on screen.
movie_aspect_fit=1
;Maximum number of columns shown in the main inventory and loot/steal windows (valid range: 1..2)
;2-column Loot/steal window requires minimum screen width of 673px
inventory_columns=2
;Set to 0 to keep the main menu art and controls at native size.
;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
[qol]
; Automatically open doors that are unlocked and has no script attached.
auto_open_doors=0
; Overrides distance at which walk animation is used when using an object.
use_walk_distance=5
; Overrides distance at which walk animation is used when using an object. 0 disables walking
; This is the number of empty tiles between the player and the target
use_walk_distance=3
; Allow opening party member inventory from the long-press world menu.
party_trade_from_menu=1
; Allow switching to companions' inventories in loot screens (and barter, in the future)
party_loot_and_barter=1
+3 -6
View File
@@ -4,7 +4,7 @@
#define ARRAY_MAX_STRING (255)
#define ARRAY_MAX_STRING (1024)
#define ARRAY_MAX_SIZE (100000)
procedure array_test_suite begin
@@ -82,8 +82,8 @@ procedure array_test_suite begin
call assertEquals("string_split", get_array(string_split("this+is+good", "+"), 2), "good");
call assertEquals("string_split 2", len_array(string_split("advice", "")), 6);
s := "";
for (i := 0; i < ARRAY_MAX_STRING+30; i+=10) begin
s += "Verbosity.";
for (i := 0; i < ARRAY_MAX_STRING+1; i+=100) begin
s += "Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.";
end
arr[0] := s;
call assertEquals("array max string", strlen(arr[0]), ARRAY_MAX_STRING-1);
@@ -141,8 +141,6 @@ procedure array_test_suite begin
end
call assertEquals("foreach 2", s, "ar2=name:John;hp:25;0:5.50000;");
/*
display_msg("Testing save/load...");
arr := [2,1];
arr2 := {1:2};
@@ -163,7 +161,6 @@ procedure array_test_suite begin
call assertEquals("unsave array 1", load_array(0.1), 0);
call assertEquals("unsave array 2", len_array(arr), 2);
call assertEquals("saved arrays 3", len_array(list_saved_arrays), len_array(arr2) - 1);
*/
display_msg("Testing nested expressions...");
arr := [["one", "two"]];
@@ -60,12 +60,14 @@ procedure start begin
display_msg("Testing combat/inventory/object helpers...");
call assertEquals("metarule attack_is_aimed", metarule_exist("attack_is_aimed"), 1);
call assertEquals("metarule get_combat_free_move", metarule_exist("get_combat_free_move"), 1);
call assertEquals("metarule set_combat_free_move", metarule_exist("set_combat_free_move"), 1);
call assertEquals("metarule item_weight", metarule_exist("item_weight"), 1);
call assertEquals("metarule obj_is_openable", metarule_exist("obj_is_openable"), 1);
call assertEquals("opcode get_critter_current_ap", opcode_exists(OP_GET_CRITTER_CURRENT_AP), 1);
call assertEquals("opcode set_critter_current_ap", opcode_exists(OP_SET_CRITTER_CURRENT_AP), 1);
call assertEquals("attack_is_aimed defaults to false", attack_is_aimed, 0);
testItem := create_object_sid(TEST_ITEM_PID, 0, 0, -1);
call assertEquals("item_weight matches proto weight for test item", item_weight(testItem), obj_weight(testItem));
+100
View File
@@ -1,5 +1,63 @@
#include "test_utils.h"
#include "sfall.h"
#include "dik.h"
variable manual_extra_tag := 0;
variable manual_tag5_color := 2;
procedure print_custom_tag_state(variable tag, variable label) begin
display_msg(label + ": " + is_iface_tag_active(tag));
end
procedure toggle_custom_tag(variable tag, variable label) begin
if (is_iface_tag_active(tag)) then begin
hide_iface_tag(tag);
display_msg(label + " hidden");
end else begin
show_iface_tag(tag);
display_msg(label + " shown");
end
call print_custom_tag_state(tag, label);
end
procedure apply_tag5_color begin
set_iface_tag_text(5, "TAG FIVE", manual_tag5_color);
display_msg(string_format1("custom tag 5 color -> %d", manual_tag5_color));
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_B) then begin
call toggle_custom_tag(5, "custom tag 5");
end else if (key == DIK_C) then begin
manual_tag5_color := manual_tag5_color + 1;
if (manual_tag5_color > 7) then begin
manual_tag5_color := 0;
end
call apply_tag5_color;
end else if (key == DIK_N) then begin
call toggle_custom_tag(6, "custom tag 6");
end else if (key == DIK_M) then begin
if (manual_extra_tag == 0) then begin
display_msg("manual extra tag is not initialized");
return;
end
call toggle_custom_tag(manual_extra_tag, "manual extra tag");
end else if (key == DIK_V) then begin
call print_custom_tag_state(5, "custom tag 5");
call print_custom_tag_state(6, "custom tag 6");
if (manual_extra_tag != 0) then begin
call print_custom_tag_state(manual_extra_tag, "manual extra tag");
end
end
end
procedure start begin
display_msg("Testing iface_tag functions...");
@@ -29,5 +87,47 @@ procedure start begin
// RADIATED
call assertFalse("hide_iface_tag(RADIATED)", is_iface_tag_active(2));
// Default custom box from BoxBarCount.
call apply_tag5_color;
call assertFalse("custom tag 5 starts inactive", is_iface_tag_active(5));
show_iface_tag(5);
call assertTrue("show_iface_tag(custom 5)", is_iface_tag_active(5));
show_iface_tag(5);
call assertTrue("show_iface_tag(custom 5 again)", is_iface_tag_active(5));
hide_iface_tag(5);
call assertFalse("hide_iface_tag(custom 5)", is_iface_tag_active(5));
hide_iface_tag(5);
call assertFalse("hide_iface_tag(custom 5 again)", is_iface_tag_active(5));
set_iface_tag_text(6, "TAG SIX", 6);
call assertFalse("custom tag 6 starts inactive", is_iface_tag_active(6));
show_iface_tag(6);
call assertTrue("show_iface_tag(custom 6)", is_iface_tag_active(6));
show_iface_tag(5);
call assertTrue("custom tag 5 still active", is_iface_tag_active(5));
call assertTrue("custom tag 6 still active", is_iface_tag_active(6));
hide_iface_tag(5);
call assertFalse("hide_iface_tag(custom 5 with 6 active)", is_iface_tag_active(5));
call assertTrue("custom tag 6 remains active", is_iface_tag_active(6));
hide_iface_tag(6);
call assertFalse("hide_iface_tag(custom 6)", is_iface_tag_active(6));
// Dynamically added custom box.
variable extra_tag := add_iface_tag;
call assertTrue("add_iface_tag lower bound", extra_tag >= 10);
call assertTrue("add_iface_tag upper bound", extra_tag <= 126);
manual_extra_tag := extra_tag;
set_iface_tag_text(extra_tag, "EXTRA TAG", 3);
call assertFalse("added custom tag starts inactive", is_iface_tag_active(extra_tag));
show_iface_tag(extra_tag);
call assertTrue("show_iface_tag(added custom)", is_iface_tag_active(extra_tag));
hide_iface_tag(extra_tag);
call assertFalse("hide_iface_tag(added custom)", is_iface_tag_active(extra_tag));
variable next_tag := add_iface_tag;
call assertEquals("add_iface_tag increments", next_tag, extra_tag + 1);
call report_test_results("iface_tag");
display_msg("iface_tag manual test ready: B toggle tag 5, C cycle tag 5 color, N toggle tag 6, M toggle extra tag, V print states");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
+78
View File
@@ -0,0 +1,78 @@
#include "sfall.h"
#include "dik.h"
variable loop_sound_id := 0;
variable quiet_loop_sound_id := 0;
variable music_sound_id := 0;
procedure stop_if_active(variable sound_id, variable label) begin
if (sound_id != 0) then begin
stop_sfall_sound(sound_id);
display_msg(label + " stopped");
end else begin
display_msg(label + " is not active");
end
end
procedure keypress_handler begin
variable pressed := get_sfall_arg_at(0);
variable key := get_sfall_arg_at(1);
variable ignored;
if (not pressed) then return;
if (key == DIK_K) then begin
display_msg("play_sfall_sound mode 0 one-shot: sound\\sfx\\pistol.ACM");
ignored := play_sfall_sound("sound\\sfx\\pistol.ACM", 0);
end else if (key == DIK_N) then begin
if (loop_sound_id != 0) then begin
display_msg(string_format1("loop already active id=%d", loop_sound_id));
return;
end
loop_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 1);
display_msg(string_format1("mode 1 loop id=%d", loop_sound_id));
end else if (key == DIK_M) then begin
call stop_if_active(loop_sound_id, "mode 1 loop");
loop_sound_id := 0;
end else if (key == DIK_C) then begin
if (quiet_loop_sound_id != 0) then begin
display_msg(string_format1("quiet loop already active id=%d", quiet_loop_sound_id));
return;
end
quiet_loop_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 0x30000001);
display_msg(string_format1("quiet mode 1 loop id=%d", quiet_loop_sound_id));
end else if (key == DIK_X) then begin
call stop_if_active(quiet_loop_sound_id, "quiet mode 1 loop");
quiet_loop_sound_id := 0;
end else if (key == DIK_G) then begin
if (music_sound_id != 0) then begin
display_msg(string_format1("mode 2 music replacement already active id=%d", music_sound_id));
return;
end
music_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 2);
display_msg(string_format1("mode 2 music replacement id=%d", music_sound_id));
end else if (key == DIK_H) then begin
call stop_if_active(music_sound_id, "mode 2 music replacement");
music_sound_id := 0;
end else if (key == DIK_V) then begin
display_msg("play_sfall_sound mode 3 speech-volume one-shot: sound\\sfx\\pistol.ACM");
ignored := play_sfall_sound("sound\\sfx\\pistol.ACM", 3);
end else if (key == DIK_B) then begin
display_msg("play_sfall_sound mode 0 one-shot wav: smw_1-up.wav"); // needs a wav file in the game dir
ignored := play_sfall_sound("smw_1-up.wav", 0);
end
end
procedure start begin
if (not game_loaded) then return;
display_msg("sfall_sound manual test ready");
display_msg("One-shots use master.dat SFX and loose-file wav; loops/replacement use music");
display_msg("K one-shot ACM mode0, B one-shot WAV mode0, N start loop mode1, M stop loop");
display_msg("C start quiet loop mode1, X stop quiet loop");
display_msg("G start mode2 music replacement, H stop mode2 replacement, V mode3 one-shot");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
+136
View File
@@ -0,0 +1,136 @@
#include "define_lite.h"
#include "sfall.h"
#include "dik.h"
#include "define_extra.h"
#include "lib.inven.h"
#include "test_utils.h"
#define TEST_ITEM_PID 40
#define PARTY_UNIQUE_ID_LOWER_BOUND 18000
#define UNIQUE_ID_LOWER_BOUND 0x10000000
procedure find_random_inventory_item_for_unique_id begin
variable items;
variable length;
variable start;
variable scan;
variable index;
variable item;
variable item_id;
items := inven_as_array(dude_obj);
length := len_array(items);
if (length <= 0) then return 0;
start := random(0, length - 1);
scan := 0;
while (scan < length) do begin
index := start + scan;
if (index >= length) then index -= length;
item := items[index];
item_id := get_object_data(item, OBJ_DATA_ID);
if (item_id < PARTY_UNIQUE_ID_LOWER_BOUND) then begin
return item;
end
scan += 1;
end
return items[start];
end
procedure assign_unique_id_to_random_inventory_item begin
variable item;
variable old_id;
variable new_id;
item := find_random_inventory_item_for_unique_id;
if (item == 0) then begin
display_msg("unique_id manual test: inventory is empty");
return;
end
old_id := get_object_data(item, OBJ_DATA_ID);
new_id := set_unique_id(item);
if (new_id == old_id) then begin
display_msg(string_format3("unique_id manual U: %s pid=%d id unchanged=%d", obj_name(item), obj_pid(item), new_id));
end else begin
display_msg(string_format4("unique_id manual U: %s pid=%d %d->%d", obj_name(item), obj_pid(item), old_id, new_id));
end
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_U) then begin
call assign_unique_id_to_random_inventory_item();
end
end
procedure start begin
variable item_a;
variable item_b;
variable item_c;
variable baseline_total;
variable unique_id_a;
variable unique_id_a_again;
variable unique_id_c;
variable engine_id_a;
variable regular_count;
variable total;
if (not game_loaded) then return;
display_msg("Testing set_unique_id...");
call assertEquals("metarule exists", metarule_exist("set_unique_id"), 1);
baseline_total := obj_is_carrying_obj_pid(dude_obj, TEST_ITEM_PID);
item_a := create_object_sid(TEST_ITEM_PID, 0, 0, -1);
item_b := create_object_sid(TEST_ITEM_PID, 0, 0, -1);
item_c := create_object_sid(TEST_ITEM_PID, 0, 0, -1);
unique_id_a := set_unique_id(item_a);
call assertTrue("unique id lower bound", unique_id_a >= UNIQUE_ID_LOWER_BOUND);
call assertEquals("unique id stored on object", get_object_data(item_a, OBJ_DATA_ID), unique_id_a);
unique_id_a_again := set_unique_id(item_a);
call assertEquals("existing unique id reused", unique_id_a_again, unique_id_a);
add_obj_to_inven(dude_obj, item_a);
add_obj_to_inven(dude_obj, item_b);
call assertEquals("unique item stays separate", obj_is_carrying_obj(dude_obj, item_a), 1);
regular_count := obj_is_carrying_obj(dude_obj, item_b);
call assertTrue("regular item still exists after unique item add", regular_count >= 1);
total := obj_is_carrying_obj_pid(dude_obj, TEST_ITEM_PID);
call assertEquals("unique and regular items add two total items", total, baseline_total + 2);
unique_id_c := set_unique_id(item_c);
call assertNotEquals("second unique item gets new id", unique_id_c, unique_id_a);
add_obj_to_inven(dude_obj, item_c);
call assertEquals("second unique item stays separate", obj_is_carrying_obj(dude_obj, item_c), 1);
total := obj_is_carrying_obj_pid(dude_obj, TEST_ITEM_PID);
call assertEquals("pid total counts all three added items", total, baseline_total + 3);
engine_id_a := unset_unique_id(item_a);
call assertTrue("unset returns engine id", engine_id_a < UNIQUE_ID_LOWER_BOUND);
call assertNotEquals("unset replaces unique id", engine_id_a, unique_id_a);
call assertEquals("engine id stored on object", get_object_data(item_a, OBJ_DATA_ID), engine_id_a);
call assertEquals("remove unique item a", rm_mult_objs_from_inven(dude_obj, item_a, 1), 1);
call assertEquals("remove regular item b", rm_mult_objs_from_inven(dude_obj, item_b, 1), 1);
call assertEquals("remove unique item c", rm_mult_objs_from_inven(dude_obj, item_c, 1), 1);
destroy_object(item_a);
destroy_object(item_b);
destroy_object(item_c);
call report_test_results("unique_id");
display_msg("unique_id manual test ready: press U to assign/print a unique id for a random inventory item");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
+93
View File
@@ -0,0 +1,93 @@
#include "sfall.h"
#include "dik.h"
#include "../test_utils.h"
#define AREA_ARROYO (0)
#define AREA_RND_CITY (28)
#define MAP_RND_CITY1 (68)
variable mode := 0;
variable pending_event := -1;
variable expected_map := -1;
variable arroyo_known_before := 0;
variable car_town_before := 0;
procedure mode_name(variable value) begin
if (value == 0) then return "observe";
if (value == 1) then return "reroute_worldmap_enter";
if (value == 2) then return "cancel_encounters";
return "unknown";
end
procedure log_mode begin
display_msg(string_format2("encounter mode=%d (%s)", mode, mode_name(mode)));
end
procedure begin_pending_assertions(variable event_type) begin
pending_event := event_type;
expected_map := MAP_RND_CITY1;
arroyo_known_before := town_known(AREA_ARROYO);
car_town_before := car_current_town;
end
procedure encounter_handler begin
variable
event_type := get_sfall_arg_at(0),
map_id := get_sfall_arg_at(1),
is_special := get_sfall_arg_at(2),
table_num := get_sfall_arg_at(3),
entry_num := get_sfall_arg_at(4);
display_msg(string_format5("encounter event=%d map=%d special=%d table=%d entry=%d", event_type, map_id, is_special, table_num, entry_num));
if (mode == 1 and event_type == 1) then begin
call begin_pending_assertions(event_type);
display_msg(string_format1("encounter rerouting worldmap entry to map %d", expected_map));
set_sfall_return(expected_map);
end else if (mode == 2 and event_type == 0) then begin
display_msg("canceling encounter");
set_sfall_return(-1);
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_X) then return;
mode := mode + 1;
if (mode > 2) then mode := 0;
call log_mode;
end
procedure start begin
if (not game_loaded) then return;
display_msg("encounter manual test ready:");
display_msg("press X to cycle mode: observe, reroute worldmap enter, cancel encounters");
display_msg("mode 1: enter any location from the world map");
display_msg("mode 2: cancel encounters");
call log_mode;
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_ENCOUNTER, encounter_handler);
end
procedure map_enter_p_proc begin
if (expected_map == -1) then return;
call assertEquals("encounter reroute loaded expected map", cur_map_index, expected_map);
call assertEquals("encounter reroute load area matches rerouted map", map_get_load_area, AREA_RND_CITY);
call assertEquals("encounter reroute does not mutate Arroyo known state", town_known(AREA_ARROYO), arroyo_known_before);
call assertEquals("encounter reroute preserves car town", car_current_town, car_town_before);
if (pending_event == 1) then
call report_test_results("hook_encounter_worldmap_enter");
pending_event := -1;
expected_map := -1;
end
+153
View File
@@ -0,0 +1,153 @@
#include "sfall.h"
#include "dik.h"
#include "define_lite.h"
#include "../test_utils.h"
variable seen_adjustfid := 0;
variable seen_invenwield := 0;
variable seen_invenwield_remove := 0;
variable seen_canuseweapon_player := 0;
variable seen_canuseweapon_ai := 0;
variable temp_container := 0;
variable invenwield_override_enabled := false;
variable canuseweapon_override := -1;
procedure invenwield_mode_name begin
if (invenwield_override_enabled) then return "suppress";
return "engine";
end
procedure canuseweapon_mode_name(variable value) begin
if (value == -1) then return "engine";
if (value == 1) then return "on";
if (value == 0) then return "off";
return "unknown";
end
procedure cycle_canuseweapon_override begin
if (canuseweapon_override == -1) then canuseweapon_override := 1;
else if (canuseweapon_override == 1) then canuseweapon_override := 0;
else canuseweapon_override := -1;
display_msg(string_format1("hook_item_compat canuseweapon mode=%s", canuseweapon_mode_name(canuseweapon_override)));
end
procedure adjustfid_handler begin
variable args := get_sfall_args;
call assertEquals("adjustfid arg count", len_array(args), 2);
call assertEquals("adjustfid arg0 type", typeof(args[0]), VALTYPE_INT);
call assertEquals("adjustfid arg1 type", typeof(args[1]), VALTYPE_INT);
seen_adjustfid := seen_adjustfid + 1;
display_msg(string_format2("adjustfid vanilla=%d modified=%d", args[0], args[1]));
end
procedure invenwield_handler begin
variable
args := get_sfall_args,
item := args[1],
slot := args[2],
is_wield := args[3],
is_remove := args[4];
call assertEquals("invenwield arg count", len_array(args), 5);
call assertTrue("invenwield slot range", slot >= 0 and slot <= 2);
call assertTrue("invenwield is_wield flag", is_wield == 0 or is_wield == 1);
call assertTrue("invenwield is_remove flag", is_remove == 0 or is_remove == 1);
seen_invenwield := seen_invenwield + 1;
if (is_remove) then begin
seen_invenwield_remove := seen_invenwield_remove + 1;
end
display_msg(string_format4("invenwield item=%s slot=%d wield=%d remove=%d", obj_name(item), slot, is_wield, is_remove));
if (invenwield_override_enabled) then begin
set_sfall_return(0);
end
end
procedure canuseweapon_handler begin
variable
args := get_sfall_args,
hit_mode := args[2],
result := args[3],
weapon := args[1];
call assertEquals("canuseweapon arg count", len_array(args), 4);
call assertTrue("canuseweapon result flag", result == 0 or result == 1);
if (hit_mode == -1) then begin
seen_canuseweapon_player := seen_canuseweapon_player + 1;
end else begin
seen_canuseweapon_ai := seen_canuseweapon_ai + 1;
end
display_msg(string_format3("canuseweapon item=%s hitmode=%d result=%d", obj_name(weapon), hit_mode, result));
if (canuseweapon_override != -1) then begin
set_sfall_return(canuseweapon_override);
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_Z) then begin
display_msg("hook_item_compat: unwield armor");
unwield_slot(dude_obj, INVEN_TYPE_WORN);
end else if (key == DIK_X) then begin
display_msg("hook_item_compat: unwield right hand");
unwield_slot(dude_obj, INVEN_TYPE_RIGHT_HAND);
end else if (key == DIK_C) then begin
display_msg("hook_item_compat: unwield left hand");
unwield_slot(dude_obj, INVEN_TYPE_LEFT_HAND);
end else if (key == DIK_V) then begin
display_msg("hook_item_compat: toggle active hand");
toggle_active_hand;
end else if (key == DIK_N) then begin
display_msg("hook_item_compat: move inventory to temp container");
if (temp_container == 0) then begin
temp_container := create_object_sid(467, 0, 0, -1);
end
move_obj_inven_to_obj(dude_obj, temp_container);
end else if (key == DIK_M) then begin
invenwield_override_enabled := not invenwield_override_enabled;
display_msg(string_format1("hook_item_compat invenwield mode=%s", invenwield_mode_name));
end else if (key == DIK_G) then begin
call cycle_canuseweapon_override;
end else if (key == DIK_B) then begin
display_msg(string_format7("hook_item_compat summary inven_mode=%s canuse_mode=%s adjust=%d inven=%d remove=%d player=%d ai=%d",
invenwield_mode_name,
canuseweapon_mode_name(canuseweapon_override),
seen_adjustfid,
seen_invenwield,
seen_invenwield_remove,
seen_canuseweapon_player,
seen_canuseweapon_ai));
call assertTrue("adjustfid observed", seen_adjustfid > 0);
call assertTrue("invenwield observed", seen_invenwield > 0);
call assertTrue("player canuseweapon observed", seen_canuseweapon_player > 0);
call report_test_results("hook_item_compat");
end
end
procedure start begin
if (not game_loaded) then return;
display_msg("hook_item_compat ready:");
display_msg("open inventory/barter to trigger adjustfid");
display_msg("press Z armor, X right, C left, V swap hand");
display_msg("press N disposable-save inventory move, M invenwield mode");
display_msg("press G canuseweapon mode (engine/on/off), B report");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_INVENWIELD, invenwield_handler);
register_hook_proc(HOOK_ADJUSTFID, adjustfid_handler);
register_hook_proc(HOOK_CANUSEWEAPON, canuseweapon_handler);
end

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