diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 49bc9496e..f998ffdd6 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -5663,8 +5663,9 @@ function mario_can_bubble(m) end --- @param m MarioState ---- Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives and preventing normal movement -function mario_set_bubbled(m) +--- @param stayAlive? boolean +--- Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives by default and preventing normal movement +function mario_set_bubbled(m, stayAlive) -- ... end diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index 114faf99d..a67e65131 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -1228,21 +1228,22 @@ Checks whether Mario can become bubbled under certain game conditions (multiplay ## [mario_set_bubbled](#mario_set_bubbled) ### Description -Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives and preventing normal movement +Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives by default and preventing normal movement ### Lua Example -`mario_set_bubbled(m)` +`mario_set_bubbled(m, stayAlive)` ### Parameters | Field | Type | | ----- | ---- | | m | [MarioState](structs.md#MarioState) | +| stayAlive | `boolean` | ### Returns - None ### C Prototype -`void mario_set_bubbled(struct MarioState* m);` +`void mario_set_bubbled(struct MarioState* m, OPTIONAL bool stayAlive);` [:arrow_up_small:](#) diff --git a/src/game/interaction.c b/src/game/interaction.c index a102e8c5f..fb6d9a2c1 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -2455,7 +2455,7 @@ void check_death_barrier(struct MarioState *m) { break; } default: - mario_set_bubbled(m); + mario_set_bubbled(m, false); return; } } diff --git a/src/game/level_update.c b/src/game/level_update.c index fdc255eef..5a2ab4563 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -449,7 +449,7 @@ void init_mario_after_warp(void) { // enforce bubble on area change if (gServerSettings.bubbleDeath) { if (i == 0 && gMarioStates[i].numLives == -1) { - mario_set_bubbled(&gMarioStates[i]); + mario_set_bubbled(&gMarioStates[i], false); gMarioStates[i].health = 0xFF; } } diff --git a/src/game/mario.c b/src/game/mario.c index cadc24e84..86a4db271 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -47,10 +47,6 @@ #define MAX_HANG_PREVENTION 64 -u32 unused80339F10; -s8 filler80339F1C[20]; -u16 gLocalBubbleCounter = 0; - /************************************************** * ANIMATIONS * @@ -426,32 +422,30 @@ bool mario_can_bubble(struct MarioState* m) { if (m->action == ACT_BUBBLED) { return false; } if (!m->visibleToObjects) { return false; } - u8 allInBubble = TRUE; for (s32 i = 1; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } if (!gMarioStates[i].visibleToObjects) { continue; } if (gMarioStates[i].action != ACT_BUBBLED && gMarioStates[i].health >= 0x100) { - allInBubble = FALSE; - break; + return true; } } - if (allInBubble) { return false; } - return true; + return false; } -void mario_set_bubbled(struct MarioState* m) { +void mario_set_bubbled(struct MarioState* m, OPTIONAL bool stayAlive) { if (!m) { return; } if (m->playerIndex != 0) { return; } if (m->action == ACT_BUBBLED) { return; } - gLocalBubbleCounter = 20; - - drop_and_set_mario_action(m, ACT_BUBBLED, 0); - if (m->numLives > 0) { - m->numLives--; + drop_and_set_mario_action(m, ACT_BUBBLED, stayAlive); + if (!stayAlive) { + if (m->numLives > 0) { + m->numLives--; + } + m->healCounter = 0; + m->hurtCounter = 31; } - m->healCounter = 0; - m->hurtCounter = 31; + gCamera->cutscene = 0; m->statusForCamera->action = m->action; m->statusForCamera->cameraEvent = 0; @@ -2193,7 +2187,6 @@ void init_single_mario(struct MarioState* m) { u16 playerIndex = m->playerIndex; struct SpawnInfo* spawnInfo = &gPlayerSpawnInfos[playerIndex]; - unused80339F10 = 0; m->freeze = 0; diff --git a/src/game/mario.h b/src/game/mario.h index 897178043..f110c4474 100644 --- a/src/game/mario.h +++ b/src/game/mario.h @@ -6,7 +6,6 @@ #include "macros.h" #include "types.h" -extern u16 gLocalBubbleCounter; struct WallCollisionData; /* |description| @@ -140,9 +139,9 @@ Checks whether Mario can become bubbled under certain game conditions (multiplay bool mario_can_bubble(struct MarioState* m); /* |description| -Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives and preventing normal movement +Transitions Mario into a bubbled state (if available in multiplayer), decrementing lives by default and preventing normal movement |descriptionEnd| */ -void mario_set_bubbled(struct MarioState* m); +void mario_set_bubbled(struct MarioState* m, OPTIONAL bool stayAlive); /* |description| Sets Mario's forward velocity (`m.forwardVel`) and updates `slideVelX/Z` and `m.vel` accordingly, based on `m.faceAngle.y`. diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index cdce9a798..c06585370 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -1741,7 +1741,7 @@ s32 act_lava_boost(struct MarioState *m) { if ((mario_can_bubble(m) && m->numLives > 0)) { m->health = 0xFF; - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index b8fe0777e..5ae355d7a 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -1032,9 +1032,11 @@ Makes Mario act like he was popped from a bubble. Useful for custom bubble poppi void mario_pop_bubble(struct MarioState* m) { if (!m) { return; } m->marioObj->activeFlags &= ~ACTIVE_FLAG_MOVE_THROUGH_GRATE; - m->hurtCounter = 0; - m->healCounter = 31; - m->health = 0x100; + if (!m->actionArg) { + m->hurtCounter = 0; + m->healCounter = 31; + m->health = 0x100; + } m->marioObj->oIntangibleTimer = 0; m->peakHeight = m->pos[1]; mario_set_forward_vel(m, 0.0f); @@ -1064,21 +1066,22 @@ s32 act_bubbled(struct MarioState* m) { s32 pitchToPlayer = obj_pitch_to_object(m->marioObj, target); s32 distanceToPlayer = dist_between_objects(m->marioObj, target); - // trigger warp if all are bubbled + // trigger warp if all are bubbled long enough if (m->playerIndex == 0) { u8 allInBubble = TRUE; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } if (!gMarioStates[i].visibleToObjects) { continue; } - if (gMarioStates[i].action != ACT_BUBBLED && gMarioStates[i].health >= 0x100) { + if (gMarioStates[i].action != ACT_BUBBLED) { allInBubble = FALSE; break; } } if (allInBubble) { - level_trigger_warp(m, WARP_OP_DEATH); - return set_mario_action(m, ACT_SOFT_BONK, 0); - } + if (m->actionState++ == 60) { + level_trigger_warp(m, WARP_OP_EXIT); + } + } else { m->actionState = 0; } } // create bubble @@ -1144,21 +1147,8 @@ s32 act_bubbled(struct MarioState* m) { // offset the player model to be in the center of the bubble bubbled_offset_visual(m); - // make invisible on -1 lives - if (m->playerIndex == 0) { - if (m->numLives <= -1) { - m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; - level_trigger_warp(m, WARP_OP_DEATH); - return set_mario_action(m, ACT_SOFT_BONK, 0); - } else { - m->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; - } - } - - if (gLocalBubbleCounter > 0) { gLocalBubbleCounter--; } - // pop bubble - if (m->playerIndex == 0 && distanceToPlayer < 120 && is_player_active(targetMarioState) && m->numLives != -1 && gLocalBubbleCounter == 0) { + if (m->playerIndex == 0 && ++m->actionTimer > 20 && distanceToPlayer < 120 && is_player_active(targetMarioState)) { mario_pop_bubble(m); return TRUE; } diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 0f03d9319..a6b3f532a 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -843,7 +843,7 @@ s32 common_death_handler(struct MarioState *m, s32 animation, s32 frameToDeathWa if (!allowDeath) { return animFrame; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } @@ -916,7 +916,7 @@ s32 act_quicksand_death(struct MarioState *m) { smlua_call_event_hooks(HOOK_ON_DEATH, m, &allowDeath); if (!allowDeath) { return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } @@ -941,7 +941,7 @@ s32 act_eaten_by_bubba(struct MarioState *m) { if ((mario_can_bubble(m) && m->numLives > 0)) { m->health = 0xFF; - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } @@ -1832,7 +1832,7 @@ s32 act_squished(struct MarioState *m) { if (!allowDeath) { return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); // woosh, he's gone! @@ -1883,7 +1883,7 @@ s32 act_squished(struct MarioState *m) { if (!allowDeath) { return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { // 0 units of health m->health = 0x00FF; diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 51cf2d247..14e56efb6 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -1004,7 +1004,7 @@ static s32 act_drowning(struct MarioState *m) { if (!allowDeath) { return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } @@ -1039,7 +1039,7 @@ static s32 act_water_death(struct MarioState *m) { if (!allowDeath) { return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } @@ -1165,7 +1165,7 @@ static s32 act_caught_in_whirlpool(struct MarioState *m) { if (!allowDeath) { reset_rumble_timers(m); return FALSE; } if ((mario_can_bubble(m) && m->numLives > 0)) { - mario_set_bubbled(m); + mario_set_bubbled(m, false); } else { level_trigger_warp(m, WARP_OP_DEATH); } diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 1d2750281..14a9e3993 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -16536,15 +16536,20 @@ int smlua_func_mario_set_bubbled(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); - if (top != 1) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mario_set_bubbled", 1, top); + if (top < 1 || top > 2) { + LOG_LUA_LINE("Improper param count for '%s': Expected between %u and %u, Received %u", "mario_set_bubbled", 1, 2, top); return 0; } struct MarioState* m = (struct MarioState*)smlua_to_cobject(L, 1, LOT_MARIOSTATE); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mario_set_bubbled"); return 0; } + bool stayAlive = (bool) 0; + if (top >= 2) { + stayAlive = smlua_to_boolean(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mario_set_bubbled"); return 0; } + } - mario_set_bubbled(m); + mario_set_bubbled(m, stayAlive); return 1; } diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index f7fc00f18..dc44dc616 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -398,7 +398,7 @@ void network_receive_player(struct Packet* p) { } // inform of player death - if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) { + if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED && !data.actionArg) { construct_player_popup(np, DLANG(NOTIF, DIED), NULL); }