From a939ddc07bff553859a90af188cb49aa0eed5915 Mon Sep 17 00:00:00 2001 From: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:46:46 +1000 Subject: [PATCH 1/2] bring back the ability to lose your cap (#229) * bring back the ability to lose your cap * run autogen and add "cap" to the mario states guide * fix some indentation --- autogen/lua_definitions/structs.lua | 1 + docs/lua/guides/mario-state.md | 1 + docs/lua/structs.md | 1 + include/types.h | 1 + src/game/behaviors/cap.inc.c | 15 +++------------ src/game/behaviors/klepto.inc.c | 11 +++++------ src/game/behaviors/mr_blizzard.inc.c | 4 ++-- src/game/behaviors/ukiki.inc.c | 13 ++++++------- src/game/interaction.c | 4 ++-- src/game/mario.c | 10 ++++------ src/game/save_file.c | 8 ++++---- src/pc/lua/smlua_cobject_autogen.c | 1 + src/pc/network/network.c | 1 + 13 files changed, 32 insertions(+), 39 deletions(-) diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 543af7ff8..21d8f6376 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -708,6 +708,7 @@ --- @field public animation MarioAnimation --- @field public area Area --- @field public bubbleObj Object +--- @field public cap integer --- @field public capTimer integer --- @field public ceil Surface --- @field public ceilHeight number diff --git a/docs/lua/guides/mario-state.md b/docs/lua/guides/mario-state.md index 4cd10a91c..3caae6de9 100644 --- a/docs/lua/guides/mario-state.md +++ b/docs/lua/guides/mario-state.md @@ -86,6 +86,7 @@ The `MarioState` structure contains 76 different variables, this guide will try |`knockbackTimer`|`integer`|Used for invincibilty when flying through the air after a bonk or being hit by another player. |`specialTripleJump`|`integer`|Can be used as a bool, sets whether or not to use the special triple jump unlocked after talking to Yoshi. |`wallNormal`|`Vec3f`|The angle of the current wall on the x, y, and z axis. +|`cap`|`integer`|Where Mario's cap is meant to be. Can be on Mario's head, the snowman's head in Snowman's Land, held by Klepto, or on Ukiki's head. ## Section 3: When should I use `gMarioStates`? Most of the time you won't be using `gMarioStates[0]` to access your Mario, but rather use a hook. A lot of hooks pass `m` through the function. What does this mean? Well, here is a example with comments to explain it as good as possible: diff --git a/docs/lua/structs.md b/docs/lua/structs.md index f64ac1c1f..fc4333a61 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -1034,6 +1034,7 @@ | animation | [MarioAnimation](structs.md#MarioAnimation) | | | area | [Area](structs.md#Area) | | | bubbleObj | [Object](structs.md#Object) | | +| cap | `integer` | | | capTimer | `integer` | | | ceil | [Surface](structs.md#Surface) | | | ceilHeight | `number` | | diff --git a/include/types.h b/include/types.h index 003c11e58..defad47ea 100644 --- a/include/types.h +++ b/include/types.h @@ -397,6 +397,7 @@ struct MarioState /*????*/ u8 specialTripleJump; /*????*/ Vec3f wallNormal; /*????*/ u8 visibleToEnemies; + /*????*/ u32 cap; }; struct TextureInfo diff --git a/src/game/behaviors/cap.inc.c b/src/game/behaviors/cap.inc.c index 066ff1fb0..44e1ad509 100644 --- a/src/game/behaviors/cap.inc.c +++ b/src/game/behaviors/cap.inc.c @@ -193,28 +193,22 @@ void bhv_normal_cap_init(void) { o->oFriction = 0.89f; o->oBuoyancy = 0.9f; o->oOpacity = 0xFF; - - save_file_set_cap_pos(o->oPosX, o->oPosY, o->oPosZ); } void normal_cap_set_save_flags(void) { save_file_clear_flags(SAVE_FLAG_CAP_ON_GROUND); switch (gCurrCourseNum) { - case COURSE_SSL: - save_file_set_flags(SAVE_FLAG_CAP_ON_KLEPTO); - break; - case COURSE_SL: - save_file_set_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_MR_BLIZZARD; break; case COURSE_TTM: - save_file_set_flags(SAVE_FLAG_CAP_ON_UKIKI); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_UKIKI; break; default: - save_file_set_flags(SAVE_FLAG_CAP_ON_KLEPTO); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_KLEPTO; break; } } @@ -251,9 +245,6 @@ void bhv_normal_cap_loop(void) { break; } - if ((s32) o->oForwardVel != 0) - save_file_set_cap_pos(o->oPosX, o->oPosY, o->oPosZ); - if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) normal_cap_set_save_flags(); diff --git a/src/game/behaviors/klepto.inc.c b/src/game/behaviors/klepto.inc.c index b4a3730d5..e66baa2f7 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -97,12 +97,11 @@ void bhv_klepto_init(void) { o->oKleptoStartPosY = o->oPosY; o->oKleptoStartPosZ = o->oPosZ; - // skip hat save flags - //if (save_file_get_flags() & SAVE_FLAG_CAP_ON_KLEPTO) { - // o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; - //} else { + if (gMarioStates[0].cap & SAVE_FLAG_CAP_ON_KLEPTO) { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; + } else { o->oAction = KLEPTO_ACT_WAIT_FOR_MARIO; - //} + } } struct SyncObject* so = sync_object_init(o, 4000.0f); @@ -419,7 +418,7 @@ void bhv_klepto_update(void) { u8 modelIndex = (np->overrideModelIndex < CT_MAX) ? np->overrideModelIndex : 0; u32 capModel = gCharacters[modelIndex].capModelId; - save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO); + gMarioStates[0].cap &= ~SAVE_FLAG_CAP_ON_KLEPTO; struct Object* cap = spawn_object(o, capModel, bhvNormalCap); if (cap != NULL) { diff --git a/src/game/behaviors/mr_blizzard.inc.c b/src/game/behaviors/mr_blizzard.inc.c index 63f613770..e5b8c210f 100644 --- a/src/game/behaviors/mr_blizzard.inc.c +++ b/src/game/behaviors/mr_blizzard.inc.c @@ -60,7 +60,7 @@ void bhv_mr_blizzard_init(void) { } else { if (o->oBehParams2ndByte != MR_BLIZZARD_STYPE_NO_CAP) { // Cap wearing Mr. Blizzard from SL. - if (save_file_get_flags() & SAVE_FLAG_CAP_ON_MR_BLIZZARD) { + if (gMarioStates[0].cap & SAVE_FLAG_CAP_ON_MR_BLIZZARD) { o->oAnimState = 1; } } @@ -244,7 +244,7 @@ static void mr_blizzard_act_death(void) { // If Mr. Blizzard is wearing Mario's cap, clear // the save flag and spawn Mario's cap. if (o->oAnimState) { - save_file_clear_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD); + gMarioStates[0].cap &= ~SAVE_FLAG_CAP_ON_MR_BLIZZARD; cap = spawn_object_relative(0, 5, 105, 0, o, MODEL_MARIOS_CAP, bhvNormalCap); if (cap != NULL) { diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index 1762672fc..0e0e987be 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -644,13 +644,12 @@ void cap_ukiki_held_loop(void) { * Initializatation for ukiki, determines if it has Mario's cap. */ void bhv_ukiki_init(void) { - // skip hat save flags - //if (o->oBehParams2ndByte == UKIKI_CAP) { - // if (save_file_get_flags() & SAVE_FLAG_CAP_ON_UKIKI) { - // o->oUkikiTextState = UKIKI_TEXT_HAS_CAP; - // o->oUkikiHasCap |= UKIKI_CAP_ON; - // } - //} + if (o->oBehParams2ndByte == UKIKI_CAP) { + if (gMarioStates[0].cap & SAVE_FLAG_CAP_ON_UKIKI) { + o->oUkikiTextState = UKIKI_TEXT_HAS_CAP; + o->oUkikiHasCap |= UKIKI_CAP_ON; + } + } sync_object_init(o, 4000.0f); sync_object_init_field(o, &o->oUkikiTauntCounter); diff --git a/src/game/interaction.c b/src/game/interaction.c index a65b6ece6..cf6d375ce 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -394,7 +394,7 @@ void mario_blow_off_cap(struct MarioState *m, f32 capSpeed) { struct Object *capObject; if (does_mario_have_normal_cap_on_head(m)) { - save_file_set_cap_pos(m->pos[0], m->pos[1], m->pos[2]); + m->cap = SAVE_FLAG_CAP_ON_MR_BLIZZARD; m->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD); @@ -426,7 +426,7 @@ u32 mario_lose_cap_to_enemy(struct MarioState* m, u32 arg) { u32 wasWearingCap = FALSE; if (does_mario_have_normal_cap_on_head(m)) { - save_file_set_flags(arg == 1 ? SAVE_FLAG_CAP_ON_KLEPTO : SAVE_FLAG_CAP_ON_UKIKI); + gMarioStates[0].cap = (arg == 1 ? SAVE_FLAG_CAP_ON_KLEPTO : SAVE_FLAG_CAP_ON_UKIKI); m->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD); wasWearingCap = TRUE; } diff --git a/src/game/mario.c b/src/game/mario.c index 33915df75..fbfb12474 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -2149,13 +2149,12 @@ void init_single_mario(struct MarioState* m) { m->invincTimer = 0; m->visibleToEnemies = TRUE; - - // always put the cap on head - /*if (save_file_get_flags() & (SAVE_FLAG_CAP_ON_GROUND | SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI | SAVE_FLAG_CAP_ON_MR_BLIZZARD)) { + + if (m->cap & (SAVE_FLAG_CAP_ON_GROUND | SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI | SAVE_FLAG_CAP_ON_MR_BLIZZARD)) { m->flags = 0; - } else {*/ + } else { m->flags = (MARIO_CAP_ON_HEAD | MARIO_NORMAL_CAP); - //} + } m->forwardVel = 0.0f; m->squishTimer = 0; @@ -2198,7 +2197,6 @@ void init_single_mario(struct MarioState* m) { m->action = (m->pos[1] <= (m->waterLevel - 100)) ? ACT_WATER_IDLE : ACT_IDLE; - mario_reset_bodystate(m); update_mario_info_for_cam(m); m->marioBodyState->punchState = 0; diff --git a/src/game/save_file.c b/src/game/save_file.c index a4435b96f..8e2b9bec8 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -706,16 +706,16 @@ u16 save_file_get_sound_mode(void) { } void save_file_move_cap_to_default_location(void) { - if (save_file_get_flags() & SAVE_FLAG_CAP_ON_GROUND) { + if (save_file_get_flags() & SAVE_FLAG_CAP_ON_GROUND || gMarioStates[0].cap == SAVE_FLAG_CAP_ON_GROUND) { switch (gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].capLevel) { case LEVEL_SSL: - save_file_set_flags(SAVE_FLAG_CAP_ON_KLEPTO); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_KLEPTO; break; case LEVEL_SL: - save_file_set_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_MR_BLIZZARD; break; case LEVEL_TTM: - save_file_set_flags(SAVE_FLAG_CAP_ON_UKIKI); + gMarioStates[0].cap = SAVE_FLAG_CAP_ON_UKIKI; break; } save_file_clear_flags(SAVE_FLAG_CAP_ON_GROUND); diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index ac43d332a..d372ebb23 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -821,6 +821,7 @@ static struct LuaObjectField sMarioStateFields[LUA_MARIO_STATE_FIELD_COUNT] = { { "animation", LVT_COBJECT_P, offsetof(struct MarioState, animation), false, LOT_MARIOANIMATION }, { "area", LVT_COBJECT_P, offsetof(struct MarioState, area), false, LOT_AREA }, { "bubbleObj", LVT_COBJECT_P, offsetof(struct MarioState, bubbleObj), false, LOT_OBJECT }, + { "cap", LVT_U32, offsetof(struct MarioState, cap), false, LOT_NONE }, { "capTimer", LVT_U16, offsetof(struct MarioState, capTimer), false, LOT_NONE }, { "ceil", LVT_COBJECT_P, offsetof(struct MarioState, ceil), false, LOT_SURFACE }, { "ceilHeight", LVT_F32, offsetof(struct MarioState, ceilHeight), false, LOT_NONE }, diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 1705b4768..026b15877 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -515,6 +515,7 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) { network_player_init(); camera_set_use_course_specific_settings(true); free_vtx_scroll_targets(); + gMarioStates[0].cap = 0; struct Controller* cnt = gMarioStates[0].controller; cnt->rawStickX = 0; From bd2bd7c498e2d8ccc01c0e9498e7839e64fba0ba Mon Sep 17 00:00:00 2001 From: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:47:03 +1000 Subject: [PATCH 2/2] bring back vanilla demos (#221) * Bring back the demos from vanilla the demo will activate if you are on the level that demo was meant to be from, and the default amount of time has passed * clean up a bit and check a few things * reset the demo input table * config option/prevent demos playing on player menu * update demo playing - keep playing level music after demo finishes - stop the demo if the player changes main menu level --- src/game/level_update.c | 105 ++++++++++++++++++++++---- src/game/level_update.h | 8 ++ src/menu/level_select_menu.c | 2 - src/pc/configfile.c | 2 + src/pc/configfile.h | 1 + src/pc/djui/djui_panel_menu_options.c | 6 ++ src/pc/djui/djui_panel_player.c | 13 +++- 7 files changed, 121 insertions(+), 16 deletions(-) diff --git a/src/game/level_update.c b/src/game/level_update.c index 7c51cdd0f..5980ab84a 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -63,6 +63,10 @@ s16 gChangeLevelTransition = -1; s16 gChangeActNum = -1; static bool sFirstCastleGroundsMenu = true; +bool isDemoActive = false; +bool inPlayerMenu = false; +static u16 gDemoCountdown = 0; +int demoNumber = -1; // TODO: Make these ifdefs better const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" }; @@ -821,10 +825,8 @@ s16 level_trigger_warp(struct MarioState *m, s32 warpOp) { switch (warpOp) { case WARP_OP_DEMO_NEXT: case WARP_OP_DEMO_END: sDelayedWarpTimer = 20; // Must be one line to match on -O2 - sSourceWarpNodeId = WARP_NODE_F0; - gSavedCourseNum = COURSE_NONE; val04 = FALSE; - play_transition(WARP_TRANSITION_FADE_INTO_STAR, 0x14, 0x00, 0x00, 0x00); + stop_demo(NULL); break; case WARP_OP_CREDITS_END: @@ -972,7 +974,6 @@ void initiate_delayed_warp(void) { break; case WARP_OP_DEMO_NEXT: - warp_special(-2); break; case WARP_OP_CREDITS_START: @@ -1105,21 +1106,92 @@ void basic_update(UNUSED s16 *arg) { } } +bool find_demo_number(void) { + bool changeLevel = false; + switch (gCurrLevelNum) { + case LEVEL_BOWSER_1: + changeLevel = true; + demoNumber = 0; + break; + case LEVEL_WF: + changeLevel = true; + demoNumber = 1; + break; + case LEVEL_CCM: + changeLevel = true; + demoNumber = 2; + break; + case LEVEL_BBH: + changeLevel = true; + demoNumber = 3; + break; + case LEVEL_JRB: + changeLevel = true; + demoNumber = 4; + break; + case LEVEL_HMC: + changeLevel = true; + demoNumber = 5; + break; + case LEVEL_PSS: + changeLevel = true; + demoNumber = 6; + break; + default: + changeLevel = false; + demoNumber = -1; + } + return changeLevel; +} + +static void start_demo(void) { + if (isDemoActive) { + isDemoActive = false; + } else { + isDemoActive = true; + + if (find_demo_number()) { + gChangeLevel = gCurrLevelNum; + } + + if (demoNumber <= 6 || demoNumber > -1) { + gCurrDemoInput = NULL; + func_80278A78(&gDemo, gDemoInputs, D_80339CF4); + load_patchable_table(&gDemo, demoNumber); + gCurrDemoInput = ((struct DemoInput *) gDemo.targetAnim); + } else { + isDemoActive = false; + } + } +} + +void stop_demo(UNUSED struct DjuiBase* caller) { + if (isDemoActive) { + isDemoActive = false; + gCurrDemoInput = NULL; + gChangeLevel = gCurrLevelNum; + gDemoCountdown = 0; + if (gDjuiInMainMenu || gNetworkType == NT_NONE) { + update_menu_level(); + } + } +} + int gPressedStart = 0; s32 play_mode_normal(void) { - if (gCurrDemoInput != NULL) { - print_intro_text(); - if (gPlayer1Controller->buttonPressed & END_DEMO) { - level_trigger_warp(gMarioState, - gCurrLevelNum == LEVEL_PSS ? WARP_OP_DEMO_END : WARP_OP_DEMO_NEXT); - } else if (!gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE - && (gPlayer1Controller->buttonPressed & START_BUTTON)) { - gPressedStart = 1; - level_trigger_warp(gMarioState, WARP_OP_DEMO_NEXT); + if (gDjuiInMainMenu && gCurrDemoInput == NULL && configMenuDemos && !inPlayerMenu) { + find_demo_number(); + if ((++gDemoCountdown) == PRESS_START_DEMO_TIMER && (demoNumber <= 6 || demoNumber > -1)) { + start_demo(); } } + if (((gCurrDemoInput != NULL) && (gPlayer1Controller->buttonPressed & END_DEMO || !isDemoActive || !gDjuiInMainMenu || gNetworkType != NT_NONE || inPlayerMenu)) || (gCurrDemoInput == NULL && isDemoActive)) { + gPlayer1Controller->buttonPressed &= ~END_DEMO; + stop_demo(NULL); + } + warp_area(); check_instant_warp(); @@ -1344,6 +1416,9 @@ void update_menu_level(void) { // warp to level, this feels buggy if (gCurrLevelNum != curLevel) { + if (isDemoActive) { + stop_demo(NULL); + } if (curLevel == LEVEL_JRB) { gChangeLevel = curLevel; gChangeActNum = 2; @@ -1353,6 +1428,10 @@ void update_menu_level(void) { gChangeLevel = curLevel; gChangeActNum = 6; } + gDemoCountdown = 0; + } + if (isDemoActive) { + return; } if (gCurrAreaIndex != 2 && gCurrLevelNum == LEVEL_THI) { diff --git a/src/game/level_update.h b/src/game/level_update.h index 24c524c66..aedab1128 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -5,6 +5,7 @@ #include "types.h" +#include "pc/djui/djui.h" #define TIMER_CONTROL_SHOW 0 #define TIMER_CONTROL_START 1 @@ -56,6 +57,8 @@ #define WARP_TYPE_CHANGE_AREA 2 #define WARP_TYPE_SAME_AREA 3 +#define PRESS_START_DEMO_TIMER 800 + struct CreditsEntry { /*0x00*/ u8 levelNum; @@ -125,6 +128,8 @@ extern s8 gNeverEnteredCastle; extern u32 gControlTimerStartNat; extern u32 gControlTimerStopNat; +extern bool inPlayerMenu; + enum HUDDisplayFlag { HUD_DISPLAY_FLAG_LIVES = 0x0001, HUD_DISPLAY_FLAG_COIN_COUNT = 0x0002, @@ -163,4 +168,7 @@ s32 lvl_exiting_credits(UNUSED s16 arg0, UNUSED s32 arg1); void fake_lvl_init_from_save_file(void); void lvl_skip_credits(void); +void update_menu_level(void); +void stop_demo(UNUSED struct DjuiBase* caller); + #endif // LEVEL_UPDATE_H diff --git a/src/menu/level_select_menu.c b/src/menu/level_select_menu.c index 6048b3a20..53857160d 100644 --- a/src/menu/level_select_menu.c +++ b/src/menu/level_select_menu.c @@ -17,8 +17,6 @@ #include "pc/lua/utils/smlua_level_utils.h" #include "menu/intro_geo.h" -#define PRESS_START_DEMO_TIMER 800 - #define STUB_LEVEL(textname, _1, _2, _3, _4, _5, _6, _7, _8) textname, #define DEFINE_LEVEL(textname, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) textname, diff --git a/src/pc/configfile.c b/src/pc/configfile.c index d97197c59..6546d41c6 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -136,6 +136,7 @@ unsigned int configPlayerModel = 0; unsigned int configMenuLevel = 0; bool configMenuSound = false; bool configMenuRandom = false; +bool configMenuDemos = false; struct PlayerPalette configPlayerPalette = {{{ 0x00, 0x00, 0xff }, { 0xff, 0x00, 0x00 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xff, 0x00, 0x00 }}}; struct PlayerPalette configCustomPalette = {{{ 0x00, 0x00, 0xff }, { 0xff, 0x00, 0x00 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xff, 0x00, 0x00 }}}; bool configUncappedFramerate = true; @@ -228,6 +229,7 @@ static const struct ConfigOption options[] = { {.name = "coop_menu_level", .type = CONFIG_TYPE_UINT , .uintValue = &configMenuLevel}, {.name = "coop_menu_sound", .type = CONFIG_TYPE_BOOL , .boolValue = &configMenuSound}, {.name = "coop_menu_random", .type = CONFIG_TYPE_BOOL , .boolValue = &configMenuRandom}, + {.name = "coop_menu_demos", .type = CONFIG_TYPE_BOOL , .boolValue = &configMenuDemos}, {.name = "coop_player_palette_pants", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[PANTS]}, {.name = "coop_player_palette_shirt", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[SHIRT]}, {.name = "coop_player_palette_gloves", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[GLOVES]}, diff --git a/src/pc/configfile.h b/src/pc/configfile.h index d98af5066..d7c4419eb 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -93,6 +93,7 @@ extern unsigned int configPlayerModel; extern unsigned int configMenuLevel; extern bool configMenuSound; extern bool configMenuRandom; +extern bool configMenuDemos; extern struct PlayerPalette configPlayerPalette; extern struct PlayerPalette configCustomPalette; extern bool configUncappedFramerate; diff --git a/src/pc/djui/djui_panel_menu_options.c b/src/pc/djui/djui_panel_menu_options.c index dddb7445a..a0423e337 100644 --- a/src/pc/djui/djui_panel_menu_options.c +++ b/src/pc/djui/djui_panel_menu_options.c @@ -1,6 +1,7 @@ #include "djui.h" #include "src/pc/utils/misc.h" #include "src/pc/configfile.h" +#include "src/game/level_update.h" static struct DjuiSelectionbox* sLevelBox = NULL; @@ -51,6 +52,11 @@ void djui_panel_main_menu_create(struct DjuiBase* caller) { djui_base_set_size(&checkbox2->base, 1.0f, 32); djui_interactable_hook_value_change(&checkbox2->base, djui_panel_random_menu); + struct DjuiCheckbox* checkbox3 = djui_checkbox_create(&body->base, "Play Vanilla Demos", &configMenuDemos); + djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&checkbox3->base, 1.0f, 32); + djui_interactable_hook_value_change(&checkbox3->base, stop_demo); + 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); diff --git a/src/pc/djui/djui_panel_player.c b/src/pc/djui/djui_panel_player.c index 429a03d50..03eadd55c 100644 --- a/src/pc/djui/djui_panel_player.c +++ b/src/pc/djui/djui_panel_player.c @@ -240,9 +240,20 @@ static void djui_panel_player_value_changed(UNUSED struct DjuiBase* caller) { } } +static void djui_panel_player_prevent_demo(UNUSED struct DjuiBase* caller) { + if (inPlayerMenu) { + inPlayerMenu = false; + djui_panel_menu_back(NULL); + } else { + inPlayerMenu = true; + } +} + void djui_panel_player_create(struct DjuiBase* caller) { f32 bodyHeight = 32 * 3 + 64 * 2 + 16 * 5; + djui_panel_player_prevent_demo(NULL); + struct DjuiBase* defaultBase = NULL; struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\L\\#00b3ff\\A\\#ffef00\\Y\\#ff0800\\E\\#1be700\\R"); struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel); @@ -338,7 +349,7 @@ void djui_panel_player_create(struct DjuiBase* caller) { djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&button6->base, 1.0f, 64); djui_button_set_style(button6, 1); - djui_interactable_hook_click(&button6->base, djui_panel_menu_back); + djui_interactable_hook_click(&button6->base, djui_panel_player_prevent_demo); } djui_panel_add(caller, &panel->base, defaultBase);