From 4351a6345a967e48421a19edd11e6cd9dc18eb89 Mon Sep 17 00:00:00 2001 From: MysterD Date: Fri, 31 Jul 2020 22:13:05 -0700 Subject: [PATCH] Made Goomba Luigi-aware, fixed Mario's hurtboxes --- levels/castle_grounds/script.c | 1 + src/game/behaviors/bird.inc.c | 2 +- src/game/behaviors/bobomb.inc.c | 12 +++++------ src/game/behaviors/butterfly.inc.c | 4 ++-- src/game/behaviors/goomba.inc.c | 20 ++++++++++++------- src/game/interaction.c | 32 ++++++++++++++++++------------ src/game/interaction.h | 1 + src/game/obj_behaviors.c | 14 ++++++------- src/game/obj_behaviors_2.c | 7 ++++--- src/game/object_collision.c | 12 +++++------ 10 files changed, 59 insertions(+), 46 deletions(-) diff --git a/levels/castle_grounds/script.c b/levels/castle_grounds/script.c index e38624382..eae425160 100644 --- a/levels/castle_grounds/script.c +++ b/levels/castle_grounds/script.c @@ -91,6 +91,7 @@ static const LevelScript script_func_local_4[] = { OBJECT(/*model*/ MODEL_YOSHI, /*pos*/ 0, 3174, -5625, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvYoshi), // TESTING BELOW OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -2028, 260, 4664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), + OBJECT(/*model*/ MODEL_GOOMBA, /*pos*/ -2028, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvGoomba), RETURN(), }; diff --git a/src/game/behaviors/bird.inc.c b/src/game/behaviors/bird.inc.c index 95f1322d3..12a6a00e8 100644 --- a/src/game/behaviors/bird.inc.c +++ b/src/game/behaviors/bird.inc.c @@ -15,7 +15,7 @@ static void bird_act_inactive(void) { // Start flying if the object is a spawned bird or if it's a spawner bird // and Mario is within 2000 units. - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); if (o->oBehParams2ndByte == BIRD_BP_SPAWNED || dist_between_objects(o, player) < 2000.0f) { // If the object is a spawner bird, play the sound of birds flying away, // and spawn 6 spawned birds (which will start flying on the next frame). diff --git a/src/game/behaviors/bobomb.inc.c b/src/game/behaviors/bobomb.inc.c index 5c52f5c2b..eebae12f9 100644 --- a/src/game/behaviors/bobomb.inc.c +++ b/src/game/behaviors/bobomb.inc.c @@ -48,7 +48,7 @@ void bobomb_check_interactions(void) { { if ((o->oInteractStatus & INT_STATUS_MARIO_UNK1) != 0) { - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); o->oMoveAngleYaw = player->header.gfx.angle[1]; o->oForwardVel = 25.0; o->oVelY = 30.0; @@ -74,7 +74,7 @@ void bobomb_act_patrol(void) { o->oForwardVel = 5.0; collisionFlags = object_step(); - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); if ((obj_return_home_if_safe(o, o->oHomeX, o->oHomeY, o->oHomeZ, 400) == 1) && (obj_check_if_facing_toward_angle(o->oMoveAngleYaw, obj_angle_to_object(o, player), 0x2000) == 1)) { o->oBobombFuseLit = 1; @@ -95,7 +95,7 @@ void bobomb_act_chase_mario(void) { if (sp1a == 5 || sp1a == 16) cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK); - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); obj_turn_toward_object(o, player, 16, 0x800); obj_check_floor_death(collisionFlags, sObjFloor); } @@ -179,7 +179,7 @@ void bobomb_free_loop(void) { void bobomb_held_loop(void) { o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; cur_obj_init_animation(1); - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); cur_obj_set_pos_relative(player, 0, 60.0f, 100.0); o->oBobombFuseLit = 1; @@ -302,7 +302,7 @@ void bobomb_buddy_act_idle(void) { if ((sp1a == 5) || (sp1a == 16)) cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK); - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); if (dist_between_objects(o, player) < 1000.0f) o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, obj_angle_to_object(o, player), 0x140); @@ -392,7 +392,7 @@ void bobomb_buddy_act_turn_to_talk(void) { if ((sp1e == 5) || (sp1e == 16)) cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK); - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); int angleToPlayer = obj_angle_to_object(o, player); o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, angleToPlayer, 0x1000); if ((s16) o->oMoveAngleYaw == (s16) angleToPlayer) diff --git a/src/game/behaviors/butterfly.inc.c b/src/game/behaviors/butterfly.inc.c index 2cee0f25f..21d797a19 100644 --- a/src/game/behaviors/butterfly.inc.c +++ b/src/game/behaviors/butterfly.inc.c @@ -42,7 +42,7 @@ void butterfly_step(s32 speed) { } void butterfly_calculate_angle(void) { - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); player->oPosX += 5 * o->oButterflyYPhase / 4; player->oPosZ += 5 * o->oButterflyYPhase / 4; obj_turn_toward_object(o, player, 16, 0x300); @@ -59,7 +59,7 @@ void butterfly_act_rest(void) { cur_obj_init_animation(0); o->oAction = BUTTERFLY_ACT_FOLLOW_MARIO; - struct Object* player = nearest_player_object(o->oPosX, o->oPosY, o->oPosZ); + struct Object* player = nearest_player_to_object(o); o->oMoveAngleYaw = player->header.gfx.angle[1]; } } diff --git a/src/game/behaviors/goomba.inc.c b/src/game/behaviors/goomba.inc.c index bf47dda1d..5afec7600 100644 --- a/src/game/behaviors/goomba.inc.c +++ b/src/game/behaviors/goomba.inc.c @@ -74,12 +74,13 @@ void bhv_goomba_triplet_spawner_update(void) { s32 dAngle; s16 dx; s16 dz; + struct Object* player = nearest_player_to_object(o); // If mario is close enough and the goombas aren't currently loaded, then // spawn them if (o->oAction == GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED) { #ifndef NODRAWINGDISTANCE - if (o->oDistanceToMario < 3000.0f) { + if (dist_between_objects(o, player) < 3000.0f) { #endif // The spawner is capable of spawning more than 3 goombas, but this // is not used in the game @@ -102,7 +103,7 @@ void bhv_goomba_triplet_spawner_update(void) { o->oAction += 1; #ifndef NODRAWINGDISTANCE } - } else if (o->oDistanceToMario > 4000.0f) { + } else if (dist_between_objects(o, player) > 4000.0f) { // If mario is too far away, enter the unloaded action. The goombas // will detect this and unload themselves o->oAction = GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED; @@ -176,15 +177,18 @@ static void goomba_act_walk(void) { if (o->oGoombaTurningAwayFromWall) { o->oGoombaTurningAwayFromWall = obj_resolve_collisions_and_turn(o->oGoombaTargetYaw, 0x200); } else { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); // If far from home, walk toward home. - if (o->oDistanceToMario >= 25000.0f) { - o->oGoombaTargetYaw = o->oAngleToMario; + if (distanceToPlayer >= 25000.0f) { + o->oGoombaTargetYaw = angleToPlayer; o->oGoombaWalkTimer = random_linear_offset(20, 30); } if (!(o->oGoombaTurningAwayFromWall = obj_bounce_off_walls_edges_objects(&o->oGoombaTargetYaw))) { - if (o->oDistanceToMario < 500.0f) { + if (distanceToPlayer < 500.0f) { // If close to mario, begin chasing him. If not already chasing // him, jump first @@ -192,7 +196,7 @@ static void goomba_act_walk(void) { goomba_begin_jump(); } - o->oGoombaTargetYaw = o->oAngleToMario; + o->oGoombaTargetYaw = angleToPlayer; o->oGoombaRelativeSpeed = 20.0f; } else { // If mario is far away, walk at a normal pace, turning randomly @@ -229,8 +233,10 @@ static void goomba_act_attacked_mario(void) { } else { //! This can happen even when the goomba is already in the air. It's // hard to chain these in practice + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); goomba_begin_jump(); - o->oGoombaTargetYaw = o->oAngleToMario; + o->oGoombaTargetYaw = angleToPlayer; o->oGoombaTurningAwayFromWall = FALSE; } } diff --git a/src/game/interaction.c b/src/game/interaction.c index 7a9c5203b..7ad1d4884 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -703,11 +703,17 @@ u32 take_damage_from_interact_object(struct MarioState *m) { return damage; } +int get_invincibility_flag(struct MarioState *m) { + return (m == &gMarioStates[0]) + ? INT_SUBTYPE_DELAY_INVINCIBILITY + : INT_SUBTYPE_DELAY_INVINCIBILITY_LUIGI; +} + u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) { u32 damage; if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) - && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + && !(o->oInteractionSubtype & get_invincibility_flag(m))) { o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_ATTACKED_MARIO; m->interactObj = o; @@ -1143,7 +1149,7 @@ u32 interact_flame(struct MarioState *m, UNUSED u32 interactType, struct Object u32 burningAction = ACT_BURNING_JUMP; if (!sInvulnerable && !(m->flags & MARIO_METAL_CAP) && !(m->flags & MARIO_VANISH_CAP) - && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + && !(o->oInteractionSubtype & get_invincibility_flag(m))) { queue_rumble_data(5, 80); o->oInteractStatus = INT_STATUS_INTERACTED; @@ -1186,7 +1192,7 @@ u32 interact_snufit_bullet(struct MarioState *m, UNUSED u32 interactType, struct } } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } @@ -1202,7 +1208,7 @@ u32 interact_clam_or_bubba(struct MarioState *m, UNUSED u32 interactType, struct return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return TRUE; @@ -1234,7 +1240,7 @@ u32 interact_bully(struct MarioState *m, UNUSED u32 interactType, struct Object } else if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) - && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + && !(o->oInteractionSubtype & get_invincibility_flag(m))) { o->oInteractStatus = INT_STATUS_INTERACTED; m->invincTimer = 2; @@ -1254,7 +1260,7 @@ u32 interact_bully(struct MarioState *m, UNUSED u32 interactType, struct Object u32 interact_shock(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) - && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + && !(o->oInteractionSubtype & get_invincibility_flag(m))) { u32 actionArg = (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) == 0; o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_ATTACKED_MARIO; @@ -1272,14 +1278,14 @@ u32 interact_shock(struct MarioState *m, UNUSED u32 interactType, struct Object } } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; } static u32 interact_stub(UNUSED struct MarioState *m, UNUSED u32 interactType, struct Object *o) { - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; @@ -1290,7 +1296,7 @@ u32 interact_mr_blizzard(struct MarioState *m, UNUSED u32 interactType, struct O return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } @@ -1332,7 +1338,7 @@ u32 interact_hit_from_below(struct MarioState *m, UNUSED u32 interactType, struc return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; @@ -1367,7 +1373,7 @@ u32 interact_bounce_top(struct MarioState *m, UNUSED u32 interactType, struct Ob return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; @@ -1383,7 +1389,7 @@ u32 interact_unknown_08(struct MarioState *m, UNUSED u32 interactType, struct Ob return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; @@ -1394,7 +1400,7 @@ u32 interact_damage(struct MarioState *m, UNUSED u32 interactType, struct Object return TRUE; } - if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + if (!(o->oInteractionSubtype & get_invincibility_flag(m))) { sDelayInvincTimer = TRUE; } return FALSE; diff --git a/src/game/interaction.h b/src/game/interaction.h index 4d1aba968..945e4bacb 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -44,6 +44,7 @@ // Damaging interactions #define INT_SUBTYPE_DELAY_INVINCIBILITY 0x00000002 +#define INT_SUBTYPE_DELAY_INVINCIBILITY_LUIGI 0x00008000 #define INT_SUBTYPE_BIG_KNOCKBACK 0x00000008 /* Used by Bowser, sets Mario's forward velocity to 40 on hit */ // INTERACT_GRABBABLE diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index cadf366c2..2430beafc 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -517,17 +517,17 @@ s32 is_point_within_radius_of_mario(f32 x, f32 y, f32 z, s32 dist) { /** * Returns either gMarioObject or gLuigiObject depending on what is closer */ -struct Object* nearest_player_object(f32 x, f32 y, f32 z) { - f32 mx = gMarioObject->header.gfx.pos[0] - x; - f32 my = gMarioObject->header.gfx.pos[1] - y; - f32 mz = gMarioObject->header.gfx.pos[2] - z; +struct Object* nearest_player_to_object(struct Object *obj) { + f32 mx = gMarioObject->header.gfx.pos[0] - obj->oPosX; + f32 my = gMarioObject->header.gfx.pos[1] - obj->oPosY; + f32 mz = gMarioObject->header.gfx.pos[2] - obj->oPosZ; mx *= mx; my *= my; mz *= mz; - f32 lx = gLuigiObject->header.gfx.pos[0] - x; - f32 ly = gLuigiObject->header.gfx.pos[1] - y; - f32 lz = gLuigiObject->header.gfx.pos[2] - z; + f32 lx = gLuigiObject->header.gfx.pos[0] - obj->oPosX; + f32 ly = gLuigiObject->header.gfx.pos[1] - obj->oPosY; + f32 lz = gLuigiObject->header.gfx.pos[2] - obj->oPosZ; lx *= lx; ly *= ly; lz *= lz; diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index cf62a87f9..a7dd244a9 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -882,9 +882,10 @@ static void treat_far_home_as_mario(f32 threshold) { o->oAngleToMario = atan2s(dz, dx); o->oDistanceToMario = 25000.0f; } else { - dx = o->oHomeX - gMarioObject->oPosX; - dy = o->oHomeY - gMarioObject->oPosY; - dz = o->oHomeZ - gMarioObject->oPosZ; + struct Object* player = nearest_player_to_object(o); + dx = o->oHomeX - player->oPosX; + dy = o->oHomeY - player->oPosY; + dz = o->oHomeZ - player->oPosZ; distance = sqrtf(dx * dx + dy * dy + dz * dz); if (distance > threshold) { diff --git a/src/game/object_collision.c b/src/game/object_collision.c index d3da8e8ef..d0c61d33b 100644 --- a/src/game/object_collision.c +++ b/src/game/object_collision.c @@ -68,10 +68,9 @@ int detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { f32 sp28 = a->hurtboxRadius + b->hurtboxRadius; f32 sp24 = sqrtf(sp34 * sp34 + sp2C * sp2C); - if (a == gMarioObject || a == gLuigiObject) { - b->oInteractionSubtype |= INT_SUBTYPE_DELAY_INVINCIBILITY; - } - + if (a == gMarioObject) { b->oInteractionSubtype |= INT_SUBTYPE_DELAY_INVINCIBILITY; } + if (a == gLuigiObject) { b->oInteractionSubtype |= INT_SUBTYPE_DELAY_INVINCIBILITY_LUIGI; } + if (sp28 > sp24) { f32 sp20 = a->hitboxHeight + sp3C; f32 sp1C = b->hurtboxHeight + sp38; @@ -82,9 +81,8 @@ int detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { if (sp20 < sp38) { return 0; } - if (a == gMarioObject || a == gLuigiObject) { - b->oInteractionSubtype &= ~INT_SUBTYPE_DELAY_INVINCIBILITY; - } + if (a == gMarioObject) { b->oInteractionSubtype &= ~INT_SUBTYPE_DELAY_INVINCIBILITY; } + if (a == gLuigiObject) { b->oInteractionSubtype &= ~INT_SUBTYPE_DELAY_INVINCIBILITY_LUIGI; } return 1; }