diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index 2755afe7b..22a5ff6f1 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -146,14 +146,47 @@ u8 unused0EA1FC[] = { 2, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0 63, 128, 0, 0, 2, 0, 0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 8, 0, 0, 0, 65, 32, 0, 0, 63, 128, 0, 0 }; -u8 cannon_ignore_remote_updates(struct Object* object) { return object->oCannonIsLocal; } +u8 cannon_ignore_remote_updates(struct Object* object) { + // two-player hack + return ((gNetworkType == NT_SERVER) && object->oCannonIsLocal); +} + +static void cannon_on_received(void) { + // check if we're on in the cannon too + struct MarioState* m = &gMarioStates[0]; + if (m->action != ACT_IN_CANNON) { return; } + if (m->interactObj != o) { return; } + // two-player hack + if (gNetworkType == NT_SERVER) { return; } + + // eject the player by shooting out of the cannon weakly + m->forwardVel = 10.0f * coss(m->faceAngle[0]); + m->vel[1] = 10.0f * sins(m->faceAngle[0]); + m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]); + m->pos[1] += 120.0f * sins(m->faceAngle[0]); + m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]); + set_mario_action(m, ACT_SHOT_FROM_CANNON, 0); + + // reset things that got messed up + m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; + reset_camera(gCamera); + o->oCannonIsLocal = FALSE; + cur_obj_become_tangible(); + cur_obj_enable_rendering(); +} void bhv_cannon_base_loop(void) { if (!network_sync_object_initialized(o)) { struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); so->ignore_if_true = &cannon_ignore_remote_updates; + so->on_received = &cannon_on_received; network_init_object_field(o, &o->oAction); + network_init_object_field(o, &o->oPrevAction); network_init_object_field(o, &o->oTimer); + 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->oCannonUnk10C); network_init_object_field(o, &o->oCannonUnk10C); network_init_object_field(o, &o->oCannonUnkF8); network_init_object_field(o, &o->oCannonUnkF4); diff --git a/src/game/interaction.c b/src/game/interaction.c index 15ef6eb79..e1b608a48 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -1233,6 +1233,7 @@ u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object // attacked u8 isInCutscene = ((m->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE) || ((m2->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE); + isInCutscene = isInCutscene || (m->action == ACT_IN_CANNON) || (m2->action == ACT_IN_CANNON); u8 isInvulnerable = (m2->action & ACT_FLAG_INVULNERABLE) || m2->invincTimer != 0 || m2->hurtCounter != 0 || isInCutscene; if ((interaction & INT_ANY_ATTACK) && !(interaction & INT_HIT_FROM_ABOVE) && !isInvulnerable) { diff --git a/src/pc/network/network.h b/src/pc/network/network.h index e7116a432..61f867927 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -62,6 +62,7 @@ struct SyncObject { bool hasStandardFields; float maxUpdateRate; u8 (*ignore_if_true)(struct Object*); + void (*on_received)(void); void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 6c9048b29..e29ecc36d 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -55,6 +55,7 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance) so->hasStandardFields = (maxSyncDistance >= 0); so->maxUpdateRate = 0; so->ignore_if_true = NULL; + so->on_received = NULL; so->syncDeathEvent = true; memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); @@ -372,6 +373,15 @@ void network_receive_object(struct Packet* p) { if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { network_forget_sync_object(so); } + + // trigger on-received callback + if (so->on_received != NULL) { + extern struct Object* gCurrentObject; + struct Object* tmp = gCurrentObject; + gCurrentObject = so->o; + (*so->on_received)(); + gCurrentObject = tmp; + } } void network_forget_sync_object(struct SyncObject* so) {