diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 7c39a339..40bda1ed 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -13,6 +13,7 @@ #include "game/object_list_processor.h" #include "graph_node.h" #include "surface_collision.h" +#include "pc/network/network.h" // Macros for retrieving arguments from behavior scripts. #define BHV_CMD_GET_1ST_U8(index) (u8)((gCurBhvCommand[index] >> 24) & 0xFF) // unused @@ -63,7 +64,12 @@ void force_replicable_seed(u8 always) { // Generate a pseudorandom integer from 0 to 65535 from the random seed, and update the seed. u16 random_u16(void) { // override this function for synchronized entities - if (gCurrentObject->oSyncID != 0) { force_replicable_seed(FALSE); } + if (gCurrentObject->oSyncID != 0) { + struct SyncObject* so = &syncObjects[gCurrentObject->oSyncID]; + if (so->o != NULL && !so->keepRandomSeed) { + force_replicable_seed(FALSE); + } + } u16 temp1, temp2; diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index f1e16cb1..0e11e565 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -180,41 +180,69 @@ void bhv_generic_bowling_ball_spawner_init(void) { } void bhv_generic_bowling_ball_spawner_loop(void) { + if (o->oSyncID == 0) { + network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + network_object_settings(o, FALSE, 0, TRUE); + } + struct Object *bowlingBall; if (o->oTimer == 256) o->oTimer = 0; + struct Object* player = nearest_player_to_object(o); + if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 1000) - || (o->oPosY < gMarioObject->header.gfx.pos[1])) + || (o->oPosY < player->header.gfx.pos[1])) return; if ((o->oTimer & o->oBBallSpawnerPeriodMinus1) == 0) /* Modulus */ { if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, o->oBBallSpawnerMaxSpawnDist)) { if ((s32)(random_float() * o->oBBallSpawnerSpawnOdds) == 0) { + if (!network_owns_object(o)) { + return; + } + // this branch only runs for one player at a time bowlingBall = spawn_object(o, MODEL_BOWLING_BALL, bhvBowlingBall); bowlingBall->oBehParams2ndByte = o->oBehParams2ndByte; + + // send out the bowlingBall object + struct Object* spawn_objects[] = { bowlingBall }; + u32 models[] = { MODEL_BOWLING_BALL }; + network_send_spawn_objects(spawn_objects, models, 1); } } } } void bhv_thi_bowling_ball_spawner_loop(void) { + if (o->oSyncID == 0) { + network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + network_object_settings(o, FALSE, 0, TRUE); + } + struct Object *bowlingBall; + struct Object* player = nearest_player_to_object(o); if (o->oTimer == 256) o->oTimer = 0; if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 800) - || (o->oPosY < gMarioObject->header.gfx.pos[1])) + || (o->oPosY < player->header.gfx.pos[1])) return; if ((o->oTimer % 64) == 0) { if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 12000)) { - if ((s32)(random_float() * 1.5) == 0) { + if (network_owns_object(o) && (s32)(random_float() * 1.5) == 0) { + // this branch only runs for one player at a time bowlingBall = spawn_object(o, MODEL_BOWLING_BALL, bhvBowlingBall); bowlingBall->oBehParams2ndByte = o->oBehParams2ndByte; + + // send out the bowlingBall object + struct Object* spawn_objects[] = { bowlingBall }; + u32 models[] = { MODEL_BOWLING_BALL }; + network_send_spawn_objects(spawn_objects, models, 1); } } } @@ -224,6 +252,9 @@ void bhv_bob_pit_bowling_ball_init(void) { o->oGravity = 12.0f; o->oFriction = 1.0f; o->oBuoyancy = 2.0f; + + network_init_object(o, 5000.0f); + network_object_settings(o, FALSE, 5.0f, TRUE); } void bhv_bob_pit_bowling_ball_loop(void) { diff --git a/src/game/behaviors/checkerboard_platform.inc.c b/src/game/behaviors/checkerboard_platform.inc.c index 55ffeac7..2eec54c5 100644 --- a/src/game/behaviors/checkerboard_platform.inc.c +++ b/src/game/behaviors/checkerboard_platform.inc.c @@ -46,7 +46,7 @@ void checkerboard_plat_act_rotate(s32 a0, s16 a1) { void bhv_checkerboard_platform_init(void) { o->oCheckerBoardPlatformUnkFC = o->parentObj->oBehParams2ndByte; network_init_object(o, 1000.0f); - network_object_settings(o, TRUE, 5.0f); + network_object_settings(o, TRUE, 5.0f, TRUE); } void bhv_checkerboard_platform_loop(void) { diff --git a/src/game/behaviors/water_bomb.inc.c b/src/game/behaviors/water_bomb.inc.c index 5254b9c7..3485e9d2 100644 --- a/src/game/behaviors/water_bomb.inc.c +++ b/src/game/behaviors/water_bomb.inc.c @@ -33,6 +33,7 @@ void bhv_water_bomb_spawner_update(void) { network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); network_init_object_field(o, &o->oWaterBombSpawnerBombActive); network_init_object_field(o, &o->oWaterBombSpawnerTimeToSpawn); + network_object_settings(o, FALSE, 0, TRUE); } f32 latDistToMario = 9999; diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 2af8db79..bc02a052 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -43,6 +43,7 @@ struct SyncObject { u16 onEventId; u8 extraFieldCount; bool fullObjectSync; + bool keepRandomSeed; float maxUpdateRate; void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; @@ -55,7 +56,7 @@ extern struct SyncObject syncObjects[]; void network_init(enum NetworkType networkType); void network_init_object(struct Object *object, float maxSyncDistance); -void network_object_settings(struct Object *object, bool fullObjectSync, float maxUpdateRate); +void network_object_settings(struct Object *object, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed); void network_send(struct Packet* p); void network_update(void); void network_shutdown(void); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index a694a2d0..469e709e 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -27,15 +27,17 @@ void network_init_object(struct Object *o, float maxSyncDistance) { so->behavior = o->behavior; so->onEventId = 0; so->fullObjectSync = false; + so->keepRandomSeed = false; so->maxUpdateRate = 0; memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); } -void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpdateRate) { +void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed) { assert(o->oSyncID != 0); struct SyncObject* so = &syncObjects[o->oSyncID]; so->fullObjectSync = fullObjectSync; so->maxUpdateRate = maxUpdateRate; + so->keepRandomSeed = keepRandomSeed; } void network_init_object_field(struct Object *o, void* field) {