diff --git a/3p.patch b/3p.patch
deleted file mode 100644
index a29e1ba5..00000000
--- a/3p.patch
+++ /dev/null
@@ -1,491 +0,0 @@
-diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj
-index c5052b8..db836c3 100644
---- a/build-windows-visual-studio/sm64ex.vcxproj
-+++ b/build-windows-visual-studio/sm64ex.vcxproj
-@@ -3973,6 +3973,7 @@
-
-
-
-+
-
-
-
-diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters
-index b33547f..26133b0 100644
---- a/build-windows-visual-studio/sm64ex.vcxproj.filters
-+++ b/build-windows-visual-studio/sm64ex.vcxproj.filters
-@@ -15078,6 +15078,9 @@
-
- Source Files\src\game
-
-+
-+ Source Files\src\pc\network\packets
-+
-
-
-
-diff --git a/proto-3.sh b/proto-3.sh
-new file mode 100644
-index 0000000..8f7a1bb
---- /dev/null
-+++ b/proto-3.sh
-@@ -0,0 +1,41 @@
-+set -e
-+if [ $# -eq 0 ]; then
-+ make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j
-+else
-+ make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 -j
-+fi
-+
-+# find file
-+FILE=./build/us_pc/sm64.us.f3dex2e.exe
-+if [ ! -f "$FILE" ]; then
-+ FILE=./build/us_pc/sm64.us.f3dex2e
-+fi
-+
-+# no debug, discord
-+#$FILE --discord 2 --configfile sm64config_server.txt &
-+#$FILE --discord 1 --configfile sm64config_client.txt &
-+#exit
-+
-+# no debug, direct
-+#$FILE --server 27015 --configfile sm64config_server.txt &
-+#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
-+#exit
-+
-+# debug on server
-+#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
-+#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
-+#exit
-+
-+###################
-+# debug on client #
-+###################
-+
-+$FILE --server 27015 --configfile sm64config_p1.txt &
-+ $FILE --client 127.0.0.1 27015 --configfile sm64config_p2.txt &
-+
-+# debug if cgdb exists
-+if ! [ -x "$(command -v cgdb)" ]; then
-+ $FILE --client 127.0.0.1 27015 --configfile sm64config_p3.txt &
-+else
-+ winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_p3.txt' -ex 'quit'
-+fi
-diff --git a/src/engine/level_script.c b/src/engine/level_script.c
-index 7e181da..a7471b7 100644
---- a/src/engine/level_script.c
-+++ b/src/engine/level_script.c
-@@ -664,15 +664,24 @@ static void level_cmd_unload_area(void) {
- }
-
- static void level_cmd_set_mario_start_pos(void) {
-+ s8 areaIndex = CMD_GET(u8, 2);
-+#if IS_64_BIT
-+ s16 x = CMD_GET(s16, 6);
-+ s16 y = CMD_GET(s16, 8);
-+ s16 z = CMD_GET(s16, 10);
-+#else
-+ Vec3s pos = CMD_GET(Vec3s, 6);
-+#endif
-+ s16 angle = CMD_GET(s16, 4);
- for (int i = 0; i < MAX_PLAYERS; i++) {
-- gPlayerSpawnInfos[i].areaIndex = CMD_GET(u8, 2);
--
-- #if IS_64_BIT
-- vec3s_set(gPlayerSpawnInfos[i].startPos, CMD_GET(s16, 6), CMD_GET(s16, 8), CMD_GET(s16, 10));
-- #else
-- vec3s_copy(gPlayerSpawnInfos[i].startPos, CMD_GET(Vec3s, 6));
-- #endif
-- vec3s_set(gPlayerSpawnInfos[i].startAngle, 0, CMD_GET(s16, 4) * 0x8000 / 180, 0);
-+ gPlayerSpawnInfos[i].areaIndex = areaIndex;
-+
-+#if IS_64_BIT
-+ vec3s_set(gPlayerSpawnInfos[i].startPos, x, y, z);
-+#else
-+ vec3s_copy(gPlayerSpawnInfos[i].startPos, pos);
-+#endif
-+ vec3s_set(gPlayerSpawnInfos[i].startAngle, 0, angle * 0x8000 / 180, 0);
- }
- sCurrentCmd = CMD_NEXT;
- }
-diff --git a/src/game/behavior_actions.c b/src/game/behavior_actions.c
-index 61fc8b9..0e5d070 100644
---- a/src/game/behavior_actions.c
-+++ b/src/game/behavior_actions.c
-@@ -176,7 +176,7 @@ Gfx *geo_move_mario_part_from_parent(s32 run, UNUSED struct GraphNode *node, Mat
-
- if (run == TRUE) {
- sp1C = (struct Object *) gCurGraphNodeObject;
-- if (sp1C == gMarioObject && sp1C->prevObj != NULL) {
-+ if (sp1C->behavior == bhvMario && sp1C->prevObj != NULL) {
- create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
- obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
- obj_set_gfx_pos_from_pos(sp1C->prevObj);
-diff --git a/src/game/mario.c b/src/game/mario.c
-index 09e2a09..9d6d3e7 100644
---- a/src/game/mario.c
-+++ b/src/game/mario.c
-@@ -2124,11 +2124,7 @@ static void init_single_mario(struct MarioState* m) {
-
- // set mario/luigi model
- // two-player hack
-- if (isLocal) {
-- m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(gNetworkType == NT_SERVER) ? MODEL_MARIO : MODEL_LUIGI];
-- } else {
-- m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(gNetworkType == NT_CLIENT) ? MODEL_MARIO : MODEL_LUIGI];
-- }
-+ m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(gNetworkPlayers[0].globalIndex == 1) ? MODEL_LUIGI : MODEL_MARIO];
- }
-
- void init_mario(void) {
-diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c
-index 67d97a2..54b533d 100644
---- a/src/game/mario_actions_moving.c
-+++ b/src/game/mario_actions_moving.c
-@@ -61,7 +61,7 @@ struct LandingAction sBackflipLandAction = {
- 4, 0, ACT_FREEFALL, ACT_BACKFLIP_LAND_STOP, ACT_BACKFLIP, ACT_FREEFALL, ACT_BEGIN_SLIDING,
- };
-
--Mat4 sFloorAlignMatrix[2];
-+Mat4 sFloorAlignMatrix[MAX_PLAYERS];
-
- s16 tilt_body_running(struct MarioState *m) {
- s16 pitch = find_floor_slope(m, 0);
-diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c
-index 0c915c3..43f81eb 100644
---- a/src/game/mario_misc.c
-+++ b/src/game/mario_misc.c
-@@ -418,7 +418,6 @@ Gfx* geo_mario_tilt_torso(s32 callContext, struct GraphNode* node, Mat4* mtx) {
- rotNode->rotation[0] = bodyState->torsoAngle[1];
- rotNode->rotation[1] = bodyState->torsoAngle[2];
- rotNode->rotation[2] = bodyState->torsoAngle[0];
--
- // update torso position in bodyState
- get_pos_from_transform_mtx(bodyState->torsoPos, *curTransform, *gCurGraphNodeCamera->matrixPtr);
- }
-@@ -491,17 +490,18 @@ Gfx* geo_switch_mario_hand(s32 callContext, struct GraphNode* node, UNUSED Mat4*
- */
- Gfx* geo_mario_hand_foot_scaler(s32 callContext, struct GraphNode* node, Mat4* mtx) {
- Mat4 * curTransform = mtx;
-- static s16 sMarioAttackAnimCounter = 0;
-+ static s16 sMarioAttackAnimCounter[MAX_PLAYERS] = { 0 };
- struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node;
- struct GraphNodeScale* scaleNode = (struct GraphNodeScale*) node->next;
-+ u8 index = geo_get_processing_object_index();
- struct MarioBodyState* bodyState = geo_get_body_state();
-
- if (callContext == GEO_CONTEXT_RENDER) {
- scaleNode->scale = 1.0f;
- if (asGenerated->parameter == bodyState->punchState >> 6) {
-- if (sMarioAttackAnimCounter != gAreaUpdateCounter && (bodyState->punchState & 0x3F) > 0) {
-+ if (sMarioAttackAnimCounter[index] != gAreaUpdateCounter && (bodyState->punchState & 0x3F) > 0) {
- bodyState->punchState -= 1;
-- sMarioAttackAnimCounter = gAreaUpdateCounter;
-+ sMarioAttackAnimCounter[index] = gAreaUpdateCounter;
- }
- scaleNode->scale =
- gMarioAttackScaleAnimation[asGenerated->parameter * 6 + (bodyState->punchState & 0x3F)]
-@@ -510,7 +510,7 @@ Gfx* geo_mario_hand_foot_scaler(s32 callContext, struct GraphNode* node, Mat4* m
- // update hand/foot position in bodyState
- get_pos_from_transform_mtx(bodyState->handFootPos[(asGenerated->parameter & 0x03)],
- *curTransform,
-- *gCurGraphNodeCamera->matrixPtr);
-+ *gCurGraphNodeCamera->matrixPtr);
-
- }
- return NULL;
-diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c
-index d0bb984..1b3c33f 100644
---- a/src/game/object_list_processor.c
-+++ b/src/game/object_list_processor.c
-@@ -516,7 +516,9 @@ void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) {
- u16 playerIndex = (spawnInfo->behaviorArg & ~(1 << 31));
- object->oBehParams = playerIndex + 1;
- gMarioObjects[playerIndex] = object;
-- if (playerIndex == 0) { gMarioObject = object; }
-+ if (playerIndex == 0) {
-+ gMarioObject = object;
-+ }
- geo_make_first_child(&object->header.gfx.node);
- }
-
-diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c
-index a511ac5..ed7f13e 100644
---- a/src/game/rendering_graph_node.c
-+++ b/src/game/rendering_graph_node.c
-@@ -1068,6 +1068,7 @@ static void interpolate_matrix(Mat4 result, Mat4 a, Mat4 b) {
- * Process an object node.
- */
- static void geo_process_object(struct Object *node) {
-+ struct Object* lastProcessingObject = gCurGraphNodeProcessingObject;
- gCurGraphNodeProcessingObject = node;
- Mat4 mtxf;
- s32 hasAnimation = (node->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0;
-@@ -1192,7 +1193,7 @@ static void geo_process_object(struct Object *node) {
- node->header.gfx.throwMatrix = NULL;
- node->header.gfx.throwMatrixInterpolated = NULL;
- }
-- gCurGraphNodeProcessingObject = NULL;
-+ gCurGraphNodeProcessingObject = lastProcessingObject;
- }
-
- /**
-diff --git a/src/pc/network/discord/discord.c b/src/pc/network/discord/discord.c
-index 7c30fc0..06a333f 100644
---- a/src/pc/network/discord/discord.c
-+++ b/src/pc/network/discord/discord.c
-@@ -121,10 +121,11 @@ static void ns_discord_shutdown(void) {
- }
-
- struct NetworkSystem gNetworkSystemDiscord = {
-- .initialize = ns_discord_initialize,
-- .save_id = ns_discord_save_id,
-- .clear_id = ns_discord_clear_id,
-- .update = ns_discord_update,
-- .send = ns_discord_network_send,
-- .shutdown = ns_discord_shutdown,
-+ .initialize = ns_discord_initialize,
-+ .save_id = ns_discord_save_id,
-+ .clear_id = ns_discord_clear_id,
-+ .update = ns_discord_update,
-+ .send = ns_discord_network_send,
-+ .shutdown = ns_discord_shutdown,
-+ .canBroadcast = true,
- };
-diff --git a/src/pc/network/network.h b/src/pc/network/network.h
-index de287b2..5318630 100644
---- a/src/pc/network/network.h
-+++ b/src/pc/network/network.h
-@@ -38,6 +38,7 @@ struct NetworkSystem {
- void (*update)(void);
- int (*send)(u8 localIndex, u8* data, u16 dataLength);
- void (*shutdown)(void);
-+ bool canBroadcast;
- };
-
- struct SyncObject {
-diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c
-index 4dc4442..2734d50 100644
---- a/src/pc/network/network_player.c
-+++ b/src/pc/network/network_player.c
-@@ -103,7 +103,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
- gNetworkSystem->save_id(i);
- if (type == NPT_SERVER) { gNetworkPlayerServer = np; }
- else { chat_add_message("player connected", CMT_SYSTEM); }
-- LOG_INFO("player connected, local %d, global %d", i, globalIndex);
-+ LOG_INFO("player connected, local %d, global %d", i, np->globalIndex);
- extern s16 sCurrPlayMode;
- if (gNetworkType == NT_SERVER && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
- network_send_level_warp_repeat();
-diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c
-index 1dc9b0b..1ad776c 100644
---- a/src/pc/network/packets/packet.c
-+++ b/src/pc/network/packets/packet.c
-@@ -39,6 +39,7 @@ void packet_receive(struct Packet* p) {
- case PACKET_LEAVING: network_receive_leaving(p); break;
- case PACKET_SAVE_FILE: network_receive_save_file(p); break;
- case PACKET_INSTANT_WARP: network_receive_instant_warp(p); break;
-+ case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break;
- ///
- case PACKET_CUSTOM: network_receive_custom(p); break;
- default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
-diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h
-index 5d91805..126afd5 100644
---- a/src/pc/network/packets/packet.h
-+++ b/src/pc/network/packets/packet.h
-@@ -31,6 +31,7 @@ enum PacketType {
- PACKET_LEAVING,
- PACKET_SAVE_FILE,
- PACKET_INSTANT_WARP,
-+ PACKET_NETWORK_PLAYERS,
- ///
- PACKET_CUSTOM = 255,
- };
-@@ -159,4 +160,8 @@ void network_receive_save_file(struct Packet* p);
- void network_send_instant_warp(void);
- void network_receive_instant_warp(struct Packet* p);
-
-+// packet_network_players.c
-+void network_send_network_players(void);
-+void network_receive_network_players(struct Packet* p);
-+
- #endif
-diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c
-index bc9da5b..a51ce6a 100644
---- a/src/pc/network/packets/packet_join.c
-+++ b/src/pc/network/packets/packet_join.c
-@@ -75,8 +75,9 @@ void network_send_join(struct Packet* joinRequestPacket) {
- }
-
- network_send_to(joinRequestPacket->localIndex , &p);
--
- LOG_INFO("sending join packet");
-+
-+ network_send_network_players();
- }
-
- void network_receive_join(struct Packet* p) {
-diff --git a/src/pc/network/packets/packet_network_players.c b/src/pc/network/packets/packet_network_players.c
-new file mode 100644
-index 0000000..eb599fb
---- /dev/null
-+++ b/src/pc/network/packets/packet_network_players.c
-@@ -0,0 +1,55 @@
-+#include
-+#include "../network.h"
-+#include "object_fields.h"
-+#include "behavior_data.h"
-+#include "src/game/behavior_actions.h"
-+#include "pc/debuglog.h"
-+
-+static void network_send_to_network_players(u8 sendToLocalIndex) {
-+ assert(gNetworkType == NT_SERVER);
-+ assert(sendToLocalIndex != 0);
-+
-+ u8 connectedCount = network_player_connected_count();
-+
-+ struct Packet p;
-+ packet_init(&p, PACKET_NETWORK_PLAYERS, true, false);
-+ packet_write(&p, &connectedCount, sizeof(u8));
-+ for (int i = 1; i < MAX_PLAYERS; i++) {
-+ if (!gNetworkPlayers[i].connected) { continue; }
-+ u8 npType = gNetworkPlayers[i].type;
-+ if (npType == NPT_LOCAL) { npType = NPT_SERVER; }
-+ else if (i == sendToLocalIndex) { npType = NPT_LOCAL; }
-+ packet_write(&p, &npType, sizeof(u8));
-+ packet_write(&p, &gNetworkPlayers[i].globalIndex, sizeof(u8));
-+ LOG_INFO("send network player [%d == %d]", gNetworkPlayers[i].globalIndex, npType);
-+ }
-+
-+ network_send_to(sendToLocalIndex, &p);
-+ LOG_INFO("sent list of %d network players to %d", connectedCount, sendToLocalIndex);
-+}
-+
-+void network_send_network_players(void) {
-+ assert(gNetworkType == NT_SERVER);
-+ LOG_INFO("sending list of network players to all");
-+ for (int i = 1; i < MAX_PLAYERS; i++) {
-+ if (!gNetworkPlayers[i].connected) { continue; }
-+ network_send_to_network_players(i);
-+ }
-+}
-+
-+void network_receive_network_players(struct Packet* p) {
-+ LOG_INFO("receiving list of network players");
-+ if (gNetworkType != NT_CLIENT) {
-+ LOG_ERROR("received list of clients as a non-client");
-+ return;
-+ }
-+ u8 connectedCount = 0;
-+ packet_read(p, &connectedCount, sizeof(u8));
-+ for (int i = 0; i < connectedCount; i++) {
-+ u8 npType, globalIndex;
-+ packet_read(p, &npType, sizeof(u8));
-+ packet_read(p, &globalIndex, sizeof(u8));
-+ network_player_connected(npType, globalIndex);
-+ LOG_INFO("received network player [%d == %d]", globalIndex, npType);
-+ }
-+}
-\ No newline at end of file
-diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c
-index 8a117ea..90dfea9 100644
---- a/src/pc/network/packets/packet_player.c
-+++ b/src/pc/network/packets/packet_player.c
-@@ -154,26 +154,33 @@ static void write_packet_data(struct PacketPlayerData* data, struct MarioState*
- *platformSyncID = data->platformSyncID;
- }
-
--void network_send_player(void) {
-- if (gMarioStates[0].marioObj == NULL) { return; }
-+void network_send_player(u8 localIndex) {
-+ if (gMarioStates[localIndex].marioObj == NULL) { return; }
-
- struct PacketPlayerData data = { 0 };
-- read_packet_data(&data, &gMarioStates[0]);
-+ read_packet_data(&data, &gMarioStates[localIndex]);
-
- struct Packet p;
- packet_init(&p, PACKET_PLAYER, false, false);
-+ packet_write(&p, &gNetworkPlayers[localIndex].globalIndex, sizeof(u8));
- packet_write(&p, &data, sizeof(struct PacketPlayerData));
-+ // two-player hack: should be network_send_to_all_except()
- network_send(&p);
- }
-
- void network_receive_player(struct Packet* p) {
-- struct MarioState* m = &gMarioStates[1];
-+ u8 globalIndex = 0;
-+ packet_read(p, &globalIndex, sizeof(u8));
-+ struct NetworkPlayer* np = network_player_from_global_index(globalIndex);
-+ if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { return; }
-+
-+ struct MarioState* m = &gMarioStates[np->localIndex];
- if (m == NULL || m->marioObj == NULL) { return; }
-
- // save previous state
- struct PacketPlayerData oldData = { 0 };
- read_packet_data(&oldData, m);
-- u16 playerIndex = m->playerIndex;
-+ u16 playerIndex = np->localIndex;
- u32 oldBehParams = m->marioObj->oBehParams;
-
- // load mario information from packet
-@@ -187,14 +194,10 @@ void network_receive_player(struct Packet* p) {
-
- // check player level/area
- u8 levelAreaMismatch = TRUE;
-- if (p->localIndex != UNKNOWN_LOCAL_INDEX) {
-- struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex];
-- np->currLevelNum = data.currLevelNum;
-- np->currAreaIndex = data.currAreaIndex;
-- levelAreaMismatch = (data.currLevelNum != gCurrLevelNum || data.currAreaIndex != gCurrAreaIndex);
-- if (levelAreaMismatch) { np->fadeOpacity = 0; }
-- }
-- if (levelAreaMismatch) { return; }
-+ np->currLevelNum = data.currLevelNum;
-+ np->currAreaIndex = data.currAreaIndex;
-+ levelAreaMismatch = (data.currLevelNum != gCurrLevelNum || data.currAreaIndex != gCurrAreaIndex);
-+ if (levelAreaMismatch) { np->fadeOpacity = 0; return; }
-
- // apply data from packet to mario state
- u8 heldSyncID = 0;
-@@ -301,8 +304,16 @@ void network_receive_player(struct Packet* p) {
- if (m->action != oldData.action) {
- m->actionTimer = 0;
- }
-+
-+ // set model
-+ m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(np->globalIndex == 1) ? MODEL_LUIGI : MODEL_MARIO];
-+
-+ // broadcast player packet
-+ if (gNetworkType == NT_SERVER && !gNetworkSystem->canBroadcast) {
-+ network_send_player(globalIndex);
-+ }
- }
-
- void network_update_player(void) {
-- network_send_player();
-+ network_send_player(0);
- }
-diff --git a/src/pc/network/socket/socket.c b/src/pc/network/socket/socket.c
-index 6ede2e9..6f81165 100644
---- a/src/pc/network/socket/socket.c
-+++ b/src/pc/network/socket/socket.c
-@@ -138,10 +138,11 @@ static void ns_socket_shutdown(void) {
- }
-
- struct NetworkSystem gNetworkSystemSocket = {
-- .initialize = ns_socket_initialize,
-- .save_id = ns_socket_save_id,
-- .clear_id = ns_socket_clear_id,
-- .update = ns_socket_update,
-- .send = ns_socket_send,
-- .shutdown = ns_socket_shutdown,
-+ .initialize = ns_socket_initialize,
-+ .save_id = ns_socket_save_id,
-+ .clear_id = ns_socket_clear_id,
-+ .update = ns_socket_update,
-+ .send = ns_socket_send,
-+ .shutdown = ns_socket_shutdown,
-+ .canBroadcast = false,
- };
diff --git a/src/game/behaviors/racing_penguin.inc.c b/src/game/behaviors/racing_penguin.inc.c
index a93b8332..62236287 100644
--- a/src/game/behaviors/racing_penguin.inc.c
+++ b/src/game/behaviors/racing_penguin.inc.c
@@ -96,6 +96,19 @@ static void racing_penguin_act_race(void) {
f32 targetSpeed;
f32 minSpeed;
+ // prevent segfault / error state
+ if (o->oPathedStartWaypoint == NULL) {
+ struct Object* child;
+ child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine);
+ child->parentObj = o;
+
+ child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceShortcutCheck);
+ child->parentObj = o;
+
+ o->oPathedStartWaypoint = o->oPathedPrevWaypoint = segmented_to_virtual(ccm_seg7_trajectory_penguin_race);
+ o->oPathedPrevWaypointFlags = 0;
+ }
+
if (cur_obj_follow_path(0) == PATH_REACHED_END) {
o->oRacingPenguinReachedBottom = TRUE;
o->oAction = RACING_PENGUIN_ACT_FINISH_RACE;