Resynchronized Koopa the Quick and race timers for late join

This commit is contained in:
MysterD 2021-08-14 11:48:15 -07:00
parent b0267a5a31
commit ed95bd317b
7 changed files with 145 additions and 55 deletions

View file

@ -65,8 +65,32 @@ static struct KoopaTheQuickProperties sKoopaTheQuickProperties[] = {
{ DIALOG_009, DIALOG_031, thi_seg7_trajectory_koopa, { 7100, -1300, -6000 } }
};
static u32 koopaForceStartRace = FALSE;
static u32 koopaForceEndRace = FALSE;
static u32 koopaPathedStartWaypoint = 0;
static u32 koopaPathedPrevWaypoint = 0;
static u32 koopaShotFromCannon = 0;
static u8 koopaWasInRace = false;
static void bhv_koopa_the_quick_on_received_pre(u8 fromLocalIndex) {
koopaWasInRace = (o->oAction >= KOOPA_THE_QUICK_ACT_RACE);
}
static void bhv_koopa_the_quick_on_received_post(u8 fromLocalIndex) {
void* path = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path);
o->oPathedStartWaypoint = (struct Waypoint*)path + koopaPathedStartWaypoint;
o->oPathedPrevWaypoint = (struct Waypoint*)path + koopaPathedPrevWaypoint;
gMarioShotFromCannon = koopaShotFromCannon;
}
static void bhv_koopa_the_quick_on_sent_pre(void) {
void* path = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path);
koopaPathedStartWaypoint = ((void*)o->oPathedStartWaypoint - path) / sizeof(struct Waypoint*);
koopaPathedPrevWaypoint = ((void*)o->oPathedPrevWaypoint - path) / sizeof(struct Waypoint*);
koopaShotFromCannon = gMarioShotFromCannon;
}
void bhv_koopa_the_quick_override_ownership(u8* shouldOverride, u8* shouldOwn) {
*shouldOverride = TRUE;
*shouldOwn = (get_network_player_smallest_global() == gNetworkPlayerLocal);
}
/**
* Initialization function.
@ -84,18 +108,43 @@ void bhv_koopa_init(void) {
o->oKoopaTheQuickRaceIndex = o->oKoopaMovementType - KOOPA_BP_KOOPA_THE_QUICK_BASE;
o->oKoopaAgility = 4.0f;
cur_obj_scale(3.0f);
koopaForceStartRace = FALSE;
koopaForceEndRace = FALSE;
} else {
o->oKoopaAgility = 1.0f;
}
if (o->oKoopaMovementType >= KOOPA_BP_KOOPA_THE_QUICK_BASE) {
// koopa the quick
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
network_init_object_field(o, &koopaForceStartRace);
o->parentObj = cur_obj_nearest_object_with_behavior(bhvKoopaRaceEndpoint);
struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
so->on_received_pre = bhv_koopa_the_quick_on_received_pre;
so->on_received_post = bhv_koopa_the_quick_on_received_post;
so->on_sent_pre = bhv_koopa_the_quick_on_sent_pre;
so->override_ownership = bhv_koopa_the_quick_override_ownership;
network_init_object_field(o, &koopaPathedStartWaypoint);
network_init_object_field(o, &koopaPathedPrevWaypoint);
network_init_object_field(o, &koopaShotFromCannon);
network_init_object_field(o, &o->oPathedPrevWaypointFlags);
network_init_object_field(o, &o->oPathedTargetPitch);
network_init_object_field(o, &o->oPathedTargetYaw);
network_init_object_field(o, &o->oPosX);
network_init_object_field(o, &o->oPosY);
network_init_object_field(o, &o->oPosZ);
network_init_object_field(o, &o->oVelX);
network_init_object_field(o, &o->oVelY);
network_init_object_field(o, &o->oVelZ);
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oSubAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oKoopaAgility);
network_init_object_field(o, &o->parentObj->oKoopaRaceEndpointRaceBegun);
network_init_object_field(o, &o->parentObj->oKoopaRaceEndpointRaceStatus);
network_init_object_field(o, &o->oForwardVel);
network_init_object_field(o, &o->oMoveAngleYaw);
network_init_object_field(o, &o->areaTimer);
o->areaTimerType = AREA_TIMER_TYPE_MAXIMUM;
o->areaTimer = 0;
o->areaTimerDuration = 60;
} else {
// normal koopa
network_init_object(o, 4000.0f);
@ -567,19 +616,6 @@ static void koopa_the_quick_act_wait_before_race(void) {
}
}
static void koopa_the_quick_force_start_race(void) {
koopaForceStartRace = FALSE;
gMarioShotFromCannon = FALSE;
o->oAction = KOOPA_THE_QUICK_ACT_RACE;
o->oForwardVel = 0.0f;
o->parentObj = cur_obj_nearest_object_with_behavior(bhvKoopaRaceEndpoint);
o->oPathedStartWaypoint = o->oPathedPrevWaypoint = segmented_to_virtual(sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].path);
o->oKoopaTurningAwayFromWall = FALSE;
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; }
/**
@ -605,10 +641,7 @@ static void koopa_the_quick_act_show_init_text(void) {
o->oKoopaTurningAwayFromWall = FALSE;
o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR;
koopaForceStartRace = TRUE;
network_send_object(o);
koopaForceStartRace = FALSE;
;
} else if (response == 2) {
o->oAction = KOOPA_THE_QUICK_ACT_WAIT_BEFORE_RACE;
o->oKoopaTheQuickInitTextboxCooldown = 60;
@ -678,8 +711,10 @@ static void koopa_the_quick_act_race(void) {
// Hitbox is slightly larger while racing
cur_obj_push_mario_away_from_cylinder(180.0f, 300.0f);
struct Waypoint* lastPrevWaypoint = o->oPathedPrevWaypoint;
if (cur_obj_follow_path(0) == PATH_REACHED_END) {
o->oAction = KOOPA_THE_QUICK_ACT_DECELERATE;
if (network_owns_object(o)) { network_send_object(o); }
} else {
downhillSteepness = 1.0f + sins((s16)(f32) o->oPathedTargetPitch);
cur_obj_rotate_yaw_toward(o->oPathedTargetYaw, (s32)(o->oKoopaAgility * 150.0f));
@ -751,6 +786,10 @@ static void koopa_the_quick_act_race(void) {
}
}
}
if (lastPrevWaypoint != o->oPathedPrevWaypoint) {
if (network_owns_object(o)) { network_send_object(o); }
}
}
}
@ -764,6 +803,7 @@ static void koopa_the_quick_act_decelerate(void) {
if (cur_obj_check_if_near_animation_end()) {
o->oAction = KOOPA_THE_QUICK_ACT_STOP;
o->oForwardVel = 3.0f;
if (network_owns_object(o)) { network_send_object(o); }
}
}
@ -777,6 +817,7 @@ static void koopa_the_quick_act_stop(void) {
// KOOPA_SHELLED_ACT_STOPPED at the end
if (o->oAction == KOOPA_SHELLED_ACT_STOPPED) {
o->oAction = KOOPA_THE_QUICK_ACT_AFTER_RACE;
if (network_owns_object(o)) { network_send_object(o); }
}
}
@ -838,8 +879,6 @@ static void koopa_the_quick_update(void) {
cur_obj_update_floor_and_walls();
obj_update_blinking(&o->oKoopaBlinkTimer, 10, 15, 3);
if (koopaForceStartRace) { koopa_the_quick_force_start_race(); }
switch (o->oAction) {
case KOOPA_THE_QUICK_ACT_WAIT_BEFORE_RACE:
case KOOPA_THE_QUICK_ACT_UNUSED1:
@ -868,7 +907,9 @@ static void koopa_the_quick_update(void) {
}
}
cur_obj_push_mario_away_from_cylinder(140.0f, 300.0f);
if (cur_obj_is_last_nat_update_per_frame()) {
cur_obj_push_mario_away_from_cylinder(140.0f, 300.0f);
}
cur_obj_move_standard(-78);
}
@ -909,28 +950,10 @@ void bhv_koopa_update(void) {
obj_face_yaw_approach(o->oMoveAngleYaw, 0x600);
}
void koopa_the_quick_force_end_race(void) {
o->oKoopaRaceEndpointRaceEnded = TRUE;
level_control_timer(TIMER_CONTROL_STOP);
if (!o->oKoopaRaceEndpointKoopaFinished) {
play_race_fanfare();
}
koopaForceEndRace = FALSE;
}
/**
* Update function for bhvKoopaRaceEndpoint.
*/
void bhv_koopa_race_endpoint_update(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
network_init_object_field(o, &o->oKoopaRaceEndpointRaceStatus);
network_init_object_field(o, &koopaForceEndRace);
}
if (koopaForceEndRace) { koopa_the_quick_force_end_race(); }
if (o->oKoopaRaceEndpointRaceBegun && !o->oKoopaRaceEndpointRaceEnded) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
@ -945,9 +968,6 @@ void bhv_koopa_race_endpoint_update(void) {
} else {
o->oKoopaRaceEndpointRaceStatus = 1;
}
koopaForceEndRace = TRUE;
network_send_object(o);
koopaForceEndRace = FALSE;
}
}
}

View file

@ -180,26 +180,43 @@ s8 gInWarpCheckpoint = 0;
u8 unused3[4];
u8 unused4[2];
u32 gControlTimerStartNat = 0;
u32 gControlTimerStopNat = 0;
u8 level_control_timer_running(void) {
return sTimerRunning;
}
u16 level_control_timer(s32 timerOp) {
switch (timerOp) {
case TIMER_CONTROL_SHOW:
gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIMER;
sTimerRunning = FALSE;
gHudDisplay.timer = 0;
gControlTimerStartNat = 0;
gControlTimerStopNat = 0;
break;
case TIMER_CONTROL_START:
sTimerRunning = TRUE;
if (!sTimerRunning) {
sTimerRunning = TRUE;
gControlTimerStartNat = gNetworkAreaTimer;
}
break;
case TIMER_CONTROL_STOP:
sTimerRunning = FALSE;
if (sTimerRunning) {
sTimerRunning = FALSE;
gControlTimerStopNat = gNetworkAreaTimer;
}
break;
case TIMER_CONTROL_HIDE:
gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIMER;
sTimerRunning = FALSE;
gHudDisplay.timer = 0;
gControlTimerStartNat = 0;
gControlTimerStopNat = 0;
break;
}
@ -1034,8 +1051,16 @@ s32 play_mode_normal(void) {
warp_area();
check_instant_warp();
if (sTimerRunning && gHudDisplay.timer < 17999) {
gHudDisplay.timer += 1;
if (sTimerRunning) {
gHudDisplay.timer = gNetworkAreaTimer - gControlTimerStartNat;
if (gHudDisplay.timer >= 17999) {
gHudDisplay.timer = 17999;
}
} else if (gControlTimerStopNat > 0) {
gHudDisplay.timer = gControlTimerStopNat - gControlTimerStartNat;
if (gHudDisplay.timer >= 17999) {
gHudDisplay.timer = 17999;
}
}
area_update_objects();

View file

@ -122,6 +122,9 @@ struct HudDisplay {
extern struct HudDisplay gHudDisplay;
extern s8 gShouldNotPlayCastleMusic;
extern u32 gControlTimerStartNat;
extern u32 gControlTimerStopNat;
enum HUDDisplayFlag {
HUD_DISPLAY_FLAG_LIVES = 0x0001,
HUD_DISPLAY_FLAG_COIN_COUNT = 0x0002,
@ -136,7 +139,7 @@ enum HUDDisplayFlag {
HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020
};
u8 level_control_timer_running(void);
u16 level_control_timer(s32 timerOp);
void fade_into_special_warp(u32 arg, u32 color);
void load_level_init_text(u32 arg);

View file

@ -60,6 +60,8 @@ struct SyncObject {
u8 (*ignore_if_true)(void);
void (*on_received_pre)(u8 fromLocalIndex);
void (*on_received_post)(u8 fromLocalIndex);
void (*on_sent_pre)(void);
void (*on_sent_post)(void);
void (*override_ownership)(u8* shouldOverride, u8* shouldOwn);
void* extraFields[MAX_SYNC_OBJECT_FIELDS];
};

View file

@ -33,6 +33,8 @@ void area_remove_sync_ids_clear(void) {
void network_send_area(struct NetworkPlayer* toNp) {
extern s16 gCurrCourseNum, gCurrActStarNum, gCurrLevelNum, gCurrAreaIndex;
bool levelControlTimerRunning = level_control_timer_running();
bool levelControlTimerVisible = (gHudDisplay.flags & HUD_DISPLAY_FLAG_TIMER) ? 1 : 0;
packet_ordered_begin();
{
@ -49,6 +51,12 @@ void network_send_area(struct NetworkPlayer* toNp) {
packet_write(&p, &gNetworkAreaTimer, sizeof(u32));
packet_write(&p, gEnvironmentLevels, sizeof(s32));
// level control timer
packet_write(&p, &levelControlTimerVisible, sizeof(u8));
packet_write(&p, &levelControlTimerRunning, sizeof(u8));
packet_write(&p, &gControlTimerStartNat, sizeof(u32));
packet_write(&p, &gControlTimerStopNat, sizeof(u32));
// write sync id removals
packet_write(&p, &sRemoveSyncIdsIndex, sizeof(u8));
for (int i = 0; i < sRemoveSyncIdsIndex; i++) {
@ -146,6 +154,20 @@ void network_receive_area(struct Packet* p) {
gNetworkAreaTimerClock = clock_elapsed_ticks() - gNetworkAreaTimer;
packet_read(p, gEnvironmentLevels, sizeof(s32));
// read control timer variables
bool levelControlTimerRunning = false;
bool levelControlTimerVisible = false;
packet_read(p, &levelControlTimerVisible, sizeof(u8));
packet_read(p, &levelControlTimerRunning, sizeof(u8));
if (levelControlTimerVisible) {
level_control_timer(TIMER_CONTROL_SHOW);
}
if (levelControlTimerRunning) {
level_control_timer(TIMER_CONTROL_START);
}
packet_read(p, &gControlTimerStartNat, sizeof(u32));
packet_read(p, &gControlTimerStopNat, sizeof(u32));
// read removed sync ids
area_remove_sync_ids_clear();
packet_read(p, &sRemoveSyncIdsIndex, sizeof(u8));

View file

@ -27,7 +27,6 @@ void network_send_level(struct NetworkPlayer* toNp, bool sendArea) {
packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16));
packet_write(&p, &gRedCoinsCollected, sizeof(u8));
packet_write(&p, &gPssSlideStarted, sizeof(u8));
packet_write(&p, &gHudDisplay.timer, sizeof(u16));
packet_write(&p, &gTTCSpeedSetting, sizeof(s16));
// send level packet
@ -72,7 +71,6 @@ void network_receive_level(struct Packet* p) {
packet_read(p, &gMarioStates[0].numCoins, sizeof(s16));
packet_read(p, &redCoinsCollected, sizeof(u8));
packet_read(p, &gPssSlideStarted, sizeof(u8));
packet_read(p, &gHudDisplay.timer, sizeof(u16));
packet_read(p, &gTTCSpeedSetting, sizeof(s16)); // likely doesn't work after level load.. but it could
// hacky way to override red coins collected

View file

@ -99,6 +99,8 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance)
so->ignore_if_true = NULL;
so->on_received_pre = NULL;
so->on_received_post = NULL;
so->on_sent_pre = NULL;
so->on_sent_post = NULL;
so->override_ownership = NULL;
so->syncDeathEvent = true;
so->randomSeed = (u16)(o->oSyncID * 7951);
@ -429,6 +431,15 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
return;
}
// trigger on_sent_pre callback
if (so->on_sent_pre != NULL) {
extern struct Object* gCurrentObject;
struct Object* tmp = gCurrentObject;
gCurrentObject = so->o;
so->on_sent_pre();
gCurrentObject = tmp;
}
// always send a new event ID
so->txEventId++;
so->clockSinceUpdate = clock_elapsed();
@ -457,6 +468,15 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
// send the packet out
network_send(&p);
// trigger on_sent_post callback
if (so->on_sent_post != NULL) {
extern struct Object* gCurrentObject;
struct Object* tmp = gCurrentObject;
gCurrentObject = so->o;
so->on_sent_post();
gCurrentObject = tmp;
}
}
void network_receive_object(struct Packet* p) {