mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2de6715dd | ||
|
|
df4b787e86 | ||
|
|
6b442546cc | ||
|
|
2c08cc0b3a | ||
|
|
09a1971cd8 | ||
|
|
7ae0452e1a | ||
|
|
f63c113d77 | ||
|
|
f8ad77061b | ||
|
|
924e12b94c | ||
|
|
706785d60e | ||
|
|
1175efd379 | ||
|
|
ab2a09610d | ||
|
|
cef24823f4 | ||
|
|
63d79e4bfd | ||
|
|
e42d8021c1 | ||
|
|
8254c758fe | ||
|
|
8b2ead8a2b | ||
|
|
4f89bb7d77 | ||
|
|
0d8741e082 | ||
|
|
6ce6bea309 | ||
|
|
6027c7cf2e |
+115
-4
@@ -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,7 +38,9 @@ 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"
|
||||
@@ -151,8 +156,6 @@ 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"
|
||||
@@ -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"
|
||||
@@ -200,6 +205,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/proto_types.h"
|
||||
"src/proto.cc"
|
||||
"src/proto.h"
|
||||
"src/prototype_options.cc"
|
||||
"src/prototype_options.h"
|
||||
"src/queue.cc"
|
||||
"src/queue.h"
|
||||
"src/random.cc"
|
||||
@@ -263,7 +270,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 +304,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 +318,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"
|
||||
@@ -527,6 +571,73 @@ 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/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_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
|
||||
)
|
||||
target_link_libraries(mapper-ce
|
||||
winmm
|
||||
debug libcpmtd
|
||||
optimized libcpmt
|
||||
)
|
||||
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}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
|
||||
|
||||
@@ -43,7 +43,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 | âś… | - |
|
||||
@@ -58,7 +58,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| 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. |
|
||||
| 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 | - |
|
||||
@@ -72,7 +72,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| 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 | - |
|
||||
| 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. |
|
||||
|
||||
@@ -98,11 +98,11 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| 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 |
|
||||
| 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` | âś… | - |
|
||||
@@ -124,5 +124,5 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| AdjustRads | `HOOK_ADJUSTRADS` | đźš« | (maybe) |
|
||||
| RollCheck | `HOOK_ROLLCHECK` | đźš« | - |
|
||||
| BestWeapon | `HOOK_BESTWEAPON` | đźš« | - |
|
||||
| CanUseWeapon | `HOOK_CANUSEWEAPON` | đźš« | - |
|
||||
| CanUseWeapon | `HOOK_CANUSEWEAPON` | âś… | - |
|
||||
| BuildSfxWeapon | `HOOK_BUILDSFXWEAPON` | đźš« | - |
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
@@ -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)
|
||||
@@ -120,3 +126,5 @@ inventory_columns=2
|
||||
auto_open_doors=0
|
||||
; Overrides distance at which walk animation is used when using an object.
|
||||
use_walk_distance=5
|
||||
; Allow switching to companions' inventories in loot screens (and barter, in the future)
|
||||
party_loot_and_barter=1
|
||||
|
||||
@@ -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"]];
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "sfall.h"
|
||||
#include "dik.h"
|
||||
#include "lib.arrays.h"
|
||||
|
||||
variable steal_mode := 0;
|
||||
|
||||
procedure steal_mode_name(variable mode) begin
|
||||
if (mode == 1) then return "force_success";
|
||||
if (mode == 2) then return "caught_fail";
|
||||
if (mode == 3) then return "silent_fail";
|
||||
if (mode == 4) then return "xp_override";
|
||||
return "vanilla";
|
||||
end
|
||||
|
||||
procedure steal_handler begin
|
||||
variable
|
||||
args := get_sfall_args,
|
||||
thief := args[0],
|
||||
target := args[1],
|
||||
item := args[2],
|
||||
is_planting := args[3],
|
||||
quantity := args[4],
|
||||
thief_name := "<null>",
|
||||
target_name := "<null>",
|
||||
item_name := "<null>";
|
||||
|
||||
if (thief) then thief_name := obj_name(thief);
|
||||
if (target) then target_name := obj_name(target);
|
||||
if (item) then item_name := obj_name(item);
|
||||
|
||||
display_msg(string_format6("steal mode=%s thief=%s target=%s item=%s planting=%d qty=%d",
|
||||
steal_mode_name(steal_mode),
|
||||
thief_name,
|
||||
target_name,
|
||||
item_name,
|
||||
is_planting,
|
||||
quantity));
|
||||
display_msg(string_format1("steal args=%s", debug_array_str(args)));
|
||||
|
||||
if (thief != dude_obj) then return;
|
||||
|
||||
if (steal_mode == 1) then begin
|
||||
display_msg("steal forcing success");
|
||||
display_msg(sprintf(mstr_skill(571 + is_planting * 2), item_name));
|
||||
set_sfall_return(1);
|
||||
end else if (steal_mode == 2) then begin
|
||||
display_msg("steal forcing caught failure");
|
||||
display_msg(sprintf(mstr_skill(570 + is_planting * 2), item_name));
|
||||
set_sfall_return(0);
|
||||
end else if (steal_mode == 3) then begin
|
||||
display_msg("steal forcing silent failure");
|
||||
set_sfall_return(2);
|
||||
end else if (steal_mode == 4) then begin
|
||||
display_msg("steal forcing success with xp override 77");
|
||||
display_msg(sprintf(mstr_skill(571 + is_planting * 2), item_name));
|
||||
set_sfall_return(1);
|
||||
set_sfall_return(77);
|
||||
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;
|
||||
|
||||
steal_mode += 1;
|
||||
if (steal_mode > 4) then steal_mode := 0;
|
||||
|
||||
display_msg(string_format1("steal mode -> %s", steal_mode_name(steal_mode)));
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
if (not game_loaded) then return;
|
||||
|
||||
display_msg("steal manual test ready: press X to cycle vanilla / force_success / caught_fail / silent_fail / xp_override");
|
||||
display_msg("open a steal screen and move an item in either direction; mode 4 should award 77 XP for a successful action");
|
||||
|
||||
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
|
||||
register_hook_proc(HOOK_STEAL, steal_handler);
|
||||
end
|
||||
+5
-5
@@ -46,13 +46,13 @@ typedef enum ScienceRepairTargetType {
|
||||
SCIENCE_REPAIR_TARGET_TYPE_ANYONE,
|
||||
} ScienceRepairTargetType;
|
||||
|
||||
// 0x5106D0
|
||||
// 0x5106D0 action_in_explode
|
||||
static bool _action_in_explode = false;
|
||||
|
||||
// 0x5106D4
|
||||
// 0x5106D4 rotation
|
||||
int rotation;
|
||||
|
||||
// 0x5106E0
|
||||
// 0x5106E0 death_2
|
||||
static const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT] = {
|
||||
ANIM_DANCING_AUTOFIRE,
|
||||
ANIM_SLICED_IN_HALF,
|
||||
@@ -63,7 +63,7 @@ static const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT] = {
|
||||
ANIM_BIG_HOLE,
|
||||
};
|
||||
|
||||
// 0x5106FC
|
||||
// 0x5106FC death_3
|
||||
static const int gMaximumBloodDeathAnimations[DAMAGE_TYPE_COUNT] = {
|
||||
ANIM_CHUNKS_OF_FLESH,
|
||||
ANIM_SLICED_IN_HALF,
|
||||
@@ -519,7 +519,7 @@ int _show_death(Object* obj, int anim)
|
||||
|
||||
// Animates damage to extras in a given attack (secondary targets).
|
||||
//
|
||||
// 0x410FEC _show_damage_extras
|
||||
// 0x410FEC show_damage_extras
|
||||
int showDamageToExtras(Attack* attack)
|
||||
{
|
||||
for (int index = 0; index < attack->extrasLength; index++) {
|
||||
|
||||
+11
-11
@@ -309,39 +309,39 @@ static unsigned int animationComputeTicksPerFrame(Object* object, int fid);
|
||||
|
||||
static void reportOverloaded(Object* critter);
|
||||
|
||||
// 0x510718
|
||||
// 0x510718 curr_sad
|
||||
static int gAnimationCurrentSad = 0;
|
||||
|
||||
// 0x51071C
|
||||
// 0x51071C curr_anim_set
|
||||
static int gAnimationSequenceCurrentIndex = -1;
|
||||
|
||||
// 0x510720
|
||||
// 0x510720 anim_in_init
|
||||
static bool gAnimationInInit = false;
|
||||
|
||||
// 0x510724
|
||||
// 0x510724 anim_in_anim_stop
|
||||
static bool gAnimationInStop = false;
|
||||
|
||||
// 0x510728
|
||||
// 0x510728 anim_in_bk
|
||||
static bool _anim_in_bk = false;
|
||||
|
||||
// 0x530014
|
||||
// 0x530014 sad
|
||||
static AnimationSad gAnimationSads[ANIMATION_SAD_LIST_CAPACITY];
|
||||
|
||||
#define PATH_NODE_CAPACITY 10000
|
||||
|
||||
// 0x542FD4
|
||||
// 0x542FD4 dad
|
||||
static PathNode gClosedPathNodeList[PATH_NODE_CAPACITY];
|
||||
|
||||
// 0x54CC14
|
||||
// 0x54CC14 anim_set
|
||||
static AnimationSequence gAnimationSequences[32];
|
||||
|
||||
// 0x561814
|
||||
// 0x561814 seen_tile
|
||||
static unsigned char gPathfinderProcessedTiles[5000];
|
||||
|
||||
// 0x562B9C
|
||||
// 0x562B9C child_path
|
||||
static PathNode gOpenPathNodeList[PATH_NODE_CAPACITY];
|
||||
|
||||
// 0x56C7DC
|
||||
// 0x56C7DC curr_anim_counter
|
||||
static int gAnimationDescriptionCurrentIndex;
|
||||
|
||||
// anim_init
|
||||
|
||||
+220
-26
@@ -1,6 +1,9 @@
|
||||
#include "art.h"
|
||||
|
||||
#include <lodepng.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -44,19 +47,19 @@ static int artReadHeader(Art* art, File* stream);
|
||||
static int artGetDataSize(const Art* art);
|
||||
static int paddingForSize(int size);
|
||||
|
||||
// 0x5002D8
|
||||
// 0x5002D8 str2
|
||||
static char gDefaultJumpsuitMaleFileName[] = "hmjmps";
|
||||
|
||||
// 0x05002E0
|
||||
// 0x05002E0 aHfjmps
|
||||
static char gDefaultJumpsuitFemaleFileName[] = "hfjmps";
|
||||
|
||||
// 0x5002E8
|
||||
// 0x5002E8 aHmwarr
|
||||
static char gDefaultTribalMaleFileName[] = "hmwarr";
|
||||
|
||||
// 0x5002F0
|
||||
// 0x5002F0 aHfprim
|
||||
static char gDefaultTribalFemaleFileName[] = "hfprim";
|
||||
|
||||
// 0x510738
|
||||
// 0x510738 art
|
||||
static ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT] = {
|
||||
{ 0, "items", nullptr, nullptr, 0 },
|
||||
{ 0, "critters", nullptr, nullptr, 0 },
|
||||
@@ -74,18 +77,18 @@ static ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT] = {
|
||||
// This flag denotes that localized arts should be looked up first. Used
|
||||
// together with [gArtLanguage].
|
||||
//
|
||||
// 0x510898
|
||||
// 0x510898 darn_foreigners
|
||||
static bool gArtLanguageInitialized = false;
|
||||
|
||||
// 0x51089C
|
||||
// 0x51089C head1
|
||||
static const char* _head1 = "gggnnnbbbgnb";
|
||||
|
||||
// 0x5108A0
|
||||
// 0x5108A0 head2
|
||||
static const char* _head2 = "vfngfbnfvppp";
|
||||
|
||||
// Current native look base fid.
|
||||
//
|
||||
// 0x5108A4
|
||||
// 0x5108A4 art_vault_guy_num
|
||||
int _art_vault_guy_num = 0;
|
||||
|
||||
// Base fids for unarmored dude.
|
||||
@@ -99,41 +102,42 @@ int _art_vault_guy_num = 0;
|
||||
// been accessed differently in 0x49F984, which clearly uses look type as an
|
||||
// index, not gender.
|
||||
//
|
||||
// 0x5108A8
|
||||
// 0x5108A8 art_vault_person_nums
|
||||
int _art_vault_person_nums[DUDE_NATIVE_LOOK_COUNT][GENDER_COUNT];
|
||||
|
||||
// Index of "grid001.frm" in tiles.lst.
|
||||
//
|
||||
// 0x5108B8
|
||||
// 0x5108B8 art_mapper_blank_tile
|
||||
static int _art_mapper_blank_tile = 1;
|
||||
|
||||
// Non-english language name.
|
||||
//
|
||||
// This value is used as a directory name to display localized arts.
|
||||
//
|
||||
// 0x56C970
|
||||
// 0x56C970 darn_foreign_sub_path
|
||||
static char gArtLanguage[32];
|
||||
|
||||
// 0x56C990
|
||||
// 0x56C990 art_cache
|
||||
Cache gArtCache;
|
||||
|
||||
// 0x56C9E4
|
||||
// 0x56C9E4 art_name
|
||||
static char _art_name[COMPAT_MAX_PATH];
|
||||
|
||||
// head_info
|
||||
// 0x56CAE8
|
||||
// 0x56CAE8 head_info
|
||||
static HeadDescription* gHeadDescriptions;
|
||||
|
||||
// anon_alias
|
||||
// 0x56CAEC
|
||||
// 0x56CAEC anon_alias
|
||||
static int* _anon_alias;
|
||||
|
||||
// artCritterFidShouldRunData
|
||||
// 0x56CAF0
|
||||
// 0x56CAF0 artCritterFidShouldRunData
|
||||
static int* gArtCritterFidShoudRunData;
|
||||
|
||||
static std::unordered_map<std::string, std::shared_ptr<NamedCacheEntry>> gNamedArtCache;
|
||||
constexpr int kNamedCacheMaxBytes = 32 * 1024 * 1024; // 32MB soft limit
|
||||
constexpr size_t kMaxNamedPngPixels = 16 * 1024 * 1024;
|
||||
static unsigned int gNamedArtCacheMruCounter = 0;
|
||||
static int gNamedArtCacheCurrentBytes = 0;
|
||||
|
||||
@@ -355,6 +359,14 @@ int artIsObjectTypeHidden(int objectType)
|
||||
return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0;
|
||||
}
|
||||
|
||||
// 0x409DF0
|
||||
void artToggleObjectTypeHidden(int objectType)
|
||||
{
|
||||
if (objectType >= 0 && objectType < OBJ_TYPE_COUNT) {
|
||||
gArtListDescriptions[objectType].flags ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x418F7C
|
||||
int artGetFidgetCount(int headFid)
|
||||
{
|
||||
@@ -444,6 +456,40 @@ int art_list_str(int fid, char* name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int artListIndex(int objectType, const char* name)
|
||||
{
|
||||
if (objectType < 0 || objectType >= OBJ_TYPE_COUNT) return -1;
|
||||
if (gArtListDescriptions[objectType].fileNames == nullptr) return -1;
|
||||
|
||||
char upperName[13] = { 0 };
|
||||
strncpy(upperName, name, 12);
|
||||
upperName[12] = '\0';
|
||||
compat_strupr(upperName);
|
||||
|
||||
int length = gArtListDescriptions[objectType].fileNamesLength;
|
||||
const char* fileNames = gArtListDescriptions[objectType].fileNames;
|
||||
|
||||
for (int index = 0; index < length; index++) {
|
||||
const char* entry = fileNames + index * 13;
|
||||
|
||||
char upperEntry[13];
|
||||
strncpy(upperEntry, entry, 12);
|
||||
upperEntry[12] = '\0';
|
||||
compat_strupr(upperEntry);
|
||||
|
||||
char* p = upperEntry;
|
||||
while (*p && ((*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_'))
|
||||
p++;
|
||||
*p = '\0';
|
||||
|
||||
if (strcmp(upperEntry, upperName) == 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x419160
|
||||
Art* artLock(int fid, CacheEntry** handlePtr)
|
||||
{
|
||||
@@ -1074,7 +1120,7 @@ static int artReadFrameData(unsigned char* data, File* stream, int count, int* p
|
||||
// 0x419E1C
|
||||
static int artReadHeader(Art* art, File* stream)
|
||||
{
|
||||
if (fileReadInt32(stream, &(art->field_0)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(art->version)) == -1) return -1;
|
||||
if (fileReadInt16(stream, &(art->framesPerSecond)) == -1) return -1;
|
||||
if (fileReadInt16(stream, &(art->actionFrame)) == -1) return -1;
|
||||
if (fileReadInt16(stream, &(art->frameCount)) == -1) return -1;
|
||||
@@ -1091,13 +1137,137 @@ static int artReadHeader(Art* art, File* stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Original function was slightly different, but never used. Basically
|
||||
// it's a memory allocating variant of `artRead` (which reads data into given
|
||||
// buffer). This function is useful to load custom `frm` files since `Art` now
|
||||
// needs more memory then it's on-disk size (due to memory padding).
|
||||
//
|
||||
// 0x419EC0
|
||||
Art* artLoad(const char* path)
|
||||
static bool artPathHasExtension(const char* path, const char* extension)
|
||||
{
|
||||
size_t pathLength = strlen(path);
|
||||
size_t extensionLength = strlen(extension);
|
||||
if (pathLength < extensionLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return compat_stricmp(path + pathLength - extensionLength, extension) == 0;
|
||||
}
|
||||
|
||||
static bool artReadFile(const char* path, std::vector<unsigned char>& data)
|
||||
{
|
||||
int size = 0;
|
||||
if (dbGetFileSize(path, &size) != 0 || size <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data.resize(size);
|
||||
return dbGetFileContents(path, data.data()) == 0;
|
||||
}
|
||||
|
||||
static bool artUnpackIndexedPngPixels(const std::vector<unsigned char>& indexedData, unsigned width, unsigned height, unsigned bitdepth, unsigned char* output)
|
||||
{
|
||||
size_t pixelCount = static_cast<size_t>(width) * static_cast<size_t>(height);
|
||||
if (bitdepth == 8) {
|
||||
if (indexedData.size() < pixelCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(output, indexedData.data(), pixelCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char mask = static_cast<unsigned char>((1 << bitdepth) - 1);
|
||||
size_t neededBytes = (pixelCount * bitdepth + 7) / 8;
|
||||
if (indexedData.size() < neededBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < pixelCount; index++) {
|
||||
size_t bitOffset = index * bitdepth;
|
||||
unsigned char byte = indexedData[bitOffset / 8];
|
||||
unsigned shift = 8 - bitdepth - static_cast<unsigned>(bitOffset % 8);
|
||||
output[index] = (byte >> shift) & mask;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static Art* artLoadIndexedPng(const char* path)
|
||||
{
|
||||
std::vector<unsigned char> encoded;
|
||||
if (!artReadFile(path, encoded)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lodepng::State state;
|
||||
state.decoder.color_convert = 0;
|
||||
|
||||
std::vector<unsigned char> indexedData;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
unsigned error = lodepng::decode(indexedData, width, height, state, encoded);
|
||||
if (error != 0) {
|
||||
debugPrint("ART: failed to decode indexed PNG %s: %s\n", path, lodepng_error_text(error));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (state.info_png.color.colortype != LCT_PALETTE) {
|
||||
debugPrint("ART: PNG is not palette-indexed: %s\n", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (lodepng_has_palette_alpha(&state.info_png.color)) {
|
||||
debugPrint("ART: indexed PNG transparency is unsupported, reserve palette index 0 instead: %s\n", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t pixelCount = static_cast<size_t>(width) * static_cast<size_t>(height);
|
||||
|
||||
if (width == 0 || height == 0 || width > SHRT_MAX || height > SHRT_MAX) {
|
||||
debugPrint("ART: invalid indexed PNG dimensions for %s: %ux%u\n", path, width, height);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pixelCount > kMaxNamedPngPixels || pixelCount > INT_MAX) {
|
||||
debugPrint("ART: indexed PNG is too large: %s\n", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Art header = {};
|
||||
header.version = 4;
|
||||
header.framesPerSecond = 10;
|
||||
header.actionFrame = 0;
|
||||
header.frameCount = 1;
|
||||
header.dataSize = sizeof(ArtFrame) + static_cast<int>(pixelCount);
|
||||
|
||||
int currentPadding = paddingForSize(sizeof(Art));
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
header.dataOffsets[rotation] = 0;
|
||||
header.padding[rotation] = currentPadding;
|
||||
}
|
||||
|
||||
int dataSize = artGetDataSize(&header);
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(internal_malloc(dataSize));
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(data, 0, dataSize);
|
||||
Art* art = reinterpret_cast<Art*>(data);
|
||||
*art = header;
|
||||
|
||||
ArtFrame* frame = reinterpret_cast<ArtFrame*>(data + sizeof(Art) + art->padding[0]);
|
||||
frame->width = static_cast<short>(width);
|
||||
frame->height = static_cast<short>(height);
|
||||
frame->size = static_cast<int>(pixelCount);
|
||||
frame->x = 0;
|
||||
frame->y = 0;
|
||||
|
||||
if (!artUnpackIndexedPngPixels(indexedData, width, height, state.info_png.color.bitdepth, reinterpret_cast<unsigned char*>(frame) + sizeof(ArtFrame))) {
|
||||
debugPrint("ART: failed to read indexed PNG pixels: %s\n", path);
|
||||
internal_free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return art;
|
||||
}
|
||||
|
||||
static Art* artLoadFrm(const char* path)
|
||||
{
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
@@ -1125,6 +1295,30 @@ Art* artLoad(const char* path)
|
||||
return reinterpret_cast<Art*>(data);
|
||||
}
|
||||
|
||||
// NOTE: Original function was slightly different, but never used. Basically
|
||||
// it's a memory allocating variant of `artRead` (which reads data into given
|
||||
// buffer). This function is useful to load custom `frm` files since `Art` now
|
||||
// needs more memory then it's on-disk size (due to memory padding).
|
||||
//
|
||||
// 0x419EC0
|
||||
Art* artLoad(const char* path)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (artPathHasExtension(path, ".png")) {
|
||||
return artLoadIndexedPng(path);
|
||||
}
|
||||
|
||||
Art* art = artLoadFrm(path);
|
||||
if (art != nullptr) {
|
||||
return art;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Art* artLoadLocalized(const char* path)
|
||||
{
|
||||
const char* localizedPath;
|
||||
@@ -1197,7 +1391,7 @@ int artWriteFrameData(unsigned char* data, File* stream, int count)
|
||||
// 0x41A138
|
||||
int artWriteHeader(Art* art, File* stream)
|
||||
{
|
||||
if (fileWriteInt32(stream, art->field_0) == -1) return -1;
|
||||
if (fileWriteInt32(stream, art->version) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->framesPerSecond) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->actionFrame) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->frameCount) == -1) return -1;
|
||||
|
||||
@@ -69,7 +69,7 @@ typedef enum Background {
|
||||
} Background;
|
||||
|
||||
typedef struct Art {
|
||||
int field_0;
|
||||
int version;
|
||||
short framesPerSecond;
|
||||
short actionFrame;
|
||||
short frameCount;
|
||||
@@ -122,6 +122,7 @@ void artReset();
|
||||
void artExit();
|
||||
char* artGetObjectTypeName(int objectType);
|
||||
int artIsObjectTypeHidden(int objectType);
|
||||
void artToggleObjectTypeHidden(int objectType);
|
||||
int artGetFidgetCount(int headFid);
|
||||
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
int art_list_str(int fid, char* name);
|
||||
@@ -150,6 +151,7 @@ int _art_alias_num(int index);
|
||||
int artCritterFidShouldRun(int fid);
|
||||
int artAliasFid(int fid);
|
||||
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation);
|
||||
int artListIndex(int objectType, const char* name);
|
||||
Art* artLoad(const char* path);
|
||||
int artRead(const char* path, unsigned char* data);
|
||||
int artWrite(const char* path, unsigned char* data);
|
||||
|
||||
+214
-14
@@ -4,9 +4,13 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "ogg_decoder.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sound.h"
|
||||
#include "sound_decoder.h"
|
||||
|
||||
@@ -15,28 +19,41 @@ namespace fallout {
|
||||
typedef enum AudioFlags {
|
||||
AUDIO_IN_USE = 0x01,
|
||||
AUDIO_COMPRESSED = 0x02,
|
||||
// CE: Decoded formats like WAV/OGG are fully loaded into memory up front.
|
||||
AUDIO_MEMORY = 0x04,
|
||||
} AudioFileFlags;
|
||||
|
||||
typedef struct Audio {
|
||||
int flags;
|
||||
File* stream;
|
||||
SoundDecoder* soundDecoder;
|
||||
unsigned char* data;
|
||||
int fileSize;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int bitsPerSample;
|
||||
int position;
|
||||
} Audio;
|
||||
|
||||
typedef enum AudioOpenMode {
|
||||
AUDIO_OPEN_MODE_RAW = 0,
|
||||
AUDIO_OPEN_MODE_COMPRESSED = 1, // ACM
|
||||
AUDIO_OPEN_MODE_WAV = 2,
|
||||
AUDIO_OPEN_MODE_OGG = 3,
|
||||
} AudioOpenMode;
|
||||
|
||||
static bool defaultCompressionFunc(char* filePath);
|
||||
static int audioSoundDecoderReadHandler(void* data, void* buf, unsigned int size);
|
||||
static bool audioIsWavePath(const char* filePath);
|
||||
static bool audioDecodeWave(File* stream, AudioFileInfo* info, unsigned char** dataPtr, int* sizePtr);
|
||||
|
||||
// 0x5108BC
|
||||
// 0x5108BC queryCompressedFunc
|
||||
static AudioQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
|
||||
// 0x56CB00
|
||||
// 0x56CB00 numAudio
|
||||
static int gAudioListLength;
|
||||
|
||||
// 0x56CB04
|
||||
// 0x56CB04 audio
|
||||
static Audio* gAudioList;
|
||||
|
||||
// 0x41A2B0
|
||||
@@ -56,18 +73,128 @@ static int audioSoundDecoderReadHandler(void* data, void* buffer, unsigned int s
|
||||
return fileRead(buffer, 1, size, reinterpret_cast<File*>(data));
|
||||
}
|
||||
|
||||
static bool audioIsWavePath(const char* filePath)
|
||||
{
|
||||
const char* dot = strrchr(filePath, '.');
|
||||
return dot != nullptr && compat_stricmp(dot + 1, "wav") == 0;
|
||||
}
|
||||
|
||||
static bool audioDecodeWave(File* stream, AudioFileInfo* info, unsigned char** dataPtr, int* sizePtr)
|
||||
{
|
||||
bool success = false;
|
||||
unsigned char* fileData = nullptr;
|
||||
Uint8* loadedData = nullptr;
|
||||
Uint8* convertedData = nullptr;
|
||||
SDL_RWops* rw = nullptr;
|
||||
SDL_AudioSpec spec = {};
|
||||
Uint32 loadedLength = 0;
|
||||
int channels = 0;
|
||||
SDL_AudioCVT cvt;
|
||||
memset(&cvt, 0, sizeof(cvt));
|
||||
int convertedLength = 0;
|
||||
bool convertedDataNeedsFree = false;
|
||||
bool loadedDataNeedsFree = false;
|
||||
|
||||
int fileSize = fileGetSize(stream);
|
||||
if (fileSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fileData = reinterpret_cast<unsigned char*>(internal_malloc_safe(fileSize, __FILE__, __LINE__));
|
||||
if (fileRead(fileData, 1, fileSize, stream) != fileSize) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
rw = SDL_RWFromConstMem(fileData, fileSize);
|
||||
if (rw == nullptr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SDL_LoadWAV_RW(rw, 1, &spec, &loadedData, &loadedLength) == nullptr) {
|
||||
rw = nullptr;
|
||||
goto done;
|
||||
}
|
||||
rw = nullptr;
|
||||
loadedDataNeedsFree = true;
|
||||
|
||||
channels = spec.channels == 1 ? 1 : 2;
|
||||
if (SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq, AUDIO_S16SYS, channels, spec.freq) < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
convertedLength = static_cast<int>(loadedLength);
|
||||
if (cvt.needed != 0) {
|
||||
cvt.len = static_cast<int>(loadedLength);
|
||||
cvt.buf = reinterpret_cast<Uint8*>(SDL_malloc(cvt.len * cvt.len_mult));
|
||||
if (cvt.buf == nullptr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(cvt.buf, loadedData, loadedLength);
|
||||
if (SDL_ConvertAudio(&cvt) != 0) {
|
||||
SDL_free(cvt.buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
convertedData = cvt.buf;
|
||||
convertedLength = cvt.len_cvt;
|
||||
convertedDataNeedsFree = true;
|
||||
} else {
|
||||
convertedData = loadedData;
|
||||
}
|
||||
|
||||
if (info != nullptr) {
|
||||
info->channels = channels;
|
||||
info->sampleRate = spec.freq;
|
||||
info->bitsPerSample = 16;
|
||||
}
|
||||
|
||||
if (dataPtr != nullptr && sizePtr != nullptr) {
|
||||
*dataPtr = reinterpret_cast<unsigned char*>(internal_malloc_safe(convertedLength, __FILE__, __LINE__));
|
||||
memcpy(*dataPtr, convertedData, convertedLength);
|
||||
*sizePtr = convertedLength;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
done:
|
||||
if (rw != nullptr) {
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
|
||||
if (convertedData != nullptr) {
|
||||
if (convertedDataNeedsFree) {
|
||||
SDL_free(convertedData);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedDataNeedsFree && loadedData != nullptr) {
|
||||
SDL_FreeWAV(loadedData);
|
||||
}
|
||||
|
||||
if (fileData != nullptr) {
|
||||
internal_free_safe(fileData, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// AudioOpen
|
||||
// 0x41A2EC
|
||||
int audioOpen(const char* fname, int* sampleRate)
|
||||
int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
|
||||
{
|
||||
char path[80];
|
||||
char path[COMPAT_MAX_PATH];
|
||||
snprintf(path, sizeof(path), "%s", fname);
|
||||
|
||||
int compression;
|
||||
if (queryCompressedFunc(path)) {
|
||||
compression = 2;
|
||||
AudioOpenMode openMode;
|
||||
if (audioIsWavePath(path)) {
|
||||
openMode = AUDIO_OPEN_MODE_WAV;
|
||||
} else if (oggDecoderIsFilePath(path)) {
|
||||
openMode = AUDIO_OPEN_MODE_OGG;
|
||||
} else if (queryCompressedFunc(path)) {
|
||||
openMode = AUDIO_OPEN_MODE_COMPRESSED;
|
||||
} else {
|
||||
compression = 0;
|
||||
openMode = AUDIO_OPEN_MODE_RAW;
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, "rb");
|
||||
@@ -93,17 +220,64 @@ int audioOpen(const char* fname, int* sampleRate)
|
||||
}
|
||||
|
||||
Audio* audioFile = &(gAudioList[index]);
|
||||
memset(audioFile, 0, sizeof(*audioFile));
|
||||
audioFile->flags = AUDIO_IN_USE;
|
||||
audioFile->stream = stream;
|
||||
|
||||
if (compression == 2) {
|
||||
if (openMode == AUDIO_OPEN_MODE_WAV || openMode == AUDIO_OPEN_MODE_OGG) {
|
||||
AudioFileInfo decodedInfo = {};
|
||||
audioFile->flags |= AUDIO_MEMORY;
|
||||
bool decoded = false;
|
||||
if (openMode == AUDIO_OPEN_MODE_WAV) {
|
||||
decoded = audioDecodeWave(stream, &decodedInfo, &(audioFile->data), &(audioFile->fileSize));
|
||||
} else {
|
||||
AudioFileInfo audioFileInfo = {};
|
||||
decoded = oggDecoderDecode(stream, &audioFileInfo, &(audioFile->data), &(audioFile->fileSize));
|
||||
decodedInfo.sampleRate = audioFileInfo.sampleRate;
|
||||
decodedInfo.channels = audioFileInfo.channels;
|
||||
decodedInfo.bitsPerSample = audioFileInfo.bitsPerSample;
|
||||
}
|
||||
|
||||
if (!decoded) {
|
||||
fileClose(stream);
|
||||
memset(audioFile, 0, sizeof(*audioFile));
|
||||
debugPrint("AudioOpen: Couldn't decode %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
audioFile->stream = nullptr;
|
||||
audioFile->sampleRate = decodedInfo.sampleRate;
|
||||
audioFile->channels = decodedInfo.channels;
|
||||
audioFile->bitsPerSample = decodedInfo.bitsPerSample;
|
||||
if (info != nullptr) {
|
||||
*info = decodedInfo;
|
||||
}
|
||||
if (isMemoryBackedPtr != nullptr) {
|
||||
*isMemoryBackedPtr = true;
|
||||
}
|
||||
} else if (openMode == AUDIO_OPEN_MODE_COMPRESSED) {
|
||||
audioFile->flags |= AUDIO_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
audioFile->bitsPerSample = 16;
|
||||
|
||||
*sampleRate = audioFile->sampleRate;
|
||||
if (info != nullptr) {
|
||||
info->sampleRate = audioFile->sampleRate;
|
||||
info->bitsPerSample = audioFile->bitsPerSample;
|
||||
}
|
||||
if (isMemoryBackedPtr != nullptr) {
|
||||
*isMemoryBackedPtr = false;
|
||||
}
|
||||
} else {
|
||||
audioFile->fileSize = fileGetSize(stream);
|
||||
audioFile->bitsPerSample = 8;
|
||||
if (info != nullptr) {
|
||||
info->bitsPerSample = audioFile->bitsPerSample;
|
||||
}
|
||||
if (isMemoryBackedPtr != nullptr) {
|
||||
*isMemoryBackedPtr = false;
|
||||
}
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
@@ -115,7 +289,13 @@ int audioOpen(const char* fname, int* sampleRate)
|
||||
int audioClose(int handle)
|
||||
{
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
fileClose(audioFile->stream);
|
||||
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
|
||||
if (audioFile->data != nullptr) {
|
||||
internal_free_safe(audioFile->data, __FILE__, __LINE__);
|
||||
}
|
||||
} else if (audioFile->stream != nullptr) {
|
||||
fileClose(audioFile->stream);
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
@@ -132,7 +312,16 @@ int audioRead(int handle, void* buffer, unsigned int size)
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
|
||||
bytesRead = audioFile->fileSize - audioFile->position;
|
||||
if (bytesRead > static_cast<int>(size)) {
|
||||
bytesRead = size;
|
||||
}
|
||||
|
||||
if (bytesRead > 0) {
|
||||
memcpy(buffer, audioFile->data + audioFile->position, bytesRead);
|
||||
}
|
||||
} else if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(audioFile->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fileRead(buffer, 1, size, audioFile->stream);
|
||||
@@ -166,7 +355,18 @@ long audioSeek(int handle, long offset, int origin)
|
||||
assert(false && "Should be unreachable");
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
|
||||
if (pos < 0) {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (pos > audioFile->fileSize) {
|
||||
pos = audioFile->fileSize;
|
||||
}
|
||||
|
||||
audioFile->position = pos;
|
||||
return audioFile->position;
|
||||
} else if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
if (pos < audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
fileSeek(audioFile->stream, 0, SEEK_SET);
|
||||
|
||||
+3
-1
@@ -1,11 +1,13 @@
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef bool(AudioQueryCompressedFunc)(char* filePath);
|
||||
|
||||
int audioOpen(const char* fname, int* sampleRate);
|
||||
int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr);
|
||||
int audioClose(int handle);
|
||||
int audioRead(int handle, void* buffer, unsigned int size);
|
||||
long audioSeek(int handle, long offset, int origin);
|
||||
|
||||
+17
-6
@@ -30,13 +30,13 @@ typedef struct AudioFile {
|
||||
static bool defaultCompressionFunc(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned int size);
|
||||
|
||||
// 0x5108C0
|
||||
// 0x5108C0 queryCompressedFunc_2
|
||||
static AudioFileQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
|
||||
// 0x56CB10
|
||||
// 0x56CB10 audiof
|
||||
static AudioFile* gAudioFileList;
|
||||
|
||||
// 0x56CB14
|
||||
// 0x56CB14 numAudiof
|
||||
static int gAudioFileListLength;
|
||||
|
||||
// 0x41A850
|
||||
@@ -57,7 +57,7 @@ static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned i
|
||||
}
|
||||
|
||||
// 0x41A88C
|
||||
int audioFileOpen(const char* fname, int* sampleRate)
|
||||
int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
strcpy(path, fname);
|
||||
@@ -98,10 +98,21 @@ int audioFileOpen(const char* fname, int* sampleRate)
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
|
||||
*sampleRate = audioFile->sampleRate;
|
||||
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;
|
||||
|
||||
+3
-1
@@ -1,11 +1,13 @@
|
||||
#ifndef AUDIO_FILE_H
|
||||
#define AUDIO_FILE_H
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef bool(AudioFileQueryCompressedFunc)(char* filePath);
|
||||
|
||||
int audioFileOpen(const char* fname, int* sampleRate);
|
||||
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);
|
||||
|
||||
+23
-23
@@ -62,14 +62,14 @@ typedef struct AutomapEntry {
|
||||
unsigned char* data;
|
||||
} AutomapEntry;
|
||||
|
||||
// 0x41ADE0
|
||||
// 0x41ADE0 defam
|
||||
static const int _defam[AUTOMAP_MAP_COUNT][ELEVATION_COUNT] = {
|
||||
{ -1, -1, -1 },
|
||||
{ -1, -1, -1 },
|
||||
{ -1, -1, -1 },
|
||||
};
|
||||
|
||||
// 0x41B560
|
||||
// 0x41B560 displayMapList
|
||||
static int _displayMapList[AUTOMAP_MAP_COUNT] = {
|
||||
-1,
|
||||
-1,
|
||||
@@ -242,17 +242,17 @@ static const int gAutomapFrmIds[AUTOMAP_FRM_COUNT] = {
|
||||
173, // autodwn.frm - switch down
|
||||
};
|
||||
|
||||
// 0x5108C4
|
||||
// 0x5108C4 autoflags
|
||||
static int gAutomapFlags = 0;
|
||||
|
||||
// 0x56CB18
|
||||
// 0x56CB18 amdbhead
|
||||
static AutomapHeader gAutomapHeader;
|
||||
|
||||
// 0x56D2A0
|
||||
// 0x56D2A0 amdbsubhead
|
||||
static AutomapEntry gAutomapEntry;
|
||||
|
||||
// automap_init
|
||||
// 0x41B7F4
|
||||
// 0x41B7F4 automap_init
|
||||
int automapInit()
|
||||
{
|
||||
gAutomapFlags = 0;
|
||||
@@ -260,7 +260,7 @@ int automapInit()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41B808
|
||||
// 0x41B808 automap_reset
|
||||
int automapReset()
|
||||
{
|
||||
gAutomapFlags = 0;
|
||||
@@ -268,7 +268,7 @@ int automapReset()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41B81C
|
||||
// 0x41B81C automap_exit
|
||||
void automapExit()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
@@ -276,25 +276,25 @@ void automapExit()
|
||||
compat_remove(path);
|
||||
}
|
||||
|
||||
// 0x41B87C
|
||||
// 0x41B87C automap_load
|
||||
int automapLoad(File* stream)
|
||||
{
|
||||
return fileReadInt32(stream, &gAutomapFlags);
|
||||
}
|
||||
|
||||
// 0x41B898
|
||||
// 0x41B898 automap_save
|
||||
int automapSave(File* stream)
|
||||
{
|
||||
return fileWriteInt32(stream, gAutomapFlags);
|
||||
}
|
||||
|
||||
// 0x41B8B4
|
||||
// 0x41B8B4 automapDisplayMap
|
||||
int _automapDisplayMap(int map)
|
||||
{
|
||||
return _displayMapList[map];
|
||||
}
|
||||
|
||||
// 0x41B8BC
|
||||
// 0x41B8BC automap
|
||||
void automapShow(bool isInGame, bool isUsingScanner)
|
||||
{
|
||||
ScopedGameMode gm(GameMode::kAutomap);
|
||||
@@ -499,7 +499,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
|
||||
// Renders automap in Map window.
|
||||
//
|
||||
// 0x41BD1C
|
||||
// 0x41BD1C draw_top_down_map
|
||||
static void automapRenderInMapWindow(int window, int elevation, unsigned char* backgroundData, int flags)
|
||||
{
|
||||
int color;
|
||||
@@ -620,7 +620,7 @@ static void automapRenderInMapWindow(int window, int elevation, unsigned char* b
|
||||
|
||||
// Renders automap in Pipboy window.
|
||||
//
|
||||
// 0x41C004
|
||||
// 0x41C004 draw_top_down_map_pipboy
|
||||
int automapRenderInPipboyWindow(int window, int map, int elevation)
|
||||
{
|
||||
unsigned char* windowBuffer = windowGetBuffer(window) + 640 * AUTOMAP_PIPBOY_VIEW_Y + AUTOMAP_PIPBOY_VIEW_X;
|
||||
@@ -682,7 +682,7 @@ int automapRenderInPipboyWindow(int window, int map, int elevation)
|
||||
}
|
||||
|
||||
// automap_pip_save
|
||||
// 0x41C0F0
|
||||
// 0x41C0F0 automap_pip_save
|
||||
int automapSaveCurrent()
|
||||
{
|
||||
int map = mapGetCurrentMap();
|
||||
@@ -896,7 +896,7 @@ int automapSaveCurrent()
|
||||
|
||||
// Saves automap entry into stream.
|
||||
//
|
||||
// 0x41C844
|
||||
// 0x41C844 WriteAM_Entry
|
||||
static int automapSaveEntry(File* stream)
|
||||
{
|
||||
unsigned char* buffer;
|
||||
@@ -928,7 +928,7 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x41C8CC
|
||||
// 0x41C8CC AM_ReadEntry
|
||||
static int automapLoadEntry(int map, int elevation)
|
||||
{
|
||||
gAutomapEntry.compressedData = nullptr;
|
||||
@@ -1015,7 +1015,7 @@ out:
|
||||
|
||||
// Saves automap.db header.
|
||||
//
|
||||
// 0x41CAD8
|
||||
// 0x41CAD8 WriteAM_Header
|
||||
static int automapSaveHeader(File* stream)
|
||||
{
|
||||
fileRewind(stream);
|
||||
@@ -1045,7 +1045,7 @@ err:
|
||||
|
||||
// Loads automap.db header.
|
||||
//
|
||||
// 0x41CB50
|
||||
// 0x41CB50 AM_ReadMainHeader
|
||||
static int automapLoadHeader(File* stream)
|
||||
{
|
||||
|
||||
@@ -1068,7 +1068,7 @@ static int automapLoadHeader(File* stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41CBA4
|
||||
// 0x41CBA4 decode_map_data
|
||||
static void _decode_map_data(int elevation)
|
||||
{
|
||||
memset(gAutomapEntry.data, 0, SQUARE_GRID_SIZE);
|
||||
@@ -1101,7 +1101,7 @@ static void _decode_map_data(int elevation)
|
||||
}
|
||||
}
|
||||
|
||||
// 0x41CC98
|
||||
// 0x41CC98 am_pip_init
|
||||
static int automapCreate()
|
||||
{
|
||||
gAutomapHeader.version = 1;
|
||||
@@ -1128,7 +1128,7 @@ static int automapCreate()
|
||||
|
||||
// Copy data from stream1 to stream2.
|
||||
//
|
||||
// 0x41CD6C
|
||||
// 0x41CD6C copy_file_data
|
||||
static int _copy_file_data(File* stream1, File* stream2, int length)
|
||||
{
|
||||
void* buffer = internal_malloc(0xFFFF);
|
||||
@@ -1160,7 +1160,7 @@ static int _copy_file_data(File* stream1, File* stream2, int length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41CE74
|
||||
// 0x41CE74 ReadAMList
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
|
||||
+3
-3
@@ -5,13 +5,13 @@
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// 0x530010
|
||||
// 0x530010 autorun_mutex
|
||||
static HANDLE gInterplayGenericAutorunMutex;
|
||||
#endif
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x4139C0
|
||||
// 0x4139C0 autorun_mutex_create
|
||||
bool autorunMutexCreate()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -25,7 +25,7 @@ bool autorunMutexCreate()
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x413A00
|
||||
// 0x413A00 autorun_mutex_destroy
|
||||
void autorunMutexClose()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user