diff --git a/Makefile b/Makefile index e987a9e1f..af9c14b4e 100644 --- a/Makefile +++ b/Makefile @@ -1469,4 +1469,4 @@ MAKEFLAGS += --no-builtin-rules -include $(DEP_FILES) -print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true +print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true \ No newline at end of file diff --git a/src/game/behaviors/bobomb.inc.c b/src/game/behaviors/bobomb.inc.c index 4b17471f6..115fb7fcb 100644 --- a/src/game/behaviors/bobomb.inc.c +++ b/src/game/behaviors/bobomb.inc.c @@ -301,25 +301,26 @@ void bhv_bobomb_buddy_init(void) { } void bobomb_buddy_act_idle(void) { - UNUSED u8 filler[4]; - s16 sp1a = o->header.gfx.animInfo.animFrame; - UNUSED s16 collisionFlags = 0; + s16 animFrame = o->header.gfx.animInfo.animFrame; o->oBobombBuddyPosXCopy = o->oPosX; o->oBobombBuddyPosYCopy = o->oPosY; o->oBobombBuddyPosZCopy = o->oPosZ; - collisionFlags = object_step(); + object_step(); - if ((sp1a == 5) || (sp1a == 16)) + if ((animFrame == 5) || (animFrame == 16)) { cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK); + } struct Object* player = nearest_player_to_object(o); - if (dist_between_objects(o, player) < 1000.0f) + if (dist_between_objects(o, player) < 1000.0f) { o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, obj_angle_to_object(o, player), 0x140); + } - if (o->oInteractStatus == INT_STATUS_INTERACTED) + if (o->oInteractStatus == INT_STATUS_INTERACTED) { o->oAction = BOBOMB_BUDDY_ACT_TURN_TO_TALK; + } } /** @@ -345,24 +346,27 @@ void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) { forceCannonOpen = FALSE; cannonClosed = cur_obj_nearest_object_with_behavior(bhvCannonClosed); - if (cannonClosed != 0) + if (cannonClosed != 0) { o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_OPENING; - else + } else { o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_STOP_TALKING; + } } break; case BOBOMB_BUDDY_CANNON_OPENING: cannonClosed = cur_obj_nearest_object_with_behavior(bhvCannonClosed); cutscene = cutscene_object(CUTSCENE_PREPARE_CANNON, cannonClosed); - if (cutscene == -1) + if (cutscene == -1) { o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_OPENED; + } break; case BOBOMB_BUDDY_CANNON_OPENED: buddyText = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogSecondText); - if (buddyText != 0) + if (buddyText != 0) { o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_STOP_TALKING; + } break; case BOBOMB_BUDDY_CANNON_STOP_TALKING: @@ -400,25 +404,28 @@ void bobomb_buddy_act_talk(void) { break; case BOBOMB_BUDDY_ROLE_CANNON: - if (gCurrCourseNum == COURSE_BOB) + if (gCurrCourseNum == COURSE_BOB) { bobomb_buddy_cannon_dialog(DIALOG_004, DIALOG_105); - else + } else { bobomb_buddy_cannon_dialog(DIALOG_047, DIALOG_106); + } break; } } } void bobomb_buddy_act_turn_to_talk(void) { - s16 sp1e = o->header.gfx.animInfo.animFrame; - if ((sp1e == 5) || (sp1e == 16)) + s16 animFrame = o->header.gfx.animInfo.animFrame; + if ((animFrame == 5) || (animFrame == 16)) { cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK); + } - struct Object* player = nearest_player_to_object(o); + struct Object *player = nearest_interacting_player_to_object(o); s32 angleToPlayer = obj_angle_to_object(o, player); o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, angleToPlayer, 0x1000); - if ((s16) o->oMoveAngleYaw == (s16) angleToPlayer) + if ((s16) o->oMoveAngleYaw == (s16) angleToPlayer) { o->oAction = BOBOMB_BUDDY_ACT_TALK; + } cur_obj_play_sound_2(SOUND_ACTION_READ_SIGN); } diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index f7fa7740d..aae60a52f 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -1,19 +1,22 @@ // bowser.c.inc static u32 networkBowserAnimationIndex = 0; static u8 bowserIsDying = FALSE; +static u8 bowserCutscenePlayed = FALSE; +static u8 bowserIsCutscenePlayer = FALSE; void bowser_tail_anchor_act_0(void) { struct Object* bowser = o->parentObj; struct Object* player = nearest_player_to_object(o); cur_obj_become_tangible(); cur_obj_scale(1.0f); - if (bowser->oAction == 19) + if (bowser->oAction == 5 || bowser->oAction == 6 || bowser->oAction == 19 || bowser->oAction == 20) { bowser->oIntangibleTimer = -1; - else if (obj_check_if_collided_with_object(o, player)) { + } else if (obj_check_if_collided_with_object(o, player)) { bowser->oIntangibleTimer = 0; o->oAction = 2; - } else + } else { bowser->oIntangibleTimer = -1; + } } void bowser_tail_anchor_act_1(void) { @@ -177,31 +180,37 @@ s32 bowser_set_anim_look_up_and_walk(void) { s32 bowser_set_anim_slow_gait(void) { o->oForwardVel = 3.0f; cur_obj_init_animation_with_sound(13); - if (cur_obj_check_if_near_animation_end()) + if (cur_obj_check_if_near_animation_end()) { return 1; - else - return 0; + } + return 0; } s32 bowser_set_anim_look_down(void) { cur_obj_init_animation_with_sound(14); - if (cur_obj_check_anim_frame(20)) + if (cur_obj_check_anim_frame(20)) { o->oForwardVel = 0.0f; - if (cur_obj_check_if_near_animation_end()) + } + if (cur_obj_check_if_near_animation_end()) { return 1; - else - return 0; + } + return 0; } void bowser_initialize_action(void) { - if (o->oBowserUnk88 == 0) + if (o->oBowserUnk88 == 0 && !bowserCutscenePlayed) { o->oAction = 5; - else if (o->oBowserUnk88 == 1) + } else if (o->oBowserUnk88 == 1 && !bowserCutscenePlayed) { o->oAction = 6; - else if (o->oBehParams2ndByte == 1) + } else if (o->oBehParams2ndByte == 1) { + bowserCutscenePlayed = TRUE; o->oAction = 13; - else + if (bowserIsCutscenePlayer) { network_send_object_reliability(o, TRUE); } + } else { + bowserCutscenePlayed = TRUE; o->oAction = 0; + if (bowserIsCutscenePlayer) { network_send_object_reliability(o, TRUE); } + } } void bowser_act_text_wait(void) // not much @@ -374,12 +383,13 @@ void bowser_act_default(void) // only lasts one frame o->oAngleVelYaw = 0; o->oForwardVel = 0.0f; o->oVelY = 0.0f; - if (BITDW) + if (BITDW) { bowser_bitdw_act_controller(); - else if (BITFS) + } else if (BITFS) { bowser_bitfs_act_controller(); - else + } else { bowser_bits_act_controller(); + } // Action 14 commonly follows } @@ -850,12 +860,14 @@ void bowser_spawn_grand_star_key(void) { reward = (prevReward != NULL) ? prevReward : spawn_object(o, MODEL_STAR, bhvGrandStar); gSecondCameraFocus = reward; - if (prevReward == NULL && reward != NULL) { + if (network_owns_object(o) && prevReward == NULL && reward != NULL) { // set the home position reward->oHomeX = reward->oPosX; reward->oHomeY = reward->oPosY; reward->oHomeZ = reward->oPosZ; + network_set_sync_id(reward); + struct Object* spawn_objects[] = { reward }; u32 models[] = { MODEL_STAR }; network_send_spawn_objects(spawn_objects, models, 1); @@ -921,7 +933,6 @@ s32 bowser_dead_wait_for_mario(void) { s32 bowser_dead_twirl_into_trophy(void) { bowserIsDying = TRUE; - s32 ret = 0; if (o->header.gfx.scale[0] < 0.8) o->oAngleVelYaw += 0x80; if (o->header.gfx.scale[0] > 0.2) { @@ -933,11 +944,11 @@ s32 bowser_dead_twirl_into_trophy(void) { o->oGravity = 0.0f; } if (o->header.gfx.scale[1] < 0.5) - ret = 1; + return 1; o->oMoveAngleYaw += o->oAngleVelYaw; if (o->oOpacity >= 3) o->oOpacity -= 2; - return ret; + return 0; } void bowser_dead_hide(void) { @@ -1094,6 +1105,9 @@ void bowser_act_ride_tilting_platform(void) { cur_obj_extend_animation_if_at_end(); } +void bowser_act_nothing(void) { + +} s32 bowser_check_fallen_off_stage(void) // bowser off stage? { @@ -1114,7 +1128,8 @@ void (*sBowserActions[])(void) = { bowser_act_default, bowser_act_thrown_droppe bowser_act_dead, bowser_act_text_wait, bowser_act_intro_walk, bowser_act_charge_mario, bowser_act_spit_fire_into_sky, bowser_act_spit_fire_onto_floor, bowser_act_hit_edge, bowser_act_turn_from_edge, bowser_act_hit_mine, bowser_act_jump, bowser_act_walk_to_mario, bowser_act_breath_fire, - bowser_act_teleport, bowser_act_jump_towards_mario, bowser_act_unused_slow_walk, bowser_act_ride_tilting_platform }; + bowser_act_teleport, bowser_act_jump_towards_mario, bowser_act_unused_slow_walk, bowser_act_ride_tilting_platform, + bowser_act_nothing, }; struct SoundState D_8032F5B8[] = { { 0, 0, 0, NO_SOUND }, { 0, 0, 0, NO_SOUND }, { 0, 0, 0, NO_SOUND }, @@ -1257,8 +1272,13 @@ void bhv_bowser_loop(void) { geo_obj_init_animation(&o->header.gfx, &anim); } } + + // If Bowser isn't in a cutscene, It's been played already. + if (!bowserCutscenePlayed && (o->oAction != 5 && o->oAction != 6 && o->oAction != 20)) { + bowserCutscenePlayed = TRUE; + } - s16 angleToMario; // AngleToMario from Bowser's perspective + s16 angleToMario; // AngleToMario from Bowser's perspective s16 angleToCentre; // AngleToCentre from Bowser's perspective o->oBowserDistToCentre = sqrtf(o->oPosX * o->oPosX + o->oPosZ * o->oPosZ); @@ -1314,6 +1334,13 @@ void bhv_bowser_loop(void) { } void bhv_bowser_override_ownership(u8* shouldOverride, u8* shouldOwn) { + // Nothing state sanity check. + if (o->oAction == 20) { + *shouldOverride = TRUE; + *shouldOwn = FALSE; + return; + } + // tilting platform static u8 tiltingTimer = 0; if (o->oAction == 19) { tiltingTimer = 5; } @@ -1327,6 +1354,7 @@ void bhv_bowser_override_ownership(u8* shouldOverride, u8* shouldOwn) { static u8 bhv_bowser_ignore_if_true(void) { if (bowserIsDying) { return TRUE; } if (o->oAction == 19) { return TRUE; } // let the platform get to a stable state + if (bowserIsCutscenePlayer && (o->oAction == 5 || o->oAction == 6)) { return TRUE; } // Ignore updates till our cutscene is done. return FALSE; } @@ -1346,21 +1374,32 @@ void bhv_bowser_init(void) { o->oBowserUnk1B2 = D_8032F690[level]; o->oHealth = D_8032F694[level]; cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_INIT); - o->oAction = 5; o->oBowserUnk1AE = 0; o->oBowserEyesShut = 0; - - struct SyncObject* so = network_init_object(o, 8000.0f); - if (so) { - so->override_ownership = bhv_bowser_override_ownership; - so->ignore_if_true = bhv_bowser_ignore_if_true; - so->fullObjectSync = TRUE; - network_init_object_field_with_size(o, &o->header.gfx.node.flags, 16); - network_init_object_field_with_size(o, &o->header.gfx.animInfo.animFrame, 16); - network_init_object_field(o, &networkBowserAnimationIndex); - network_init_object_field(o, &o->header.gfx.scale[0]); - network_init_object_field(o, &o->header.gfx.scale[1]); - network_init_object_field(o, &o->header.gfx.scale[2]); + bowserCutscenePlayed = FALSE; + + // Make sure we're the first to trigger Bowser. + if (!is_other_player_active()) { + bowserIsCutscenePlayer = TRUE; + o->oAction = 5; // bowser_act_text_wait + } else { // If we aren't do nothing till we get our sync. + bowserIsCutscenePlayer = FALSE; + o->oAction = 20; // bowser_act_nothing + } + + if (!network_sync_object_initialized(o)) { + struct SyncObject* so = network_init_object(o, 8000.0f); + if (so) { + so->override_ownership = bhv_bowser_override_ownership; + so->ignore_if_true = bhv_bowser_ignore_if_true; + so->fullObjectSync = TRUE; + network_init_object_field_with_size(o, &o->header.gfx.node.flags, 16); + network_init_object_field_with_size(o, &o->header.gfx.animInfo.animFrame, 16); + network_init_object_field(o, &networkBowserAnimationIndex); + network_init_object_field(o, &o->header.gfx.scale[0]); + network_init_object_field(o, &o->header.gfx.scale[1]); + network_init_object_field(o, &o->header.gfx.scale[2]); + } } } diff --git a/src/game/behaviors/grand_star.inc.c b/src/game/behaviors/grand_star.inc.c index 0f5f4fe9c..f97d89913 100644 --- a/src/game/behaviors/grand_star.inc.c +++ b/src/game/behaviors/grand_star.inc.c @@ -1,8 +1,8 @@ // grand_star.c.inc -s32 arc_to_goal_pos(Vec3f a0, Vec3f a1, f32 yVel, f32 gravity) { - f32 dx = a0[0] - a1[0]; - f32 dz = a0[2] - a1[2]; +s32 arc_to_goal_pos(Vec3f empty, Vec3f pos, f32 yVel, f32 gravity) { + f32 dx = empty[0] - pos[0]; + f32 dz = empty[2] - pos[2]; f32 planarDist = sqrtf(dx * dx + dz * dz); o->oMoveAngleYaw = atan2s(dz, dx); o->oVelY = yVel; @@ -22,12 +22,15 @@ void bhv_grand_star_init(void) { struct Object *other = cur_obj_nearest_object_with_behavior(bhvGrandStar); if (other == NULL) { if (!network_sync_object_initialized(o)) { - struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + struct SyncObject *so = network_init_object(o, 4000.0f); if (so) { - network_init_object_field_with_size(o, &o->activeFlags, 16); + network_init_object_field(o, &o->header.gfx.scale[0]); + network_init_object_field(o, &o->header.gfx.scale[1]); + network_init_object_field(o, &o->header.gfx.scale[2]); network_init_object_field(o, &o->oPrevAction); network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oSubAction); + network_init_object_field(o, &o->oInteractStatus); network_init_object_field(o, &o->oTimer); network_init_object_field(o, &o->oHomeX); network_init_object_field(o, &o->oHomeY); @@ -41,7 +44,7 @@ void bhv_grand_star_init(void) { network_init_object_field(o, &o->oAngleVelYaw); network_init_object_field(o, &o->oMoveAngleYaw); network_init_object_field(o, &o->oFaceAngleYaw); - network_init_object_field(o, &o->oGrandStarUnk108); + network_init_object_field(o, &o->oGraphYOffset); } } return; @@ -66,12 +69,12 @@ void bhv_grand_star_loop(void) { spawn_sparkle_particles(3, 200, 80, -60); } else if (o->oAction == 1) { if (o->oTimer == 0) { - Vec3f sp28; - sp28[0] = sp28[1] = sp28[2] = 0.0f; + Vec3f empty; + empty[0] = empty[1] = empty[2] = 0.0f; cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR); cutscene_object(CUTSCENE_STAR_SPAWN, o); - o->oGrandStarUnk108 = arc_to_goal_pos(sp28, &o->oPosX, 80.0f, -2.0f); + o->oGrandStarUnk108 = arc_to_goal_pos(empty, &o->oPosX, 80.0f, -2.0f); } cur_obj_move_using_fvel_and_gravity(); if (o->oSubAction == 0) { @@ -92,13 +95,25 @@ void bhv_grand_star_loop(void) { cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR_JUMP); } spawn_sparkle_particles(3, 200, 80, -60); - } else { + } else if (o->oAction == 2) { + // Make our object tangible. cur_obj_become_tangible(); + // Check for if the jumbo star has been collected. if (o->oInteractStatus & INT_STATUS_INTERACTED) { + // Make sure we're in the jumbo star cutscene. if (gMarioStates[0].action != ACT_JUMBO_STAR_CUTSCENE) { set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0); } + // Increment our action, The star despawns next action. + o->oAction++; + } + } else { + // The star cutscene has started, Make sure the star is deleted + // if it isn't already deactivated. + if (o->activeFlags != ACTIVE_FLAG_DEACTIVATED) { + // Mark our object for deletion. obj_mark_for_deletion(o); + // Reset our interactive status. o->oInteractStatus = 0; } } @@ -108,4 +123,4 @@ void bhv_grand_star_loop(void) { o->oFaceAngleYaw += o->oAngleVelYaw; cur_obj_scale(2.0f); o->oGraphYOffset = 110.0f; -} +} \ No newline at end of file diff --git a/src/game/behaviors/treasure_chest.inc.c b/src/game/behaviors/treasure_chest.inc.c index 227a2838e..55d689a46 100644 --- a/src/game/behaviors/treasure_chest.inc.c +++ b/src/game/behaviors/treasure_chest.inc.c @@ -327,4 +327,4 @@ void bhv_treasure_chest_loop(void) { case 2: break; } -} +} \ No newline at end of file diff --git a/src/game/camera.c b/src/game/camera.c index abdfd0bcd..f82fce7a2 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3336,7 +3336,8 @@ void reset_camera(struct Camera *c) { } void init_camera(struct Camera *c) { - struct Surface *floor = 0; + struct Surface *floor = NULL; + struct Object *obj = NULL; Vec3f marioOffset; s32 i; @@ -3391,18 +3392,34 @@ void init_camera(struct Camera *c) { case LEVEL_BOWSER_1: #ifndef VERSION_JP if (gCurrDemoInput == NULL) { + // Make sure Bowser is in a state that we'd start speaking to him in. + obj = find_object_with_behavior(bhvBowser); + if (obj != NULL && obj->oAction != 5) { break; } + start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); } else if (gSecondCameraFocus != NULL) { gSecondCameraFocus->oBowserUnk88 = 2; } #else + // Make sure Bowser is in a state that we'd start speaking to him in. + obj = find_object_with_behavior(bhvBowser); + if (obj != NULL && obj->oAction != 5) { break; } + start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); #endif break; case LEVEL_BOWSER_2: + // Make sure Bowser is in a state that we'd start speaking to him in. + obj = find_object_with_behavior(bhvBowser); + if (obj != NULL && obj->oAction != 5) { break; } + start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); break; case LEVEL_BOWSER_3: + // Make sure Bowser is in a state that we'd start speaking to him in. + obj = find_object_with_behavior(bhvBowser); + if (obj != NULL && obj->oAction != 5) { break; } + start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); break; diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index b4e2899e4..8eb5bb448 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -536,6 +536,14 @@ u8 is_player_active(struct MarioState* m) { return TRUE; } +u8 is_other_player_active(void) { + for (s32 i = 1; i < MAX_PLAYERS; i++) { + struct MarioState *m = &gMarioStates[i]; + if (is_player_active(m)) { return TRUE; } + } + return FALSE; +} + u8 is_player_in_local_area(struct MarioState* m) { if (gNetworkType == NT_NONE && m == &gMarioStates[0]) { return TRUE; } struct NetworkPlayer* np = &gNetworkPlayers[m->playerIndex]; @@ -589,6 +597,43 @@ struct Object* nearest_player_to_object(struct Object *obj) { return nearest->marioObj; } +/** + * Returns closest MarioState that's interacting with the object. + */ +struct MarioState *nearest_interacting_mario_state_to_object(struct Object *obj) { + struct MarioState *nearest = NULL; + f32 nearestDist = 0; + u8 checkActive = TRUE; + do { + for (s32 i = 0; i < MAX_PLAYERS; i++) { + if (gMarioStates[i].marioObj == obj) { continue; } + if (gMarioStates[i].interactObj != obj) { continue; } + if (checkActive && !is_player_active(&gMarioStates[i])) { continue; } + float dist = dist_between_objects(obj, gMarioStates[i].marioObj); + if (nearest == NULL || dist < nearestDist) { + nearest = &gMarioStates[i]; + nearestDist = dist; + } + } + if (!checkActive) { break; } + checkActive = FALSE; + } while (nearest == NULL); + + if (nearest == NULL) { + nearest = &gMarioStates[0]; + } + + return nearest; +} + +/** + * Returns closest marioObj that's interacting with the object. + */ +struct Object *nearest_interacting_player_to_object(struct Object *obj) { + struct MarioState *nearest = nearest_interacting_mario_state_to_object(obj); + return nearest->marioObj; +} + /** * Returns whether or not the MarioState is the closet MarioState * to the object. diff --git a/src/game/obj_behaviors.h b/src/game/obj_behaviors.h index 6f7092d71..39b78a292 100644 --- a/src/game/obj_behaviors.h +++ b/src/game/obj_behaviors.h @@ -163,9 +163,12 @@ void bhv_rr_cruiser_wing_init(void); void bhv_rr_cruiser_wing_loop(void); struct Object* spawn_default_star(f32 sp20, f32 sp24, f32 sp28); u8 is_player_active(struct MarioState* m); +u8 is_other_player_active(void); u8 is_player_in_local_area(struct MarioState* m); struct MarioState* nearest_mario_state_to_object(struct Object* obj); struct Object* nearest_player_to_object(struct Object* obj); +struct MarioState *nearest_interacting_mario_state_to_object(struct Object *obj); +struct Object *nearest_interacting_player_to_object(struct Object *obj); u8 is_nearest_mario_state_to_object(struct MarioState* m, struct Object* obj); u8 is_nearest_player_to_object(struct Object* m, struct Object* obj); #endif // OBJ_BEHAVIORS_H diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index aa2094d25..5ff9a791b 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -1036,6 +1036,22 @@ s32 count_objects_with_behavior(const BehaviorScript *behavior) { return count; } +struct Object *find_object_with_behavior(const BehaviorScript *behavior) { + uintptr_t *behaviorAddr = segmented_to_virtual(behavior); + struct ObjectNode *listHead = &gObjectLists[get_object_list_from_behavior(behaviorAddr)]; + struct ObjectNode *obj = listHead->next; + + while (listHead != obj) { + if (((struct Object *) obj)->behavior == behaviorAddr) { + return (struct Object *)obj; + } + + obj = obj->next; + } + + return NULL; +} + struct Object *cur_obj_find_nearby_held_actor(const BehaviorScript *behavior, f32 maxDist) { const BehaviorScript *behaviorAddr = segmented_to_virtual(behavior); struct ObjectNode *listHead; diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index 1da5f8933..be3ba4b21 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -146,6 +146,7 @@ f32 cur_obj_dist_to_nearest_object_with_behavior(const BehaviorScript* behavior) struct Object* cur_obj_find_nearest_pole(void); struct Object *cur_obj_find_nearest_object_with_behavior(const BehaviorScript * behavior, f32 *dist); u16 cur_obj_count_objects_with_behavior(const BehaviorScript* behavior, f32 dist); +struct Object *find_object_with_behavior(const BehaviorScript *behavior); struct Object *find_unimportant_object(void); s32 count_unimportant_objects(void); s32 count_objects_with_behavior(const BehaviorScript *behavior);