From cf732c7bebc77b3f157da285fffa78cb7741cce3 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 8 Sep 2020 16:12:11 -0700 Subject: [PATCH] Eject a player if more than one is in the cannon Two players in the same cannon was causing softlocks and general insanity. Now this should be fixed. Also prevented players from being able to push or attack a player inside of a cannon. --- src/game/behaviors/cannon.inc.c | 35 +++++++++++++++++++++++++- src/game/interaction.c | 1 + src/pc/network/network.h | 1 + src/pc/network/packets/packet_object.c | 10 ++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) 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) {