Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/behaviors/beta_boo_key.inc.c
7861 views
1
/**
2
* Behavior for bhvAlphaBooKey and bhvBetaBooKey.
3
* They were apparently intended to be a key that would be contained in boos
4
* and would fall out, like coins do. There is a model, MODEL_BETA_BOO_KEY, that
5
* is loaded in script_func_global_10, which contains boo-themed models used in
6
* BBH and the castle courtyard. It is used in a macro preset with bhvAlphaBooKey,
7
* which is also grouped near other boo/BBH-related macros. This is evidence that
8
* bhvAlphaBooKey was supposed to be a key. bhvBetaBooKey has code similar to
9
* bhvAlphaBooKey's for rotation and collection, and functions correctly when
10
* spawned as a child of a boo (it checks the death status of the boo to know when
11
* to drop, so this is almost definitely what was intended). It appears that
12
* bhvAlphaBooKey was abandoned for reasons unknown and replaced with bhvBetaBooKey.
13
*/
14
15
/**
16
* Update function for bhvAlphaBooKey.
17
* It rotates the key, and deletes it when collected.
18
* The code in this function is similar to that found in
19
* bhvBetaBooKey code, which implies that these are 2 versions
20
* of the same object. It is a less developed version of
21
* bhvBetaBooKey, hence the "alpha" moniker.
22
*/
23
void bhv_alpha_boo_key_loop(void) {
24
// Rotate the key
25
o->oFaceAngleRoll += 0x200;
26
o->oFaceAngleYaw += 0x200;
27
28
if (obj_check_if_collided_with_object(o, gMarioObject)) {
29
// This line makes the object inside the key's parent boo drop.
30
// Was this intended to make the boo die when the key is collected?
31
// Boos don't read from oBooDeathStatus, they only set it to let the
32
// objects inside them know when to drop.
33
// Due to this line, the key will cause the game to crash if collected
34
// when its parent object is NULL.
35
// Another theory is that the boo key was intended to be spawned by a
36
// spawner that used object field 0x00 for something else. This
37
// is elaborated on more in beta_boo_key_dropped_loop.
38
o->parentObj->oBooDeathStatus = BOO_DEATH_STATUS_DYING;
39
40
// Delete the object and spawn sparkles
41
obj_mark_for_deletion(o);
42
spawn_object(o, MODEL_SPARKLES, bhvGoldenCoinSparkles);
43
}
44
}
45
46
// For some reason, the action functions for the beta boo key
47
// are written in reverse order.
48
49
/**
50
* Continue to make the key fall, and handle collection.
51
*/
52
static void beta_boo_key_dropped_loop(void) {
53
// Apply standard physics to the key
54
cur_obj_update_floor_and_walls();
55
cur_obj_move_standard(78);
56
57
// Slowly increase the Y offset to make the model aligned correctly.
58
// This is spread out over 13 frames so that it's not noticable.
59
if (o->oGraphYOffset < 26.0f) {
60
o->oGraphYOffset += 2.0f;
61
}
62
63
// Transition from rotating in both the yaw and the roll axes
64
// to just in the yaw axis. This is done by truncating the key's roll
65
// to the nearest multiple of 0x800, then continuously adding 0x800
66
// until it reaches a multiple of 0x10000, at which point &-ing with
67
// 0xFFFF returns 0 and the key stops rotating in the roll direction.
68
if (o->oFaceAngleRoll & 0xFFFF) {
69
o->oFaceAngleRoll &= 0xF800;
70
o->oFaceAngleRoll += 0x800;
71
}
72
73
// Once the key stops bouncing, stop its horizontal movement on the ground.
74
if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {
75
o->oVelX = 0.0f;
76
o->oVelZ = 0.0f;
77
}
78
79
// Rotate the key
80
o->oFaceAngleYaw += 0x800;
81
82
// If the key hits the floor or 90 frames have elapsed since it was dropped,
83
// become tangible and handle collision.
84
if (o->oTimer > 90 || o->oMoveFlags & OBJ_MOVE_LANDED) {
85
cur_obj_become_tangible();
86
87
if (obj_check_if_collided_with_object(o, gMarioObject)) {
88
// This interaction status is 0x01, the first interaction status flag.
89
// It was only used for Hoot in the final game, but it seems it could've
90
// treated as a TRUE/FALSE statement or held some special meaning in beta.
91
// Earlier, in beta_boo_key_drop (called when the parent boo is killed),
92
// o->parentObj is set to the parent boo's parentObj. This means that
93
// here, the parentObj is actually the parent of the old parent boo.
94
// One theory about this code is that there was a boo spawner, which
95
// spawned "false" boos and one "true" boo with the key, and the player
96
// was intended to find the one with the key to progress.
97
o->parentObj->oInteractStatus = TRUE;
98
99
// Delete the object and spawn sparkles
100
obj_mark_for_deletion(o);
101
spawn_object(o, MODEL_SPARKLES, bhvGoldenCoinSparkles);
102
}
103
}
104
}
105
106
/**
107
* Drop the key. This function is run once, the frame after the boo dies;
108
* It immediately sets the action to BETA_BOO_KEY_ACT_DROPPED.
109
*/
110
static void beta_boo_key_drop(void) {
111
s16 velocityDirection;
112
f32 velocityMagnitude;
113
114
// Update the key to be inside the boo
115
struct Object *parent = o->parentObj;
116
obj_copy_pos(o, parent);
117
118
// This if statement to only run this code on the first frame
119
// is redundant, since it instantly sets the action to BETA_BOO_KEY_ACT_DROPPED
120
// which stops this function from running again.
121
if (o->oTimer == 0) {
122
// Separate from the parent boo
123
o->parentObj = parent->parentObj;
124
125
o->oAction = BETA_BOO_KEY_ACT_DROPPED;
126
127
// Make the key move laterally away from Mario at 3 units/frame
128
// (as if he transferred kinetic energy to it)
129
velocityDirection = gMarioObject->oMoveAngleYaw;
130
velocityMagnitude = 3.0f;
131
132
o->oVelX = sins(velocityDirection) * velocityMagnitude;
133
o->oVelZ = coss(velocityDirection) * velocityMagnitude;
134
135
// Give it an initial Y velocity of 40 units/frame
136
o->oVelY = 40.0f;
137
}
138
139
// Rotate the key
140
o->oFaceAngleYaw += 0x200;
141
o->oFaceAngleRoll += 0x200;
142
}
143
144
/**
145
* Update the key to be inside its parent boo, and handle the boo dying.
146
*/
147
static void beta_boo_key_inside_boo_loop(void) {
148
// Update the key to be inside the boo at all times
149
struct Object *parent = o->parentObj;
150
obj_copy_pos(o, parent);
151
152
// Use a Y offset of 40 to make the key model aligned correctly.
153
// (Why didn't they use oGraphYOffset?)
154
o->oPosY += 40.0f;
155
156
// If the boo is dying/dead, set the action to BETA_BOO_KEY_ACT_DROPPING.
157
if (parent->oBooDeathStatus != BOO_DEATH_STATUS_ALIVE) {
158
o->oAction = BETA_BOO_KEY_ACT_DROPPING;
159
}
160
161
// Rotate the key
162
o->oFaceAngleRoll += 0x200;
163
o->oFaceAngleYaw += 0x200;
164
}
165
166
static void (*sBetaBooKeyActions[])(void) = { beta_boo_key_inside_boo_loop, beta_boo_key_drop,
167
beta_boo_key_dropped_loop };
168
169
/**
170
* Update function for bhvBetaBooKey.
171
*/
172
void bhv_beta_boo_key_loop(void) {
173
cur_obj_call_action_function(sBetaBooKeyActions);
174
}
175
176