mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-12-22 16:30:23 +00:00
Made Goomba Luigi-aware, fixed Mario's hurtboxes
This commit is contained in:
parent
c437e075ff
commit
4351a6345a
10 changed files with 59 additions and 46 deletions
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue