Truly deal with the NPC dialog softlock problem

Reported by somario360:
After I (Luigi) gave the baby penguin to the mother, the start spawned,
but I was stuck in the looking up animation.
My friend (Mario) talked to Bowser after defeating him, Bowser turned into
a key, but he was stuck in the looking up animation after (I was able to
grab the key though, but Bowser was slightly visible) (Also don't mind 0
stars, he loves doing the lobby BLJ)

The issue is the state machine moved on without removing the reading
dialog action. There was no straight forward way to deal with this.
Custom functions were written for each call to dialog to ensure that we
should stay reading the dialog.
This commit is contained in:
MysterD 2020-08-31 21:10:34 -07:00
parent 5d7499bd2a
commit efa1600ad0
17 changed files with 101 additions and 37 deletions

View file

@ -492,6 +492,8 @@ static void boo_act_3(void) {
} }
} }
u8 boo_act_4_continue_dialog(void) { return o->oAction == 4; }
// Called when a Go on a Ghost Hunt boo dies // Called when a Go on a Ghost Hunt boo dies
static void boo_act_4(void) { static void boo_act_4(void) {
s32 dialogID; s32 dialogID;
@ -504,7 +506,7 @@ static void boo_act_4(void) {
} }
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
if (marioState->playerIndex != 0 || cur_obj_update_dialog(&gMarioStates[0], 2, 2, dialogID, 0)) { if (marioState->playerIndex != 0 || cur_obj_update_dialog(&gMarioStates[0], 2, 2, dialogID, 0, boo_act_4_continue_dialog)) {
create_sound_spawner(SOUND_OBJ_DYING_ENEMY1); create_sound_spawner(SOUND_OBJ_DYING_ENEMY1);
obj_mark_for_deletion(o); obj_mark_for_deletion(o);

View file

@ -925,6 +925,8 @@ void bowser_dead_hide(void) {
o->oGravity = 0; o->oGravity = 0;
} }
u8 bowser_dead_not_bits_end_continue_dialog(void) { return o->oAction == 4 && o->oSubAction == 3; }
s32 bowser_dead_not_bits_end(void) { s32 bowser_dead_not_bits_end(void) {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
@ -934,7 +936,7 @@ s32 bowser_dead_not_bits_end(void) {
func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40);
o->oBowserUnkF8++; o->oBowserUnkF8++;
} }
if (marioState->playerIndex == 0 && cur_obj_update_dialog(marioState, 2, 18, sBowserDefeatedDialogText[o->oBehParams2ndByte], 0)) { if (marioState->playerIndex == 0 && cur_obj_update_dialog(marioState, 2, 18, sBowserDefeatedDialogText[o->oBehParams2ndByte], 0, bowser_dead_not_bits_end_continue_dialog)) {
o->oBowserUnkF8++; o->oBowserUnkF8++;
cur_obj_play_sound_2(SOUND_GENERAL2_BOWSER_EXPLODE); cur_obj_play_sound_2(SOUND_GENERAL2_BOWSER_EXPLODE);
sequence_player_unlower(SEQ_PLAYER_LEVEL, 60); sequence_player_unlower(SEQ_PLAYER_LEVEL, 60);
@ -950,6 +952,8 @@ s32 bowser_dead_not_bits_end(void) {
return ret; return ret;
} }
u8 bowser_dead_bits_end_continue_dialog(void) { return o->oAction == 4 && o->oBowserUnkF8 < 2; }
s32 bowser_dead_bits_end(void) { s32 bowser_dead_bits_end(void) {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
UNUSED s32 unused; UNUSED s32 unused;
@ -964,7 +968,7 @@ s32 bowser_dead_bits_end(void) {
func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40);
o->oBowserUnkF8++; o->oBowserUnkF8++;
} }
if (marioState->playerIndex == 0 && cur_obj_update_dialog(marioState, 2, 18, dialogID, 0)) { if (marioState->playerIndex == 0 && cur_obj_update_dialog(marioState, 2, 18, dialogID, 0, bowser_dead_bits_end_continue_dialog)) {
cur_obj_set_model(MODEL_BOWSER2); cur_obj_set_model(MODEL_BOWSER2);
sequence_player_unlower(SEQ_PLAYER_LEVEL, 60); sequence_player_unlower(SEQ_PLAYER_LEVEL, 60);
sequence_player_fade_out(0, 1); sequence_player_fade_out(0, 1);

View file

@ -57,6 +57,8 @@ static void camera_lakitu_intro_act_spawn_cloud(void) {
} }
} }
u8 camera_lakitu_intro_act_show_dialog_continue_dialog(void) { return o->oCameraLakituFinishedDialog != TRUE; }
/** /**
* Circle down to mario, show the dialog, then fly away. * Circle down to mario, show the dialog, then fly away.
*/ */
@ -115,7 +117,7 @@ static void camera_lakitu_intro_act_show_dialog(void) {
} }
} }
} }
} else if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, DIALOG_UNK2_FLAG_0, CUTSCENE_DIALOG, DIALOG_034) != 0) { } else if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, DIALOG_UNK2_FLAG_0, CUTSCENE_DIALOG, DIALOG_034, camera_lakitu_intro_act_show_dialog_continue_dialog) != 0) {
o->oCameraLakituFinishedDialog = TRUE; o->oCameraLakituFinishedDialog = TRUE;
} }
} }

View file

@ -30,6 +30,8 @@ void cap_switch_act_1(void) {
} }
} }
u8 cap_switch_act_2_continue_dialog(void) { return o->oAction == 2 && o->oTimer >= 5; }
void cap_switch_act_2(void) { void cap_switch_act_2(void) {
capSwitchForcePress = FALSE; capSwitchForcePress = FALSE;
s32 sp1C; s32 sp1C;
@ -44,10 +46,8 @@ void cap_switch_act_2(void) {
} else { } else {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
if (marioState == &gMarioStates[0]) { if (marioState == &gMarioStates[0]) {
sp1C = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 1, 0x0C, CUTSCENE_CAP_SWITCH_PRESS, 0); sp1C = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 1, 0x0C, CUTSCENE_CAP_SWITCH_PRESS, 0, cap_switch_act_2_continue_dialog);
if (sp1C) { o->oAction = 3; } if (sp1C) { o->oAction = 3; }
} else {
o->oAction = 3;
} }
} }
} }

View file

@ -62,8 +62,10 @@ static void eyerok_boss_act_wake_up(void) {
} }
} }
u8 eyerok_boss_act_show_intro_text_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_SHOW_INTRO_TEXT; }
static void eyerok_boss_act_show_intro_text(void) { static void eyerok_boss_act_show_intro_text(void) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117)) { if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117, eyerok_boss_act_show_intro_text_continue_dialog)) {
o->oAction = EYEROK_BOSS_ACT_FIGHT; o->oAction = EYEROK_BOSS_ACT_FIGHT;
} }
} }
@ -115,9 +117,11 @@ static void eyerok_boss_act_fight(void) {
} }
} }
u8 eyerok_boss_act_die_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_DIE; }
static void eyerok_boss_act_die(void) { static void eyerok_boss_act_die(void) {
if (o->oTimer == 60) { if (o->oTimer == 60) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118)) { if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118, eyerok_boss_act_die_continue_dialog)) {
spawn_default_star(0.0f, -900.0f, -3700.0f); spawn_default_star(0.0f, -900.0f, -3700.0f);
} else { } else {
o->oTimer -= 1; o->oTimer -= 1;

View file

@ -580,6 +580,8 @@ static void koopa_the_quick_force_start_race(void) {
o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR; o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR;
} }
u8 koopa_the_quick_act_show_init_text_continue_dialog(void) { return o->oAction == KOOPA_THE_QUICK_ACT_SHOW_INIT_TEXT; }
/** /**
* Display the dialog asking mario if he wants to race. Begin the race or * Display the dialog asking mario if he wants to race. Begin the race or
* return to the waiting action. * return to the waiting action.
@ -588,7 +590,7 @@ static void koopa_the_quick_act_show_init_text(void) {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
s32 response = 0; s32 response = 0;
if (marioState == &gMarioStates[0]) { if (marioState == &gMarioStates[0]) {
response = obj_update_race_proposition_dialog(&gMarioStates[0], sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText); response = obj_update_race_proposition_dialog(&gMarioStates[0], sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText, koopa_the_quick_act_show_init_text_continue_dialog);
} }
if (response == 1) { if (response == 1) {
@ -778,6 +780,8 @@ static void koopa_the_quick_act_stop(void) {
} }
} }
u8 koopa_the_quick_act_after_race_continue_dialog(void) { return o->oAction == KOOPA_THE_QUICK_ACT_AFTER_RACE && o->parentObj->oKoopaRaceEndpointUnk100 > 0; }
/** /**
* Wait for mario to approach, then show text indicating the status of the race. * Wait for mario to approach, then show text indicating the status of the race.
* If mario got to the finish line first and didn't use the cannon, then spawn * If mario got to the finish line first and didn't use the cannon, then spawn
@ -812,7 +816,7 @@ static void koopa_the_quick_act_after_race(void) {
} }
} else if (o->parentObj->oKoopaRaceEndpointUnk100 > 0) { } else if (o->parentObj->oKoopaRaceEndpointUnk100 > 0) {
if (marioState == &gMarioStates[0]) { if (marioState == &gMarioStates[0]) {
s32 dialogResponse = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointUnk100); s32 dialogResponse = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointUnk100, koopa_the_quick_act_after_race_continue_dialog);
if (dialogResponse != 0) { if (dialogResponse != 0) {
o->parentObj->oKoopaRaceEndpointUnk100 = -1; o->parentObj->oKoopaRaceEndpointUnk100 = -1;
o->oTimer = 0; o->oTimer = 0;

View file

@ -51,11 +51,13 @@ static void racing_penguin_force_start_race(void) {
penguinForceStartRace = FALSE; penguinForceStartRace = FALSE;
} }
u8 racing_penguin_act_show_init_text_continue_dialog(void) { return o->oAction == RACING_PENGUIN_ACT_SHOW_INIT_TEXT; }
static void racing_penguin_act_show_init_text(void) { static void racing_penguin_act_show_init_text(void) {
s32 response; s32 response;
struct Object *child; struct Object *child;
response = obj_update_race_proposition_dialog(&gMarioStates[0], sRacingPenguinData[o->oBehParams2ndByte].text); response = obj_update_race_proposition_dialog(&gMarioStates[0], sRacingPenguinData[o->oBehParams2ndByte].text, racing_penguin_act_show_init_text_continue_dialog);
if (response == 1) { if (response == 1) {
child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine); child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine);
child->parentObj = o; child->parentObj = o;
@ -151,6 +153,8 @@ static void racing_penguin_act_finish_race(void) {
} }
} }
u8 racing_penguin_act_show_final_text_continue_dialog(void) { return o->oAction == RACING_PENGUIN_ACT_SHOW_FINAL_TEXT && o->oRacingPenguinFinalTextbox > 0; }
static void racing_penguin_act_show_final_text(void) { static void racing_penguin_act_show_final_text(void) {
s32 textResult; s32 textResult;
@ -181,7 +185,7 @@ static void racing_penguin_act_show_final_text(void) {
o->oForwardVel = 4.0f; o->oForwardVel = 4.0f;
} }
} else if (o->oRacingPenguinFinalTextbox > 0) { } else if (o->oRacingPenguinFinalTextbox > 0) {
if ((textResult = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox)) != 0) { if ((textResult = cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox, racing_penguin_act_show_final_text_continue_dialog)) != 0) {
o->oRacingPenguinFinalTextbox = -1; o->oRacingPenguinFinalTextbox = -1;
o->oTimer = 0; o->oTimer = 0;
} }

View file

@ -1,5 +1,7 @@
// sl_snowman_wind.c.inc // sl_snowman_wind.c.inc
u8 bhv_sl_snowman_wind_loop_continue_dialog(void) { return o->oSubAction == SL_SNOWMAN_WIND_ACT_TALKING; }
void bhv_sl_snowman_wind_loop(void) { void bhv_sl_snowman_wind_loop(void) {
UNUSED s32 unusedVar = 0; UNUSED s32 unusedVar = 0;
s16 marioAngleFromWindSource; s16 marioAngleFromWindSource;
@ -21,7 +23,7 @@ void bhv_sl_snowman_wind_loop(void) {
// Mario has come close, begin dialog. // Mario has come close, begin dialog.
} else if (o->oSubAction == SL_SNOWMAN_WIND_ACT_TALKING) { } else if (o->oSubAction == SL_SNOWMAN_WIND_ACT_TALKING) {
if (cur_obj_update_dialog(&gMarioStates[0], 2, 2, DIALOG_153, 0)) if (cur_obj_update_dialog(&gMarioStates[0], 2, 2, DIALOG_153, 0, bhv_sl_snowman_wind_loop_continue_dialog))
o->oSubAction++; o->oSubAction++;
// Blowing, spawn wind particles (SL_SNOWMAN_WIND_ACT_BLOWING) // Blowing, spawn wind particles (SL_SNOWMAN_WIND_ACT_BLOWING)

View file

@ -43,6 +43,8 @@ void tuxies_mother_act_2(void) {
} }
} }
u8 tuxies_mother_act_1_continue_dialog(void) { return (o->oAction == 1 && o->oSubAction == 0); }
void tuxies_mother_act_1(void) { void tuxies_mother_act_1(void) {
// only local can interact with mother // only local can interact with mother
struct MarioState* marioState = &gMarioStates[0]; struct MarioState* marioState = &gMarioStates[0];
@ -60,7 +62,7 @@ void tuxies_mother_act_1(void) {
dialogID = DIALOG_058; dialogID = DIALOG_058;
else else
dialogID = DIALOG_059; dialogID = DIALOG_059;
if (cur_obj_update_dialog_with_cutscene(marioState, 2, 1, CUTSCENE_DIALOG, dialogID)) { if (cur_obj_update_dialog_with_cutscene(marioState, 2, 1, CUTSCENE_DIALOG, dialogID, tuxies_mother_act_1_continue_dialog)) {
if (dialogID == DIALOG_058) if (dialogID == DIALOG_058)
o->oSubAction = 1; o->oSubAction = 1;
else else
@ -102,6 +104,8 @@ void tuxies_mother_act_1(void) {
} }
} }
u8 tuxies_mother_act_0_continue_dialog(void) { return (o->oAction == 0 && o->oSubAction == 1); }
void tuxies_mother_act_0(void) { void tuxies_mother_act_0(void) {
// only local can interact with mother // only local can interact with mother
struct MarioState* marioState = &gMarioStates[0]; struct MarioState* marioState = &gMarioStates[0];
@ -116,11 +120,9 @@ void tuxies_mother_act_0(void) {
cur_obj_init_animation_with_sound(3); cur_obj_init_animation_with_sound(3);
if (sp28 < 500.0f) if (sp28 < 500.0f)
sp2C = 1; sp2C = 1;
if (sp24 != NULL && sp28 < 300.0f && sp24->oHeldState != HELD_FREE) { if (sp24->heldByPlayerIndex == 0 && sp24 != NULL && sp28 < 300.0f && sp24->oHeldState != HELD_FREE) {
if (sp24->heldByPlayerIndex == 0) { o->oAction = 1;
o->oAction = 1; sp24->oSmallPenguinUnk88 = 1;
sp24->oSmallPenguinUnk88 = 1;
}
o->prevObj = sp24; o->prevObj = sp24;
} else { } else {
switch (o->oSubAction) { switch (o->oSubAction) {
@ -130,7 +132,7 @@ void tuxies_mother_act_0(void) {
o->oSubAction++; o->oSubAction++;
break; break;
case 1: case 1:
if (cur_obj_update_dialog_with_cutscene(marioState, 2, 1, CUTSCENE_DIALOG, DIALOG_057)) if (cur_obj_update_dialog_with_cutscene(marioState, 2, 1, CUTSCENE_DIALOG, DIALOG_057, tuxies_mother_act_0_continue_dialog))
o->oSubAction++; o->oSubAction++;
break; break;
case 2: case 2:

View file

@ -333,6 +333,8 @@ static Trajectory sCageUkikiPath[] = {
TRAJECTORY_END(), TRAJECTORY_END(),
}; };
u8 ukiki_act_go_to_cage_continue_dialog(void) { return o->oAction == UKIKI_ACT_GO_TO_CAGE && o->oSubAction == UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO; }
/** /**
* Travel to the cage, wait for Mario, jump to it, and ride it to * Travel to the cage, wait for Mario, jump to it, and ride it to
* our death. Ukiki is a tad suicidal. * our death. Ukiki is a tad suicidal.
@ -383,7 +385,7 @@ void ukiki_act_go_to_cage(void) {
case UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO: case UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO:
cur_obj_init_animation_with_sound(UKIKI_ANIM_HANDSTAND); cur_obj_init_animation_with_sound(UKIKI_ANIM_HANDSTAND);
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, DIALOG_080)) { if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, DIALOG_080, ukiki_act_go_to_cage_continue_dialog)) {
o->oSubAction++; o->oSubAction++;
} }
break; break;
@ -554,6 +556,9 @@ void cage_ukiki_held_loop(void) {
} }
} }
u8 hat_ukiki_held_loop_1(void) { return o->oHeldState == HELD_HELD && o->oUkikiTextState == UKIKI_TEXT_STEAL_HAT; }
u8 hat_ukiki_held_loop_2(void) { return o->oHeldState == HELD_HELD && o->oUkikiTextState == UKIKI_TEXT_HAS_HAT; }
/** /**
* Called by the main behavior function for the hat ukiki whenever it is held. * Called by the main behavior function for the hat ukiki whenever it is held.
*/ */
@ -567,7 +572,7 @@ void hat_ukiki_held_loop(void) {
break; break;
case UKIKI_TEXT_STEAL_HAT: case UKIKI_TEXT_STEAL_HAT:
if (cur_obj_update_dialog(&gMarioStates[0], 2, 2, DIALOG_100, 0)) { if (cur_obj_update_dialog(&gMarioStates[0], 2, 2, DIALOG_100, 0, hat_ukiki_held_loop_1)) {
o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY;
o->oUkikiTextState = UKIKI_TEXT_STOLE_HAT; o->oUkikiTextState = UKIKI_TEXT_STOLE_HAT;
} }
@ -577,7 +582,7 @@ void hat_ukiki_held_loop(void) {
break; break;
case UKIKI_TEXT_HAS_HAT: case UKIKI_TEXT_HAS_HAT:
if (cur_obj_update_dialog(&gMarioStates[0], 2, 18, DIALOG_101, 0)) { if (cur_obj_update_dialog(&gMarioStates[0], 2, 18, DIALOG_101, 0, hat_ukiki_held_loop_2)) {
mario_retrieve_cap(); mario_retrieve_cap();
set_mario_npc_dialog(&gMarioStates[0], 0); set_mario_npc_dialog(&gMarioStates[0], 0);
o->oUkikiHasHat &= ~UKIKI_HAT_ON; o->oUkikiHasHat &= ~UKIKI_HAT_ON;

View file

@ -14,6 +14,8 @@ void whomp_play_sfx_from_pound_animation(void) {
cur_obj_play_sound_2(SOUND_OBJ_POUNDING1); cur_obj_play_sound_2(SOUND_OBJ_POUNDING1);
} }
u8 whomp_act_0_continue_dialog(void) { return o->oAction == 0; }
void whomp_act_0(void) { void whomp_act_0(void) {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
struct Object* player = marioState->marioObj; struct Object* player = marioState->marioObj;
@ -32,7 +34,7 @@ void whomp_act_0(void) {
cur_obj_set_pos_to_home(); cur_obj_set_pos_to_home();
o->oHealth = 3; o->oHealth = 3;
} }
} else if (marioState == &gMarioStates[0] && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, DIALOG_114)) { } else if (marioState == &gMarioStates[0] && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 1, CUTSCENE_DIALOG, DIALOG_114, whomp_act_0_continue_dialog)) {
o->oAction = 2; o->oAction = 2;
network_send_object(o); network_send_object(o);
} }
@ -230,10 +232,12 @@ void whomp_act_6(void) {
} }
} }
u8 whomp_act_8_continue_dialog(void) { return o->oAction == 8; }
void whomp_act_8(void) { void whomp_act_8(void) {
if (o->oBehParams2ndByte != 0) { if (o->oBehParams2ndByte != 0) {
struct MarioState* marioState = nearest_mario_state_to_object(o); struct MarioState* marioState = nearest_mario_state_to_object(o);
if (marioState == &gMarioStates[0] && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 2, CUTSCENE_DIALOG, DIALOG_115)) { if (marioState == &gMarioStates[0] && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 2, CUTSCENE_DIALOG, DIALOG_115, whomp_act_8_continue_dialog)) {
obj_set_angle(o, 0, 0, 0); obj_set_angle(o, 0, 0, 0);
cur_obj_hide(); cur_obj_hide();
cur_obj_become_intangible(); cur_obj_become_intangible();

View file

@ -209,6 +209,8 @@ void wiggler_init_segments(void) {
} }
} }
u8 wiggler_act_walk_continue_dialog(void) { return o->oAction == WIGGLER_ACT_WALK && o->oWigglerTextStatus < WIGGLER_TEXT_STATUS_COMPLETED_DIALOG; }
/** /**
* Show text if necessary. Then walk toward mario if not at full health, and * Show text if necessary. Then walk toward mario if not at full health, and
* otherwise wander in random directions. * otherwise wander in random directions.
@ -228,7 +230,7 @@ static void wiggler_act_walk(void) {
// If Mario is positioned below the wiggler, assume he entered through the // If Mario is positioned below the wiggler, assume he entered through the
// lower cave entrance, so don't display text. // lower cave entrance, so don't display text.
if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_150) != 0) { if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_150, wiggler_act_walk_continue_dialog) != 0) {
o->oWigglerTextStatus = WIGGLER_TEXT_STATUS_COMPLETED_DIALOG; o->oWigglerTextStatus = WIGGLER_TEXT_STATUS_COMPLETED_DIALOG;
} }
} else { } else {
@ -284,6 +286,9 @@ static void wiggler_act_walk(void) {
} }
} }
} }
u8 wiggler_act_jumped_on_continue_dialog(void) { return o->oAction == WIGGLER_ACT_JUMPED_ON && o->header.gfx.scale[1] >= 4.0f && o->oTimer > 30; }
/** /**
* Squish and unsquish, then show text and enter either the walking or shrinking * Squish and unsquish, then show text and enter either the walking or shrinking
* action. * action.
@ -304,7 +309,7 @@ static void wiggler_act_jumped_on(void) {
// defeated) or go back to walking // defeated) or go back to walking
if (o->header.gfx.scale[1] >= 4.0f) { if (o->header.gfx.scale[1] >= 4.0f) {
if (o->oTimer > 30) { if (o->oTimer > 30) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, attackText[o->oHealth - 2]) != 0) { if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, attackText[o->oHealth - 2], wiggler_act_jumped_on_continue_dialog) != 0) {
// Because we don't want the wiggler to disappear after being // Because we don't want the wiggler to disappear after being
// defeated, we leave its health at 1 // defeated, we leave its health at 1
if (--o->oHealth == 1) { if (--o->oHealth == 1) {

View file

@ -358,6 +358,8 @@ s32 set_mario_npc_dialog(struct MarioState* m, s32 actionArg) {
if (m->playerIndex == 0 && actionArg == 0) { if (m->playerIndex == 0 && actionArg == 0) {
localDialogNPCBehavior = NULL; localDialogNPCBehavior = NULL;
continueDialogFunction = NULL;
continueDialogFunctionObject = NULL;
} }
// in dialog // in dialog
@ -395,8 +397,17 @@ s32 act_reading_npc_dialog(struct MarioState *m) {
s32 headTurnAmount = 0; s32 headTurnAmount = 0;
s16 angleToNPC; s16 angleToNPC;
if (m->playerIndex != 0) { return FALSE; }
if (m->playerIndex == 0) { if (m->playerIndex == 0) {
if (m->usedObj == NULL || m->usedObj->activeFlags == ACTIVE_FLAG_DEACTIVATED || m->usedObj->behavior != localDialogNPCBehavior) { u8 continueDialogCallback = TRUE;
if (continueDialogFunction != NULL && continueDialogFunctionObject != NULL) {
struct Object* tmp = gCurrentObject;
gCurrentObject = continueDialogFunctionObject;
continueDialogCallback = continueDialogFunction();
gCurrentObject = tmp;
}
if (!continueDialogCallback || m->usedObj == NULL || m->usedObj->activeFlags == ACTIVE_FLAG_DEACTIVATED || m->usedObj->behavior != localDialogNPCBehavior) {
set_mario_npc_dialog(m, 0); set_mario_npc_dialog(m, 0);
} }
} }

View file

@ -124,7 +124,7 @@ static void toad_message_opaque(void) {
} }
static void toad_message_talking(void) { static void toad_message_talking(void) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId) if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId, NULL)
!= 0) { != 0) {
gCurrentObject->oToadMessageRecentlyTalked = 1; gCurrentObject->oToadMessageRecentlyTalked = 1;
gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING; gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING;

View file

@ -97,9 +97,8 @@ static s16 obj_get_pitch_from_vel(void) {
* If the player declines the race, then disable time stop and allow Mario to * If the player declines the race, then disable time stop and allow Mario to
* move again. * move again.
*/ */
static s32 obj_update_race_proposition_dialog(struct MarioState* m, s16 dialogID) { static s32 obj_update_race_proposition_dialog(struct MarioState* m, s16 dialogID, u8 (*inContinueDialogFunction)(void)) {
s32 dialogResponse = s32 dialogResponse = cur_obj_update_dialog_with_cutscene(m, 2, DIALOG_UNK2_FLAG_0 | DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED, CUTSCENE_RACE_DIALOG, dialogID, inContinueDialogFunction);
cur_obj_update_dialog_with_cutscene(m, 2, DIALOG_UNK2_FLAG_0 | DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED, CUTSCENE_RACE_DIALOG, dialogID);
if (dialogResponse == 2) { if (dialogResponse == 2) {
set_mario_npc_dialog(m, 0); set_mario_npc_dialog(m, 0);

View file

@ -27,6 +27,9 @@
#include "spawn_object.h" #include "spawn_object.h"
#include "spawn_sound.h" #include "spawn_sound.h"
u8 (*continueDialogFunction)(void) = NULL;
struct Object* continueDialogFunctionObject = NULL;
s8 D_8032F0A0[] = { 0xF8, 0x08, 0xFC, 0x04 }; s8 D_8032F0A0[] = { 0xF8, 0x08, 0xFC, 0x04 };
s16 D_8032F0A4[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; s16 D_8032F0A4[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
static s8 sLevelsWithRooms[] = { LEVEL_BBH, LEVEL_CASTLE, LEVEL_HMC, -1 }; static s8 sLevelsWithRooms[] = { LEVEL_BBH, LEVEL_CASTLE, LEVEL_HMC, -1 };
@ -2663,6 +2666,8 @@ s32 cur_obj_can_mario_activate_textbox_2(struct MarioState* m, f32 radius, f32 h
} }
static void cur_obj_end_dialog(struct MarioState* m, s32 dialogFlags, s32 dialogResult) { static void cur_obj_end_dialog(struct MarioState* m, s32 dialogFlags, s32 dialogResult) {
if (m->playerIndex != 0) { return 0; }
o->oDialogResponse = dialogResult; o->oDialogResponse = dialogResult;
o->oDialogState++; o->oDialogState++;
@ -2671,10 +2676,14 @@ static void cur_obj_end_dialog(struct MarioState* m, s32 dialogFlags, s32 dialog
} }
} }
s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused) { s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused, u8 (*inContinueDialogFunction)(void)) {
s32 dialogResponse = 0; s32 dialogResponse = 0;
UNUSED s32 doneTurning = TRUE; UNUSED s32 doneTurning = TRUE;
if (m->playerIndex != 0) { return 0; }
continueDialogFunctionObject = gCurrentObject;
continueDialogFunction = inContinueDialogFunction;
switch (o->oDialogState) { switch (o->oDialogState) {
#ifdef VERSION_JP #ifdef VERSION_JP
case DIALOG_UNK1_ENABLE_TIME_STOP: case DIALOG_UNK1_ENABLE_TIME_STOP:
@ -2748,10 +2757,14 @@ s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags,
return dialogResponse; return dialogResponse;
} }
s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID) { s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID, u8 (*inContinueDialogFunction)(void)) {
s32 dialogResponse = 0; s32 dialogResponse = 0;
s32 doneTurning = TRUE; s32 doneTurning = TRUE;
if (m->playerIndex != 0) { return 0; }
continueDialogFunctionObject = gCurrentObject;
continueDialogFunction = inContinueDialogFunction;
switch (o->oDialogState) { switch (o->oDialogState) {
#ifdef VERSION_JP #ifdef VERSION_JP
case DIALOG_UNK2_ENABLE_TIME_STOP: case DIALOG_UNK2_ENABLE_TIME_STOP:

View file

@ -67,6 +67,9 @@ struct SpawnParticlesInfo
/*0x10*/ f32 sizeRange; /*0x10*/ f32 sizeRange;
}; };
extern u8 (*continueDialogFunction)(void);
extern struct Object* continueDialogFunctionObject;
Gfx *geo_update_projectile_pos_from_parent(s32 callContext, UNUSED struct GraphNode *node, Mat4 mtx); Gfx *geo_update_projectile_pos_from_parent(s32 callContext, UNUSED struct GraphNode *node, Mat4 mtx);
Gfx *geo_update_layer_transparency(s32 callContext, struct GraphNode *node, UNUSED void *context); Gfx *geo_update_layer_transparency(s32 callContext, struct GraphNode *node, UNUSED void *context);
#ifdef AVOID_UB #ifdef AVOID_UB
@ -277,8 +280,8 @@ void set_time_stop_flags(s32 flags);
void clear_time_stop_flags(s32 flags); void clear_time_stop_flags(s32 flags);
s32 cur_obj_can_mario_activate_textbox(struct MarioState* m, f32 radius, f32 height, UNUSED s32 unused); s32 cur_obj_can_mario_activate_textbox(struct MarioState* m, f32 radius, f32 height, UNUSED s32 unused);
s32 cur_obj_can_mario_activate_textbox_2(struct MarioState* m, f32 radius, f32 height); s32 cur_obj_can_mario_activate_textbox_2(struct MarioState* m, f32 radius, f32 height);
s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused); s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused, u8 (*inContinueDialogFunction)(void));
s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID); s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID, u8 (*inContinueDialogFunction)(void));
s32 cur_obj_has_model(u16 modelID); s32 cur_obj_has_model(u16 modelID);
void cur_obj_align_gfx_with_floor(void); void cur_obj_align_gfx_with_floor(void);
s32 mario_is_within_rectangle(s16 minX, s16 maxX, s16 minZ, s16 maxZ); s32 mario_is_within_rectangle(s16 minX, s16 maxX, s16 minZ, s16 maxZ);