Fix various bugs with spiny and lakitu

This commit is contained in:
MysterD 2022-01-14 19:10:22 -08:00
parent 839575efe1
commit 625e9b5df9
7 changed files with 103 additions and 10 deletions

View File

@ -520,6 +520,7 @@ const BehaviorScript* gBehaviorTable[id_bhv_max_count] = {
enum BehaviorId get_id_from_behavior(const BehaviorScript* behavior) {
if (behavior == NULL) { return 0; }
return (enum BehaviorId)(behavior[1] & 0xFFFF);
}

View File

@ -33,7 +33,6 @@ void bhv_donut_platform_update(void) {
network_init_object(o, 4000.0f);
network_init_object_field(o, &o->oGravity);
network_init_object_field(o, &o->oIntangibleTimer);
network_init_object_field(o, &o->header.gfx.node.flags);
}
struct Object* player = nearest_player_to_object(o);

View File

@ -109,6 +109,7 @@ static void enemy_lakitu_sub_act_no_spiny(void) {
cur_obj_init_animation_with_sound(1);
o->oEnemyLakituNumSpinies = cur_obj_count_objects_with_behavior(bhvSpiny, 2000);
if (o->oEnemyLakituSpinyCooldown != 0) {
o->oEnemyLakituSpinyCooldown -= 1;
} else if (o->oEnemyLakituNumSpinies < 3 && distanceToPlayer < 800.0f
@ -140,6 +141,12 @@ static void enemy_lakitu_sub_act_no_spiny(void) {
* enter the throw spiny sub-action.
*/
static void enemy_lakitu_sub_act_hold_spiny(void) {
if (o->prevObj == NULL) {
o->oSubAction = ENEMY_LAKITU_SUB_ACT_NO_SPINY;
o->oEnemyLakituSpinyCooldown = 0;
return;
}
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
@ -191,6 +198,12 @@ static void enemy_lakitu_act_main(void) {
obj_update_blinking(&o->oEnemyLakituBlinkTimer, 20, 40, 4);
if (o->prevObj != NULL) {
if (o->prevObj->behavior != bhvSpiny || o->prevObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
o->prevObj = NULL;
}
}
switch (o->oSubAction) {
case ENEMY_LAKITU_SUB_ACT_NO_SPINY:
enemy_lakitu_sub_act_no_spiny();
@ -203,7 +216,11 @@ static void enemy_lakitu_act_main(void) {
break;
}
cur_obj_move_standard(78);
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
if (distanceToPlayer <= o->oDrawingDistance) {
cur_obj_move_standard(78);
}
// Die and drop held spiny when attacked by mario
if (obj_check_attacks(&sEnemyLakituHitbox, o->oAction)) {
@ -222,7 +239,6 @@ void bhv_enemy_lakitu_update(void) {
network_init_object_field(o, &o->oEnemyLakituBlinkTimer);
network_init_object_field(o, &o->oEnemyLakituSpinyCooldown);
network_init_object_field(o, &o->oEnemyLakituFaceForwardCountdown);
network_init_object_field(o, &o->oEnemyLakituNumSpinies);
}
treat_far_home_as_mario(2000.0f, NULL, NULL);

View File

@ -33,12 +33,56 @@ static u8 sSpinyWalkAttackHandlers[] = {
/* ATTACK_FROM_BELOW: */ ATTACK_HANDLER_KNOCKBACK,
};
static u32 spinyAnimCache = 0;
static void spiny_to_anim_cache(void) {
if (o->oAnimations == (struct Animation**)spiny_egg_seg5_anims_050157E4) {
spinyAnimCache = 0;
} else if (o->oAnimations == (struct Animation**)spiny_seg5_anims_05016EAC) {
spinyAnimCache = 1;
} else {
assert(false);
}
}
static void spiny_from_anim_cache(void) {
struct Animation** anim = NULL;
switch (spinyAnimCache) {
case 0:
anim = (struct Animation**)spiny_egg_seg5_anims_050157E4;
break;
case 1:
anim = (struct Animation**)spiny_seg5_anims_05016EAC;
break;
default:
assert(false);
}
if (anim != o->oAnimations) {
obj_init_animation_with_sound(o, (const struct Animation* const*)anim, 0);
}
}
static void bhv_spiny_on_received_post(UNUSED u8 localIndex) {
spiny_from_anim_cache();
}
static void bhv_spiny_on_sent_pre(void) {
spiny_to_anim_cache();
}
/**
* If the spiny was spawned by lakitu and mario is far away, despawn.
*/
static s32 spiny_check_active(void) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
if (o->parentObj == NULL || o->parentObj->behavior != bhvEnemyLakitu) {
obj_mark_for_deletion(o);
return FALSE;
}
if (o->parentObj != o) {
if (distanceToPlayer > 2500.0f) {
//! It's possible for the lakitu to despawn while the spiny still
@ -48,7 +92,7 @@ static s32 spiny_check_active(void) {
// behave similar to a regular goomba.
// It can also be used on a bob-omb respawner to change its model
// to a butterfly or fish.
o->parentObj->oEnemyLakituNumSpinies -= 1;
//o->parentObj->oEnemyLakituNumSpinies -= 1;
obj_mark_for_deletion(o);
return FALSE;
}
@ -65,6 +109,7 @@ static void spiny_act_walk(void) {
cur_obj_update_floor_and_walls();
o->oGraphYOffset = -17.0f;
o->oFaceAnglePitch = 0;
cur_obj_init_animation_with_sound(0);
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
@ -132,7 +177,7 @@ static void spiny_act_held_by_lakitu(void) {
o->oParentRelativePosY = 35.0f;
o->oParentRelativePosZ = -100.0f;
if (o->parentObj->prevObj == NULL) {
if (o->parentObj != NULL && o->parentObj->prevObj == NULL) {
o->oAction = SPINY_ACT_THROWN_BY_LAKITU;
o->oMoveAngleYaw = o->parentObj->oFaceAngleYaw;
@ -173,7 +218,7 @@ static void spiny_act_thrown_by_lakitu(void) {
if (obj_check_attacks(&sSpinyHitbox, o->oAction)) {
if (o->parentObj != o) {
o->parentObj->oEnemyLakituNumSpinies -= 1;
//o->parentObj->oEnemyLakituNumSpinies -= 1;
}
}
}
@ -193,7 +238,10 @@ void bhv_spiny_update(void) {
if (!network_sync_object_initialized(o)) {
struct SyncObject* so = network_init_object(o, 4000.0f);
so->syncDeathEvent = FALSE;
so->on_received_post = bhv_spiny_on_received_post;
so->on_sent_pre = bhv_spiny_on_sent_pre;
so->override_ownership = bhv_spiny_override_ownership;
network_init_object_field(o, &o->oGraphYOffset);
network_init_object_field(o, &o->oFaceAngleYaw);
network_init_object_field(o, &o->oSpinyTimeUntilTurn);
@ -202,13 +250,17 @@ void bhv_spiny_update(void) {
network_init_object_field(o, &o->oMoveFlags);
network_init_object_field(o, &o->oInteractType);
network_init_object_field(o, &o->oFaceAnglePitch);
network_init_object_field(o, &spinyAnimCache);
struct Object* lakitu = cur_obj_nearest_object_with_behavior(bhvEnemyLakitu);
if (lakitu != NULL) {
lakitu->prevObj = o;
o->oAction = SPINY_ACT_HELD_BY_LAKITU;
obj_init_animation_with_sound(o, spiny_egg_seg5_anims_050157E4, 0);
o->parentObj = lakitu;
if ((lakitu->oSubAction == ENEMY_LAKITU_SUB_ACT_HOLD_SPINY) && (o->oAction == SPINY_ACT_HELD_BY_LAKITU)) {
lakitu->prevObj = o;
o->oAction = SPINY_ACT_HELD_BY_LAKITU;
obj_init_animation_with_sound(o, spiny_egg_seg5_anims_050157E4, 0);
}
}
}

View File

@ -959,6 +959,30 @@ struct Object *cur_obj_find_nearest_object_with_behavior(const BehaviorScript *b
return closestObj;
}
u16 cur_obj_count_objects_with_behavior(const BehaviorScript* behavior, f32 dist) {
u16 numObjs = 0;
uintptr_t* behaviorAddr = segmented_to_virtual(behavior);
struct Object* obj;
struct ObjectNode* listHead;
listHead = &gObjectLists[get_object_list_from_behavior(behaviorAddr)];
obj = (struct Object*)listHead->next;
while (obj != (struct Object*)listHead) {
if (obj->behavior == behaviorAddr) {
if (obj->activeFlags != ACTIVE_FLAG_DEACTIVATED && obj != o) {
f32 objDist = dist_between_objects(o, obj);
if (objDist < dist) {
numObjs++;
}
}
}
obj = (struct Object*)obj->header.next;
}
return numObjs;
}
struct Object *find_unimportant_object(void) {
struct ObjectNode *listHead = &gObjectLists[OBJ_LIST_UNIMPORTANT];
struct ObjectNode *obj = listHead->next;

View File

@ -145,6 +145,7 @@ struct Object *cur_obj_nearest_object_with_behavior(const BehaviorScript *behavi
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_unimportant_object(void);
s32 count_unimportant_objects(void);
s32 count_objects_with_behavior(const BehaviorScript *behavior);

View File

@ -24,7 +24,7 @@ void network_send_debug_sync(void) {
packet_write(&p, &objectCount, sizeof(u8));
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
if (gSyncObjects[i].o == NULL) { continue; }
u16 behaviorId = get_id_from_behavior(gSyncObjects[i].behavior);
u16 behaviorId = get_id_from_behavior((gSyncObjects[i].behavior == NULL) ? gSyncObjects[i].behavior : gSyncObjects[i].o->behavior);
packet_write(&p, &i, sizeof(u8));
packet_write(&p, &behaviorId, sizeof(u16));
}