mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80bdd7fdb0 | ||
|
|
4eb9e869df | ||
|
|
49a24f6925 | ||
|
|
9423a2c289 | ||
|
|
dc4753cde9 | ||
|
|
cd3adf1621 | ||
|
|
d42c8456dd | ||
|
|
c574812f1d | ||
|
|
8afe4b3061 | ||
|
|
c423d475c5 | ||
|
|
06d7f09728 | ||
|
|
81164465cf | ||
|
|
0a7834f81b | ||
|
|
f76e310f10 | ||
|
|
303e7573ca | ||
|
|
16ae69fa5a | ||
|
|
6d2d9d6ef3 | ||
|
|
471ebbf417 | ||
|
|
bc7ab1ecb2 | ||
|
|
a0a6091bd0 | ||
|
|
f2b2127709 | ||
|
|
ec6647968b | ||
|
|
f97ceff645 | ||
|
|
4247d7ac3f | ||
|
|
bd3358709f |
+59
-4
@@ -47,8 +47,6 @@ set(FALLOUT_ENGINE_SOURCES
|
||||
"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"
|
||||
@@ -161,6 +159,8 @@ set(FALLOUT_ENGINE_SOURCES
|
||||
"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"
|
||||
@@ -372,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"
|
||||
@@ -496,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"))
|
||||
@@ -522,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})
|
||||
@@ -545,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/*")
|
||||
@@ -605,11 +640,30 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
|
||||
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
|
||||
debug libcpmtd
|
||||
optimized libcpmt
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_link_libraries(mapper-ce
|
||||
debug libcpmtd
|
||||
optimized libcpmt
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(mapper-ce PUBLIC
|
||||
"os/windows/fallout2-ce.rc"
|
||||
)
|
||||
@@ -633,6 +687,7 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
|
||||
fpattern_windows::fpattern_windows
|
||||
${ZLIB_LIBRARIES}
|
||||
${SDL2_LIBRARIES}
|
||||
${SDL2_MAIN_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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,8 @@ 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
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+17
-5
@@ -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.
|
||||
@@ -55,7 +67,7 @@ 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 | âś… | - |
|
||||
@@ -70,7 +82,7 @@ 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/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 | - |
|
||||
@@ -97,7 +109,7 @@ 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` | đźš« | - |
|
||||
| UseSkill | `HOOK_USESKILL` | âś… | - |
|
||||
| Steal | `HOOK_STEAL` | âś… | - |
|
||||
| WithinPerception | `HOOK_WITHINPERCEPTION` | âś… | - |
|
||||
| InventoryMove | `HOOK_INVENTORYMOVE` | âś… | - |
|
||||
@@ -113,13 +125,13 @@ 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` | đźš« | - |
|
||||
|
||||
@@ -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.
@@ -110,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
|
||||
@@ -126,5 +128,7 @@ inventory_columns=2
|
||||
auto_open_doors=0
|
||||
; Overrides distance at which walk animation is used when using an object.
|
||||
use_walk_distance=5
|
||||
; 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "sfall.h"
|
||||
#include "dik.h"
|
||||
#include "lib.arrays.h"
|
||||
#include "../test_utils.h"
|
||||
|
||||
variable useskill_mode := 0;
|
||||
variable useskillon_calls := 0;
|
||||
variable useskill_calls := 0;
|
||||
variable last_useskillon_skill := -1;
|
||||
variable last_useskill_skill := -1;
|
||||
|
||||
procedure skill_name(variable skill) begin
|
||||
if (skill == SKILL_FIRST_AID) then return "first_aid";
|
||||
if (skill == SKILL_DOCTOR) then return "doctor";
|
||||
if (skill == SKILL_LOCKPICK) then return "lockpick";
|
||||
if (skill == SKILL_STEAL) then return "steal";
|
||||
if (skill == SKILL_TRAPS) then return "traps";
|
||||
if (skill == SKILL_SCIENCE) then return "science";
|
||||
if (skill == SKILL_REPAIR) then return "repair";
|
||||
if (skill == SKILL_SNEAK) then return "sneak";
|
||||
return string_format1("skill_%d", skill);
|
||||
end
|
||||
|
||||
procedure obj_name_safe(variable obj) begin
|
||||
if (obj == 0) then return "<null>";
|
||||
return obj_name(obj);
|
||||
end
|
||||
|
||||
procedure useskill_mode_name(variable mode) begin
|
||||
if (mode == 1) then return "useskillon_cancel";
|
||||
if (mode == 2) then return "useskillon_user_override";
|
||||
if (mode == 3) then return "useskillon_allow_combat";
|
||||
if (mode == 4) then return "useskill_override";
|
||||
if (mode == 5) then return "useskill_cancel_steal";
|
||||
return "vanilla";
|
||||
end
|
||||
|
||||
procedure print_mode begin
|
||||
display_msg(string_format1("useskill mode -> %s", useskill_mode_name(useskill_mode)));
|
||||
end
|
||||
|
||||
procedure useskillon_handler begin
|
||||
variable
|
||||
args := get_sfall_args,
|
||||
user := args[0],
|
||||
target := args[1],
|
||||
skill := args[2];
|
||||
|
||||
useskillon_calls++;
|
||||
last_useskillon_skill := skill;
|
||||
|
||||
display_msg(string_format("useskillon mode=%s user=%s target=%s skill=%s",
|
||||
useskill_mode_name(useskill_mode),
|
||||
obj_name_safe(user),
|
||||
obj_name_safe(target),
|
||||
skill_name(skill)));
|
||||
display_msg(string_format1("useskillon args=%s", debug_array_str(args)));
|
||||
|
||||
call assertEquals("useskillon arg count", len_array(args), 3);
|
||||
call assertTrue("useskillon user is set", user != 0);
|
||||
call assertTrue("useskillon target is set", target != 0);
|
||||
|
||||
if (useskill_mode == 1) then begin
|
||||
display_msg("useskillon cancelling skill action");
|
||||
set_sfall_return(-1);
|
||||
end else if (useskill_mode == 2) then begin
|
||||
if (skill == SKILL_STEAL) then begin
|
||||
display_msg("useskillon returning dude_obj for Steal; engine should ignore this return value");
|
||||
end else begin
|
||||
display_msg("useskillon returning dude_obj as user override");
|
||||
end
|
||||
set_sfall_return(dude_obj);
|
||||
end else if (useskill_mode == 3) then begin
|
||||
display_msg("useskillon allowing combat use");
|
||||
set_sfall_return(0);
|
||||
set_sfall_return(1);
|
||||
end
|
||||
end
|
||||
|
||||
procedure useskill_handler begin
|
||||
variable
|
||||
args := get_sfall_args,
|
||||
user := args[0],
|
||||
target := args[1],
|
||||
skill := args[2],
|
||||
skill_bonus := args[3];
|
||||
|
||||
useskill_calls++;
|
||||
last_useskill_skill := skill;
|
||||
|
||||
display_msg(string_format("useskill mode=%s user=%s target=%s skill=%s bonus=%d",
|
||||
useskill_mode_name(useskill_mode),
|
||||
obj_name_safe(user),
|
||||
obj_name_safe(target),
|
||||
skill_name(skill),
|
||||
skill_bonus));
|
||||
display_msg(string_format1("useskill args=%s", debug_array_str(args)));
|
||||
|
||||
call assertEquals("useskill arg count", len_array(args), 4);
|
||||
call assertTrue("useskill user is set", user != 0);
|
||||
call assertTrue("useskill target is set", target != 0);
|
||||
|
||||
if (useskill_mode == 4) then begin
|
||||
display_msg("useskill overriding hard-coded handler with result 1");
|
||||
set_sfall_return(1);
|
||||
end else if (useskill_mode == 5) then begin
|
||||
if (skill == SKILL_STEAL) then begin
|
||||
display_msg("useskill canceling steal by overriding hard-coded handler with result 0");
|
||||
set_sfall_return(0);
|
||||
end
|
||||
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_U) then begin
|
||||
useskill_mode += 1;
|
||||
if (useskill_mode > 5) then useskill_mode := 0;
|
||||
call print_mode;
|
||||
end else if (key == DIK_Y) then begin
|
||||
display_msg(string_format("useskill stats: on=%d skill=%s, handler=%d skill=%s",
|
||||
useskillon_calls,
|
||||
skill_name(last_useskillon_skill),
|
||||
useskill_calls,
|
||||
skill_name(last_useskill_skill)));
|
||||
call report_test_results("hook_useskill");
|
||||
end
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
if (not game_loaded) then return;
|
||||
|
||||
display_msg("useskill manual test ready");
|
||||
display_msg("press U to cycle modes: vanilla / useskillon_cancel / useskillon_user_override / useskillon_allow_combat / useskill_override / useskill_cancel_steal");
|
||||
display_msg("use a Skilldex skill or a medical kit on a valid target; press Y to report assertions");
|
||||
|
||||
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
|
||||
register_hook_proc(HOOK_USESKILLON, useskillon_handler);
|
||||
register_hook_proc(HOOK_USESKILL, useskill_handler);
|
||||
end
|
||||
+25
-22
@@ -1262,20 +1262,18 @@ int actionPickUp(Object* critter, Object* item)
|
||||
return reg_anim_end();
|
||||
}
|
||||
|
||||
// TODO: Looks like the name is a little misleading, container can only be a
|
||||
// critter, which is enforced by this function as well as at the call sites.
|
||||
// Used to loot corpses, so probably should be something like actionLootCorpse.
|
||||
// Check if it can be called with a living critter.
|
||||
// This is primarily used to loot critters, namely corpses. I don't believe it can
|
||||
// be called with a living creature, but am not 100% certain.
|
||||
//
|
||||
// 0x4123E8
|
||||
int _action_loot_container(Object* critter, Object* container)
|
||||
// 0x4123E8 was _action_loot_container
|
||||
int actionLootCritter(Object* critter, Object* target)
|
||||
{
|
||||
if (FID_TYPE(container->fid) != OBJ_TYPE_CRITTER) {
|
||||
if (FID_TYPE(target->fid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SFALL: Fix for trying to loot corpses with the "NoSteal" flag.
|
||||
if (critterFlagCheck(container->pid, CRITTER_NO_STEAL)) {
|
||||
if (critterFlagCheck(target->pid, CRITTER_NO_STEAL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1288,20 +1286,20 @@ int _action_loot_container(Object* critter, Object* container)
|
||||
|
||||
if (isInCombat()) {
|
||||
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
|
||||
animationRegisterMoveToObject(critter, container, critter->data.critter.combat.ap, 0);
|
||||
animationRegisterMoveToObject(critter, target, critter->data.critter.combat.ap, 0);
|
||||
} else {
|
||||
reg_anim_begin(critter == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
|
||||
|
||||
if (objectWithinWalkDistance(critter, container)) {
|
||||
animationRegisterMoveToObject(critter, container, -1, 0);
|
||||
if (objectWithinWalkDistance(critter, target)) {
|
||||
animationRegisterMoveToObject(critter, target, -1, 0);
|
||||
} else {
|
||||
animationRegisterRunToObject(critter, container, -1, 0);
|
||||
animationRegisterRunToObject(critter, target, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
animationRegisterCallbackForced(critter, container, (AnimationCallback*)_is_next_to, -1);
|
||||
animationRegisterCallback(critter, container, (AnimationCallback*)checkSceneryUseActionPointCost, -1);
|
||||
animationRegisterCallback(critter, container, (AnimationCallback*)scriptsRequestLooting, -1);
|
||||
animationRegisterCallbackForced(critter, target, (AnimationCallback*)_is_next_to, -1);
|
||||
animationRegisterCallback(critter, target, (AnimationCallback*)checkSceneryUseActionPointCost, -1);
|
||||
animationRegisterCallback(critter, target, (AnimationCallback*)scriptsRequestLooting, -1);
|
||||
return reg_anim_end();
|
||||
}
|
||||
|
||||
@@ -1338,10 +1336,15 @@ static int _action_use_skill_in_combat_error(Object* critter)
|
||||
// 0x41255C
|
||||
int actionUseSkill(Object* user, Object* target, int skill)
|
||||
{
|
||||
UseSkillOnHookResult hookResult = scriptHooks_UseSkillOn(&user, target, skill);
|
||||
if (!hookResult.shouldContinue) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (skill) {
|
||||
case SKILL_FIRST_AID:
|
||||
case SKILL_DOCTOR:
|
||||
if (isInCombat()) {
|
||||
if (isInCombat() && !hookResult.allowInCombat) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
@@ -1351,7 +1354,7 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
||||
}
|
||||
break;
|
||||
case SKILL_LOCKPICK:
|
||||
if (isInCombat()) {
|
||||
if (isInCombat() && !hookResult.allowInCombat) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
@@ -1362,7 +1365,7 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
||||
|
||||
break;
|
||||
case SKILL_STEAL:
|
||||
if (isInCombat()) {
|
||||
if (isInCombat() && !hookResult.allowInCombat) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
@@ -1377,7 +1380,7 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
||||
|
||||
break;
|
||||
case SKILL_TRAPS:
|
||||
if (isInCombat()) {
|
||||
if (isInCombat() && !hookResult.allowInCombat) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
@@ -1389,7 +1392,7 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
||||
break;
|
||||
case SKILL_SCIENCE:
|
||||
case SKILL_REPAIR:
|
||||
if (isInCombat()) {
|
||||
if (isInCombat() && !hookResult.allowInCombat) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
@@ -1430,9 +1433,9 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
||||
|
||||
// Performer is either dude, or party member who's best at the specified
|
||||
// skill in entire party, and this skill is his/her own best.
|
||||
Object* performer = gDude;
|
||||
Object* performer = hookResult.userOverridden ? user : gDude;
|
||||
|
||||
if (user == gDude) {
|
||||
if (user == gDude && !hookResult.userOverridden) {
|
||||
Object* partyMember = partyMemberGetBestInSkill(skill);
|
||||
|
||||
if (partyMember == gDude) {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ int _action_attack(Attack* attack);
|
||||
int _action_use_an_item_on_object(Object* user, Object* targetObj, Object* item);
|
||||
int _action_use_an_object(Object* user, Object* targetObj);
|
||||
int actionPickUp(Object* critter, Object* item);
|
||||
int _action_loot_container(Object* critter, Object* container);
|
||||
int actionLootCritter(Object* critter, Object* target);
|
||||
int _action_skill_use(int skill);
|
||||
int actionUseSkill(Object* user, Object* target, int skill);
|
||||
bool _is_hit_from_front(const Object* attacker, const Object* defender);
|
||||
|
||||
@@ -263,6 +263,9 @@ int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
|
||||
audioFile->bitsPerSample = 16;
|
||||
|
||||
if (info != nullptr) {
|
||||
// Do not propagate decoder-reported channels by default. Legacy
|
||||
// speech/lips paths rely on the caller's existing mono/stereo
|
||||
// choice unless they explicitly opt into stereo before soundLoad.
|
||||
info->sampleRate = audioFile->sampleRate;
|
||||
info->bitsPerSample = audioFile->bitsPerSample;
|
||||
}
|
||||
|
||||
+7
-2
@@ -10,6 +10,8 @@ namespace fallout {
|
||||
|
||||
#define AUDIO_ENGINE_SOUND_BUFFERS 8
|
||||
|
||||
static constexpr int kAudioEngineTargetSampleRate = 44100;
|
||||
|
||||
struct AudioEngineSoundBuffer {
|
||||
bool active;
|
||||
unsigned int size;
|
||||
@@ -96,14 +98,17 @@ static void audioEngineMixin(void* userData, Uint8* stream, int length)
|
||||
bool audioEngineInit()
|
||||
{
|
||||
SDL_AudioSpec desiredSpec;
|
||||
desiredSpec.freq = 22050;
|
||||
// Request 44.1 kHz output so 44.1 kHz ACM music can play without being
|
||||
// downsampled by the mixer on the common path.
|
||||
desiredSpec.freq = kAudioEngineTargetSampleRate;
|
||||
desiredSpec.format = AUDIO_S16;
|
||||
desiredSpec.channels = 2;
|
||||
desiredSpec.samples = 1024;
|
||||
desiredSpec.callback = audioEngineMixin;
|
||||
|
||||
gAudioEngineDeviceId = SDL_OpenAudioDevice(nullptr, 0, &desiredSpec, &gAudioEngineSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
if (gAudioEngineDeviceId == -1) {
|
||||
if (gAudioEngineDeviceId == 0) {
|
||||
gAudioEngineDeviceId = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
#include "audio_file.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sound.h"
|
||||
#include "sound_decoder.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AudioFileFlags {
|
||||
AUDIO_FILE_IN_USE = 0x01,
|
||||
AUDIO_FILE_COMPRESSED = 0x02,
|
||||
} AudioFileFlags;
|
||||
|
||||
typedef struct AudioFile {
|
||||
int flags;
|
||||
FILE* stream;
|
||||
SoundDecoder* soundDecoder;
|
||||
int fileSize;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int position;
|
||||
} AudioFile;
|
||||
|
||||
static bool defaultCompressionFunc(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned int size);
|
||||
|
||||
// 0x5108C0 queryCompressedFunc_2
|
||||
static AudioFileQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
|
||||
// 0x56CB10 audiof
|
||||
static AudioFile* gAudioFileList;
|
||||
|
||||
// 0x56CB14 numAudiof
|
||||
static int gAudioFileListLength;
|
||||
|
||||
// 0x41A850
|
||||
static bool defaultCompressionFunc(char* filePath)
|
||||
{
|
||||
char* pch = strrchr(filePath, '.');
|
||||
if (pch != nullptr) {
|
||||
strcpy(pch + 1, "raw");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x41A870
|
||||
static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned int size)
|
||||
{
|
||||
return fread(buffer, 1, size, reinterpret_cast<FILE*>(data));
|
||||
}
|
||||
|
||||
// 0x41A88C
|
||||
int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
strcpy(path, fname);
|
||||
|
||||
int compression;
|
||||
if (queryCompressedFunc(path)) {
|
||||
compression = 2;
|
||||
} else {
|
||||
compression = 0;
|
||||
}
|
||||
|
||||
FILE* stream = compat_fopen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
for (index = 0; index < gAudioFileListLength; index++) {
|
||||
if ((gAudioFileList[index].flags & AUDIO_FILE_IN_USE) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == gAudioFileListLength) {
|
||||
if (gAudioFileList != nullptr) {
|
||||
gAudioFileList = (AudioFile*)internal_realloc_safe(gAudioFileList, sizeof(*gAudioFileList) * (gAudioFileListLength + 1), __FILE__, __LINE__); // "..\int\audiof.c", 207
|
||||
} else {
|
||||
gAudioFileList = (AudioFile*)internal_malloc_safe(sizeof(*gAudioFileList), __FILE__, __LINE__); // "..\int\audiof.c", 209
|
||||
}
|
||||
gAudioFileListLength++;
|
||||
}
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[index]);
|
||||
audioFile->flags = AUDIO_FILE_IN_USE;
|
||||
audioFile->stream = stream;
|
||||
|
||||
if (compression == 2) {
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
if (info != nullptr) {
|
||||
info->sampleRate = audioFile->sampleRate;
|
||||
info->bitsPerSample = 16;
|
||||
}
|
||||
if (isMemoryBackedPtr != nullptr) {
|
||||
*isMemoryBackedPtr = false;
|
||||
}
|
||||
} else {
|
||||
audioFile->fileSize = getFileSize(stream);
|
||||
if (info != nullptr) {
|
||||
info->bitsPerSample = 8;
|
||||
}
|
||||
if (isMemoryBackedPtr != nullptr) {
|
||||
*isMemoryBackedPtr = false;
|
||||
}
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
// 0x41AAA0
|
||||
int audioFileClose(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
fclose(audioFile->stream);
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
}
|
||||
|
||||
// Reset audio file (which also resets it's use flag).
|
||||
memset(audioFile, 0, sizeof(*audioFile));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41AB08
|
||||
int audioFileRead(int handle, void* buffer, unsigned int size)
|
||||
{
|
||||
|
||||
AudioFile* ptr = &(gAudioFileList[handle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((ptr->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(ptr->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fread(buffer, 1, size, ptr->stream);
|
||||
}
|
||||
|
||||
ptr->position += bytesRead;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
// 0x41AB74
|
||||
long audioFileSeek(int handle, long offset, int origin)
|
||||
{
|
||||
void* buf;
|
||||
int remaining;
|
||||
int targetPosition;
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
targetPosition = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
targetPosition = audioFile->fileSize + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
targetPosition = audioFile->position + offset;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable");
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if (targetPosition <= audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
|
||||
fseek(audioFile->stream, 0, 0);
|
||||
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
audioFile->position = 0;
|
||||
|
||||
if (targetPosition != 0) {
|
||||
buf = internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audiof.c", 364
|
||||
while (targetPosition > 4096) {
|
||||
audioFileRead(handle, buf, 4096);
|
||||
targetPosition -= 4096;
|
||||
}
|
||||
if (targetPosition != 0) {
|
||||
audioFileRead(handle, buf, targetPosition);
|
||||
}
|
||||
internal_free_safe(buf, __FILE__, __LINE__); // "..\int\audiof.c", 370
|
||||
}
|
||||
} else {
|
||||
buf = internal_malloc_safe(0x400, __FILE__, __LINE__); // "..\int\audiof.c", 316
|
||||
remaining = audioFile->position - targetPosition;
|
||||
while (remaining > 1024) {
|
||||
audioFileRead(handle, buf, 1024);
|
||||
remaining -= 1024;
|
||||
}
|
||||
if (remaining != 0) {
|
||||
audioFileRead(handle, buf, remaining);
|
||||
}
|
||||
// TODO: Obiously leaks memory.
|
||||
}
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
return fseek(audioFile->stream, offset, origin);
|
||||
}
|
||||
|
||||
// 0x41AD20
|
||||
long audioFileGetSize(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
return audioFile->fileSize;
|
||||
}
|
||||
|
||||
// 0x41AD3C
|
||||
long audioFileTell(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
// AudiofWrite
|
||||
// 0x41AD58
|
||||
int audioFileWrite(int handle, const void* buffer, unsigned int size)
|
||||
{
|
||||
debugPrint("AudiofWrite shouldn't be ever called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41AD68
|
||||
int audioFileInit(AudioFileQueryCompressedFunc* func)
|
||||
{
|
||||
queryCompressedFunc = func;
|
||||
gAudioFileList = nullptr;
|
||||
gAudioFileListLength = 0;
|
||||
|
||||
return soundSetDefaultFileIO(audioFileOpen, audioFileClose, audioFileRead, audioFileWrite, audioFileSeek, audioFileTell, audioFileGetSize);
|
||||
}
|
||||
|
||||
// 0x41ADAC
|
||||
void audioFileExit()
|
||||
{
|
||||
if (gAudioFileList != nullptr) {
|
||||
internal_free_safe(gAudioFileList, __FILE__, __LINE__); // "..\int\audiof.c", 405
|
||||
}
|
||||
|
||||
gAudioFileListLength = 0;
|
||||
gAudioFileList = nullptr;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef AUDIO_FILE_H
|
||||
#define AUDIO_FILE_H
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef bool(AudioFileQueryCompressedFunc)(char* filePath);
|
||||
|
||||
int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr);
|
||||
int audioFileClose(int handle);
|
||||
int audioFileRead(int handle, void* buf, unsigned int size);
|
||||
long audioFileSeek(int handle, long offset, int origin);
|
||||
long audioFileGetSize(int handle);
|
||||
long audioFileTell(int handle);
|
||||
int audioFileWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioFileInit(AudioFileQueryCompressedFunc* func);
|
||||
void audioFileExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_FILE_H */
|
||||
+78
-88
@@ -6254,79 +6254,75 @@ static void criticalsInit()
|
||||
}
|
||||
|
||||
if (mode == 1 || mode == 3) {
|
||||
Config criticalsConfig;
|
||||
if (configInit(&criticalsConfig)) {
|
||||
char* criticalsConfigFilePath;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_OVERRIDE_CRITICALS_FILE_KEY, &criticalsConfigFilePath);
|
||||
if (criticalsConfigFilePath != nullptr && *criticalsConfigFilePath == '\0') {
|
||||
criticalsConfigFilePath = nullptr;
|
||||
}
|
||||
char* criticalsConfigFilePath;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_OVERRIDE_CRITICALS_FILE_KEY, &criticalsConfigFilePath);
|
||||
if (criticalsConfigFilePath != nullptr && *criticalsConfigFilePath == '\0') {
|
||||
criticalsConfigFilePath = nullptr;
|
||||
}
|
||||
|
||||
if (configRead(&criticalsConfig, criticalsConfigFilePath, false)) {
|
||||
if (mode == 1) {
|
||||
char sectionKey[16];
|
||||
ScopedConfig criticalsConfig(criticalsConfigFilePath, false);
|
||||
if (criticalsConfig) {
|
||||
if (mode == 1) {
|
||||
char sectionKey[16];
|
||||
|
||||
// Read original kill types (19) plus one for the player.
|
||||
for (int killType = 0; killType < KILL_TYPE_COUNT + 1; killType++) {
|
||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||
snprintf(sectionKey, sizeof(sectionKey), "c_%02d_%d_%d", killType, hitLocation, effect);
|
||||
// Read original kill types (19) plus one for the player.
|
||||
for (int killType = 0; killType < KILL_TYPE_COUNT + 1; killType++) {
|
||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||
snprintf(sectionKey, sizeof(sectionKey), "c_%02d_%d_%d", killType, hitLocation, effect);
|
||||
|
||||
// Update player kill type if needed.
|
||||
int newKillType = killType == KILL_TYPE_COUNT ? SFALL_KILL_TYPE_COUNT : killType;
|
||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||
int value = criticalsGetValue(newKillType, hitLocation, effect, dataMember);
|
||||
if (configGetInt(&criticalsConfig, sectionKey, gCritDataMemberKeys[dataMember], &value)) {
|
||||
criticalsSetValue(newKillType, hitLocation, effect, dataMember, value);
|
||||
}
|
||||
// Update player kill type if needed.
|
||||
int newKillType = killType == KILL_TYPE_COUNT ? SFALL_KILL_TYPE_COUNT : killType;
|
||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||
int value = criticalsGetValue(newKillType, hitLocation, effect, dataMember);
|
||||
if (configGetInt(criticalsConfig.get(), sectionKey, gCritDataMemberKeys[dataMember], &value)) {
|
||||
criticalsSetValue(newKillType, hitLocation, effect, dataMember, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mode == 3) {
|
||||
char ktSectionKey[32];
|
||||
char hitLocationSectionKey[32];
|
||||
char key[32];
|
||||
}
|
||||
} else if (mode == 3) {
|
||||
char ktSectionKey[32];
|
||||
char hitLocationSectionKey[32];
|
||||
char key[32];
|
||||
|
||||
// Read Sfall kill types (38) plus one for the player.
|
||||
for (int killType = 0; killType < SFALL_KILL_TYPE_COUNT + 1; killType++) {
|
||||
snprintf(ktSectionKey, sizeof(ktSectionKey), "c_%02d", killType);
|
||||
// Read Sfall kill types (38) plus one for the player.
|
||||
for (int killType = 0; killType < SFALL_KILL_TYPE_COUNT + 1; killType++) {
|
||||
snprintf(ktSectionKey, sizeof(ktSectionKey), "c_%02d", killType);
|
||||
|
||||
int enabled = 0;
|
||||
configGetInt(&criticalsConfig, ktSectionKey, "Enabled", &enabled);
|
||||
if (enabled == 0) {
|
||||
continue;
|
||||
int enabled = 0;
|
||||
configGetInt(criticalsConfig.get(), ktSectionKey, "Enabled", &enabled);
|
||||
if (enabled == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||
if (enabled < 2) {
|
||||
bool hitLocationChanged = false;
|
||||
|
||||
snprintf(key, sizeof(key), "Part_%d", hitLocation);
|
||||
configGetBool(criticalsConfig.get(), ktSectionKey, key, &hitLocationChanged);
|
||||
|
||||
if (!hitLocationChanged) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||
if (enabled < 2) {
|
||||
bool hitLocationChanged = false;
|
||||
snprintf(hitLocationSectionKey, sizeof(hitLocationSectionKey), "c_%02d_%d", killType, hitLocation);
|
||||
|
||||
snprintf(key, sizeof(key), "Part_%d", hitLocation);
|
||||
configGetBool(&criticalsConfig, ktSectionKey, key, &hitLocationChanged);
|
||||
|
||||
if (!hitLocationChanged) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(hitLocationSectionKey, sizeof(hitLocationSectionKey), "c_%02d_%d", killType, hitLocation);
|
||||
|
||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||
int value = criticalsGetValue(killType, hitLocation, effect, dataMember);
|
||||
snprintf(key, sizeof(key), "e%d_%s", effect, gCritDataMemberKeys[dataMember]);
|
||||
if (configGetInt(&criticalsConfig, hitLocationSectionKey, key, &value)) {
|
||||
criticalsSetValue(killType, hitLocation, effect, dataMember, value);
|
||||
}
|
||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||
int value = criticalsGetValue(killType, hitLocation, effect, dataMember);
|
||||
snprintf(key, sizeof(key), "e%d_%s", effect, gCritDataMemberKeys[dataMember]);
|
||||
if (configGetInt(criticalsConfig.get(), hitLocationSectionKey, key, &value)) {
|
||||
criticalsSetValue(killType, hitLocation, effect, dataMember, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFree(&criticalsConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6600,46 +6596,40 @@ static void unarmedInitCustom()
|
||||
{
|
||||
char* unarmedFileName = nullptr;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_UNARMED_FILE_KEY, &unarmedFileName);
|
||||
if (unarmedFileName != nullptr && *unarmedFileName == '\0') {
|
||||
unarmedFileName = nullptr;
|
||||
}
|
||||
|
||||
if (unarmedFileName == nullptr) {
|
||||
if (unarmedFileName == nullptr || *unarmedFileName == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
Config unarmedConfig;
|
||||
if (configInit(&unarmedConfig)) {
|
||||
if (configRead(&unarmedConfig, unarmedFileName, false)) {
|
||||
char section[4];
|
||||
char statKey[6];
|
||||
ScopedConfig unarmedConfig(unarmedFileName, false);
|
||||
if (!unarmedConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int hitMode = 0; hitMode < HIT_MODE_COUNT; hitMode++) {
|
||||
if (!isUnarmedHitMode(hitMode)) {
|
||||
continue;
|
||||
}
|
||||
char section[4];
|
||||
char statKey[6];
|
||||
|
||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||
snprintf(section, sizeof(section), "%d", hitMode);
|
||||
|
||||
configGetInt(&unarmedConfig, section, "ReqLevel", &(hitDescription->requiredLevel));
|
||||
configGetInt(&unarmedConfig, section, "SkillLevel", &(hitDescription->requiredSkill));
|
||||
configGetInt(&unarmedConfig, section, "MinDamage", &(hitDescription->minDamage));
|
||||
configGetInt(&unarmedConfig, section, "MaxDamage", &(hitDescription->maxDamage));
|
||||
configGetInt(&unarmedConfig, section, "BonusDamage", &(hitDescription->bonusDamage));
|
||||
configGetInt(&unarmedConfig, section, "BonusCrit", &(hitDescription->bonusCriticalChance));
|
||||
configGetInt(&unarmedConfig, section, "APCost", &(hitDescription->actionPointCost));
|
||||
configGetBool(&unarmedConfig, section, "BonusDamage", &(hitDescription->isPenetrate));
|
||||
configGetBool(&unarmedConfig, section, "Secondary", &(hitDescription->isSecondary));
|
||||
|
||||
for (int stat = 0; stat < PRIMARY_STAT_COUNT; stat++) {
|
||||
snprintf(statKey, sizeof(statKey), "Stat%d", stat);
|
||||
configGetInt(&unarmedConfig, section, statKey, &(hitDescription->requiredStats[stat]));
|
||||
}
|
||||
}
|
||||
for (int hitMode = 0; hitMode < HIT_MODE_COUNT; hitMode++) {
|
||||
if (!isUnarmedHitMode(hitMode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
configFree(&unarmedConfig);
|
||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||
snprintf(section, sizeof(section), "%d", hitMode);
|
||||
|
||||
configGetInt(unarmedConfig.get(), section, "ReqLevel", &(hitDescription->requiredLevel));
|
||||
configGetInt(unarmedConfig.get(), section, "SkillLevel", &(hitDescription->requiredSkill));
|
||||
configGetInt(unarmedConfig.get(), section, "MinDamage", &(hitDescription->minDamage));
|
||||
configGetInt(unarmedConfig.get(), section, "MaxDamage", &(hitDescription->maxDamage));
|
||||
configGetInt(unarmedConfig.get(), section, "BonusDamage", &(hitDescription->bonusDamage));
|
||||
configGetInt(unarmedConfig.get(), section, "BonusCrit", &(hitDescription->bonusCriticalChance));
|
||||
configGetInt(unarmedConfig.get(), section, "APCost", &(hitDescription->actionPointCost));
|
||||
configGetBool(unarmedConfig.get(), section, "BonusDamage", &(hitDescription->isPenetrate));
|
||||
configGetBool(unarmedConfig.get(), section, "Secondary", &(hitDescription->isSecondary));
|
||||
|
||||
for (int stat = 0; stat < PRIMARY_STAT_COUNT; stat++) {
|
||||
snprintf(statKey, sizeof(statKey), "Stat%d", stat);
|
||||
configGetInt(unarmedConfig.get(), section, statKey, &(hitDescription->requiredStats[stat]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+55
-63
@@ -378,81 +378,77 @@ int aiInit()
|
||||
|
||||
gAiPacketsLength = 0;
|
||||
|
||||
Config config;
|
||||
if (!configInit(&config)) {
|
||||
ScopedConfig config("data\\ai.txt", true);
|
||||
if (!config) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!configRead(&config, "data\\ai.txt", true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gAiPackets = (AiPacket*)internal_malloc(sizeof(*gAiPackets) * config.entriesLength);
|
||||
gAiPackets = (AiPacket*)internal_malloc(sizeof(*gAiPackets) * config.get()->entriesLength);
|
||||
if (gAiPackets == nullptr) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (index = 0; index < config.entriesLength; index++) {
|
||||
for (index = 0; index < config.get()->entriesLength; index++) {
|
||||
aiPacketInit(&(gAiPackets[index]));
|
||||
}
|
||||
|
||||
for (index = 0; index < config.entriesLength; index++) {
|
||||
DictionaryEntry* sectionEntry = &(config.entries[index]);
|
||||
for (index = 0; index < config.get()->entriesLength; index++) {
|
||||
DictionaryEntry* sectionEntry = &(config.get()->entries[index]);
|
||||
AiPacket* ai = &(gAiPackets[index]);
|
||||
char* stringValue;
|
||||
|
||||
ai->name = internal_strdup(sectionEntry->key);
|
||||
|
||||
if (!configGetInt(&config, sectionEntry->key, "packet_num", &(ai->packet_num))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "max_dist", &(ai->max_dist))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "min_to_hit", &(ai->min_to_hit))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "min_hp", &(ai->min_hp))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "aggression", &(ai->aggression))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "packet_num", &(ai->packet_num))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "max_dist", &(ai->max_dist))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "min_to_hit", &(ai->min_to_hit))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "min_hp", &(ai->min_hp))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "aggression", &(ai->aggression))) goto err;
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "hurt_too_much", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "hurt_too_much", &stringValue)) {
|
||||
_parse_hurt_str(stringValue, &(ai->hurt_too_much));
|
||||
}
|
||||
|
||||
if (!configGetInt(&config, sectionEntry->key, "secondary_freq", &(ai->secondary_freq))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "called_freq", &(ai->called_freq))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "font", &(ai->font))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "color", &(ai->color))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "outline_color", &(ai->outline_color))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "chance", &(ai->chance))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "run_start", &(ai->run.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "run_end", &(ai->run.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "move_start", &(ai->move.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "move_end", &(ai->move.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "attack_start", &(ai->attack.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "attack_end", &(ai->attack.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "miss_start", &(ai->miss.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "miss_end", &(ai->miss.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_head_start", &(ai->hit[HIT_LOCATION_HEAD].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_head_end", &(ai->hit[HIT_LOCATION_HEAD].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_arm_start", &(ai->hit[HIT_LOCATION_LEFT_ARM].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_arm_end", &(ai->hit[HIT_LOCATION_LEFT_ARM].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_arm_start", &(ai->hit[HIT_LOCATION_RIGHT_ARM].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_arm_end", &(ai->hit[HIT_LOCATION_RIGHT_ARM].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_torso_start", &(ai->hit[HIT_LOCATION_TORSO].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_torso_end", &(ai->hit[HIT_LOCATION_TORSO].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_leg_start", &(ai->hit[HIT_LOCATION_RIGHT_LEG].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_leg_end", &(ai->hit[HIT_LOCATION_RIGHT_LEG].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_leg_start", &(ai->hit[HIT_LOCATION_LEFT_LEG].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_leg_end", &(ai->hit[HIT_LOCATION_LEFT_LEG].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_eyes_start", &(ai->hit[HIT_LOCATION_EYES].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_eyes_end", &(ai->hit[HIT_LOCATION_EYES].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_groin_start", &(ai->hit[HIT_LOCATION_GROIN].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_groin_end", &(ai->hit[HIT_LOCATION_GROIN].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "secondary_freq", &(ai->secondary_freq))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "called_freq", &(ai->called_freq))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "font", &(ai->font))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "color", &(ai->color))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "outline_color", &(ai->outline_color))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "chance", &(ai->chance))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "run_start", &(ai->run.start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "run_end", &(ai->run.end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "move_start", &(ai->move.start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "move_end", &(ai->move.end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "attack_start", &(ai->attack.start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "attack_end", &(ai->attack.end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "miss_start", &(ai->miss.start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "miss_end", &(ai->miss.end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_head_start", &(ai->hit[HIT_LOCATION_HEAD].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_head_end", &(ai->hit[HIT_LOCATION_HEAD].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_left_arm_start", &(ai->hit[HIT_LOCATION_LEFT_ARM].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_left_arm_end", &(ai->hit[HIT_LOCATION_LEFT_ARM].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_right_arm_start", &(ai->hit[HIT_LOCATION_RIGHT_ARM].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_right_arm_end", &(ai->hit[HIT_LOCATION_RIGHT_ARM].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_torso_start", &(ai->hit[HIT_LOCATION_TORSO].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_torso_end", &(ai->hit[HIT_LOCATION_TORSO].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_right_leg_start", &(ai->hit[HIT_LOCATION_RIGHT_LEG].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_right_leg_end", &(ai->hit[HIT_LOCATION_RIGHT_LEG].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_left_leg_start", &(ai->hit[HIT_LOCATION_LEFT_LEG].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_left_leg_end", &(ai->hit[HIT_LOCATION_LEFT_LEG].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_eyes_start", &(ai->hit[HIT_LOCATION_EYES].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_eyes_end", &(ai->hit[HIT_LOCATION_EYES].end))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_groin_start", &(ai->hit[HIT_LOCATION_GROIN].start))) goto err;
|
||||
if (!configGetInt(config.get(), sectionEntry->key, "hit_groin_end", &(ai->hit[HIT_LOCATION_GROIN].end))) goto err;
|
||||
|
||||
ai->hit[HIT_LOCATION_GROIN].end++;
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "area_attack_mode", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "area_attack_mode", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gAreaAttackModeKeys, AREA_ATTACK_MODE_COUNT, &(ai->area_attack_mode));
|
||||
} else {
|
||||
ai->area_attack_mode = -1;
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "run_away_mode", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "run_away_mode", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gRunAwayModeKeys, RUN_AWAY_MODE_COUNT, &(ai->run_away_mode));
|
||||
|
||||
if (ai->run_away_mode >= 0) {
|
||||
@@ -460,49 +456,47 @@ int aiInit()
|
||||
}
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "best_weapon", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "best_weapon", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gBestWeaponKeys, BEST_WEAPON_COUNT, &(ai->best_weapon));
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "distance", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "distance", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gDistanceModeKeys, DISTANCE_COUNT, &(ai->distance));
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "attack_who", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "attack_who", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gAttackWhoKeys, ATTACK_WHO_COUNT, &(ai->attack_who));
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "chem_use", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "chem_use", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gChemUseKeys, CHEM_USE_COUNT, &(ai->chem_use));
|
||||
}
|
||||
|
||||
configGetIntList(&config, sectionEntry->key, "chem_primary_desire", ai->chem_primary_desire, AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT);
|
||||
configGetIntList(config.get(), sectionEntry->key, "chem_primary_desire", ai->chem_primary_desire, AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT);
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "disposition", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "disposition", &stringValue)) {
|
||||
_cai_match_str_to_list(stringValue, gDispositionKeys, DISPOSITION_COUNT, &(ai->disposition));
|
||||
ai->disposition--;
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "body_type", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "body_type", &stringValue)) {
|
||||
ai->body_type = internal_strdup(stringValue);
|
||||
} else {
|
||||
ai->body_type = nullptr;
|
||||
}
|
||||
|
||||
if (configGetString(&config, sectionEntry->key, "general_type", &stringValue)) {
|
||||
if (configGetString(config.get(), sectionEntry->key, "general_type", &stringValue)) {
|
||||
ai->general_type = internal_strdup(stringValue);
|
||||
} else {
|
||||
ai->general_type = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < config.entriesLength) {
|
||||
if (index < config.get()->entriesLength) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gAiPacketsLength = config.entriesLength;
|
||||
|
||||
configFree(&config);
|
||||
gAiPacketsLength = config.get()->entriesLength;
|
||||
|
||||
gAiInitialized = true;
|
||||
|
||||
@@ -511,7 +505,7 @@ int aiInit()
|
||||
err:
|
||||
|
||||
if (gAiPackets != nullptr) {
|
||||
for (index = 0; index < config.entriesLength; index++) {
|
||||
for (index = 0; index < config.get()->entriesLength; index++) {
|
||||
AiPacket* ai = &(gAiPackets[index]);
|
||||
if (ai->name != nullptr) {
|
||||
internal_free(ai->name);
|
||||
@@ -525,8 +519,6 @@ err:
|
||||
|
||||
debugPrint("Error processing ai.txt");
|
||||
|
||||
configFree(&config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user