diff --git a/CONFIG.md b/CONFIG.md index 0511c0e..af40420 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -358,7 +358,7 @@ keyboard (there is no hold behavior). - `keypad 0`-`keypad 9`: a controller button per digit is not useful; use the on-screen keyboard. - `toggle_freelook` (F): the free-view actions cover mouse look. -- The 4 `cheat_*` entries: debug cheats. +- The 4 `cheat_*` entries: debug cheats. They are on the menu's Cheats tab instead. - `mac_help` (disabled) and `audiolog_cancel` (its build flag is not defined): they are not real hotkeys in this build. - `toggle_opengl` (Ctrl+G): the Video Options tab's Renderer buttons already diff --git a/android/app/src/main/cpp/qs_config.c b/android/app/src/main/cpp/qs_config.c index 1519657..799af92 100644 --- a/android/app/src/main/cpp/qs_config.c +++ b/android/app/src/main/cpp/qs_config.c @@ -1250,6 +1250,7 @@ static Uint32 s_begin_control_capture_event_type; static Uint32 s_cancel_control_capture_event_type; static Uint32 s_reset_player_controls_event_type; static Uint32 s_menu_visibility_event_type; +static Uint32 s_cheat_event_type; void qs_config_load_startup(void) { // Registers the custom SDL event types qs_config_request_save()/_load()/ @@ -1260,7 +1261,7 @@ void qs_config_load_startup(void) { // exist yet, rather than lazily from those functions themselves (which // run on Android's UI thread and could otherwise race each other doing // this lazily). - Uint32 base = SDL_RegisterEvents(14); + Uint32 base = SDL_RegisterEvents(15); s_save_event_type = base; s_load_event_type = base + 1; s_set_renderer_event_type = base + 2; @@ -1275,6 +1276,7 @@ void qs_config_load_startup(void) { s_cancel_control_capture_event_type = base + 11; s_reset_player_controls_event_type = base + 12; s_menu_visibility_event_type = base + 13; + s_cheat_event_type = base + 14; QsParsedConfig parsed; bool haveConfig = qs_config_read_file(&parsed); @@ -1407,6 +1409,14 @@ void qs_config_request_cancel_control_capture(void) { SDL_PushEvent(&event); } +void qs_config_request_cheat(int cheat_id) { + SDL_Event event; + SDL_zero(event); + event.type = s_cheat_event_type; + event.user.code = cheat_id; + SDL_PushEvent(&event); +} + void qs_config_notify_menu_visibility(bool visible) { SDL_Event event; SDL_zero(event); @@ -1449,6 +1459,77 @@ static void qs_apply_menu_pause(bool menu_visible) { } } +// hkeyfunc.c - the engine's own cheat hotkey handlers, and the refill added by +// android/engine-patches/26-android-cheat-refill.patch. +extern uchar toggle_giveall_func(ushort keycode, uint32_t context, intptr_t data); +extern uchar toggle_physics_func(ushort keycode, uint32_t context, intptr_t data); +extern uchar toggle_up_level_func(ushort keycode, uint32_t context, intptr_t data); +extern uchar toggle_down_level_func(ushort keycode, uint32_t context, intptr_t data); +extern void qs_cheat_refill(int what); +extern uchar physics_running; + +#define QS_CHEAT_GIVE_ALL 0 +#define QS_CHEAT_PHYSICS 1 +#define QS_CHEAT_LEVEL_UP 2 +#define QS_CHEAT_LEVEL_DOWN 3 +#define QS_CHEAT_UNLIMITED_HEALTH 4 +#define QS_CHEAT_UNLIMITED_ENERGY 5 +#define QS_CHEAT_UNLIMITED_AMMO 6 +#define QS_CHEAT_UNLIMITED_ITEMS 7 + +// Bits of s_cheat_unlimited; the values match qs_cheat_refill() in patch 26. +#define QS_CHEAT_MASK_HEALTH 1 +#define QS_CHEAT_MASK_ENERGY 2 +#define QS_CHEAT_MASK_AMMO 4 +#define QS_CHEAT_MASK_ITEMS 8 + +static int s_cheat_unlimited = 0; + +int qs_config_cheat_unlimited_mask(void) { return s_cheat_unlimited; } +bool qs_config_cheat_physics_running(void) { return physics_running != 0; } + +void qs_config_frame_tick(void) { + if (s_cheat_unlimited && s_screen_profile_is_game) + qs_cheat_refill(s_cheat_unlimited); +} + +static void qs_apply_cheat(int cheat_id) { + if (cheat_id >= QS_CHEAT_UNLIMITED_HEALTH && cheat_id <= QS_CHEAT_UNLIMITED_ITEMS) { + static const struct { + int mask; + const char *on, *off; + } kUnlimited[] = { + {QS_CHEAT_MASK_HEALTH, "Unlimited health on", "Unlimited health off"}, + {QS_CHEAT_MASK_ENERGY, "Unlimited energy on", "Unlimited energy off"}, + {QS_CHEAT_MASK_AMMO, "Unlimited ammo on", "Unlimited ammo off"}, + {QS_CHEAT_MASK_ITEMS, "Unlimited items on", "Unlimited items off"}, + }; + const int i = cheat_id - QS_CHEAT_UNLIMITED_HEALTH; + s_cheat_unlimited ^= kUnlimited[i].mask; + message_info((s_cheat_unlimited & kUnlimited[i].mask) ? kUnlimited[i].on : kUnlimited[i].off); + return; + } + // The engine's own handlers assume a running game (player state, levels). + if (!s_screen_profile_is_game) { + message_info("Cheats need a running game"); + return; + } + switch (cheat_id) { + case QS_CHEAT_GIVE_ALL: + toggle_giveall_func(0, 0, 0); + break; + case QS_CHEAT_PHYSICS: + toggle_physics_func(0, 0, 0); + break; + case QS_CHEAT_LEVEL_UP: + toggle_up_level_func(0, 0, 0); + break; + case QS_CHEAT_LEVEL_DOWN: + toggle_down_level_func(0, 0, 0); + break; + } +} + bool qs_config_handle_event(const SDL_Event *event) { if (event->type == s_save_event_type) { if (qs_config_write_file()) @@ -1531,6 +1612,10 @@ bool qs_config_handle_event(const SDL_Event *event) { xr_input_capture_cancel(); return true; } + if (event->type == s_cheat_event_type) { + qs_apply_cheat(event->user.code); + return true; + } if (event->type == s_menu_visibility_event_type) { qs_apply_menu_pause(event->user.code != 0); return true; diff --git a/android/app/src/main/cpp/qs_config.h b/android/app/src/main/cpp/qs_config.h index 194791e..06f6b7b 100644 --- a/android/app/src/main/cpp/qs_config.h +++ b/android/app/src/main/cpp/qs_config.h @@ -104,6 +104,20 @@ void qs_config_notify_control_capture_result(int action_index, const char *raw_n // engine's thread at pump_events() time. void qs_config_notify_menu_visibility(bool visible); +// Cheats tab (MenuOverlay.java). Same enqueue-only requests as above; the work +// runs on the engine's thread. cheat_id: 0 give everything, 1 toggle physics, +// 2 next level, 3 previous level, 4-7 toggle unlimited health, energy, ammo, +// items (grenades and drugs). Cheats need a running game (the unlimited +// switches can be set anywhere). The getters are plain scalar reads, safe from +// the UI thread; the unlimited mask has bit 0 health, 1 energy, 2 ammo, 3 items. +void qs_config_request_cheat(int cheat_id); +int qs_config_cheat_unlimited_mask(void); +bool qs_config_cheat_physics_running(void); + +// Called once per frame from xr_input.c on the engine's thread; applies the +// unlimited-resource cheats that are switched on. +void qs_config_frame_tick(void); + // Called from xr_input.c's xr_input_suggest_bindings() when the OpenXR runtime // rejects a supported interaction profile's suggested bindings at startup. // That is an app bug, not a config problem, so it shows diff --git a/android/app/src/main/cpp/questshock_native.c b/android/app/src/main/cpp/questshock_native.c index f7afcc3..35dc2b0 100644 --- a/android/app/src/main/cpp/questshock_native.c +++ b/android/app/src/main/cpp/questshock_native.c @@ -270,3 +270,19 @@ Java_de_ladkau_questshock_MenuOverlay_nativeSetControllerOptionsTabOpen(JNIEnv * jboolean open) { xr_input_set_controller_options_tab_open(open == JNI_TRUE); } + +// Cheats tab: same enqueue-only pattern as the other requests. +JNIEXPORT void JNICALL +Java_de_ladkau_questshock_MenuOverlay_nativeRequestCheat(JNIEnv *env, jclass clazz, jint cheatId) { + qs_config_request_cheat(cheatId); +} + +JNIEXPORT jint JNICALL +Java_de_ladkau_questshock_MenuOverlay_nativeGetCheatUnlimitedMask(JNIEnv *env, jclass clazz) { + return qs_config_cheat_unlimited_mask(); +} + +JNIEXPORT jboolean JNICALL +Java_de_ladkau_questshock_MenuOverlay_nativeGetCheatPhysicsRunning(JNIEnv *env, jclass clazz) { + return qs_config_cheat_physics_running(); +} diff --git a/android/app/src/main/cpp/xr_input.c b/android/app/src/main/cpp/xr_input.c index c49ac29..89ca279 100644 --- a/android/app/src/main/cpp/xr_input.c +++ b/android/app/src/main/cpp/xr_input.c @@ -2000,6 +2000,7 @@ void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw) { (menuVisible || freeView[xr_input_raw_input_hand(raw)])) && g_raw_down[raw]; } + qs_config_frame_tick(); xr_input_update_cyber_scales(wantDown); xr_input_apply_free_view(freeView); for (size_t i = 0; i < QS_NUM_KEY_ACTIONS; i++) { diff --git a/android/app/src/main/java/de/ladkau/questshock/MenuOverlay.java b/android/app/src/main/java/de/ladkau/questshock/MenuOverlay.java index ccb125c..9a0780c 100644 --- a/android/app/src/main/java/de/ladkau/questshock/MenuOverlay.java +++ b/android/app/src/main/java/de/ladkau/questshock/MenuOverlay.java @@ -143,14 +143,27 @@ public class MenuOverlay extends OverlayPanel { private TextView statsView; // Content area (tabs) - only one of mainMenuTab/videoOptionsTab/ - // controllerOptionsTab is VISIBLE at a time; currentTab tracks which. + // controllerOptionsTab/cheatsTab is VISIBLE at a time; currentTab tracks which. private View mainMenuTab; private View videoOptionsTab; private View controllerOptionsTab; + private View cheatsTab; private View currentTab; private Button mainMenuTabButton; private Button videoOptionsTabButton; private Button controllerOptionsTabButton; + private Button cheatsTabButton; + + // Cheats tab + private TextView cheatsNoteView; + private Button giveAllButton; + private Button physicsButton; + private Button levelUpButton; + private Button levelDownButton; + private Button unlimitedHealthButton; + private Button unlimitedEnergyButton; + private Button unlimitedAmmoButton; + private Button unlimitedItemsButton; // Main Menu tab's own two states (only one VISIBLE at a time, within // mainMenuTab) - mainMenuContent is the normal state (button row + @@ -251,14 +264,18 @@ public class MenuOverlay extends OverlayPanel { mainMenuTab = buildMainMenuTab(); videoOptionsTab = buildVideoOptionsTab(); controllerOptionsTab = buildControllerOptionsTab(); + cheatsTab = buildCheatsTab(); content.addView(mainMenuTab, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); content.addView(videoOptionsTab, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); content.addView(controllerOptionsTab, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + content.addView(cheatsTab, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); videoOptionsTab.setVisibility(View.GONE); controllerOptionsTab.setVisibility(View.GONE); + cheatsTab.setVisibility(View.GONE); currentTab = mainMenuTab; panel.addView(content, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f)); @@ -923,6 +940,86 @@ public class MenuOverlay extends OverlayPanel { return profile.image; } + // Cheats tab: the engine's own cheat functions as buttons, plus four switches + // for unlimited health, energy, ammo and items. The physics and unlimited + // buttons show their state through the selected highlight. + private static final int CHEAT_GIVE_ALL = 0; + private static final int CHEAT_PHYSICS = 1; + private static final int CHEAT_LEVEL_UP = 2; + private static final int CHEAT_LEVEL_DOWN = 3; + private static final int CHEAT_UNLIMITED_HEALTH = 4; + private static final int CHEAT_UNLIMITED_ENERGY = 5; + private static final int CHEAT_UNLIMITED_AMMO = 6; + private static final int CHEAT_UNLIMITED_ITEMS = 7; + + private View buildCheatsTab() { + LinearLayout tab = new LinearLayout(activity); + tab.setOrientation(LinearLayout.VERTICAL); + tab.setGravity(Gravity.CENTER); + tab.setPadding(24, 16, 24, 16); + + cheatsNoteView = new TextView(activity); + cheatsNoteView.setTextColor(0xFFFFD060); + cheatsNoteView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + cheatsNoteView.setGravity(Gravity.CENTER); + cheatsNoteView.setPadding(0, 0, 0, 16); + cheatsNoteView.setText(Strings.get("cheats_note", currentLanguage)); + tab.addView(cheatsNoteView); + + LinearLayout firstRow = new LinearLayout(activity); + firstRow.setOrientation(LinearLayout.HORIZONTAL); + giveAllButton = addSelectableButton(firstRow, Strings.get("cheat_give_all", currentLanguage), + v -> nativeRequestCheat(CHEAT_GIVE_ALL)); + physicsButton = addSelectableButton(firstRow, Strings.get("cheat_physics", currentLanguage), + v -> { + nativeRequestCheat(CHEAT_PHYSICS); + refreshCheatsSelection(); + }); + tab.addView(firstRow); + + LinearLayout secondRow = new LinearLayout(activity); + secondRow.setOrientation(LinearLayout.HORIZONTAL); + levelUpButton = addSelectableButton(secondRow, Strings.get("cheat_level_up", currentLanguage), + v -> nativeRequestCheat(CHEAT_LEVEL_UP)); + levelDownButton = addSelectableButton(secondRow, Strings.get("cheat_level_down", currentLanguage), + v -> nativeRequestCheat(CHEAT_LEVEL_DOWN)); + tab.addView(secondRow); + + LinearLayout thirdRow = new LinearLayout(activity); + thirdRow.setOrientation(LinearLayout.HORIZONTAL); + unlimitedHealthButton = addSelectableButton(thirdRow, + Strings.get("cheat_unlimited_health", currentLanguage), v -> toggleUnlimited(CHEAT_UNLIMITED_HEALTH)); + unlimitedEnergyButton = addSelectableButton(thirdRow, + Strings.get("cheat_unlimited_energy", currentLanguage), v -> toggleUnlimited(CHEAT_UNLIMITED_ENERGY)); + tab.addView(thirdRow); + + LinearLayout fourthRow = new LinearLayout(activity); + fourthRow.setOrientation(LinearLayout.HORIZONTAL); + unlimitedAmmoButton = addSelectableButton(fourthRow, + Strings.get("cheat_unlimited_ammo", currentLanguage), v -> toggleUnlimited(CHEAT_UNLIMITED_AMMO)); + unlimitedItemsButton = addSelectableButton(fourthRow, + Strings.get("cheat_unlimited_items", currentLanguage), v -> toggleUnlimited(CHEAT_UNLIMITED_ITEMS)); + tab.addView(fourthRow); + + return tab; + } + + // The requests run on the engine's thread a frame later, so the physics + // and unlimited highlights catch up on the next periodic refresh. + private void refreshCheatsSelection() { + physicsButton.setSelected(nativeGetCheatPhysicsRunning()); + int mask = nativeGetCheatUnlimitedMask(); + unlimitedHealthButton.setSelected((mask & 1) != 0); + unlimitedEnergyButton.setSelected((mask & 2) != 0); + unlimitedAmmoButton.setSelected((mask & 4) != 0); + unlimitedItemsButton.setSelected((mask & 8) != 0); + } + + private void toggleUnlimited(int cheatId) { + nativeRequestCheat(cheatId); + refreshCheatsSelection(); + } + private View buildTabBar() { LinearLayout tabBar = new LinearLayout(activity); tabBar.setOrientation(LinearLayout.HORIZONTAL); @@ -969,7 +1066,21 @@ public class MenuOverlay extends OverlayPanel { controllerOptionsTabButton.setOnTouchListener(CLICK_ON_TOUCH_UP); registerHoverable(controllerOptionsTabButton); tabBar.addView(controllerOptionsTabButton, - new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f)); + new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1.3f)); + + View separator3 = new View(activity); + separator3.setBackgroundColor(0xFFFFFFFF); + tabBar.addView(separator3, new LinearLayout.LayoutParams(2, ViewGroup.LayoutParams.MATCH_PARENT)); + + cheatsTabButton = new Button(activity); + cheatsTabButton.setText(Strings.get("cheats", currentLanguage)); + cheatsTabButton.setBackground(selectableButtonBackground()); + cheatsTabButton.setTextColor(buttonTextColors()); + cheatsTabButton.setOnClickListener(v -> switchTab(cheatsTab)); + cheatsTabButton.setOnTouchListener(CLICK_ON_TOUCH_UP); + registerHoverable(cheatsTabButton); + tabBar.addView(cheatsTabButton, + new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 0.7f)); return tabBar; } @@ -992,6 +1103,7 @@ public class MenuOverlay extends OverlayPanel { mainMenuTabButton.setSelected(tab == mainMenuTab); videoOptionsTabButton.setSelected(tab == videoOptionsTab); controllerOptionsTabButton.setSelected(tab == controllerOptionsTab); + cheatsTabButton.setSelected(tab == cheatsTab); nativeSetControllerOptionsTabOpen(tab == controllerOptionsTab); resetHover(); if (tab == videoOptionsTab) { @@ -1007,6 +1119,8 @@ public class MenuOverlay extends OverlayPanel { controllerScrollView.scrollTo(0, 0); controllerScrollBar.setFraction(0f); refreshControllerOptionsSelection(); + } else if (tab == cheatsTab) { + refreshCheatsSelection(); } relayoutAndRedraw(); } @@ -1172,6 +1286,8 @@ public class MenuOverlay extends OverlayPanel { refreshLanguageSelection(); } else if (currentTab == controllerOptionsTab) { refreshControllerOptionsSelection(); + } else if (currentTab == cheatsTab) { + refreshCheatsSelection(); } // The stats text's width changes every tick (digit count, "ms" @@ -1227,6 +1343,16 @@ public class MenuOverlay extends OverlayPanel { gameScreenDistanceLabel.setText(Strings.get("distance", currentLanguage)); controllerOptionsTabButton.setText(Strings.get("controller_options", currentLanguage)); + cheatsTabButton.setText(Strings.get("cheats", currentLanguage)); + cheatsNoteView.setText(Strings.get("cheats_note", currentLanguage)); + giveAllButton.setText(Strings.get("cheat_give_all", currentLanguage)); + physicsButton.setText(Strings.get("cheat_physics", currentLanguage)); + levelUpButton.setText(Strings.get("cheat_level_up", currentLanguage)); + levelDownButton.setText(Strings.get("cheat_level_down", currentLanguage)); + unlimitedHealthButton.setText(Strings.get("cheat_unlimited_health", currentLanguage)); + unlimitedEnergyButton.setText(Strings.get("cheat_unlimited_energy", currentLanguage)); + unlimitedAmmoButton.setText(Strings.get("cheat_unlimited_ammo", currentLanguage)); + unlimitedItemsButton.setText(Strings.get("cheat_unlimited_items", currentLanguage)); controllerGenericNoteView.setText(Strings.get("generic_profile_note", currentLanguage)); controlResetButton.setText(Strings.get("reset_to_defaults", currentLanguage)); for (int i = 0; i < ACTION_KEYS.length; i++) { @@ -1351,6 +1477,12 @@ public class MenuOverlay extends OverlayPanel { // or reassigned - see switchTab(). private static native void nativeSetControllerOptionsTabOpen(boolean open); + // Cheats tab - see qs_config.h. cheatId: 0 give all, 1 toggle physics, 2 next level, + // 3 previous level, 4-7 toggle unlimited health/energy/ammo/items. + private static native void nativeRequestCheat(int cheatId); + private static native int nativeGetCheatUnlimitedMask(); + private static native boolean nativeGetCheatPhysicsRunning(); + // Called from xr_overlay.c's xr_overlay_init_jni(), on the render // thread, right after it resolves this class via the activity's own // ClassLoader (plain FindClass() can't see app classes from a thread diff --git a/android/app/src/main/java/de/ladkau/questshock/Strings.java b/android/app/src/main/java/de/ladkau/questshock/Strings.java index 34bb098..6b80d48 100644 --- a/android/app/src/main/java/de/ladkau/questshock/Strings.java +++ b/android/app/src/main/java/de/ladkau/questshock/Strings.java @@ -119,6 +119,19 @@ final class Strings { put("action_mfd_right_4", "Right MFD: Target", "MFD droit : cible", "Rechtes MFD: Ziel"); put("action_mfd_right_5", "Right MFD: Info", "MFD droit : info", "Rechtes MFD: Info"); put("action_fire_weapon", "Fire Weapon", "Tirer", "Waffe abfeuern"); + // Cheats tab. + put("cheats", "Cheats", "Triches", "Cheats"); + put("cheats_note", "Cheats need a running game.", "Les triches nécessitent une partie en cours.", + "Cheats benötigen ein laufendes Spiel."); + put("cheat_give_all", "Give All Items & Weapons", "Tout obtenir", "Alles erhalten"); + put("cheat_physics", "Physics", "Physique", "Physik"); + put("cheat_level_up", "Next Level", "Niveau suivant", "Nächstes Level"); + put("cheat_level_down", "Previous Level", "Niveau précédent", "Vorheriges Level"); + put("cheat_unlimited_health", "Unlimited Health", "Santé illimitée", "Unbegrenzt Leben"); + put("cheat_unlimited_energy", "Unlimited Energy", "Énergie illimitée", "Unbegrenzt Energie"); + put("cheat_unlimited_ammo", "Unlimited Ammo", "Munitions illimitées", "Unbegrenzt Munition"); + put("cheat_unlimited_items", "Unlimited Items", "Objets illimités", "Unbegrenzt Items"); + put("action_free_left_thumbstick_view", "Free View (Left Stick)", "Vue libre (stick gauche)", "Freie Ansicht (linker Stick)"); put("action_free_right_thumbstick_view", "Free View (Right Stick)", diff --git a/android/engine-patches/26-android-cheat-refill.patch b/android/engine-patches/26-android-cheat-refill.patch new file mode 100644 index 0000000..cca5943 --- /dev/null +++ b/android/engine-patches/26-android-cheat-refill.patch @@ -0,0 +1,74 @@ +--- a/src/GameSrc/hkeyfunc.c ++++ b/src/GameSrc/hkeyfunc.c +@@ -1465,3 +1465,71 @@ + #pragma enable_message(202) + + #endif // NOT_YET ++ ++#ifdef __ANDROID__ ++// Tops up parts of the player's state; android/app/src/main/cpp/qs_config.c ++// calls it once per frame with the "unlimited" cheats that are switched on. ++// `what` is a bitmask: 1 health, 2 energy, 4 ammo, 8 items (the same values as ++// QS_CHEAT_MASK_* in qs_config.c). Only conventional guns use ammo: beam and ++// melee weapons keep heat in the same field, so they are left alone (beams draw ++// on energy). Spare ammo clips, grenades and drugs are only refilled for kinds ++// the player already holds, so the cheat never creates items. ++void qs_cheat_refill(int what) { ++ const int kAmmoFloor = 99; ++ const int kItemFloor = 99; ++ uchar vitalsChanged = FALSE; ++ uchar inventoryChanged = FALSE; ++ ++ if (player_struct.dead) ++ return; ++ if ((what & 1) && player_struct.hit_points < PLAYER_MAX_HP) { ++ player_struct.hit_points = PLAYER_MAX_HP; ++ vitalsChanged = TRUE; ++ } ++ if ((what & 1) && player_struct.cspace_hp < PLAYER_MAX_HP) { ++ player_struct.cspace_hp = PLAYER_MAX_HP; ++ vitalsChanged = TRUE; ++ } ++ if ((what & 2) && player_struct.energy < 255) { ++ player_struct.energy = 255; ++ vitalsChanged = TRUE; ++ } ++ if (vitalsChanged) ++ chg_set_flg(VITALS_UPDATE); ++ ++ if (what & 4) { ++ for (int i = 0; i < NUM_WEAPON_SLOTS; i++) { ++ weapon_slot *slot = &player_struct.weapons[i]; ++ if (slot->type != EMPTY_WEAPON_SLOT && slot->type <= GUN_SUBCLASS_SPECIAL && ++ slot->ammo < kAmmoFloor) { ++ slot->ammo = kAmmoFloor; ++ inventoryChanged = TRUE; ++ } ++ } ++ for (int i = 0; i < NUM_AMMO_TYPES; i++) { ++ if (player_struct.cartridges[i] > 0 && player_struct.cartridges[i] < kItemFloor) { ++ player_struct.cartridges[i] = kItemFloor; ++ inventoryChanged = TRUE; ++ } ++ } ++ } ++ if (what & 8) { ++ for (int i = 0; i < NUM_GRENADEZ; i++) { ++ if (player_struct.grenades[i] > 0 && player_struct.grenades[i] < kItemFloor) { ++ player_struct.grenades[i] = kItemFloor; ++ inventoryChanged = TRUE; ++ } ++ } ++ for (int i = 0; i < NUM_DRUGZ; i++) { ++ if (player_struct.drugs[i] > 0 && player_struct.drugs[i] < kItemFloor) { ++ player_struct.drugs[i] = kItemFloor; ++ inventoryChanged = TRUE; ++ } ++ } ++ } ++ if (inventoryChanged) { ++ chg_set_flg(INVENTORY_UPDATE); ++ mfd_force_update(); ++ } ++} ++#endif