mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9a5aeff9a | ||
|
|
bf55a6fbb1 | ||
|
|
9764e2911d | ||
|
|
5d5bb78087 | ||
|
|
6f0f68d5aa | ||
|
|
141c67575f | ||
|
|
a7a7f0b63c |
@@ -17,15 +17,5 @@
|
||||
|
||||
- *Preview builds are not available for pull requests from forked repositories.* To enable preview builds, submit the PR from a branch within this repository.
|
||||
|
||||
- *Formatting issues? You have two options:*
|
||||
1. **Fix formatting automatically** using the following Docker command: *(If you're using Windows, remove `--user $(id -u):$(id -g)`)*
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v $(pwd):/app --workdir /app \
|
||||
--user $(id -u):$(id -g) silkeh/clang:18 \
|
||||
bash -c 'find src -type f -name \*.cc -o -name \*.h | xargs clang-format -i'
|
||||
```
|
||||
2. **Skip formatting check** by adding the `skip-formatting` label to this PR.
|
||||
|
||||
--->
|
||||
|
||||
|
||||
+10
-8
@@ -16,7 +16,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| Skills | get/set_critter_skill_points<br>get/set_available_skill_points<br>set_skill_max<br>set_critter_skill_mod<br>set_base_skill_mod<br>mod_skill_points_per_level | not implemented | - |
|
||||
| Graphics | graphics_funcs_available<br>force_graphics_refresh<br>get_screen_width<br>get_screen_height<br>set_palette | implemented: only get_screen_width, get_screen_height | - |
|
||||
| Shaders | load_shader<br>free_shader<br>activate_shader<br>deactivate_shader<br>set/get_shader_* | đźš« | likely will not implement direct compatibility
|
||||
| Perks and traits | set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>set_fake_perk<br>set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>hide_real_perks<br>show_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>has_fake_perk<br>has_fake_trait<br>add_trait<br>remove_trait<br>seq_perk_freq | not implemented | - |
|
||||
| Perks and traits | get_perk_owed<br>set_perk_owed<br>set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | implemented: only get_perk_owed, set_perk_owed | - |
|
||||
| Virtual file system | fs_create<br>fs_copy<br>fs_find<br>fs_read/write_*<br>fs_delete<br>fs_size<br>fs_pos<br>fs_seek<br>fs_resize | đźš« | Open an issue if you have a use case for these |
|
||||
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
|
||||
| Maps and encounters | in_world_map<br>force_encounter<br>force_encounter_with_flags<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
|
||||
@@ -27,7 +27,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| Utility / Math | log, exponent, round, sqrt, abs, sin, cos, tan, arctan, ceil, ^, floor2, div | âś… | - |
|
||||
| Keyboard and mouse | key_pressed<br>tap_key<br>get_mouse_x/y<br>get_mouse_buttons | âś… | - |
|
||||
| Lists | list_begin<br>list_next<br>list_end<br>list_as_array<br>party_member_list | âś… | - |
|
||||
| Explosions | metarule2_explosions<br>set_attack_explosion_pattern<br>set_attack_explosion_art<br>set_attack_explosion_radius<br>set_attack_is_explosion_fire<br>set_explosion_radius<br>set_dynamite_damage<br>set_plastic_damage<br>get_explosion_damage<br>set_explosion_max_targets<br>item_make_explosive | âś… except item_make_explosive | - |
|
||||
| Explosions | set_attack_explosion_pattern<br>set_attack_explosion_art<br>set_attack_explosion_radius<br>set_attack_is_explosion_fire<br>set_explosion_radius<br>set_dynamite_damage<br>set_plastic_damage<br>get_explosion_damage<br>set_explosion_max_targets<br>item_make_explosive | âś… except item_make_explosive | - |
|
||||
| Animations | reg_anim_combat_check<br>reg_anim_destroy<br>reg_anim_animate_and_hide<br>reg_anim_light<br>reg_anim_change_fid<br>reg_anim_take_out<br>reg_anim_turn_towards<br>reg_anim_callback<br>reg_anim_animate_and_move | âś… except reg_anim_callback | - |
|
||||
| Art and appearance | art_exists<br>refresh_pc_art<br>art_cache_clear<br>set_hero_race<br>set_hero_style | implemented: art_exists, refresh_pc_art, art_cache_clear | - |
|
||||
| Tiles and paths | get_tile_fid<br>tile_under_cursor<br>tile_light<br>tile_get_objs<br>tile_refresh_display<br>obj_blocking_tile<br>tile_by_position<br>get_tile_ground_fid<br>get_tile_roof_fid<br>obj_blocking_line<br>path_find_to<br>objects_in_radius | âś… except objects_in_radius | - |
|
||||
@@ -38,19 +38,21 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| Hooks / Hook functions | init_hook<br>get_sfall_arg<br>get_sfall_args<br>get_sfall_arg_at<br>set_sfall_return<br>set_sfall_arg<br>register_hook<br>register_hook_proc<br>register_hook_proc_spec | âś… | See below for implemented hooks. `init_hook` is deprecated and will not be implemented. register_hook_proc and register_hook_proc_spec both add hooks to the *end* of the hook list, instead of beginning and end, respectively. |
|
||||
| Arrays / Array functions | create_array<br>temp_array<br>fix_array<br>get/set_array<br>resize_array<br>free_array<br>scan_array<br>len_array<br>save/load_array<br>array_key<br>arrayexpr | âś… except save_array, load_array | - |
|
||||
| Perks and traits / NPC perks | set_fake_perk_npc<br>set_fake_trait_npc<br>set_selectable_perk_npc<br>has_fake_perk_npc<br>has_fake_trait_npc | not implemented | - |
|
||||
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | implemented: all except available_global_script_types | - |
|
||||
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | âś… except available_global_script_types | - |
|
||||
| Combat | attack_is_aimed<br>block_combat<br>force_aimed_shots<br>disable_aimed_shots<br>get_attack_type<br>get/set_bodypart_hit_modifier<br>combat_data<br>get/set/reset_critical_table<br>get_last_target<br>get_last_attacker<br>set_critter_burst_disable<br>get/set_critter_current_ap<br>set_spray_settings<br>get/set_combat_free_move | implemented: only get_attack_type, get_bodypart_hit_modifier, combat_data, set_bodypart_hit_modifier | - |
|
||||
| Car | set_car_current_town<br>car_gas_amount<br>set_car_intface_art | implemented: all except set_car_intface_art | - |
|
||||
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window | implemented: only message_box, get_text_width, show_window | - |
|
||||
| Interface / Outline | outlined_object<br>get_outline<br>set_outline | implemented: all except get_outline | - |
|
||||
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window<br>create_message_window | implemented: only message_box, get_text_width, show_window, create_message_window | - |
|
||||
| Interface / Outline | outlined_object<br>get_outline<br>set_outline | âś… except get_outline | - |
|
||||
| Interface / Main interface | intface_is_hidden<br>intface_redraw<br>intface_hide<br>intface_show<br>set_quest_failure_value | implemented: only intface_redraw | `intface_redraw` only supports the zero-argument form; the optional-argument path is explicitly unimplemented. |
|
||||
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | implemented: only critter_inven_obj2 | - |
|
||||
| Interface / Cursor | get/set_cursor_mode | âś… | - |
|
||||
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
|
||||
| INI settings | modified_ini<br>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 modified_ini, 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 | âś… 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>set_script<br>get_script<br>obj_is_carrying_obj<br>loot_obj<br>dialog_obj<br>obj_under_cursor<br>get_object_data<br>set_object_data<br>get_flags<br>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_script, obj_is_carrying_obj, loot_obj, dialog_obj, obj_under_cursor, get_object_data, get_flags, set_flags, get_proto_data, set_proto_data | - |
|
||||
| Other / Game management | set_movie_path<br>stop_game<br>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 | - |
|
||||
| Other | input_funcs_available<br>get_year<br>set_dm_model<br>set_df_model<br>set_pipboy_available<br>get_kill_counter<br>mod_kill_counter<br>active_hand<br>toggle_active_hand<br>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>inc_npc_level<br>get_npc_level<br>get/set_viewport_x/y<br>set_hp_per_level_mod<br>get/set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>hero_select_win<br>create_message_window<br>get_light_level<br>gdialog_get_barter_mod<br>set_inven_ap_cost<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>message_str_game<br>sneak_success<br>create_spatial<br>unwield_slot<br>get_inven_ap_cost<br>add_g_timer_event<br>add_extra_msg_file<br>get_metarule_table<br>metarule_exist<br>npc_engine_level_up<br>remove_timer_event<br>set_drugs_data<br>spatial_radius | implemented: get_year, active_hand, toggle_active_hand, create_message_window, 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. |
|
||||
| Other / Game management | set_movie_path<br>stop_game<br>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>get_unspent_ap_bonus<br>gdialog_get_barter_mod<br>set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>set_inven_ap_cost<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>get_inven_ap_cost<br>set_drugs_data<br>get_kill_counter<br>mod_kill_counter<br>set_pipboy_available | not implemented | - |
|
||||
| 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, 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
|
||||
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
#include "test_utils.h"
|
||||
#include "sfall.h"
|
||||
#include "dik.h"
|
||||
|
||||
variable signal_close_game_test_done := false;
|
||||
|
||||
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 return;
|
||||
|
||||
if (signal_close_game_test_done) then begin
|
||||
display_msg("signal_close_game test already triggered");
|
||||
return;
|
||||
end
|
||||
|
||||
signal_close_game_test_done := true;
|
||||
display_msg("signal_close_game test triggered");
|
||||
signal_close_game;
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
// TODO: move this to a more suitable place, once we have more functions implemented
|
||||
@@ -10,6 +30,8 @@ procedure start begin
|
||||
call assertEquals("active_hand toggled", active_hand, 1 - hand);
|
||||
toggle_active_hand;
|
||||
call assertEquals("active_hand toggled", active_hand, hand);
|
||||
|
||||
|
||||
call report_test_results("misc");
|
||||
display_msg("signal_close_game manual test ready: press J");
|
||||
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
|
||||
end
|
||||
|
||||
+1
-1
@@ -3063,7 +3063,7 @@ void _dude_fidget()
|
||||
// 0x56C7E0
|
||||
static Object* candidates[100];
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -475,7 +475,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+159
-39
@@ -37,6 +37,7 @@
|
||||
#include "platform_compat.h"
|
||||
#include "proto.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
@@ -144,6 +145,11 @@ enum {
|
||||
EDITOR_BUTTONS_COUNT = EDITOR_FIRST_TRAIT + TRAIT_COUNT,
|
||||
};
|
||||
|
||||
static constexpr int kMaxPerkOwed = 250;
|
||||
// nb. this is number of perks, not total perk ranks. This only prevents level ups from granting more perks.
|
||||
static constexpr int kMaxSelectablePerks = 37;
|
||||
static constexpr int kPrimaryStatDescriptionWidth = 100;
|
||||
|
||||
enum {
|
||||
EDITOR_GRAPHIC_BIG_NUMBERS,
|
||||
EDITOR_GRAPHIC_AGE_MASK,
|
||||
@@ -282,6 +288,8 @@ static int perkDialogDrawTraits(int a1);
|
||||
static int perkDialogOptionCompare(const void* a1, const void* a2);
|
||||
static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description);
|
||||
static void _pop_perks();
|
||||
static int characterEditorGetLevelsPerPerk();
|
||||
static void characterEditorGrantPerkAtLevel(int level);
|
||||
static int _is_supper_bonus();
|
||||
static int characterEditorFolderViewInit();
|
||||
static void characterEditorFolderViewScroll(int direction);
|
||||
@@ -769,7 +777,7 @@ static int gCharacterEditorTaggedSkillCount;
|
||||
static int gCharacterEditorTempTaggedSkills[NUM_TAGGED_SKILLS];
|
||||
|
||||
// 0x570A28
|
||||
static char gCharacterEditorHasFreePerkBackup;
|
||||
static unsigned char gCharacterEditorHasFreePerkBackup;
|
||||
|
||||
// 0x570A29
|
||||
static unsigned char gCharacterEditorHasFreePerk;
|
||||
@@ -919,7 +927,7 @@ int characterEditorShow(bool isCreationMode)
|
||||
} else if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
|
||||
showQuitConfirmationDialog();
|
||||
windowRefresh(gCharacterEditorWindow);
|
||||
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || keyCode == KEY_UPPERCASE_C || keyCode == KEY_LOWERCASE_C || _game_user_wants_to_quit != 0) {
|
||||
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || keyCode == KEY_UPPERCASE_C || keyCode == KEY_LOWERCASE_C || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
windowRefresh(gCharacterEditorWindow);
|
||||
rc = 1;
|
||||
} else if (gCharacterEditorIsCreationMode && (keyCode == 517 || keyCode == KEY_UPPERCASE_N || keyCode == KEY_LOWERCASE_N)) {
|
||||
@@ -1950,7 +1958,7 @@ static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength,
|
||||
} else if (keyCode == KEY_RETURN) {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
rc = 0;
|
||||
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
||||
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = -1;
|
||||
} else {
|
||||
if ((keyCode == KEY_DELETE || keyCode == KEY_BACKSPACE) && nameLength >= 1) {
|
||||
@@ -2474,7 +2482,7 @@ static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousV
|
||||
|
||||
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], flags, value, previousValue, gCharacterEditorWindow);
|
||||
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, kPrimaryStatDescriptionWidth, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
|
||||
messageListItemId = critterGetStat(gDude, stat) + 199;
|
||||
if (messageListItemId > 210) {
|
||||
@@ -2486,7 +2494,7 @@ static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousV
|
||||
} else {
|
||||
value = critterGetStat(gDude, stat);
|
||||
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], 0, value, 0, gCharacterEditorWindow);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, kPrimaryStatDescriptionWidth, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
|
||||
value = critterGetStat(gDude, stat);
|
||||
if (value > 10) {
|
||||
@@ -3435,7 +3443,7 @@ static int characterEditorEditAge()
|
||||
|
||||
windowDestroy(win);
|
||||
return 0;
|
||||
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
||||
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
} else if (keyCode == 501) {
|
||||
age = critterGetStat(gDude, STAT_AGE);
|
||||
@@ -3535,7 +3543,7 @@ static int characterEditorEditAge()
|
||||
}
|
||||
|
||||
keyCode = inputGetInput();
|
||||
if (keyCode == 503 || keyCode == 504 || _game_user_wants_to_quit != 0) {
|
||||
if (keyCode == 503 || keyCode == 504 || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3667,7 +3675,7 @@ static void characterEditorEditGender()
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
||||
if (eventCode == KEY_ESCAPE || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
critterSetBaseStat(gDude, STAT_GENDER, savedGender);
|
||||
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
||||
characterEditorDrawDerivedStats();
|
||||
@@ -3891,7 +3899,7 @@ static int characterEditorShowOptions()
|
||||
|
||||
int keyCode = inputGetInput();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 2;
|
||||
} else if (keyCode == 504) {
|
||||
rc = 2;
|
||||
@@ -5668,11 +5676,117 @@ int characterEditorLoad(File* stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int characterEditorGetPerkOwed()
|
||||
{
|
||||
return gCharacterEditorHasFreePerk;
|
||||
}
|
||||
|
||||
void characterEditorSetPerkOwed(int value)
|
||||
{
|
||||
unsigned int maskedValue = static_cast<unsigned int>(value) & 0xFF;
|
||||
if (maskedValue <= kMaxPerkOwed) {
|
||||
gCharacterEditorHasFreePerk = maskedValue;
|
||||
}
|
||||
}
|
||||
|
||||
// External interface: called when level up occurs
|
||||
void characterEditorHandleLevelUp(int level)
|
||||
{
|
||||
characterEditorGrantPerkAtLevel(level);
|
||||
}
|
||||
|
||||
// compute the character level that the next perk selection should use
|
||||
int characterEditorGetPerkSelectionLevel()
|
||||
{
|
||||
int currentLevel = pcGetStat(PC_STAT_LEVEL);
|
||||
if (settings.gameplay.perk_carryover != PERK_CARRY_OVER_MODE_ON) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
int owed = characterEditorGetPerkOwed();
|
||||
if (owed <= 1) {
|
||||
// If a single perk is owed, use the current level. This prevents odd effects in
|
||||
// saves where perks have been skipped and is a general safe fallback.
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
int levelsPerPerk = characterEditorGetLevelsPerPerk();
|
||||
|
||||
// This therefore uses the number of perk thresholds strictly before the
|
||||
// current level, then compares that against the total perk ranks already
|
||||
// spent. In the common non-scripted case:
|
||||
// - level 6 with 0 spent perks yields one deferred threshold (level 3)
|
||||
// - after spending one perk, there is no older backlog left, so the next
|
||||
// owed perk uses level 6 requirements
|
||||
// - level 9 with 2 spent perks has no older backlog, so owed perks are
|
||||
// immediately spendable at level 9
|
||||
int previousThresholdsReached = (currentLevel - 1) / levelsPerPerk;
|
||||
int spentPerks = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
spentPerks += perkGetRank(gDude, perk);
|
||||
}
|
||||
|
||||
// This is a heuristic for the 99.9% case where perk ranks come from normal
|
||||
// perk picks. If enough perk ranks have already been spent to cover all
|
||||
// earlier thresholds, there is no deferred backlog to force in order.
|
||||
if (spentPerks >= previousThresholdsReached) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
// The next deferred pick corresponds to the earliest previously missed
|
||||
// threshold after the already-spent perk ranks.
|
||||
int thresholdIndex = spentPerks + 1;
|
||||
int selectionLevel = std::max(3, thresholdIndex * levelsPerPerk);
|
||||
if (selectionLevel <= 0 || selectionLevel > currentLevel) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
return selectionLevel;
|
||||
}
|
||||
|
||||
// 0x43C20C
|
||||
void characterEditorReset()
|
||||
{
|
||||
gCharacterEditorRemainingCharacterPoints = 5;
|
||||
gCharacterEditorLastLevel = 1;
|
||||
characterEditorSetPerkOwed(0);
|
||||
}
|
||||
|
||||
static int characterEditorGetLevelsPerPerk()
|
||||
{
|
||||
int progression = 3;
|
||||
if (traitIsSelected(TRAIT_SKILLED)) {
|
||||
progression += 1;
|
||||
}
|
||||
|
||||
return progression;
|
||||
}
|
||||
|
||||
static void characterEditorGrantPerkAtLevel(int level)
|
||||
{
|
||||
if (level <= 0 || level % characterEditorGetLevelsPerPerk() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int selectedPerksCount = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
if (perkGetRank(gDude, perk) != 0) {
|
||||
selectedPerksCount += 1;
|
||||
if (selectedPerksCount >= kMaxSelectablePerks) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (settings.gameplay.perk_carryover) {
|
||||
case PERK_CARRY_OVER_MODE_OFF:
|
||||
characterEditorSetPerkOwed(1);
|
||||
break;
|
||||
case PERK_CARRY_OVER_MODE_ON:
|
||||
case PERK_CARRY_OVER_MODE_SFALL:
|
||||
characterEditorSetPerkOwed(characterEditorGetPerkOwed() + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// level up if needed
|
||||
@@ -5682,6 +5796,13 @@ static int characterEditorUpdateLevel()
|
||||
{
|
||||
int level = pcGetStat(PC_STAT_LEVEL);
|
||||
if (level != gCharacterEditorLastLevel && level <= PC_LEVEL_MAX) {
|
||||
// Runtime level-up now grants perks immediately. However, older saves
|
||||
// may still have last_level behind the real level with no owed perks
|
||||
// recorded, because perk grants used to be deferred until the next
|
||||
// character screen visit. Replay perk grants only for that legacy
|
||||
// catch-up case.
|
||||
bool shouldReplayPerkGrants = characterEditorGetPerkOwed() == 0;
|
||||
|
||||
for (int nextLevel = gCharacterEditorLastLevel + 1; nextLevel <= level; nextLevel++) {
|
||||
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
||||
sp += 5;
|
||||
@@ -5700,30 +5821,13 @@ static int characterEditorUpdateLevel()
|
||||
|
||||
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp);
|
||||
|
||||
int selectedPerksCount = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
if (perkGetRank(gDude, perk) != 0) {
|
||||
selectedPerksCount += 1;
|
||||
if (selectedPerksCount >= 37) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedPerksCount < 37) {
|
||||
int progression = 3;
|
||||
if (traitIsSelected(TRAIT_SKILLED)) {
|
||||
progression += 1;
|
||||
}
|
||||
|
||||
if (nextLevel % progression == 0) {
|
||||
gCharacterEditorHasFreePerk = 1;
|
||||
}
|
||||
if (shouldReplayPerkGrants) {
|
||||
characterEditorGrantPerkAtLevel(nextLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gCharacterEditorHasFreePerk != 0) {
|
||||
while (characterEditorGetPerkOwed() != 0) {
|
||||
characterEditorWindowSelectedFolder = 0;
|
||||
characterEditorDrawFolders();
|
||||
windowRefresh(gCharacterEditorWindow);
|
||||
@@ -5732,11 +5836,15 @@ static int characterEditorUpdateLevel()
|
||||
if (rc == -1) {
|
||||
debugPrint("\n *** Error running perks dialog! ***\n");
|
||||
return -1;
|
||||
} else if (rc == 0) {
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
characterEditorDrawFolders();
|
||||
} else if (rc == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
characterEditorDrawFolders();
|
||||
gCharacterEditorHasFreePerk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5785,6 +5893,10 @@ static int perkDialogShow()
|
||||
gPerkDialogCardFrmId = -1;
|
||||
gPerkDialogCardTitle[0] = '\0';
|
||||
gPerkDialogCardDrawn = false;
|
||||
int previousPerkRanks[PERK_COUNT];
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
previousPerkRanks[perk] = perkGetRank(gDude, perk);
|
||||
}
|
||||
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 86, 0, 0, 0);
|
||||
if (!_perkDialogBackgroundFrmImage.lock(backgroundFid)) {
|
||||
@@ -5910,6 +6022,12 @@ static int perkDialogShow()
|
||||
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 186 + 171, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
||||
|
||||
int count = perkDialogDrawPerks();
|
||||
if (count == 0) {
|
||||
debugPrint("*** No perks available for current owed slot! ***");
|
||||
_perkDialogBackgroundFrmImage.unlock();
|
||||
windowDestroy(gPerkDialogWindow);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Original code is slightly different, but does the same thing.
|
||||
int perk = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value;
|
||||
@@ -5931,7 +6049,8 @@ static int perkDialogShow()
|
||||
int rc = perkDialogHandleInput(count, perkDialogRefreshPerks);
|
||||
|
||||
if (rc == 1) {
|
||||
if (perkAdd(gDude, gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value) == -1) {
|
||||
int selectionLevel = characterEditorGetPerkSelectionLevel();
|
||||
if (perkAddAtLevel(gDude, gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value, selectionLevel) == -1) {
|
||||
debugPrint("\n*** Unable to add perk! ***\n");
|
||||
rc = 2;
|
||||
}
|
||||
@@ -5940,19 +6059,20 @@ static int perkDialogShow()
|
||||
rc &= 1;
|
||||
|
||||
if (rc != 0) {
|
||||
if (perkGetRank(gDude, PERK_TAG) != 0 && gCharacterEditorPerksBackup[PERK_TAG] == 0) {
|
||||
characterEditorSetPerkOwed(characterEditorGetPerkOwed() - 1);
|
||||
if (perkGetRank(gDude, PERK_TAG) != 0 && previousPerkRanks[PERK_TAG] == 0) {
|
||||
if (!perkDialogHandleTagPerk()) {
|
||||
perkRemove(gDude, PERK_TAG);
|
||||
}
|
||||
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && gCharacterEditorPerksBackup[PERK_MUTATE] == 0) {
|
||||
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && previousPerkRanks[PERK_MUTATE] == 0) {
|
||||
if (!perkDialogHandleMutatePerk()) {
|
||||
perkRemove(gDude, PERK_MUTATE);
|
||||
}
|
||||
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != gCharacterEditorPerksBackup[PERK_LIFEGIVER]) {
|
||||
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != previousPerkRanks[PERK_LIFEGIVER]) {
|
||||
int maxHp = critterGetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
||||
critterSetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS, maxHp + 4);
|
||||
critterAdjustHitPoints(gDude, 4);
|
||||
} else if (perkGetRank(gDude, PERK_EDUCATED) != gCharacterEditorPerksBackup[PERK_EDUCATED]) {
|
||||
} else if (perkGetRank(gDude, PERK_EDUCATED) != previousPerkRanks[PERK_EDUCATED]) {
|
||||
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
||||
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp + 2);
|
||||
}
|
||||
@@ -6016,7 +6136,7 @@ static int perkDialogHandleInput(int count, void (*refreshProc)())
|
||||
}
|
||||
gPerkDialogPreviousCurrentLine = gPerkDialogCurrentLine;
|
||||
refreshProc();
|
||||
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
||||
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 2;
|
||||
} else {
|
||||
switch (keyCode) {
|
||||
@@ -6266,7 +6386,7 @@ static int perkDialogDrawPerks()
|
||||
fontSetCurrent(101);
|
||||
|
||||
int perks[PERK_COUNT];
|
||||
int count = perkGetAvailablePerks(gDude, perks);
|
||||
int count = perkGetAvailablePerks(gDude, characterEditorGetPerkSelectionLevel(), perks);
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,16 @@ namespace fallout {
|
||||
|
||||
extern int gCharacterEditorRemainingCharacterPoints;
|
||||
|
||||
enum PerkCarryOverMode {
|
||||
// Unspent perks are lost on level up (vanilla)
|
||||
PERK_CARRY_OVER_MODE_OFF = 0,
|
||||
// Unspent perks are preserved on level up, but you still spend unspent perks at the appropriate levels.
|
||||
// E.g. if you reach level 9 and have never spent any perks, you first choose from the level 3 perks, then 6, then 9. (CE)
|
||||
PERK_CARRY_OVER_MODE_ON = 1,
|
||||
// Unspent perks are preserved on level up, and you can choose to spend them on perks for the current level.
|
||||
PERK_CARRY_OVER_MODE_SFALL = 2,
|
||||
};
|
||||
|
||||
int characterEditorShow(bool isCreationMode);
|
||||
void characterEditorInit();
|
||||
bool _isdoschar(int ch);
|
||||
@@ -14,6 +24,10 @@ char* _strmfe(char* dest, const char* name, const char* ext);
|
||||
int characterEditorSave(File* stream);
|
||||
int characterEditorLoad(File* stream);
|
||||
void characterEditorReset();
|
||||
int characterEditorGetPerkOwed();
|
||||
void characterEditorSetPerkOwed(int value);
|
||||
void characterEditorHandleLevelUp(int level);
|
||||
int characterEditorGetPerkSelectionLevel();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ int characterSelectorOpen()
|
||||
while (!done) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -2762,7 +2762,7 @@ void _combat_update_critter_outline_for_los(Object* critter, bool a2)
|
||||
// 0x421EFC
|
||||
static void _combat_over()
|
||||
{
|
||||
if (_game_user_wants_to_quit == 0) {
|
||||
if (_game_user_wants_to_quit == GAME_QUIT_REQUEST_NONE) {
|
||||
for (int index = 0; index < _list_com; index++) {
|
||||
Object* critter = _combat_list[index];
|
||||
if (critter != gDude) {
|
||||
@@ -2820,7 +2820,7 @@ static void _combat_over()
|
||||
|
||||
interfaceRenderActionPoints(0, 0);
|
||||
|
||||
if (_game_user_wants_to_quit == 0) {
|
||||
if (_game_user_wants_to_quit == GAME_QUIT_REQUEST_NONE) {
|
||||
_combat_give_exps(_combat_exps);
|
||||
}
|
||||
|
||||
@@ -3167,7 +3167,7 @@ static int _combat_input()
|
||||
break;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3205,8 +3205,8 @@ static int _combat_input()
|
||||
}
|
||||
|
||||
int v4 = _game_user_wants_to_quit;
|
||||
if (_game_user_wants_to_quit == 1) {
|
||||
_game_user_wants_to_quit = 0;
|
||||
if (_game_user_wants_to_quit == GAME_QUIT_REQUEST_END_COMBAT) {
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_NONE;
|
||||
}
|
||||
|
||||
if ((gCombatState & COMBAT_STATE_0x08) != 0) {
|
||||
@@ -3214,7 +3214,7 @@ static int _combat_input()
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0 || v4 != 0 || _combat_end_due_to_load != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE || v4 != GAME_QUIT_REQUEST_NONE || _combat_end_due_to_load != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -3273,7 +3273,7 @@ static int _combat_turn(Object* obj, bool reloadedDuringCombat)
|
||||
scriptOverrides = scr->scriptOverrides;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit == 1) {
|
||||
if (_game_user_wants_to_quit == GAME_QUIT_REQUEST_END_COMBAT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -3511,8 +3511,8 @@ void _combat(CombatStartData* csd)
|
||||
|
||||
_combat_end_due_to_load = 0;
|
||||
|
||||
if (_game_user_wants_to_quit == 1) {
|
||||
_game_user_wants_to_quit = 0;
|
||||
if (_game_user_wants_to_quit == GAME_QUIT_REQUEST_END_COMBAT) {
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5669,7 +5669,7 @@ static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hi
|
||||
break;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -912,7 +912,7 @@ void critterKill(Object* critter, int anim, bool refreshRect)
|
||||
|
||||
if (critter == gDude) {
|
||||
endgameSetupDeathEnding(ENDGAME_DEATH_ENDING_REASON_DEATH);
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -547,7 +547,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
}
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
@@ -890,7 +890,7 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
delay_ms(delay - (getTicks() - scrollTick));
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
@@ -1338,7 +1338,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24;
|
||||
delay_ms(delay - (getTicks() - scrollTick));
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
@@ -1372,7 +1372,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
delay_ms(1000 / 24 - (getTicks() - tick));
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -288,7 +288,7 @@ static int endgameEndingHandleContinuePlaying()
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
rc = showDialogBox(messageListItem.text, nullptr, 0, 169, 117, _colorTable[32328], nullptr, _colorTable[32328], DIALOG_BOX_YES_NO);
|
||||
if (rc == 0) {
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
|
||||
+6
-6
@@ -114,7 +114,7 @@ int gGameGlobalVarsLength = 0;
|
||||
const char* asc_5186C8 = _aGame_0;
|
||||
|
||||
// 0x5186CC
|
||||
int _game_user_wants_to_quit = 0;
|
||||
GameQuitRequest _game_user_wants_to_quit = GAME_QUIT_REQUEST_NONE;
|
||||
|
||||
// misc.msg
|
||||
//
|
||||
@@ -445,7 +445,7 @@ void gameReset()
|
||||
_ResetLoadSave();
|
||||
gameDialogReset();
|
||||
combatReset();
|
||||
_game_user_wants_to_quit = 0;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_NONE;
|
||||
automapReset();
|
||||
_init_options_menu();
|
||||
|
||||
@@ -1274,7 +1274,7 @@ static void showHelp()
|
||||
windowShow(overlay);
|
||||
windowShow(win);
|
||||
|
||||
while (inputGetInput() == -1 && _game_user_wants_to_quit == 0) {
|
||||
while (inputGetInput() == -1 && _game_user_wants_to_quit == GAME_QUIT_REQUEST_NONE) {
|
||||
sharedFpsLimiter.mark();
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
@@ -1342,7 +1342,7 @@ int showQuitConfirmationDialog()
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
rc = showDialogBox(messageListItem.text, nullptr, 0, 169, 117, _colorTable[32328], nullptr, _colorTable[32328], DIALOG_BOX_YES_NO);
|
||||
if (rc != 0) {
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
@@ -1579,8 +1579,8 @@ int gameShowDeathDialog(const char* message)
|
||||
int oldCursor = gameMouseGetCursor();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
|
||||
int oldUserWantsToQuit = _game_user_wants_to_quit;
|
||||
_game_user_wants_to_quit = 0;
|
||||
GameQuitRequest oldUserWantsToQuit = _game_user_wants_to_quit;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_NONE;
|
||||
|
||||
int rc = showDialogBox(message, nullptr, 0, 169, 117, _colorTable[32328], nullptr, _colorTable[32328], DIALOG_BOX_LARGE);
|
||||
|
||||
|
||||
+8
-1
@@ -16,10 +16,17 @@ typedef enum GameState {
|
||||
GAME_STATE_5,
|
||||
} GameState;
|
||||
|
||||
typedef enum GameQuitRequest {
|
||||
GAME_QUIT_REQUEST_NONE = 0,
|
||||
GAME_QUIT_REQUEST_END_COMBAT = 1,
|
||||
GAME_QUIT_REQUEST_MAIN_MENU = 2,
|
||||
GAME_QUIT_REQUEST_EXIT = 3,
|
||||
} GameQuitRequest;
|
||||
|
||||
extern int* gGameGlobalVars;
|
||||
extern int gGameGlobalVarsLength;
|
||||
extern const char* asc_5186C8;
|
||||
extern int _game_user_wants_to_quit;
|
||||
extern GameQuitRequest _game_user_wants_to_quit;
|
||||
|
||||
extern MessageList gMiscMessageList;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace fallout {
|
||||
#define GAME_CONFIG_SYSTEM_KEY "system"
|
||||
#define GAME_CONFIG_SCREEN_KEY "screen"
|
||||
#define GAME_CONFIG_UI_KEY "ui"
|
||||
#define GAME_CONFIG_GAMEPLAY_KEY "gameplay"
|
||||
#define GAME_CONFIG_PREFERENCES_KEY "preferences"
|
||||
#define GAME_CONFIG_SOUND_KEY "sound"
|
||||
#define GAME_CONFIG_MAPPER_KEY "mapper"
|
||||
@@ -86,6 +87,7 @@ namespace fallout {
|
||||
#define GAME_CONFIG_SORT_SCRIPT_LIST_KEY "sort_script_list"
|
||||
#define GAME_CONFIG_PLAYER_SPEEDUP_KEY "player_speedup"
|
||||
#define GAME_CONFIG_UI_ANIM_SPEED_KEY "ui_anim_speed"
|
||||
#define GAME_CONFIG_PERK_CARRYOVER_KEY "perk_carryover"
|
||||
|
||||
#define GAME_CONFIG_RESOLUTION_X_KEY "resolution_x"
|
||||
#define GAME_CONFIG_RESOLUTION_Y_KEY "resolution_y"
|
||||
|
||||
+5
-5
@@ -1525,7 +1525,7 @@ int gameDialogShowReview()
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0 || keyCode == KEY_ESCAPE) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE || keyCode == KEY_ESCAPE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1936,7 +1936,7 @@ int gameDialogProcessUI()
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3772,7 +3772,7 @@ void partyMemberControlWindowHandleEvents()
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4022,7 +4022,7 @@ void partyMemberCustomizationWindowHandleEvents()
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4235,7 +4235,7 @@ int _gdCustomSelect(int option)
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1146,7 +1146,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
|
||||
inputGetInput();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
actionMenuItems[actionIndex] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1569,7 +1569,7 @@ static void opPickup(Program* program)
|
||||
int sid = scriptGetSid(program);
|
||||
|
||||
Script* script;
|
||||
if (scriptGetScript(sid, &script) == 1) {
|
||||
if (scriptGetScript(sid, &script) == -1) {
|
||||
scriptPredefinedError(program, "pickup_obj", SCRIPT_ERROR_CANT_MATCH_PROGRAM_TO_SID);
|
||||
return;
|
||||
}
|
||||
@@ -3208,7 +3208,7 @@ static void opMetarule(Program* program)
|
||||
switch (rule) {
|
||||
case METARULE_SIGNAL_END_GAME:
|
||||
result = 0;
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
break;
|
||||
case METARULE_FIRST_RUN:
|
||||
result = (gMapHeader.flags & MAP_SAVED) == 0;
|
||||
@@ -4775,7 +4775,7 @@ static void opCritterSetFleeState(Program* program)
|
||||
static void opTerminateCombat(Program* program)
|
||||
{
|
||||
if (isInCombat()) {
|
||||
_game_user_wants_to_quit = 1;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_END_COMBAT;
|
||||
Object* self = scriptGetSelf(program);
|
||||
if (self != nullptr) {
|
||||
if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) {
|
||||
|
||||
+6
-6
@@ -669,7 +669,7 @@ void inventoryOpen()
|
||||
break;
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2696,7 +2696,7 @@ void inventoryOpenUseItemOn(Object* targetObj)
|
||||
for (;;) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4328,7 +4328,7 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
for (;;) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4342,7 +4342,7 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5212,7 +5212,7 @@ void barterProcessUI(int win, Object* barterer, Object* playerTable, Object* bar
|
||||
for (;;) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
||||
if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5221,7 +5221,7 @@ void barterProcessUI(int win, Object* barterer, Object* playerTable, Object* bar
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -528,7 +528,7 @@ int lsgSaveGame(int mode)
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) {
|
||||
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 0;
|
||||
} else {
|
||||
switch (keyCode) {
|
||||
@@ -659,7 +659,7 @@ int lsgSaveGame(int mode)
|
||||
case KEY_F10:
|
||||
showQuitConfirmationDialog();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
@@ -1057,7 +1057,7 @@ int lsgLoadGame(int mode)
|
||||
|
||||
messageListFree(&gLoadSaveMessageList);
|
||||
mapNewMap();
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1141,7 +1141,7 @@ int lsgLoadGame(int mode)
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) {
|
||||
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 0;
|
||||
} else {
|
||||
switch (keyCode) {
|
||||
@@ -1281,7 +1281,7 @@ int lsgLoadGame(int mode)
|
||||
case KEY_CTRL_X:
|
||||
case KEY_F10:
|
||||
showQuitConfirmationDialog();
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
if (_game_user_wants_to_quit != GAME_QUIT_REQUEST_NONE) {
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
@@ -1462,7 +1462,7 @@ int lsgLoadGame(int mode)
|
||||
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 135));
|
||||
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], nullptr, _colorTable[32328], DIALOG_BOX_LARGE);
|
||||
mapNewMap();
|
||||
_game_user_wants_to_quit = 2;
|
||||
_game_user_wants_to_quit = GAME_QUIT_REQUEST_MAIN_MENU;
|
||||
rc = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user