Path: blob/master/src/game/behaviors/beta_boo_key.inc.c
7861 views
/**1* Behavior for bhvAlphaBooKey and bhvBetaBooKey.2* They were apparently intended to be a key that would be contained in boos3* and would fall out, like coins do. There is a model, MODEL_BETA_BOO_KEY, that4* is loaded in script_func_global_10, which contains boo-themed models used in5* BBH and the castle courtyard. It is used in a macro preset with bhvAlphaBooKey,6* which is also grouped near other boo/BBH-related macros. This is evidence that7* bhvAlphaBooKey was supposed to be a key. bhvBetaBooKey has code similar to8* bhvAlphaBooKey's for rotation and collection, and functions correctly when9* spawned as a child of a boo (it checks the death status of the boo to know when10* to drop, so this is almost definitely what was intended). It appears that11* bhvAlphaBooKey was abandoned for reasons unknown and replaced with bhvBetaBooKey.12*/1314/**15* Update function for bhvAlphaBooKey.16* It rotates the key, and deletes it when collected.17* The code in this function is similar to that found in18* bhvBetaBooKey code, which implies that these are 2 versions19* of the same object. It is a less developed version of20* bhvBetaBooKey, hence the "alpha" moniker.21*/22void bhv_alpha_boo_key_loop(void) {23// Rotate the key24o->oFaceAngleRoll += 0x200;25o->oFaceAngleYaw += 0x200;2627if (obj_check_if_collided_with_object(o, gMarioObject)) {28// This line makes the object inside the key's parent boo drop.29// Was this intended to make the boo die when the key is collected?30// Boos don't read from oBooDeathStatus, they only set it to let the31// objects inside them know when to drop.32// Due to this line, the key will cause the game to crash if collected33// when its parent object is NULL.34// Another theory is that the boo key was intended to be spawned by a35// spawner that used object field 0x00 for something else. This36// is elaborated on more in beta_boo_key_dropped_loop.37o->parentObj->oBooDeathStatus = BOO_DEATH_STATUS_DYING;3839// Delete the object and spawn sparkles40obj_mark_for_deletion(o);41spawn_object(o, MODEL_SPARKLES, bhvGoldenCoinSparkles);42}43}4445// For some reason, the action functions for the beta boo key46// are written in reverse order.4748/**49* Continue to make the key fall, and handle collection.50*/51static void beta_boo_key_dropped_loop(void) {52// Apply standard physics to the key53cur_obj_update_floor_and_walls();54cur_obj_move_standard(78);5556// Slowly increase the Y offset to make the model aligned correctly.57// This is spread out over 13 frames so that it's not noticable.58if (o->oGraphYOffset < 26.0f) {59o->oGraphYOffset += 2.0f;60}6162// Transition from rotating in both the yaw and the roll axes63// to just in the yaw axis. This is done by truncating the key's roll64// to the nearest multiple of 0x800, then continuously adding 0x80065// until it reaches a multiple of 0x10000, at which point &-ing with66// 0xFFFF returns 0 and the key stops rotating in the roll direction.67if (o->oFaceAngleRoll & 0xFFFF) {68o->oFaceAngleRoll &= 0xF800;69o->oFaceAngleRoll += 0x800;70}7172// Once the key stops bouncing, stop its horizontal movement on the ground.73if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {74o->oVelX = 0.0f;75o->oVelZ = 0.0f;76}7778// Rotate the key79o->oFaceAngleYaw += 0x800;8081// If the key hits the floor or 90 frames have elapsed since it was dropped,82// become tangible and handle collision.83if (o->oTimer > 90 || o->oMoveFlags & OBJ_MOVE_LANDED) {84cur_obj_become_tangible();8586if (obj_check_if_collided_with_object(o, gMarioObject)) {87// This interaction status is 0x01, the first interaction status flag.88// It was only used for Hoot in the final game, but it seems it could've89// treated as a TRUE/FALSE statement or held some special meaning in beta.90// Earlier, in beta_boo_key_drop (called when the parent boo is killed),91// o->parentObj is set to the parent boo's parentObj. This means that92// here, the parentObj is actually the parent of the old parent boo.93// One theory about this code is that there was a boo spawner, which94// spawned "false" boos and one "true" boo with the key, and the player95// was intended to find the one with the key to progress.96o->parentObj->oInteractStatus = TRUE;9798// Delete the object and spawn sparkles99obj_mark_for_deletion(o);100spawn_object(o, MODEL_SPARKLES, bhvGoldenCoinSparkles);101}102}103}104105/**106* Drop the key. This function is run once, the frame after the boo dies;107* It immediately sets the action to BETA_BOO_KEY_ACT_DROPPED.108*/109static void beta_boo_key_drop(void) {110s16 velocityDirection;111f32 velocityMagnitude;112113// Update the key to be inside the boo114struct Object *parent = o->parentObj;115obj_copy_pos(o, parent);116117// This if statement to only run this code on the first frame118// is redundant, since it instantly sets the action to BETA_BOO_KEY_ACT_DROPPED119// which stops this function from running again.120if (o->oTimer == 0) {121// Separate from the parent boo122o->parentObj = parent->parentObj;123124o->oAction = BETA_BOO_KEY_ACT_DROPPED;125126// Make the key move laterally away from Mario at 3 units/frame127// (as if he transferred kinetic energy to it)128velocityDirection = gMarioObject->oMoveAngleYaw;129velocityMagnitude = 3.0f;130131o->oVelX = sins(velocityDirection) * velocityMagnitude;132o->oVelZ = coss(velocityDirection) * velocityMagnitude;133134// Give it an initial Y velocity of 40 units/frame135o->oVelY = 40.0f;136}137138// Rotate the key139o->oFaceAngleYaw += 0x200;140o->oFaceAngleRoll += 0x200;141}142143/**144* Update the key to be inside its parent boo, and handle the boo dying.145*/146static void beta_boo_key_inside_boo_loop(void) {147// Update the key to be inside the boo at all times148struct Object *parent = o->parentObj;149obj_copy_pos(o, parent);150151// Use a Y offset of 40 to make the key model aligned correctly.152// (Why didn't they use oGraphYOffset?)153o->oPosY += 40.0f;154155// If the boo is dying/dead, set the action to BETA_BOO_KEY_ACT_DROPPING.156if (parent->oBooDeathStatus != BOO_DEATH_STATUS_ALIVE) {157o->oAction = BETA_BOO_KEY_ACT_DROPPING;158}159160// Rotate the key161o->oFaceAngleRoll += 0x200;162o->oFaceAngleYaw += 0x200;163}164165static void (*sBetaBooKeyActions[])(void) = { beta_boo_key_inside_boo_loop, beta_boo_key_drop,166beta_boo_key_dropped_loop };167168/**169* Update function for bhvBetaBooKey.170*/171void bhv_beta_boo_key_loop(void) {172cur_obj_call_action_function(sBetaBooKeyActions);173}174175176