Made Goomba Luigi-aware, fixed Mario's hurtboxes

This commit is contained in:
MysterD 2020-07-31 22:13:05 -07:00
parent c437e075ff
commit 4351a6345a
10 changed files with 59 additions and 46 deletions

View file

@ -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(),
};

View file

@ -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).

View file

@ -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)

View file

@ -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];
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}