mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-26 20:11:42 +00:00
Synchronized Ukiki
This commit is contained in:
parent
aa345ede4d
commit
41295fb814
3 changed files with 75 additions and 34 deletions
|
|
@ -28,9 +28,11 @@ void handle_hat_ukiki_reset(void) {
|
|||
*/
|
||||
s32 is_hat_ukiki_and_mario_has_hat(void) {
|
||||
if (o->oBehParams2ndByte == UKIKI_HAT) {
|
||||
if (does_mario_have_hat(gMarioState)) {
|
||||
return TRUE;
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!is_player_active(&gMarioStates[i])) { continue; }
|
||||
if (!does_mario_have_hat(&gMarioStates[i])) { return FALSE; }
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -122,17 +124,21 @@ void idle_ukiki_taunt(void) {
|
|||
* standing around.
|
||||
*/
|
||||
void ukiki_act_idle(void) {
|
||||
struct Object* player = nearest_player_to_object(o);
|
||||
int distanceToPlayer = dist_between_objects(o, player);
|
||||
int angleToPlayer = obj_angle_to_object(o, player);
|
||||
|
||||
idle_ukiki_taunt();
|
||||
|
||||
if (is_hat_ukiki_and_mario_has_hat()) {
|
||||
if (o->oDistanceToMario > 700.0f && o->oDistanceToMario < 1000.0f) {
|
||||
if (distanceToPlayer > 700.0f && distanceToPlayer < 1000.0f) {
|
||||
o->oAction = UKIKI_ACT_RUN;
|
||||
} else if (o->oDistanceToMario <= 700.0f && 200.0f < o->oDistanceToMario) {
|
||||
if (abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) > 0x1000) {
|
||||
} else if (distanceToPlayer <= 700.0f && 200.0f < distanceToPlayer) {
|
||||
if (abs_angle_diff(angleToPlayer, o->oMoveAngleYaw) > 0x1000) {
|
||||
o->oAction = UKIKI_ACT_TURN_TO_MARIO;
|
||||
}
|
||||
}
|
||||
} else if (o->oDistanceToMario < 300.0f) {
|
||||
} else if (distanceToPlayer < 300.0f) {
|
||||
o->oAction = UKIKI_ACT_RUN;
|
||||
}
|
||||
|
||||
|
|
@ -142,17 +148,17 @@ void ukiki_act_idle(void) {
|
|||
|
||||
// Jump away from Mario after stealing his hat.
|
||||
if (o->oUkikiTextState == UKIKI_TEXT_STOLE_HAT) {
|
||||
o->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + 0x8000;
|
||||
o->oMoveAngleYaw = player->oMoveAngleYaw + 0x8000;
|
||||
|
||||
if (check_if_moving_over_floor(50.0f, 150.0f)) {
|
||||
o->oAction = UKIKI_ACT_JUMP;
|
||||
} else {
|
||||
o->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + 0x4000;
|
||||
o->oMoveAngleYaw = player->oMoveAngleYaw + 0x4000;
|
||||
|
||||
if (check_if_moving_over_floor(50.0f, 150.0f)) {
|
||||
o->oAction = UKIKI_ACT_JUMP;
|
||||
} else {
|
||||
o->oMoveAngleYaw = gMarioObject->oMoveAngleYaw - 0x4000;
|
||||
o->oMoveAngleYaw = player->oMoveAngleYaw - 0x4000;
|
||||
if (check_if_moving_over_floor(50.0f, 150.0f)) {
|
||||
o->oAction = UKIKI_ACT_JUMP;
|
||||
}
|
||||
|
|
@ -206,10 +212,12 @@ void ukiki_act_wait_to_respawn(void) {
|
|||
* part of the ukiki_act_go_to_cage action.
|
||||
*/
|
||||
void ukiki_act_unused_turn(void) {
|
||||
struct Object* player = nearest_player_to_object(o);
|
||||
int angleToPlayer = obj_angle_to_object(o, player);
|
||||
idle_ukiki_taunt();
|
||||
|
||||
if (o->oSubAction == UKIKI_SUB_ACT_TAUNT_JUMP_CLAP) {
|
||||
cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400);
|
||||
cur_obj_rotate_yaw_toward(angleToPlayer, 0x400);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +225,9 @@ void ukiki_act_unused_turn(void) {
|
|||
* Turns ukiki to face towards Mario while moving with slow forward velocity.
|
||||
*/
|
||||
void ukiki_act_turn_to_mario(void) {
|
||||
struct Object* player = nearest_player_to_object(o);
|
||||
int distanceToPlayer = dist_between_objects(o, player);
|
||||
int angleToPlayer = obj_angle_to_object(o, player);
|
||||
s32 facingMario;
|
||||
|
||||
// Initialize the action with a random fVel from 2-5.
|
||||
|
|
@ -226,17 +237,17 @@ void ukiki_act_turn_to_mario(void) {
|
|||
|
||||
cur_obj_init_animation_with_sound(UKIKI_ANIM_TURN);
|
||||
|
||||
facingMario = cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x800);
|
||||
facingMario = cur_obj_rotate_yaw_toward(angleToPlayer, 0x800);
|
||||
|
||||
if (facingMario) {
|
||||
o->oAction = UKIKI_ACT_IDLE;
|
||||
}
|
||||
|
||||
if (is_hat_ukiki_and_mario_has_hat()){
|
||||
if (o->oDistanceToMario > 500.0f) {
|
||||
if (distanceToPlayer > 500.0f) {
|
||||
o->oAction = UKIKI_ACT_RUN;
|
||||
}
|
||||
} else if (o->oDistanceToMario < 300.0f) {
|
||||
} else if (distanceToPlayer < 300.0f) {
|
||||
o->oAction = UKIKI_ACT_RUN;
|
||||
}
|
||||
}
|
||||
|
|
@ -245,12 +256,17 @@ void ukiki_act_turn_to_mario(void) {
|
|||
* Ukiki either runs away away from Mario or towards him if stealing Mario's cap.
|
||||
*/
|
||||
void ukiki_act_run(void) {
|
||||
struct MarioState* marioState = nearest_mario_state_to_object(o);
|
||||
struct Object* player = marioState->marioObj;
|
||||
int distanceToPlayer = dist_between_objects(o, player);
|
||||
int angleToPlayer = obj_angle_to_object(o, player);
|
||||
|
||||
s32 fleeMario = TRUE;
|
||||
s16 goalYaw = o->oAngleToMario + 0x8000;
|
||||
s16 goalYaw = angleToPlayer + 0x8000;
|
||||
|
||||
if (is_hat_ukiki_and_mario_has_hat()) {
|
||||
fleeMario = FALSE;
|
||||
goalYaw = o->oAngleToMario;
|
||||
goalYaw = angleToPlayer;
|
||||
}
|
||||
|
||||
if (o->oTimer == 0) {
|
||||
|
|
@ -262,18 +278,18 @@ void ukiki_act_run(void) {
|
|||
|
||||
//! @bug (Ukikispeedia) This function sets forward speed to 0.9 * Mario's
|
||||
//! forward speed, which means ukiki can move at hyperspeed rates.
|
||||
cur_obj_set_vel_from_mario_vel(&gMarioStates[0], 20.0f, 0.9f);
|
||||
cur_obj_set_vel_from_mario_vel(marioState, 20.0f, 0.9f);
|
||||
|
||||
if (fleeMario) {
|
||||
if (o->oDistanceToMario > o->oUkikiChaseFleeRange) {
|
||||
if (distanceToPlayer > o->oUkikiChaseFleeRange) {
|
||||
o->oAction = UKIKI_ACT_TURN_TO_MARIO;
|
||||
}
|
||||
} else if (o->oDistanceToMario < o->oUkikiChaseFleeRange) {
|
||||
} else if (distanceToPlayer < o->oUkikiChaseFleeRange) {
|
||||
o->oAction = UKIKI_ACT_TURN_TO_MARIO;
|
||||
}
|
||||
|
||||
if (fleeMario) {
|
||||
if (o->oDistanceToMario < 200.0f) {
|
||||
if (distanceToPlayer < 200.0f) {
|
||||
if((o->oMoveFlags & OBJ_MOVE_HIT_WALL) &&
|
||||
is_mario_moving_fast_or_in_air(10)) {
|
||||
o->oAction = UKIKI_ACT_JUMP;
|
||||
|
|
@ -340,6 +356,10 @@ u8 ukiki_act_go_to_cage_continue_dialog(void) { return o->oAction == UKIKI_ACT_G
|
|||
* our death. Ukiki is a tad suicidal.
|
||||
*/
|
||||
void ukiki_act_go_to_cage(void) {
|
||||
struct MarioState* marioState = nearest_mario_state_to_object(o);
|
||||
struct Object* player = marioState->marioObj;
|
||||
int angleToPlayer = obj_angle_to_object(o, player);
|
||||
|
||||
struct Object* obj;
|
||||
f32 latDistToCage = 0.0f;
|
||||
s16 yawToCage = 0;
|
||||
|
|
@ -374,7 +394,7 @@ void ukiki_act_go_to_cage(void) {
|
|||
|
||||
case UKIKI_SUB_ACT_CAGE_WAIT_FOR_MARIO:
|
||||
cur_obj_init_animation_with_sound(UKIKI_ANIM_JUMP_CLAP);
|
||||
cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400);
|
||||
cur_obj_rotate_yaw_toward(angleToPlayer, 0x400);
|
||||
|
||||
if (cur_obj_can_mario_activate_textbox(&gMarioStates[0], 200.0f, 30.0f, 0x7FFF)) {
|
||||
o->oSubAction++; // fallthrough
|
||||
|
|
@ -385,8 +405,9 @@ void ukiki_act_go_to_cage(void) {
|
|||
case UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO:
|
||||
cur_obj_init_animation_with_sound(UKIKI_ANIM_HANDSTAND);
|
||||
|
||||
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, DIALOG_080, ukiki_act_go_to_cage_continue_dialog)) {
|
||||
if (should_start_or_continue_dialog(marioState, o) && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 3, 1, CUTSCENE_DIALOG, DIALOG_080, ukiki_act_go_to_cage_continue_dialog)) {
|
||||
o->oSubAction++;
|
||||
network_send_object_reliability(o, TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -519,10 +540,13 @@ static u8 cage_ukiki_held_default_continue_dialog(void) {
|
|||
* Called by the main behavior function for the cage ukiki whenever it is held.
|
||||
*/
|
||||
void cage_ukiki_held_loop(void) {
|
||||
struct MarioState* heldByMario = &gMarioStates[o->heldByPlayerIndex];
|
||||
if (heldByMario->playerIndex != 0) { return; }
|
||||
|
||||
if (o->oPosY - o->oHomeY > -100.0f) {
|
||||
switch(o->oUkikiTextState) {
|
||||
case UKIKI_TEXT_DEFAULT:
|
||||
if (set_mario_npc_dialog(&gMarioStates[0], 2, cage_ukiki_held_default_continue_dialog) == 2) {
|
||||
if (set_mario_npc_dialog(heldByMario, 2, cage_ukiki_held_default_continue_dialog) == 2) {
|
||||
create_dialog_box_with_response(DIALOG_079);
|
||||
o->oUkikiTextState = UKIKI_TEXT_CAGE_TEXTBOX;
|
||||
}
|
||||
|
|
@ -530,7 +554,7 @@ void cage_ukiki_held_loop(void) {
|
|||
|
||||
case UKIKI_TEXT_CAGE_TEXTBOX:
|
||||
if (gDialogResponse != 0) {
|
||||
set_mario_npc_dialog(&gMarioStates[0], 0, NULL);
|
||||
set_mario_npc_dialog(heldByMario, 0, NULL);
|
||||
if (gDialogResponse == 1) {
|
||||
o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY;
|
||||
o->oUkikiTextState = UKIKI_TEXT_GO_TO_CAGE;
|
||||
|
|
@ -567,16 +591,25 @@ u8 hat_ukiki_held_loop_2(void) { return o->oHeldState == HELD_HELD && o->oUkikiT
|
|||
* Called by the main behavior function for the hat ukiki whenever it is held.
|
||||
*/
|
||||
void hat_ukiki_held_loop(void) {
|
||||
struct MarioState* heldByMario = &gMarioStates[o->heldByPlayerIndex];
|
||||
if (heldByMario->playerIndex != 0) { return; }
|
||||
|
||||
// other player must catch ukiki
|
||||
if ((o->oUkikiHasHat & UKIKI_HAT_ON) && does_mario_have_hat(heldByMario)) {
|
||||
o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(o->oUkikiTextState) {
|
||||
case UKIKI_TEXT_DEFAULT:
|
||||
if (mario_lose_cap_to_enemy(&gMarioStates[0], 2)) {
|
||||
if (mario_lose_cap_to_enemy(heldByMario, 2)) {
|
||||
o->oUkikiTextState = UKIKI_TEXT_STEAL_HAT;
|
||||
o->oUkikiHasHat |= UKIKI_HAT_ON;
|
||||
} else {}
|
||||
break;
|
||||
|
||||
case UKIKI_TEXT_STEAL_HAT:
|
||||
if (cur_obj_update_dialog(&gMarioStates[0], 2, 2, DIALOG_100, 0, hat_ukiki_held_loop_1)) {
|
||||
if (should_start_or_continue_dialog(heldByMario, o) && cur_obj_update_dialog(heldByMario, 2, 2, DIALOG_100, 0, hat_ukiki_held_loop_1)) {
|
||||
o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY;
|
||||
o->oUkikiTextState = UKIKI_TEXT_STOLE_HAT;
|
||||
}
|
||||
|
|
@ -586,9 +619,9 @@ void hat_ukiki_held_loop(void) {
|
|||
break;
|
||||
|
||||
case UKIKI_TEXT_HAS_HAT:
|
||||
if (cur_obj_update_dialog(&gMarioStates[0], 2, 18, DIALOG_101, 0, hat_ukiki_held_loop_2)) {
|
||||
mario_retrieve_cap();
|
||||
set_mario_npc_dialog(&gMarioStates[0], 0, NULL);
|
||||
if (should_start_or_continue_dialog(heldByMario, o) && cur_obj_update_dialog(heldByMario, 2, 18, DIALOG_101, 0, hat_ukiki_held_loop_2)) {
|
||||
mario_retrieve_cap(heldByMario);
|
||||
set_mario_npc_dialog(heldByMario, 0, NULL);
|
||||
o->oUkikiHasHat &= ~UKIKI_HAT_ON;
|
||||
o->oUkikiTextState = UKIKI_TEXT_GAVE_HAT_BACK;
|
||||
}
|
||||
|
|
@ -611,6 +644,12 @@ void bhv_ukiki_init(void) {
|
|||
o->oUkikiHasHat |= UKIKI_HAT_ON;
|
||||
}
|
||||
}
|
||||
|
||||
network_init_object(o, 4000.0f);
|
||||
network_init_object_field(o, &o->oUkikiTauntCounter);
|
||||
network_init_object_field(o, &o->oUkikiChaseFleeRange);
|
||||
network_init_object_field(o, &o->oUkikiCageSpinTimer);
|
||||
network_init_object_field(o, &o->oIntangibleTimer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -618,6 +657,8 @@ void bhv_ukiki_init(void) {
|
|||
* dependent on the held state and whick ukiki it is (cage or hat).
|
||||
*/
|
||||
void bhv_ukiki_loop(void) {
|
||||
struct Object* heldByPlayer = gMarioStates[o->heldByPlayerIndex].marioObj;
|
||||
|
||||
switch(o->oHeldState) {
|
||||
case HELD_FREE:
|
||||
//! @bug (PARTIAL_UPDATE)
|
||||
|
|
@ -627,7 +668,7 @@ void bhv_ukiki_loop(void) {
|
|||
|
||||
case HELD_HELD:
|
||||
cur_obj_unrender_and_reset_state(UKIKI_ANIM_HELD, 0);
|
||||
obj_copy_pos(o, gMarioObject);
|
||||
obj_copy_pos(o, heldByPlayer);
|
||||
|
||||
if (o->oBehParams2ndByte == UKIKI_HAT) {
|
||||
hat_ukiki_held_loop();
|
||||
|
|
|
|||
|
|
@ -409,11 +409,11 @@ u32 mario_lose_cap_to_enemy(struct MarioState* m, u32 arg) {
|
|||
return wasWearingCap;
|
||||
}
|
||||
|
||||
void mario_retrieve_cap(void) {
|
||||
mario_drop_held_object(gMarioState);
|
||||
void mario_retrieve_cap(struct MarioState* m) {
|
||||
mario_drop_held_object(m);
|
||||
save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI);
|
||||
gMarioState->flags &= ~MARIO_CAP_ON_HEAD;
|
||||
gMarioState->flags |= MARIO_NORMAL_CAP | MARIO_CAP_IN_HAND;
|
||||
m->flags &= ~MARIO_CAP_ON_HEAD;
|
||||
m->flags |= MARIO_NORMAL_CAP | MARIO_CAP_IN_HAND;
|
||||
}
|
||||
|
||||
u32 able_to_grab_object(struct MarioState *m, UNUSED struct Object *o) {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void mario_stop_riding_and_holding(struct MarioState *m);
|
|||
u32 does_mario_have_hat(struct MarioState *m);
|
||||
void mario_blow_off_cap(struct MarioState *m, f32 capSpeed);
|
||||
u32 mario_lose_cap_to_enemy(struct MarioState* m, u32 arg);
|
||||
void mario_retrieve_cap(void);
|
||||
void mario_retrieve_cap(struct MarioState* m);
|
||||
struct Object *mario_get_collided_object(struct MarioState *m, u32 interactType);
|
||||
u32 mario_check_object_grab(struct MarioState *m);
|
||||
u32 get_door_save_file_flag(struct Object *door);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue