Fix various bugs with spiny and lakitu
This commit is contained in:
parent
839575efe1
commit
625e9b5df9
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue