mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b649c416c | ||
|
|
1a50bebff1 | ||
|
|
ab2a09610d | ||
|
|
cef24823f4 | ||
|
|
63d79e4bfd | ||
|
|
e42d8021c1 | ||
|
|
8254c758fe | ||
|
|
8b2ead8a2b | ||
|
|
4f89bb7d77 | ||
|
|
0d8741e082 | ||
|
|
6ce6bea309 | ||
|
|
6027c7cf2e |
+113
-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"
|
||||
@@ -263,7 +268,7 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/xfile.h"
|
||||
)
|
||||
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
set(FALLOUT_PLATFORM_SOURCES
|
||||
"src/audio_engine.cc"
|
||||
"src/audio_engine.h"
|
||||
"src/delay.cc"
|
||||
@@ -297,6 +302,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/sfall_opcodes.cc"
|
||||
"src/sfall_opcodes.h"
|
||||
"src/sfall_script_hooks.cc"
|
||||
"src/script_sound.cc"
|
||||
"src/script_sound.h"
|
||||
"src/sfall_arrays.cc"
|
||||
"src/sfall_arrays.h"
|
||||
"src/sfall_animation.cc"
|
||||
@@ -309,8 +316,43 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"third_party/lodepng/lodepng.cpp"
|
||||
)
|
||||
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
${FALLOUT_ENGINE_SOURCES}
|
||||
"src/main.cc"
|
||||
"src/main.h"
|
||||
)
|
||||
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC ${FALLOUT_PLATFORM_SOURCES})
|
||||
|
||||
target_include_directories(${EXECUTABLE_NAME} PUBLIC "third_party/lodepng")
|
||||
|
||||
set(FALLOUT_HAVE_STB_VORBIS OFF)
|
||||
if(FALLOUT_AUDIO_OGG)
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis/stb_vorbis.c")
|
||||
set(_fallout_stb_vorbis_dir "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis")
|
||||
else()
|
||||
set(_fallout_stb_vorbis_dir "${FALLOUT_STB_VORBIS_DIR}")
|
||||
if(NOT _fallout_stb_vorbis_dir)
|
||||
find_path(_fallout_stb_vorbis_dir
|
||||
NAMES "stb_vorbis.c"
|
||||
DOC "Directory containing stb_vorbis.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_fallout_stb_vorbis_dir AND EXISTS "${_fallout_stb_vorbis_dir}/stb_vorbis.c")
|
||||
set(FALLOUT_HAVE_STB_VORBIS ON)
|
||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE "${_fallout_stb_vorbis_dir}")
|
||||
else()
|
||||
message(STATUS "OGG support disabled: stb_vorbis.c not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FALLOUT_HAVE_STB_VORBIS)
|
||||
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=1)
|
||||
else()
|
||||
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=0)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/platform/ios/paths.h"
|
||||
@@ -527,6 +569,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 | - |
|
||||
@@ -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` | đźš« | - |
|
||||
|
||||
@@ -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)
|
||||
enable_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
|
||||
+42
@@ -355,6 +355,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 +452,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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
+211
-11
@@ -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,20 +19,33 @@ 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
|
||||
static AudioQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
@@ -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);
|
||||
|
||||
+14
-3
@@ -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);
|
||||
|
||||
+24
-14
@@ -1972,31 +1972,41 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
// 0x4298EC
|
||||
static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
int damageFlags = critter->data.critter.combat.results;
|
||||
if ((damageFlags & DAM_CRIP_ARM_LEFT) != 0 && (damageFlags & DAM_CRIP_ARM_RIGHT) != 0) {
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
|
||||
if ((damageFlags & DAM_CRIP_ARM_ANY) != 0 && weaponIsTwoHanded(weapon)) {
|
||||
return false;
|
||||
if (result && (damageFlags & DAM_CRIP_ARM_ANY) != 0 && weaponIsTwoHanded(weapon)) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
int rotation = critter->rotation + 1;
|
||||
int animationCode = weaponGetAnimationCode(weapon);
|
||||
int weaponAnimationCode = weaponGetAnimationForHitMode(weapon, hitMode);
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, weaponAnimationCode, animationCode, rotation);
|
||||
if (!artExists(fid)) {
|
||||
return false;
|
||||
if (result) {
|
||||
int rotation = critter->rotation + 1;
|
||||
int animationCode = weaponGetAnimationCode(weapon);
|
||||
int weaponAnimationCode = weaponGetAnimationForHitMode(weapon, hitMode);
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, weaponAnimationCode, animationCode, rotation);
|
||||
if (!artExists(fid)) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
int skill = weaponGetSkillForHitMode(weapon, hitMode);
|
||||
AiPacket* ai = aiGetPacket(critter);
|
||||
if (skillGetValue(critter, skill) < ai->min_to_hit) {
|
||||
return false;
|
||||
if (result) {
|
||||
int skill = weaponGetSkillForHitMode(weapon, hitMode);
|
||||
if (skillGetValue(critter, skill) < ai->min_to_hit) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
int attackType = weaponGetAttackTypeForHitMode(weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY);
|
||||
return _caiHasWeapPrefType(ai, attackType) != 0;
|
||||
if (result) {
|
||||
int attackType = weaponGetAttackTypeForHitMode(weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY);
|
||||
result = _caiHasWeapPrefType(ai, attackType) != 0;
|
||||
}
|
||||
|
||||
return scriptHooks_CanUseWeapon(result, critter, weapon, hitMode);
|
||||
}
|
||||
|
||||
// 0x4299A0
|
||||
|
||||
@@ -29,34 +29,82 @@ long fileTell(File* stream);
|
||||
void fileRewind(File* stream);
|
||||
int fileEof(File* stream);
|
||||
int fileReadUInt8(File* stream, unsigned char* valuePtr);
|
||||
|
||||
// Reads a 16-bit big-endian integer from stream and stores it in host byte order.
|
||||
int fileReadInt16(File* stream, short* valuePtr);
|
||||
|
||||
// Reads a 16-bit big-endian unsigned integer from stream and stores it in host byte order.
|
||||
int fileReadUInt16(File* stream, unsigned short* valuePtr);
|
||||
|
||||
// Reads a 32-bit big-endian integer from stream and stores it in host byte order.
|
||||
int fileReadInt32(File* stream, int* valuePtr);
|
||||
|
||||
// Reads a 32-bit big-endian unsigned integer from stream and stores it in host byte order.
|
||||
int fileReadUInt32(File* stream, unsigned int* valuePtr);
|
||||
|
||||
// Reads a 32-bit big-endian integer from stream and stores it in host byte order (alias).
|
||||
int _db_freadInt(File* stream, int* valuePtr);
|
||||
|
||||
// Reads a 32-bit big-endian floating-point value from stream and stores it in host byte order.
|
||||
int fileReadFloat(File* stream, float* valuePtr);
|
||||
|
||||
// Reads a 32-bit big-endian integer from stream and stores the boolean equivalent in host byte order.
|
||||
int fileReadBool(File* stream, bool* valuePtr);
|
||||
int fileWriteUInt8(File* stream, unsigned char value);
|
||||
|
||||
// Writes a 16-bit integer to stream in big-endian byte order.
|
||||
int fileWriteInt16(File* stream, short value);
|
||||
|
||||
// Writes a 16-bit unsigned integer to stream in big-endian byte order.
|
||||
int fileWriteUInt16(File* stream, unsigned short value);
|
||||
|
||||
// Writes a 32-bit integer to stream in big-endian byte order.
|
||||
int fileWriteInt32(File* stream, int value);
|
||||
|
||||
// Writes a 32-bit integer to stream in big-endian byte order (alias).
|
||||
int _db_fwriteLong(File* stream, int value);
|
||||
|
||||
// Writes a 32-bit unsigned integer to stream in big-endian byte order.
|
||||
int fileWriteUInt32(File* stream, unsigned int value);
|
||||
|
||||
// Writes a 32-bit floating-point value to stream in big-endian byte order.
|
||||
int fileWriteFloat(File* stream, float value);
|
||||
|
||||
// Writes a boolean value to stream as a 32-bit big-endian integer (1 or 0).
|
||||
int fileWriteBool(File* stream, bool value);
|
||||
int fileReadUInt8List(File* stream, unsigned char* arr, int count);
|
||||
int fileReadFixedLengthString(File* stream, char* string, int length);
|
||||
|
||||
// Reads a list of 16-bit big-endian integers from stream into arr (in host byte order).
|
||||
int fileReadInt16List(File* stream, short* arr, int count);
|
||||
|
||||
// Reads a list of 16-bit big-endian unsigned integers from stream into arr (in host byte order).
|
||||
int fileReadUInt16List(File* stream, unsigned short* arr, int count);
|
||||
|
||||
// Reads a list of 32-bit big-endian integers from stream into arr (in host byte order).
|
||||
int fileReadInt32List(File* stream, int* arr, int count);
|
||||
|
||||
// Reads a list of 32-bit big-endian integers from stream into arr (in host byte order, alias).
|
||||
int _db_freadIntCount(File* stream, int* arr, int count);
|
||||
|
||||
// Reads a list of 32-bit big-endian unsigned integers from stream into arr (in host byte order).
|
||||
int fileReadUInt32List(File* stream, unsigned int* arr, int count);
|
||||
int fileWriteUInt8List(File* stream, unsigned char* arr, int count);
|
||||
int fileWriteFixedLengthString(File* stream, char* string, int length);
|
||||
|
||||
// Writes a list of 16-bit integers to stream in big-endian byte order.
|
||||
int fileWriteInt16List(File* stream, short* arr, int count);
|
||||
|
||||
// Writes a list of 16-bit unsigned integers to stream in big-endian byte order.
|
||||
int fileWriteUInt16List(File* stream, unsigned short* arr, int count);
|
||||
|
||||
// Writes a list of 32-bit integers to stream in big-endian byte order.
|
||||
int fileWriteInt32List(File* stream, int* arr, int count);
|
||||
|
||||
// Writes a list of 32-bit integers to stream in big-endian byte order (alias).
|
||||
int _db_fwriteLongCount(File* stream, int* arr, int count);
|
||||
|
||||
// Writes a list of 32-bit unsigned integers to stream in big-endian byte order.
|
||||
int fileWriteUInt32List(File* stream, unsigned int* arr, int count);
|
||||
int fileNameListInit(const char* pattern, char*** fileNames);
|
||||
void fileNameListFree(char*** fileNames, int unused);
|
||||
|
||||
+51
-16
@@ -1,11 +1,11 @@
|
||||
#include "debug.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <string>
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
@@ -15,11 +15,18 @@ namespace fallout {
|
||||
|
||||
static int _debug_puts(char* string);
|
||||
static void _debug_clear();
|
||||
static int _debug_mono(char* string);
|
||||
static int _debug_log(char* string);
|
||||
static int _debug_screen(char* string);
|
||||
static int _debug_mono(const char* string);
|
||||
static int _debug_log(const char* string);
|
||||
static int _debug_screen(const char* string);
|
||||
static void _debug_putc(int ch);
|
||||
static void _debug_scroll();
|
||||
static void debugFlushBuffer();
|
||||
|
||||
// Messages logged before any debug proc is registered are held here and
|
||||
// flushed when the first proc is registered.
|
||||
static std::string debugBuffer;
|
||||
static constexpr size_t kDebugBufferMaxSize = 64 * 1024;
|
||||
static bool debugBufferDisabled = false;
|
||||
|
||||
// 0x51DEF8
|
||||
static FILE* _fd = nullptr;
|
||||
@@ -35,6 +42,12 @@ static DebugPrintProc* gDebugPrintProc = nullptr;
|
||||
|
||||
void debugModeInit(const char* debugMode)
|
||||
{
|
||||
debugBufferDisabled = true;
|
||||
|
||||
if (debugMode == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CE: Handle debug mode (exactly as seen in `mapper2.exe`).
|
||||
if (compat_stricmp(debugMode, "environment") == 0) {
|
||||
_debug_register_env();
|
||||
@@ -47,6 +60,10 @@ void debugModeInit(const char* debugMode)
|
||||
} else if (compat_stricmp(debugMode, "gnw") == 0) {
|
||||
_debug_register_func(_win_debug);
|
||||
}
|
||||
|
||||
if (gDebugPrintProc == nullptr) {
|
||||
debugBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6CD0
|
||||
@@ -66,6 +83,7 @@ void _debug_register_mono()
|
||||
|
||||
gDebugPrintProc = _debug_mono;
|
||||
_debug_clear();
|
||||
debugFlushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +97,7 @@ void _debug_register_log(const char* fileName, const char* mode)
|
||||
|
||||
_fd = compat_fopen(fileName, mode);
|
||||
gDebugPrintProc = _debug_log;
|
||||
debugFlushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +111,7 @@ void _debug_register_screen()
|
||||
}
|
||||
|
||||
gDebugPrintProc = _debug_screen;
|
||||
debugFlushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +157,7 @@ void _debug_register_func(DebugPrintProc* proc)
|
||||
}
|
||||
|
||||
gDebugPrintProc = proc;
|
||||
debugFlushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,25 +167,39 @@ int debugPrint(const char* format, ...)
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char string[260];
|
||||
int len = vsnprintf(string, sizeof(string), format, args);
|
||||
if (len < 0) {
|
||||
string[0] = '\0';
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
int rc;
|
||||
|
||||
if (gDebugPrintProc != nullptr) {
|
||||
char string[260];
|
||||
vsnprintf(string, sizeof(string), format, args);
|
||||
|
||||
rc = gDebugPrintProc(string);
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args);
|
||||
#endif
|
||||
if (!debugBufferDisabled && debugBuffer.size() + strlen(string) <= kDebugBufferMaxSize) {
|
||||
debugBuffer += string;
|
||||
}
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
#ifndef NDEBUG
|
||||
SDL_Log("%s", string);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void debugFlushBuffer()
|
||||
{
|
||||
if (debugBuffer.empty() || gDebugPrintProc == nullptr) {
|
||||
return;
|
||||
}
|
||||
gDebugPrintProc(debugBuffer.c_str());
|
||||
debugBuffer.clear();
|
||||
}
|
||||
|
||||
// 0x4C6F94
|
||||
static int _debug_puts(char* string)
|
||||
{
|
||||
@@ -203,7 +238,7 @@ static void _debug_clear()
|
||||
}
|
||||
|
||||
// 0x4C7004
|
||||
static int _debug_mono(char* string)
|
||||
static int _debug_mono(const char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_mono) {
|
||||
while (*string != '\0') {
|
||||
@@ -215,7 +250,7 @@ static int _debug_mono(char* string)
|
||||
}
|
||||
|
||||
// 0x4C7028
|
||||
static int _debug_log(char* string)
|
||||
static int _debug_log(const char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_log) {
|
||||
if (_fd == nullptr) {
|
||||
@@ -235,7 +270,7 @@ static int _debug_log(char* string)
|
||||
}
|
||||
|
||||
// 0x4C7068
|
||||
static int _debug_screen(char* string)
|
||||
static int _debug_screen(const char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_screen) {
|
||||
printf("%s", string);
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef int(DebugPrintProc)(char* string);
|
||||
typedef int(DebugPrintProc)(const char* string);
|
||||
|
||||
void debugModeInit(const char* debugMode);
|
||||
void _GNW_debug_init();
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
namespace fallout {
|
||||
|
||||
// The size of decompression buffer for reading compressed [DFile]s.
|
||||
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x400)
|
||||
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x1000)
|
||||
|
||||
// Specifies that [DFile] has unget character.
|
||||
//
|
||||
|
||||
@@ -152,6 +152,8 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
|
||||
|
||||
settingsInit(isMapper, argc, argv);
|
||||
|
||||
debugModeInit(settings.debug.mode.c_str());
|
||||
|
||||
gIsMapper = isMapper;
|
||||
|
||||
if (gameDbInit() == -1) {
|
||||
|
||||
@@ -119,11 +119,6 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
|
||||
configRead(&gGameConfig, gGameConfigFilePath, false);
|
||||
|
||||
// Init debug mode ASAP to catch early debug messages.
|
||||
char* debugMode;
|
||||
configGetString(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, &debugMode);
|
||||
debugModeInit(debugMode);
|
||||
|
||||
debugPrint("Game config loaded from %s.\n", gGameConfigFilePath);
|
||||
|
||||
if (!isMapper && gameConfigMigrateFromF2Res(gGameConfigFilePath, &gGameConfig)) {
|
||||
|
||||
+85
-29
@@ -279,6 +279,8 @@ static int gGameDialogBackgroundWindow = -1;
|
||||
// 0x518744
|
||||
static int gGameDialogWindow = -1;
|
||||
|
||||
static bool gameDialogUseHrArt = false;
|
||||
|
||||
// 0x518748
|
||||
static Rect _backgrndRects[8] = {
|
||||
{ 126, 14, 152, 40 },
|
||||
@@ -291,6 +293,37 @@ static Rect _backgrndRects[8] = {
|
||||
{ 504, 40, 514, 188 },
|
||||
};
|
||||
|
||||
static bool gameDialogShouldUseHrArt()
|
||||
{
|
||||
return settings.ui.enable_dialog_border
|
||||
&& (screenGetWidth() > GAME_DIALOG_WINDOW_WIDTH || screenGetHeight() > GAME_DIALOG_WINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
static int gameDialogHrArtYOffset()
|
||||
{
|
||||
return gameDialogUseHrArt ? 5 : 0;
|
||||
}
|
||||
|
||||
static Rect gameDialogGetBackgroundRect(int index)
|
||||
{
|
||||
Rect rect = _backgrndRects[index];
|
||||
int yOffset = gameDialogHrArtYOffset();
|
||||
rect.top += yOffset;
|
||||
rect.bottom += yOffset;
|
||||
return rect;
|
||||
}
|
||||
|
||||
static int gameDialogGetBackgroundWindowY()
|
||||
{
|
||||
// center onplay area if large enough, else center on screen
|
||||
int visibleHeight = screenGetVisibleHeight();
|
||||
if (visibleHeight >= GAME_DIALOG_WINDOW_HEIGHT) {
|
||||
return (visibleHeight - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
return (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
// 0x5187C8
|
||||
static bool _talk_need_to_center = true;
|
||||
|
||||
@@ -2494,31 +2527,35 @@ int _gdCreateHeadWindow()
|
||||
int windowWidth = GAME_DIALOG_WINDOW_WIDTH;
|
||||
|
||||
// NOTE: Uninline.
|
||||
talk_to_create_background_window();
|
||||
gameDialogWindowRenderBackground();
|
||||
if (talk_to_create_background_window() == -1 || gameDialogWindowRenderBackground() == -1) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* buf = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
ConstBuffer2D backgroundBuf = windowGetBuffer2D(gGameDialogBackgroundWindow);
|
||||
|
||||
for (int index = 0; index < 8; index++) {
|
||||
soundContinueAll();
|
||||
|
||||
Rect* rect = &(_backgrndRects[index]);
|
||||
int width = rect->right - rect->left;
|
||||
int height = rect->bottom - rect->top;
|
||||
Rect rect = gameDialogGetBackgroundRect(index);
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
_backgrndBufs[index] = (unsigned char*)internal_malloc(width * height);
|
||||
if (_backgrndBufs[index] == nullptr) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* src = buf;
|
||||
src += windowWidth * rect->top + rect->left;
|
||||
|
||||
blitBufferToBuffer(src, width, height, windowWidth, _backgrndBufs[index], width);
|
||||
Buffer2D savedBackgroundBuf { _backgrndBufs[index], width, height };
|
||||
blitBuffer2D(backgroundBuf, rect.left, rect.top, width, height, savedBackgroundBuf);
|
||||
}
|
||||
|
||||
_gdialog_window_create();
|
||||
if (_gdialog_window_create() == -1) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
gGameDialogDisplayBuffer = windowGetBuffer(gGameDialogBackgroundWindow) + windowWidth * 14 + 126;
|
||||
gGameDialogDisplayBuffer = windowGetBuffer(gGameDialogBackgroundWindow) + windowWidth * (14 + gameDialogHrArtYOffset()) + 126;
|
||||
|
||||
// TODO: jnz at 0x447275 without cmp or test, not sure what that means.
|
||||
if (false) {
|
||||
@@ -2547,10 +2584,12 @@ void _gdDestroyHeadWindow()
|
||||
gGameDialogBackgroundWindow = -1;
|
||||
}
|
||||
|
||||
gameDialogUseHrArt = false;
|
||||
gExpandedBarterEnabled = false;
|
||||
|
||||
for (int index = 0; index < 8; index++) {
|
||||
internal_free(_backgrndBufs[index]);
|
||||
_backgrndBufs[index] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4551,13 +4590,14 @@ static const char* expandedBarterFrmName()
|
||||
// 0x44AAD8
|
||||
static int talk_to_create_background_window()
|
||||
{
|
||||
gameDialogUseHrArt = false;
|
||||
|
||||
gExpandedBarterEnabled = settings.ui.expand_barter_window
|
||||
&& screenGetHeight() >= GAME_DIALOG_WINDOW_HEIGHT + kExpandedBarterExtraHeight
|
||||
&& FrmImage().lock(OBJ_TYPE_INTERFACE, expandedBarterFrmName());
|
||||
|
||||
int backgroundWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
|
||||
int effectiveBgHeight = GAME_DIALOG_WINDOW_HEIGHT + (gExpandedBarterEnabled ? kExpandedBarterExtraHeight : 0);
|
||||
int backgroundWindowY = (screenGetHeight() - effectiveBgHeight) / 2;
|
||||
int backgroundWindowY = gameDialogGetBackgroundWindowY();
|
||||
|
||||
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX,
|
||||
backgroundWindowY,
|
||||
@@ -4577,15 +4617,29 @@ static int talk_to_create_background_window()
|
||||
int gameDialogWindowRenderBackground()
|
||||
{
|
||||
FrmImage backgroundFrmImage;
|
||||
// alltlk.frm - dialog screen background
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 103, 0, 0, 0);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return -1;
|
||||
|
||||
if (gameDialogShouldUseHrArt()) {
|
||||
if (backgroundFrmImage.lock(OBJ_TYPE_INTERFACE, "HR_ALLTLK.frm")
|
||||
&& backgroundFrmImage.getWidth() >= GAME_DIALOG_WINDOW_WIDTH
|
||||
&& backgroundFrmImage.getHeight() >= GAME_DIALOG_WINDOW_HEIGHT) {
|
||||
gameDialogUseHrArt = true;
|
||||
} else {
|
||||
backgroundFrmImage.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int windowWidth = GAME_DIALOG_WINDOW_WIDTH;
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
blitBufferToBuffer(backgroundFrmImage.getData(), windowWidth, 480, windowWidth, windowBuffer, windowWidth);
|
||||
if (!backgroundFrmImage.isLocked()) {
|
||||
// alltlk.frm - dialog screen background
|
||||
FrmId backgroundFid(OBJ_TYPE_INTERFACE, 103);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return -1;
|
||||
}
|
||||
gameDialogUseHrArt = false;
|
||||
}
|
||||
|
||||
ConstBuffer2D backgroundFrmBuf = backgroundFrmImage.getBuffer();
|
||||
Buffer2D windowBuf = windowGetBuffer2D(gGameDialogBackgroundWindow);
|
||||
blitBuffer2D(backgroundFrmBuf, 0, 0, GAME_DIALOG_WINDOW_WIDTH, GAME_DIALOG_WINDOW_HEIGHT, windowBuf);
|
||||
|
||||
if (!_dialogue_just_started) {
|
||||
windowRefresh(gGameDialogBackgroundWindow);
|
||||
@@ -4734,11 +4788,13 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
int yOffset = gameDialogHrArtYOffset();
|
||||
|
||||
Rect headRect;
|
||||
headRect.left = 126;
|
||||
headRect.top = 14;
|
||||
headRect.top = 14 + yOffset;
|
||||
headRect.right = 514;
|
||||
headRect.bottom = 214;
|
||||
headRect.bottom = 214 + yOffset;
|
||||
|
||||
unsigned char* dest = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
|
||||
@@ -4748,7 +4804,7 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
_upperHighlightFrmImage.getWidth(),
|
||||
dest,
|
||||
426,
|
||||
15,
|
||||
15 + yOffset,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
_light_BlendTable,
|
||||
_light_GrayTable);
|
||||
@@ -4759,20 +4815,20 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
_lowerHighlightFrmImage.getWidth(),
|
||||
dest,
|
||||
129,
|
||||
214 - _lowerHighlightFrmImage.getHeight() - 2,
|
||||
214 + yOffset - _lowerHighlightFrmImage.getHeight() - 2,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
_dark_BlendTable,
|
||||
_dark_GrayTable);
|
||||
|
||||
for (int index = 0; index < 8; ++index) {
|
||||
Rect* rect = &(_backgrndRects[index]);
|
||||
int width = rect->right - rect->left;
|
||||
Rect rect = gameDialogGetBackgroundRect(index);
|
||||
int width = rect.right - rect.left;
|
||||
|
||||
blitBufferToBufferTrans(_backgrndBufs[index],
|
||||
width,
|
||||
rect->bottom - rect->top,
|
||||
rect.bottom - rect.top,
|
||||
width,
|
||||
dest + GAME_DIALOG_WINDOW_WIDTH * rect->top + rect->left,
|
||||
dest + GAME_DIALOG_WINDOW_WIDTH * rect.top + rect.left,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user