mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 21:45:12 +00:00
Resynchronized Koopa the Quick and race timers for late join
This commit is contained in:
parent
b0267a5a31
commit
ed95bd317b
7 changed files with 145 additions and 55 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue