mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e3e94ffd9 | ||
|
|
25e006cffd | ||
|
|
3edd00d85f | ||
|
|
2bfa10411c | ||
|
|
a9eddc1705 | ||
|
|
26d7b632fc | ||
|
|
c6818f0849 | ||
|
|
84cac43da1 | ||
|
|
261b54c603 | ||
|
|
46b89abbd8 | ||
|
|
1ee64988bc | ||
|
|
c78ba885d7 | ||
|
|
8c98a15ef6 |
@@ -614,8 +614,6 @@ 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"
|
||||
|
||||
@@ -81,12 +81,14 @@ 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 | âś… except get_ini_config, get_ini_config_db | `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 | âś… | `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 | - |
|
||||
| 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. |
|
||||
| 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. |
|
||||
|
||||
## Hooks
|
||||
|
||||
@@ -104,8 +106,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` | âś… | - |
|
||||
| MoveCost | `HOOK_MOVECOST` | đźš« | - |
|
||||
| ItemDamage | `HOOK_ITEMDAMAGE` | đźš« | - |
|
||||
| ItemDamage | `HOOK_ITEMDAMAGE` | âś… | - |
|
||||
| MoveCost | `HOOK_MOVECOST` | âś… | - |
|
||||
| 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` | âś… | - |
|
||||
|
||||
@@ -65,6 +65,12 @@ 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
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#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
|
||||
@@ -0,0 +1,98 @@
|
||||
#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
|
||||
@@ -0,0 +1,70 @@
|
||||
#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
|
||||
@@ -0,0 +1,7 @@
|
||||
[ValidSection]
|
||||
ValidKey=ValidValue
|
||||
Key2=2
|
||||
|
||||
[Section2]
|
||||
Key1=AA
|
||||
Key2=BB
|
||||
@@ -0,0 +1,2 @@
|
||||
A test mod for sfall scripting features testing.
|
||||
Add it to your mods_order.txt
|
||||
@@ -0,0 +1 @@
|
||||
Put compiled scripts in here
|
||||
@@ -367,12 +367,6 @@ 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)
|
||||
{
|
||||
|
||||
@@ -123,7 +123,6 @@ 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);
|
||||
|
||||
+30
-7
@@ -112,6 +112,8 @@ typedef enum EditorFolder {
|
||||
EDITOR_FOLDER_KILLS,
|
||||
} EditorFolder;
|
||||
|
||||
static void characterEditorMessageListReset();
|
||||
|
||||
enum {
|
||||
EDITOR_DERIVED_STAT_ARMOR_CLASS,
|
||||
EDITOR_DERIVED_STAT_ACTION_POINTS,
|
||||
@@ -587,6 +589,12 @@ 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];
|
||||
|
||||
@@ -1284,18 +1292,35 @@ 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)) {
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
characterEditorMessageListReset();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1318,11 +1343,9 @@ static int characterEditorWindowInit()
|
||||
while (--i >= 0) {
|
||||
_editorFrmImages[i].unlock();
|
||||
}
|
||||
return -1;
|
||||
|
||||
_editorBackgroundFrmImage.unlock();
|
||||
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
characterEditorMessageListReset();
|
||||
|
||||
if (gCharacterEditorIsoWasEnabled) {
|
||||
isoEnable();
|
||||
@@ -1360,7 +1383,7 @@ static int characterEditorWindowInit()
|
||||
|
||||
_editorBackgroundFrmImage.unlock();
|
||||
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
characterEditorMessageListReset();
|
||||
if (gCharacterEditorIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
@@ -1389,7 +1412,7 @@ static int characterEditorWindowInit()
|
||||
|
||||
_editorBackgroundFrmImage.unlock();
|
||||
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
characterEditorMessageListReset();
|
||||
if (gCharacterEditorIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
@@ -1869,7 +1892,7 @@ static void characterEditorWindowFree()
|
||||
// SFALL: Custom town reputation.
|
||||
customTownReputationFree();
|
||||
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
characterEditorMessageListReset();
|
||||
|
||||
interfaceBarRefresh();
|
||||
|
||||
|
||||
+6
-3
@@ -1359,13 +1359,16 @@ 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) {
|
||||
return 8 * distance;
|
||||
actionPoints = 8 * distance;
|
||||
} else if ((flags & DAM_CRIP_LEG_ANY) != 0) {
|
||||
return 4 * distance;
|
||||
actionPoints = 4 * distance;
|
||||
} else {
|
||||
return distance;
|
||||
actionPoints = distance;
|
||||
}
|
||||
|
||||
return scriptHooks_MoveCost(critter, distance, actionPoints);
|
||||
}
|
||||
|
||||
// 0x42E66C critterIsOverloaded
|
||||
|
||||
@@ -144,30 +144,6 @@ 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, ...)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@ 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);
|
||||
@@ -112,10 +111,6 @@ 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 */
|
||||
|
||||
@@ -448,6 +448,7 @@ void gameReset()
|
||||
scriptHooksReset();
|
||||
sfallArraysReset();
|
||||
sfall_gl_scr_reset();
|
||||
sfall_ini_cache_clear();
|
||||
sfallOnGameReset();
|
||||
gGameLoaded = false;
|
||||
}
|
||||
|
||||
+12
-1
@@ -86,6 +86,8 @@ 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,
|
||||
@@ -583,6 +585,12 @@ 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;
|
||||
|
||||
@@ -3966,10 +3974,12 @@ 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;
|
||||
}
|
||||
|
||||
@@ -4081,6 +4091,7 @@ int partyMemberCustomizationWindowInit()
|
||||
void partyMemberCustomizationWindowFree()
|
||||
{
|
||||
if (gGameDialogWindow == -1) {
|
||||
partyMemberCustomizationMessageListReset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4118,7 +4129,7 @@ void partyMemberCustomizationWindowFree()
|
||||
windowDestroy(gGameDialogWindow);
|
||||
gGameDialogWindow = -1;
|
||||
|
||||
messageListFree(&gCustomMessageList);
|
||||
partyMemberCustomizationMessageListReset();
|
||||
}
|
||||
|
||||
// 0x449B3C
|
||||
|
||||
@@ -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);
|
||||
static int _correctFidForRemovedItem(Object* critter, Object* item, int flags);
|
||||
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
|
||||
static int _correctFidForRemovedItem(Object* critter, Object* item, int flags)
|
||||
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);
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
#define INTERPRETER_EXTRA_H
|
||||
|
||||
#include "interpreter.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
enum class InvenSlot {
|
||||
enum class InvenSlot : int {
|
||||
Armor = 0, // INVEN_TYPE_WORN
|
||||
RightHand = 1, // INVEN_TYPE_RIGHT_HAND
|
||||
LeftHand = 2, // INVEN_TYPE_LEFT_HAND
|
||||
@@ -13,6 +14,8 @@ enum class InvenSlot {
|
||||
|
||||
constexpr int kInvenSlotInvCount = -2;
|
||||
|
||||
int correctFidForRemovedItem(Object* critter, Object* item, int flags);
|
||||
|
||||
void _intExtraClose_();
|
||||
void _initIntExtra();
|
||||
void intExtraUpdate();
|
||||
|
||||
+138
-3
@@ -937,6 +937,7 @@ static int inventoryMessageListInit()
|
||||
if (!messageListLoad(&gInventoryMessageList, path))
|
||||
return -1;
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_INVENTORY, &gInventoryMessageList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -944,6 +945,7 @@ static int inventoryMessageListInit()
|
||||
// 0x46E7A0
|
||||
static int inventoryMessageListFree()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_INVENTORY, nullptr);
|
||||
messageListFree(&gInventoryMessageList);
|
||||
return 0;
|
||||
}
|
||||
@@ -3643,7 +3645,6 @@ int inventoryUnequipFunc(Object* critter, int hand, bool animate)
|
||||
{
|
||||
int activeHand;
|
||||
Object* item;
|
||||
int fid;
|
||||
|
||||
if (critter == gDude) {
|
||||
activeHand = interfaceGetCurrentHand();
|
||||
@@ -3678,13 +3679,13 @@ int inventoryUnequipFunc(Object* critter, int hand, bool animate)
|
||||
|
||||
animationRegisterAnimate(critter, ANIM_PUT_AWAY, 0);
|
||||
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
|
||||
animationRegisterSetFid(critter, fid, -1);
|
||||
|
||||
return reg_anim_end();
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1);
|
||||
_dude_stand(critter, critter->rotation, fid);
|
||||
}
|
||||
|
||||
@@ -6344,4 +6345,138 @@ 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
Reference in New Issue
Block a user