mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
Grand star fix and etc (#47)
A ton of Bowser fixes, Grand star included. Fixed Grand Star cutscene syncing. Partially fix grand star syncing after joining late. Fix Bowser's intro cutscene always playing even if you joined after the first person. Hopefully fixed Bowser's state getting interrupted mid-fight just a bit. Add nothing state sanity check, and send object reliability when cutscene is finished. Fix ownership override.
This commit is contained in:
parent
9d16605c3b
commit
a1af1c2ffb
7 changed files with 145 additions and 48 deletions
|
@ -1,19 +1,22 @@
|
|||
// bowser.c.inc
|
||||
static u32 networkBowserAnimationIndex = 0;
|
||||
static u8 bowserIsDying = FALSE;
|
||||
static u8 bowserCutscenePlayed = FALSE;
|
||||
static u8 bowserIsCutscenePlayer = FALSE;
|
||||
|
||||
void bowser_tail_anchor_act_0(void) {
|
||||
struct Object* bowser = o->parentObj;
|
||||
struct Object* player = nearest_player_to_object(o);
|
||||
cur_obj_become_tangible();
|
||||
cur_obj_scale(1.0f);
|
||||
if (bowser->oAction == 19)
|
||||
if (bowser->oAction == 5 || bowser->oAction == 6 || bowser->oAction == 19 || bowser->oAction == 20) {
|
||||
bowser->oIntangibleTimer = -1;
|
||||
else if (obj_check_if_collided_with_object(o, player)) {
|
||||
} else if (obj_check_if_collided_with_object(o, player)) {
|
||||
bowser->oIntangibleTimer = 0;
|
||||
o->oAction = 2;
|
||||
} else
|
||||
} else {
|
||||
bowser->oIntangibleTimer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void bowser_tail_anchor_act_1(void) {
|
||||
|
@ -177,31 +180,37 @@ s32 bowser_set_anim_look_up_and_walk(void) {
|
|||
s32 bowser_set_anim_slow_gait(void) {
|
||||
o->oForwardVel = 3.0f;
|
||||
cur_obj_init_animation_with_sound(13);
|
||||
if (cur_obj_check_if_near_animation_end())
|
||||
if (cur_obj_check_if_near_animation_end()) {
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 bowser_set_anim_look_down(void) {
|
||||
cur_obj_init_animation_with_sound(14);
|
||||
if (cur_obj_check_anim_frame(20))
|
||||
if (cur_obj_check_anim_frame(20)) {
|
||||
o->oForwardVel = 0.0f;
|
||||
if (cur_obj_check_if_near_animation_end())
|
||||
}
|
||||
if (cur_obj_check_if_near_animation_end()) {
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bowser_initialize_action(void) {
|
||||
if (o->oBowserUnk88 == 0)
|
||||
if (o->oBowserUnk88 == 0 && !bowserCutscenePlayed) {
|
||||
o->oAction = 5;
|
||||
else if (o->oBowserUnk88 == 1)
|
||||
} else if (o->oBowserUnk88 == 1 && !bowserCutscenePlayed) {
|
||||
o->oAction = 6;
|
||||
else if (o->oBehParams2ndByte == 1)
|
||||
} else if (o->oBehParams2ndByte == 1) {
|
||||
bowserCutscenePlayed = TRUE;
|
||||
o->oAction = 13;
|
||||
else
|
||||
if (bowserIsCutscenePlayer) { network_send_object_reliability(o, TRUE); }
|
||||
} else {
|
||||
bowserCutscenePlayed = TRUE;
|
||||
o->oAction = 0;
|
||||
if (bowserIsCutscenePlayer) { network_send_object_reliability(o, TRUE); }
|
||||
}
|
||||
}
|
||||
|
||||
void bowser_act_text_wait(void) // not much
|
||||
|
@ -374,12 +383,13 @@ void bowser_act_default(void) // only lasts one frame
|
|||
o->oAngleVelYaw = 0;
|
||||
o->oForwardVel = 0.0f;
|
||||
o->oVelY = 0.0f;
|
||||
if (BITDW)
|
||||
if (BITDW) {
|
||||
bowser_bitdw_act_controller();
|
||||
else if (BITFS)
|
||||
} else if (BITFS) {
|
||||
bowser_bitfs_act_controller();
|
||||
else
|
||||
} else {
|
||||
bowser_bits_act_controller();
|
||||
}
|
||||
// Action 14 commonly follows
|
||||
}
|
||||
|
||||
|
@ -850,12 +860,14 @@ void bowser_spawn_grand_star_key(void) {
|
|||
reward = (prevReward != NULL) ? prevReward : spawn_object(o, MODEL_STAR, bhvGrandStar);
|
||||
gSecondCameraFocus = reward;
|
||||
|
||||
if (prevReward == NULL && reward != NULL) {
|
||||
if (network_owns_object(o) && prevReward == NULL && reward != NULL) {
|
||||
// set the home position
|
||||
reward->oHomeX = reward->oPosX;
|
||||
reward->oHomeY = reward->oPosY;
|
||||
reward->oHomeZ = reward->oPosZ;
|
||||
|
||||
network_set_sync_id(reward);
|
||||
|
||||
struct Object* spawn_objects[] = { reward };
|
||||
u32 models[] = { MODEL_STAR };
|
||||
network_send_spawn_objects(spawn_objects, models, 1);
|
||||
|
@ -921,7 +933,6 @@ s32 bowser_dead_wait_for_mario(void) {
|
|||
|
||||
s32 bowser_dead_twirl_into_trophy(void) {
|
||||
bowserIsDying = TRUE;
|
||||
s32 ret = 0;
|
||||
if (o->header.gfx.scale[0] < 0.8)
|
||||
o->oAngleVelYaw += 0x80;
|
||||
if (o->header.gfx.scale[0] > 0.2) {
|
||||
|
@ -933,11 +944,11 @@ s32 bowser_dead_twirl_into_trophy(void) {
|
|||
o->oGravity = 0.0f;
|
||||
}
|
||||
if (o->header.gfx.scale[1] < 0.5)
|
||||
ret = 1;
|
||||
return 1;
|
||||
o->oMoveAngleYaw += o->oAngleVelYaw;
|
||||
if (o->oOpacity >= 3)
|
||||
o->oOpacity -= 2;
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bowser_dead_hide(void) {
|
||||
|
@ -1094,6 +1105,9 @@ void bowser_act_ride_tilting_platform(void) {
|
|||
cur_obj_extend_animation_if_at_end();
|
||||
}
|
||||
|
||||
void bowser_act_nothing(void) {
|
||||
|
||||
}
|
||||
|
||||
s32 bowser_check_fallen_off_stage(void) // bowser off stage?
|
||||
{
|
||||
|
@ -1114,7 +1128,8 @@ void (*sBowserActions[])(void) = { bowser_act_default, bowser_act_thrown_droppe
|
|||
bowser_act_dead, bowser_act_text_wait, bowser_act_intro_walk, bowser_act_charge_mario,
|
||||
bowser_act_spit_fire_into_sky, bowser_act_spit_fire_onto_floor, bowser_act_hit_edge, bowser_act_turn_from_edge,
|
||||
bowser_act_hit_mine, bowser_act_jump, bowser_act_walk_to_mario, bowser_act_breath_fire,
|
||||
bowser_act_teleport, bowser_act_jump_towards_mario, bowser_act_unused_slow_walk, bowser_act_ride_tilting_platform };
|
||||
bowser_act_teleport, bowser_act_jump_towards_mario, bowser_act_unused_slow_walk, bowser_act_ride_tilting_platform,
|
||||
bowser_act_nothing, };
|
||||
struct SoundState D_8032F5B8[] = { { 0, 0, 0, NO_SOUND },
|
||||
{ 0, 0, 0, NO_SOUND },
|
||||
{ 0, 0, 0, NO_SOUND },
|
||||
|
@ -1257,8 +1272,13 @@ void bhv_bowser_loop(void) {
|
|||
geo_obj_init_animation(&o->header.gfx, &anim);
|
||||
}
|
||||
}
|
||||
|
||||
// If Bowser isn't in a cutscene, It's been played already.
|
||||
if (!bowserCutscenePlayed && (o->oAction != 5 && o->oAction != 6 && o->oAction != 20)) {
|
||||
bowserCutscenePlayed = TRUE;
|
||||
}
|
||||
|
||||
s16 angleToMario; // AngleToMario from Bowser's perspective
|
||||
s16 angleToMario; // AngleToMario from Bowser's perspective
|
||||
s16 angleToCentre; // AngleToCentre from Bowser's perspective
|
||||
|
||||
o->oBowserDistToCentre = sqrtf(o->oPosX * o->oPosX + o->oPosZ * o->oPosZ);
|
||||
|
@ -1314,6 +1334,13 @@ void bhv_bowser_loop(void) {
|
|||
}
|
||||
|
||||
void bhv_bowser_override_ownership(u8* shouldOverride, u8* shouldOwn) {
|
||||
// Nothing state sanity check.
|
||||
if (o->oAction == 20) {
|
||||
*shouldOverride = TRUE;
|
||||
*shouldOwn = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
// tilting platform
|
||||
static u8 tiltingTimer = 0;
|
||||
if (o->oAction == 19) { tiltingTimer = 5; }
|
||||
|
@ -1327,6 +1354,7 @@ void bhv_bowser_override_ownership(u8* shouldOverride, u8* shouldOwn) {
|
|||
static u8 bhv_bowser_ignore_if_true(void) {
|
||||
if (bowserIsDying) { return TRUE; }
|
||||
if (o->oAction == 19) { return TRUE; } // let the platform get to a stable state
|
||||
if (bowserIsCutscenePlayer && (o->oAction == 5 || o->oAction == 6)) { return TRUE; } // Ignore updates till our cutscene is done.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -1346,21 +1374,32 @@ void bhv_bowser_init(void) {
|
|||
o->oBowserUnk1B2 = D_8032F690[level];
|
||||
o->oHealth = D_8032F694[level];
|
||||
cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_INIT);
|
||||
o->oAction = 5;
|
||||
o->oBowserUnk1AE = 0;
|
||||
o->oBowserEyesShut = 0;
|
||||
|
||||
struct SyncObject* so = network_init_object(o, 8000.0f);
|
||||
if (so) {
|
||||
so->override_ownership = bhv_bowser_override_ownership;
|
||||
so->ignore_if_true = bhv_bowser_ignore_if_true;
|
||||
so->fullObjectSync = TRUE;
|
||||
network_init_object_field_with_size(o, &o->header.gfx.node.flags, 16);
|
||||
network_init_object_field_with_size(o, &o->header.gfx.animInfo.animFrame, 16);
|
||||
network_init_object_field(o, &networkBowserAnimationIndex);
|
||||
network_init_object_field(o, &o->header.gfx.scale[0]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[1]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[2]);
|
||||
bowserCutscenePlayed = FALSE;
|
||||
|
||||
// Make sure we're the first to trigger Bowser.
|
||||
if (!is_other_player_active()) {
|
||||
bowserIsCutscenePlayer = TRUE;
|
||||
o->oAction = 5; // bowser_act_text_wait
|
||||
} else { // If we aren't do nothing till we get our sync.
|
||||
bowserIsCutscenePlayer = FALSE;
|
||||
o->oAction = 20; // bowser_act_nothing
|
||||
}
|
||||
|
||||
if (!network_sync_object_initialized(o)) {
|
||||
struct SyncObject* so = network_init_object(o, 8000.0f);
|
||||
if (so) {
|
||||
so->override_ownership = bhv_bowser_override_ownership;
|
||||
so->ignore_if_true = bhv_bowser_ignore_if_true;
|
||||
so->fullObjectSync = TRUE;
|
||||
network_init_object_field_with_size(o, &o->header.gfx.node.flags, 16);
|
||||
network_init_object_field_with_size(o, &o->header.gfx.animInfo.animFrame, 16);
|
||||
network_init_object_field(o, &networkBowserAnimationIndex);
|
||||
network_init_object_field(o, &o->header.gfx.scale[0]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[1]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// grand_star.c.inc
|
||||
|
||||
s32 arc_to_goal_pos(Vec3f a0, Vec3f a1, f32 yVel, f32 gravity) {
|
||||
f32 dx = a0[0] - a1[0];
|
||||
f32 dz = a0[2] - a1[2];
|
||||
s32 arc_to_goal_pos(Vec3f empty, Vec3f pos, f32 yVel, f32 gravity) {
|
||||
f32 dx = empty[0] - pos[0];
|
||||
f32 dz = empty[2] - pos[2];
|
||||
f32 planarDist = sqrtf(dx * dx + dz * dz);
|
||||
o->oMoveAngleYaw = atan2s(dz, dx);
|
||||
o->oVelY = yVel;
|
||||
|
@ -22,12 +22,15 @@ void bhv_grand_star_init(void) {
|
|||
struct Object *other = cur_obj_nearest_object_with_behavior(bhvGrandStar);
|
||||
if (other == NULL) {
|
||||
if (!network_sync_object_initialized(o)) {
|
||||
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
|
||||
struct SyncObject *so = network_init_object(o, 4000.0f);
|
||||
if (so) {
|
||||
network_init_object_field_with_size(o, &o->activeFlags, 16);
|
||||
network_init_object_field(o, &o->header.gfx.scale[0]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[1]);
|
||||
network_init_object_field(o, &o->header.gfx.scale[2]);
|
||||
network_init_object_field(o, &o->oPrevAction);
|
||||
network_init_object_field(o, &o->oAction);
|
||||
network_init_object_field(o, &o->oSubAction);
|
||||
network_init_object_field(o, &o->oInteractStatus);
|
||||
network_init_object_field(o, &o->oTimer);
|
||||
network_init_object_field(o, &o->oHomeX);
|
||||
network_init_object_field(o, &o->oHomeY);
|
||||
|
@ -41,7 +44,7 @@ void bhv_grand_star_init(void) {
|
|||
network_init_object_field(o, &o->oAngleVelYaw);
|
||||
network_init_object_field(o, &o->oMoveAngleYaw);
|
||||
network_init_object_field(o, &o->oFaceAngleYaw);
|
||||
network_init_object_field(o, &o->oGrandStarUnk108);
|
||||
network_init_object_field(o, &o->oGraphYOffset);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -66,12 +69,12 @@ void bhv_grand_star_loop(void) {
|
|||
spawn_sparkle_particles(3, 200, 80, -60);
|
||||
} else if (o->oAction == 1) {
|
||||
if (o->oTimer == 0) {
|
||||
Vec3f sp28;
|
||||
sp28[0] = sp28[1] = sp28[2] = 0.0f;
|
||||
Vec3f empty;
|
||||
empty[0] = empty[1] = empty[2] = 0.0f;
|
||||
|
||||
cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR);
|
||||
cutscene_object(CUTSCENE_STAR_SPAWN, o);
|
||||
o->oGrandStarUnk108 = arc_to_goal_pos(sp28, &o->oPosX, 80.0f, -2.0f);
|
||||
o->oGrandStarUnk108 = arc_to_goal_pos(empty, &o->oPosX, 80.0f, -2.0f);
|
||||
}
|
||||
cur_obj_move_using_fvel_and_gravity();
|
||||
if (o->oSubAction == 0) {
|
||||
|
@ -92,13 +95,25 @@ void bhv_grand_star_loop(void) {
|
|||
cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR_JUMP);
|
||||
}
|
||||
spawn_sparkle_particles(3, 200, 80, -60);
|
||||
} else {
|
||||
} else if (o->oAction == 2) {
|
||||
// Make our object tangible.
|
||||
cur_obj_become_tangible();
|
||||
// Check for if the jumbo star has been collected.
|
||||
if (o->oInteractStatus & INT_STATUS_INTERACTED) {
|
||||
// Make sure we're in the jumbo star cutscene.
|
||||
if (gMarioStates[0].action != ACT_JUMBO_STAR_CUTSCENE) {
|
||||
set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0);
|
||||
}
|
||||
// Increment our action, The star despawns next action.
|
||||
o->oAction++;
|
||||
}
|
||||
} else {
|
||||
// The star cutscene has started, Make sure the star is deleted
|
||||
// if it isn't already deactivated.
|
||||
if (o->activeFlags != ACTIVE_FLAG_DEACTIVATED) {
|
||||
// Mark our object for deletion.
|
||||
obj_mark_for_deletion(o);
|
||||
// Reset our interactive status.
|
||||
o->oInteractStatus = 0;
|
||||
}
|
||||
}
|
||||
|
@ -108,4 +123,4 @@ void bhv_grand_star_loop(void) {
|
|||
o->oFaceAngleYaw += o->oAngleVelYaw;
|
||||
cur_obj_scale(2.0f);
|
||||
o->oGraphYOffset = 110.0f;
|
||||
}
|
||||
}
|
|
@ -3336,7 +3336,8 @@ void reset_camera(struct Camera *c) {
|
|||
}
|
||||
|
||||
void init_camera(struct Camera *c) {
|
||||
struct Surface *floor = 0;
|
||||
struct Surface *floor = NULL;
|
||||
struct Object *obj = NULL;
|
||||
Vec3f marioOffset;
|
||||
s32 i;
|
||||
|
||||
|
@ -3391,18 +3392,34 @@ void init_camera(struct Camera *c) {
|
|||
case LEVEL_BOWSER_1:
|
||||
#ifndef VERSION_JP
|
||||
if (gCurrDemoInput == NULL) {
|
||||
// Make sure Bowser is in a state that we'd start speaking to him in.
|
||||
obj = find_object_with_behavior(bhvBowser);
|
||||
if (obj != NULL && obj->oAction != 5) { break; }
|
||||
|
||||
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
|
||||
} else if (gSecondCameraFocus != NULL) {
|
||||
gSecondCameraFocus->oBowserUnk88 = 2;
|
||||
}
|
||||
#else
|
||||
// Make sure Bowser is in a state that we'd start speaking to him in.
|
||||
obj = find_object_with_behavior(bhvBowser);
|
||||
if (obj != NULL && obj->oAction != 5) { break; }
|
||||
|
||||
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
|
||||
#endif
|
||||
break;
|
||||
case LEVEL_BOWSER_2:
|
||||
// Make sure Bowser is in a state that we'd start speaking to him in.
|
||||
obj = find_object_with_behavior(bhvBowser);
|
||||
if (obj != NULL && obj->oAction != 5) { break; }
|
||||
|
||||
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
|
||||
break;
|
||||
case LEVEL_BOWSER_3:
|
||||
// Make sure Bowser is in a state that we'd start speaking to him in.
|
||||
obj = find_object_with_behavior(bhvBowser);
|
||||
if (obj != NULL && obj->oAction != 5) { break; }
|
||||
|
||||
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
|
||||
break;
|
||||
|
||||
|
|
|
@ -536,6 +536,14 @@ u8 is_player_active(struct MarioState* m) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
u8 is_other_player_active(void) {
|
||||
for (s32 i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct MarioState *m = &gMarioStates[i];
|
||||
if (is_player_active(m)) { return TRUE; }
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
u8 is_player_in_local_area(struct MarioState* m) {
|
||||
if (gNetworkType == NT_NONE && m == &gMarioStates[0]) { return TRUE; }
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[m->playerIndex];
|
||||
|
|
|
@ -163,6 +163,7 @@ void bhv_rr_cruiser_wing_init(void);
|
|||
void bhv_rr_cruiser_wing_loop(void);
|
||||
struct Object* spawn_default_star(f32 sp20, f32 sp24, f32 sp28);
|
||||
u8 is_player_active(struct MarioState* m);
|
||||
u8 is_other_player_active(void);
|
||||
u8 is_player_in_local_area(struct MarioState* m);
|
||||
struct MarioState* nearest_mario_state_to_object(struct Object* obj);
|
||||
struct Object* nearest_player_to_object(struct Object* obj);
|
||||
|
|
|
@ -1036,6 +1036,22 @@ s32 count_objects_with_behavior(const BehaviorScript *behavior) {
|
|||
return count;
|
||||
}
|
||||
|
||||
struct Object *find_object_with_behavior(const BehaviorScript *behavior) {
|
||||
uintptr_t *behaviorAddr = segmented_to_virtual(behavior);
|
||||
struct ObjectNode *listHead = &gObjectLists[get_object_list_from_behavior(behaviorAddr)];
|
||||
struct ObjectNode *obj = listHead->next;
|
||||
|
||||
while (listHead != obj) {
|
||||
if (((struct Object *) obj)->behavior == behaviorAddr) {
|
||||
return (struct Object *)obj;
|
||||
}
|
||||
|
||||
obj = obj->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Object *cur_obj_find_nearby_held_actor(const BehaviorScript *behavior, f32 maxDist) {
|
||||
const BehaviorScript *behaviorAddr = segmented_to_virtual(behavior);
|
||||
struct ObjectNode *listHead;
|
||||
|
|
|
@ -146,6 +146,7 @@ f32 cur_obj_dist_to_nearest_object_with_behavior(const BehaviorScript* behavior)
|
|||
struct Object* cur_obj_find_nearest_pole(void);
|
||||
struct Object *cur_obj_find_nearest_object_with_behavior(const BehaviorScript * behavior, f32 *dist);
|
||||
u16 cur_obj_count_objects_with_behavior(const BehaviorScript* behavior, f32 dist);
|
||||
struct Object *find_object_with_behavior(const BehaviorScript *behavior);
|
||||
struct Object *find_unimportant_object(void);
|
||||
s32 count_unimportant_objects(void);
|
||||
s32 count_objects_with_behavior(const BehaviorScript *behavior);
|
||||
|
|
Loading…
Reference in a new issue