Add a Cheats menu tab with engine cheat buttons and unlimited-resource switches
build / build (push) Successful in 3m42s
build / build (push) Successful in 3m42s
The new Cheats tab exposes the engine's own cheat handlers as buttons: give all items and weapons, toggle physics, next level and previous level. Physics shows its state through the button highlight. The buttons need a running game and show a message otherwise. It also has four independent session-only switches for unlimited health, energy, ammo and items (grenades and drugs). While a switch is on, its resource is topped up every frame by qs_cheat_refill() from the new engine patch 26. The switches are not saved to the config.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user