Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/macro_special_objects.c
7858 views
1
#include <PR/ultratypes.h>
2
3
#include "sm64.h"
4
#include "object_helpers.h"
5
#include "macro_special_objects.h"
6
#include "object_list_processor.h"
7
8
#include "behavior_data.h"
9
10
#include "macro_presets.h"
11
12
#include "special_presets.h"
13
14
/*
15
* Converts the rotation value supplied by macro objects into one
16
* that can be used by in-game objects.
17
*/
18
s16 convert_rotation(s16 inRotation) {
19
u16 rotation = ((u16)(inRotation & 0xFF));
20
rotation <<= 8;
21
22
if (rotation == 0x3F00) {
23
rotation = 0x4000;
24
}
25
26
if (rotation == 0x7F00) {
27
rotation = 0x8000;
28
}
29
30
if (rotation == 0xBF00) {
31
rotation = 0xC000;
32
}
33
34
if (rotation == 0xFF00) {
35
rotation = 0x0000;
36
}
37
38
return (s16) rotation;
39
}
40
41
/*
42
* Spawns an object at an absolute location with rotation around the y-axis and
43
* parameters filling up the upper 2 bytes of newObj->oBehParams.
44
* The object will not spawn if 'behavior' is NULL.
45
*/
46
void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params) {
47
if (behavior != NULL) {
48
struct Object *newObj = spawn_object_abs_with_rot(
49
&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
50
newObj->oBehParams = ((u32) params) << 16;
51
}
52
}
53
54
/*
55
* Spawns an object at an absolute location with rotation around the y-axis and
56
* a single parameter filling up the upper byte of newObj->oBehParams.
57
* The object will not spawn if 'behavior' is NULL.
58
*/
59
void spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 param) {
60
if (behavior != NULL) {
61
struct Object *newObj = spawn_object_abs_with_rot(
62
&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, convert_rotation(ry), 0);
63
newObj->oBehParams = ((u32) param) << 24;
64
}
65
}
66
67
/*
68
* Spawns an object at an absolute location with currently 3 unknown variables that get converted to
69
* floats. Oddly enough, this function doesn't care if 'behavior' is NULL or not.
70
*/
71
void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB,
72
s16 unkC) {
73
struct Object *newObj =
74
spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior, x, y, z, 0, 0, 0);
75
76
// Are all three of these values unused?
77
newObj->oMacroUnk108 = (f32) unkA;
78
newObj->oMacroUnk10C = (f32) unkB;
79
newObj->oMacroUnk110 = (f32) unkC;
80
}
81
82
UNUSED static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) {
83
struct Object *sp3C;
84
s16 model;
85
86
model = bhvYellowCoin == behavior ? MODEL_YELLOW_COIN : MODEL_NONE;
87
88
sp3C = spawn_object_abs_with_rot(&gMacroObjectDefaultParent, 0, model, behavior,
89
a1[1], a1[2], a1[3], 0, convert_rotation(a1[0]), 0);
90
91
sp3C->oUnk1A8 = a1[4];
92
sp3C->oBehParams = (a1[4] & 0xFF) >> 16;
93
}
94
95
struct LoadedPreset {
96
/*0x00*/ const BehaviorScript *behavior;
97
/*0x04*/ s16 param; // huh? why does the below function swap these.. just use the struct..
98
/*0x06*/ s16 model;
99
};
100
101
#define MACRO_OBJ_Y_ROT 0
102
#define MACRO_OBJ_X 1
103
#define MACRO_OBJ_Y 2
104
#define MACRO_OBJ_Z 3
105
#define MACRO_OBJ_PARAMS 4
106
107
void despawn_macro_objects(s16 *macroObjList)
108
{
109
s32 presetID;
110
111
s16 macroObject[5]; // see the 5 #define statements above
112
struct Object *objToDelete;
113
struct LoadedPreset preset;
114
115
u16 *info16;
116
117
while (TRUE) {
118
if (*macroObjList == -1) { // An encountered value of -1 means the list has ended.
119
break;
120
}
121
122
presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array
123
124
if (presetID < 0) {
125
break;
126
}
127
128
// Set macro object properties from the list
129
macroObject[MACRO_OBJ_Y_ROT] = ((*macroObjList++ >> 9) & 0x7F) << 1; // Y-Rotation
130
macroObject[MACRO_OBJ_X] = *macroObjList++; // X position
131
macroObject[MACRO_OBJ_Y] = *macroObjList++; // Y position
132
macroObject[MACRO_OBJ_Z] = *macroObjList++; // Z position
133
macroObject[MACRO_OBJ_PARAMS] = *macroObjList++; // Behavior params
134
135
// Get the preset values from the MacroObjectPresets list.
136
preset.model = MacroObjectPresets[presetID].model;
137
preset.behavior = MacroObjectPresets[presetID].behavior;
138
preset.param = MacroObjectPresets[presetID].param;
139
140
if (preset.behavior != bhvYellowCoin) // Doesn't work for yellow coins - Not sure why
141
{
142
objToDelete = find_nearest_object_with_behavior(preset.behavior, macroObject[MACRO_OBJ_X],
143
macroObject[MACRO_OBJ_Y], macroObject[MACRO_OBJ_Z]);
144
145
if (objToDelete != NULL) {
146
info16 = (u16 *) objToDelete->respawnInfo;
147
*info16 &= 0xFF; // ALLOW RESPAWN (cuts off first 8 bits, leaves last 8 bits)
148
obj_mark_for_deletion(objToDelete);
149
}
150
}
151
}
152
}
153
154
void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) {
155
UNUSED u32 pad5C;
156
s32 presetID;
157
158
s16 macroObject[5]; // see the 5 #define statements above
159
struct Object *newObj;
160
struct LoadedPreset preset;
161
162
gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
163
gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
164
165
while (TRUE) {
166
if (*macroObjList == -1) { // An encountered value of -1 means the list has ended.
167
break;
168
}
169
170
presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array
171
172
if (presetID < 0) {
173
break;
174
}
175
176
// Set macro object properties from the list
177
macroObject[MACRO_OBJ_Y_ROT] = ((*macroObjList++ >> 9) & 0x7F) << 1; // Y-Rotation
178
macroObject[MACRO_OBJ_X] = *macroObjList++; // X position
179
macroObject[MACRO_OBJ_Y] = *macroObjList++; // Y position
180
macroObject[MACRO_OBJ_Z] = *macroObjList++; // Z position
181
macroObject[MACRO_OBJ_PARAMS] = *macroObjList++; // Behavior params
182
183
// Get the preset values from the MacroObjectPresets list.
184
preset.model = MacroObjectPresets[presetID].model;
185
preset.behavior = MacroObjectPresets[presetID].behavior;
186
preset.param = MacroObjectPresets[presetID].param;
187
188
if (preset.param != 0) {
189
macroObject[MACRO_OBJ_PARAMS] =
190
(macroObject[MACRO_OBJ_PARAMS] & 0xFF00) + (preset.param & 0x00FF);
191
}
192
193
// If object has been killed, prevent it from respawning
194
if (((macroObject[MACRO_OBJ_PARAMS] >> 8) & RESPAWN_INFO_DONT_RESPAWN)
195
!= RESPAWN_INFO_DONT_RESPAWN) {
196
// Spawn the new macro object.
197
newObj =
198
spawn_object_abs_with_rot(&gMacroObjectDefaultParent, // Parent object
199
0, // Unused
200
preset.model, // Model ID
201
preset.behavior, // Behavior address
202
macroObject[MACRO_OBJ_X], // X-position
203
macroObject[MACRO_OBJ_Y], // Y-position
204
macroObject[MACRO_OBJ_Z], // Z-position
205
0, // X-rotation
206
convert_rotation(macroObject[MACRO_OBJ_Y_ROT]), // Y-rotation
207
0 // Z-rotation
208
);
209
210
newObj->oUnk1A8 = macroObject[MACRO_OBJ_PARAMS];
211
newObj->oBehParams = ((macroObject[MACRO_OBJ_PARAMS] & 0x00FF) << 16)
212
+ (macroObject[MACRO_OBJ_PARAMS] & 0xFF00);
213
newObj->oBehParams2ndByte = macroObject[MACRO_OBJ_PARAMS] & 0x00FF;
214
newObj->respawnInfoType = RESPAWN_INFO_TYPE_16;
215
newObj->respawnInfo = macroObjList - 1;
216
newObj->parentObj = newObj;
217
}
218
}
219
}
220
221
void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) {
222
UNUSED u8 pad[8];
223
224
// This version of macroObjList has the preset and Y-Rotation separated,
225
// and lacks behavior params. Might be an early version of the macro object list?
226
s16 macroObjX;
227
s16 macroObjY;
228
s16 macroObjZ;
229
s16 macroObjPreset;
230
s16 macroObjRY; // Y Rotation
231
232
UNUSED u8 pad2[10];
233
234
gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
235
gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
236
237
while (TRUE) {
238
macroObjPreset = *macroObjList++;
239
240
if (macroObjPreset < 0) {
241
break;
242
}
243
244
macroObjX = *macroObjList++;
245
macroObjY = *macroObjList++;
246
macroObjZ = *macroObjList++;
247
macroObjRY = *macroObjList++;
248
249
// Spawn objects based on hardcoded presets, and most seem to be for Big Boo's Haunt.
250
// However, BBH doesn't use this function so this might just be an early test?
251
switch (macroObjPreset) {
252
case 0:
253
spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooStaircase, macroObjX, macroObjY,
254
macroObjZ, macroObjRY, 0);
255
break;
256
case 1:
257
spawn_macro_abs_yrot_2params(MODEL_BBH_TILTING_FLOOR_PLATFORM,
258
bhvBbhTiltingTrapPlatform, macroObjX, macroObjY, macroObjZ,
259
macroObjRY, 0);
260
break;
261
case 2:
262
spawn_macro_abs_yrot_2params(MODEL_BBH_TUMBLING_PLATFORM, bhvBbhTumblingBridge,
263
macroObjX, macroObjY, macroObjZ, macroObjRY, 0);
264
break;
265
case 3:
266
spawn_macro_abs_yrot_2params(MODEL_BBH_MOVING_BOOKSHELF, bhvHauntedBookshelf, macroObjX,
267
macroObjY, macroObjZ, macroObjRY, 0);
268
break;
269
case 4:
270
spawn_macro_abs_yrot_2params(MODEL_BBH_MESH_ELEVATOR, bhvMeshElevator, macroObjX,
271
macroObjY, macroObjZ, macroObjRY, 0);
272
break;
273
case 20:
274
spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
275
macroObjZ, macroObjRY, 0);
276
break;
277
case 21:
278
spawn_macro_abs_yrot_2params(MODEL_YELLOW_COIN, bhvYellowCoin, macroObjX, macroObjY,
279
macroObjZ, macroObjRY, 0);
280
break;
281
default:
282
break;
283
}
284
}
285
}
286
287
void spawn_special_objects(s16 areaIndex, s16 **specialObjList) {
288
s32 numOfSpecialObjects;
289
s32 i;
290
s32 offset;
291
s16 x;
292
s16 y;
293
s16 z;
294
s16 extraParams[4];
295
u8 model;
296
u8 type;
297
u8 presetID;
298
u8 defaultParam;
299
const BehaviorScript *behavior;
300
301
numOfSpecialObjects = **specialObjList;
302
(*specialObjList)++;
303
304
gMacroObjectDefaultParent.header.gfx.areaIndex = areaIndex;
305
gMacroObjectDefaultParent.header.gfx.activeAreaIndex = areaIndex;
306
307
for (i = 0; i < numOfSpecialObjects; i++) {
308
presetID = (u8) **specialObjList;
309
(*specialObjList)++;
310
x = **specialObjList;
311
(*specialObjList)++;
312
y = **specialObjList;
313
(*specialObjList)++;
314
z = **specialObjList;
315
(*specialObjList)++;
316
317
offset = 0;
318
while (TRUE) {
319
if (SpecialObjectPresets[offset].preset_id == presetID) {
320
break;
321
}
322
323
if (SpecialObjectPresets[offset].preset_id == 0xFF) {
324
}
325
326
offset++;
327
}
328
329
model = SpecialObjectPresets[offset].model;
330
behavior = SpecialObjectPresets[offset].behavior;
331
type = SpecialObjectPresets[offset].type;
332
defaultParam = SpecialObjectPresets[offset].defParam;
333
334
switch (type) {
335
case SPTYPE_NO_YROT_OR_PARAMS:
336
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, 0, 0);
337
break;
338
case SPTYPE_YROT_NO_PARAMS:
339
extraParams[0] = **specialObjList; // Y-rotation
340
(*specialObjList)++;
341
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], 0);
342
break;
343
case SPTYPE_PARAMS_AND_YROT:
344
extraParams[0] = **specialObjList; // Y-rotation
345
(*specialObjList)++;
346
extraParams[1] = **specialObjList; // Params
347
(*specialObjList)++;
348
spawn_macro_abs_yrot_2params(model, behavior, x, y, z, extraParams[0], extraParams[1]);
349
break;
350
case SPTYPE_UNKNOWN:
351
extraParams[0] =
352
**specialObjList; // Unknown, gets put into obj->oMacroUnk108 as a float
353
(*specialObjList)++;
354
extraParams[1] =
355
**specialObjList; // Unknown, gets put into obj->oMacroUnk10C as a float
356
(*specialObjList)++;
357
extraParams[2] =
358
**specialObjList; // Unknown, gets put into obj->oMacroUnk110 as a float
359
(*specialObjList)++;
360
spawn_macro_abs_special(model, behavior, x, y, z, extraParams[0], extraParams[1],
361
extraParams[2]);
362
break;
363
case SPTYPE_DEF_PARAM_AND_YROT:
364
extraParams[0] = **specialObjList; // Y-rotation
365
(*specialObjList)++;
366
spawn_macro_abs_yrot_param1(model, behavior, x, y, z, extraParams[0], defaultParam);
367
break;
368
default:
369
break;
370
}
371
}
372
}
373
374
#ifdef NO_SEGMENTED_MEMORY
375
u32 get_special_objects_size(s16 *data) {
376
s16 *startPos = data;
377
s32 numOfSpecialObjects;
378
s32 i;
379
u8 presetID;
380
s32 offset;
381
382
numOfSpecialObjects = *data++;
383
384
for (i = 0; i < numOfSpecialObjects; i++) {
385
presetID = (u8) *data++;
386
data += 3;
387
offset = 0;
388
389
while (TRUE) {
390
if (SpecialObjectPresets[offset].preset_id == presetID) {
391
break;
392
}
393
offset++;
394
}
395
396
switch (SpecialObjectPresets[offset].type) {
397
case SPTYPE_NO_YROT_OR_PARAMS:
398
break;
399
case SPTYPE_YROT_NO_PARAMS:
400
data++;
401
break;
402
case SPTYPE_PARAMS_AND_YROT:
403
data += 2;
404
break;
405
case SPTYPE_UNKNOWN:
406
data += 3;
407
break;
408
case SPTYPE_DEF_PARAM_AND_YROT:
409
data++;
410
break;
411
default:
412
break;
413
}
414
}
415
416
return data - startPos;
417
}
418
#endif
419
420