Compare commits

...
Author SHA1 Message Date
Mike Klaas d2de6715dd more 2026-05-25 14:58:55 -07:00
Mike Klaas df4b787e86 prototype 1 2026-05-24 17:35:26 -07:00
Mike Klaas 6b442546cc better validation of transparency 2026-05-13 14:20:37 -07:00
Mike Klaas 2c08cc0b3a Switch 2-col inventory .frms to .png 2026-05-12 23:53:17 -07:00
Mike Klaas 09a1971cd8 Ability to load indexed pngs in game 2026-05-12 23:02:21 -07:00
Mike Klaas 7ae0452e1a Add original symbol beside all function and symbol offsets (#332)
* Add original symbol beside all function offsets

e.g.

```
// 0x414E98 register_object_call
int animationRegisterCallback(

// 0x414E20 register_object_must_erase
int animationRegisterHideObjectForced(
```

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

* mapper: save map corrections + some stubs

* mapper: fix playmode and cleanup discrepancy

* mapper: edit_mapper inacuracies and tidying up some code

* mapper: corrected Delete Spatial, minor fixes

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

* chore: auto-format with clang-format

* mapper: fix inaccuracies after AI review, round 1

* mapper: fix inaccuracies after AI review, round 2

* chore: auto-format with clang-format

---------

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

Description

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

* Emty commit for start clang formatter

* Used clang format

---------

Co-authored-by: ZoschukEN <ZoschukEN@RTK-CD.RU>
2026-05-11 10:10:23 -07:00
Mike Klaas 924e12b94c [HRP] Enable HR dialog screen (#441)
* [HRP] Enable HR dialog screen

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

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

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

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

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

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

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

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

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

* edit_mapper function + stubs

* Rename exe to mapper-ce

* load_lbm_to_buf

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

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

* Fix LBM loading

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

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

* load_lbm_to_buf rewrite, print_toolbar_name background fix

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

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

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

* Elevation display fix, object type switching

* Spatial script placement and display, basic object selection

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

* chore: auto-format with clang-format

* Fix non-win builds

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

* Fix compile on Linux

* Attempt to fix iOS signing error

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

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

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

* Add new files to CMakeLists

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

* chore: auto-format with clang-format

* Linux build fix attempt

* Critter inventory editing

* Vanilla grid-based inventory item picker

* Review fixes

* More review fixes and const correctness

---------

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

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

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

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

* Implement HOOK_INVENWIELD, HOOK_CANUSEWEAPON and fix HOOK_ADJUSTFID

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

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

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

* enum class

* chore: auto-format with clang-format

* bad merge

* PR feedback

* restore isEmpty() to vanilla while fixing bug

* fixes

* minor fixes

* extra

* Potential fix for pull request finding

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

---------

Co-authored-by: tectiv3 <tectiv3@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-04 21:36:50 -07:00
153 changed files with 10220 additions and 4028 deletions
+81 -4
View File
@@ -38,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"
@@ -154,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"
@@ -205,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"
@@ -268,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"
@@ -316,6 +318,14 @@ 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)
@@ -561,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")
+5 -5
View File
@@ -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

+6
View File
@@ -22,6 +22,10 @@ save_text_maps=0
show_pid_numbers=0
sort_script_list=0
use_art_not_protos=0
; Allows to load a certain map right away after loading the mapper.
map=denbus2
; Allows to disable grid item picker and use a simpler list-based picker.
use_grid_item_picker=1
[preferences]
brightness=1.000000
@@ -94,6 +98,8 @@ auto_quick_save=3
display_bonus_damage=1
;Set to 1 to get notification of karma changes in the notification window
display_karma_changes=0
;Set to 1 to use the hi-res dialog border/background at resolutions above 640x480. Requires art\intrface\HR_ALLTLK.FRM (for example from f2_res.dat)
dialog_border=1
;Set to one to hide areas outside map bounds when using higher than 640x480 resolution, and to zero to disable
enable_high_resolution_stencil=1
;Set to 1 to extend the action points bar to show up to 16 AP instead of 10 (requires iface_apbar_e.frm)
+83
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+3 -1
View File
@@ -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);
+3 -4
View File
@@ -47,13 +47,13 @@ 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
@@ -264,7 +264,6 @@ int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
if (info != nullptr) {
info->sampleRate = audioFile->sampleRate;
info->channels = audioFile->channels;
info->bitsPerSample = audioFile->bitsPerSample;
}
if (isMemoryBackedPtr != nullptr) {
+3 -4
View File
@@ -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
@@ -100,7 +100,6 @@ int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPt
audioFile->fileSize *= 2;
if (info != nullptr) {
info->sampleRate = audioFile->sampleRate;
info->channels = audioFile->channels;
info->bitsPerSample = 16;
}
if (isMemoryBackedPtr != nullptr) {
+23 -23
View File
@@ -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
View File
@@ -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
+19 -19
View File
@@ -30,11 +30,11 @@ static bool cacheSetCapacity(Cache* cache, int newCapacity);
static int cacheEntriesCompareByUsage(const void* a1, const void* a2);
static int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2);
// 0x510938
// 0x510938 lock_sound_ticker
static int _lock_sound_ticker = 0;
// cache_init
// 0x41FCC0
// 0x41FCC0 cache_init
bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, CacheFreeProc* freeProc, int maxSize)
{
if (!heapInit(&(cache->heap), maxSize)) {
@@ -61,7 +61,7 @@ bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, C
}
// cache_exit
// 0x41FD50
// 0x41FD50 cache_exit
bool cacheFree(Cache* cache)
{
if (cache == nullptr) {
@@ -90,7 +90,7 @@ bool cacheFree(Cache* cache)
return true;
}
// 0x41FDE8
// 0x41FDE8 cache_lock
bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr)
{
if (cache == nullptr || data == nullptr || cacheEntryPtr == nullptr) {
@@ -145,7 +145,7 @@ bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr)
return true;
}
// 0x4200B8
// 0x4200B8 cache_unlock
bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry)
{
if (cache == nullptr || cacheEntry == nullptr) {
@@ -166,7 +166,7 @@ bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry)
}
// cache_flush
// 0x42012C
// 0x42012C cache_flush
bool cacheFlush(Cache* cache)
{
if (cache == nullptr) {
@@ -193,7 +193,7 @@ bool cacheFlush(Cache* cache)
return true;
}
// 0x42019C
// 0x42019C cache_stats
bool cachePrintStats(Cache* cache, char* dest, size_t size)
{
if (cache == nullptr || dest == nullptr) {
@@ -207,7 +207,7 @@ bool cachePrintStats(Cache* cache, char* dest, size_t size)
// Fetches entry for the specified key into the cache.
//
// 0x4203AC
// 0x4203AC cache_add
static bool cacheFetchEntryForKey(Cache* cache, int key, int* indexPtr)
{
CacheEntry* cacheEntry = (CacheEntry*)internal_malloc(sizeof(*cacheEntry));
@@ -307,7 +307,7 @@ static bool cacheFetchEntryForKey(Cache* cache, int key, int* indexPtr)
return false;
}
// 0x4205E8
// 0x4205E8 cache_insert
static bool cacheInsertEntryAtIndex(Cache* cache, CacheEntry* cacheEntry, int index)
{
// Ensure cache have enough space for new entry.
@@ -332,7 +332,7 @@ static bool cacheInsertEntryAtIndex(Cache* cache, CacheEntry* cacheEntry, int in
// Returns 2 if entry already exists in cache, or 3 if entry does not exist. In
// this case indexPtr represents insertion point.
//
// 0x420654
// 0x420654 cache_find
static int cacheFindIndexForKey(Cache* cache, int key, int* indexPtr)
{
int length = cache->entriesLength;
@@ -371,7 +371,7 @@ static int cacheFindIndexForKey(Cache* cache, int key, int* indexPtr)
return 3;
}
// 0x420708
// 0x420708 cache_init_item
static bool cacheEntryInit(CacheEntry* cacheEntry)
{
cacheEntry->key = 0;
@@ -386,7 +386,7 @@ static bool cacheEntryInit(CacheEntry* cacheEntry)
// NOTE: Inlined.
//
// 0x420740
// 0x420740 cache_destroy_item
static bool cacheEntryFree(Cache* cache, CacheEntry* cacheEntry)
{
if (cacheEntry->data != nullptr) {
@@ -398,7 +398,7 @@ static bool cacheEntryFree(Cache* cache, CacheEntry* cacheEntry)
return true;
}
// 0x420764
// 0x420764 cache_unlock_all
static bool cacheClean(Cache* cache)
{
Heap* heap = &(cache->heap);
@@ -417,7 +417,7 @@ static bool cacheClean(Cache* cache)
return true;
}
// 0x4207D4
// 0x4207D4 cache_reset_counter
static bool cacheResetStatistics(Cache* cache)
{
if (cache == nullptr) {
@@ -447,7 +447,7 @@ static bool cacheResetStatistics(Cache* cache)
// Prepare cache for storing new entry with the specified size.
//
// 0x42084C
// 0x42084C cache_make_room
static bool cacheEnsureSize(Cache* cache, int size)
{
if (size > cache->maxSize) {
@@ -523,7 +523,7 @@ static bool cacheEnsureSize(Cache* cache, int size)
return false;
}
// 0x42099C
// 0x42099C cache_purge
static bool cacheSweep(Cache* cache)
{
for (int index = 0; index < cache->entriesLength; index++) {
@@ -554,7 +554,7 @@ static bool cacheSweep(Cache* cache)
return true;
}
// 0x420A40
// 0x420A40 cache_resize_array
static bool cacheSetCapacity(Cache* cache, int newCapacity)
{
if (newCapacity < cache->entriesLength) {
@@ -572,7 +572,7 @@ static bool cacheSetCapacity(Cache* cache, int newCapacity)
return true;
}
// 0x420A74
// 0x420A74 cache_compare_make_room
static int cacheEntriesCompareByUsage(const void* a1, const void* a2)
{
CacheEntry* lhs = *(CacheEntry**)a1;
@@ -601,7 +601,7 @@ static int cacheEntriesCompareByUsage(const void* a1, const void* a2)
return 0;
}
// 0x420AE8
// 0x420AE8 cache_compare_reset_counter
static int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2)
{
CacheEntry* lhs = *(CacheEntry**)a1;
+152 -152
View File
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -90,44 +90,44 @@ static bool characterSelectorWindowFatalError(bool result);
static void premadeCharactersLocalizePath(char* path);
// 0x51C84C
// 0x51C84C premade_index
static int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
// 0x51C850
// 0x51C850 premade_characters
static PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACTER_COUNT] = {
{ "premade\\combat", 201, "VID 208-197-88-125" },
{ "premade\\stealth", 202, "VID 208-206-49-229" },
{ "premade\\diplomat", 203, "VID 208-206-49-227" },
};
// 0x51C8D4
// 0x51C8D4 premade_total
static int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
// 0x51C7F8
// 0x51C7F8 select_window_id
static int gCharacterSelectorWindow = -1;
// 0x51C7FC
// 0x51C7FC select_window_buffer
static unsigned char* gCharacterSelectorWindowBuffer = nullptr;
// 0x51C800
// 0x51C800 monitor
static unsigned char* gCharacterSelectorBackground = nullptr;
// 0x51C804
// 0x51C804 previous_button
static int gCharacterSelectorWindowPreviousButton = -1;
// 0x51C810
// 0x51C810 next_button
static int gCharacterSelectorWindowNextButton = -1;
// 0x51C81C
// 0x51C81C take_button
static int gCharacterSelectorWindowTakeButton = -1;
// 0x51C828
// 0x51C828 modify_button
static int gCharacterSelectorWindowModifyButton = -1;
// 0x51C834
// 0x51C834 create_button
static int gCharacterSelectorWindowCreateButton = -1;
// 0x51C840
// 0x51C840 back_button
static int gCharacterSelectorWindowBackButton = -1;
static FrmImage _takeButtonNormalFrmImage;
@@ -145,7 +145,7 @@ static FrmImage _previousButtonPressedFrmImage;
static std::vector<PremadeCharacterDescription> gCustomPremadeCharacterDescriptions;
// 0x4A71D0
// 0x4A71D0 select_character
int characterSelectorOpen()
{
#if __APPLE__ && TARGET_OS_IOS
@@ -260,7 +260,7 @@ int characterSelectorOpen()
return rc;
}
// 0x4A7468
// 0x4A7468 select_init
static bool characterSelectorWindowInit()
{
if (gCharacterSelectorWindow != -1) {
@@ -497,7 +497,7 @@ static bool characterSelectorWindowInit()
return true;
}
// 0x4A7AD4
// 0x4A7AD4 select_exit
static void characterSelectorWindowFree()
{
if (gCharacterSelectorWindow == -1) {
@@ -561,7 +561,7 @@ static void characterSelectorWindowFree()
gCharacterSelectorWindow = -1;
}
// 0x4A7D58
// 0x4A7D58 select_update_display
static bool characterSelectorWindowRefresh()
{
char path[COMPAT_MAX_PATH];
@@ -592,7 +592,7 @@ static bool characterSelectorWindowRefresh()
return success;
}
// 0x4A7E08
// 0x4A7E08 select_display_portrait
static bool characterSelectorWindowRenderFace()
{
bool success = false;
@@ -613,7 +613,7 @@ static bool characterSelectorWindowRenderFace()
return success;
}
// 0x4A7EA8
// 0x4A7EA8 select_display_stats
static bool characterSelectorWindowRenderStats()
{
char* str;
@@ -865,7 +865,7 @@ static bool characterSelectorWindowRenderStats()
return true;
}
// 0x4A8AE4
// 0x4A8AE4 select_display_bio
static bool characterSelectorWindowRenderBio()
{
int oldFont = fontGetCurrent();
@@ -896,7 +896,7 @@ static bool characterSelectorWindowRenderBio()
// NOTE: Inlined.
//
// 0x4A8BD0
// 0x4A8BD0 select_fatal_error
static bool characterSelectorWindowFatalError(bool result)
{
characterSelectorWindowFree();
+36 -36
View File
@@ -17,63 +17,63 @@ static void _setMixTableColor(int color);
static void _buildBlendTable(unsigned char* ptr, unsigned char ch);
static void _rebuildColorBlendTables();
// 0x50F930
// 0x50F930 aColor_cNoError
static char _aColor_cNoError[] = "color.c: No errors\n";
// 0x50F95C
// 0x50F95C aColor_cColorTa
static char _aColor_cColorTa[] = "color.c: color table not found\n";
// 0x50F984
// 0x50F984 aColor_cColorpa
static char _aColor_cColorpa[] = "color.c: colorpalettestack overflow";
// 0x50F9AC
// 0x50F9AC aColor_cColor_0
static char aColor_cColor_0[] = "color.c: colorpalettestack underflow";
// 0x51DF10
// 0x51DF10 errorStr
static char* _errorStr = _aColor_cNoError;
// 0x51DF14
// 0x51DF14 colorsInited
static bool _colorsInited = false;
// 0x51DF18
// 0x51DF18 currentGamma
static double gBrightness = 1.0;
// 0x51DF20
// 0x51DF20 colorFadeBkFuncP
static ColorTransitionCallback* gColorPaletteTransitionCallback = nullptr;
// 0x51DF30
// 0x51DF30 colorNameMangler
static ColorFileNameManger* gColorFileNameMangler = nullptr;
// 0x51DF34
// 0x51DF34 cmap
unsigned char _cmap[768] = {
0x3F, 0x3F, 0x3F
};
// 0x673090
// 0x673090 systemCmap1
unsigned char _systemCmap[256 * 3];
// 0x673390
// 0x673390 currentGammaTable
unsigned char _currentGammaTable[64];
// 0x6733D0
// 0x6733D0 blendTable
unsigned char* _blendTable[256];
// 0x6737D0
// 0x6737D0 mappedColor
unsigned char _mappedColor[256];
// 0x6738D0
// 0x6738D0 colorMixAddTable
Color colorMixAddTable[256][256];
// 0x6838D0
// 0x6838D0 intensityColorTable
Color intensityColorTable[256][256];
// 0x6938D0
// 0x6938D0 colorMixMulTable
Color colorMixMulTable[256][256];
// 0x6A38D0
// 0x6A38D0 colorTable
unsigned char _colorTable[32768];
// 0x4C72B4
// 0x4C72B4 calculateColor
int _calculateColor(int intensity, Color color)
{
return intensityColorTable[color][intensity / 512];
@@ -91,7 +91,7 @@ int Color2RGB(Color c)
// Performs animated palette transition.
//
// 0x4C7320
// 0x4C7320 fadeSystemPalette
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps)
{
for (int step = 0; step < steps; step++) {
@@ -120,13 +120,13 @@ void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalett
sharedFpsLimiter.throttle();
}
// 0x4C73D4
// 0x4C73D4 colorSetFadeBkFunc
void colorPaletteSetTransitionCallback(ColorTransitionCallback* callback)
{
gColorPaletteTransitionCallback = callback;
}
// 0x4C73E4
// 0x4C73E4 setSystemPalette
void _setSystemPalette(unsigned char* palette)
{
unsigned char newPalette[768];
@@ -139,13 +139,13 @@ void _setSystemPalette(unsigned char* palette)
directDrawSetPalette(newPalette);
}
// 0x4C7420
// 0x4C7420 getSystemPalette
unsigned char* _getSystemPalette()
{
return _systemCmap;
}
// 0x4C7428
// 0x4C7428 setSystemPaletteEntries
void _setSystemPaletteEntries(unsigned char* palette, int start, int end)
{
unsigned char newPalette[768];
@@ -164,7 +164,7 @@ void _setSystemPaletteEntries(unsigned char* palette, int start, int end)
directDrawSetPaletteInRange(newPalette, start, end - start + 1);
}
// 0x4C7550
// 0x4C7550 setIntensityTableColor
static void _setIntensityTableColor(int cc)
{
int shift = 0;
@@ -190,7 +190,7 @@ static void _setIntensityTableColor(int cc)
}
}
// 0x4C7658
// 0x4C7658 setIntensityTables
static void _setIntensityTables()
{
for (int index = 0; index < 256; index++) {
@@ -202,7 +202,7 @@ static void _setIntensityTables()
}
}
// 0x4C769C
// 0x4C769C setMixTableColor
static void _setMixTableColor(int color)
{
for (int otherColor = 0; otherColor < 256; otherColor++) {
@@ -278,7 +278,7 @@ static void _setMixTableColor(int color)
}
}
// 0x4C78E4
// 0x4C78E4 loadColorTable
bool colorPaletteLoad(const char* path)
{
if (gColorFileNameMangler != nullptr) {
@@ -353,13 +353,13 @@ bool colorPaletteLoad(const char* path)
return true;
}
// 0x4C7AB4
// 0x4C7AB4 colorError
char* _colorError()
{
return _errorStr;
}
// 0x4C7B44
// 0x4C7B44 buildBlendTable
static void _buildBlendTable(unsigned char* ptr, unsigned char ch)
{
int r, g, b;
@@ -419,7 +419,7 @@ static void _buildBlendTable(unsigned char* ptr, unsigned char ch)
}
}
// 0x4C7D90
// 0x4C7D90 rebuildColorBlendTables
static void _rebuildColorBlendTables()
{
int i;
@@ -431,7 +431,7 @@ static void _rebuildColorBlendTables()
}
}
// 0x4C7DC0
// 0x4C7DC0 getColorBlendTable
unsigned char* _getColorBlendTable(int ch)
{
unsigned char* ptr;
@@ -449,7 +449,7 @@ unsigned char* _getColorBlendTable(int ch)
return ptr;
}
// 0x4C7E20
// 0x4C7E20 freeColorBlendTable
void _freeColorBlendTable(int color)
{
unsigned char* blendTable = _blendTable[color];
@@ -463,7 +463,7 @@ void _freeColorBlendTable(int color)
}
}
// 0x4C7E6C
// 0x4C7E6C colorGamma
void colorSetBrightness(double value)
{
gBrightness = value;
@@ -476,7 +476,7 @@ void colorSetBrightness(double value)
_setSystemPalette(_systemCmap);
}
// 0x4C89CC
// 0x4C89CC initColors
bool _initColors()
{
if (_colorsInited) {
@@ -496,7 +496,7 @@ bool _initColors()
return true;
}
// 0x4C8A18
// 0x4C8A18 colorsClose
void _colorsClose()
{
for (int index = 0; index < 256; index++) {

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