diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj
index 407ce5d8..31c4ff6b 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj
+++ b/build-windows-visual-studio/sm64ex.vcxproj
@@ -3944,6 +3944,7 @@
+
@@ -4389,6 +4390,7 @@
+
diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters
index 8ab7358d..c95d9792 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj.filters
+++ b/build-windows-visual-studio/sm64ex.vcxproj.filters
@@ -15261,6 +15261,9 @@
Source Files\src\pc\djui\panel
+
+ Source Files\src\pc\djui\panel
+
@@ -16342,5 +16345,8 @@
Source Files\src\pc\djui\panel
+
+ Source Files\src\pc\djui\panel
+
\ No newline at end of file
diff --git a/src/pc/configfile.c b/src/pc/configfile.c
index 1b948d01..101b247c 100644
--- a/src/pc/configfile.c
+++ b/src/pc/configfile.c
@@ -92,7 +92,8 @@ bool configCameraAnalog = true;
bool configCameraMouse = false;
#endif
bool configSkipIntro = 0;
-bool configShareLives = 0;
+bool configShareLives = 0;
+bool configEnableCheats = 0;
bool configHUD = true;
#ifdef DISCORDRPC
bool configDiscordRPC = true;
@@ -153,6 +154,7 @@ static const struct ConfigOption options[] = {
#endif
{.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro},
{.name = "share_lives", .type = CONFIG_TYPE_BOOL, .boolValue = &configShareLives},
+ {.name = "enable_cheats", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCheats},
#ifdef DISCORDRPC
{.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC},
#endif
diff --git a/src/pc/configfile.h b/src/pc/configfile.h
index b71ecc7a..0059b0c4 100644
--- a/src/pc/configfile.h
+++ b/src/pc/configfile.h
@@ -61,6 +61,7 @@ extern bool configCameraAnalog;
extern bool configHUD;
extern bool configSkipIntro;
extern bool configShareLives;
+extern bool configEnableCheats;
#ifdef DISCORDRPC
extern bool configDiscordRPC;
#endif
diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h
index 533bdca2..c810cf4b 100644
--- a/src/pc/djui/djui.h
+++ b/src/pc/djui/djui.h
@@ -45,6 +45,7 @@
#include "djui_panel_display.h"
#include "djui_panel_sound.h"
#include "djui_panel_confirm.h"
+#include "djui_panel_cheats.h"
extern struct DjuiRoot* gDjuiRoot;
extern struct DjuiText* gDjuiPauseOptions;
diff --git a/src/pc/djui/djui_panel_cheats.c b/src/pc/djui/djui_panel_cheats.c
new file mode 100644
index 00000000..ee4b2de4
--- /dev/null
+++ b/src/pc/djui/djui_panel_cheats.c
@@ -0,0 +1,47 @@
+#include "djui.h"
+#include "pc/cheats.h"
+
+void djui_panel_cheats_create(struct DjuiBase* caller) {
+ f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 6;
+
+ struct DjuiBase* defaultBase = NULL;
+ struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\H\\#00b3ff\\E\\#ffef00\\A\\#ff0800\\T\\#1be700\\S");
+ struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
+
+ {
+ {
+ struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Moon jump", &Cheats.MoonJump);
+ djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox->base, 1.0f, 32);
+ defaultBase = &checkbox->base;
+ }
+ {
+ struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "God mode", &Cheats.GodMode);
+ djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox->base, 1.0f, 32);
+ }
+ {
+ struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Infinite lives", &Cheats.InfiniteLives);
+ djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox->base, 1.0f, 32);
+ }
+ {
+ struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Super speed", &Cheats.SuperSpeed);
+ djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox->base, 1.0f, 32);
+ }
+ {
+ struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Responsive controls", &Cheats.Responsive);
+ djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox->base, 1.0f, 32);
+ }
+
+ struct DjuiButton* button1 = djui_button_create(&body->base, "Back");
+ djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&button1->base, 1.0f, 64);
+ djui_button_set_style(button1, 1);
+ djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
+ }
+
+ djui_panel_add(caller, &panel->base, defaultBase);
+}
diff --git a/src/pc/djui/djui_panel_cheats.h b/src/pc/djui/djui_panel_cheats.h
new file mode 100644
index 00000000..d26290f5
--- /dev/null
+++ b/src/pc/djui/djui_panel_cheats.h
@@ -0,0 +1,4 @@
+#pragma once
+#include "djui.h"
+
+void djui_panel_cheats_create(struct DjuiBase* caller);
diff --git a/src/pc/djui/djui_panel_host.c b/src/pc/djui/djui_panel_host.c
index 430dac3d..ee5b31ae 100644
--- a/src/pc/djui/djui_panel_host.c
+++ b/src/pc/djui/djui_panel_host.c
@@ -4,6 +4,7 @@
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
+#include "pc/cheats.h"
#ifdef DISCORD_SDK
#define DJUI_HOST_NS_IS_SOCKET (configNetworkSystem == 1)
@@ -60,9 +61,9 @@ static void djui_panel_host_do_host(struct DjuiBase* caller) {
void djui_panel_host_create(struct DjuiBase* caller) {
#ifdef DISCORD_SDK
- f32 bodyHeight = 32 * 6 + 64 * 2 + 16 * 8;
+ f32 bodyHeight = 32 * 7 + 64 * 2 + 16 * 9;
#else
- f32 bodyHeight = 32 * 5 + 64 * 2 + 16 * 7;
+ f32 bodyHeight = 32 * 6 + 64 * 2 + 16 * 8;
#endif
struct DjuiBase* defaultBase = NULL;
@@ -148,6 +149,10 @@ void djui_panel_host_create(struct DjuiBase* caller) {
djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox3->base, 1.0f, 32);
+ struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "Enable cheats", &configEnableCheats);
+ djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&checkbox4->base, 1.0f, 32);
+
struct DjuiRect* rect3 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect3->base, 1.0f, 64);
diff --git a/src/pc/djui/djui_panel_pause.c b/src/pc/djui/djui_panel_pause.c
index 1ff0ef63..1aa843db 100644
--- a/src/pc/djui/djui_panel_pause.c
+++ b/src/pc/djui/djui_panel_pause.c
@@ -1,4 +1,5 @@
#include "djui.h"
+#include "pc/cheats.h"
bool gDjuiPanelPauseCreated = false;
@@ -19,6 +20,7 @@ static void djui_panel_pause_quit(struct DjuiBase* caller) {
void djui_panel_pause_create(struct DjuiBase* caller) {
f32 bodyHeight = 64 * 3 + 16 * 2;
+ if (Cheats.EnableCheats) { bodyHeight += 64 + 16; }
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\A\\#00b3ff\\U\\#ffef00\\S\\#ff0800\\E");
@@ -30,6 +32,13 @@ void djui_panel_pause_create(struct DjuiBase* caller) {
djui_interactable_hook_click(&button1->base, djui_panel_options_create);
defaultBase = &button1->base;
+ if (Cheats.EnableCheats) {
+ struct DjuiButton* button1 = djui_button_create(&body->base, "Cheats");
+ djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&button1->base, 1.0f, 64);
+ djui_interactable_hook_click(&button1->base, djui_panel_cheats_create);
+ }
+
struct DjuiButton* button2 = djui_button_create(&body->base, "Resume");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 1.0f, 64);
diff --git a/src/pc/network/network.c b/src/pc/network/network.c
index 36adfe94..24e7c663 100644
--- a/src/pc/network/network.c
+++ b/src/pc/network/network.c
@@ -9,6 +9,7 @@
#include "discord/discord.h"
#endif
#include "pc/configfile.h"
+#include "pc/cheats.h"
#include "pc/debuglog.h"
// Mario 64 specific externs
@@ -37,6 +38,7 @@ struct ServerSettings gServerSettings = {
.playerKnockbackStrength = 25,
.skipIntro = 0,
.shareLives = 0,
+ .enableCheats = 0,
};
void network_set_system(enum NetworkSystemType nsType) {
@@ -62,6 +64,8 @@ bool network_init(enum NetworkType inNetworkType) {
gServerSettings.stayInLevelAfterStar = configStayInLevelAfterStar;
gServerSettings.skipIntro = configSkipIntro;
gServerSettings.shareLives = configShareLives;
+ gServerSettings.enableCheats = configEnableCheats;
+ Cheats.EnableCheats = gServerSettings.enableCheats;
// initialize the network system
int rc = gNetworkSystem->initialize(inNetworkType);
diff --git a/src/pc/network/network.h b/src/pc/network/network.h
index f9e18249..d6dd42cc 100644
--- a/src/pc/network/network.h
+++ b/src/pc/network/network.h
@@ -76,6 +76,7 @@ struct ServerSettings {
u8 stayInLevelAfterStar;
u8 skipIntro;
u8 shareLives;
+ u8 enableCheats;
};
// Networking-specific externs
diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c
index 173eadf6..9de84ee8 100644
--- a/src/pc/network/packets/packet_join.c
+++ b/src/pc/network/packets/packet_join.c
@@ -11,6 +11,7 @@
#include "PR/os_eeprom.h"
#include "pc/network/version.h"
#include "pc/djui/djui.h"
+#include "pc/cheats.h"
#include "pc/utils/string_builder.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
@@ -65,6 +66,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
packet_write(&p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
packet_write(&p, &gServerSettings.skipIntro, sizeof(u8));
packet_write(&p, &gServerSettings.shareLives, sizeof(u8));
+ packet_write(&p, &gServerSettings.enableCheats, sizeof(u8));
packet_write(&p, eeprom, sizeof(u8) * 512);
u8 modCount = string_linked_list_count(&gRegisteredMods);
@@ -124,9 +126,12 @@ void network_receive_join(struct Packet* p) {
packet_read(p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
packet_read(p, &gServerSettings.skipIntro, sizeof(u8));
packet_read(p, &gServerSettings.shareLives, sizeof(u8));
+ packet_read(p, &gServerSettings.enableCheats, sizeof(u8));
packet_read(p, eeprom, sizeof(u8) * 512);
packet_read(p, &modCount, sizeof(u8));
+ Cheats.EnableCheats = gServerSettings.enableCheats;
+
struct StringLinkedList head = { 0 };
for (int i = 0; i < modCount; i++) {
char* modName = (char*) &p->buffer[p->cursor];