Compare commits

..
Author SHA1 Message Date
phobos2077 a4a929f620 mapper: reworked writing paths logic
- Drop "target_path_base" and other references to BIS "fallout/dev/" folder in favor of new dev_temp_path setting
- Clear separation between "mapper temp assets" (.cfg, .txt, .tgt), "shipped assets" (.map, .edg, .pro) and "runtime temp assets" (.sav)
- dev_temp_path is mounted as highest priority xbase, so all saved data goes there by default
- as a consequence, play-mode assets (maps with .sav extension and party member .pro files) are explicitly saved to master_patches_path instead of implicitly by using xfileOpen in write mode
2026-06-14 13:29:22 +02:00
phobos2077 f5ba58f27a mapper: proto edit: fix bugs, light refactor and use correct colors 2026-06-13 00:29:09 +02:00
phobos2077 9bd179167c mapper: move proto TXT handling to separate file 2026-06-12 14:50:33 +02:00
phobos2077 9e88b16d71 mapper: fix incorrect strings 2026-06-12 00:37:21 +02:00
phobos2077 15a4f4275b mapper: critter proto editing + wire up all editors 2026-06-12 00:05:34 +02:00
phobos2077 466f12b22e mapper: proto TXT support 2026-06-11 23:45:48 +02:00
phobos2077 26622f3596 mapper: name/description editing 2026-06-11 23:41:07 +02:00
phobos2077 629d1f2b7b mapper: item proto editing 2026-06-11 21:37:20 +02:00
phobos2077 1453a3e294 mapper: scenery proto editing 2026-06-11 21:13:06 +02:00
phobos2077 b5c0fbdf86 mapper: simple proto editing 2026-06-11 21:02:42 +02:00
phobos2077 948558c64c mapper: misc proto editing functions 2026-06-07 11:52:53 +02:00
phobos2077 6412d14a28 mapper: proto_edit_init, proto_remove 2026-06-07 11:15:44 +02:00
63 changed files with 3699 additions and 1100 deletions
+2
View File
@@ -614,6 +614,8 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
target_sources(mapper-ce PUBLIC
${FALLOUT_ENGINE_SOURCES}
${FALLOUT_PLATFORM_SOURCES}
"src/proto_txt.cc"
"src/proto_txt.h"
"src/mapper/map_edge_setup.cc"
"src/mapper/map_edge_setup.h"
"src/mapper/map_func.cc"
+4 -6
View File
@@ -81,14 +81,12 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | implemented: critter_inven_obj2, item_weight | - |
| Interface / Cursor | get/set_cursor_mode | âś… | - |
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… | `modified_ini` is intentionally omitted as deprecated. |
| 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, set_unique_id, obj_is_openable, get_proto_data, set_proto_data | - |
| Other / Game management | set_movie_path<br>stop/resume_game<br>mark_movie_played<br>game_loaded<br>get_game_mode<br>get_uptime<br>signal_close_game | implemented: game_loaded, get_game_mode, get_uptime, signal_close_game | - |
| Gameplay tweaks | set_pickpocket_max<br>set_hit_chance_max<br>set_xp_mod<br>set_critter_hit_chance_mod<br>set_base_hit_chance_mod<br>set_hp_per_level_mod<br>gdialog_get_barter_mod<br>get/set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>get/set_inven_ap_cost<br>set_drugs_data<br>get_kill_counter<br>mod_kill_counter<br>set_pipboy_available | implemented: gdialog_get_barter_mod, get/set_unspent_ap{_perk}_bonus, get/set_inven_ap_cost | - |
| NPCs | inc_npc_level<br>get_npc_level<br>npc_engine_level_up | not implemented | - |
| Hero Appearange | set_dm/df_model<br>hero_select_win | not implemented | - |
| Events | add_g_timer_event<br>remove_timer_event<br>create_spatial<br>spatial_radius | not implemented | - |
| Other | get_year<br>active_hand<br>toggle_active_hand<br>get/set_viewport_x/y<br>get_light_level<br>message_str_game<br>sneak_success<br>unwield_slot<br>add_extra_msg_file<br>get_metarule_table<br>metarule_exist<br> | âś… except get/set_viewport_x/y, sneak_success | `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. |
| 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. |
## Hooks
@@ -106,8 +104,8 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| UseObj | `HOOK_USEOBJ` | âś… | CE notes an sfall-matching inconsistency around return code `2` behavior between interface contexts. |
| RemoveInvenObj | `HOOK_REMOVEINVENOBJ` | đźš« | - |
| BarterPrice | `HOOK_BARTERPRICE` | âś… | - |
| ItemDamage | `HOOK_ITEMDAMAGE` | âś… | - |
| MoveCost | `HOOK_MOVECOST` | âś… | - |
| MoveCost | `HOOK_MOVECOST` | đźš« | - |
| ItemDamage | `HOOK_ITEMDAMAGE` | đźš« | - |
| AmmoCost | `HOOK_AMMOCOST` | âś… | Requires `check_weapon_ammo_cost=1` if you want pre-attack ammo validation to respect per-shot/per-round overrides. |
| KeyPress | `HOOK_KEYPRESS` | âś… | Third hook arg is currently `0`; CE doesn't use VK codes. |
| MouseClick | `HOOK_MOUSECLICK` | âś… | - |
-6
View File
@@ -65,12 +65,6 @@ procedure ini_test_suite begin
call assertEquals("TC7 get_ini_sections size", len_array(result_array), 3);
call assertTrue("TC7 get_ini_sections", scan_array(result_array, "TestMisc") >= 0);
// get_ini_config
result_array := get_ini_config_db("config\\config_from_db.cfg");
call assertEquals("TC8 get_ini_config_db size", len_array(result_array), 2);
call assertTrue("TC8 get_ini_config ValidSection", result_array.ValidSection != 0);
call assertEquals("TC8 get_ini_config_db ValidValue", result_array.ValidSection.ValidKey, "ValidValue");
call report_test_results("ini");
end
-43
View File
@@ -1,43 +0,0 @@
#include "sfall.h"
#include "dik.h"
#include "define_lite.h"
#include "define_extra.h"
#include "test_utils.h"
procedure run_unwield_slot_test(variable slot, variable slotName) begin
variable equippedItem := critter_inven_obj2(dude_obj, slot);
if (equippedItem == 0) then begin
display_msg("unwield_slot " + slotName + ": slot is empty");
return;
end
unwield_slot(dude_obj, slot);
call assertTrue("unwield_slot clears " + slotName + " slot", critter_inven_obj2(dude_obj, slot) == 0);
call report_test_results("unwield_slot");
end
procedure keypress_handler begin
variable pressed := get_sfall_arg_at(0);
variable key := get_sfall_arg_at(1);
if (not pressed) then return;
if (key == DIK_J) then begin
call run_unwield_slot_test(INVEN_TYPE_WORN, "armor");
end else if (key == DIK_K) then begin
call run_unwield_slot_test(INVEN_TYPE_RIGHT_HAND, "right");
end else if (key == DIK_L) then begin
call run_unwield_slot_test(INVEN_TYPE_LEFT_HAND, "left");
end
end
procedure start begin
if (not game_loaded) then return;
call assertEquals("unwield_slot metarule exists", metarule_exist("unwield_slot"), 1);
call assertEquals("critter_inven_obj2 metarule exists", metarule_exist("critter_inven_obj2"), 1);
display_msg("unwield_slot manual test ready: open inventory or barter, then press J armor, K right, L left");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
-98
View File
@@ -1,98 +0,0 @@
#include "sfall.h"
#include "dik.h"
#include "lib.arrays.h"
#include "../test_utils.h"
variable itemdamage_mode := 0;
variable itemdamage_seen := 0;
variable itemdamage_last_min := 0;
variable itemdamage_last_max := 0;
variable itemdamage_last_hit_mode := 0;
variable itemdamage_last_is_melee_weapon := 0;
variable itemdamage_last_weapon_pid := -1;
variable itemdamage_last_weapon_name := "<none>";
procedure itemdamage_mode_name begin
if (itemdamage_mode == 1) then return "fixed-42";
if (itemdamage_mode == 2) then return "range-30-30";
return "engine";
end
procedure itemdamage_weapon_name(variable weapon) begin
if (weapon == 0) then return "<unarmed>";
return obj_name(weapon);
end
procedure itemdamage_handler begin
variable
args := get_sfall_args,
weapon := args[2];
call assertEquals("itemdamage arg count", len_array(args), 6);
call assertTrue("itemdamage min <= max", args[0] <= args[1]);
call assertTrue("itemdamage melee flag", args[5] == 0 or args[5] == 1);
itemdamage_seen := itemdamage_seen + 1;
itemdamage_last_min := args[0];
itemdamage_last_max := args[1];
itemdamage_last_hit_mode := args[4];
itemdamage_last_is_melee_weapon := args[5];
itemdamage_last_weapon_name := itemdamage_weapon_name(weapon);
if (weapon == 0) then
itemdamage_last_weapon_pid := -1;
else
itemdamage_last_weapon_pid := obj_pid(weapon);
display_msg(string_format6("itemdamage mode=%s min=%d max=%d weapon=%s hit=%d melee=%d",
itemdamage_mode_name,
args[0],
args[1],
itemdamage_last_weapon_name,
itemdamage_last_hit_mode,
itemdamage_last_is_melee_weapon));
if (itemdamage_mode == 1) then begin
set_sfall_return(42);
end else if (itemdamage_mode == 2) then begin
set_sfall_return(30);
set_sfall_return(30);
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_J) then begin
itemdamage_mode := itemdamage_mode + 1;
if (itemdamage_mode > 2) then itemdamage_mode := 0;
display_msg(string_format1("itemdamage mode -> %s", itemdamage_mode_name));
end else if (key == DIK_K) then begin
display_msg(string_format7("itemdamage summary mode=%s seen=%d last=%d-%d weapon=%s pid=%d melee=%d",
itemdamage_mode_name,
itemdamage_seen,
itemdamage_last_min,
itemdamage_last_max,
itemdamage_last_weapon_name,
itemdamage_last_weapon_pid,
itemdamage_last_is_melee_weapon));
call assertTrue("itemdamage observed", itemdamage_seen > 0);
call report_test_results("itemdamage");
end
end
procedure start begin
if (not game_loaded) then return;
display_msg("itemdamage manual test ready:");
display_msg("press J to cycle engine/fixed-42/range-30-30");
display_msg("attack with fists, melee weapons, and ranged weapons");
display_msg("press K to report after HOOK_ITEMDAMAGE fires");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_ITEMDAMAGE, itemdamage_handler);
end
-70
View File
@@ -1,70 +0,0 @@
#include "sfall.h"
#include "dik.h"
variable movecost_mode := 0;
procedure movecost_mode_name(variable mode) begin
variable name := "unknown";
if (mode == 0) then name := "engine";
else if (mode == 1) then name := "plus_per_hex";
else if (mode == 2) then name := "double";
return name;
end
procedure cycle_movecost_mode begin
if (movecost_mode == 0) then movecost_mode := 1;
else if (movecost_mode == 1) then movecost_mode := 2;
else movecost_mode := 0;
display_msg(string_format1("movecost mode=%s", movecost_mode_name(movecost_mode)));
end
procedure movecost_handler begin
variable
args := get_sfall_args,
critter := args[0],
distance := args[1],
defaultCost := args[2],
modeName := movecost_mode_name(movecost_mode),
newCost := defaultCost;
if (critter != dude_obj) then return;
display_msg(string_format3("movecost dist=%d default=%d mode=%s",
distance,
defaultCost,
modeName));
if (movecost_mode == 1) then begin
newCost := defaultCost + distance;
end else if (movecost_mode == 2) then begin
newCost := defaultCost * 2;
end else begin
return;
end
set_sfall_return(newCost);
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_M) then return;
call cycle_movecost_mode;
end
procedure start begin
if (not game_loaded) then return;
display_msg("movecost manual test ready: enter combat, hover a tile, then move");
display_msg("press M to cycle hook override: engine -> plus_per_hex -> double");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_MOVECOST, movecost_handler);
end
@@ -1,7 +0,0 @@
[ValidSection]
ValidKey=ValidValue
Key2=2
[Section2]
Key1=AA
Key2=BB
-2
View File
@@ -1,2 +0,0 @@
A test mod for sfall scripting features testing.
Add it to your mods_order.txt
@@ -1 +0,0 @@
Put compiled scripts in here
+6
View File
@@ -367,6 +367,12 @@ void artToggleObjectTypeHidden(int objectType)
}
}
// art_total
int art_total(int objectType)
{
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].fileNamesLength : 0;
}
// 0x418F7C
int artGetFidgetCount(int headFid)
{
+1
View File
@@ -123,6 +123,7 @@ void artExit();
char* artGetObjectTypeName(int objectType);
int artIsObjectTypeHidden(int objectType);
void artToggleObjectTypeHidden(int objectType);
int art_total(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);
+7 -30
View File
@@ -112,8 +112,6 @@ typedef enum EditorFolder {
EDITOR_FOLDER_KILLS,
} EditorFolder;
static void characterEditorMessageListReset();
enum {
EDITOR_DERIVED_STAT_ARMOR_CLASS,
EDITOR_DERIVED_STAT_ACTION_POINTS,
@@ -589,12 +587,6 @@ static int gCharacterEditorOptionalTraitBtns[TRAIT_COUNT];
// 0x5700E8 mesg
static MessageListItem gCharacterEditorMessageListItem;
static void characterEditorMessageListReset()
{
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_EDITOR, nullptr);
messageListFree(&gCharacterEditorMessageList);
}
// 0x5700F8 old_str1
static char gCharacterEditorCardTitle[48];
@@ -1292,35 +1284,18 @@ static int characterEditorWindowInit()
if (!messageListLoad(&gCharacterEditorMessageList, path)) {
return -1;
}
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_EDITOR, &gCharacterEditorMessageList);
fid = buildFid(OBJ_TYPE_INTERFACE, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0);
if (!_editorBackgroundFrmImage.lock(fid)) {
characterEditorMessageListReset();
messageListFree(&gCharacterEditorMessageList);
return -1;
}
if (karmaInit() == -1) {
_editorBackgroundFrmImage.unlock();
characterEditorMessageListReset();
if (gCharacterEditorIsoWasEnabled) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
if (genericReputationInit() == -1) {
karmaFree();
_editorBackgroundFrmImage.unlock();
characterEditorMessageListReset();
if (gCharacterEditorIsoWasEnabled) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
@@ -1343,9 +1318,11 @@ static int characterEditorWindowInit()
while (--i >= 0) {
_editorFrmImages[i].unlock();
}
return -1;
_editorBackgroundFrmImage.unlock();
characterEditorMessageListReset();
messageListFree(&gCharacterEditorMessageList);
if (gCharacterEditorIsoWasEnabled) {
isoEnable();
@@ -1383,7 +1360,7 @@ static int characterEditorWindowInit()
_editorBackgroundFrmImage.unlock();
characterEditorMessageListReset();
messageListFree(&gCharacterEditorMessageList);
if (gCharacterEditorIsoWasEnabled) {
isoEnable();
}
@@ -1412,7 +1389,7 @@ static int characterEditorWindowInit()
_editorBackgroundFrmImage.unlock();
characterEditorMessageListReset();
messageListFree(&gCharacterEditorMessageList);
if (gCharacterEditorIsoWasEnabled) {
isoEnable();
}
@@ -1892,7 +1869,7 @@ static void characterEditorWindowFree()
// SFALL: Custom town reputation.
customTownReputationFree();
characterEditorMessageListReset();
messageListFree(&gCharacterEditorMessageList);
interfaceBarRefresh();
+3 -6
View File
@@ -1359,16 +1359,13 @@ int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int dist
}
int flags = critter->data.critter.combat.results;
int actionPoints = 0;
if ((flags & DAM_CRIP_LEG_LEFT) != 0 && (flags & DAM_CRIP_LEG_RIGHT) != 0) {
actionPoints = 8 * distance;
return 8 * distance;
} else if ((flags & DAM_CRIP_LEG_ANY) != 0) {
actionPoints = 4 * distance;
return 4 * distance;
} else {
actionPoints = distance;
return distance;
}
return scriptHooks_MoveCost(critter, distance, actionPoints);
}
// 0x42E66C critterIsOverloaded
+24
View File
@@ -144,6 +144,30 @@ File* fileOpen(const char* filename, const char* mode)
return xfileOpen(filename, mode);
}
File* fileOpenDirect(const char* filename, const char* mode)
{
return xfileOpenDirect(filename, mode);
}
const char* buildDataPath(const char* root, const char* relative)
{
static char path[COMPAT_MAX_PATH];
size_t rootLen = strlen(root);
bool rootHasSeparator = rootLen > 0 && (root[rootLen - 1] == '\\' || root[rootLen - 1] == '/');
snprintf(path, sizeof(path), "%s%s%s", root, rootHasSeparator ? "" : "\\", relative);
char dir[COMPAT_MAX_PATH];
snprintf(dir, sizeof(dir), "%s", path);
char* separator = strrchr(dir, '\\');
if (separator != nullptr) {
*separator = '\0';
compat_mkdir_recursive(dir);
}
return path;
}
// 0x4C5ED0 db_fprintf
int filePrintFormatted(File* stream, const char* format, ...)
{
+5
View File
@@ -18,6 +18,7 @@ int dbGetFileSize(const char* filePath, int* sizePtr);
int dbGetFileContents(const char* filePath, void* ptr);
int fileClose(File* stream);
File* fileOpen(const char* filename, const char* mode);
File* fileOpenDirect(const char* filename, const char* mode);
int filePrintFormatted(File* stream, const char* format, ...);
int fileReadChar(File* stream);
char* fileReadString(char* str, size_t size, File* stream);
@@ -111,6 +112,10 @@ void fileNameListFree(char*** fileNames, int unused);
int fileGetSize(File* stream);
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size);
// Joins [root] and [relative] into a save path and creates its directory.
// Returns a pointer to a static buffer.
const char* buildDataPath(const char* root, const char* relative);
} // namespace fallout
#endif /* DB_H */
-1
View File
@@ -448,7 +448,6 @@ void gameReset()
scriptHooksReset();
sfallArraysReset();
sfall_gl_scr_reset();
sfall_ini_cache_clear();
sfallOnGameReset();
gGameLoaded = false;
}
+1 -12
View File
@@ -86,8 +86,6 @@ typedef enum GameDialogReviewWindowButtonFrm {
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT,
} GameDialogReviewWindowButtonFrm;
static void partyMemberCustomizationMessageListReset();
typedef enum GameDialogReaction {
GAME_DIALOG_REACTION_GOOD = 49,
GAME_DIALOG_REACTION_NEUTRAL = 50,
@@ -585,12 +583,6 @@ static int gGameDialogReviewWindowOldFont;
// 0x58F470 gdialog_buttons
static int _gdialog_buttons[9];
static void partyMemberCustomizationMessageListReset()
{
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_CUSTOM, nullptr);
messageListFree(&gCustomMessageList);
}
// 0x58F4C8 oldFont
static int _oldFont;
@@ -3974,12 +3966,10 @@ int partyMemberCustomizationWindowInit()
if (!messageListLoad(&gCustomMessageList, "game\\custom.msg")) {
return -1;
}
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_CUSTOM, &gCustomMessageList);
FrmImage backgroundFrmImage;
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0);
if (!backgroundFrmImage.lock(backgroundFid)) {
partyMemberCustomizationMessageListReset();
return -1;
}
@@ -4091,7 +4081,6 @@ int partyMemberCustomizationWindowInit()
void partyMemberCustomizationWindowFree()
{
if (gGameDialogWindow == -1) {
partyMemberCustomizationMessageListReset();
return;
}
@@ -4129,7 +4118,7 @@ void partyMemberCustomizationWindowFree()
windowDestroy(gGameDialogWindow);
gGameDialogWindow = -1;
partyMemberCustomizationMessageListReset();
messageListFree(&gCustomMessageList);
}
// 0x449B3C
+4 -4
View File
@@ -151,7 +151,7 @@ typedef enum OpRegAnimFunc {
static void scriptPredefinedError(Program* program, const char* name, int error);
static void scriptError(const char* format, ...);
static int tileIsVisible(int tile);
int correctFidForRemovedItem(Object* critter, Object* item, int flags);
static int _correctFidForRemovedItem(Object* critter, Object* item, int flags);
static void opGiveExpPoints(Program* program);
static void opScrReturn(Program* program);
static void opPlaySfx(Program* program);
@@ -407,7 +407,7 @@ static int tileIsVisible(int tile)
}
// 0x45409C correctFidForRemovedItem
int correctFidForRemovedItem(Object* critter, Object* item, int flags)
static int _correctFidForRemovedItem(Object* critter, Object* item, int flags)
{
InvenSlot invenSlot = InvenSlot::Armor;
if ((flags & OBJECT_IN_RIGHT_HAND) != 0) {
@@ -1683,7 +1683,7 @@ static void opRemoveObjectFromInventory(Program* program)
tileWindowRefreshRect(&rect, item->elevation);
if (updateFlags) {
correctFidForRemovedItem(owner, item, flags);
_correctFidForRemovedItem(owner, item, flags);
}
}
}
@@ -4641,7 +4641,7 @@ static void opMoveObjectInventoryToObject(Program* program)
flags |= OBJECT_IN_RIGHT_HAND;
}
correctFidForRemovedItem(object1, oldWeapon, flags);
_correctFidForRemovedItem(object1, oldWeapon, flags);
}
itemMoveAll(object1, object2);
+1 -4
View File
@@ -2,11 +2,10 @@
#define INTERPRETER_EXTRA_H
#include "interpreter.h"
#include "obj_types.h"
namespace fallout {
enum class InvenSlot : int {
enum class InvenSlot {
Armor = 0, // INVEN_TYPE_WORN
RightHand = 1, // INVEN_TYPE_RIGHT_HAND
LeftHand = 2, // INVEN_TYPE_LEFT_HAND
@@ -14,8 +13,6 @@ enum class InvenSlot : int {
constexpr int kInvenSlotInvCount = -2;
int correctFidForRemovedItem(Object* critter, Object* item, int flags);
void _intExtraClose_();
void _initIntExtra();
void intExtraUpdate();
+3 -138
View File
@@ -937,7 +937,6 @@ static int inventoryMessageListInit()
if (!messageListLoad(&gInventoryMessageList, path))
return -1;
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_INVENTORY, &gInventoryMessageList);
return 0;
}
@@ -945,7 +944,6 @@ static int inventoryMessageListInit()
// 0x46E7A0
static int inventoryMessageListFree()
{
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_INVENTORY, nullptr);
messageListFree(&gInventoryMessageList);
return 0;
}
@@ -3645,6 +3643,7 @@ int inventoryUnequipFunc(Object* critter, int hand, bool animate)
{
int activeHand;
Object* item;
int fid;
if (critter == gDude) {
activeHand = interfaceGetCurrentHand();
@@ -3679,13 +3678,13 @@ int inventoryUnequipFunc(Object* critter, int hand, bool animate)
animationRegisterAnimate(critter, ANIM_PUT_AWAY, 0);
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
animationRegisterSetFid(critter, fid, -1);
return reg_anim_end();
}
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
_dude_stand(critter, critter->rotation, fid);
}
@@ -6345,138 +6344,4 @@ Object* inventoryGetTargetObject()
return _target_stack[_target_curr_stack];
}
int inventoryUnwieldSlot(Object* critter, InvenSlot slot)
{
if (critter == nullptr) {
return -1;
}
bool isDude = critter == gDude;
bool uiModeActive = GameMode::isInGameMode(GameMode::kInventory)
|| GameMode::isInGameMode(GameMode::kUseOn)
|| GameMode::isInGameMode(GameMode::kLoot)
|| GameMode::isInGameMode(GameMode::kBarter);
bool update = false;
if (slot != InvenSlot::Armor && !uiModeActive) {
int rc = inventoryUnequipFunc(critter, slot == InvenSlot::LeftHand ? HAND_LEFT : HAND_RIGHT, false);
if (rc == 0) {
update = isDude;
}
if (update) {
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
}
return rc;
}
bool forceAdd = false;
Object* item = nullptr;
Object** itemSlot = nullptr;
if (slot != InvenSlot::Armor) {
if (!isDude || critter != _inven_dude) {
return 0;
}
if (slot == InvenSlot::RightHand) {
item = gInventoryRightHandItem;
itemSlot = &gInventoryRightHandItem;
} else {
item = gInventoryLeftHandItem;
itemSlot = &gInventoryLeftHandItem;
}
if (item != nullptr) {
if (!scriptHooks_InvenWield(critter, item, slot, 0, 0, false)) {
return -1;
}
int oldFlags = item->flags;
bool clearBothHandSlots = gInventoryLeftHandItem == item && gInventoryRightHandItem == item;
if (clearBothHandSlots) {
gInventoryLeftHandItem = nullptr;
gInventoryRightHandItem = nullptr;
} else {
*itemSlot = nullptr;
}
item->flags &= ~OBJECT_IN_ANY_HAND;
if (itemAdd(critter, item, 1) != 0) {
// item will be in an invalid state, but this can only happen on malloc failure
return -1;
}
update = true;
}
} else {
if (isDude && critter == _inven_dude) {
item = gInventoryArmor;
}
if (item == nullptr) {
item = critterGetArmor(critter);
} else {
gInventoryArmor = nullptr;
forceAdd = true;
}
if (item != nullptr) {
item->flags &= ~OBJECT_WORN;
if (correctFidForRemovedItem(critter, item, OBJECT_WORN) != 0) {
if (forceAdd) {
gInventoryArmor = item;
item->flags |= OBJECT_WORN;
}
return -1;
}
if (forceAdd && itemAdd(critter, item, 1) != 0) {
// improper cleanup, but this can only happen on malloc failure
return -1;
}
if (isDude) {
interfaceRenderArmorClass(false);
}
}
}
if (!uiModeActive) {
return 0;
}
InventoryWindowType inventoryWindowType = INVENTORY_WINDOW_TYPE_NORMAL;
if (GameMode::isInGameMode(GameMode::kBarter)) {
inventoryWindowType = INVENTORY_WINDOW_TYPE_TRADE;
} else if (GameMode::isInGameMode(GameMode::kLoot)) {
inventoryWindowType = INVENTORY_WINDOW_TYPE_LOOT;
} else if (GameMode::isInGameMode(GameMode::kUseOn)) {
inventoryWindowType = INVENTORY_WINDOW_TYPE_USE_ITEM_ON;
}
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_NORMAL) {
inventoryRenderSummary();
}
int targetFid = -1;
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT
|| inventoryWindowType == INVENTORY_WINDOW_TYPE_TRADE) {
targetFid = _target_stack[_target_curr_stack]->fid;
_display_target_inventory(_target_stack_offset[_target_curr_stack], -1, _target_pud, inventoryWindowType);
}
_adjust_fid();
_display_inventory(_stack_offset[_curr_stack], -1, inventoryWindowType);
_display_body(targetFid, inventoryWindowType);
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_TRADE) {
barterDisplayTables(gInventoryBarterBackgroundWindow, gPlayerTableObj, gBartererTableObj, -1);
}
if (update) {
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
}
return 0;
}
} // namespace fallout

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