diff --git a/data/behavior_data.c b/data/behavior_data.c index f39bc8dc..2770e80d 100644 --- a/data/behavior_data.c +++ b/data/behavior_data.c @@ -6380,6 +6380,7 @@ const BehaviorScript bhvEyerokBoss[] = { ID(id_bhvEyerokBoss), OR_INT(oFlags, (OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), SET_HOME(), + CALL_NATIVE(bhv_eyerok_boss_init), BEGIN_LOOP(), CALL_NATIVE(bhv_eyerok_boss_loop), END_LOOP(), diff --git a/include/object_constants.h b/include/object_constants.h index 82a16769..2916a7d9 100644 --- a/include/object_constants.h +++ b/include/object_constants.h @@ -844,6 +844,8 @@ #define EYEROK_BOSS_ACT_SHOW_INTRO_TEXT 2 #define EYEROK_BOSS_ACT_FIGHT 3 #define EYEROK_BOSS_ACT_DIE 4 + #define EYEROK_BOSS_ACT_DEAD 5 + #define EYEROK_BOSS_ACT_PAUSE 6 /* Eyerok hand */ /* oAction */ @@ -863,6 +865,8 @@ #define EYEROK_HAND_ACT_RECOVER 13 #define EYEROK_HAND_ACT_BECOME_ACTIVE 14 #define EYEROK_HAND_ACT_DIE 15 + #define EYEROK_HAND_ACT_DEAD 16 + #define EYEROK_HAND_ACT_PAUSE 17 /* Klepto */ /* oAction */ diff --git a/include/object_fields.h b/include/object_fields.h index 82cfdd2d..0e1fed54 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -475,6 +475,7 @@ #define /*0x0F8*/ oEyerokReceivedAttack OBJECT_FIELD_S32(0x1C) #define /*0x0FC*/ oEyerokHandUnkFC OBJECT_FIELD_S32(0x1D) #define /*0x100*/ oEyerokHandUnk100 OBJECT_FIELD_S32(0x1E) +#define /*0x100*/ oEyerokHandDead OBJECT_FIELD_S32(0x1F) /* Falling Pillar */ #define /*0x0F4*/ oFallingPillarPitchAcceleration OBJECT_FIELD_F32(0x1B) diff --git a/network.sh b/network.sh index 97e9b5dc..59c3a63c 100755 --- a/network.sh +++ b/network.sh @@ -11,14 +11,25 @@ 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_server.txt & # debug if cgdb exists diff --git a/src/game/behavior_actions.h b/src/game/behavior_actions.h index 4554e69a..b0578327 100644 --- a/src/game/behavior_actions.h +++ b/src/game/behavior_actions.h @@ -531,6 +531,7 @@ void bhv_snufit_loop(void); void bhv_snufit_balls_loop(void); void bhv_horizontal_grindel_init(void); void bhv_horizontal_grindel_update(void); +void bhv_eyerok_boss_init(void); void bhv_eyerok_boss_loop(void); void bhv_eyerok_hand_loop(void); void bhv_klepto_init(void); diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index a1398f7c..0dc0e3e9 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -11,29 +11,84 @@ struct ObjectHitbox sEyerokHitbox = { }; s8 D_80331BA4[] = { 0, 1, 3, 2, 1, 0 }; +static u8 eyerokBossImmediateUpdate = FALSE; static s32 eyerok_check_mario_relative_z(s32 arg0) { - if (gMarioObject->oPosZ - o->oHomeZ < arg0) { + struct Object* player = nearest_player_to_object(o); + if (player->oPosZ - o->oHomeZ < arg0) { return TRUE; } else { return FALSE; } } -static void eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) { +static struct Object* eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) { struct Object *hand; hand = spawn_object_relative_with_scale(side, -500 * side, 0, 300, 1.5f, o, model, behavior); if (hand != NULL) { hand->oFaceAngleYaw -= 0x4000 * side; } + + return hand; +} + +void bhv_eyerok_boss_override_ownership(u8* shouldOverride, u8* shouldOwn) { + *shouldOverride = TRUE; + *shouldOwn = (gNetworkType == NT_SERVER); +} + +u8 bhv_eyerok_boss_ignore_if_true(void) { + return network_owns_object(o); +} + +void bhv_eyerok_boss_init(void) { + struct Object* hands[2]; + hands[0] = eyerok_spawn_hand(-1, MODEL_EYEROK_LEFT_HAND, bhvEyerokHand); + hands[1] = eyerok_spawn_hand(1, MODEL_EYEROK_RIGHT_HAND, bhvEyerokHand); + + struct SyncObject* so = network_init_object(o, 4000.0f); + so->override_ownership = bhv_eyerok_boss_override_ownership; + so->ignore_if_true = bhv_eyerok_boss_ignore_if_true; + so->minUpdateRate = 1.0f; + so->maxUpdateRate = 1.0f; + so->syncDeathEvent = FALSE; + network_init_object_field(o, &o->oEyerokBossNumHands); + network_init_object_field(o, &o->oEyerokBossUnkFC); + network_init_object_field(o, &o->oEyerokBossActiveHand); + network_init_object_field(o, &o->oEyerokBossUnk104); + network_init_object_field(o, &o->oEyerokBossUnk108); + network_init_object_field(o, &o->oEyerokBossUnk10C); + network_init_object_field(o, &o->oEyerokBossUnk110); + network_init_object_field(o, &o->oEyerokBossUnk1AC); + for (int i = 0; i < 2; i++) { + network_init_object_field(o, &hands[i]->oPosX); + network_init_object_field(o, &hands[i]->oPosY); + network_init_object_field(o, &hands[i]->oPosZ); + network_init_object_field(o, &hands[i]->oVelX); + network_init_object_field(o, &hands[i]->oVelY); + network_init_object_field(o, &hands[i]->oVelZ); + network_init_object_field(o, &hands[i]->oForwardVel); + network_init_object_field(o, &hands[i]->oAction); + network_init_object_field(o, &hands[i]->oPrevAction); + network_init_object_field(o, &hands[i]->oTimer); + network_init_object_field(o, &hands[i]->oHealth); + network_init_object_field(o, &hands[i]->oEyerokHandWakeUpTimer); + network_init_object_field(o, &hands[i]->oEyerokReceivedAttack); + network_init_object_field(o, &hands[i]->oEyerokHandUnkFC); + network_init_object_field(o, &hands[i]->oEyerokHandUnk100); + network_init_object_field(o, &hands[i]->oFaceAngleYaw); + network_init_object_field(o, &hands[i]->oMoveAngleYaw); + network_init_object_field(o, &hands[i]->oGravity); + network_init_object_field(o, &hands[i]->oAnimState); + } } static void eyerok_boss_act_sleep(void) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); if (o->oTimer == 0) { - eyerok_spawn_hand(-1, MODEL_EYEROK_LEFT_HAND, bhvEyerokHand); - eyerok_spawn_hand(1, MODEL_EYEROK_RIGHT_HAND, bhvEyerokHand); - } else if (o->oDistanceToMario < 500.0f) { + } else if (distanceToPlayer < 500.0f) { cur_obj_play_sound_2(SOUND_OBJ_EYEROK_EXPLODE); o->oAction = EYEROK_BOSS_ACT_WAKE_UP; } @@ -65,14 +120,20 @@ static void eyerok_boss_act_wake_up(void) { u8 eyerok_boss_act_show_intro_text_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_SHOW_INTRO_TEXT; } static void eyerok_boss_act_show_intro_text(void) { - if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117, eyerok_boss_act_show_intro_text_continue_dialog)) { + // todo: get dialog working again + /*struct MarioState* marioState = nearest_mario_state_to_object(o); + if (should_start_or_continue_dialog(marioState, o) && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117, eyerok_boss_act_show_intro_text_continue_dialog)) { o->oAction = EYEROK_BOSS_ACT_FIGHT; - } + network_send_object_reliability(o, TRUE); + }*/ + o->oAction = EYEROK_BOSS_ACT_FIGHT; } static void eyerok_boss_act_fight(void) { if (o->oEyerokBossNumHands == 0) { - o->oAction = EYEROK_BOSS_ACT_DIE; + if (network_owns_object(o)) { + o->oAction = EYEROK_BOSS_ACT_DIE; + } } else if (o->oEyerokBossUnk1AC == 0 && o->oEyerokBossActiveHand == 0) { if (o->oEyerokBossUnk104 != 0) { if (approach_f32_ptr(&o->oEyerokBossUnk110, 1.0f, 0.02f)) { @@ -108,7 +169,8 @@ static void eyerok_boss_act_fight(void) { o->oEyerokBossUnk108 = 1.0f; } - o->oEyerokBossUnk10C = gMarioObject->oPosZ; + struct Object* player = nearest_player_to_object(o); + o->oEyerokBossUnk10C = player->oPosZ; clamp_f32(&o->oEyerokBossUnk10C, o->oPosZ + 400.0f, o->oPosZ + 1600.0f); } else if ((o->oEyerokBossActiveHand = o->oEyerokBossUnkFC & 0x1) == 0) { o->oEyerokBossActiveHand = -1; @@ -120,8 +182,10 @@ static void eyerok_boss_act_fight(void) { u8 eyerok_boss_act_die_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_DIE; } static void eyerok_boss_act_die(void) { + // todo: get dialog working again + /*struct MarioState* marioState = nearest_mario_state_to_object(o); if (o->oTimer == 60) { - if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118, eyerok_boss_act_die_continue_dialog)) { + if (should_start_or_continue_dialog(marioState, o) && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118, eyerok_boss_act_die_continue_dialog)) { spawn_default_star(0.0f, -900.0f, -3700.0f); } else { o->oTimer -= 1; @@ -129,10 +193,21 @@ static void eyerok_boss_act_die(void) { } else if (o->oTimer > 120) { stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS)); obj_mark_for_deletion(o); + }*/ + stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS)); + if (network_owns_object(o)) { + spawn_default_star(0.0f, -900.0f, -3700.0f); + network_send_object_reliability(o, TRUE); } + o->oAction = EYEROK_BOSS_ACT_DEAD; } void bhv_eyerok_boss_loop(void) { + if (o->oAction == EYEROK_BOSS_ACT_DEAD) { + return; + } + + s16 oldAction = o->oAction; switch (o->oAction) { case EYEROK_BOSS_ACT_SLEEP: eyerok_boss_act_sleep(); @@ -148,15 +223,30 @@ void bhv_eyerok_boss_loop(void) { break; case EYEROK_BOSS_ACT_DIE: eyerok_boss_act_die(); - break; + return; + } + + if (o->oAction != oldAction) { + if (network_owns_object(o->parentObj)) { + eyerokBossImmediateUpdate = TRUE; + } else { + o->oAction = EYEROK_BOSS_ACT_PAUSE; + } + } + + if (eyerokBossImmediateUpdate && network_owns_object(o)) { + eyerokBossImmediateUpdate = FALSE; + network_send_object(o); } } static s32 eyerok_hand_check_attacked(void) { - if (o->oEyerokReceivedAttack != 0 && abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x3000) { + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); + if (o->oEyerokReceivedAttack != 0 && abs_angle_diff(angleToPlayer, o->oFaceAngleYaw) < 0x3000) { cur_obj_play_sound_2(SOUND_OBJ2_EYEROK_SOUND_SHORT); - if (--o->oHealth >= 2) { + if (--o->oHealth >= 2 || !network_owns_object(o->parentObj)) { o->oAction = EYEROK_HAND_ACT_ATTACKED; o->oVelY = 30.0f; } else { @@ -210,6 +300,8 @@ static void eyerok_hand_act_sleep(void) { } static void eyerok_hand_act_idle(void) { + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); cur_obj_init_animation_with_sound(2); if (o->parentObj->oAction == EYEROK_BOSS_ACT_FIGHT) { @@ -222,17 +314,17 @@ static void eyerok_hand_act_idle(void) { if (o->parentObj->oEyerokBossActiveHand == o->oBehParams2ndByte) { if (eyerok_check_mario_relative_z(400) != 0 || random_u16() % 2 != 0) { o->oAction = EYEROK_HAND_ACT_TARGET_MARIO; - o->oMoveAngleYaw = o->oAngleToMario; + o->oMoveAngleYaw = angleToPlayer; o->oGravity = 0.0f; } else { o->oAction = EYEROK_HAND_ACT_FIST_PUSH; - if (o->parentObj->oPosX - gMarioObject->oPosX < 0.0f) { + if (o->parentObj->oPosX - player->oPosX < 0.0f) { o->oMoveAngleYaw = -0x800; } else { o->oMoveAngleYaw = 0x800; } - o->oMoveAngleYaw += o->oAngleToMario; + o->oMoveAngleYaw += angleToPlayer; o->oGravity = -4.0f; } } else { @@ -245,6 +337,8 @@ static void eyerok_hand_act_idle(void) { } static void eyerok_hand_act_open(void) { + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); s16 sp1E; o->parentObj->oEyerokBossUnk1AC = o->oBehParams2ndByte; @@ -257,7 +351,7 @@ static void eyerok_hand_act_open(void) { o->collisionData = segmented_to_virtual(ssl_seg7_collision_070282F8); if (o->parentObj->oEyerokBossNumHands != 2) { - sp1E = o->oAngleToMario; + sp1E = angleToPlayer; clamp_s16(&sp1E, -0x3000, 0x3000); o->oMoveAngleYaw = sp1E; o->oForwardVel = 50.0f; @@ -269,6 +363,8 @@ static void eyerok_hand_act_open(void) { } static void eyerok_hand_act_show_eye(void) { + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); UNUSED s16 val06; cur_obj_init_animation_with_sound(5); @@ -279,7 +375,7 @@ static void eyerok_hand_act_show_eye(void) { if (o->oAnimState < 3) { o->oAnimState += 1; } else if (cur_obj_check_if_near_animation_end()) { - val06 = (s16)(o->oAngleToMario - o->oFaceAngleYaw) * o->oBehParams2ndByte; + val06 = (s16)(angleToPlayer - o->oFaceAngleYaw) * o->oBehParams2ndByte; o->oAction = EYEROK_HAND_ACT_CLOSE; } } else { @@ -296,7 +392,7 @@ static void eyerok_hand_act_show_eye(void) { if (o->parentObj->oEyerokBossNumHands != 2) { obj_face_yaw_approach(o->oMoveAngleYaw, 0x800); if (o->oTimer > 10 - && (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { + && (o->oPosZ - player->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { o->parentObj->oEyerokBossActiveHand = 0; o->oForwardVel = 0.0f; } @@ -343,11 +439,23 @@ static void eyerok_hand_act_become_active(void) { } } +static void eyerok_hand_act_die_event(void) { + if (o->oEyerokHandDead) { return; } + o->oEyerokHandDead = TRUE; + + s16 activeFlags = o->activeFlags; + obj_explode_and_spawn_coins(150.0f, 1); + o->activeFlags = activeFlags; + cur_obj_disable(); + + create_sound_spawner(SOUND_OBJ2_EYEROK_SOUND_LONG); +} + static void eyerok_hand_act_die(void) { if (cur_obj_init_anim_and_check_if_end(1)) { o->parentObj->oEyerokBossUnk1AC = 0; - obj_explode_and_spawn_coins(150.0f, 1); - create_sound_spawner(SOUND_OBJ2_EYEROK_SOUND_LONG); + eyerok_hand_act_die_event(); + o->oAction = EYEROK_HAND_ACT_DEAD; } if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) { @@ -380,7 +488,9 @@ static void eyerok_hand_act_retreat(void) { } static void eyerok_hand_act_target_mario(void) { - if (eyerok_check_mario_relative_z(400) != 0 || o->oPosZ - gMarioObject->oPosZ > 0.0f + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); + if (eyerok_check_mario_relative_z(400) != 0 || o->oPosZ - player->oPosZ > 0.0f || o->oPosZ - o->parentObj->oPosZ > 1700.0f || absf(o->oPosX - o->parentObj->oPosX) > 900.0f || (o->oMoveFlags & OBJ_MOVE_HIT_WALL)) { o->oForwardVel = 0.0f; @@ -390,11 +500,14 @@ static void eyerok_hand_act_target_mario(void) { } else { obj_forward_vel_approach(50.0f, 5.0f); approach_f32_ptr(&o->oPosY, o->oHomeY + 300.0f, 20.0f); - cur_obj_rotate_yaw_toward(o->oAngleToMario, 4000); + cur_obj_rotate_yaw_toward(angleToPlayer, 4000); } } static void eyerok_hand_act_smash(void) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); s16 sp1E; if (o->oTimer > 20) { @@ -403,10 +516,10 @@ static void eyerok_hand_act_smash(void) { eyerok_hand_pound_ground(); o->oGravity = -4.0f; } else { - sp1E = abs_angle_diff(o->oFaceAngleYaw, o->oAngleToMario); - if (o->oDistanceToMario < 300.0f && sp1E > 0x2000 && sp1E < 0x6000) { + sp1E = abs_angle_diff(o->oFaceAngleYaw, angleToPlayer); + if (distanceToPlayer < 300.0f && sp1E > 0x2000 && sp1E < 0x6000) { o->oAction = EYEROK_HAND_ACT_FIST_SWEEP; - if ((s16)(o->oFaceAngleYaw - o->oAngleToMario) < 0) { + if ((s16)(o->oFaceAngleYaw - angleToPlayer) < 0) { o->oMoveAngleYaw = 0x4000; } else { o->oMoveAngleYaw = -0x4000; @@ -422,11 +535,12 @@ static void eyerok_hand_act_smash(void) { } static void eyerok_hand_act_fist_push(void) { - if (o->oTimer > 5 && (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { + struct Object* player = nearest_player_to_object(o); + if (o->oTimer > 5 && (o->oPosZ - player->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { o->oAction = EYEROK_HAND_ACT_FIST_SWEEP; o->oForwardVel = 0.0f; - if (o->oPosX - gMarioObject->oPosX < 0.0f) { + if (o->oPosX - player->oPosX < 0.0f) { o->oMoveAngleYaw = 0x4000; } else { o->oMoveAngleYaw = -0x4000; @@ -492,6 +606,12 @@ static void eyerok_hand_act_double_pound(void) { } void bhv_eyerok_hand_loop(void) { + if (o->oAction == EYEROK_HAND_ACT_DEAD) { + eyerok_hand_act_die_event(); + return; + } + + s16 oldAction = o->oAction; o->header.gfx.scale[0] = 1.5f; if (o->oAction == EYEROK_HAND_ACT_SLEEP) { @@ -545,6 +665,8 @@ void bhv_eyerok_hand_loop(void) { case EYEROK_HAND_ACT_DIE: eyerok_hand_act_die(); break; + case EYEROK_HAND_ACT_PAUSE: + break; } o->oEyerokReceivedAttack = obj_check_attacks(&sEyerokHitbox, o->oAction); @@ -553,4 +675,12 @@ void bhv_eyerok_hand_loop(void) { load_object_collision_model(); o->header.gfx.scale[0] = 1.5f * o->oBehParams2ndByte; + + if (o->oAction != oldAction) { + if (network_owns_object(o->parentObj)) { + eyerokBossImmediateUpdate = TRUE; + } else { + o->oAction = EYEROK_HAND_ACT_PAUSE; + } + } } diff --git a/src/game/hud.c b/src/game/hud.c index e50f2391..0fc848ca 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -303,7 +303,7 @@ void render_hud_unsupported_level(void) { case COURSE_BBH: // (5) Big Boo's Haunt //case COURSE_HMC: // (6) Hazy Maze Cave case COURSE_LLL: // (7) Lethal Lava Land - //case COURSE_SSL: // (8) Shifting Sand Land + case COURSE_SSL: // (8) Shifting Sand Land //case COURSE_DDD: // (9) Dire Dire Docks //case COURSE_SL: // (10) Snowman's Land //case COURSE_WDW: // (11) Wet Dry World diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 24d73d02..2f78e41d 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -53,6 +53,7 @@ struct SyncObject { bool keepRandomSeed; bool syncDeathEvent; bool hasStandardFields; + float minUpdateRate; float maxUpdateRate; u8 (*ignore_if_true)(void); void (*on_received_pre)(u8 fromLocalIndex); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 8bb7e373..08289e5b 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -64,7 +64,8 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance) so->fullObjectSync = false; so->keepRandomSeed = false; so->hasStandardFields = (maxSyncDistance >= 0); - so->maxUpdateRate = 0; + so->minUpdateRate = 0.33f; + so->maxUpdateRate = 0.00f; so->ignore_if_true = NULL; so->on_received_pre = NULL; so->on_received_post = NULL; @@ -85,6 +86,19 @@ void network_init_object_field(struct Object *o, void* field) { bool network_owns_object(struct Object* o) { struct SyncObject* so = &gSyncObjects[o->oSyncID]; if (so == NULL) { return false; } + + // check for override + u8 shouldOverride = FALSE; + u8 shouldOwn = FALSE; + if (so->override_ownership != NULL) { + extern struct Object* gCurrentObject; + struct Object* tmp = gCurrentObject; + gCurrentObject = so->o; + so->override_ownership(&shouldOverride, &shouldOwn); + gCurrentObject = tmp; + if (shouldOverride) { return shouldOwn; } + } + return so->owned; } @@ -452,7 +466,7 @@ void network_update_objects(void) { // set max and min update rate if (so->maxUpdateRate > 0 && updateRate < so->maxUpdateRate) { updateRate = so->maxUpdateRate; } - if (updateRate < 0.33f) { updateRate = 0.33f; } + if (updateRate < so->minUpdateRate) { updateRate = so->minUpdateRate; } // see if we should update float timeSinceUpdate = ((float)clock() - (float)so->clockSinceUpdate) / (float)CLOCKS_PER_SEC;