Massive refactor

This commit is contained in:
jaburns
2020-10-27 11:07:42 -06:00
parent 48ab192e17
commit fcb6b5b431
85 changed files with 207 additions and 168 deletions
+797
View File
@@ -0,0 +1,797 @@
#include "../include/sm64.h"
#include "geo_layout.h"
#include "math_util.h"
#include "../memory.h"
#include "graph_node.h"
#include "../shim.h"
static Vec3s gVec3sZero = { 0, 0, 0 };
typedef void (*GeoLayoutCommandProc)(void);
GeoLayoutCommandProc GeoLayoutJumpTable[] = {
geo_layout_cmd_branch_and_link,
geo_layout_cmd_end,
geo_layout_cmd_branch,
geo_layout_cmd_return,
geo_layout_cmd_open_node,
geo_layout_cmd_close_node,
geo_layout_cmd_assign_as_view,
geo_layout_cmd_update_node_flags,
geo_layout_cmd_node_root,
geo_layout_cmd_node_ortho_projection,
geo_layout_cmd_node_perspective,
geo_layout_cmd_node_start,
geo_layout_cmd_node_master_list,
geo_layout_cmd_node_level_of_detail,
geo_layout_cmd_node_switch_case,
geo_layout_cmd_node_camera,
geo_layout_cmd_node_translation_rotation,
geo_layout_cmd_node_translation,
geo_layout_cmd_node_rotation,
geo_layout_cmd_node_animated_part,
geo_layout_cmd_node_billboard,
geo_layout_cmd_node_display_list,
geo_layout_cmd_node_shadow,
geo_layout_cmd_node_object_parent,
geo_layout_cmd_node_generated,
geo_layout_cmd_node_background,
geo_layout_cmd_nop,
geo_layout_cmd_copy_view,
geo_layout_cmd_node_held_obj,
geo_layout_cmd_node_scale,
geo_layout_cmd_nop2,
geo_layout_cmd_nop3,
geo_layout_cmd_node_culling_radius,
};
struct GraphNode gObjParentGraphNode;
struct AllocOnlyPool *gGraphNodePool;
struct GraphNode *gCurRootGraphNode;
UNUSED s32 D_8038BCA8;
/* The gGeoViews array is a mysterious one. Some background:
*
* If there are e.g. multiple Goombas, the multiple Goomba objects share one
* Geo node tree describing the goomba 3D model. Since every node has a single
* parent field and not a parent array, the parent is dynamically rebinded to
* each goomba instance just before rendering and set to null afterwards.
* The same happens for ObjectParentNode, which has as his sharedChild a group
* of all 240 object nodes. Why does the ObjectParentNode exist at all, if its
* only purpose is to temporarily bind the actual group with objects? This might
* be another remnant to Luigi.
*
* When creating a root node, room for (2 + cmd+0x02) pointers is allocated in
* gGeoViews. Except for the title screen, cmd+0x02 is 10. The 2 default ones
* might be for Mario and Luigi, and the other 10 could be different cameras for
* different rooms / boss fights. An area might be structured like this:
*
* geo_camera mode_player //Mario cam
* geo_open_node
* geo_render_obj
* geo_assign_as_view 1 // currently unused geo command
* geo_close_node
*
* geo_camera mode_player //Luigi cam
* geo_open_node
* geo_render_obj
* geo_copy_view 1 // currently unused geo command
* geo_assign_as_view 2
* geo_close_node
*
* geo_camera mode_boss //boss fight cam
* geo_assign_as_view 3
* ...
*
* There might also be specific geo nodes for Mario or Luigi only. Or a fixed camera
* might not have display list nodes of parts of the level that are out of view.
* In the end Luigi got scrapped and the multiple-camera design did not pan out,
* so everything was reduced to a single ObjectParent with a single group, and
* camera switching was all done in one node. End of speculation.
*/
struct GraphNode **gGeoViews;
u16 gGeoNumViews; // length of gGeoViews array
uintptr_t gGeoLayoutStack[16];
struct GraphNode *gCurGraphNodeList[32];
s16 gCurGraphNodeIndex;
s16 gGeoLayoutStackIndex; // similar to SP register in MIPS
UNUSED s16 D_8038BD7C;
s16 gGeoLayoutReturnIndex; // similar to RA register in MIPS
u8 *gGeoLayoutCommand;
u32 unused_8038B894[3] = { 0 };
/*
0x00: Branch and store return address
cmd+0x04: void *branchTarget
*/
void geo_layout_cmd_branch_and_link(void) {
gGeoLayoutStack[gGeoLayoutStackIndex++] = (uintptr_t) (gGeoLayoutCommand + CMD_PROCESS_OFFSET(8));
gGeoLayoutStack[gGeoLayoutStackIndex++] = (gCurGraphNodeIndex << 16) + gGeoLayoutReturnIndex;
gGeoLayoutReturnIndex = gGeoLayoutStackIndex;
gGeoLayoutCommand = segmented_to_virtual(cur_geo_cmd_ptr(0x04));
}
// 0x01: Terminate geo layout
void geo_layout_cmd_end(void) {
gGeoLayoutStackIndex = gGeoLayoutReturnIndex;
gGeoLayoutReturnIndex = gGeoLayoutStack[--gGeoLayoutStackIndex] & 0xFFFF;
gCurGraphNodeIndex = gGeoLayoutStack[gGeoLayoutStackIndex] >> 16;
gGeoLayoutCommand = (u8 *) gGeoLayoutStack[--gGeoLayoutStackIndex];
}
/*
0x02: Branch
cmd+0x04: void *branchTarget
*/
void geo_layout_cmd_branch(void) {
if (cur_geo_cmd_u8(0x01) == 1) {
gGeoLayoutStack[gGeoLayoutStackIndex++] = (uintptr_t) (gGeoLayoutCommand + CMD_PROCESS_OFFSET(8));
}
gGeoLayoutCommand = segmented_to_virtual(cur_geo_cmd_ptr(0x04));
}
// 0x03: Return from branch
void geo_layout_cmd_return(void) {
gGeoLayoutCommand = (u8 *) gGeoLayoutStack[--gGeoLayoutStackIndex];
}
// 0x04: Open node
void geo_layout_cmd_open_node(void) {
gCurGraphNodeList[gCurGraphNodeIndex + 1] = gCurGraphNodeList[gCurGraphNodeIndex];
gCurGraphNodeIndex++;
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
// 0x05: Close node
void geo_layout_cmd_close_node(void) {
gCurGraphNodeIndex--;
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x06: Register the current node as a view
cmd+0x02: index
Register the current node in the gGeoViews array at the given index
*/
void geo_layout_cmd_assign_as_view(void) {
u16 index = cur_geo_cmd_s16(0x02);
if (index < gGeoNumViews) {
gGeoViews[index] = gCurGraphNodeList[gCurGraphNodeIndex];
}
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x07: Update current scene graph node flags
cmd+0x01: u8 operation (0 = reset, 1 = set, 2 = clear)
cmd+0x02: s16 bits
*/
void geo_layout_cmd_update_node_flags(void) {
u16 operation = cur_geo_cmd_u8(0x01);
u16 flagBits = cur_geo_cmd_s16(0x02);
switch (operation) {
case GEO_CMD_FLAGS_RESET:
gCurGraphNodeList[gCurGraphNodeIndex]->flags = flagBits;
break;
case GEO_CMD_FLAGS_SET:
gCurGraphNodeList[gCurGraphNodeIndex]->flags |= flagBits;
break;
case GEO_CMD_FLAGS_CLEAR:
gCurGraphNodeList[gCurGraphNodeIndex]->flags &= ~flagBits;
break;
}
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x08: Create a scene graph root node that specifies the viewport
cmd+0x02: s16 num entries (+2) to allocate for gGeoViews
cmd+0x04: s16 x
cmd+0x06: s16 y
cmd+0x08: s16 width
cmd+0x0A: s16 height
*/
void geo_layout_cmd_node_root(void) {
s32 i;
struct GraphNodeRoot *graphNode;
s16 x = cur_geo_cmd_s16(0x04);
s16 y = cur_geo_cmd_s16(0x06);
s16 width = cur_geo_cmd_s16(0x08);
s16 height = cur_geo_cmd_s16(0x0A);
// number of entries to allocate for gGeoViews array
// at least 2 are allocated by default
// cmd+0x02 = 0x00: Mario face, 0x0A: all other levels
gGeoNumViews = cur_geo_cmd_s16(0x02) + 2;
graphNode = init_graph_node_root(gGraphNodePool, NULL, 0, x, y, width, height);
// TODO: check type
gGeoViews = alloc_only_pool_alloc(gGraphNodePool, gGeoNumViews * sizeof(struct GraphNode *));
graphNode->views = gGeoViews;
graphNode->numViews = gGeoNumViews;
for (i = 0; i < gGeoNumViews; i++) {
gGeoViews[i] = NULL;
}
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
}
/*
0x09: Create orthographic projection scene graph node
cmd+0x02: s16 scale as a percentage (usually it's 100)
*/
void geo_layout_cmd_node_ortho_projection(void) {
struct GraphNodeOrthoProjection *graphNode;
f32 scale = (f32) cur_geo_cmd_s16(0x02) / 100.0f;
graphNode = init_graph_node_ortho_projection(gGraphNodePool, NULL, scale);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x0A: Create camera frustum scene graph node
cmd+0x01: u8 if nonzero, enable frustumFunc field
cmd+0x02: s16 field of view
cmd+0x04: s16 near
cmd+0x06: s16 far
[cmd+0x08: GraphNodeFunc frustumFunc]
*/
void geo_layout_cmd_node_perspective(void) {
struct GraphNodePerspective *graphNode;
GraphNodeFunc frustumFunc = NULL;
s16 fov = cur_geo_cmd_s16(0x02);
s16 near = cur_geo_cmd_s16(0x04);
s16 far = cur_geo_cmd_s16(0x06);
if (cur_geo_cmd_u8(0x01) != 0) {
// optional asm function
frustumFunc = (GraphNodeFunc) cur_geo_cmd_ptr(0x08);
gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT;
}
graphNode = init_graph_node_perspective(gGraphNodePool, NULL, (f32) fov, near, far, frustumFunc, 0);
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x0B: Create a scene graph node that groups other nodes without any
additional functionality
*/
void geo_layout_cmd_node_start(void) {
struct GraphNodeStart *graphNode;
graphNode = init_graph_node_start(gGraphNodePool, NULL);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
// 0x1F: No operation
void geo_layout_cmd_nop3(void) {
gGeoLayoutCommand += 0x10 << CMD_SIZE_SHIFT;
}
/*
0x0C: Create zbuffer-toggling scene graph node
cmd+0x01: u8 enableZBuffer (1 = on, 0 = off)
*/
void geo_layout_cmd_node_master_list(void) {
struct GraphNodeMasterList *graphNode;
graphNode = init_graph_node_master_list(gGraphNodePool, NULL, cur_geo_cmd_u8(0x01));
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x0D: Create a level of detail graph node, which only renders at a certain
distance interval from the camera.
cmd+0x04: s16 minDistance
cmd+0x06: s16 maxDistance
*/
void geo_layout_cmd_node_level_of_detail(void) {
struct GraphNodeLevelOfDetail *graphNode;
s16 minDistance = cur_geo_cmd_s16(0x04);
s16 maxDistance = cur_geo_cmd_s16(0x06);
graphNode = init_graph_node_render_range(gGraphNodePool, NULL, minDistance, maxDistance);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x0E: Create switch-case scene graph node
cmd+0x02: s16 initialSelectedCase
cmd+0x04: GraphNodeFunc caseSelectorFunc
caseSelectorFunc returns an index which is used to select the child node to render.
Used for animating coins, blinking, color selection, etc.
*/
void geo_layout_cmd_node_switch_case(void) {
struct GraphNodeSwitchCase *graphNode;
graphNode =
init_graph_node_switch_case(gGraphNodePool, NULL,
cur_geo_cmd_s16(0x02), // case which is initially selected
0,
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // case update function
0);
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x0F: Create a camera scene graph node (GraphNodeCamera). The focus sets the Camera's areaCen position.
cmd+0x02: s16 camera type (changes from course to course)
cmd+0x04: s16 posX
cmd+0x06: s16 posY
cmd+0x08: s16 posZ
cmd+0x0A: s16 focusX
cmd+0x0C: s16 focusY
cmd+0x0E: s16 focusZ
cmd+0x10: GraphNodeFunc func
*/
void geo_layout_cmd_node_camera(void) {
struct GraphNodeCamera *graphNode;
s16 *cmdPos = (s16 *) &gGeoLayoutCommand[4];
Vec3f pos, focus;
cmdPos = read_vec3s_to_vec3f(pos, cmdPos);
cmdPos = read_vec3s_to_vec3f(focus, cmdPos);
graphNode = init_graph_node_camera(gGraphNodePool, NULL, pos, focus,
(GraphNodeFunc) cur_geo_cmd_ptr(0x10), cur_geo_cmd_s16(0x02));
register_scene_graph_node(&graphNode->fnNode.node);
gGeoViews[0] = &graphNode->fnNode.node;
gGeoLayoutCommand += 0x14 << CMD_SIZE_SHIFT;
}
/*
0x10: Create translation & rotation scene graph node with optional display list
cmd+0x01: u8 params
(params & 0x80): if set, enable displayList field and drawingLayer
((params & 0x70)>>4): fieldLayout
(params & 0x0F): drawingLayer
fieldLayout == 0:
cmd+0x04: s16 xTranslation
cmd+0x06: s16 yTranslation
cmd+0x08: s16 zTranslation
cmd+0x0A: s16 xRotation
cmd+0x0C: s16 yRotation
cmd+0x0E: s16 zRotation
fieldLayout == 1:
cmd+0x02: s16 xTranslation
cmd+0x04: s16 yTranslation
cmd+0x06: s16 zTranslation
(rotation gets copied from gVec3sZero)
fieldLayout == 2:
cmd+0x02: s16 xRotation
cmd+0x04: s16 yRotation
cmd+0x06: s16 zRotation
(translation gets copied from gVec3sZero)
fieldLayout == 3:
cmd+0x02: s16 yRotation
(translation gets copied from gVec3sZero)
(x and z translation are set to 0)
[cmd+var: void *displayList]
*/
void geo_layout_cmd_node_translation_rotation(void) {
struct GraphNodeTranslationRotation *graphNode;
Vec3s translation, rotation;
void *displayList = NULL;
s16 drawingLayer = 0;
s16 params = cur_geo_cmd_u8(0x01);
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
switch ((params & 0x70) >> 4) {
case 0:
cmdPos = read_vec3s(translation, &cmdPos[2]);
cmdPos = read_vec3s_angle(rotation, cmdPos);
break;
case 1:
cmdPos = read_vec3s(translation, &cmdPos[1]);
vec3s_copy(rotation, gVec3sZero);
break;
case 2:
cmdPos = read_vec3s_angle(rotation, &cmdPos[1]);
vec3s_copy(translation, gVec3sZero);
break;
case 3:
vec3s_copy(translation, gVec3sZero);
vec3s_set(rotation, 0, (cmdPos[1] << 15) / 180, 0);
cmdPos += 2 << CMD_SIZE_SHIFT;
break;
}
if (params & 0x80) {
displayList = *(void **) &cmdPos[0];
drawingLayer = params & 0x0F;
cmdPos += 2 << CMD_SIZE_SHIFT;
}
graphNode = init_graph_node_translation_rotation(gGraphNodePool, NULL, drawingLayer, displayList,
translation, rotation);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand = (u8 *) cmdPos;
}
/*
0x11: Create translation scene graph node with optional display list
cmd+0x01: u8 params
(params & 0x80): if set, enable displayList field and drawingLayer
(params & 0x0F): drawingLayer
cmd+0x02: s16 xTranslation
cmd+0x04: s16 yTranslation
cmd+0x06: s16 zTranslation
[cmd+0x08: void *displayList]
*/
void geo_layout_cmd_node_translation(void) {
struct GraphNodeTranslation *graphNode;
Vec3s translation;
s16 drawingLayer = 0;
s16 params = cur_geo_cmd_u8(0x01);
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
void *displayList = NULL;
cmdPos = read_vec3s(translation, &cmdPos[1]);
if (params & 0x80) {
displayList = *(void **) &cmdPos[0];
drawingLayer = params & 0x0F;
cmdPos += 2 << CMD_SIZE_SHIFT;
}
graphNode =
init_graph_node_translation(gGraphNodePool, NULL, drawingLayer, displayList, translation);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand = (u8 *) cmdPos;
}
/*
0x12: Create ? scene graph node
cmd+0x01: u8 params
(params & 0x80): if set, enable displayList field and drawingLayer
(params & 0x0F): drawingLayer
cmd+0x02: s16 unkX
cmd+0x04: s16 unkY
cmd+0x06: s16 unkZ
[cmd+0x08: void *displayList]
*/
void geo_layout_cmd_node_rotation(void) {
struct GraphNodeRotation *graphNode;
Vec3s sp2c;
s16 drawingLayer = 0;
s16 params = cur_geo_cmd_u8(0x01);
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
void *displayList = NULL;
cmdPos = read_vec3s_angle(sp2c, &cmdPos[1]);
if (params & 0x80) {
displayList = *(void **) &cmdPos[0];
drawingLayer = params & 0x0F;
cmdPos += 2 << CMD_SIZE_SHIFT;
}
graphNode = init_graph_node_rotation(gGraphNodePool, NULL, drawingLayer, displayList, sp2c);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand = (u8 *) cmdPos;
}
/*
0x1D: Create scale scene graph node with optional display list
cmd+0x01: u8 params
(params & 0x80): if set, enable displayList field and drawingLayer
(params & 0x0F): drawingLayer
cmd+0x04: u32 scale (0x10000 = 1.0)
[cmd+0x08: void *displayList]
*/
void geo_layout_cmd_node_scale(void) {
struct GraphNodeScale *graphNode;
s16 drawingLayer = 0;
s16 params = cur_geo_cmd_u8(0x01);
f32 scale = cur_geo_cmd_u32(0x04) / 65536.0f;
void *displayList = NULL;
if (params & 0x80) {
displayList = cur_geo_cmd_ptr(0x08);
drawingLayer = params & 0x0F;
gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT;
}
graphNode = init_graph_node_scale(gGraphNodePool, NULL, drawingLayer, displayList, scale);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
// 0x1E: No operation
void geo_layout_cmd_nop2(void) {
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x13: Create a scene graph node that is rotated by the object's animation.
cmd+0x01: u8 drawingLayer
cmd+0x02: s16 xTranslation
cmd+0x04: s16 yTranslation
cmd+0x06: s16 zTranslation
cmd+0x08: void *displayList
*/
void geo_layout_cmd_node_animated_part(void) {
struct GraphNodeAnimatedPart *graphNode;
Vec3s translation;
s32 drawingLayer = cur_geo_cmd_u8(0x01);
void *displayList = cur_geo_cmd_ptr(0x08);
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
read_vec3s(translation, &cmdPos[1]);
graphNode =
init_graph_node_animated_part(gGraphNodePool, NULL, drawingLayer, displayList, translation);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
}
/*
0x14: Create billboarding node with optional display list
cmd+0x01: u8 params
(params & 0x80): if set, enable displayList field and drawingLayer
(params & 0x0F): drawingLayer
cmd+0x02: s16 xTranslation
cmd+0x04: s16 yTranslation
cmd+0x06: s16 zTranslation
[cmd+0x08: void *displayList]
*/
void geo_layout_cmd_node_billboard(void) {
struct GraphNodeBillboard *graphNode;
Vec3s translation;
s16 drawingLayer = 0;
s16 params = cur_geo_cmd_u8(0x01);
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
void *displayList = NULL;
cmdPos = read_vec3s(translation, &cmdPos[1]);
if (params & 0x80) {
displayList = *(void **) &cmdPos[0];
drawingLayer = params & 0x0F;
cmdPos += 2 << CMD_SIZE_SHIFT;
}
graphNode = init_graph_node_billboard(gGraphNodePool, NULL, drawingLayer, displayList, translation);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand = (u8 *) cmdPos;
}
/*
0x15: Create plain display list scene graph node
cmd+0x01: u8 drawingLayer
cmd+0x04: void *displayList
*/
void geo_layout_cmd_node_display_list(void) {
struct GraphNodeDisplayList *graphNode;
s32 drawingLayer = cur_geo_cmd_u8(0x01);
void *displayList = cur_geo_cmd_ptr(0x04);
graphNode = init_graph_node_display_list(gGraphNodePool, NULL, drawingLayer, displayList);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x16: Create shadow scene graph node
cmd+0x02: s16 shadowType
cmd+0x04: s16 shadowSolidity
cmd+0x06: s16 shadowScale
*/
void geo_layout_cmd_node_shadow(void) {
struct GraphNodeShadow *graphNode;
u8 shadowType = cur_geo_cmd_s16(0x02);
u8 shadowSolidity = cur_geo_cmd_s16(0x04);
s16 shadowScale = cur_geo_cmd_s16(0x06);
graphNode = init_graph_node_shadow(gGraphNodePool, NULL, shadowScale, shadowSolidity, shadowType);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
// 0x17: Create scene graph node that manages the group of all object nodes
void geo_layout_cmd_node_object_parent(void) {
struct GraphNodeObjectParent *graphNode;
graphNode = init_graph_node_object_parent(gGraphNodePool, NULL, &gObjParentGraphNode);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x18: Create dynamically generated displaylist scene graph node
cmd+0x02: s16 parameter
cmd+0x04: GraphNodeFunc func
*/
void geo_layout_cmd_node_generated(void) {
struct GraphNodeGenerated *graphNode;
graphNode = init_graph_node_generated(gGraphNodePool, NULL,
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // asm function
cur_geo_cmd_s16(0x02)); // parameter
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x19: Create background scene graph node
cmd+0x02: s16 background // background ID, or RGBA5551 color if backgroundFunc is null
cmd+0x04: GraphNodeFunc backgroundFunc
*/
void geo_layout_cmd_node_background(void) {
struct GraphNodeBackground *graphNode;
graphNode = init_graph_node_background(
gGraphNodePool, NULL,
cur_geo_cmd_s16(0x02), // background ID, or RGBA5551 color if asm function is null
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // asm function
0);
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
// 0x1A: No operation
void geo_layout_cmd_nop(void) {
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
}
/*
0x1B: Copy the shared children from the object parent from a specific view
to a newly created object parent node.
cmd+0x02: s16 index (of gGeoViews)
*/
void geo_layout_cmd_copy_view(void) {
struct GraphNodeObjectParent *graphNode;
struct GraphNode *node = NULL;
s16 index = cur_geo_cmd_s16(0x02);
if (index >= 0) {
node = gGeoViews[index];
if (node->type == GRAPH_NODE_TYPE_OBJECT_PARENT) {
node = ((struct GraphNodeObjectParent *) node)->sharedChild;
} else {
node = NULL;
}
}
graphNode = init_graph_node_object_parent(gGraphNodePool, NULL, node);
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x1C: Create a held object scene graph node
cmd+0x01: u8 unused
cmd+0x02: s16 offsetX
cmd+0x04: s16 offsetY
cmd+0x06: s16 offsetZ
cmd+0x08: GraphNodeFunc nodeFunc
*/
void geo_layout_cmd_node_held_obj(void) {
struct GraphNodeHeldObject *graphNode;
Vec3s offset;
read_vec3s(offset, (s16 *) &gGeoLayoutCommand[0x02]);
graphNode = init_graph_node_held_object(
gGraphNodePool, NULL, NULL, offset, (GraphNodeFunc) cur_geo_cmd_ptr(0x08), cur_geo_cmd_u8(0x01));
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
}
/*
0x20: Create a scene graph node that specifies for an object the radius that
is used for frustum culling.
cmd+0x02: s16 cullingRadius
*/
void geo_layout_cmd_node_culling_radius(void) {
struct GraphNodeCullingRadius *graphNode;
graphNode = init_graph_node_culling_radius(gGraphNodePool, NULL, cur_geo_cmd_s16(0x02));
register_scene_graph_node(&graphNode->node);
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
struct GraphNode *process_geo_layout(struct AllocOnlyPool *pool, void *segptr) {
// set by register_scene_graph_node when gCurGraphNodeIndex is 0
// and gCurRootGraphNode is NULL
gCurRootGraphNode = NULL;
gGeoNumViews = 0; // number of entries in gGeoViews
gCurGraphNodeList[0] = 0;
gCurGraphNodeIndex = 0; // incremented by cmd_open_node, decremented by cmd_close_node
gGeoLayoutStackIndex = 2;
gGeoLayoutReturnIndex = 2; // stack index is often copied here?
gGeoLayoutCommand = segmented_to_virtual(segptr);
gGraphNodePool = pool;
gGeoLayoutStack[0] = 0;
gGeoLayoutStack[1] = 0;
while (gGeoLayoutCommand != NULL) {
GeoLayoutJumpTable[gGeoLayoutCommand[0x00]]();
}
return gCurRootGraphNode;
}
+87
View File
@@ -0,0 +1,87 @@
#ifndef GEO_LAYOUT_H
#define GEO_LAYOUT_H
#include "../include/PR/ultratypes.h"
#include "../memory.h"
#include "../include/macros.h"
#include "../include/types.h"
#define GEO_CMD_FLAGS_RESET 0
#define GEO_CMD_FLAGS_SET 1
#define GEO_CMD_FLAGS_CLEAR 2
#define CMD_SIZE_SHIFT (sizeof(void *) >> 3)
#define CMD_PROCESS_OFFSET(offset) (((offset) & 3) | (((offset) & ~3) << CMD_SIZE_SHIFT))
#define cur_geo_cmd_u8(offset) \
(gGeoLayoutCommand[CMD_PROCESS_OFFSET(offset)])
#define cur_geo_cmd_s16(offset) \
(*(s16 *) &gGeoLayoutCommand[CMD_PROCESS_OFFSET(offset)])
#define cur_geo_cmd_s32(offset) \
(*(s32 *) &gGeoLayoutCommand[CMD_PROCESS_OFFSET(offset)])
#define cur_geo_cmd_u32(offset) \
(*(u32 *) &gGeoLayoutCommand[CMD_PROCESS_OFFSET(offset)])
#define cur_geo_cmd_ptr(offset) \
(*(void **) &gGeoLayoutCommand[CMD_PROCESS_OFFSET(offset)])
extern struct AllocOnlyPool *gGraphNodePool;
extern struct GraphNode *gCurRootGraphNode;
extern UNUSED s32 D_8038BCA8;
extern struct GraphNode **gGeoViews;
extern u16 gGeoNumViews;
extern uintptr_t gGeoLayoutStack[];
extern struct GraphNode *gCurGraphNodeList[];
extern s16 gCurGraphNodeIndex;
extern s16 gGeoLayoutStackIndex;
extern UNUSED s16 D_8038BD7C;
extern s16 gGeoLayoutReturnIndex;
extern u8 *gGeoLayoutCommand;
extern struct GraphNode gObjParentGraphNode;
extern struct AllocOnlyPool *D_8038BCA0;
extern struct GraphNode *D_8038BCA4;
extern s16 D_8038BD78;
extern struct GraphNode *D_8038BCF8[];
void geo_layout_cmd_branch_and_link(void);
void geo_layout_cmd_end(void);
void geo_layout_cmd_branch(void);
void geo_layout_cmd_return(void);
void geo_layout_cmd_open_node(void);
void geo_layout_cmd_close_node(void);
void geo_layout_cmd_assign_as_view(void);
void geo_layout_cmd_update_node_flags(void);
void geo_layout_cmd_node_root(void);
void geo_layout_cmd_node_ortho_projection(void);
void geo_layout_cmd_node_perspective(void);
void geo_layout_cmd_node_start(void);
void geo_layout_cmd_nop3(void);
void geo_layout_cmd_node_master_list(void);
void geo_layout_cmd_node_level_of_detail(void);
void geo_layout_cmd_node_switch_case(void);
void geo_layout_cmd_node_camera(void);
void geo_layout_cmd_node_translation_rotation(void);
void geo_layout_cmd_node_translation(void);
void geo_layout_cmd_node_rotation(void);
void geo_layout_cmd_node_scale(void);
void geo_layout_cmd_nop2(void);
void geo_layout_cmd_node_animated_part(void);
void geo_layout_cmd_node_billboard(void);
void geo_layout_cmd_node_display_list(void);
void geo_layout_cmd_node_shadow(void);
void geo_layout_cmd_node_object_parent(void);
void geo_layout_cmd_node_generated(void);
void geo_layout_cmd_node_background(void);
void geo_layout_cmd_nop(void);
void geo_layout_cmd_copy_view(void);
void geo_layout_cmd_node_held_obj(void);
void geo_layout_cmd_node_culling_radius(void);
struct GraphNode *process_geo_layout(struct AllocOnlyPool *a0, void *segptr);
#endif // GEO_LAYOUT_H
+894
View File
@@ -0,0 +1,894 @@
#include "../include/sm64.h"
#include "../game/level_update.h"
#include "math_util.h"
//#include "game/memory.h"
#include "graph_node.h"
#include "../game/rendering_graph_node.h"
#include "../game/area.h"
#include "geo_layout.h"
#include "../shim.h"
// unused Mtx(s)
static Vec3f gVec3fZero = { 0.0f, 0.0f, 0.0f };
static Vec3s gVec3sZero = { 0, 0, 0 };
static Vec3f gVec3fOne = { 1.0f, 1.0f, 1.0f };
/**
* Initialize a geo node with a given type. Sets all links such that there
* are no siblings, parent or children for this node.
*/
void init_scene_graph_node_links(struct GraphNode *graphNode, s32 type) {
graphNode->type = type;
graphNode->flags = GRAPH_RENDER_ACTIVE;
graphNode->prev = graphNode;
graphNode->next = graphNode;
graphNode->parent = NULL;
graphNode->children = NULL;
}
/**
* Allocated and returns a newly created root node
*/
struct GraphNodeRoot *init_graph_node_root(struct AllocOnlyPool *pool, struct GraphNodeRoot *graphNode,
s16 areaIndex, s16 x, s16 y, s16 width, s16 height) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeRoot));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ROOT);
graphNode->areaIndex = areaIndex;
graphNode->unk15 = 0;
graphNode->x = x;
graphNode->y = y;
graphNode->width = width;
graphNode->height = height;
graphNode->views = NULL;
graphNode->numViews = 0;
}
return graphNode;
}
/**
* Allocates and returns a newly created otrhographic projection node
*/
struct GraphNodeOrthoProjection *
init_graph_node_ortho_projection(struct AllocOnlyPool *pool, struct GraphNodeOrthoProjection *graphNode,
f32 scale) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeOrthoProjection));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ORTHO_PROJECTION);
graphNode->scale = scale;
}
return graphNode;
}
/**
* Allocates and returns a newly created perspective node
*/
struct GraphNodePerspective *init_graph_node_perspective(struct AllocOnlyPool *pool,
struct GraphNodePerspective *graphNode,
f32 fov, s16 near, s16 far,
GraphNodeFunc nodeFunc, s32 unused) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodePerspective));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_PERSPECTIVE);
graphNode->fov = fov;
graphNode->near = near;
graphNode->far = far;
graphNode->fnNode.func = nodeFunc;
graphNode->unused = unused;
if (nodeFunc != NULL) {
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Allocates and returns a newly created start node
*/
struct GraphNodeStart *init_graph_node_start(struct AllocOnlyPool *pool,
struct GraphNodeStart *graphNode) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeStart));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_START);
}
return graphNode;
}
/**
* Allocates and returns a newly created master list node
*/
struct GraphNodeMasterList *init_graph_node_master_list(struct AllocOnlyPool *pool,
struct GraphNodeMasterList *graphNode, s16 on) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeMasterList));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_MASTER_LIST);
if (on) {
graphNode->node.flags |= GRAPH_RENDER_Z_BUFFER;
}
}
return graphNode;
}
/**
* Allocates and returns a newly created render range node
*/
struct GraphNodeLevelOfDetail *init_graph_node_render_range(struct AllocOnlyPool *pool,
struct GraphNodeLevelOfDetail *graphNode,
s16 minDistance, s16 maxDistance) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeLevelOfDetail));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_LEVEL_OF_DETAIL);
graphNode->minDistance = minDistance;
graphNode->maxDistance = maxDistance;
}
return graphNode;
}
/**
* Allocates and returns a newly created switch case node
*/
struct GraphNodeSwitchCase *init_graph_node_switch_case(struct AllocOnlyPool *pool,
struct GraphNodeSwitchCase *graphNode,
s16 numCases, s16 selectedCase,
GraphNodeFunc nodeFunc, s32 unused) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeSwitchCase));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_SWITCH_CASE);
graphNode->numCases = numCases;
graphNode->selectedCase = selectedCase;
graphNode->fnNode.func = nodeFunc;
graphNode->unused = unused;
if (nodeFunc != NULL) {
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Allocates and returns a newly created camera node
*/
struct GraphNodeCamera *init_graph_node_camera(struct AllocOnlyPool *pool,
struct GraphNodeCamera *graphNode, f32 *pos,
f32 *focus, GraphNodeFunc func, s32 mode) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeCamera));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_CAMERA);
vec3f_copy(graphNode->pos, pos);
vec3f_copy(graphNode->focus, focus);
graphNode->fnNode.func = func;
graphNode->config.mode = mode;
graphNode->roll = 0;
graphNode->rollScreen = 0;
if (func != NULL) {
func(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Allocates and returns a newly created translation rotation node
*/
struct GraphNodeTranslationRotation *
init_graph_node_translation_rotation(struct AllocOnlyPool *pool,
struct GraphNodeTranslationRotation *graphNode, s32 drawingLayer,
void *displayList, Vec3s translation, Vec3s rotation) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeTranslationRotation));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_TRANSLATION_ROTATION);
vec3s_copy(graphNode->translation, translation);
vec3s_copy(graphNode->rotation, rotation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created translation node
*/
struct GraphNodeTranslation *init_graph_node_translation(struct AllocOnlyPool *pool,
struct GraphNodeTranslation *graphNode,
s32 drawingLayer, void *displayList,
Vec3s translation) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeTranslation));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_TRANSLATION);
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created rotation node
*/
struct GraphNodeRotation *init_graph_node_rotation(struct AllocOnlyPool *pool,
struct GraphNodeRotation *graphNode,
s32 drawingLayer, void *displayList,
Vec3s rotation) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeRotation));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ROTATION);
vec3s_copy(graphNode->rotation, rotation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created scaling node
*/
struct GraphNodeScale *init_graph_node_scale(struct AllocOnlyPool *pool,
struct GraphNodeScale *graphNode, s32 drawingLayer,
void *displayList, f32 scale) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeScale));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->scale = scale;
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created object node
*/
struct GraphNodeObject *init_graph_node_object(struct AllocOnlyPool *pool,
struct GraphNodeObject *graphNode,
struct GraphNode *sharedChild, Vec3f pos, Vec3s angle,
Vec3f scale) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeObject));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT);
vec3f_copy(graphNode->pos, pos);
vec3f_copy(graphNode->scale, scale);
vec3s_copy(graphNode->angle, angle);
#ifdef USE_SYSTEM_MALLOC
// To avoid uninitialised memory usage in audio code
vec3f_copy(graphNode->cameraToObject, gVec3fZero);
#endif
graphNode->sharedChild = sharedChild;
graphNode->throwMatrix = NULL;
graphNode->animInfo.animID = 0;
graphNode->animInfo.curAnim = NULL;
graphNode->animInfo.animFrame = 0;
graphNode->animInfo.animFrameAccelAssist = 0;
graphNode->animInfo.animAccel = 0x10000;
graphNode->animInfo.animTimer = 0;
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
}
return graphNode;
}
/**
* Allocates and returns a newly created frustum culling radius node
*/
struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct AllocOnlyPool *pool,
struct GraphNodeCullingRadius *graphNode,
s16 radius) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeCullingRadius));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_CULLING_RADIUS);
graphNode->cullingRadius = radius;
}
return graphNode;
}
/**
* Allocates and returns a newly created animated part node
*/
struct GraphNodeAnimatedPart *init_graph_node_animated_part(struct AllocOnlyPool *pool,
struct GraphNodeAnimatedPart *graphNode,
s32 drawingLayer, void *displayList,
Vec3s translation) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeAnimatedPart));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ANIMATED_PART);
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created billboard node
*/
struct GraphNodeBillboard *init_graph_node_billboard(struct AllocOnlyPool *pool,
struct GraphNodeBillboard *graphNode,
s32 drawingLayer, void *displayList,
Vec3s translation) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBillboard));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_BILLBOARD);
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created displaylist node
*/
struct GraphNodeDisplayList *init_graph_node_display_list(struct AllocOnlyPool *pool,
struct GraphNodeDisplayList *graphNode,
s32 drawingLayer, void *displayList) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeDisplayList));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_DISPLAY_LIST);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = displayList;
}
return graphNode;
}
/**
* Allocates and returns a newly created shadow node
*/
struct GraphNodeShadow *init_graph_node_shadow(struct AllocOnlyPool *pool,
struct GraphNodeShadow *graphNode, s16 shadowScale,
u8 shadowSolidity, u8 shadowType) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeShadow));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SHADOW);
graphNode->shadowScale = shadowScale;
graphNode->shadowSolidity = shadowSolidity;
graphNode->shadowType = shadowType;
}
return graphNode;
}
/**
* Allocates and returns a newly created object parent node
*/
struct GraphNodeObjectParent *init_graph_node_object_parent(struct AllocOnlyPool *pool,
struct GraphNodeObjectParent *graphNode,
struct GraphNode *sharedChild) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeObjectParent));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT_PARENT);
graphNode->sharedChild = sharedChild;
}
return graphNode;
}
/**
* Allocates and returns a newly created generated node
*/
struct GraphNodeGenerated *init_graph_node_generated(struct AllocOnlyPool *pool,
struct GraphNodeGenerated *graphNode,
GraphNodeFunc gfxFunc, s32 parameter) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeGenerated));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_GENERATED_LIST);
graphNode->fnNode.func = gfxFunc;
graphNode->parameter = parameter;
if (gfxFunc != NULL) {
gfxFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Allocates and returns a newly created background node
*/
struct GraphNodeBackground *init_graph_node_background(struct AllocOnlyPool *pool,
struct GraphNodeBackground *graphNode,
u16 background, GraphNodeFunc backgroundFunc,
s32 zero) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBackground));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_BACKGROUND);
graphNode->background = (background << 16) | background;
graphNode->fnNode.func = backgroundFunc;
graphNode->unused = zero; // always 0, unused
if (backgroundFunc != NULL) {
backgroundFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Allocates and returns a newly created held object node
*/
struct GraphNodeHeldObject *init_graph_node_held_object(struct AllocOnlyPool *pool,
struct GraphNodeHeldObject *graphNode,
struct Object *objNode,
Vec3s translation,
GraphNodeFunc nodeFunc, s32 playerIndex) {
if (pool != NULL) {
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeHeldObject));
}
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_HELD_OBJ);
vec3s_copy(graphNode->translation, translation);
graphNode->objNode = objNode;
graphNode->fnNode.func = nodeFunc;
graphNode->playerIndex = playerIndex;
if (nodeFunc != NULL) {
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
}
}
return graphNode;
}
/**
* Adds 'childNode' to the end of the list children from 'parent'
*/
struct GraphNode *geo_add_child(struct GraphNode *parent, struct GraphNode *childNode) {
struct GraphNode *parentFirstChild;
struct GraphNode *parentLastChild;
if (childNode != NULL) {
childNode->parent = parent;
parentFirstChild = parent->children;
if (parentFirstChild == NULL) {
parent->children = childNode;
childNode->prev = childNode;
childNode->next = childNode;
} else {
parentLastChild = parentFirstChild->prev;
childNode->prev = parentLastChild;
childNode->next = parentFirstChild;
parentFirstChild->prev = childNode;
parentLastChild->next = childNode;
}
}
return childNode;
}
/**
* Remove a node from the scene graph. It changes the links with its
* siblings and with its parent, it doesn't deallocate the memory
* since geo nodes are allocated in a pointer-bumping pool that
* gets thrown out when changing areas.
*/
struct GraphNode *geo_remove_child(struct GraphNode *graphNode) {
struct GraphNode *parent;
struct GraphNode **firstChild;
parent = graphNode->parent;
firstChild = &parent->children;
// Remove link with siblings
graphNode->prev->next = graphNode->next;
graphNode->next->prev = graphNode->prev;
// If this node was the first child, a new first child must be chosen
if (*firstChild == graphNode) {
// The list is circular, so this checks whether it was the only child
if (graphNode->next == graphNode) {
*firstChild = NULL; // Parent has no children anymore
} else {
*firstChild = graphNode->next; // Choose a new first child
}
}
return parent;
}
/**
* Reorders the given node so it's the first child of its parent.
* This is called on the Mario object when he is spawned. That's why Mario's
* object is always drawn before any other objects. (Note that the geo order
* is independent from processing group order, where Mario is not first.)
*/
struct GraphNode *geo_make_first_child(struct GraphNode *newFirstChild) {
struct GraphNode *lastSibling;
struct GraphNode *parent;
struct GraphNode **firstChild;
parent = newFirstChild->parent;
firstChild = &parent->children;
if (*firstChild != newFirstChild) {
if ((*firstChild)->prev != newFirstChild) {
newFirstChild->prev->next = newFirstChild->next;
newFirstChild->next->prev = newFirstChild->prev;
lastSibling = (*firstChild)->prev;
newFirstChild->prev = lastSibling;
newFirstChild->next = *firstChild;
(*firstChild)->prev = newFirstChild;
lastSibling->next = newFirstChild;
}
*firstChild = newFirstChild;
}
return parent;
}
/**
* Helper function for geo_call_global_function_nodes that recursively
* traverses the scene graph and calls the functions of global nodes.
*/
void geo_call_global_function_nodes_helper(struct GraphNode *graphNode, s32 callContext) {
struct GraphNode **globalPtr;
struct GraphNode *curNode;
struct FnGraphNode *asFnNode;
curNode = graphNode;
do {
asFnNode = (struct FnGraphNode *) curNode;
if (curNode->type & GRAPH_NODE_TYPE_FUNCTIONAL) {
if (asFnNode->func != NULL) {
asFnNode->func(callContext, curNode, NULL);
}
}
if (curNode->children != NULL) {
switch (curNode->type) {
case GRAPH_NODE_TYPE_MASTER_LIST:
globalPtr = (struct GraphNode **) &gCurGraphNodeMasterList;
break;
case GRAPH_NODE_TYPE_PERSPECTIVE:
globalPtr = (struct GraphNode **) &gCurGraphNodeCamFrustum;
break;
case GRAPH_NODE_TYPE_CAMERA:
globalPtr = (struct GraphNode **) &gCurGraphNodeCamera;
break;
case GRAPH_NODE_TYPE_OBJECT:
globalPtr = (struct GraphNode **) &gCurGraphNodeObject;
break;
default:
globalPtr = NULL;
break;
}
if (globalPtr != NULL) {
*globalPtr = curNode;
}
geo_call_global_function_nodes_helper(curNode->children, callContext);
if (globalPtr != NULL) {
*globalPtr = NULL;
}
}
} while ((curNode = curNode->next) != graphNode);
}
/**
* Call the update functions of geo nodes that are stored in global variables.
* These variables include gCurGraphNodeMasterList, gCurGraphNodeCamFrustum,
* gCurGraphNodeCamera and gCurGraphNodeObject.
* callContext is one of the GEO_CONTEXT_ defines.
* The graphNode argument should be of type GraphNodeRoot.
*/
void geo_call_global_function_nodes(struct GraphNode *graphNode, s32 callContext) {
if (graphNode->flags & GRAPH_RENDER_ACTIVE) {
gCurGraphNodeRoot = (struct GraphNodeRoot *) graphNode;
if (graphNode->children != NULL) {
geo_call_global_function_nodes_helper(graphNode->children, callContext);
}
gCurGraphNodeRoot = 0;
}
}
/**
* When objects are cleared, this is called on all object nodes (loaded or unloaded).
*/
void geo_reset_object_node(struct GraphNodeObject *graphNode) {
init_graph_node_object(NULL, graphNode, 0, gVec3fZero, gVec3sZero, gVec3fOne);
geo_add_child(&gObjParentGraphNode, &graphNode->node);
graphNode->node.flags &= ~GRAPH_RENDER_ACTIVE;
}
/**
* Initialize an object node using the given parameters
*/
void geo_obj_init(struct GraphNodeObject *graphNode, void *sharedChild, Vec3f pos, Vec3s angle) {
vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f);
vec3f_copy(graphNode->pos, pos);
vec3s_copy(graphNode->angle, angle);
graphNode->sharedChild = sharedChild;
graphNode->unk4C = 0;
graphNode->throwMatrix = NULL;
graphNode->animInfo.curAnim = NULL;
graphNode->node.flags |= GRAPH_RENDER_ACTIVE;
graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE;
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD;
}
/**
* Initialize and object node using the given SpawnInfo struct
*/
void geo_obj_init_spawninfo(struct GraphNodeObject *graphNode, struct SpawnInfo *spawn) {
vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f);
vec3s_copy(graphNode->angle, spawn->startAngle);
graphNode->pos[0] = (f32) spawn->startPos[0];
graphNode->pos[1] = (f32) spawn->startPos[1];
graphNode->pos[2] = (f32) spawn->startPos[2];
graphNode->areaIndex = spawn->areaIndex;
graphNode->activeAreaIndex = spawn->activeAreaIndex;
graphNode->sharedChild = spawn->unk18;
graphNode->unk4C = spawn;
graphNode->throwMatrix = NULL;
graphNode->animInfo.curAnim = 0;
graphNode->node.flags |= GRAPH_RENDER_ACTIVE;
graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE;
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD;
}
/**
* Initialize the animation of an object node
*/
void geo_obj_init_animation(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr) {
struct Animation **animSegmented = segmented_to_virtual(animPtrAddr);
struct Animation *anim = segmented_to_virtual(*animSegmented);
if (graphNode->animInfo.curAnim != anim) {
graphNode->animInfo.curAnim = anim;
graphNode->animInfo.animFrame = anim->startFrame + ((anim->flags & ANIM_FLAG_FORWARD) ? 1 : -1);
graphNode->animInfo.animAccel = 0;
graphNode->animInfo.animYTrans = 0;
}
}
/**
* Initialize the animation of an object node
*/
void geo_obj_init_animation_accel(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr, u32 animAccel) {
struct Animation **animSegmented = segmented_to_virtual(animPtrAddr);
struct Animation *anim = segmented_to_virtual(*animSegmented);
if (graphNode->animInfo.curAnim != anim) {
graphNode->animInfo.curAnim = anim;
graphNode->animInfo.animYTrans = 0;
graphNode->animInfo.animFrameAccelAssist =
(anim->startFrame << 16) + ((anim->flags & ANIM_FLAG_FORWARD) ? animAccel : -animAccel);
graphNode->animInfo.animFrame = graphNode->animInfo.animFrameAccelAssist >> 16;
}
graphNode->animInfo.animAccel = animAccel;
}
/**
* Retrieves an index into animation data based on the attribute pointer
* An attribute is an x-, y- or z-component of the translation / rotation for a part
* Each attribute is a pair of s16's, where the first s16 represents the maximum frame
* and the second s16 the actual index. This index can be used to index in the array
* with actual animation values.
*/
s32 retrieve_animation_index(s32 frame, u16 **attributes) {
s32 result;
if (frame < (*attributes)[0]) {
result = (*attributes)[1] + frame;
} else {
result = (*attributes)[1] + (*attributes)[0] - 1;
}
*attributes += 2;
return result;
}
/**
* Update the animation frame of an object. The animation flags determine
* whether it plays forwards or backwards, and whether it stops or loops at
* the end etc.
*/
s16 geo_update_animation_frame(struct AnimInfo *obj, s32 *accelAssist) {
s32 result;
struct Animation *anim;
anim = obj->curAnim;
if (obj->animTimer == gAreaUpdateCounter || anim->flags & ANIM_FLAG_2) {
if (accelAssist != NULL) {
accelAssist[0] = obj->animFrameAccelAssist;
}
return obj->animFrame;
}
if (anim->flags & ANIM_FLAG_FORWARD) {
if (obj->animAccel) {
result = obj->animFrameAccelAssist - obj->animAccel;
} else {
result = (obj->animFrame - 1) << 16;
}
if (GET_HIGH_S16_OF_32(result) < anim->loopStart) {
if (anim->flags & ANIM_FLAG_NOLOOP) {
SET_HIGH_S16_OF_32(result, anim->loopStart);
} else {
SET_HIGH_S16_OF_32(result, anim->loopEnd - 1);
}
}
} else {
if (obj->animAccel != 0) {
result = obj->animFrameAccelAssist + obj->animAccel;
} else {
result = (obj->animFrame + 1) << 16;
}
if (GET_HIGH_S16_OF_32(result) >= anim->loopEnd) {
if (anim->flags & ANIM_FLAG_NOLOOP) {
SET_HIGH_S16_OF_32(result, anim->loopEnd - 1);
} else {
SET_HIGH_S16_OF_32(result, anim->loopStart);
}
}
}
if (accelAssist != 0) {
accelAssist[0] = result;
}
return GET_HIGH_S16_OF_32(result);
}
/**
* Unused function to retrieve an object's current animation translation
* Assumes that it has x, y and z data in animations, which isn't always the
* case since some animation types only have vertical or lateral translation.
* This might have been used for positioning the shadow under an object, which
* currently happens in-line in geo_process_shadow where it also accounts for
* animations without lateral translation.
*/
void geo_retreive_animation_translation(struct GraphNodeObject *obj, Vec3f position) {
struct Animation *animation = obj->animInfo.curAnim;
u16 *attribute;
s16 *values;
s16 frame;
if (animation != NULL) {
attribute = segmented_to_virtual((void *) animation->index);
values = segmented_to_virtual((void *) animation->values);
frame = obj->animInfo.animFrame;
if (frame < 0) {
frame = 0;
}
if (1) // ? necessary to match
{
position[0] = (f32) values[retrieve_animation_index(frame, &attribute)];
position[1] = (f32) values[retrieve_animation_index(frame, &attribute)];
position[2] = (f32) values[retrieve_animation_index(frame, &attribute)];
}
} else {
vec3f_set(position, 0, 0, 0);
}
}
/**
* Unused function to find the root of the geo node tree, which should be a
* GraphNodeRoot. If it is not for some reason, null is returned.
*/
struct GraphNodeRoot *geo_find_root(struct GraphNode *graphNode) {
struct GraphNodeRoot *resGraphNode = NULL;
while (graphNode->parent != NULL) {
graphNode = graphNode->parent;
}
if (graphNode->type == GRAPH_NODE_TYPE_ROOT) {
resGraphNode = (struct GraphNodeRoot *) graphNode;
}
return resGraphNode;
}
+434
View File
@@ -0,0 +1,434 @@
#ifndef GRAPH_NODE_H
#define GRAPH_NODE_H
#include "../include/PR/ultratypes.h"
#include "../include/PR/gbi.h"
#include "../include/types.h"
#include "../../memory.h"
#define GRAPH_RENDER_ACTIVE (1 << 0)
#define GRAPH_RENDER_CHILDREN_FIRST (1 << 1)
#define GRAPH_RENDER_BILLBOARD (1 << 2)
#define GRAPH_RENDER_Z_BUFFER (1 << 3)
#define GRAPH_RENDER_INVISIBLE (1 << 4)
#define GRAPH_RENDER_HAS_ANIMATION (1 << 5)
// Whether the node type has a function pointer of type GraphNodeFunc
#define GRAPH_NODE_TYPE_FUNCTIONAL 0x100
// Type used for Bowser and an unused geo function in obj_behaviors.c
#define GRAPH_NODE_TYPE_400 0x400
// The discriminant for different types of geo nodes
#define GRAPH_NODE_TYPE_ROOT 0x001
#define GRAPH_NODE_TYPE_ORTHO_PROJECTION 0x002
#define GRAPH_NODE_TYPE_PERSPECTIVE (0x003 | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_MASTER_LIST 0x004
#define GRAPH_NODE_TYPE_START 0x00A
#define GRAPH_NODE_TYPE_LEVEL_OF_DETAIL 0x00B
#define GRAPH_NODE_TYPE_SWITCH_CASE (0x00C | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_CAMERA (0x014 | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_TRANSLATION_ROTATION 0x015
#define GRAPH_NODE_TYPE_TRANSLATION 0x016
#define GRAPH_NODE_TYPE_ROTATION 0x017
#define GRAPH_NODE_TYPE_OBJECT 0x018
#define GRAPH_NODE_TYPE_ANIMATED_PART 0x019
#define GRAPH_NODE_TYPE_BILLBOARD 0x01A
#define GRAPH_NODE_TYPE_DISPLAY_LIST 0x01B
#define GRAPH_NODE_TYPE_SCALE 0x01C
#define GRAPH_NODE_TYPE_SHADOW 0x028
#define GRAPH_NODE_TYPE_OBJECT_PARENT 0x029
#define GRAPH_NODE_TYPE_GENERATED_LIST (0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_BACKGROUND (0x02C | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_HELD_OBJ (0x02E | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_CULLING_RADIUS 0x02F
// The number of master lists. A master list determines the order and render
// mode with which display lists are drawn.
#define GFX_NUM_MASTER_LISTS 8
// Passed as first argument to a GraphNodeFunc to give information about in
// which context it was called and what it is expected to do.
#define GEO_CONTEXT_CREATE 0 // called when node is created from a geo command
#define GEO_CONTEXT_RENDER 1 // called from rendering_graph_node.c
#define GEO_CONTEXT_AREA_UNLOAD 2 // called when unloading an area
#define GEO_CONTEXT_AREA_LOAD 3 // called when loading an area
#define GEO_CONTEXT_AREA_INIT 4 // called when initializing the 8 areas
#define GEO_CONTEXT_HELD_OBJ 5 // called when processing a GraphNodeHeldObj
// The signature for a function stored in a geo node
// The context argument depends on the callContext:
// - for GEO_CONTEXT_CREATE it is the AllocOnlyPool from which the node was allocated
// - for GEO_CONTEXT_RENDER or GEO_CONTEXT_HELD_OBJ it is the top of the float matrix stack with type Mat4
// - for GEO_CONTEXT_AREA_* it is the root geo node
typedef Gfx *(*GraphNodeFunc)(s32 callContext, struct GraphNode *node, void *context);
/** An extension of a graph node that includes a function pointer.
* Many graph node types have an update function that gets called
* when they are processed.
*/
struct FnGraphNode
{
/*0x00*/ struct GraphNode node;
/*0x14*/ GraphNodeFunc func;
};
/** The very root of the geo tree. Specifies the viewport.
*/
struct GraphNodeRoot
{
/*0x00*/ struct GraphNode node;
/*0x14*/ u8 areaIndex;
/*0x15*/ s8 unk15; // ?
/*0x16*/ s16 x;
/*0x18*/ s16 y;
/*0x1A*/ s16 width; // half width, 160
/*0x1C*/ s16 height; // half height
/*0x1E*/ s16 numViews; // number of entries in mystery array
/*0x20*/ struct GraphNode **views;
};
/** A node that sets up an orthographic projection based on the global
* root node. Used to draw the skybox image.
*/
struct GraphNodeOrthoProjection
{
/*0x00*/ struct GraphNode node;
/*0x14*/ f32 scale;
};
/** A node that sets up a perspective projection. Used for drawing the
* game world. It does not set up the camera position, that is done by
* the child of this node, which has type GraphNodeCamera.
*/
struct GraphNodePerspective
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 unused;
/*0x1C*/ f32 fov; // horizontal field of view in degrees
/*0x20*/ s16 near; // near clipping plane
/*0x22*/ s16 far; // far clipping plane
};
/** An entry in the master list. It is a linked list of display lists
* carrying a transformation matrix.
*/
struct DisplayListNode
{
Mtx *transform;
void *displayList;
struct DisplayListNode *next;
};
/** GraphNode that manages the 8 top-level display lists that will be drawn
* Each list has its own render mode, so for example water is drawn in a
* different master list than opaque objects.
* It also sets the z-buffer on before rendering and off after.
*/
struct GraphNodeMasterList
{
/*0x00*/ struct GraphNode node;
/*0x14*/ struct DisplayListNode *listHeads[GFX_NUM_MASTER_LISTS];
/*0x34*/ struct DisplayListNode *listTails[GFX_NUM_MASTER_LISTS];
};
/** Simply used as a parent to group multiple children.
* Does not have any additional functionality.
*/
struct GraphNodeStart
{
/*0x00*/ struct GraphNode node;
};
/** GraphNode that only renders its children if the current transformation matrix
* has a z-translation (in camera space) greater than minDistance and less than
* maxDistance.
* Usage examples: Mario has three level's of detail: Normal, low-poly arms only, and fully low-poly
* The tower in Whomp's fortress has two levels of detail.
*/
struct GraphNodeLevelOfDetail
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 minDistance;
/*0x16*/ s16 maxDistance;
};
/** GraphNode that renders exactly one of its children.
* Which one is rendered is determined by the field 'selectedCase'
* which is set in the node's function.
* Usage examples: room visibility, coin animation, blinking, Mario's power-up / hand pose / cap
*/
struct GraphNodeSwitchCase
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 unused;
/*0x1C*/ s16 numCases;
/*0x1E*/ s16 selectedCase;
};
/**
* GraphNode that specifies the location and aim of the camera.
* When the roll is 0, the up vector is (0, 1, 0).
*/
struct GraphNodeCamera
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ union {
// When the node is created, a mode is assigned to the node.
// Later in geo_camera_main a Camera is allocated,
// the mode is passed to the struct, and the field is overridden
// by a pointer to the struct. Gotta save those 4 bytes.
s32 mode;
struct Camera *camera;
} config;
/*0x1C*/ Vec3f pos;
/*0x28*/ Vec3f focus;
/*0x34*/ Mat4 *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
/*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen.
/*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent
};
/** GraphNode that translates and rotates its children.
* Usage example: wing cap wings.
* There is a dprint function that sets the translation and rotation values
* based on the ENEMYINFO array.
* The display list can be null, in which case it won't draw anything itself.
*/
struct GraphNodeTranslationRotation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
/*0x1E*/ Vec3s rotation;
};
/** GraphNode that translates itself and its children.
* Usage example: SUPER MARIO logo letters in debug level select.
* The display list can be null, in which case it won't draw anything itself.
*/
struct GraphNodeTranslation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
u8 pad1E[2];
};
/** GraphNode that rotates itself and its children.
* Usage example: Mario torso / head rotation. Its parameters are dynamically
* set by a parent script node in that case.
* The display list can be null, in which case it won't draw anything itself.
*/
struct GraphNodeRotation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s rotation;
u8 pad1E[2];
};
/** GraphNode part that transforms itself and its children based on animation
* data. This animation data is not stored in the node itself but in global
* variables that are set when object nodes are processed if the object has
* animation.
* Used for Mario, enemies and anything else with animation data.
* The display list can be null, in which case it won't draw anything itself.
*/
struct GraphNodeAnimatedPart
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
};
/** A GraphNode that draws a display list rotated in a way to always face the
* camera. Note that if the entire object is a billboard (like a coin or 1-up)
* then it simply sets the billboard flag for the entire object, this node is
* used for billboard parts (like a chuckya or goomba body).
*/
struct GraphNodeBillboard
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
};
/** A GraphNode that simply draws a display list without doing any
* transformation beforehand. It does inherit the parent's transformation.
*/
struct GraphNodeDisplayList
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
};
/** GraphNode part that scales itself and its children.
* Usage example: Mario's fist or shoe, which grows when attacking. This can't
* be done with an animated part sine animation data doesn't support scaling.
* Note that many scaling animations (like a goomba getting stomped) happen on
* the entire object. This node is only used when a single part needs to be scaled.
* There is also a level command that scales the entire level, used for THI.
* The display list can be null, in which case it won't draw anything itself.
*/
struct GraphNodeScale
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ f32 scale;
};
/** GraphNode that draws a shadow under an object.
* Every object starts with a shadow node.
* The shadow type determines the shape (round or rectangular), vertices (4 or 9)
* and other features.
*/
struct GraphNodeShadow
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 shadowScale; // diameter (when a circle) or side (when a square) of shadow
/*0x16*/ u8 shadowSolidity; // opacity of shadow, 255 = opaque
/*0x17*/ u8 shadowType; // see ShadowType enum in shadow.h
};
/** GraphNode that contains as its sharedChild a group node containing all
* object nodes.
*/
struct GraphNodeObjectParent
{
/*0x00*/ struct GraphNode node;
/*0x14*/ struct GraphNode *sharedChild;
};
/** GraphNode that draws display lists not directly in memory but generated by
* a function.
* Used for wobbling paintings, water, environment effects.
* It might not draw anything, it could also just update something.
* For example: there is a node that stops water flow when the game is paused.
* The parameter field gives extra context info. For shifting sand or paintings,
* it can determine which texture to use.
*/
struct GraphNodeGenerated
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ u32 parameter; // extra context for the function
};
/** GraphNode that draws a background image or a rectangle of a color.
* Drawn in an orthographic projection, used for skyboxes.
*/
struct GraphNodeBackground
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 unused;
/*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null
};
/** Renders the object that Mario is holding.
*/
struct GraphNodeHeldObject
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 playerIndex;
/*0x1C*/ struct Object *objNode;
/*0x20*/ Vec3s translation;
};
/** A node that allows an object to specify a different culling radius than the
* default one of 300. For this to work, it needs to be a direct child of the
* object node. Used for very large objects, such as shock wave rings that Bowser
* creates, tornadoes, the big eel.
*/
struct GraphNodeCullingRadius
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 cullingRadius; // specifies the 'sphere radius' for purposes of frustum culling
u8 pad1E[2];
};
extern struct GraphNodeMasterList *gCurGraphNodeMasterList;
extern struct GraphNodePerspective *gCurGraphNodeCamFrustum;
extern struct GraphNodeCamera *gCurGraphNodeCamera;
extern struct GraphNodeHeldObject *gCurGraphNodeHeldObject;
extern u16 gAreaUpdateCounter;
extern struct GraphNode *gCurRootGraphNode;
extern struct GraphNode *gCurGraphNodeList[];
extern s16 gCurGraphNodeIndex;
//extern Vec3f gVec3fZero;
//extern Vec3s gVec3sZero;
//extern Vec3f gVec3fOne;
//extern Vec3s gVec3sOne;
void init_scene_graph_node_links(struct GraphNode *graphNode, s32 type);
struct GraphNodeRoot *init_graph_node_root(struct AllocOnlyPool *pool, struct GraphNodeRoot *graphNode,
s16 areaIndex, s16 x, s16 y, s16 width, s16 height);
struct GraphNodeOrthoProjection *init_graph_node_ortho_projection(struct AllocOnlyPool *pool, struct GraphNodeOrthoProjection *graphNode, f32 scale);
struct GraphNodePerspective *init_graph_node_perspective(struct AllocOnlyPool *pool, struct GraphNodePerspective *graphNode,
f32 fov, s16 near, s16 far, GraphNodeFunc nodeFunc, s32 unused);
struct GraphNodeStart *init_graph_node_start(struct AllocOnlyPool *pool, struct GraphNodeStart *graphNode);
struct GraphNodeMasterList *init_graph_node_master_list(struct AllocOnlyPool *pool, struct GraphNodeMasterList *graphNode, s16 on);
struct GraphNodeLevelOfDetail *init_graph_node_render_range(struct AllocOnlyPool *pool, struct GraphNodeLevelOfDetail *graphNode,
s16 minDistance, s16 maxDistance);
struct GraphNodeSwitchCase *init_graph_node_switch_case(struct AllocOnlyPool *pool, struct GraphNodeSwitchCase *graphNode,
s16 numCases, s16 selectedCase, GraphNodeFunc nodeFunc, s32 unused);
struct GraphNodeCamera *init_graph_node_camera(struct AllocOnlyPool *pool, struct GraphNodeCamera *graphNode,
f32 *pos, f32 *focus, GraphNodeFunc func, s32 mode);
struct GraphNodeTranslationRotation *init_graph_node_translation_rotation(struct AllocOnlyPool *pool, struct GraphNodeTranslationRotation *graphNode,
s32 drawingLayer, void *displayList, Vec3s translation, Vec3s rotation);
struct GraphNodeTranslation *init_graph_node_translation(struct AllocOnlyPool *pool, struct GraphNodeTranslation *graphNode,
s32 drawingLayer, void *displayList, Vec3s translation);
struct GraphNodeRotation *init_graph_node_rotation(struct AllocOnlyPool *pool, struct GraphNodeRotation *graphNode,
s32 drawingLayer, void *displayList, Vec3s rotation);
struct GraphNodeScale *init_graph_node_scale(struct AllocOnlyPool *pool, struct GraphNodeScale *graphNode,
s32 drawingLayer, void *displayList, f32 scale);
struct GraphNodeObject *init_graph_node_object(struct AllocOnlyPool *pool, struct GraphNodeObject *graphNode,
struct GraphNode *sharedChild, Vec3f pos, Vec3s angle, Vec3f scale);
struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct AllocOnlyPool *pool, struct GraphNodeCullingRadius *graphNode, s16 radius);
struct GraphNodeAnimatedPart *init_graph_node_animated_part(struct AllocOnlyPool *pool, struct GraphNodeAnimatedPart *graphNode,
s32 drawingLayer, void *displayList, Vec3s translation);
struct GraphNodeBillboard *init_graph_node_billboard(struct AllocOnlyPool *pool, struct GraphNodeBillboard *graphNode,
s32 drawingLayer, void *displayList, Vec3s translation);
struct GraphNodeDisplayList *init_graph_node_display_list(struct AllocOnlyPool *pool, struct GraphNodeDisplayList *graphNode,
s32 drawingLayer, void *displayList);
struct GraphNodeShadow *init_graph_node_shadow(struct AllocOnlyPool *pool, struct GraphNodeShadow *graphNode,
s16 shadowScale, u8 shadowSolidity, u8 shadowType);
struct GraphNodeObjectParent *init_graph_node_object_parent(struct AllocOnlyPool *pool, struct GraphNodeObjectParent *sp1c,
struct GraphNode *sharedChild);
struct GraphNodeGenerated *init_graph_node_generated(struct AllocOnlyPool *pool, struct GraphNodeGenerated *sp1c,
GraphNodeFunc gfxFunc, s32 parameter);
struct GraphNodeBackground *init_graph_node_background(struct AllocOnlyPool *pool, struct GraphNodeBackground *sp1c,
u16 background, GraphNodeFunc backgroundFunc, s32 zero);
struct GraphNodeHeldObject *init_graph_node_held_object(struct AllocOnlyPool *pool, struct GraphNodeHeldObject *sp1c,
struct Object *objNode, Vec3s translation,
GraphNodeFunc nodeFunc, s32 playerIndex);
struct GraphNode *geo_add_child(struct GraphNode *parent, struct GraphNode *childNode);
struct GraphNode *geo_remove_child(struct GraphNode *graphNode);
struct GraphNode *geo_make_first_child(struct GraphNode *newFirstChild);
void geo_call_global_function_nodes_helper(struct GraphNode *graphNode, s32 callContext);
void geo_call_global_function_nodes(struct GraphNode *graphNode, s32 callContext);
void geo_reset_object_node(struct GraphNodeObject *graphNode);
void geo_obj_init(struct GraphNodeObject *graphNode, void *sharedChild, Vec3f pos, Vec3s angle);
void geo_obj_init_spawninfo(struct GraphNodeObject *graphNode, struct SpawnInfo *spawn);
void geo_obj_init_animation(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr);
void geo_obj_init_animation_accel(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr, u32 animAccel);
s32 retrieve_animation_index(s32 frame, u16 **attributes);
s16 geo_update_animation_frame(struct AnimInfo *obj, s32 *accelAssist);
void geo_retreive_animation_translation(struct GraphNodeObject *obj, Vec3f position);
struct GraphNodeRoot *geo_find_root(struct GraphNode *graphNode);
// graph_node_manager
s16 *read_vec3s_to_vec3f(Vec3f, s16 *src);
s16 *read_vec3s(Vec3s dst, s16 *src);
s16 *read_vec3s_angle(Vec3s dst, s16 *src);
void register_scene_graph_node(struct GraphNode *graphNode);
#endif // GRAPH_NODE_H
+81
View File
@@ -0,0 +1,81 @@
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#include "geo_layout.h"
#include "graph_node.h"
#if IS_64_BIT
static s16 next_s16_in_geo_script(s16 **src) {
s16 ret;
if (((uintptr_t)(*src) & 7) == 4) {
*src += 2; // skip 32 bits
}
ret = *(*src)++;
if (((uintptr_t)(*src) & 7) == 4) {
*src += 2; // skip 32 bits
}
return ret;
}
#else
#define next_s16_in_geo_script(src) (*(*src)++)
#endif
/**
* Takes a pointer to three shorts (supplied by a geo layout script) and
* copies it to the destination float vector.
*/
s16 *read_vec3s_to_vec3f(Vec3f dst, s16 *src) {
dst[0] = next_s16_in_geo_script(&src);
dst[1] = next_s16_in_geo_script(&src);
dst[2] = next_s16_in_geo_script(&src);
return src;
}
/**
* Takes a pointer to three shorts (supplied by a geo layout script) and
* copies it to the destination vector. It's essentially a memcpy but consistent
* with the other two 'geo-script vector to internal vector' functions.
*/
s16 *read_vec3s(Vec3s dst, s16 *src) {
dst[0] = next_s16_in_geo_script(&src);
dst[1] = next_s16_in_geo_script(&src);
dst[2] = next_s16_in_geo_script(&src);
return src;
}
/**
* Takes a pointer to three angles in degrees (supplied by a geo layout script)
* and converts it to a vector of three in-game angle units in [-32768, 32767]
* range.
*/
s16 *read_vec3s_angle(Vec3s dst, s16 *src) {
dst[0] = (next_s16_in_geo_script(&src) << 15) / 180;
dst[1] = (next_s16_in_geo_script(&src) << 15) / 180;
dst[2] = (next_s16_in_geo_script(&src) << 15) / 180;
return src;
}
/**
* Add the given graph node as a child to the current top of the gfx stack:
* 'gCurGraphNodeList'. This is called from geo_layout commands to add nodes
* to the scene graph.
*/
void register_scene_graph_node(struct GraphNode *graphNode) {
if (graphNode != NULL) {
gCurGraphNodeList[gCurGraphNodeIndex] = graphNode;
if (gCurGraphNodeIndex == 0) {
if (gCurRootGraphNode == NULL) {
gCurRootGraphNode = graphNode;
}
} else {
if (gCurGraphNodeList[gCurGraphNodeIndex - 1]->type == GRAPH_NODE_TYPE_OBJECT_PARENT) {
((struct GraphNodeObjectParent *) gCurGraphNodeList[gCurGraphNodeIndex - 1])
->sharedChild = graphNode;
} else {
geo_add_child(gCurGraphNodeList[gCurGraphNodeIndex - 1], graphNode);
}
}
}
}
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
#ifndef MATH_UTIL_H
#define MATH_UTIL_H
#include "../include/PR/ultratypes.h"
#include "../include/PR/gbi.h"
#include "../include/types.h"
/*
* The sine and cosine tables overlap, but "#define gCosineTable (gSineTable +
* 0x400)" doesn't give expected codegen; gSineTable and gCosineTable need to
* be different symbols for code to match. Most likely the tables were placed
* adjacent to each other, and gSineTable cut short, such that reads overflow
* into gCosineTable.
*
* These kinds of out of bounds reads are undefined behavior, and break on
* e.g. GCC (which doesn't place the tables next to each other, and probably
* exploits array sizes for range analysis-based optimizations as well).
* Thus, for non-IDO compilers we use the standard-compliant version.
*/
extern f32 gSineTable[];
#ifdef AVOID_UB
#define gCosineTable (gSineTable + 0x400)
#else
extern f32 gCosineTable[];
#endif
#define sins(x) gSineTable[(u16) (x) >> 4]
#define coss(x) gCosineTable[(u16) (x) >> 4]
#define min(a, b) ((a) <= (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define sqr(x) ((x) * (x))
void *vec3f_copy(Vec3f dest, Vec3f src);
void *vec3f_set(Vec3f dest, f32 x, f32 y, f32 z);
void *vec3f_add(Vec3f dest, Vec3f a);
void *vec3f_sum(Vec3f dest, Vec3f a, Vec3f b);
void *vec3s_copy(Vec3s dest, Vec3s src);
void *vec3s_set(Vec3s dest, s16 x, s16 y, s16 z);
void *vec3s_add(Vec3s dest, Vec3s a);
void *vec3s_sum(Vec3s dest, Vec3s a, Vec3s b);
void *vec3s_sub(Vec3s dest, Vec3s a);
void *vec3s_to_vec3f(Vec3f dest, Vec3s a);
void *vec3f_to_vec3s(Vec3s dest, Vec3f a);
void *find_vector_perpendicular_to_plane(Vec3f dest, Vec3f a, Vec3f b, Vec3f c);
void *vec3f_cross(Vec3f dest, Vec3f a, Vec3f b);
void *vec3f_normalize(Vec3f dest);
void mtxf_copy(Mat4 dest, Mat4 src);
void mtxf_identity(Mat4 mtx);
void mtxf_translate(Mat4 dest, Vec3f b);
void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll);
void mtxf_rotate_zxy_and_translate(Mat4 dest, Vec3f translate, Vec3s rotate);
void mtxf_rotate_xyz_and_translate(Mat4 dest, Vec3f b, Vec3s c);
void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, s16 angle);
void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s16 yaw);
void mtxf_align_terrain_triangle(Mat4 mtx, Vec3f pos, s16 yaw, f32 radius);
void mtxf_mul(Mat4 dest, Mat4 a, Mat4 b);
void mtxf_scale_vec3f(Mat4 dest, Mat4 mtx, Vec3f s);
void mtxf_mul_vec3s(Mat4 mtx, Vec3s b);
void mtxf_mul_vec3f(Mat4 mtx, Vec3f b);
void mtxf_to_mtx(Mtx *dest, Mat4 src);
void mtxf_rotate_xy(Mtx *mtx, s16 angle);
void get_pos_from_transform_mtx(Vec3f dest, Mat4 objMtx, Mat4 camMtx);
void vec3f_get_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, s16 *pitch, s16 *yaw);
void vec3f_set_dist_and_angle(Vec3f from, Vec3f to, f32 dist, s16 pitch, s16 yaw);
s32 approach_s32(s32 current, s32 target, s32 inc, s32 dec);
f32 approach_f32(f32 current, f32 target, f32 inc, f32 dec);
s16 atan2s(f32 y, f32 x);
f32 atan2f(f32 a, f32 b);
void spline_get_weights(Vec4f result, f32 t, UNUSED s32 c);
void anim_spline_init(Vec4s *keyFrames);
s32 anim_spline_poll(Vec3f result);
// From object_helpers.c
void linear_mtxf_mul_vec3f(Mat4 m, Vec3f dst, Vec3f v);
void linear_mtxf_transpose_mul_vec3f(Mat4 m, Vec3f dst, Vec3f v);
#endif // MATH_UTIL_H
+415
View File
@@ -0,0 +1,415 @@
// CUSTOM/PATCH
#include "../shim.h"
#include "surface_collision.h"
#include "../include/surface_terrains.h"
#include "../../load_surfaces.h"
/**
* Iterate through the list of ceilings and find the first ceiling over a given point.
*/
static struct Surface *find_ceil_from_list( s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
struct Surface *ceil = NULL;
ceil = NULL;
// Stay in this loop until out of ceilings.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y >= -0.01f ) continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
z2 = surf->vertex2[2];
x2 = surf->vertex2[0];
// Checking if point is in bounds of the triangle laterally.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) > 0) {
continue;
}
// Slight optimization by checking these later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) > 0) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) > 0) {
continue;
}
// // Determine if checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera != 0) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// }
// // Ignore camera only surfaces.
// else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// continue;
// }
{
f32 nx = surf->normal.x;
f32 ny = surf->normal.y;
f32 nz = surf->normal.z;
f32 oo = surf->originOffset;
f32 height;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
continue;
}
// Find the ceil height at the specific point.
height = -(x * nx + nz * z + oo) / ny;
// Checks for ceiling interaction with a 78 unit buffer.
//! (Exposed Ceilings) Because any point above a ceiling counts
// as interacting with a ceiling, ceilings far below can cause
// "invisible walls" that are really just exposed ceilings.
if (y - (height - -78.0f) > 0.0f) {
continue;
}
if( height < *pheight )
{
*pheight = height;
ceil = surf;
}
}
}
//! (Surface Cucking) Since only the first ceil is returned and not the lowest,
// lower ceilings can be "cucked" by higher ceilings.
return ceil;
}
/**
* Iterate through the list of floors and find the first floor under a given point.
*/
static struct Surface *find_floor_from_list( s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
f32 nx, ny, nz;
f32 oo;
f32 height;
struct Surface *floor = NULL;
// Iterate through the list of floors until there are no more floors.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y <= 0.01f ) continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
x2 = surf->vertex2[0];
z2 = surf->vertex2[2];
// Check that the point is within the triangle bounds.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) {
continue;
}
// To slightly save on computation time, set this later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) < 0) {
continue;
}
// // Determine if we are checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera != 0) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// }
// // If we are not checking for the camera, ignore camera only floors.
// else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// continue;
// }
nx = surf->normal.x;
ny = surf->normal.y;
nz = surf->normal.z;
oo = surf->originOffset;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
continue;
}
// Find the height of the floor at a given location.
height = -(x * nx + nz * z + oo) / ny;
// Checks for floor interaction with a 78 unit buffer.
if (y - (height + -78.0f) < 0.0f) {
continue;
}
if( height > *pheight )
{
*pheight = height;
floor = surf;
}
}
//! (Surface Cucking) Since only the first floor is returned and not the highest,
// higher floors can be "cucked" by lower floors.
return floor;
}
static s32 find_wall_collisions_from_list( struct WallCollisionData *data) {
register struct Surface *surf;
register f32 offset;
register f32 radius = data->radius;
register f32 x = data->x;
register f32 y = data->y + data->offsetY;
register f32 z = data->z;
register f32 px, pz;
register f32 w1, w2, w3;
register f32 y1, y2, y3;
s32 numCols = 0;
// Max collision radius = 200
if (radius > 200.0f) {
radius = 200.0f;
}
// Stay in this loop until out of walls.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y < -0.01f || surf->normal.y > 0.01f ) continue;
if( surf->normal.x < -0.707f || surf->normal.x > 0.707f ) {
surf->flags |= SURFACE_FLAG_X_PROJECTION;
}
// Exclude a large number of walls immediately to optimize.
if (y < surf->lowerY || y > surf->upperY) {
continue;
}
offset = surf->normal.x * x + surf->normal.y * y + surf->normal.z * z + surf->originOffset;
if (offset < -radius || offset > radius) {
continue;
}
px = x;
pz = z;
//! (Quantum Tunneling) Due to issues with the vertices walls choose and
// the fact they are floating point, certain floating point positions
// along the seam of two walls may collide with neither wall or both walls.
if (surf->flags & SURFACE_FLAG_X_PROJECTION) {
w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2];
y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1];
if (surf->normal.x > 0.0f) {
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) > 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) > 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) > 0.0f) {
continue;
}
} else {
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) < 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) < 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) < 0.0f) {
continue;
}
}
} else {
w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0];
y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1];
if (surf->normal.z > 0.0f) {
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) > 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) > 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) > 0.0f) {
continue;
}
} else {
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) < 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) < 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) < 0.0f) {
continue;
}
}
}
// Determine if checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// } else {
// // Ignore camera only surfaces.
// if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// continue;
// }
// // If an object can pass through a vanish cap wall, pass through.
// if (surf->type == SURFACE_VANISH_CAP_WALLS) {
// // If an object can pass through a vanish cap wall, pass through.
// if (gCurrentObject != NULL
// && (gCurrentObject->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE)) {
// continue;
// }
// // If Mario has a vanish cap, pass through the vanish cap wall.
// if (gCurrentObject != NULL && gCurrentObject == gMarioObject
// && (gMarioState->flags & MARIO_VANISH_CAP)) {
// continue;
// }
// }
// }
//! (Wall Overlaps) Because this doesn't update the x and z local variables,
// multiple walls can push mario more than is required.
data->x += surf->normal.x * (radius - offset);
data->z += surf->normal.z * (radius - offset);
//! (Unreferenced Walls) Since this only returns the first four walls,
// this can lead to wall interaction being missed. Typically unreferenced walls
// come from only using one wall, however.
if (data->numWalls < 4) {
data->walls[data->numWalls++] = surf;
}
numCols++;
}
return numCols;
}
s32 f32_find_wall_collision(f32 *xPtr, f32 *yPtr, f32 *zPtr, f32 offsetY, f32 radius)
{
struct WallCollisionData collision;
s32 numCollisions = 0;
collision.offsetY = offsetY;
collision.radius = radius;
collision.x = *xPtr;
collision.y = *yPtr;
collision.z = *zPtr;
collision.numWalls = 0;
numCollisions = find_wall_collisions(&collision);
*xPtr = collision.x;
*yPtr = collision.y;
*zPtr = collision.z;
return numCollisions;
}
s32 find_wall_collisions(struct WallCollisionData *colData)
{
s32 numCollisions = 0;
s16 x = colData->x;
s16 z = colData->z;
colData->numWalls = 0;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
return numCollisions;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
return numCollisions;
}
numCollisions += find_wall_collisions_from_list(colData);
return numCollisions;
}
f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil)
{
f32 height = CELL_HEIGHT_LIMIT;
*pceil = find_ceil_from_list( posX, posY, posZ, &height );
return height;
}
struct FloorGeometry sFloorGeo;
f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo)
{
struct Surface *floor;
f32 floorHeight = find_floor(xPos, yPos, zPos, &floor);
*floorGeo = NULL;
if (floor != NULL) {
sFloorGeo.normalX = floor->normal.x;
sFloorGeo.normalY = floor->normal.y;
sFloorGeo.normalZ = floor->normal.z;
sFloorGeo.originOffset = floor->originOffset;
*floorGeo = &sFloorGeo;
}
return floorHeight;
}
f32 find_floor_height(f32 x, f32 y, f32 z)
{
f32 height = FLOOR_LOWER_LIMIT;
find_floor_from_list( x, y, z, &height );
return height;
}
f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor)
{
f32 height = FLOOR_LOWER_LIMIT;
*pfloor = find_floor_from_list( xPos, yPos, zPos, &height );
return height;
}
f32 find_water_level(f32 x, f32 z)
{
return -10000.0f;
}
f32 find_poison_gas_level(f32 x, f32 z)
{
return -10000.0f;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef SURFACE_COLLISION_H
#define SURFACE_COLLISION_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#define LEVEL_BOUNDARY_MAX 0x2000
#define CELL_SIZE 0x400
#define CELL_HEIGHT_LIMIT 20000.f
#define FLOOR_LOWER_LIMIT -11000.f
struct WallCollisionData
{
/*0x00*/ f32 x, y, z;
/*0x0C*/ f32 offsetY;
/*0x10*/ f32 radius;
/*0x14*/ s16 unk14;
/*0x16*/ s16 numWalls;
/*0x18*/ struct Surface *walls[4];
};
struct FloorGeometry
{
f32 unused[4]; // possibly position data?
f32 normalX;
f32 normalY;
f32 normalZ;
f32 originOffset;
};
s32 f32_find_wall_collision(f32 *xPtr, f32 *yPtr, f32 *zPtr, f32 offsetY, f32 radius);
s32 find_wall_collisions(struct WallCollisionData *colData);
f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil);
f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo);
f32 find_floor_height(f32 x, f32 y, f32 z);
f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor);
f32 find_water_level(f32 x, f32 z);
f32 find_poison_gas_level(f32 x, f32 z);
#endif // SURFACE_COLLISION_H
+157
View File
@@ -0,0 +1,157 @@
#ifndef AREA_H
#define AREA_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#include "camera.h"
//#include "engine/graph_node.h"
struct WarpNode
{
/*00*/ u8 id;
/*01*/ u8 destLevel;
/*02*/ u8 destArea;
/*03*/ u8 destNode;
};
struct ObjectWarpNode
{
/*0x00*/ struct WarpNode node;
/*0x04*/ struct Object *object;
/*0x08*/ struct ObjectWarpNode *next;
};
// From Surface 0x1B to 0x1E
#define INSTANT_WARP_INDEX_START 0x00 // Equal and greater than Surface 0x1B
#define INSTANT_WARP_INDEX_STOP 0x04 // Less than Surface 0x1F
struct InstantWarp
{
/*0x00*/ u8 id; // 0 = 0x1B / 1 = 0x1C / 2 = 0x1D / 3 = 0x1E
/*0x01*/ u8 area;
/*0x02*/ Vec3s displacement;
};
struct SpawnInfo
{
/*0x00*/ Vec3s startPos;
/*0x06*/ Vec3s startAngle;
/*0x0C*/ s8 areaIndex;
/*0x0D*/ s8 activeAreaIndex;
/*0x10*/ u32 behaviorArg;
/*0x14*/ void *behaviorScript;
/*0x18*/ struct GraphNode *unk18;
/*0x1C*/ struct SpawnInfo *next;
};
struct UnusedArea28
{
/*0x00*/ s16 unk00;
/*0x02*/ s16 unk02;
/*0x04*/ s16 unk04;
/*0x06*/ s16 unk06;
/*0x08*/ s16 unk08;
};
struct Whirlpool
{
/*0x00*/ Vec3s pos;
/*0x03*/ s16 strength;
};
struct Area
{
/*0x00*/ s8 index;
/*0x01*/ s8 flags; // Only has 1 flag: 0x01 = Is this the active area?
/*0x02*/ u16 terrainType; // default terrain of the level (set from level script cmd 0x31)
/*0x04*/ struct GraphNodeRoot *unk04; // geometry layout data
/*0x08*/ s16 *terrainData; // collision data (set from level script cmd 0x2E)
/*0x0C*/ s8 *surfaceRooms; // (set from level script cmd 0x2F)
/*0x10*/ s16 *macroObjects; // Macro Objects Ptr (set from level script cmd 0x39)
/*0x14*/ struct ObjectWarpNode *warpNodes;
/*0x18*/ struct WarpNode *paintingWarpNodes;
/*0x1C*/ struct InstantWarp *instantWarps;
/*0x20*/ struct SpawnInfo *objectSpawnInfos;
/*0x24*/ struct Camera *camera;
/*0x28*/ struct UnusedArea28 *unused28; // Filled by level script 0x3A, but is unused.
/*0x2C*/ struct Whirlpool *whirlpools[2];
/*0x34*/ u8 dialog[2]; // Level start dialog number (set by level script cmd 0x30)
/*0x36*/ u16 musicParam;
/*0x38*/ u16 musicParam2;
};
// All the transition data to be used in screen_transition.c
struct WarpTransitionData
{
/*0x00*/ u8 red;
/*0x01*/ u8 green;
/*0x02*/ u8 blue;
/*0x04*/ s16 startTexRadius;
/*0x06*/ s16 endTexRadius;
/*0x08*/ s16 startTexX;
/*0x0A*/ s16 startTexY;
/*0x0C*/ s16 endTexX;
/*0x0E*/ s16 endTexY;
/*0x10*/ s16 texTimer; // always 0, does seems to affect transition when disabled
};
#define WARP_TRANSITION_FADE_FROM_COLOR 0x00
#define WARP_TRANSITION_FADE_INTO_COLOR 0x01
#define WARP_TRANSITION_FADE_FROM_STAR 0x08
#define WARP_TRANSITION_FADE_INTO_STAR 0x09
#define WARP_TRANSITION_FADE_FROM_CIRCLE 0x0A
#define WARP_TRANSITION_FADE_INTO_CIRCLE 0x0B
#define WARP_TRANSITION_FADE_FROM_MARIO 0x10
#define WARP_TRANSITION_FADE_INTO_MARIO 0x11
#define WARP_TRANSITION_FADE_FROM_BOWSER 0x12
#define WARP_TRANSITION_FADE_INTO_BOWSER 0x13
struct WarpTransition
{
/*0x00*/ u8 isActive; // Is the transition active. (either TRUE or FALSE)
/*0x01*/ u8 type; // Determines the type of transition to use (circle, star, etc.)
/*0x02*/ u8 time; // Amount of time to complete the transition (in frames)
/*0x03*/ u8 pauseRendering; // Should the game stop rendering. (either TRUE or FALSE)
/*0x04*/ struct WarpTransitionData data;
};
// extern struct GraphNode **gLoadedGraphNodes;
// extern struct SpawnInfo gPlayerSpawnInfos[];
// extern struct GraphNode *D_8033A160[];
// extern struct Area gAreaData[];
// extern struct WarpTransition gWarpTransition;
// extern s16 gCurrCourseNum;
// extern s16 gCurrActNum;
// extern s16 gCurrAreaIndex;
// extern s16 gSavedCourseNum;
// extern s16 gPauseScreenMode;
// extern s16 gSaveOptSelectIndex;
//
// extern struct SpawnInfo *gMarioSpawnInfo;
//
// extern struct Area *gAreas;
// extern struct Area *gCurrentArea;
//
// extern s16 gCurrSaveFileNum;
// extern s16 gCurrLevelNum;
// void override_viewport_and_clip(Vp *a, Vp *b, u8 c, u8 d, u8 e);
// void print_intro_text(void);
// u32 get_mario_spawn_type(struct Object *o);
// struct ObjectWarpNode *area_get_warp_node(u8 id);
// void clear_areas(void);
// void clear_area_graph_nodes(void);
// void load_area(s32 index);
// void unload_area(void);
// void load_mario_area(void);
// void unload_mario_area(void);
// void change_area(s32 index);
// void area_update_objects(void);
// void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);
// void play_transition_after_delay(s16 transType, s16 time, u8 red, u8 green, u8 blue, s16 delay);
// void render_game(void);
#endif // AREA_H
+19
View File
@@ -0,0 +1,19 @@
#include "behavior_actions.h"
#include "rendering_graph_node.h"
#include "../shim.h"
// not sure what this is doing here. not in a behavior file.
Gfx *geo_move_mario_part_from_parent(s32 run, UNUSED struct GraphNode *node, Mat4 mtx) {
Mat4 sp20;
struct Object *sp1C;
if (run == TRUE) {
sp1C = (struct Object *) gCurGraphNodeObject;
if (sp1C == gMarioObject && sp1C->prevObj != NULL) {
create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
obj_set_gfx_pos_from_pos(sp1C->prevObj);
}
}
return NULL;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "../include/types.h"
#include "../mario/model.inc.h"
extern Gfx *geo_move_mario_part_from_parent(s32 run, UNUSED struct GraphNode *node, Mat4 mtx);
+776
View File
@@ -0,0 +1,776 @@
#ifndef CAMERA_H
#define CAMERA_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#include "area.h"
//#include "engine/geo_layout.h"
//#include "engine/graph_node.h"
//#include "level_table.h"
/**
* @file camera.h
* Constants, defines, and structs used by the camera system.
* @see camera.c
*/
#define ABS(x) ((x) > 0.f ? (x) : -(x))
#define ABS2(x) ((x) >= 0.f ? (x) : -(x))
/**
* Converts an angle in degrees to sm64's s16 angle units. For example, DEGREES(90) == 0x4000
* This should be used mainly to make camera code clearer at first glance.
*/
#define DEGREES(x) ((x) * 0x10000 / 360)
#define LEVEL_AREA_INDEX(levelNum, areaNum) (((levelNum) << 4) + (areaNum))
/**
* Helper macro for defining which areas of a level should zoom out the camera when the game is paused.
* Because a mask is used by two levels, the pattern will repeat when more than 4 areas are used by a level.
*/
#define ZOOMOUT_AREA_MASK(level1Area1, level1Area2, level1Area3, level1Area4, \
level2Area1, level2Area2, level2Area3, level2Area4) \
((level2Area4) << 7 | \
(level2Area3) << 6 | \
(level2Area2) << 5 | \
(level2Area1) << 4 | \
(level1Area4) << 3 | \
(level1Area3) << 2 | \
(level1Area2) << 1 | \
(level1Area1) << 0)
#define AREA_BBH LEVEL_AREA_INDEX(LEVEL_BBH, 1)
#define AREA_CCM_OUTSIDE LEVEL_AREA_INDEX(LEVEL_CCM, 1)
#define AREA_CCM_SLIDE LEVEL_AREA_INDEX(LEVEL_CCM, 2)
#define AREA_CASTLE_LOBBY LEVEL_AREA_INDEX(LEVEL_CASTLE, 1)
#define AREA_CASTLE_TIPPY LEVEL_AREA_INDEX(LEVEL_CASTLE, 2)
#define AREA_CASTLE_BASEMENT LEVEL_AREA_INDEX(LEVEL_CASTLE, 3)
#define AREA_HMC LEVEL_AREA_INDEX(LEVEL_HMC, 1)
#define AREA_SSL_OUTSIDE LEVEL_AREA_INDEX(LEVEL_SSL, 1)
#define AREA_SSL_PYRAMID LEVEL_AREA_INDEX(LEVEL_SSL, 2)
#define AREA_SSL_EYEROK LEVEL_AREA_INDEX(LEVEL_SSL, 3)
#define AREA_BOB LEVEL_AREA_INDEX(LEVEL_BOB, 1)
#define AREA_SL_OUTSIDE LEVEL_AREA_INDEX(LEVEL_SL, 1)
#define AREA_SL_IGLOO LEVEL_AREA_INDEX(LEVEL_SL, 2)
#define AREA_WDW_MAIN LEVEL_AREA_INDEX(LEVEL_WDW, 1)
#define AREA_WDW_TOWN LEVEL_AREA_INDEX(LEVEL_WDW, 2)
#define AREA_JRB_MAIN LEVEL_AREA_INDEX(LEVEL_JRB, 1)
#define AREA_JRB_SHIP LEVEL_AREA_INDEX(LEVEL_JRB, 2)
#define AREA_THI_HUGE LEVEL_AREA_INDEX(LEVEL_THI, 1)
#define AREA_THI_TINY LEVEL_AREA_INDEX(LEVEL_THI, 2)
#define AREA_THI_WIGGLER LEVEL_AREA_INDEX(LEVEL_THI, 3)
#define AREA_TTC LEVEL_AREA_INDEX(LEVEL_TTC, 1)
#define AREA_RR LEVEL_AREA_INDEX(LEVEL_RR, 1)
#define AREA_CASTLE_GROUNDS LEVEL_AREA_INDEX(LEVEL_CASTLE_GROUNDS, 1)
#define AREA_BITDW LEVEL_AREA_INDEX(LEVEL_BITDW, 1)
#define AREA_VCUTM LEVEL_AREA_INDEX(LEVEL_VCUTM, 1)
#define AREA_BITFS LEVEL_AREA_INDEX(LEVEL_BITFS, 1)
#define AREA_SA LEVEL_AREA_INDEX(LEVEL_SA, 1)
#define AREA_BITS LEVEL_AREA_INDEX(LEVEL_BITS, 1)
#define AREA_LLL_OUTSIDE LEVEL_AREA_INDEX(LEVEL_LLL, 1)
#define AREA_LLL_VOLCANO LEVEL_AREA_INDEX(LEVEL_LLL, 2)
#define AREA_DDD_WHIRLPOOL LEVEL_AREA_INDEX(LEVEL_DDD, 1)
#define AREA_DDD_SUB LEVEL_AREA_INDEX(LEVEL_DDD, 2)
#define AREA_WF LEVEL_AREA_INDEX(LEVEL_WF, 1)
#define AREA_ENDING LEVEL_AREA_INDEX(LEVEL_ENDING, 1)
#define AREA_COURTYARD LEVEL_AREA_INDEX(LEVEL_CASTLE_COURTYARD, 1)
#define AREA_PSS LEVEL_AREA_INDEX(LEVEL_PSS, 1)
#define AREA_COTMC LEVEL_AREA_INDEX(LEVEL_COTMC, 1)
#define AREA_TOTWC LEVEL_AREA_INDEX(LEVEL_TOTWC, 1)
#define AREA_BOWSER_1 LEVEL_AREA_INDEX(LEVEL_BOWSER_1, 1)
#define AREA_WMOTR LEVEL_AREA_INDEX(LEVEL_WMOTR, 1)
#define AREA_BOWSER_2 LEVEL_AREA_INDEX(LEVEL_BOWSER_2, 1)
#define AREA_BOWSER_3 LEVEL_AREA_INDEX(LEVEL_BOWSER_3, 1)
#define AREA_TTM_OUTSIDE LEVEL_AREA_INDEX(LEVEL_TTM, 1)
#define CAM_MODE_MARIO_ACTIVE 0x01
#define CAM_MODE_LAKITU_WAS_ZOOMED_OUT 0x02
#define CAM_MODE_MARIO_SELECTED 0x04
#define CAM_SELECTION_MARIO 1
#define CAM_SELECTION_FIXED 2
#define CAM_ANGLE_MARIO 1
#define CAM_ANGLE_LAKITU 2
#define CAMERA_MODE_NONE 0x00
#define CAMERA_MODE_RADIAL 0x01
#define CAMERA_MODE_OUTWARD_RADIAL 0x02
#define CAMERA_MODE_BEHIND_MARIO 0x03
#define CAMERA_MODE_CLOSE 0x04 // Inside Castle / Big Boo's Haunt
#define CAMERA_MODE_C_UP 0x06
#define CAMERA_MODE_WATER_SURFACE 0x08
#define CAMERA_MODE_SLIDE_HOOT 0x09
#define CAMERA_MODE_INSIDE_CANNON 0x0A
#define CAMERA_MODE_BOSS_FIGHT 0x0B
#define CAMERA_MODE_PARALLEL_TRACKING 0x0C
#define CAMERA_MODE_FIXED 0x0D
#define CAMERA_MODE_8_DIRECTIONS 0x0E // AKA Parallel Camera, Bowser Courses & Rainbow Ride
#define CAMERA_MODE_FREE_ROAM 0x10
#define CAMERA_MODE_SPIRAL_STAIRS 0x11
#define CAM_MOVE_RETURN_TO_MIDDLE 0x0001
#define CAM_MOVE_ZOOMED_OUT 0x0002
#define CAM_MOVE_ROTATE_RIGHT 0x0004
#define CAM_MOVE_ROTATE_LEFT 0x0008
#define CAM_MOVE_ENTERED_ROTATE_SURFACE 0x0010
#define CAM_MOVE_METAL_BELOW_WATER 0x0020
#define CAM_MOVE_FIX_IN_PLACE 0x0040
#define CAM_MOVE_UNKNOWN_8 0x0080
#define CAM_MOVING_INTO_MODE 0x0100
#define CAM_MOVE_STARTED_EXITING_C_UP 0x0200
#define CAM_MOVE_UNKNOWN_11 0x0400
#define CAM_MOVE_INIT_CAMERA 0x0800
#define CAM_MOVE_ALREADY_ZOOMED_OUT 0x1000
#define CAM_MOVE_C_UP_MODE 0x2000
#define CAM_MOVE_SUBMERGED 0x4000
#define CAM_MOVE_PAUSE_SCREEN 0x8000
#define CAM_MOVE_ROTATE /**/ (CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ROTATE_LEFT | CAM_MOVE_RETURN_TO_MIDDLE)
/// These flags force the camera to move a certain way
#define CAM_MOVE_RESTRICT /**/ (CAM_MOVE_ENTERED_ROTATE_SURFACE | CAM_MOVE_METAL_BELOW_WATER | CAM_MOVE_FIX_IN_PLACE | CAM_MOVE_UNKNOWN_8)
#define CAM_SOUND_C_UP_PLAYED 0x01
#define CAM_SOUND_MARIO_ACTIVE 0x02
#define CAM_SOUND_NORMAL_ACTIVE 0x04
#define CAM_SOUND_UNUSED_SELECT_MARIO 0x08
#define CAM_SOUND_UNUSED_SELECT_FIXED 0x10
#define CAM_SOUND_FIXED_ACTIVE 0x20
#define CAM_FLAG_SMOOTH_MOVEMENT 0x0001
#define CAM_FLAG_BLOCK_SMOOTH_MOVEMENT 0x0002
#define CAM_FLAG_FRAME_AFTER_CAM_INIT 0x0004
#define CAM_FLAG_CHANGED_PARTRACK_INDEX 0x0008
#define CAM_FLAG_CCM_SLIDE_SHORTCUT 0x0010
#define CAM_FLAG_CAM_NEAR_WALL 0x0020
#define CAM_FLAG_SLEEPING 0x0040
#define CAM_FLAG_UNUSED_7 0x0080
#define CAM_FLAG_UNUSED_8 0x0100
#define CAM_FLAG_COLLIDED_WITH_WALL 0x0200
#define CAM_FLAG_START_TRANSITION 0x0400
#define CAM_FLAG_TRANSITION_OUT_OF_C_UP 0x0800
#define CAM_FLAG_BLOCK_AREA_PROCESSING 0x1000
#define CAM_FLAG_UNUSED_13 0x2000
#define CAM_FLAG_UNUSED_CUTSCENE_ACTIVE 0x4000
#define CAM_FLAG_BEHIND_MARIO_POST_DOOR 0x8000
#define CAM_STATUS_NONE 0
#define CAM_STATUS_MARIO 1 << 0
#define CAM_STATUS_LAKITU 1 << 1
#define CAM_STATUS_FIXED 1 << 2
#define CAM_STATUS_C_DOWN 1 << 3
#define CAM_STATUS_C_UP 1 << 4
#define CAM_STATUS_MODE_GROUP (CAM_STATUS_MARIO | CAM_STATUS_LAKITU | CAM_STATUS_FIXED)
#define CAM_STATUS_C_MODE_GROUP (CAM_STATUS_C_DOWN | CAM_STATUS_C_UP)
#define SHAKE_ATTACK 1
#define SHAKE_GROUND_POUND 2
#define SHAKE_SMALL_DAMAGE 3
#define SHAKE_MED_DAMAGE 4
#define SHAKE_LARGE_DAMAGE 5
#define SHAKE_HIT_FROM_BELOW 8
#define SHAKE_FALL_DAMAGE 9
#define SHAKE_SHOCK 10
#define SHAKE_ENV_EXPLOSION 1
#define SHAKE_ENV_BOWSER_THROW_BOUNCE 2
#define SHAKE_ENV_BOWSER_JUMP 3
#define SHAKE_ENV_UNUSED_5 5
#define SHAKE_ENV_UNUSED_6 6
#define SHAKE_ENV_UNUSED_7 7
#define SHAKE_ENV_PYRAMID_EXPLODE 8
#define SHAKE_ENV_JRB_SHIP_DRAIN 9
#define SHAKE_ENV_FALLING_BITS_PLAT 10
#define SHAKE_FOV_SMALL 1
#define SHAKE_FOV_UNUSED 2
#define SHAKE_FOV_MEDIUM 3
#define SHAKE_FOV_LARGE 4
#define SHAKE_POS_SMALL 1
#define SHAKE_POS_MEDIUM 2
#define SHAKE_POS_LARGE 3
#define SHAKE_POS_BOWLING_BALL 4
#define CUTSCENE_DOOR_PULL 130
#define CUTSCENE_DOOR_PUSH 131
#define CUTSCENE_ENTER_CANNON 133
#define CUTSCENE_ENTER_PAINTING 134
#define CUTSCENE_DEATH_EXIT 135
#define CUTSCENE_DOOR_WARP 139
#define CUTSCENE_DOOR_PULL_MODE 140
#define CUTSCENE_DOOR_PUSH_MODE 141
#define CUTSCENE_INTRO_PEACH 142
#define CUTSCENE_DANCE_ROTATE 143
#define CUTSCENE_ENTER_BOWSER_ARENA 144
#define CUTSCENE_0F_UNUSED 145 // Never activated, stub cutscene functions
#define CUTSCENE_UNUSED_EXIT 147 // Never activated
#define CUTSCENE_SLIDING_DOORS_OPEN 149
#define CUTSCENE_PREPARE_CANNON 150
#define CUTSCENE_UNLOCK_KEY_DOOR 151
#define CUTSCENE_STANDING_DEATH 152
#define CUTSCENE_DEATH_ON_STOMACH 153
#define CUTSCENE_DEATH_ON_BACK 154
#define CUTSCENE_QUICKSAND_DEATH 155
#define CUTSCENE_SUFFOCATION_DEATH 156
#define CUTSCENE_EXIT_BOWSER_SUCC 157
#define CUTSCENE_EXIT_BOWSER_DEATH 158 // Never activated
#define CUTSCENE_WATER_DEATH 159 // Not in cutscene switch
#define CUTSCENE_EXIT_PAINTING_SUCC 160
#define CUTSCENE_CAP_SWITCH_PRESS 161
#define CUTSCENE_DIALOG 162
#define CUTSCENE_RACE_DIALOG 163
#define CUTSCENE_ENTER_PYRAMID_TOP 164
#define CUTSCENE_DANCE_FLY_AWAY 165
#define CUTSCENE_DANCE_CLOSEUP 166
#define CUTSCENE_KEY_DANCE 167
#define CUTSCENE_SSL_PYRAMID_EXPLODE 168 // Never activated
#define CUTSCENE_EXIT_SPECIAL_SUCC 169
#define CUTSCENE_NONPAINTING_DEATH 170
#define CUTSCENE_READ_MESSAGE 171
#define CUTSCENE_ENDING 172
#define CUTSCENE_STAR_SPAWN 173
#define CUTSCENE_GRAND_STAR 174
#define CUTSCENE_DANCE_DEFAULT 175
#define CUTSCENE_RED_COIN_STAR_SPAWN 176
#define CUTSCENE_END_WAVING 177
#define CUTSCENE_CREDITS 178
#define CUTSCENE_EXIT_WATERFALL 179
#define CUTSCENE_EXIT_FALL_WMOTR 180
#define CUTSCENE_ENTER_POOL 181
/**
* Stop the cutscene.
*/
#define CUTSCENE_STOP 0x8000
/**
* Play the current cutscene shot indefinitely (until canceled).
*/
#define CUTSCENE_LOOP 0x7FFF
#define HAND_CAM_SHAKE_OFF 0
#define HAND_CAM_SHAKE_CUTSCENE 1
#define HAND_CAM_SHAKE_UNUSED 2
#define HAND_CAM_SHAKE_HANG_OWL 3
#define HAND_CAM_SHAKE_HIGH 4
#define HAND_CAM_SHAKE_STAR_DANCE 5
#define HAND_CAM_SHAKE_LOW 6
#define DOOR_DEFAULT 0
#define DOOR_LEAVING_SPECIAL 1
#define DOOR_ENTER_LOBBY 2
// Might rename these to reflect what they are used for instead "SET_45" etc.
#define CAM_FOV_SET_45 1
#define CAM_FOV_DEFAULT 2
#define CAM_FOV_APP_45 4
#define CAM_FOV_SET_30 5
#define CAM_FOV_APP_20 6
#define CAM_FOV_BBH 7
#define CAM_FOV_APP_80 9
#define CAM_FOV_APP_30 10
#define CAM_FOV_APP_60 11
#define CAM_FOV_ZOOM_30 12
#define CAM_FOV_SET_29 13
#define CAM_EVENT_CANNON 1
#define CAM_EVENT_SHOT_FROM_CANNON 2
#define CAM_EVENT_UNUSED_3 3
#define CAM_EVENT_BOWSER_INIT 4
#define CAM_EVENT_DOOR_WARP 5
#define CAM_EVENT_DOOR 6
#define CAM_EVENT_BOWSER_JUMP 7
#define CAM_EVENT_BOWSER_THROW_BOUNCE 8
#define CAM_EVENT_START_INTRO 9
#define CAM_EVENT_START_GRAND_STAR 10
#define CAM_EVENT_START_ENDING 11
#define CAM_EVENT_START_END_WAVING 12
#define CAM_EVENT_START_CREDITS 13
/**
* A copy of player information that is relevant to the camera.
*/
struct PlayerCameraState
{
/**
* Mario's action on this frame.
*/
/*0x00*/ u32 action;
/*0x04*/ Vec3f pos;
/*0x10*/ Vec3s faceAngle;
/*0x16*/ Vec3s headRotation;
/*0x1C*/ s16 unused;
/**
* Set to nonzero when an event, such as entering a door, starting the credits, or throwing bowser,
* has happened on this frame.
*/
/*0x1E*/ s16 cameraEvent;
/*0x20*/ struct Object *usedObj;
};
/**
* Struct containing info that is used when transition_next_state() is called. Stores the intermediate
* distances and angular displacements from lakitu's goal position and focus.
*/
struct TransitionInfo
{
/*0x00*/ s16 posPitch;
/*0x02*/ s16 posYaw;
/*0x04*/ f32 posDist;
/*0x08*/ s16 focPitch;
/*0x0A*/ s16 focYaw;
/*0x0C*/ f32 focDist;
/*0x10*/ s32 framesLeft;
/*0x14*/ Vec3f marioPos;
/*0x20*/ u8 pad; // for the structs to align, there has to be an extra unused variable here. type is unknown.
};
/**
* A point that's used in a spline, controls the direction to move the camera in
* during the shake effect.
*/
struct HandheldShakePoint
{
/*0x00*/ s8 index; // only set to -1
/*0x04 (aligned)*/ u32 pad;
/*0x08*/ Vec3s point;
}; // size = 0x10
struct Camera;
/**
* A function that is called by CameraTriggers and cutscene shots.
* These are concurrent: multiple CameraEvents can occur on the same frame.
*/
typedef BAD_RETURN(s32) (*CameraEvent)(struct Camera *c);
/**
* The same type as a CameraEvent, but because these are generally longer, and happen in sequential
* order, they're are called "shots," a term taken from cinematography.
*
* To further tell the difference: CutsceneShots usually call multiple CameraEvents at once, but only
* one CutsceneShot is ever called on a given frame.
*/
typedef CameraEvent CutsceneShot;
/**
* Defines a bounding box which activates an event while Mario is inside
*/
struct CameraTrigger
{
/**
* The area this should be checked in, or -1 if it should run in every area of the level.
*
* Triggers with area set to -1 are run by default, they don't care if Mario is inside their bounds.
* However, they are only active if Mario is not already inside an area-specific trigger's
* boundaries.
*/
s8 area;
/// A function that gets called while Mario is in the trigger bounds
CameraEvent event;
// The (x,y,z) position of the center of the bounding box
s16 centerX;
s16 centerY;
s16 centerZ;
// The max displacement in x, y, and z from the center for a point to be considered inside the
// bounding box
s16 boundsX;
s16 boundsY;
s16 boundsZ;
/// This angle rotates Mario's offset from the box's origin, before it is checked for being inside.
s16 boundsYaw;
};
/**
* A camera shot that is active for a number of frames.
* Together, a sequence of shots makes up a cutscene.
*/
struct Cutscene
{
/// The function that gets called.
CutsceneShot shot;
/// How long the shot lasts.
s16 duration;
};
/**
* Info for the camera's field of view and the FOV shake effect.
*/
struct CameraFOVStatus
{
/// The current function being used to set the camera's field of view (before any fov shake is applied).
/*0x00*/ u8 fovFunc;
/// The current field of view in degrees
/*0x04*/ f32 fov;
// Fields used by shake_camera_fov()
/// The amount to change the current fov by in the fov shake effect.
/*0x08*/ f32 fovOffset;
/// A bool set in fov_default() but unused otherwise
/*0x0C*/ u32 unusedIsSleeping;
/// The range in degrees to shake fov
/*0x10*/ f32 shakeAmplitude;
/// Used to calculate fovOffset, the phase through the shake's period.
/*0x14*/ s16 shakePhase;
/// How much to progress through the shake period
/*0x16*/ s16 shakeSpeed;
/// How much to decrease shakeAmplitude each frame.
/*0x18*/ s16 decay;
};
/**
* Information for a control point in a spline segment.
*/
struct CutsceneSplinePoint
{
/* The index of this point in the spline. Ignored except for -1, which ends the spline.
An index of -1 should come four points after the start of the last segment. */
s8 index;
/* Roughly controls the number of frames it takes to progress through the spline segment.
See move_point_along_spline() in camera.c */
u8 speed;
Vec3s point;
};
/**
* Struct containing the nearest floor and ceiling to the player, as well as the previous floor and
* ceiling. It also stores their distances from the player's position.
*/
struct PlayerGeometry
{
/*0x00*/ struct Surface *currFloor;
/*0x04*/ f32 currFloorHeight;
/*0x08*/ s16 currFloorType;
/*0x0C*/ struct Surface *currCeil;
/*0x10*/ s16 currCeilType;
/*0x14*/ f32 currCeilHeight;
/*0x18*/ struct Surface *prevFloor;
/*0x1C*/ f32 prevFloorHeight;
/*0x20*/ s16 prevFloorType;
/*0x24*/ struct Surface *prevCeil;
/*0x28*/ f32 prevCeilHeight;
/*0x2C*/ s16 prevCeilType;
/// Unused, but recalculated every frame
/*0x30*/ f32 waterHeight;
};
/**
* Point used in transitioning between camera modes and C-Up.
*/
struct LinearTransitionPoint
{
Vec3f focus;
Vec3f pos;
f32 dist;
s16 pitch;
s16 yaw;
};
/**
* Info about transitioning between camera modes.
*/
struct ModeTransitionInfo
{
s16 newMode;
s16 lastMode;
s16 max;
s16 frame;
struct LinearTransitionPoint transitionStart;
struct LinearTransitionPoint transitionEnd;
};
/**
* A point in a path used by update_parallel_tracking_camera
*/
struct ParallelTrackingPoint
{
/// Whether this point is the start of a path
s16 startOfPath;
/// Point used to define a line segment to follow
Vec3f pos;
/// The distance Mario can move along the line before the camera should move
f32 distThresh;
/// The percentage that the camera should move from the line to Mario
f32 zoom;
};
/**
* Stores the camera's info
*/
struct CameraStoredInfo
{
/*0x00*/ Vec3f pos;
/*0x0C*/ Vec3f focus;
/*0x18*/ f32 panDist;
/*0x1C*/ f32 cannonYOffset;
};
/**
* Struct used to store cutscene info, like the camera's target position/focus.
*
* See the sCutsceneVars[] array in camera.c for more details.
*/
struct CutsceneVariable
{
/// Perhaps an index
s32 unused1;
Vec3f point;
Vec3f unusedPoint;
Vec3s angle;
/// Perhaps a boolean or an extra angle
s16 unused2;
};
/**
* The main camera struct. Gets updated by the active camera mode and the current level/area. In
* update_lakitu, its pos and focus are used to calculate lakitu's next position and focus, which are
* then used to render the game.
*/
struct Camera
{
/*0x00*/ u8 mode; // What type of mode the camera uses (see defines above)
/*0x01*/ u8 defMode;
/**
* Determines what direction Mario moves in when the analog stick is moved.
*
* @warning This is NOT the camera's xz-rotation in world space. This is the angle calculated from the
* camera's focus TO the camera's position, instead of the other way around like it should
* be. It's effectively the opposite of the camera's actual yaw. Use
* vec3f_get_dist_and_angle() if you need the camera's yaw.
*/
/*0x02*/ s16 yaw;
/*0x04*/ Vec3f focus;
/*0x10*/ Vec3f pos;
/*0x1C*/ Vec3f unusedVec1;
/// The x coordinate of the "center" of the area. The camera will rotate around this point.
/// For example, this is what makes the camera rotate around the hill in BoB
/*0x28*/ f32 areaCenX;
/// The z coordinate of the "center" of the area. The camera will rotate around this point.
/// For example, this is what makes the camera rotate around the hill in BoB
/*0x2C*/ f32 areaCenZ;
/*0x30*/ u8 cutscene;
/*0x31*/ u8 filler31[0x8];
/*0x3A*/ s16 nextYaw;
/*0x3C*/ u8 filler3C[0x28];
/*0x64*/ u8 doorStatus;
/// The y coordinate of the "center" of the area. Unlike areaCenX and areaCenZ, this is only used
/// when paused. See zoom_out_if_paused_and_outside
/*0x68*/ f32 areaCenY;
};
/**
* A struct containing info pertaining to lakitu, such as his position and focus, and what
* camera-related effects are happening to him, like camera shakes.
*
* This struct's pos and focus are what is actually used to render the game.
*
* @see update_lakitu()
*/
struct LakituState
{
/**
* Lakitu's position, which (when CAM_FLAG_SMOOTH_MOVEMENT is set), approaches his goalPos every frame.
*/
/*0x00*/ Vec3f curFocus;
/**
* Lakitu's focus, which (when CAM_FLAG_SMOOTH_MOVEMENT is set), approaches his goalFocus every frame.
*/
/*0x0C*/ Vec3f curPos;
/**
* The focus point that lakitu turns towards every frame.
* If CAM_FLAG_SMOOTH_MOVEMENT is unset, this is the same as curFocus.
*/
/*0x18*/ Vec3f goalFocus;
/**
* The point that lakitu flies towards every frame.
* If CAM_FLAG_SMOOTH_MOVEMENT is unset, this is the same as curPos.
*/
/*0x24*/ Vec3f goalPos;
/*0x30*/ u8 filler30[12]; // extra unused Vec3f?
/// Copy of the active camera mode
/*0x3C*/ u8 mode;
/// Copy of the default camera mode
/*0x3D*/ u8 defMode;
/*0x3E*/ u8 filler3E[10];
/*0x48*/ f32 focusDistance; // unused
/*0x4C*/ s16 oldPitch; // unused
/*0x4E*/ s16 oldYaw; // unused
/*0x50*/ s16 oldRoll; // unused
/// The angular offsets added to lakitu's pitch, yaw, and roll
/*0x52*/ Vec3s shakeMagnitude;
// shake pitch, yaw, and roll phase: The progression through the camera shake (a cosine wave).
// shake pitch, yaw, and roll vel: The speed of the camera shake.
// shake pitch, yaw, and roll decay: The shake's deceleration.
/*0x58*/ s16 shakePitchPhase;
/*0x5A*/ s16 shakePitchVel;
/*0x5C*/ s16 shakePitchDecay;
/*0x60*/ Vec3f unusedVec1;
/*0x6C*/ Vec3s unusedVec2;
/*0x72*/ u8 filler72[8];
/// Used to rotate the screen when rendering.
/*0x7A*/ s16 roll;
/// Copy of the camera's yaw.
/*0x7C*/ s16 yaw;
/// Copy of the camera's next yaw.
/*0x7E*/ s16 nextYaw;
/// The actual focus point the game uses to render.
/*0x80*/ Vec3f focus;
/// The actual position the game is rendered from.
/*0x8C*/ Vec3f pos;
// Shake variables: See above description
/*0x98*/ s16 shakeRollPhase;
/*0x9A*/ s16 shakeRollVel;
/*0x9C*/ s16 shakeRollDecay;
/*0x9E*/ s16 shakeYawPhase;
/*0xA0*/ s16 shakeYawVel;
/*0xA2*/ s16 shakeYawDecay;
// focH,Vspeed: how fast lakitu turns towards his goalFocus.
/// By default HSpeed is 0.8, so lakitu turns 80% of the horz distance to his goal each frame.
/*0xA4*/ f32 focHSpeed;
/// By default VSpeed is 0.3, so lakitu turns 30% of the vert distance to his goal each frame.
/*0xA8*/ f32 focVSpeed;
// posH,Vspeed: How fast lakitu flies towards his goalPos.
/// By default they are 0.3, so lakitu will fly 30% of the way towards his goal each frame.
/*0xAC*/ f32 posHSpeed;
/*0xB0*/ f32 posVSpeed;
/// The roll offset applied during part of the key dance cutscene
/*0xB4*/ s16 keyDanceRoll;
/// Mario's action from the previous frame. Only used to determine if Mario just finished a dive.
/*0xB8*/ u32 lastFrameAction;
/*0xBC*/ s16 unused;
};
// // bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise
// #ifndef INCLUDED_FROM_CAMERA_C
// // BSS
// extern s16 sSelectionFlags;
// extern s16 sCameraSoundFlags;
// extern u16 sCButtonsPressed;
// extern struct PlayerCameraState gPlayerCameraState[2];
// extern struct LakituState gLakituState;
// extern s16 gCameraMovementFlags;
// extern s32 gObjCutsceneDone;
// extern struct Camera *gCamera;
// #endif
//
// extern struct Object *gCutsceneFocus;
// extern struct Object *gSecondCameraFocus;
// extern u8 gRecentCutscene;
//
// // TODO: sort all of this extremely messy shit out after the split
//
// void set_camera_shake_from_hit(s16 shake);
// void set_environmental_camera_shake(s16 shake);
// void set_camera_shake_from_point(s16 shake, f32 posX, f32 posY, f32 posZ);
// void move_mario_head_c_up(UNUSED struct Camera *c);
// void transition_next_state(UNUSED struct Camera *c, s16 frames);
// void set_camera_mode(struct Camera *c, s16 mode, s16 frames);
// void update_camera(struct Camera *c);
// void reset_camera(struct Camera *c);
// void init_camera(struct Camera *c);
// void select_mario_cam_mode(void);
// Gfx *geo_camera_main(s32 callContext, struct GraphNode *g, void *context);
// void stub_camera_2(UNUSED struct Camera *c);
// void stub_camera_3(UNUSED struct Camera *c);
// void vec3f_sub(Vec3f dst, Vec3f src);
// void object_pos_to_vec3f(Vec3f dst, struct Object *o);
// void vec3f_to_object_pos(struct Object *o, Vec3f src);
// s32 move_point_along_spline(Vec3f p, struct CutsceneSplinePoint spline[], s16 *splineSegment, f32 *progress);
// s32 cam_select_alt_mode(s32 angle);
// s32 set_cam_angle(s32 mode);
// void set_handheld_shake(u8 mode);
// void shake_camera_handheld(Vec3f pos, Vec3f focus);
// s32 find_c_buttons_pressed(u16 currentState, u16 buttonsPressed, u16 buttonsDown);
// s32 update_camera_hud_status(struct Camera *c);
// s32 collide_with_walls(Vec3f pos, f32 offsetY, f32 radius);
// s32 clamp_pitch(Vec3f from, Vec3f to, s16 maxPitch, s16 minPitch);
// s32 is_within_100_units_of_mario(f32 posX, f32 posY, f32 posZ);
// s32 set_or_approach_f32_asymptotic(f32 *dst, f32 goal, f32 scale);
// s32 approach_f32_asymptotic_bool(f32 *current, f32 target, f32 multiplier);
// f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier);
// s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor);
// s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor);
// void approach_vec3f_asymptotic(Vec3f current, Vec3f target, f32 xMul, f32 yMul, f32 zMul);
// void set_or_approach_vec3f_asymptotic(Vec3f dst, Vec3f goal, f32 xMul, f32 yMul, f32 zMul);
// s32 camera_approach_s16_symmetric_bool(s16 *current, s16 target, s16 increment);
// s32 set_or_approach_s16_symmetric(s16 *current, s16 target, s16 increment);
// s32 camera_approach_f32_symmetric_bool(f32 *current, f32 target, f32 increment);
// f32 camera_approach_f32_symmetric(f32 value, f32 target, f32 increment);
// void random_vec3s(Vec3s dst, s16 xRange, s16 yRange, s16 zRange);
// s32 clamp_positions_and_find_yaw(Vec3f pos, Vec3f origin, f32 xMax, f32 xMin, f32 zMax, f32 zMin);
// s32 is_range_behind_surface(Vec3f from, Vec3f to, struct Surface *surf, s16 range, s16 surfType);
// void scale_along_line(Vec3f dest, Vec3f from, Vec3f to, f32 scale);
// s16 calculate_pitch(Vec3f from, Vec3f to);
// s16 calculate_yaw(Vec3f from, Vec3f to);
// void calculate_angles(Vec3f from, Vec3f to, s16 *pitch, s16 *yaw);
// f32 calc_abs_dist(Vec3f a, Vec3f b);
// f32 calc_hor_dist(Vec3f a, Vec3f b);
// void rotate_in_xz(Vec3f dst, Vec3f src, s16 yaw);
// void rotate_in_yz(Vec3f dst, Vec3f src, s16 pitch);
// void set_camera_pitch_shake(s16 mag, s16 decay, s16 inc);
// void set_camera_yaw_shake(s16 mag, s16 decay, s16 inc);
// void set_camera_roll_shake(s16 mag, s16 decay, s16 inc);
// void set_pitch_shake_from_point(s16 mag, s16 decay, s16 inc, f32 maxDist, f32 posX, f32 posY, f32 posZ);
// void shake_camera_pitch(Vec3f pos, Vec3f focus);
// void shake_camera_yaw(Vec3f pos, Vec3f focus);
// void shake_camera_roll(s16 *roll);
// s32 offset_yaw_outward_radial(struct Camera *c, s16 areaYaw);
// void play_camera_buzz_if_cdown(void);
// void play_camera_buzz_if_cbutton(void);
// void play_camera_buzz_if_c_sideways(void);
// void play_sound_cbutton_up(void);
// void play_sound_cbutton_down(void);
// void play_sound_cbutton_side(void);
// void play_sound_button_change_blocked(void);
// void play_sound_rbutton_changed(void);
// void play_sound_if_cam_switched_to_lakitu_or_mario(void);
// s32 radial_camera_input(struct Camera *c, UNUSED f32 unused);
// s32 trigger_cutscene_dialog(s32 trigger);
// void handle_c_button_movement(struct Camera *c);
// void start_cutscene(struct Camera *c, u8 cutscene);
// u8 get_cutscene_from_mario_status(struct Camera *c);
// void warp_camera(f32 displacementX, f32 displacementY, f32 displacementZ);
// void approach_camera_height(struct Camera *c, f32 goal, f32 inc);
// void offset_rotated(Vec3f dst, Vec3f from, Vec3f to, Vec3s rotation);
// s16 next_lakitu_state(Vec3f newPos, Vec3f newFoc, Vec3f curPos, Vec3f curFoc, Vec3f oldPos, Vec3f oldFoc, s16 yaw);
// void set_fixed_cam_axis_sa_lobby(UNUSED s16 preset);
// s16 camera_course_processing(struct Camera *c);
// void resolve_geometry_collisions(Vec3f pos, UNUSED Vec3f lastGood);
// s32 rotate_camera_around_walls(struct Camera *c, Vec3f cPos, s16 *avoidYaw, s16 yawRange);
// void find_mario_floor_and_ceil(struct PlayerGeometry *pg);
// u8 start_object_cutscene_without_focus(u8 cutscene);
// s16 cutscene_object_with_dialog(u8 cutscene, struct Object *o, s16 dialogID);
// s16 cutscene_object_without_dialog(u8 cutscene, struct Object *o);
// s16 cutscene_object(u8 cutscene, struct Object *o);
// void play_cutscene(struct Camera *c);
// s32 cutscene_event(CameraEvent event, struct Camera * c, s16 start, s16 end);
// s32 cutscene_spawn_obj(u32 obj, s16 frame);
// void set_fov_shake(s16 amplitude, s16 decay, s16 shakeSpeed);
//
// void set_fov_function(u8 func);
// void cutscene_set_fov_shake_preset(u8 preset);
// void set_fov_shake_from_point_preset(u8 preset, f32 posX, f32 posY, f32 posZ);
// void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 yawOff, s16 pitchDiv, s16 yawDiv);
//
// Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context);
//
#endif // CAMERA_H
+928
View File
@@ -0,0 +1,928 @@
// HEAVILY EDITED === Specific interaction functions removed
#include <math.h>
#include "../include/PR/ultratypes.h"
#include "../shim.h"
#include "area.h"
//#include "actors/common1.h"
//#include "audio/external.h"
//#include "behavior_actions.h"
//#include "behavior_data.h"
#include "camera.h"
//#include "course_table.h"
//#include "dialog_ids.h"
#include "../engine/math_util.h"
#include "../engine/surface_collision.h"
//#include "game_init.h"
#include "interaction.h"
#include "level_update.h"
#include "mario.h"
#include "mario_step.h"
#include "memory.h"
//#include "obj_behaviors.h"
//#include "object_helpers.h"
#include "save_file.h"
//#include "seq_ids.h"
#include "../include/sm64.h"
//#include "sound_init.h"
//#include "thread6.h"
#include "../include/mario_animation_ids.h"
#include "../include/object_fields.h"
#include "../include/mario_geo_switch_case_ids.h"
#define INT_GROUND_POUND_OR_TWIRL (1 << 0) // 0x01
#define INT_PUNCH (1 << 1) // 0x02
#define INT_KICK (1 << 2) // 0x04
#define INT_TRIP (1 << 3) // 0x08
#define INT_SLIDE_KICK (1 << 4) // 0x10
#define INT_FAST_ATTACK_OR_SHELL (1 << 5) // 0x20
#define INT_HIT_FROM_ABOVE (1 << 6) // 0x40
#define INT_HIT_FROM_BELOW (1 << 7) // 0x80
#define INT_ATTACK_NOT_FROM_BELOW \
(INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \
| INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE)
#define INT_ANY_ATTACK \
(INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \
| INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE | INT_HIT_FROM_BELOW)
#define INT_ATTACK_NOT_WEAK_FROM_ABOVE \
(INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_HIT_FROM_BELOW)
u8 sDelayInvincTimer;
s16 sInvulnerable;
struct InteractionHandler {
u32 interactType;
u32 (*handler)(struct MarioState *, u32, struct Object *);
};
static struct InteractionHandler sInteractionHandlers[] = { };
static u32 sForwardKnockbackActions[][3] = {
{ ACT_SOFT_FORWARD_GROUND_KB, ACT_FORWARD_GROUND_KB, ACT_HARD_FORWARD_GROUND_KB },
{ ACT_FORWARD_AIR_KB, ACT_FORWARD_AIR_KB, ACT_HARD_FORWARD_AIR_KB },
{ ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB },
};
static u32 sBackwardKnockbackActions[][3] = {
{ ACT_SOFT_BACKWARD_GROUND_KB, ACT_BACKWARD_GROUND_KB, ACT_HARD_BACKWARD_GROUND_KB },
{ ACT_BACKWARD_AIR_KB, ACT_BACKWARD_AIR_KB, ACT_HARD_BACKWARD_AIR_KB },
{ ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB },
};
static u8 sDisplayingDoorText = FALSE;
static u8 sJustTeleported = FALSE;
static u8 sPssSlideStarted = FALSE;
/**
* Returns the type of cap Mario is wearing.
*/
u32 get_mario_cap_flag(struct Object *capObject) {
return MARIO_NORMAL_CAP;
// const BehaviorScript *script = virtual_to_segmented(0x13, capObject->behavior);
// if (script == bhvNormalCap) {
// return MARIO_NORMAL_CAP;
// } else if (script == bhvMetalCap) {
// return MARIO_METAL_CAP;
// } else if (script == bhvWingCap) {
// return MARIO_WING_CAP;
// } else if (script == bhvVanishCap) {
// return MARIO_VANISH_CAP;
// }
return 0;
}
/**
* Returns true if the passed in object has a moving angle yaw
* in the angular range given towards Mario.
*/
u32 object_facing_mario(struct MarioState *m, struct Object *o, s16 angleRange) {
f32 dx = m->pos[0] - o->oPosX;
f32 dz = m->pos[2] - o->oPosZ;
s16 angleToMario = atan2s(dz, dx);
s16 dAngle = angleToMario - o->oMoveAngleYaw;
if (-angleRange <= dAngle && dAngle <= angleRange) {
return TRUE;
}
return FALSE;
}
s16 mario_obj_angle_to_object(struct MarioState *m, struct Object *o) {
f32 dx = o->oPosX - m->pos[0];
f32 dz = o->oPosZ - m->pos[2];
return atan2s(dz, dx);
}
/**
* Determines Mario's interaction with a given object depending on their proximity,
* action, speed, and position.
*/
u32 determine_interaction(struct MarioState *m, struct Object *o) {
u32 interaction = 0;
u32 action = m->action;
if (action & ACT_FLAG_ATTACKING) {
if (action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) {
s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1];
if (m->flags & MARIO_PUNCHING) {
// 120 degrees total, or 60 each way
if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) {
interaction = INT_PUNCH;
}
}
if (m->flags & MARIO_KICKING) {
// 120 degrees total, or 60 each way
if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) {
interaction = INT_KICK;
}
}
if (m->flags & MARIO_TRIPPING) {
// 180 degrees total, or 90 each way
if (-0x4000 <= dYawToObject && dYawToObject <= 0x4000) {
interaction = INT_TRIP;
}
}
} else if (action == ACT_GROUND_POUND || action == ACT_TWIRLING) {
if (m->vel[1] < 0.0f) {
interaction = INT_GROUND_POUND_OR_TWIRL;
}
} else if (action == ACT_GROUND_POUND_LAND || action == ACT_TWIRL_LAND) {
// Neither ground pounding nor twirling change Mario's vertical speed on landing.,
// so the speed check is nearly always true (perhaps not if you land while going upwards?)
// Additionally, actionState it set on each first thing in their action, so this is
// only true prior to the very first frame (i.e. active 1 frame prior to it run).
if (m->vel[1] < 0.0f && m->actionState == 0) {
interaction = INT_GROUND_POUND_OR_TWIRL;
}
} else if (action == ACT_SLIDE_KICK || action == ACT_SLIDE_KICK_SLIDE) {
interaction = INT_SLIDE_KICK;
} else if (action & ACT_FLAG_RIDING_SHELL) {
interaction = INT_FAST_ATTACK_OR_SHELL;
} else if (m->forwardVel <= -26.0f || 26.0f <= m->forwardVel) {
interaction = INT_FAST_ATTACK_OR_SHELL;
}
}
// Prior to this, the interaction type could be overwritten. This requires, however,
// that the interaction not be set prior. This specifically overrides turning a ground
// pound into just a bounce.
if (interaction == 0 && (action & ACT_FLAG_AIR)) {
if (m->vel[1] < 0.0f) {
if (m->pos[1] > o->oPosY) {
interaction = INT_HIT_FROM_ABOVE;
}
} else {
if (m->pos[1] < o->oPosY) {
interaction = INT_HIT_FROM_BELOW;
}
}
}
return interaction;
}
/**
* Sets the interaction types for INT_STATUS_INTERACTED, INT_STATUS_WAS_ATTACKED
*/
u32 attack_object(struct Object *o, s32 interaction) {
u32 attackType = 0;
switch (interaction) {
case INT_GROUND_POUND_OR_TWIRL:
attackType = ATTACK_GROUND_POUND_OR_TWIRL;
break;
case INT_PUNCH:
attackType = ATTACK_PUNCH;
break;
case INT_KICK:
case INT_TRIP:
attackType = ATTACK_KICK_OR_TRIP;
break;
case INT_SLIDE_KICK:
case INT_FAST_ATTACK_OR_SHELL:
attackType = ATTACK_FAST_ATTACK;
break;
case INT_HIT_FROM_ABOVE:
attackType = ATTACK_FROM_ABOVE;
break;
case INT_HIT_FROM_BELOW:
attackType = ATTACK_FROM_BELOW;
break;
}
o->oInteractStatus = attackType + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED);
return attackType;
}
void mario_stop_riding_object(struct MarioState *m) {
if (m->riddenObj != NULL) {
m->riddenObj->oInteractStatus = INT_STATUS_STOP_RIDING;
stop_shell_music();
m->riddenObj = NULL;
}
}
void mario_grab_used_object(struct MarioState *m) {
if (m->heldObj == NULL) {
m->heldObj = m->usedObj;
// obj_set_held_state(m->heldObj, bhvCarrySomething3);
}
}
void mario_drop_held_object(struct MarioState *m) {
if (m->heldObj != NULL) {
// if (m->heldObj->behavior == segmented_to_virtual(bhvKoopaShellUnderwater)) {
// stop_shell_music();
// }
// obj_set_held_state(m->heldObj, bhvCarrySomething4);
// ! When dropping an object instead of throwing it, it will be put at Mario's
// y-positon instead of the HOLP's y-position. This fact is often exploited when
// cloning objects.
m->heldObj->oPosX = m->marioBodyState->heldObjLastPosition[0];
m->heldObj->oPosY = m->pos[1];
m->heldObj->oPosZ = m->marioBodyState->heldObjLastPosition[2];
m->heldObj->oMoveAngleYaw = m->faceAngle[1];
m->heldObj = NULL;
}
}
void mario_throw_held_object(struct MarioState *m) {
if (m->heldObj != NULL) {
// if (m->heldObj->behavior == segmented_to_virtual(bhvKoopaShellUnderwater)) {
// stop_shell_music();
// }
// obj_set_held_state(m->heldObj, bhvCarrySomething5);
m->heldObj->oPosX = m->marioBodyState->heldObjLastPosition[0] + 32.0f * sins(m->faceAngle[1]);
m->heldObj->oPosY = m->marioBodyState->heldObjLastPosition[1];
m->heldObj->oPosZ = m->marioBodyState->heldObjLastPosition[2] + 32.0f * coss(m->faceAngle[1]);
m->heldObj->oMoveAngleYaw = m->faceAngle[1];
m->heldObj = NULL;
}
}
void mario_stop_riding_and_holding(struct MarioState *m) {
mario_drop_held_object(m);
mario_stop_riding_object(m);
if (m->action == ACT_RIDING_HOOT) {
m->usedObj->oInteractStatus = 0;
m->usedObj->oHootMarioReleaseTime = gGlobalTimer;
}
}
u32 does_mario_have_normal_cap_on_head(struct MarioState *m) {
return (m->flags & (MARIO_CAPS | MARIO_CAP_ON_HEAD)) == (MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD);
}
void mario_blow_off_cap(struct MarioState *m, f32 capSpeed) {
// struct Object *capObject;
// if (does_mario_have_normal_cap_on_head(m)) {
// save_file_set_cap_pos(m->pos[0], m->pos[1], m->pos[2]);
// m->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD);
// capObject = spawn_object(m->marioObj, MODEL_MARIOS_CAP, bhvNormalCap);
// capObject->oPosY += (m->action & ACT_FLAG_SHORT_HITBOX) ? 120.0f : 180.0f;
// capObject->oForwardVel = capSpeed;
// capObject->oMoveAngleYaw = (s16)(m->faceAngle[1] + 0x400);
// if (m->forwardVel < 0.0f) {
// capObject->oMoveAngleYaw = (s16)(capObject->oMoveAngleYaw + 0x8000);
// }
// }
}
u32 mario_lose_cap_to_enemy(u32 arg) {
u32 wasWearingCap = FALSE;
if (does_mario_have_normal_cap_on_head(gMarioState)) {
save_file_set_flags(arg == 1 ? SAVE_FLAG_CAP_ON_KLEPTO : SAVE_FLAG_CAP_ON_UKIKI);
gMarioState->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD);
wasWearingCap = TRUE;
}
return wasWearingCap;
}
void mario_retrieve_cap(void) {
mario_drop_held_object(gMarioState);
save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI);
gMarioState->flags &= ~MARIO_CAP_ON_HEAD;
gMarioState->flags |= MARIO_NORMAL_CAP | MARIO_CAP_IN_HAND;
}
u32 able_to_grab_object(struct MarioState *m, UNUSED struct Object *o) {
u32 action = m->action;
if (action == ACT_DIVE_SLIDE || action == ACT_DIVE) {
if (!(o->oInteractionSubtype & INT_SUBTYPE_GRABS_MARIO)) {
return TRUE;
}
} else if (action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING) {
if (m->actionArg < 2) {
return TRUE;
}
}
return FALSE;
}
struct Object *mario_get_collided_object(struct MarioState *m, u32 interactType) {
s32 i;
struct Object *object;
for (i = 0; i < m->marioObj->numCollidedObjs; i++) {
object = m->marioObj->collidedObjs[i];
if (object->oInteractType == interactType) {
return object;
}
}
return NULL;
}
u32 mario_check_object_grab(struct MarioState *m) {
u32 result = FALSE;
const BehaviorScript *script;
if (m->input & INPUT_INTERACT_OBJ_GRABBABLE) {
script = virtual_to_segmented(0x13, m->interactObj->behavior);
// if (script == bhvBowser) {
// s16 facingDYaw = m->faceAngle[1] - m->interactObj->oMoveAngleYaw;
// if (facingDYaw >= -0x5555 && facingDYaw <= 0x5555) {
// m->faceAngle[1] = m->interactObj->oMoveAngleYaw;
// m->usedObj = m->interactObj;
// result = set_mario_action(m, ACT_PICKING_UP_BOWSER, 0);
// }
// } else {
s16 facingDYaw = mario_obj_angle_to_object(m, m->interactObj) - m->faceAngle[1];
if (facingDYaw >= -0x2AAA && facingDYaw <= 0x2AAA) {
m->usedObj = m->interactObj;
if (!(m->action & ACT_FLAG_AIR)) {
set_mario_action(
m, (m->action & ACT_FLAG_DIVING) ? ACT_DIVE_PICKING_UP : ACT_PICKING_UP, 0);
}
result = TRUE;
}
// }
}
return result;
}
u32 bully_knock_back_mario(struct MarioState *mario) {
struct BullyCollisionData marioData;
struct BullyCollisionData bullyData;
s16 newMarioYaw;
s16 newBullyYaw;
s16 marioDYaw;
UNUSED s16 bullyDYaw;
u32 bonkAction = 0;
struct Object *bully = mario->interactObj;
//! Conversion ratios multiply to more than 1 (could allow unbounded speed
// with bonk cancel - but this isn't important for regular bully battery)
f32 bullyToMarioRatio = bully->hitboxRadius * 3 / 53;
f32 marioToBullyRatio = 53.0f / bully->hitboxRadius;
init_bully_collision_data(&marioData, mario->pos[0], mario->pos[2], mario->forwardVel,
mario->faceAngle[1], bullyToMarioRatio, 52.0f);
init_bully_collision_data(&bullyData, bully->oPosX, bully->oPosZ, bully->oForwardVel,
bully->oMoveAngleYaw, marioToBullyRatio, bully->hitboxRadius + 2.0f);
if (mario->forwardVel != 0.0f) {
transfer_bully_speed(&marioData, &bullyData);
} else {
transfer_bully_speed(&bullyData, &marioData);
}
newMarioYaw = atan2s(marioData.velZ, marioData.velX);
newBullyYaw = atan2s(bullyData.velZ, bullyData.velX);
marioDYaw = newMarioYaw - mario->faceAngle[1];
bullyDYaw = newBullyYaw - bully->oMoveAngleYaw;
mario->faceAngle[1] = newMarioYaw;
mario->forwardVel = sqrtf(marioData.velX * marioData.velX + marioData.velZ * marioData.velZ);
mario->pos[0] = marioData.posX;
mario->pos[2] = marioData.posZ;
bully->oMoveAngleYaw = newBullyYaw;
bully->oForwardVel = sqrtf(bullyData.velX * bullyData.velX + bullyData.velZ * bullyData.velZ);
bully->oPosX = bullyData.posX;
bully->oPosZ = bullyData.posZ;
if (marioDYaw < -0x4000 || marioDYaw > 0x4000) {
mario->faceAngle[1] += 0x8000;
mario->forwardVel *= -1.0f;
if (mario->action & ACT_FLAG_AIR) {
bonkAction = ACT_BACKWARD_AIR_KB;
} else {
bonkAction = ACT_SOFT_BACKWARD_GROUND_KB;
}
} else {
if (mario->action & ACT_FLAG_AIR) {
bonkAction = ACT_FORWARD_AIR_KB;
} else {
bonkAction = ACT_SOFT_FORWARD_GROUND_KB;
}
}
return bonkAction;
}
void bounce_off_object(struct MarioState *m, struct Object *o, f32 velY) {
m->pos[1] = o->oPosY + o->hitboxHeight;
m->vel[1] = velY;
m->flags &= ~MARIO_UNKNOWN_08;
play_sound(SOUND_ACTION_BOUNCE_OFF_OBJECT, m->marioObj->header.gfx.cameraToObject);
}
void hit_object_from_below(struct MarioState *m, UNUSED struct Object *o) {
m->vel[1] = 0.0f;
set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW);
}
static u32 unused_determine_knockback_action(struct MarioState *m) {
u32 bonkAction;
s16 angleToObject = mario_obj_angle_to_object(m, m->interactObj);
s16 facingDYaw = angleToObject - m->faceAngle[1];
if (m->forwardVel < 16.0f) {
m->forwardVel = 16.0f;
}
m->faceAngle[1] = angleToObject;
if (facingDYaw >= -0x4000 && facingDYaw <= 0x4000) {
m->forwardVel *= -1.0f;
if (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) {
bonkAction = ACT_BACKWARD_AIR_KB;
} else {
bonkAction = ACT_SOFT_BACKWARD_GROUND_KB;
}
} else {
m->faceAngle[1] += 0x8000;
if (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) {
bonkAction = ACT_FORWARD_AIR_KB;
} else {
bonkAction = ACT_SOFT_FORWARD_GROUND_KB;
}
}
return bonkAction;
}
u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) {
u32 bonkAction;
s16 terrainIndex = 0; // 1 = air, 2 = water, 0 = default
s16 strengthIndex = 0;
s16 angleToObject = mario_obj_angle_to_object(m, m->interactObj);
s16 facingDYaw = angleToObject - m->faceAngle[1];
s16 remainingHealth = m->health - 0x40 * m->hurtCounter;
if (m->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) {
terrainIndex = 2;
} else if (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) {
terrainIndex = 1;
}
if (remainingHealth < 0x100) {
strengthIndex = 2;
} else if (m->interactObj->oDamageOrCoinValue >= 4) {
strengthIndex = 2;
} else if (m->interactObj->oDamageOrCoinValue >= 2) {
strengthIndex = 1;
}
m->faceAngle[1] = angleToObject;
if (terrainIndex == 2) {
if (m->forwardVel < 28.0f) {
mario_set_forward_vel(m, 28.0f);
}
if (m->pos[1] >= m->interactObj->oPosY) {
if (m->vel[1] < 20.0f) {
m->vel[1] = 20.0f;
}
} else {
if (m->vel[1] > 0.0f) {
m->vel[1] = 0.0f;
}
}
} else {
if (m->forwardVel < 16.0f) {
mario_set_forward_vel(m, 16.0f);
}
}
if (-0x4000 <= facingDYaw && facingDYaw <= 0x4000) {
m->forwardVel *= -1.0f;
bonkAction = sBackwardKnockbackActions[terrainIndex][strengthIndex];
} else {
m->faceAngle[1] += 0x8000;
bonkAction = sForwardKnockbackActions[terrainIndex][strengthIndex];
}
return bonkAction;
}
void push_mario_out_of_object(struct MarioState *m, struct Object *o, f32 padding) {
f32 minDistance = o->hitboxRadius + m->marioObj->hitboxRadius + padding;
f32 offsetX = m->pos[0] - o->oPosX;
f32 offsetZ = m->pos[2] - o->oPosZ;
f32 distance = sqrtf(offsetX * offsetX + offsetZ * offsetZ);
if (distance < minDistance) {
struct Surface *floor;
s16 pushAngle;
f32 newMarioX;
f32 newMarioZ;
if (distance == 0.0f) {
pushAngle = m->faceAngle[1];
} else {
pushAngle = atan2s(offsetZ, offsetX);
}
newMarioX = o->oPosX + minDistance * sins(pushAngle);
newMarioZ = o->oPosZ + minDistance * coss(pushAngle);
f32_find_wall_collision(&newMarioX, &m->pos[1], &newMarioZ, 60.0f, 50.0f);
find_floor(newMarioX, m->pos[1], newMarioZ, &floor);
if (floor != NULL) {
//! Doesn't update Mario's referenced floor (allows oob death when
// an object pushes you into a steep slope while in a ground action)
m->pos[0] = newMarioX;
m->pos[2] = newMarioZ;
}
}
}
void bounce_back_from_attack(struct MarioState *m, u32 interaction) {
if (interaction & (INT_PUNCH | INT_KICK | INT_TRIP)) {
if (m->action == ACT_PUNCHING) {
m->action = ACT_MOVE_PUNCHING;
}
if (m->action & ACT_FLAG_AIR) {
mario_set_forward_vel(m, -16.0f);
} else {
mario_set_forward_vel(m, -48.0f);
}
set_camera_shake_from_hit(SHAKE_ATTACK);
m->particleFlags |= PARTICLE_TRIANGLE;
}
if (interaction & (INT_PUNCH | INT_KICK | INT_TRIP | INT_FAST_ATTACK_OR_SHELL)) {
play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject);
}
}
u32 should_push_or_pull_door(struct MarioState *m, struct Object *o) {
f32 dx = o->oPosX - m->pos[0];
f32 dz = o->oPosZ - m->pos[2];
s16 dYaw = o->oMoveAngleYaw - atan2s(dz, dx);
return (dYaw >= -0x4000 && dYaw <= 0x4000) ? 0x00000001 : 0x00000002;
}
u32 take_damage_from_interact_object(struct MarioState *m) {
s32 shake;
s32 damage = m->interactObj->oDamageOrCoinValue;
if (damage >= 4) {
shake = SHAKE_LARGE_DAMAGE;
} else if (damage >= 2) {
shake = SHAKE_MED_DAMAGE;
} else {
shake = SHAKE_SMALL_DAMAGE;
}
if (!(m->flags & MARIO_CAP_ON_HEAD)) {
damage += (damage + 1) / 2;
}
if (m->flags & MARIO_METAL_CAP) {
damage = 0;
}
m->hurtCounter += 4 * damage;
#ifdef VERSION_SH
queue_rumble_data(5, 80);
#endif
set_camera_shake_from_hit(shake);
return damage;
}
u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) {
u32 damage;
if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP)
&& !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) {
o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_ATTACKED_MARIO;
m->interactObj = o;
damage = take_damage_from_interact_object(m);
if (o->oInteractionSubtype & INT_SUBTYPE_BIG_KNOCKBACK) {
m->forwardVel = 40.0f;
}
if (o->oDamageOrCoinValue > 0) {
play_sound(SOUND_MARIO_ATTACKED, m->marioObj->header.gfx.cameraToObject);
}
update_mario_sound_and_camera(m);
return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue),
damage);
}
return FALSE;
}
void reset_mario_pitch(struct MarioState *m) {
if (m->action == ACT_WATER_JUMP || m->action == ACT_SHOT_FROM_CANNON || m->action == ACT_FLYING) {
set_camera_mode(m->area->camera, m->area->camera->defMode, 1);
m->faceAngle[0] = 0;
}
}
u32 check_object_grab_mario(struct MarioState *m, UNUSED u32 interactType, struct Object *o) {
if ((!(m->action & (ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ATTACKING)) || !sInvulnerable)
&& (o->oInteractionSubtype & INT_SUBTYPE_GRABS_MARIO)) {
if (object_facing_mario(m, o, 0x2AAA)) {
mario_stop_riding_and_holding(m);
o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_GRABBED_MARIO;
m->faceAngle[1] = o->oMoveAngleYaw;
m->interactObj = o;
m->usedObj = o;
update_mario_sound_and_camera(m);
play_sound(SOUND_MARIO_OOOF, m->marioObj->header.gfx.cameraToObject);
#ifdef VERSION_SH
queue_rumble_data(5, 80);
#endif
return set_mario_action(m, ACT_GRABBED, 0);
}
}
push_mario_out_of_object(m, o, -5.0f);
return FALSE;
}
u32 mario_can_talk(struct MarioState *m, u32 arg) {
s16 val6;
if ((m->action & ACT_FLAG_IDLE) != 0x00000000) {
return TRUE;
}
if (m->action == ACT_WALKING) {
if (arg) {
return TRUE;
}
val6 = m->marioObj->header.gfx.animInfo.animID;
if (val6 == 0x0080 || val6 == 0x007F || val6 == 0x006C) {
return TRUE;
}
}
return FALSE;
}
#ifdef VERSION_JP
#define READ_MASK (INPUT_B_PRESSED)
#else
#define READ_MASK (INPUT_B_PRESSED | INPUT_A_PRESSED)
#endif
#ifdef VERSION_JP
#define SIGN_RANGE 0x38E3
#else
#define SIGN_RANGE 0x4000
#endif
u32 check_read_sign(struct MarioState *m, struct Object *o) {
if ((m->input & READ_MASK) && mario_can_talk(m, 0) && object_facing_mario(m, o, SIGN_RANGE)) {
s16 facingDYaw = (s16)(o->oMoveAngleYaw + 0x8000) - m->faceAngle[1];
if (facingDYaw >= -SIGN_RANGE && facingDYaw <= SIGN_RANGE) {
f32 targetX = o->oPosX + 105.0f * sins(o->oMoveAngleYaw);
f32 targetZ = o->oPosZ + 105.0f * coss(o->oMoveAngleYaw);
m->marioObj->oMarioReadingSignDYaw = facingDYaw;
m->marioObj->oMarioReadingSignDPosX = targetX - m->pos[0];
m->marioObj->oMarioReadingSignDPosZ = targetZ - m->pos[2];
m->interactObj = o;
m->usedObj = o;
return set_mario_action(m, ACT_READING_SIGN, 0);
}
}
return FALSE;
}
u32 check_npc_talk(struct MarioState *m, struct Object *o) {
if ((m->input & READ_MASK) && mario_can_talk(m, 1)) {
s16 facingDYaw = mario_obj_angle_to_object(m, o) - m->faceAngle[1];
if (facingDYaw >= -0x4000 && facingDYaw <= 0x4000) {
o->oInteractStatus = INT_STATUS_INTERACTED;
m->interactObj = o;
m->usedObj = o;
push_mario_out_of_object(m, o, -10.0f);
return set_mario_action(m, ACT_WAITING_FOR_DIALOG, 0);
}
}
push_mario_out_of_object(m, o, -10.0f);
return FALSE;
}
void check_kick_or_punch_wall(struct MarioState *m) {
if (m->flags & (MARIO_PUNCHING | MARIO_KICKING | MARIO_TRIPPING)) {
Vec3f detector;
detector[0] = m->pos[0] + 50.0f * sins(m->faceAngle[1]);
detector[2] = m->pos[2] + 50.0f * coss(m->faceAngle[1]);
detector[1] = m->pos[1];
if (resolve_and_return_wall_collisions(detector, 80.0f, 5.0f) != NULL) {
if (m->action != ACT_MOVE_PUNCHING || m->forwardVel >= 0.0f) {
if (m->action == ACT_PUNCHING) {
m->action = ACT_MOVE_PUNCHING;
}
mario_set_forward_vel(m, -48.0f);
play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject);
m->particleFlags |= PARTICLE_TRIANGLE;
} else if (m->action & ACT_FLAG_AIR) {
mario_set_forward_vel(m, -16.0f);
play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject);
m->particleFlags |= PARTICLE_TRIANGLE;
}
}
}
}
void mario_process_interactions(struct MarioState *m) {
sDelayInvincTimer = FALSE;
sInvulnerable = (m->action & ACT_FLAG_INVULNERABLE) || m->invincTimer != 0;
if (!(m->action & ACT_FLAG_INTANGIBLE) && m->collidedObjInteractTypes != 0) {
s32 i;
for (i = 0; i < 31; i++) {
u32 interactType = sInteractionHandlers[i].interactType;
if (m->collidedObjInteractTypes & interactType) {
struct Object *object = mario_get_collided_object(m, interactType);
m->collidedObjInteractTypes &= ~interactType;
if (!(object->oInteractStatus & INT_STATUS_INTERACTED)) {
if (sInteractionHandlers[i].handler(m, interactType, object)) {
break;
}
}
}
}
}
if (m->invincTimer > 0 && !sDelayInvincTimer) {
m->invincTimer -= 1;
}
//! If the kick/punch flags are set and an object collision changes Mario's
// action, he will get the kick/punch wall speed anyway.
check_kick_or_punch_wall(m);
m->flags &= ~MARIO_PUNCHING & ~MARIO_KICKING & ~MARIO_TRIPPING;
if (!(m->marioObj->collidedObjInteractTypes & (INTERACT_WARP_DOOR | INTERACT_DOOR))) {
sDisplayingDoorText = FALSE;
}
if (!(m->marioObj->collidedObjInteractTypes & INTERACT_WARP)) {
sJustTeleported = FALSE;
}
}
void check_death_barrier(struct MarioState *m) {
if (m->pos[1] < m->floorHeight + 2048.0f) {
if (level_trigger_warp(m, WARP_OP_WARP_FLOOR) == 20 && !(m->flags & MARIO_UNKNOWN_18)) {
play_sound(SOUND_MARIO_WAAAOOOW, m->marioObj->header.gfx.cameraToObject);
}
}
}
void check_lava_boost(struct MarioState *m) {
if (!(m->action & ACT_FLAG_RIDING_SHELL) && m->pos[1] < m->floorHeight + 10.0f) {
if (!(m->flags & MARIO_METAL_CAP)) {
m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18;
}
update_mario_sound_and_camera(m);
drop_and_set_mario_action(m, ACT_LAVA_BOOST, 0);
}
}
void pss_begin_slide(UNUSED struct MarioState *m) {
// if (!(gHudDisplay.flags & HUD_DISPLAY_FLAG_TIMER)) {
// level_control_timer(TIMER_CONTROL_SHOW);
// level_control_timer(TIMER_CONTROL_START);
// sPssSlideStarted = TRUE;
// }
}
void pss_end_slide(struct MarioState *m) {
//! This flag isn't set on death or level entry, allowing double star spawn
if (sPssSlideStarted) {
u16 slideTime = level_control_timer(TIMER_CONTROL_STOP);
if (slideTime < 630) {
m->marioObj->oBehParams = (1 << 24);
spawn_default_star(-6358.0f, -4300.0f, 4700.0f);
}
sPssSlideStarted = FALSE;
}
}
void mario_handle_special_floors(struct MarioState *m) {
if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE) {
return;
}
if (m->floor != NULL) {
s32 floorType = m->floor->type;
switch (floorType) {
case SURFACE_DEATH_PLANE:
case SURFACE_VERTICAL_WIND:
check_death_barrier(m);
break;
case SURFACE_WARP:
level_trigger_warp(m, WARP_OP_WARP_FLOOR);
break;
case SURFACE_TIMER_START:
pss_begin_slide(m);
break;
case SURFACE_TIMER_END:
pss_end_slide(m);
break;
}
if (!(m->action & ACT_FLAG_AIR) && !(m->action & ACT_FLAG_SWIMMING)) {
switch (floorType) {
case SURFACE_BURNING:
check_lava_boost(m);
break;
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
#ifndef INTERACTION_H
#define INTERACTION_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#define INTERACT_HOOT /* 0x00000001 */ (1 << 0)
#define INTERACT_GRABBABLE /* 0x00000002 */ (1 << 1)
#define INTERACT_DOOR /* 0x00000004 */ (1 << 2)
#define INTERACT_DAMAGE /* 0x00000008 */ (1 << 3)
#define INTERACT_COIN /* 0x00000010 */ (1 << 4)
#define INTERACT_CAP /* 0x00000020 */ (1 << 5)
#define INTERACT_POLE /* 0x00000040 */ (1 << 6)
#define INTERACT_KOOPA /* 0x00000080 */ (1 << 7)
#define INTERACT_UNKNOWN_08 /* 0x00000100 */ (1 << 8)
#define INTERACT_BREAKABLE /* 0x00000200 */ (1 << 9)
#define INTERACT_STRONG_WIND /* 0x00000400 */ (1 << 10)
#define INTERACT_WARP_DOOR /* 0x00000800 */ (1 << 11)
#define INTERACT_STAR_OR_KEY /* 0x00001000 */ (1 << 12)
#define INTERACT_WARP /* 0x00002000 */ (1 << 13)
#define INTERACT_CANNON_BASE /* 0x00004000 */ (1 << 14)
#define INTERACT_BOUNCE_TOP /* 0x00008000 */ (1 << 15)
#define INTERACT_WATER_RING /* 0x00010000 */ (1 << 16)
#define INTERACT_BULLY /* 0x00020000 */ (1 << 17)
#define INTERACT_FLAME /* 0x00040000 */ (1 << 18)
#define INTERACT_KOOPA_SHELL /* 0x00080000 */ (1 << 19)
#define INTERACT_BOUNCE_TOP2 /* 0x00100000 */ (1 << 20)
#define INTERACT_MR_BLIZZARD /* 0x00200000 */ (1 << 21)
#define INTERACT_HIT_FROM_BELOW /* 0x00400000 */ (1 << 22)
#define INTERACT_TEXT /* 0x00800000 */ (1 << 23)
#define INTERACT_TORNADO /* 0x01000000 */ (1 << 24)
#define INTERACT_WHIRLPOOL /* 0x02000000 */ (1 << 25)
#define INTERACT_CLAM_OR_BUBBA /* 0x04000000 */ (1 << 26)
#define INTERACT_BBH_ENTRANCE /* 0x08000000 */ (1 << 27)
#define INTERACT_SNUFIT_BULLET /* 0x10000000 */ (1 << 28)
#define INTERACT_SHOCK /* 0x20000000 */ (1 << 29)
#define INTERACT_IGLOO_BARRIER /* 0x40000000 */ (1 << 30)
#define INTERACT_UNKNOWN_31 /* 0x80000000 */ (1 << 31)
// INTERACT_WARP
#define INT_SUBTYPE_FADING_WARP 0x00000001
// Damaging interactions
#define INT_SUBTYPE_DELAY_INVINCIBILITY 0x00000002
#define INT_SUBTYPE_BIG_KNOCKBACK 0x00000008 /* Used by Bowser, sets Mario's forward velocity to 40 on hit */
// INTERACT_GRABBABLE
#define INT_SUBTYPE_GRABS_MARIO 0x00000004 /* Also makes the object heavy */
#define INT_SUBTYPE_HOLDABLE_NPC 0x00000010 /* Allows the object to be gently dropped, and sets vertical speed to 0 when dropped with no forwards velocity */
#define INT_SUBTYPE_DROP_IMMEDIATELY 0x00000040 /* This gets set by grabbable NPCs that talk to Mario to make him drop them after the dialog is finished */
#define INT_SUBTYPE_KICKABLE 0x00000100
#define INT_SUBTYPE_NOT_GRABBABLE 0x00000200 /* Used by Heavy-Ho to allow it to throw Mario, without Mario being able to pick it up */
// INTERACT_DOOR
#define INT_SUBTYPE_STAR_DOOR 0x00000020
//INTERACT_BOUNCE_TOP
#define INT_SUBTYPE_TWIRL_BOUNCE 0x00000080
// INTERACT_STAR_OR_KEY
#define INT_SUBTYPE_NO_EXIT 0x00000400
#define INT_SUBTYPE_GRAND_STAR 0x00000800
// INTERACT_TEXT
#define INT_SUBTYPE_SIGN 0x00001000
#define INT_SUBTYPE_NPC 0x00004000
// INTERACT_CLAM_OR_BUBBA
#define INT_SUBTYPE_EATS_MARIO 0x00002000
#define ATTACK_PUNCH 1
#define ATTACK_KICK_OR_TRIP 2
#define ATTACK_FROM_ABOVE 3
#define ATTACK_GROUND_POUND_OR_TWIRL 4
#define ATTACK_FAST_ATTACK 5
#define ATTACK_FROM_BELOW 6
#define INT_STATUS_ATTACK_MASK 0x000000FF
#define INT_STATUS_HOOT_GRABBED_BY_MARIO (1 << 0) /* 0x00000001 */
#define INT_STATUS_MARIO_UNK1 (1 << 1) /* 0x00000002 */
#define INT_STATUS_MARIO_UNK2 (1 << 2) /* 0x00000004 */
#define INT_STATUS_MARIO_DROP_OBJECT (1 << 3) /* 0x00000008 */
#define INT_STATUS_HIT_BY_SHOCKWAVE (1 << 4) /* 0x00000010 */
#define INT_STATUS_MARIO_UNK5 (1 << 5) /* 0x00000020 */
#define INT_STATUS_MARIO_UNK6 (1 << 6) /* 0x00000040 */
#define INT_STATUS_MARIO_UNK7 (1 << 7) /* 0x00000080 */
#define INT_STATUS_GRABBED_MARIO (1 << 11) /* 0x00000800 */
#define INT_STATUS_ATTACKED_MARIO (1 << 13) /* 0x00002000 */
#define INT_STATUS_WAS_ATTACKED (1 << 14) /* 0x00004000 */
#define INT_STATUS_INTERACTED (1 << 15) /* 0x00008000 */
#define INT_STATUS_TRAP_TURN (1 << 20) /* 0x00100000 */
#define INT_STATUS_HIT_MINE (1 << 21) /* 0x00200000 */
#define INT_STATUS_STOP_RIDING (1 << 22) /* 0x00400000 */
#define INT_STATUS_TOUCHED_BOB_OMB (1 << 23) /* 0x00800000 */
s16 mario_obj_angle_to_object(struct MarioState *m, struct Object *o);
void mario_stop_riding_object(struct MarioState *m);
void mario_grab_used_object(struct MarioState *m);
void mario_drop_held_object(struct MarioState *m);
void mario_throw_held_object(struct MarioState *m);
void mario_stop_riding_and_holding(struct MarioState *m);
u32 does_mario_have_normal_cap_on_head(struct MarioState *m);
void mario_blow_off_cap(struct MarioState *m, f32 capSpeed);
u32 mario_lose_cap_to_enemy(u32 arg);
void mario_retrieve_cap(void);
struct Object *mario_get_collided_object(struct MarioState *m, u32 interactType);
u32 mario_check_object_grab(struct MarioState *m);
u32 get_door_save_file_flag(struct Object *door);
void mario_process_interactions(struct MarioState *m);
void mario_handle_special_floors(struct MarioState *m);
#endif // INTERACTION_H
+132
View File
@@ -0,0 +1,132 @@
#ifndef LEVEL_UPDATE_H
#define LEVEL_UPDATE_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#define TIMER_CONTROL_SHOW 0
#define TIMER_CONTROL_START 1
#define TIMER_CONTROL_STOP 2
#define TIMER_CONTROL_HIDE 3
#define WARP_OP_NONE 0x00
#define WARP_OP_UNKNOWN_01 0x01
#define WARP_OP_UNKNOWN_02 0x02
#define WARP_OP_WARP_DOOR 0x03
#define WARP_OP_WARP_OBJECT 0x04
#define WARP_OP_TELEPORT 0x05
#define WARP_OP_STAR_EXIT 0x11
#define WARP_OP_DEATH 0x12
#define WARP_OP_WARP_FLOOR 0x13
#define WARP_OP_GAME_OVER 0x14
#define WARP_OP_CREDITS_END 0x15
#define WARP_OP_DEMO_NEXT 0x16
#define WARP_OP_CREDITS_START 0x17
#define WARP_OP_CREDITS_NEXT 0x18
#define WARP_OP_DEMO_END 0x19
#define WARP_OP_TRIGGERS_LEVEL_SELECT 0x10
#define MARIO_SPAWN_DOOR_WARP 0x01
#define MARIO_SPAWN_UNKNOWN_02 0x02
#define MARIO_SPAWN_UNKNOWN_03 0x03
#define MARIO_SPAWN_TELEPORT 0x04
#define MARIO_SPAWN_INSTANT_ACTIVE 0x10
#define MARIO_SPAWN_SWIMMING 0x11
#define MARIO_SPAWN_AIRBORNE 0x12
#define MARIO_SPAWN_HARD_AIR_KNOCKBACK 0x13
#define MARIO_SPAWN_SPIN_AIRBORNE_CIRCLE 0x14
#define MARIO_SPAWN_DEATH 0x15
#define MARIO_SPAWN_SPIN_AIRBORNE 0x16
#define MARIO_SPAWN_FLYING 0x17
#define MARIO_SPAWN_PAINTING_STAR_COLLECT 0x20
#define MARIO_SPAWN_PAINTING_DEATH 0x21
#define MARIO_SPAWN_AIRBORNE_STAR_COLLECT 0x22
#define MARIO_SPAWN_AIRBORNE_DEATH 0x23
#define MARIO_SPAWN_LAUNCH_STAR_COLLECT 0x24
#define MARIO_SPAWN_LAUNCH_DEATH 0x25
#define MARIO_SPAWN_UNKNOWN_27 0x27
// struct CreditsEntry
// {
// /*0x00*/ u8 levelNum;
// /*0x01*/ u8 areaIndex;
// /*0x02*/ u8 unk02;
// /*0x03*/ s8 marioAngle;
// /*0x04*/ Vec3s marioPos;
// /*0x0C*/ const char **unk0C;
// };
//
// extern struct CreditsEntry *gCurrCreditsEntry;
//
// extern struct MarioState gMarioStates[];
// extern struct MarioState *gMarioState;
//
// extern s16 sCurrPlayMode;
// extern u16 D_80339ECA;
// extern s16 sTransitionTimer;
// extern void (*sTransitionUpdate)(s16 *);
// extern u8 unused3[4];
//
// struct WarpDest {
// u8 type;
// u8 levelNum;
// u8 areaIdx;
// u8 nodeId;
// u32 arg;
// };
//
// extern struct WarpDest sWarpDest;
//
// extern s16 D_80339EE0;
// extern s16 sDelayedWarpOp;
// extern s16 sDelayedWarpTimer;
// extern s16 sSourceWarpNodeId;
// extern s32 sDelayedWarpArg;
// extern u8 unused4[2];
// extern s8 sTimerRunning;
struct HudDisplay {
/*0x00*/ s16 lives;
/*0x02*/ s16 coins;
/*0x04*/ s16 stars;
/*0x06*/ s16 wedges;
/*0x08*/ s16 keys;
/*0x0A*/ s16 flags;
/*0x0C*/ u16 timer;
};
// extern struct HudDisplay gHudDisplay;
// extern s8 gNeverEnteredCastle;
enum HUDDisplayFlag {
HUD_DISPLAY_FLAG_LIVES = 0x0001,
HUD_DISPLAY_FLAG_COIN_COUNT = 0x0002,
HUD_DISPLAY_FLAG_STAR_COUNT = 0x0004,
HUD_DISPLAY_FLAG_CAMERA_AND_POWER = 0x0008,
HUD_DISPLAY_FLAG_KEYS = 0x0010,
HUD_DISPLAY_FLAG_UNKNOWN_0020 = 0x0020,
HUD_DISPLAY_FLAG_TIMER = 0x0040,
HUD_DISPLAY_FLAG_EMPHASIZE_POWER = 0x8000,
HUD_DISPLAY_NONE = 0x0000,
HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020
};
//
//
// u16 level_control_timer(s32 timerOp);
// void fade_into_special_warp(u32 arg, u32 color);
// void load_level_init_text(u32 arg);
// s16 level_trigger_warp(struct MarioState *m, s32 warpOp);
// void level_set_transition(s16 length, void (*updateFunction)(s16 *));
//
// s32 lvl_init_or_update(s16 initOrUpdate, UNUSED s32 unused);
// s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum);
// s32 lvl_set_current_level(UNUSED s16 arg0, s32 levelNum);
// s32 lvl_play_the_end_screen_sound(UNUSED s16 arg0, UNUSED s32 arg1);
// void basic_update(UNUSED s16 *arg);
#endif // LEVEL_UPDATE_H
File diff suppressed because it is too large Load Diff
+54
View File
@@ -0,0 +1,54 @@
#ifndef MARIO_H
#define MARIO_H
#include "../include/PR/ultratypes.h"
#include "../include/macros.h"
#include "../include/types.h"
s32 is_anim_at_end(struct MarioState *m);
s32 is_anim_past_end(struct MarioState *m);
s16 set_mario_animation(struct MarioState *m, s32 targetAnimID);
s16 set_mario_anim_with_accel(struct MarioState *m, s32 targetAnimID, s32 accel);
void set_anim_to_frame(struct MarioState *m, s16 animFrame);
s32 is_anim_past_frame(struct MarioState *m, s16 animFrame);
s16 find_mario_anim_flags_and_translation(struct Object *o, s32 yaw, Vec3s translation);
void update_mario_pos_for_anim(struct MarioState *m);
s16 return_mario_anim_y_translation(struct MarioState *m);
void play_sound_if_no_flag(struct MarioState *m, u32 soundBits, u32 flags);
void play_mario_jump_sound(struct MarioState *m);
void adjust_sound_for_speed(struct MarioState *m);
void play_sound_and_spawn_particles(struct MarioState *m, u32 soundBits, u32 waveParticleType);
void play_mario_action_sound(struct MarioState *m, u32 soundBits, u32 waveParticleType);
void play_mario_landing_sound(struct MarioState *m, u32 soundBits);
void play_mario_landing_sound_once(struct MarioState *m, u32 soundBits);
void play_mario_heavy_landing_sound(struct MarioState *m, u32 soundBits);
void play_mario_heavy_landing_sound_once(struct MarioState *m, u32 soundBits);
void play_mario_sound(struct MarioState *m, s32 primarySoundBits, s32 scondarySoundBits);
void mario_set_forward_vel(struct MarioState *m, f32 speed);
s32 mario_get_floor_class(struct MarioState *m);
u32 mario_get_terrain_sound_addend(struct MarioState *m);
struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius);
f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil);
s32 mario_facing_downhill(struct MarioState *m, s32 turnYaw);
u32 mario_floor_is_slippery(struct MarioState *m);
s32 mario_floor_is_slope(struct MarioState *m);
s32 mario_floor_is_steep(struct MarioState *m);
f32 find_floor_height_relative_polar(struct MarioState *m, s16 angleFromMario, f32 distFromMario);
s16 find_floor_slope(struct MarioState *m, s16 yawOffset);
void update_mario_sound_and_camera(struct MarioState *m);
void set_steep_jump_action(struct MarioState *m);
u32 set_mario_action(struct MarioState *, u32 action, u32 actionArg);
s32 set_jump_from_landing(struct MarioState *m);
s32 set_jumping_action(struct MarioState *m, u32 action, u32 actionArg);
s32 drop_and_set_mario_action(struct MarioState *m, u32 action, u32 actionArg);
s32 hurt_and_set_mario_action(struct MarioState *m, u32 action, u32 actionArg, s16 hurtCounter);
s32 check_common_action_exits(struct MarioState *m);
s32 check_common_hold_action_exits(struct MarioState *m);
s32 transition_submerged_to_walking(struct MarioState *m);
s32 set_water_plunge_action(struct MarioState *m);
s32 execute_mario_action(UNUSED struct Object *o);
void init_mario(void);
void init_mario_from_save_file(void);
#endif // MARIO_H
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
#ifndef MARIO_ACTIONS_AIRBORNE_H
#define MARIO_ACTIONS_AIRBORNE_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
s32 mario_execute_airborne_action(struct MarioState *m);
#endif // MARIO_ACTIONS_AIRBORNE_H
+896
View File
@@ -0,0 +1,896 @@
#include "../include/PR/ultratypes.h"
#include "../shim.h"
#include "../include/sm64.h"
//#include "behavior_data.h"
#include "mario_actions_automatic.h"
//#include "audio/external.h"
#include "area.h"
#include "mario.h"
#include "mario_step.h"
#include "../engine/math_util.h"
#include "memory.h"
#include "../engine/graph_node.h"
#include "save_file.h"
#include "../engine/surface_collision.h"
#include "interaction.h"
#include "camera.h"
//#include "level_table.h"
//#include "thread6.h"
#include "../include/mario_animation_ids.h"
#include "../include/object_fields.h"
#include "../include/mario_geo_switch_case_ids.h"
static Vec3f gVec3fZero = { 0.0f, 0.0f, 0.0f };
#define POLE_NONE 0
#define POLE_TOUCHED_FLOOR 1
#define POLE_FELL_OFF 2
#define HANG_NONE 0
#define HANG_HIT_CEIL_OR_OOB 1
#define HANG_LEFT_CEIL 2
void add_tree_leaf_particles(struct MarioState *m) {
// f32 leafHeight;
// if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {
// // make leaf effect spawn higher on the Shifting Sand Land palm tree
// if (gCurrLevelNum == LEVEL_SSL) {
// leafHeight = 250.0f;
// } else {
// leafHeight = 100.0f;
// }
// if (m->pos[1] - m->floorHeight > leafHeight) {
// m->particleFlags |= PARTICLE_LEAF;
// }
// }
}
void play_climbing_sounds(struct MarioState *m, s32 b) {
// s32 isOnTree = (m->usedObj->behavior == segmented_to_virtual(bhvTree));
s32 isOnTree = FALSE;
if (b == 1) {
if (is_anim_past_frame(m, 1)) {
play_sound(isOnTree ? SOUND_ACTION_CLIMB_UP_TREE : SOUND_ACTION_CLIMB_UP_POLE,
m->marioObj->header.gfx.cameraToObject);
}
} else {
play_sound(isOnTree ? SOUND_MOVING_SLIDE_DOWN_TREE : SOUND_MOVING_SLIDE_DOWN_POLE,
m->marioObj->header.gfx.cameraToObject);
}
}
s32 set_pole_position(struct MarioState *m, f32 offsetY) {
UNUSED s32 unused1;
UNUSED s32 unused2;
UNUSED s32 unused3;
struct Surface *floor;
struct Surface *ceil;
f32 floorHeight;
f32 ceilHeight;
s32 collided;
s32 result = POLE_NONE;
f32 poleTop = m->usedObj->hitboxHeight - 100.0f;
struct Object *marioObj = m->marioObj;
if (marioObj->oMarioPolePos > poleTop) {
marioObj->oMarioPolePos = poleTop;
}
m->pos[0] = m->usedObj->oPosX;
m->pos[2] = m->usedObj->oPosZ;
m->pos[1] = m->usedObj->oPosY + marioObj->oMarioPolePos + offsetY;
collided = f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f);
collided |= f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f);
ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &ceil);
if (m->pos[1] > ceilHeight - 160.0f) {
m->pos[1] = ceilHeight - 160.0f;
marioObj->oMarioPolePos = m->pos[1] - m->usedObj->oPosY;
}
floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);
if (m->pos[1] < floorHeight) {
m->pos[1] = floorHeight;
set_mario_action(m, ACT_IDLE, 0);
result = POLE_TOUCHED_FLOOR;
} else if (marioObj->oMarioPolePos < -m->usedObj->hitboxDownOffset) {
m->pos[1] = m->usedObj->oPosY - m->usedObj->hitboxDownOffset;
set_mario_action(m, ACT_FREEFALL, 0);
result = POLE_FELL_OFF;
} else if (collided) {
if (m->pos[1] > floorHeight + 20.0f) {
m->forwardVel = -2.0f;
set_mario_action(m, ACT_SOFT_BONK, 0);
result = POLE_FELL_OFF;
} else {
set_mario_action(m, ACT_IDLE, 0);
result = POLE_TOUCHED_FLOOR;
}
}
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1],
m->usedObj->oMoveAngleRoll);
return result;
}
s32 act_holding_pole(struct MarioState *m) {
struct Object *marioObj = m->marioObj;
#ifdef VERSION_JP
if (m->input & INPUT_A_PRESSED) {
add_tree_leaf_particles(m);
m->faceAngle[1] += 0x8000;
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
}
if (m->input & INPUT_Z_PRESSED) {
add_tree_leaf_particles(m);
m->forwardVel = -2.0f;
return set_mario_action(m, ACT_SOFT_BONK, 0);
}
#else
if ((m->input & INPUT_Z_PRESSED) || m->health < 0x100) {
add_tree_leaf_particles(m);
m->forwardVel = -2.0f;
return set_mario_action(m, ACT_SOFT_BONK, 0);
}
if (m->input & INPUT_A_PRESSED) {
add_tree_leaf_particles(m);
m->faceAngle[1] += 0x8000;
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
}
#endif
if (m->controller->stickY > 16.0f) {
f32 poleTop = m->usedObj->hitboxHeight - 100.0f;
const BehaviorScript *poleBehavior = virtual_to_segmented(0x13, m->usedObj->behavior);
if (marioObj->oMarioPolePos < poleTop - 0.4f) {
return set_mario_action(m, ACT_CLIMBING_POLE, 0);
}
// if (poleBehavior != bhvGiantPole && m->controller->stickY > 50.0f) {
if (m->controller->stickY > 50.0f) {
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 0);
}
}
if (m->controller->stickY < -16.0f) {
marioObj->oMarioPoleYawVel -= m->controller->stickY * 2;
if (marioObj->oMarioPoleYawVel > 0x1000) {
marioObj->oMarioPoleYawVel = 0x1000;
}
m->faceAngle[1] += marioObj->oMarioPoleYawVel;
marioObj->oMarioPolePos -= marioObj->oMarioPoleYawVel / 0x100;
// if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {
// //! The Shifting Sand Land palm tree check is done climbing up in
// // add_tree_leaf_particles, but not here, when climbing down.
// if (m->pos[1] - m->floorHeight > 100.0f) {
// m->particleFlags |= PARTICLE_LEAF;
// }
// }
play_climbing_sounds(m, 2);
#ifdef VERSION_SH
reset_rumble_timers();
#endif
func_80320A4C(1, marioObj->oMarioPoleYawVel / 0x100 * 2);
} else {
marioObj->oMarioPoleYawVel = 0;
m->faceAngle[1] -= m->controller->stickX * 16.0f;
}
if (set_pole_position(m, 0.0f) == POLE_NONE) {
set_mario_animation(m, MARIO_ANIM_IDLE_ON_POLE);
}
return FALSE;
}
s32 act_climbing_pole(struct MarioState *m) {
s32 sp24;
struct Object *marioObj = m->marioObj;
s16 cameraAngle = m->area->camera->yaw;
#ifndef VERSION_JP
if (m->health < 0x100) {
add_tree_leaf_particles(m);
m->forwardVel = -2.0f;
return set_mario_action(m, ACT_SOFT_BONK, 0);
}
#endif
if (m->input & INPUT_A_PRESSED) {
add_tree_leaf_particles(m);
m->faceAngle[1] += 0x8000;
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
}
if (m->controller->stickY < 8.0f) {
return set_mario_action(m, ACT_HOLDING_POLE, 0);
}
marioObj->oMarioPolePos += m->controller->stickY / 8.0f;
marioObj->oMarioPoleYawVel = 0;
m->faceAngle[1] = cameraAngle - approach_s32((s16)(cameraAngle - m->faceAngle[1]), 0, 0x400, 0x400);
if (set_pole_position(m, 0.0f) == POLE_NONE) {
sp24 = m->controller->stickY / 4.0f * 0x10000;
set_mario_anim_with_accel(m, MARIO_ANIM_CLIMB_UP_POLE, sp24);
add_tree_leaf_particles(m);
play_climbing_sounds(m, 1);
}
return FALSE;
}
s32 act_grab_pole_slow(struct MarioState *m) {
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
if (set_pole_position(m, 0.0f) == POLE_NONE) {
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SHORT);
if (is_anim_at_end(m)) {
set_mario_action(m, ACT_HOLDING_POLE, 0);
}
add_tree_leaf_particles(m);
}
return FALSE;
}
s32 act_grab_pole_fast(struct MarioState *m) {
struct Object *marioObj = m->marioObj;
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
m->faceAngle[1] += marioObj->oMarioPoleYawVel;
marioObj->oMarioPoleYawVel = marioObj->oMarioPoleYawVel * 8 / 10;
if (set_pole_position(m, 0.0f) == POLE_NONE) {
if (marioObj->oMarioPoleYawVel > 0x800) {
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART1);
} else {
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART2);
if (is_anim_at_end(m)) {
marioObj->oMarioPoleYawVel = 0;
set_mario_action(m, ACT_HOLDING_POLE, 0);
}
}
add_tree_leaf_particles(m);
}
return FALSE;
}
s32 act_top_of_pole_transition(struct MarioState *m) {
struct Object *marioObj = m->marioObj;
marioObj->oMarioPoleYawVel = 0;
if (m->actionArg == 0) {
set_mario_animation(m, MARIO_ANIM_START_HANDSTAND);
if (is_anim_at_end(m)) {
return set_mario_action(m, ACT_TOP_OF_POLE, 0);
}
} else {
set_mario_animation(m, MARIO_ANIM_RETURN_FROM_HANDSTAND);
if (m->marioObj->header.gfx.animInfo.animFrame == 0) {
return set_mario_action(m, ACT_HOLDING_POLE, 0);
}
}
set_pole_position(m, return_mario_anim_y_translation(m));
return FALSE;
}
s32 act_top_of_pole(struct MarioState *m) {
UNUSED struct Object *marioObj = m->marioObj;
if (m->input & INPUT_A_PRESSED) {
return set_mario_action(m, ACT_TOP_OF_POLE_JUMP, 0);
}
if (m->controller->stickY < -16.0f) {
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 1);
}
m->faceAngle[1] -= m->controller->stickX * 16.0f;
set_mario_animation(m, MARIO_ANIM_HANDSTAND_IDLE);
set_pole_position(m, return_mario_anim_y_translation(m));
return FALSE;
}
s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
UNUSED s32 unused;
struct Surface *ceil;
struct Surface *floor;
f32 ceilHeight;
f32 floorHeight;
f32 ceilOffset;
m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
if (floor == NULL) {
return HANG_HIT_CEIL_OR_OOB;
}
if (ceil == NULL) {
return HANG_LEFT_CEIL;
}
if (ceilHeight - floorHeight <= 160.0f) {
return HANG_HIT_CEIL_OR_OOB;
}
if (ceil->type != SURFACE_HANGABLE) {
return HANG_LEFT_CEIL;
}
ceilOffset = ceilHeight - (nextPos[1] + 160.0f);
if (ceilOffset < -30.0f) {
return HANG_HIT_CEIL_OR_OOB;
}
if (ceilOffset > 30.0f) {
return HANG_LEFT_CEIL;
}
nextPos[1] = m->ceilHeight - 160.0f;
vec3f_copy(m->pos, nextPos);
m->floor = floor;
m->floorHeight = floorHeight;
m->ceil = ceil;
m->ceilHeight = ceilHeight;
return HANG_NONE;
}
s32 update_hang_moving(struct MarioState *m) {
s32 stepResult;
Vec3f nextPos;
f32 maxSpeed = 4.0f;
m->forwardVel += 1.0f;
if (m->forwardVel > maxSpeed) {
m->forwardVel = maxSpeed;
}
m->faceAngle[1] =
m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);
m->slideYaw = m->faceAngle[1];
m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);
m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);
m->vel[0] = m->slideVelX;
m->vel[1] = 0.0f;
m->vel[2] = m->slideVelZ;
nextPos[0] = m->pos[0] - m->ceil->normal.y * m->vel[0];
nextPos[2] = m->pos[2] - m->ceil->normal.y * m->vel[2];
nextPos[1] = m->pos[1];
stepResult = perform_hanging_step(m, nextPos);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
return stepResult;
}
void update_hang_stationary(struct MarioState *m) {
m->forwardVel = 0.0f;
m->slideVelX = 0.0f;
m->slideVelZ = 0.0f;
m->pos[1] = m->ceilHeight - 160.0f;
vec3f_copy(m->vel, gVec3fZero);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
}
s32 act_start_hanging(struct MarioState *m) {
#ifdef VERSION_SH
if (m->actionTimer++ == 0) {
queue_rumble_data(5, 80);
}
#else
m->actionTimer++;
#endif
if ((m->input & INPUT_NONZERO_ANALOG) && m->actionTimer >= 31) {
return set_mario_action(m, ACT_HANGING, 0);
}
if (!(m->input & INPUT_A_DOWN)) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->input & INPUT_Z_PRESSED) {
return set_mario_action(m, ACT_GROUND_POUND, 0);
}
//! Crash if Mario's referenced ceiling is NULL (same for other hanging actions)
if (m->ceil->type != SURFACE_HANGABLE) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
set_mario_animation(m, MARIO_ANIM_HANG_ON_CEILING);
play_sound_if_no_flag(m, SOUND_ACTION_HANGING_STEP, MARIO_ACTION_SOUND_PLAYED);
update_hang_stationary(m);
if (is_anim_at_end(m)) {
set_mario_action(m, ACT_HANGING, 0);
}
return FALSE;
}
s32 act_hanging(struct MarioState *m) {
if (m->input & INPUT_NONZERO_ANALOG) {
return set_mario_action(m, ACT_HANG_MOVING, m->actionArg);
}
if (!(m->input & INPUT_A_DOWN)) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->input & INPUT_Z_PRESSED) {
return set_mario_action(m, ACT_GROUND_POUND, 0);
}
if (m->ceil->type != SURFACE_HANGABLE) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->actionArg & 1) {
set_mario_animation(m, MARIO_ANIM_HANDSTAND_LEFT);
} else {
set_mario_animation(m, MARIO_ANIM_HANDSTAND_RIGHT);
}
update_hang_stationary(m);
return FALSE;
}
s32 act_hang_moving(struct MarioState *m) {
if (!(m->input & INPUT_A_DOWN)) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->input & INPUT_Z_PRESSED) {
return set_mario_action(m, ACT_GROUND_POUND, 0);
}
if (m->ceil->type != SURFACE_HANGABLE) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->actionArg & 1) {
set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_RIGHT);
} else {
set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_LEFT);
}
if (m->marioObj->header.gfx.animInfo.animFrame == 12) {
play_sound(SOUND_ACTION_HANGING_STEP, m->marioObj->header.gfx.cameraToObject);
#ifdef VERSION_SH
queue_rumble_data(5, 30);
#endif
}
if (is_anim_past_end(m)) {
m->actionArg ^= 1;
if (m->input & INPUT_UNKNOWN_5) {
return set_mario_action(m, ACT_HANGING, m->actionArg);
}
}
if (update_hang_moving(m) == HANG_LEFT_CEIL) {
set_mario_action(m, ACT_FREEFALL, 0);
}
return FALSE;
}
s32 let_go_of_ledge(struct MarioState *m) {
f32 floorHeight;
struct Surface *floor;
m->vel[1] = 0.0f;
m->forwardVel = -8.0f;
m->pos[0] -= 60.0f * sins(m->faceAngle[1]);
m->pos[2] -= 60.0f * coss(m->faceAngle[1]);
floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);
if (floorHeight < m->pos[1] - 100.0f) {
m->pos[1] -= 100.0f;
} else {
m->pos[1] = floorHeight;
}
return set_mario_action(m, ACT_SOFT_BONK, 0);
}
void climb_up_ledge(struct MarioState *m) {
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
m->pos[0] += 14.0f * sins(m->faceAngle[1]);
m->pos[2] += 14.0f * coss(m->faceAngle[1]);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
}
void update_ledge_climb_camera(struct MarioState *m) {
// f32 sp4;
// if (m->actionTimer < 14) {
// sp4 = m->actionTimer;
// } else {
// sp4 = 14.0f;
// }
// m->statusForCamera->pos[0] = m->pos[0] + sp4 * sins(m->faceAngle[1]);
// m->statusForCamera->pos[2] = m->pos[2] + sp4 * coss(m->faceAngle[1]);
// m->statusForCamera->pos[1] = m->pos[1];
// m->actionTimer++;
// m->flags |= MARIO_UNKNOWN_25;
}
void update_ledge_climb(struct MarioState *m, s32 animation, u32 endAction) {
stop_and_set_height_to_floor(m);
set_mario_animation(m, animation);
if (is_anim_at_end(m)) {
set_mario_action(m, endAction, 0);
if (endAction == ACT_IDLE) {
climb_up_ledge(m);
}
}
}
s32 act_ledge_grab(struct MarioState *m) {
f32 heightAboveFloor;
s16 intendedDYaw = m->intendedYaw - m->faceAngle[1];
s32 hasSpaceForMario = (m->ceilHeight - m->floorHeight >= 160.0f);
if (m->actionTimer < 10) {
m->actionTimer++;
}
if (m->floor->normal.y < 0.9063078f) {
return let_go_of_ledge(m);
}
if (m->input & (INPUT_Z_PRESSED | INPUT_OFF_FLOOR)) {
return let_go_of_ledge(m);
}
if ((m->input & INPUT_A_PRESSED) && hasSpaceForMario) {
return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);
}
if (m->input & INPUT_UNKNOWN_10) {
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK1) {
m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18;
}
return let_go_of_ledge(m);
}
#ifdef VERSION_EU
// On EU, you can't slow climb up ledges while holding A.
if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG) && !(m->input & INPUT_A_DOWN))
#else
if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG))
#endif
{
if (intendedDYaw >= -0x4000 && intendedDYaw <= 0x4000) {
if (hasSpaceForMario) {
return set_mario_action(m, ACT_LEDGE_CLIMB_SLOW_1, 0);
}
} else {
return let_go_of_ledge(m);
}
}
heightAboveFloor = m->pos[1] - find_floor_height_relative_polar(m, -0x8000, 30.0f);
if (hasSpaceForMario && heightAboveFloor < 100.0f) {
return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);
}
if (m->actionArg == 0) {
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
}
stop_and_set_height_to_floor(m);
set_mario_animation(m, MARIO_ANIM_IDLE_ON_LEDGE);
return FALSE;
}
s32 act_ledge_climb_slow(struct MarioState *m) {
if (m->input & INPUT_OFF_FLOOR) {
return let_go_of_ledge(m);
}
if (m->actionTimer >= 28
&& (m->input
& (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE))) {
climb_up_ledge(m);
return check_common_action_exits(m);
}
if (m->actionTimer == 10) {
play_sound_if_no_flag(m, SOUND_MARIO_EEUH, MARIO_MARIO_SOUND_PLAYED);
}
update_ledge_climb(m, MARIO_ANIM_SLOW_LEDGE_GRAB, ACT_IDLE);
update_ledge_climb_camera(m);
if (m->marioObj->header.gfx.animInfo.animFrame == 17) {
m->action = ACT_LEDGE_CLIMB_SLOW_2;
}
return FALSE;
}
s32 act_ledge_climb_down(struct MarioState *m) {
if (m->input & INPUT_OFF_FLOOR) {
return let_go_of_ledge(m);
}
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
update_ledge_climb(m, MARIO_ANIM_CLIMB_DOWN_LEDGE, ACT_LEDGE_GRAB);
m->actionArg = 1;
return FALSE;
}
s32 act_ledge_climb_fast(struct MarioState *m) {
if (m->input & INPUT_OFF_FLOOR) {
return let_go_of_ledge(m);
}
play_sound_if_no_flag(m, SOUND_MARIO_UH2, MARIO_MARIO_SOUND_PLAYED);
update_ledge_climb(m, MARIO_ANIM_FAST_LEDGE_GRAB, ACT_IDLE);
if (m->marioObj->header.gfx.animInfo.animFrame == 8) {
play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING);
}
update_ledge_climb_camera(m);
return FALSE;
}
s32 act_grabbed(struct MarioState *m) {
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK2) {
s32 thrown = (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK6) == 0;
m->faceAngle[1] = m->usedObj->oMoveAngleYaw;
vec3f_copy(m->pos, m->marioObj->header.gfx.pos);
#ifdef VERSION_SH
queue_rumble_data(5, 60);
#endif
return set_mario_action(m, (m->forwardVel >= 0.0f) ? ACT_THROWN_FORWARD : ACT_THROWN_BACKWARD,
thrown);
}
set_mario_animation(m, MARIO_ANIM_BEING_GRABBED);
return FALSE;
}
s32 act_in_cannon(struct MarioState *m) {
struct Object *marioObj = m->marioObj;
s16 startFacePitch = m->faceAngle[0];
s16 startFaceYaw = m->faceAngle[1];
switch (m->actionState) {
case 0:
m->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
m->usedObj->oInteractStatus = INT_STATUS_INTERACTED;
// m->statusForCamera->cameraEvent = CAM_EVENT_CANNON;
// m->statusForCamera->usedObj = m->usedObj;
vec3f_set(m->vel, 0.0f, 0.0f, 0.0f);
m->pos[0] = m->usedObj->oPosX;
m->pos[1] = m->usedObj->oPosY + 350.0f;
m->pos[2] = m->usedObj->oPosZ;
m->forwardVel = 0.0f;
m->actionState = 1;
break;
case 1:
if (m->usedObj->oAction == 1) {
m->faceAngle[0] = m->usedObj->oMoveAnglePitch;
m->faceAngle[1] = m->usedObj->oMoveAngleYaw;
marioObj->oMarioCannonObjectYaw = m->usedObj->oMoveAngleYaw;
marioObj->oMarioCannonInputYaw = 0;
m->actionState = 2;
}
break;
case 2:
m->faceAngle[0] -= (s16)(m->controller->stickY * 10.0f);
marioObj->oMarioCannonInputYaw -= (s16)(m->controller->stickX * 10.0f);
if (m->faceAngle[0] > 0x38E3) {
m->faceAngle[0] = 0x38E3;
}
if (m->faceAngle[0] < 0) {
m->faceAngle[0] = 0;
}
if (marioObj->oMarioCannonInputYaw > 0x4000) {
marioObj->oMarioCannonInputYaw = 0x4000;
}
if (marioObj->oMarioCannonInputYaw < -0x4000) {
marioObj->oMarioCannonInputYaw = -0x4000;
}
m->faceAngle[1] = marioObj->oMarioCannonObjectYaw + marioObj->oMarioCannonInputYaw;
if (m->input & INPUT_A_PRESSED) {
m->forwardVel = 100.0f * coss(m->faceAngle[0]);
m->vel[1] = 100.0f * sins(m->faceAngle[0]);
m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
m->pos[1] += 120.0f * sins(m->faceAngle[0]);
m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
play_sound(SOUND_ACTION_FLYING_FAST, m->marioObj->header.gfx.cameraToObject);
play_sound(SOUND_OBJ_POUNDING_CANNON, m->marioObj->header.gfx.cameraToObject);
m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);
#ifdef VERSION_SH
queue_rumble_data(60, 70);
#endif
m->usedObj->oAction = 2;
return FALSE;
} else if (m->faceAngle[0] != startFacePitch || m->faceAngle[1] != startFaceYaw) {
play_sound(SOUND_MOVING_AIM_CANNON, m->marioObj->header.gfx.cameraToObject);
#ifdef VERSION_SH
reset_rumble_timers_2(0);
#endif
}
}
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
set_mario_animation(m, MARIO_ANIM_DIVE);
return FALSE;
}
s32 act_tornado_twirling(struct MarioState *m) {
struct Surface *floor;
Vec3f nextPos;
f32 sinAngleVel;
f32 cosAngleVel;
f32 floorHeight;
struct Object *marioObj = m->marioObj;
struct Object *usedObj = m->usedObj;
s16 prevTwirlYaw = m->twirlYaw;
f32 dx = (m->pos[0] - usedObj->oPosX) * 0.95f;
f32 dz = (m->pos[2] - usedObj->oPosZ) * 0.95f;
if (m->vel[1] < 60.0f) {
m->vel[1] += 1.0f;
}
if ((marioObj->oMarioTornadoPosY += m->vel[1]) < 0.0f) {
marioObj->oMarioTornadoPosY = 0.0f;
}
if (marioObj->oMarioTornadoPosY > usedObj->hitboxHeight) {
if (m->vel[1] < 20.0f) {
m->vel[1] = 20.0f;
}
return set_mario_action(m, ACT_TWIRLING, 1);
}
if (m->angleVel[1] < 0x3000) {
m->angleVel[1] += 0x100;
}
if (marioObj->oMarioTornadoYawVel < 0x1000) {
marioObj->oMarioTornadoYawVel += 0x100;
}
m->twirlYaw += m->angleVel[1];
sinAngleVel = sins(marioObj->oMarioTornadoYawVel);
cosAngleVel = coss(marioObj->oMarioTornadoYawVel);
nextPos[0] = usedObj->oPosX + dx * cosAngleVel + dz * sinAngleVel;
nextPos[2] = usedObj->oPosZ - dx * sinAngleVel + dz * cosAngleVel;
nextPos[1] = usedObj->oPosY + marioObj->oMarioTornadoPosY;
f32_find_wall_collision(&nextPos[0], &nextPos[1], &nextPos[2], 60.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
if (floor != NULL) {
m->floor = floor;
m->floorHeight = floorHeight;
vec3f_copy(m->pos, nextPos);
} else {
if (nextPos[1] >= m->floorHeight) {
m->pos[1] = nextPos[1];
} else {
m->pos[1] = m->floorHeight;
}
}
m->actionTimer++;
set_mario_animation(m, (m->actionArg == 0) ? MARIO_ANIM_START_TWIRL : MARIO_ANIM_TWIRL);
if (is_anim_past_end(m)) {
m->actionArg = 1;
}
// Play sound on angle overflow
if (prevTwirlYaw > m->twirlYaw) {
play_sound(SOUND_ACTION_TWIRL, m->marioObj->header.gfx.cameraToObject);
}
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1] + m->twirlYaw, 0);
#ifdef VERSION_SH
reset_rumble_timers();
#endif
return FALSE;
}
s32 check_common_automatic_cancels(struct MarioState *m) {
if (m->pos[1] < m->waterLevel - 100) {
return set_water_plunge_action(m);
}
return FALSE;
}
s32 mario_execute_automatic_action(struct MarioState *m) {
s32 cancel;
if (check_common_automatic_cancels(m)) {
return TRUE;
}
m->quicksandDepth = 0.0f;
/* clang-format off */
switch (m->action) {
case ACT_HOLDING_POLE: cancel = act_holding_pole(m); break;
case ACT_GRAB_POLE_SLOW: cancel = act_grab_pole_slow(m); break;
case ACT_GRAB_POLE_FAST: cancel = act_grab_pole_fast(m); break;
case ACT_CLIMBING_POLE: cancel = act_climbing_pole(m); break;
case ACT_TOP_OF_POLE_TRANSITION: cancel = act_top_of_pole_transition(m); break;
case ACT_TOP_OF_POLE: cancel = act_top_of_pole(m); break;
case ACT_START_HANGING: cancel = act_start_hanging(m); break;
case ACT_HANGING: cancel = act_hanging(m); break;
case ACT_HANG_MOVING: cancel = act_hang_moving(m); break;
case ACT_LEDGE_GRAB: cancel = act_ledge_grab(m); break;
case ACT_LEDGE_CLIMB_SLOW_1: cancel = act_ledge_climb_slow(m); break;
case ACT_LEDGE_CLIMB_SLOW_2: cancel = act_ledge_climb_slow(m); break;
case ACT_LEDGE_CLIMB_DOWN: cancel = act_ledge_climb_down(m); break;
case ACT_LEDGE_CLIMB_FAST: cancel = act_ledge_climb_fast(m); break;
case ACT_GRABBED: cancel = act_grabbed(m); break;
case ACT_IN_CANNON: cancel = act_in_cannon(m); break;
case ACT_TORNADO_TWIRLING: cancel = act_tornado_twirling(m); break;
}
/* clang-format on */
return cancel;
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef MARIO_ACTIONS_AUTOMATIC_H
#define MARIO_ACTIONS_AUTOMATIC_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
s32 mario_execute_automatic_action(struct MarioState *m);
#endif // MARIO_ACTIONS_AUTOMATIC_H
File diff suppressed because it is too large Load Diff
+17
View File
@@ -0,0 +1,17 @@
#ifndef MARIO_ACTIONS_CUTSCENE_H
#define MARIO_ACTIONS_CUTSCENE_H
#include "../include/PR/ultratypes.h"
#include "../include/macros.h"
#include "../include/types.h"
void print_displaying_credits_entry(void);
void bhv_end_peach_loop(void);
void bhv_end_toad_loop(void);
s32 geo_switch_peach_eyes(s32 run, struct GraphNode *node, UNUSED s32 a2);
s32 mario_ready_to_speak(void);
s32 set_mario_npc_dialog(s32 actionArg);
s32 mario_execute_cutscene_action(struct MarioState *m);
#endif // MARIO_ACTIONS_CUTSCENE_H
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
#ifndef MARIO_ACTIONS_MOVING
#define MARIO_ACTIONS_MOVING
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
void play_step_sound(struct MarioState *m, s16 frame1, s16 frame2);
s32 mario_execute_moving_action(struct MarioState *m);
#endif // MARIO_ACTIONS_MOVING
+496
View File
@@ -0,0 +1,496 @@
#include <math.h>
#include "../include/PR/ultratypes.h"
#include "../shim.h"
#include "../include/sm64.h"
#include "mario_actions_object.h"
#include "../include/types.h"
#include "mario_step.h"
#include "mario.h"
//#include "audio/external.h"
#include "interaction.h"
//#include "audio_defines.h"
#include "../engine/math_util.h"
//#include "thread6.h"
#include "../include/mario_animation_ids.h"
#include "../include/object_fields.h"
#include "../include/mario_geo_switch_case_ids.h"
/**
* Used by act_punching() to determine Mario's forward velocity during each
* animation frame.
*/
s8 sPunchingForwardVelocities[8] = { 0, 1, 1, 2, 3, 5, 7, 10 };
void animated_stationary_ground_step(struct MarioState *m, s32 animation, u32 endAction) {
stationary_ground_step(m);
set_mario_animation(m, animation);
if (is_anim_at_end(m)) {
set_mario_action(m, endAction, 0);
}
}
s32 mario_update_punch_sequence(struct MarioState *m) {
u32 endAction, crouchEndAction;
s32 animFrame;
if (m->action & ACT_FLAG_MOVING) {
endAction = ACT_WALKING, crouchEndAction = ACT_CROUCH_SLIDE;
} else {
endAction = ACT_IDLE, crouchEndAction = ACT_CROUCHING;
}
switch (m->actionArg) {
case 0:
play_sound(SOUND_MARIO_PUNCH_YAH, m->marioObj->header.gfx.cameraToObject);
// Fall-through:
case 1:
set_mario_animation(m, MARIO_ANIM_FIRST_PUNCH);
if (is_anim_past_end(m)) {
m->actionArg = 2;
} else {
m->actionArg = 1;
}
if (m->marioObj->header.gfx.animInfo.animFrame >= 2) {
if (mario_check_object_grab(m)) {
return TRUE;
}
m->flags |= MARIO_PUNCHING;
}
if (m->actionArg == 2) {
m->marioBodyState->punchState = (0 << 6) | 4;
}
break;
case 2:
set_mario_animation(m, MARIO_ANIM_FIRST_PUNCH_FAST);
if (m->marioObj->header.gfx.animInfo.animFrame <= 0) {
m->flags |= MARIO_PUNCHING;
}
if (m->input & INPUT_B_PRESSED) {
m->actionArg = 3;
}
if (is_anim_at_end(m)) {
set_mario_action(m, endAction, 0);
}
break;
case 3:
play_sound(SOUND_MARIO_PUNCH_WAH, m->marioObj->header.gfx.cameraToObject);
// Fall-through:
case 4:
set_mario_animation(m, MARIO_ANIM_SECOND_PUNCH);
if (is_anim_past_end(m)) {
m->actionArg = 5;
} else {
m->actionArg = 4;
}
if (m->marioObj->header.gfx.animInfo.animFrame > 0) {
m->flags |= MARIO_PUNCHING;
}
if (m->actionArg == 5) {
m->marioBodyState->punchState = (1 << 6) | 4;
}
break;
case 5:
set_mario_animation(m, MARIO_ANIM_SECOND_PUNCH_FAST);
if (m->marioObj->header.gfx.animInfo.animFrame <= 0) {
m->flags |= MARIO_PUNCHING;
}
if (m->input & INPUT_B_PRESSED) {
m->actionArg = 6;
}
if (is_anim_at_end(m)) {
set_mario_action(m, endAction, 0);
}
break;
case 6:
play_mario_action_sound(m, SOUND_MARIO_PUNCH_HOO, 1);
animFrame = set_mario_animation(m, MARIO_ANIM_GROUND_KICK);
if (animFrame == 0) {
m->marioBodyState->punchState = (2 << 6) | 6;
}
if (animFrame >= 0 && animFrame < 8) {
m->flags |= MARIO_KICKING;
}
if (is_anim_at_end(m)) {
set_mario_action(m, endAction, 0);
}
break;
case 9:
play_mario_action_sound(m, SOUND_MARIO_PUNCH_HOO, 1);
set_mario_animation(m, MARIO_ANIM_BREAKDANCE);
animFrame = m->marioObj->header.gfx.animInfo.animFrame;
if (animFrame >= 2 && animFrame < 8) {
m->flags |= MARIO_TRIPPING;
}
if (is_anim_at_end(m)) {
set_mario_action(m, crouchEndAction, 0);
}
break;
}
return FALSE;
}
s32 act_punching(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE)) {
return check_common_action_exits(m);
}
if (m->actionState == 0 && (m->input & INPUT_A_DOWN)) {
return set_mario_action(m, ACT_JUMP_KICK, 0);
}
m->actionState = 1;
if (m->actionArg == 0) {
m->actionTimer = 7;
}
mario_set_forward_vel(m, sPunchingForwardVelocities[m->actionTimer]);
if (m->actionTimer > 0) {
m->actionTimer--;
}
mario_update_punch_sequence(m);
perform_ground_step(m);
return FALSE;
}
s32 act_picking_up(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & INPUT_OFF_FLOOR) {
return drop_and_set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->actionState == 0 && is_anim_at_end(m)) {
//! While the animation is playing, it is possible for the used object
// to unload. This allows you to pick up a vacant or newly loaded object
// slot (cloning via fake object).
mario_grab_used_object(m);
play_sound_if_no_flag(m, SOUND_MARIO_HRMM, MARIO_MARIO_SOUND_PLAYED);
m->actionState = 1;
}
if (m->actionState == 1) {
if (m->heldObj->oInteractionSubtype & INT_SUBTYPE_GRABS_MARIO) {
m->marioBodyState->grabPos = GRAB_POS_HEAVY_OBJ;
set_mario_animation(m, MARIO_ANIM_GRAB_HEAVY_OBJECT);
if (is_anim_at_end(m)) {
set_mario_action(m, ACT_HOLD_HEAVY_IDLE, 0);
}
} else {
m->marioBodyState->grabPos = GRAB_POS_LIGHT_OBJ;
set_mario_animation(m, MARIO_ANIM_PICK_UP_LIGHT_OBJ);
if (is_anim_at_end(m)) {
set_mario_action(m, ACT_HOLD_IDLE, 0);
}
}
}
stationary_ground_step(m);
return FALSE;
}
s32 act_dive_picking_up(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
//! Hands-free holding. Landing on a slope or being pushed off a ledge while
// landing from a dive grab sets Mario's action to a non-holding action
// without dropping the object, causing the hands-free holding glitch.
if (m->input & INPUT_OFF_FLOOR) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->input & INPUT_ABOVE_SLIDE) {
return set_mario_action(m, ACT_BEGIN_SLIDING, 0);
}
animated_stationary_ground_step(m, MARIO_ANIM_STOP_SLIDE_LIGHT_OBJ, ACT_HOLD_IDLE);
return FALSE;
}
s32 act_placing_down(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & INPUT_OFF_FLOOR) {
return drop_and_set_mario_action(m, ACT_FREEFALL, 0);
}
if (++m->actionTimer == 8) {
mario_drop_held_object(m);
}
animated_stationary_ground_step(m, MARIO_ANIM_PLACE_LIGHT_OBJ, ACT_IDLE);
return FALSE;
}
s32 act_throwing(struct MarioState *m) {
if (m->heldObj && (m->heldObj->oInteractionSubtype & INT_SUBTYPE_HOLDABLE_NPC)) {
return set_mario_action(m, ACT_PLACING_DOWN, 0);
}
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & INPUT_OFF_FLOOR) {
return drop_and_set_mario_action(m, ACT_FREEFALL, 0);
}
if (++m->actionTimer == 7) {
mario_throw_held_object(m);
play_sound_if_no_flag(m, SOUND_MARIO_WAH2, MARIO_MARIO_SOUND_PLAYED);
play_sound_if_no_flag(m, SOUND_ACTION_THROW, MARIO_ACTION_SOUND_PLAYED);
#ifdef VERSION_SH
queue_rumble_data(3, 50);
#endif
}
animated_stationary_ground_step(m, MARIO_ANIM_GROUND_THROW, ACT_IDLE);
return FALSE;
}
s32 act_heavy_throw(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & INPUT_OFF_FLOOR) {
return drop_and_set_mario_action(m, ACT_FREEFALL, 0);
}
if (++m->actionTimer == 13) {
mario_drop_held_object(m);
play_sound_if_no_flag(m, SOUND_MARIO_WAH2, MARIO_MARIO_SOUND_PLAYED);
play_sound_if_no_flag(m, SOUND_ACTION_THROW, MARIO_ACTION_SOUND_PLAYED);
#ifdef VERSION_SH
queue_rumble_data(3, 50);
#endif
}
animated_stationary_ground_step(m, MARIO_ANIM_HEAVY_THROW, ACT_IDLE);
return FALSE;
}
s32 act_stomach_slide_stop(struct MarioState *m) {
if (m->input & INPUT_UNKNOWN_10) {
return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0);
}
if (m->input & INPUT_OFF_FLOOR) {
return set_mario_action(m, ACT_FREEFALL, 0);
}
if (m->input & INPUT_ABOVE_SLIDE) {
return set_mario_action(m, ACT_BEGIN_SLIDING, 0);
}
animated_stationary_ground_step(m, MARIO_ANIM_SLOW_LAND_FROM_DIVE, ACT_IDLE);
return FALSE;
}
s32 act_picking_up_bowser(struct MarioState *m) {
if (m->actionState == 0) {
m->actionState = 1;
m->angleVel[1] = 0;
m->marioBodyState->grabPos = GRAB_POS_BOWSER;
mario_grab_used_object(m);
#ifdef VERSION_SH
queue_rumble_data(5, 80);
#endif
play_sound(SOUND_MARIO_HRMM, m->marioObj->header.gfx.cameraToObject);
}
set_mario_animation(m, MARIO_ANIM_GRAB_BOWSER);
if (is_anim_at_end(m)) {
set_mario_action(m, ACT_HOLDING_BOWSER, 0);
}
stationary_ground_step(m);
return FALSE;
}
s32 act_holding_bowser(struct MarioState *m) {
s16 spin;
if (m->input & INPUT_B_PRESSED) {
#ifndef VERSION_JP
if (m->angleVel[1] <= -0xE00 || m->angleVel[1] >= 0xE00) {
play_sound(SOUND_MARIO_SO_LONGA_BOWSER, m->marioObj->header.gfx.cameraToObject);
} else {
play_sound(SOUND_MARIO_HERE_WE_GO, m->marioObj->header.gfx.cameraToObject);
}
#else
play_sound(SOUND_MARIO_HERE_WE_GO, m->marioObj->header.gfx.cameraToObject);
#endif
return set_mario_action(m, ACT_RELEASING_BOWSER, 0);
}
if (m->angleVel[1] == 0) {
if (m->actionTimer++ > 120) {
return set_mario_action(m, ACT_RELEASING_BOWSER, 1);
}
set_mario_animation(m, MARIO_ANIM_HOLDING_BOWSER);
} else {
m->actionTimer = 0;
set_mario_animation(m, MARIO_ANIM_SWINGING_BOWSER);
}
if (m->intendedMag > 20.0f) {
if (m->actionArg == 0) {
m->actionArg = 1;
m->twirlYaw = m->intendedYaw;
} else {
// spin = acceleration
spin = (s16)(m->intendedYaw - m->twirlYaw) / 0x80;
if (spin < -0x80) {
spin = -0x80;
}
if (spin > 0x80) {
spin = 0x80;
}
m->twirlYaw = m->intendedYaw;
m->angleVel[1] += spin;
if (m->angleVel[1] > 0x1000) {
m->angleVel[1] = 0x1000;
}
if (m->angleVel[1] < -0x1000) {
m->angleVel[1] = -0x1000;
}
}
} else {
m->actionArg = 0;
m->angleVel[1] = approach_s32(m->angleVel[1], 0, 64, 64);
}
// spin = starting yaw
spin = m->faceAngle[1];
m->faceAngle[1] += m->angleVel[1];
// play sound on overflow
if (m->angleVel[1] <= -0x100 && spin < m->faceAngle[1]) {
#ifdef VERSION_SH
queue_rumble_data(4, 20);
#endif
play_sound(SOUND_OBJ_BOWSER_SPINNING, m->marioObj->header.gfx.cameraToObject);
}
if (m->angleVel[1] >= 0x100 && spin > m->faceAngle[1]) {
#ifdef VERSION_SH
queue_rumble_data(4, 20);
#endif
play_sound(SOUND_OBJ_BOWSER_SPINNING, m->marioObj->header.gfx.cameraToObject);
}
stationary_ground_step(m);
if (m->angleVel[1] >= 0) {
m->marioObj->header.gfx.angle[0] = -m->angleVel[1];
} else {
m->marioObj->header.gfx.angle[0] = m->angleVel[1];
}
return FALSE;
}
s32 act_releasing_bowser(struct MarioState *m) {
if (++m->actionTimer == 1) {
if (m->actionArg == 0) {
#ifdef VERSION_SH
queue_rumble_data(4, 50);
#endif
mario_throw_held_object(m);
} else {
#ifdef VERSION_SH
queue_rumble_data(4, 50);
#endif
mario_drop_held_object(m);
}
}
m->angleVel[1] = 0;
animated_stationary_ground_step(m, MARIO_ANIM_RELEASE_BOWSER, ACT_IDLE);
return FALSE;
}
s32 check_common_object_cancels(struct MarioState *m) {
f32 waterSurface = m->waterLevel - 100;
if (m->pos[1] < waterSurface) {
return set_water_plunge_action(m);
}
if (m->input & INPUT_SQUISHED) {
return drop_and_set_mario_action(m, ACT_SQUISHED, 0);
}
if (m->health < 0x100) {
return drop_and_set_mario_action(m, ACT_STANDING_DEATH, 0);
}
return FALSE;
}
s32 mario_execute_object_action(struct MarioState *m) {
s32 cancel;
if (check_common_object_cancels(m)) {
return TRUE;
}
if (mario_update_quicksand(m, 0.5f)) {
return TRUE;
}
/* clang-format off */
switch (m->action) {
case ACT_PUNCHING: cancel = act_punching(m); break;
case ACT_PICKING_UP: cancel = act_picking_up(m); break;
case ACT_DIVE_PICKING_UP: cancel = act_dive_picking_up(m); break;
case ACT_STOMACH_SLIDE_STOP: cancel = act_stomach_slide_stop(m); break;
case ACT_PLACING_DOWN: cancel = act_placing_down(m); break;
case ACT_THROWING: cancel = act_throwing(m); break;
case ACT_HEAVY_THROW: cancel = act_heavy_throw(m); break;
case ACT_PICKING_UP_BOWSER: cancel = act_picking_up_bowser(m); break;
case ACT_HOLDING_BOWSER: cancel = act_holding_bowser(m); break;
case ACT_RELEASING_BOWSER: cancel = act_releasing_bowser(m); break;
}
/* clang-format on */
if (!cancel && (m->input & INPUT_IN_WATER)) {
m->particleFlags |= PARTICLE_IDLE_WATER_WAVE;
}
return cancel;
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef MARIO_ACTIONS_OBJECT_H
#define MARIO_ACTIONS_OBJECT_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
s32 mario_update_punch_sequence(struct MarioState *m);
s32 mario_execute_object_action(struct MarioState *m);
#endif // MARIO_ACTIONS_OBJECT_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,50 @@
#ifndef MARIO_ACTIONS_STATIONARY
#define MARIO_ACTIONS_STATIONARY
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
s32 check_common_idle_cancels(struct MarioState *m);
s32 check_common_hold_idle_cancels(struct MarioState *m);
s32 act_idle(struct MarioState *m);
void play_anim_sound(struct MarioState *m, u32 actionState, s32 animFrame, u32 sound);
s32 act_start_sleeping(struct MarioState *m);
s32 act_sleeping(struct MarioState *m);
s32 act_waking_up(struct MarioState *m);
s32 act_shivering(struct MarioState *m);
s32 act_coughing(struct MarioState *m);
s32 act_standing_against_wall(struct MarioState *m);
s32 act_in_quicksand(struct MarioState *m);
s32 act_crouching(struct MarioState *m);
s32 act_panting(struct MarioState *m);
void stopping_step(struct MarioState *m, s32 animID, u32 action);
s32 act_braking_stop(struct MarioState *m);
s32 act_butt_slide_stop(struct MarioState *m);
s32 act_hold_butt_slide_stop(struct MarioState *m);
s32 act_slide_kick_slide_stop(struct MarioState *m);
s32 act_start_crouching(struct MarioState *m);
s32 act_stop_crouching(struct MarioState *m);
s32 act_start_crawling(struct MarioState *m);
s32 act_stop_crawling(struct MarioState *m);
s32 act_shockwave_bounce(struct MarioState *m);
s32 landing_step(struct MarioState *m, s32 arg1, u32 action);
s32 check_common_landing_cancels(struct MarioState *m, u32 action);
s32 act_jump_land_stop(struct MarioState *m);
s32 act_double_jump_land_stop(struct MarioState *m);
s32 act_side_flip_land_stop(struct MarioState *m);
s32 act_freefall_land_stop(struct MarioState *m);
s32 act_triple_jump_land_stop(struct MarioState *m);
s32 act_backflip_land_stop(struct MarioState *m);
s32 act_lava_boost_land(struct MarioState *m);
s32 act_long_jump_land_stop(struct MarioState *m);
s32 act_hold_jump_land_stop(struct MarioState *m);
s32 act_hold_freefall_land_stop(struct MarioState *m);
s32 act_air_throw_land(struct MarioState *m);
s32 act_twirl_land(struct MarioState *m);
s32 act_ground_pound_land(struct MarioState *m);
s32 act_first_person(struct MarioState *m);
s32 check_common_stationary_cancels(struct MarioState *m);
s32 mario_execute_stationary_action(struct MarioState *m);
#endif // MARIO_ACTIONS_STATIONARY
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
#ifndef MARIO_ACTIONS_SUBMERGED_H
#define MARIO_ACTIONS_SUBMERGED_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
s32 mario_execute_submerged_action(struct MarioState *m);
#endif // MARIO_ACTIONS_SUBMERGED_H
+657
View File
@@ -0,0 +1,657 @@
#include "../include/PR/ultratypes.h"
#include "../include/sm64.h"
#include "area.h"
//#include "audio/external.h"
//#include "behavior_actions.h"
//#include "behavior_data.h"
#include "camera.h"
//#include "dialog_ids.h"
//#include "engine/behavior_script.h"
#include "../engine/graph_node.h"
#include "../engine/math_util.h"
//#include "envfx_snow.h"
//#include "game_init.h"
//#include "goddard/renderer.h"
#include "interaction.h"
#include "level_update.h"
#include "mario_misc.h"
#include "../memory.h"
//#include "object_helpers.h"
//#include "object_list_processor.h"
#include "rendering_graph_node.h"
#include "save_file.h"
//#include "skybox.h"
//#include "sound_init.h"
#include "../shim.h"
#include "../include/mario_animation_ids.h"
#include "../include/object_fields.h"
#include "../include/mario_geo_switch_case_ids.h"
static Vec3f gVec3fZero = {0,0,0};
static Vec3s gVec3sZero = {0,0,0};
static Vec3f gVec3fOne = {1,1,1};
#define TOAD_STAR_1_REQUIREMENT 12
#define TOAD_STAR_2_REQUIREMENT 25
#define TOAD_STAR_3_REQUIREMENT 35
#define TOAD_STAR_1_DIALOG 90 // DIALOG_082
#define TOAD_STAR_2_DIALOG 91 // DIALOG_076
#define TOAD_STAR_3_DIALOG 92 // DIALOG_083
#define TOAD_STAR_1_DIALOG_AFTER 90 // DIALOG_154
#define TOAD_STAR_2_DIALOG_AFTER 91 // DIALOG_155
#define TOAD_STAR_3_DIALOG_AFTER 92 // DIALOG_156
enum ToadMessageStates {
TOAD_MESSAGE_FADED,
TOAD_MESSAGE_OPAQUE,
TOAD_MESSAGE_OPACIFYING,
TOAD_MESSAGE_FADING,
TOAD_MESSAGE_TALKING
};
enum UnlockDoorStarStates {
UNLOCK_DOOR_STAR_RISING,
UNLOCK_DOOR_STAR_WAITING,
UNLOCK_DOOR_STAR_SPAWNING_PARTICLES,
UNLOCK_DOOR_STAR_DONE
};
/**
* The eye texture on succesive frames of Mario's blink animation.
* He intentionally blinks twice each time.
*/
static s8 gMarioBlinkAnimation[7] = { 1, 2, 1, 0, 1, 2, 1 };
/**
* The scale values per frame for Mario's foot/hand for his attack animation
* There are 3 scale animations in groups of 6 frames.
* The first animation starts at frame index 3 and goes down, the others start at frame index 5.
* The values get divided by 10 before assigning, so e.g. 12 gives a scale factor 1.2.
* All combined, this means e.g. the first animation scales Mario's fist by {2.4, 1.6, 1.2, 1.0} on
* successive frames.
*/
static s8 gMarioAttackScaleAnimation[3 * 6] = {
10, 12, 16, 24, 10, 10, 10, 14, 20, 30, 10, 10, 10, 16, 20, 26, 26, 20,
};
struct MarioBodyState gBodyStates[2]; // 2nd is never accessed in practice, most likely Luigi related
//struct GraphNodeObject gMirrorMario; // copy of Mario's geo node for drawing mirror Mario
// This whole file is weirdly organized. It has to be the same file due
// to rodata boundaries and function aligns, which means the programmer
// treated this like a "misc" file for vaguely Mario related things
// (message NPC related things, the Mario head geo, and Mario geo
// functions)
/**
* Geo node script that draws Mario's head on the title screen.
*/
// Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c) {
// Gfx *gfx = NULL;
// s16 sfx = 0;
// struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
// UNUSED Mat4 *transform = c;
//
// if (callContext == GEO_CONTEXT_RENDER) {
// if (gPlayerController->controllerData != NULL && !gWarpTransition.isActive) {
// gd_copy_p1_contpad(gPlayer1Controller->controllerData);
// }
// gfx = (Gfx *) PHYSICAL_TO_VIRTUAL(gdm_gettestdl(asGenerated->parameter));
// D_8032C6A0 = gd_vblank;
// sfx = gd_sfx_to_play();
// play_menu_sounds(sfx);
// }
// return gfx;
// }
static void toad_message_faded(void) {
// if (gCurrentObject->oDistanceToMario > 700.0f) {
// gCurrentObject->oToadMessageRecentlyTalked = FALSE;
// }
// if (!gCurrentObject->oToadMessageRecentlyTalked && gCurrentObject->oDistanceToMario < 600.0f) {
// gCurrentObject->oToadMessageState = TOAD_MESSAGE_OPACIFYING;
// }
}
static void toad_message_opaque(void) {
// if (gCurrentObject->oDistanceToMario > 700.0f) {
// gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING;
// } else if (!gCurrentObject->oToadMessageRecentlyTalked) {
// gCurrentObject->oInteractionSubtype = INT_SUBTYPE_NPC;
// if (gCurrentObject->oInteractStatus & INT_STATUS_INTERACTED) {
// gCurrentObject->oInteractStatus = 0;
// gCurrentObject->oToadMessageState = TOAD_MESSAGE_TALKING;
// play_toads_jingle();
// }
// }
}
static void toad_message_talking(void) {
// if (cur_obj_update_dialog_with_cutscene(3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId)
// != 0) {
// gCurrentObject->oToadMessageRecentlyTalked = TRUE;
// gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING;
// switch (gCurrentObject->oToadMessageDialogId) {
// case TOAD_STAR_1_DIALOG:
// gCurrentObject->oToadMessageDialogId = TOAD_STAR_1_DIALOG_AFTER;
// bhv_spawn_star_no_level_exit(0);
// break;
// case TOAD_STAR_2_DIALOG:
// gCurrentObject->oToadMessageDialogId = TOAD_STAR_2_DIALOG_AFTER;
// bhv_spawn_star_no_level_exit(1);
// break;
// case TOAD_STAR_3_DIALOG:
// gCurrentObject->oToadMessageDialogId = TOAD_STAR_3_DIALOG_AFTER;
// bhv_spawn_star_no_level_exit(2);
// break;
// }
// }
}
static void toad_message_opacifying(void) {
if ((gCurrentObject->oOpacity += 6) == 255) {
gCurrentObject->oToadMessageState = TOAD_MESSAGE_OPAQUE;
}
}
static void toad_message_fading(void) {
if ((gCurrentObject->oOpacity -= 6) == 81) {
gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADED;
}
}
void bhv_toad_message_loop(void) {
if (gCurrentObject->header.gfx.node.flags & GRAPH_RENDER_ACTIVE) {
gCurrentObject->oInteractionSubtype = 0;
switch (gCurrentObject->oToadMessageState) {
case TOAD_MESSAGE_FADED:
toad_message_faded();
break;
case TOAD_MESSAGE_OPAQUE:
toad_message_opaque();
break;
case TOAD_MESSAGE_OPACIFYING:
toad_message_opacifying();
break;
case TOAD_MESSAGE_FADING:
toad_message_fading();
break;
case TOAD_MESSAGE_TALKING:
toad_message_talking();
break;
}
}
}
void bhv_toad_message_init(void) {
// s32 saveFlags = save_file_get_flags();
// s32 starCount = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1);
// s32 dialogId = (gCurrentObject->oBehParams >> 24) & 0xFF;
// s32 enoughStars = TRUE;
//
// switch (dialogId) {
// case TOAD_STAR_1_DIALOG:
// enoughStars = (starCount >= TOAD_STAR_1_REQUIREMENT);
// if (saveFlags & SAVE_FLAG_COLLECTED_TOAD_STAR_1) {
// dialogId = TOAD_STAR_1_DIALOG_AFTER;
// }
// break;
// case TOAD_STAR_2_DIALOG:
// enoughStars = (starCount >= TOAD_STAR_2_REQUIREMENT);
// if (saveFlags & SAVE_FLAG_COLLECTED_TOAD_STAR_2) {
// dialogId = TOAD_STAR_2_DIALOG_AFTER;
// }
// break;
// case TOAD_STAR_3_DIALOG:
// enoughStars = (starCount >= TOAD_STAR_3_REQUIREMENT);
// if (saveFlags & SAVE_FLAG_COLLECTED_TOAD_STAR_3) {
// dialogId = TOAD_STAR_3_DIALOG_AFTER;
// }
// break;
// }
// if (enoughStars) {
// gCurrentObject->oToadMessageDialogId = dialogId;
// gCurrentObject->oToadMessageRecentlyTalked = FALSE;
// gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADED;
// gCurrentObject->oOpacity = 81;
// } else {
// obj_mark_for_deletion(gCurrentObject);
// }
}
//static void star_door_unlock_spawn_particles(s16 angleOffset) {
// struct Object *sparkleParticle = spawn_object(gCurrentObject, 0, bhvSparkleSpawn);
//
// sparkleParticle->oPosX +=
// 100.0f * sins((gCurrentObject->oUnlockDoorStarTimer * 0x2800) + angleOffset);
// sparkleParticle->oPosZ +=
// 100.0f * coss((gCurrentObject->oUnlockDoorStarTimer * 0x2800) + angleOffset);
// // Particles are spawned lower each frame
// sparkleParticle->oPosY -= gCurrentObject->oUnlockDoorStarTimer * 10.0f;
//}
void bhv_unlock_door_star_init(void) {
// gCurrentObject->oUnlockDoorStarState = UNLOCK_DOOR_STAR_RISING;
// gCurrentObject->oUnlockDoorStarTimer = 0;
// gCurrentObject->oUnlockDoorStarYawVel = 0x1000;
// gCurrentObject->oPosX += 30.0f * sins(gMarioState->faceAngle[1] - 0x4000);
// gCurrentObject->oPosY += 160.0f;
// gCurrentObject->oPosZ += 30.0f * coss(gMarioState->faceAngle[1] - 0x4000);
// gCurrentObject->oMoveAngleYaw = 0x7800;
// obj_scale(gCurrentObject, 0.5f);
}
void bhv_unlock_door_star_loop(void) {
// UNUSED u8 unused1[4];
// s16 prevYaw = gCurrentObject->oMoveAngleYaw;
// UNUSED u8 unused2[4];
//
// // Speed up the star every frame
// if (gCurrentObject->oUnlockDoorStarYawVel < 0x2400) {
// gCurrentObject->oUnlockDoorStarYawVel += 0x60;
// }
// switch (gCurrentObject->oUnlockDoorStarState) {
// case UNLOCK_DOOR_STAR_RISING:
// gCurrentObject->oPosY += 3.4f; // Raise the star up in the air
// gCurrentObject->oMoveAngleYaw +=
// gCurrentObject->oUnlockDoorStarYawVel; // Apply yaw velocity
// obj_scale(gCurrentObject, gCurrentObject->oUnlockDoorStarTimer / 50.0f
// + 0.5f); // Scale the star to be bigger
// if (++gCurrentObject->oUnlockDoorStarTimer == 30) {
// gCurrentObject->oUnlockDoorStarTimer = 0;
// gCurrentObject->oUnlockDoorStarState++; // Sets state to UNLOCK_DOOR_STAR_WAITING
// }
// break;
// case UNLOCK_DOOR_STAR_WAITING:
// gCurrentObject->oMoveAngleYaw +=
// gCurrentObject->oUnlockDoorStarYawVel; // Apply yaw velocity
// if (++gCurrentObject->oUnlockDoorStarTimer == 30) {
// play_sound(SOUND_MENU_STAR_SOUND,
// gCurrentObject->header.gfx.cameraToObject); // Play final sound
// cur_obj_hide(); // Hide the object
// gCurrentObject->oUnlockDoorStarTimer = 0;
// gCurrentObject
// ->oUnlockDoorStarState++; // Sets state to UNLOCK_DOOR_STAR_SPAWNING_PARTICLES
// }
// break;
// case UNLOCK_DOOR_STAR_SPAWNING_PARTICLES:
// // Spawn two particles, opposite sides of the star.
// star_door_unlock_spawn_particles(0);
// star_door_unlock_spawn_particles(0x8000);
// if (gCurrentObject->oUnlockDoorStarTimer++ == 20) {
// gCurrentObject->oUnlockDoorStarTimer = 0;
// gCurrentObject->oUnlockDoorStarState++; // Sets state to UNLOCK_DOOR_STAR_DONE
// }
// break;
// case UNLOCK_DOOR_STAR_DONE: // The object stays loaded for an additional 50 frames so that the
// // sound doesn't immediately stop.
// if (gCurrentObject->oUnlockDoorStarTimer++ == 50) {
// obj_mark_for_deletion(gCurrentObject);
// }
// break;
// }
// // Checks if the angle has cycled back to 0.
// // This means that the code will execute when the star completes a full revolution.
// if (prevYaw > (s16) gCurrentObject->oMoveAngleYaw) {
// play_sound(
// SOUND_GENERAL_SHORT_STAR,
// gCurrentObject->header.gfx.cameraToObject); // Play a sound every time the star spins once
// }
}
/**
* Generate a display list that sets the correct blend mode and color for mirror Mario.
*/
static Gfx *make_gfx_mario_alpha(struct GraphNodeGenerated *node, s16 alpha) {
Gfx *gfx;
Gfx *gfxHead = NULL;
if (alpha == 255) {
node->fnNode.node.flags = (node->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8);
gfxHead = alloc_display_list(2 * sizeof(*gfxHead));
gfx = gfxHead;
} else {
node->fnNode.node.flags = (node->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8);
gfxHead = alloc_display_list(3 * sizeof(*gfxHead));
gfx = gfxHead;
gDPSetAlphaCompare(gfx++, G_AC_DITHER);
}
gDPSetEnvColor(gfx++, 255, 255, 255, alpha);
gSPEndDisplayList(gfx);
return gfxHead;
}
/**
* Sets the correct blend mode and color for mirror Mario.
*/
Gfx *geo_mirror_mario_set_alpha(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
UNUSED u8 unused1[4];
Gfx *gfx = NULL;
struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
struct MarioBodyState *bodyState = &gBodyStates[asGenerated->parameter];
s16 alpha;
UNUSED u8 unused2[4];
if (callContext == GEO_CONTEXT_RENDER) {
alpha = (bodyState->modelState & 0x100) ? (bodyState->modelState & 0xFF) : 255;
gfx = make_gfx_mario_alpha(asGenerated, alpha);
}
return gfx;
}
/**
* Determines if Mario is standing or running for the level of detail of his model.
* If Mario is standing still, he is always high poly. If he is running,
* his level of detail depends on the distance to the camera.
*/
Gfx *geo_switch_mario_stand_run(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx) {
struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node;
struct MarioBodyState *bodyState = &gBodyStates[switchCase->numCases];
if (callContext == GEO_CONTEXT_RENDER) {
// assign result. 0 if moving, 1 if stationary.
switchCase->selectedCase = ((bodyState->action & ACT_FLAG_STATIONARY) == 0);
}
return NULL;
}
/**
* Geo node script that makes Mario blink
*/
Gfx *geo_switch_mario_eyes(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node;
struct MarioBodyState *bodyState = &gBodyStates[switchCase->numCases];
s16 blinkFrame;
if (callContext == GEO_CONTEXT_RENDER) {
if (bodyState->eyeState == 0) {
blinkFrame = ((switchCase->numCases * 32 + gAreaUpdateCounter) >> 1) & 0x1F;
if (blinkFrame < 7) {
switchCase->selectedCase = gMarioBlinkAnimation[blinkFrame];
} else {
switchCase->selectedCase = 0;
}
} else {
switchCase->selectedCase = bodyState->eyeState - 1;
}
}
return NULL;
}
/**
* Makes Mario's upper body tilt depending on the rotation stored in his bodyState
*/
Gfx *geo_mario_tilt_torso(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
struct MarioBodyState *bodyState = &gBodyStates[asGenerated->parameter];
s32 action = bodyState->action;
if (callContext == GEO_CONTEXT_RENDER) {
struct GraphNodeRotation *rotNode = (struct GraphNodeRotation *) node->next;
if (action != ACT_BUTT_SLIDE && action != ACT_HOLD_BUTT_SLIDE && action != ACT_WALKING
&& action != ACT_RIDING_SHELL_GROUND) {
vec3s_copy(bodyState->torsoAngle, gVec3sZero);
}
rotNode->rotation[0] = bodyState->torsoAngle[1];
rotNode->rotation[1] = bodyState->torsoAngle[2];
rotNode->rotation[2] = bodyState->torsoAngle[0];
}
return NULL;
}
/**
* Makes Mario's head rotate with the camera angle when in C-up mode
*/
Gfx *geo_mario_head_rotation(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
struct MarioBodyState *bodyState = &gBodyStates[asGenerated->parameter];
// s32 action = bodyState->action;
if (callContext == GEO_CONTEXT_RENDER) {
struct GraphNodeRotation *rotNode = (struct GraphNodeRotation *) node->next;
// struct Camera *camera = gCurGraphNodeCamera->config.camera;
// if (camera->mode == CAMERA_MODE_C_UP) {
// rotNode->rotation[0] = 0; // gPlayerCameraState->headRotation[1]; // PATCH
// rotNode->rotation[2] = 0; // gPlayerCameraState->headRotation[0];
// } else if (action & ACT_FLAG_WATER_OR_TEXT) {
// rotNode->rotation[0] = bodyState->headAngle[1];
// rotNode->rotation[1] = bodyState->headAngle[2];
// rotNode->rotation[2] = bodyState->headAngle[0];
// } else {
vec3s_set(bodyState->headAngle, 0, 0, 0);
vec3s_set(rotNode->rotation, 0, 0, 0);
// }
}
return NULL;
}
/**
* Switch between hand models.
* Possible options are described in the MarioHandGSCId enum.
*/
Gfx *geo_switch_mario_hand(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node;
struct MarioBodyState *bodyState = &gBodyStates[0];
if (callContext == GEO_CONTEXT_RENDER) {
if (bodyState->handState == MARIO_HAND_FISTS) {
// switch between fists (0) and open (1)
switchCase->selectedCase = ((bodyState->action & ACT_FLAG_SWIMMING_OR_FLYING) != 0);
} else {
if (switchCase->numCases == 0) {
switchCase->selectedCase =
(bodyState->handState < 5) ? bodyState->handState : MARIO_HAND_OPEN;
} else {
switchCase->selectedCase =
(bodyState->handState < 2) ? bodyState->handState : MARIO_HAND_FISTS;
}
}
}
return NULL;
}
/**
* Increase Mario's hand / foot size when he punches / kicks.
* Since animation geo nodes only support rotation, this scaling animation
* was scripted separately. The node with this script should be placed before
* a scaling node containing the hand / foot geo layout.
* ! Since the animation gets updated in GEO_CONTEXT_RENDER, drawing Mario multiple times
* (such as in the mirror room) results in a faster and desynced punch / kick animation.
*/
Gfx *geo_mario_hand_foot_scaler(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
static s16 sMarioAttackAnimCounter = 0;
struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
struct GraphNodeScale *scaleNode = (struct GraphNodeScale *) node->next;
struct MarioBodyState *bodyState = &gBodyStates[0];
if (callContext == GEO_CONTEXT_RENDER) {
scaleNode->scale = 1.0f;
if (asGenerated->parameter == bodyState->punchState >> 6) {
if (sMarioAttackAnimCounter != gAreaUpdateCounter && (bodyState->punchState & 0x3F) > 0) {
bodyState->punchState -= 1;
sMarioAttackAnimCounter = gAreaUpdateCounter;
}
scaleNode->scale =
gMarioAttackScaleAnimation[asGenerated->parameter * 6 + (bodyState->punchState & 0x3F)]
/ 10.0f;
}
}
return NULL;
}
/**
* Switch between normal cap, wing cap, vanish cap and metal cap.
*/
Gfx *geo_switch_mario_cap_effect(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node;
struct MarioBodyState *bodyState = &gBodyStates[switchCase->numCases];
if (callContext == GEO_CONTEXT_RENDER) {
switchCase->selectedCase = bodyState->modelState >> 8;
}
return NULL;
}
/**
* Determine whether Mario's head is drawn with or without a cap on.
* Also sets the visibility of the wing cap wings on or off.
*/
Gfx *geo_switch_mario_cap_on_off(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
struct GraphNode *next = node->next;
struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node;
struct MarioBodyState *bodyState = &gBodyStates[switchCase->numCases];
if (callContext == GEO_CONTEXT_RENDER) {
switchCase->selectedCase = bodyState->capState & 1;
while (next != node) {
if (next->type == GRAPH_NODE_TYPE_TRANSLATION_ROTATION) {
if (bodyState->capState & 2) {
next->flags |= GRAPH_RENDER_ACTIVE;
} else {
next->flags &= ~GRAPH_RENDER_ACTIVE;
}
}
next = next->next;
}
}
return NULL;
}
/**
* Geo node script that makes the wings on Mario's wing cap flap.
* Should be placed before a rotation node.
*/
Gfx *geo_mario_rotate_wing_cap_wings(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
s16 rotX;
struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
if (callContext == GEO_CONTEXT_RENDER) {
struct GraphNodeRotation *rotNode = (struct GraphNodeRotation *) node->next;
if (!gBodyStates[asGenerated->parameter >> 1].wingFlutter) {
rotX = (coss((gAreaUpdateCounter & 0xF) << 12) + 1.0f) * 4096.0f;
} else {
rotX = (coss((gAreaUpdateCounter & 7) << 13) + 1.0f) * 6144.0f;
}
if (!(asGenerated->parameter & 1)) {
rotNode->rotation[0] = -rotX;
} else {
rotNode->rotation[0] = rotX;
}
}
return NULL;
}
/**
* Geo node that updates the held object node and the HOLP.
*/
Gfx *geo_switch_mario_hand_grab_pos(s32 callContext, struct GraphNode *b, Mat4 *mtx) {
struct GraphNodeHeldObject *asHeldObj = (struct GraphNodeHeldObject *) b;
Mat4 *curTransform = mtx;
struct MarioState *marioState = gMarioState; // &gMarioStates[asHeldObj->playerIndex]; // PATCH
if (callContext == GEO_CONTEXT_RENDER) {
asHeldObj->objNode = NULL;
if (marioState->heldObj != NULL) {
asHeldObj->objNode = marioState->heldObj;
switch (marioState->marioBodyState->grabPos) {
case GRAB_POS_LIGHT_OBJ:
if (marioState->action & ACT_FLAG_THROWING) {
vec3s_set(asHeldObj->translation, 50, 0, 0);
} else {
vec3s_set(asHeldObj->translation, 50, 0, 110);
}
break;
case GRAB_POS_HEAVY_OBJ:
vec3s_set(asHeldObj->translation, 145, -173, 180);
break;
case GRAB_POS_BOWSER:
vec3s_set(asHeldObj->translation, 80, -270, 1260);
break;
}
}
} else if (callContext == GEO_CONTEXT_HELD_OBJ) {
// ! The HOLP is set here, which is why it only updates when the held object is drawn.
// This is why it won't update during a pause buffered hitstun or when the camera is very far
// away.
get_pos_from_transform_mtx(marioState->marioBodyState->heldObjLastPosition, *curTransform,
*gCurGraphNodeCamera->matrixPtr);
}
return NULL;
}
// X position of the mirror
#define MIRROR_X 4331.53
/**
* Geo node that creates a clone of Mario's geo node and updates it to becomes
* a mirror image of the player.
*/
Gfx *geo_render_mirror_mario(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
// f32 mirroredX;
// struct Object *mario = gMarioState->marioObj; // PATCH gMarioStates[0].marioObj;
// switch (callContext) {
// case GEO_CONTEXT_CREATE:
// init_graph_node_object(NULL, &gMirrorMario, NULL, gVec3fZero, gVec3sZero, gVec3fOne);
// break;
// case GEO_CONTEXT_AREA_LOAD:
// geo_add_child(node, &gMirrorMario.node);
// break;
// case GEO_CONTEXT_AREA_UNLOAD:
// geo_remove_child(&gMirrorMario.node);
// break;
// case GEO_CONTEXT_RENDER:
// if (mario->header.gfx.pos[0] > 1700.0f) {
// // TODO: Is this a geo layout copy or a graph node copy?
// gMirrorMario.sharedChild = mario->header.gfx.sharedChild;
// gMirrorMario.areaIndex = mario->header.gfx.areaIndex;
// vec3s_copy(gMirrorMario.angle, mario->header.gfx.angle);
// vec3f_copy(gMirrorMario.pos, mario->header.gfx.pos);
// vec3f_copy(gMirrorMario.scale, mario->header.gfx.scale);
// gMirrorMario.animInfo = mario->header.gfx.animInfo;
// mirroredX = MIRROR_X - gMirrorMario.pos[0];
// gMirrorMario.pos[0] = mirroredX + MIRROR_X;
// gMirrorMario.angle[1] = -gMirrorMario.angle[1];
// gMirrorMario.scale[0] *= -1.0f;
// ((struct GraphNode *) &gMirrorMario)->flags |= 1;
// } else {
// ((struct GraphNode *) &gMirrorMario)->flags &= ~1;
// }
// break;
// }
// return NULL;
}
/**
* Since Mirror Mario has an x scale of -1, the mesh becomes inside out.
* This node corrects that by changing the culling mode accordingly.
*/
Gfx *geo_mirror_mario_backface_culling(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c) {
// struct GraphNodeGenerated *asGenerated = (struct GraphNodeGenerated *) node;
// Gfx *gfx = NULL;
// if (callContext == GEO_CONTEXT_RENDER && gCurGraphNodeObject == &gMirrorMario) {
// gfx = alloc_display_list(3 * sizeof(*gfx));
// if (asGenerated->parameter == 0) {
// gSPClearGeometryMode(&gfx[0], G_CULL_BACK);
// gSPSetGeometryMode(&gfx[1], G_CULL_FRONT);
// gSPEndDisplayList(&gfx[2]);
// } else {
// gSPClearGeometryMode(&gfx[0], G_CULL_FRONT);
// gSPSetGeometryMode(&gfx[1], G_CULL_BACK);
// gSPEndDisplayList(&gfx[2]);
// }
// asGenerated->fnNode.node.flags = (asGenerated->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8);
// }
// return gfx;
return NULL;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef MARIO_MISC_H
#define MARIO_MISC_H
#include "../include/PR/ultratypes.h"
#include "../include/macros.h"
#include "../include/types.h"
extern struct GraphNodeObject gMirrorMario;
extern struct MarioBodyState gBodyStates[2];
// Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c);
void bhv_toad_message_loop(void);
void bhv_toad_message_init(void);
void bhv_unlock_door_star_init(void);
void bhv_unlock_door_star_loop(void);
Gfx *geo_mirror_mario_set_alpha(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_switch_mario_stand_run(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx);
Gfx *geo_switch_mario_eyes(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_mario_tilt_torso(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_mario_head_rotation(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_switch_mario_hand(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_mario_hand_foot_scaler(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_switch_mario_cap_effect(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_switch_mario_cap_on_off(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_mario_rotate_wing_cap_wings(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_switch_mario_hand_grab_pos(s32 callContext, struct GraphNode *b, Mat4 *mtx);
Gfx *geo_render_mirror_mario(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
Gfx *geo_mirror_mario_backface_culling(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c);
#endif // MARIO_MISC_H
+668
View File
@@ -0,0 +1,668 @@
#include "../shim.h"
#include "../include/sm64.h"
#include "../engine/math_util.h"
#include "../engine/surface_collision.h"
#include "mario.h"
//#include "audio/external.h"
//#include "game_init.h"
#include "interaction.h"
#include "mario_step.h"
static s16 sMovingSandSpeeds[] = { 12, 8, 4, 0 };
struct Surface gWaterSurfacePseudoFloor = {
SURFACE_VERY_SLIPPERY, 0, 0, 0, 0, 0, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0.0f, 1.0f, 0.0f }, 0.0f, NULL,
};
/**
* Always returns zero. This may have been intended
* to be used for the beta trampoline. Its return value
* is used by set_mario_y_vel_based_on_fspeed as a constant
* addition to Mario's Y velocity. Given the closeness of
* this function to stub_mario_step_2, it is probable that this
* was intended to check whether a trampoline had made itself
* known through stub_mario_step_2 and whether Mario was on it,
* and if so return a higher value than 0.
*/
f32 get_additive_y_vel_for_jumps(void) {
return 0.0f;
}
/**
* Does nothing, but takes in a MarioState. This is only ever
* called by update_mario_inputs, which is called as part of Mario's
* update routine. Due to its proximity to stub_mario_step_2, an
* incomplete trampoline function, and get_additive_y_vel_for_jumps,
* a potentially trampoline-related function, it is plausible that
* this could be used for checking if Mario was on the trampoline.
* It could, for example, make him bounce.
*/
void stub_mario_step_1(UNUSED struct MarioState *x) {
}
/**
* Does nothing. This is only called by the beta trampoline.
* Due to its proximity to get_additive_y_vel_for_jumps, another
* currently-pointless function, it is probable that this was used
* by the trampoline to make itself known to get_additive_y_vel_for_jumps,
* or to set a variable with its intended additive Y vel.
*/
void stub_mario_step_2(void) {
}
void transfer_bully_speed(struct BullyCollisionData *obj1, struct BullyCollisionData *obj2) {
f32 rx = obj2->posX - obj1->posX;
f32 rz = obj2->posZ - obj1->posZ;
//! Bully NaN crash
f32 projectedV1 = (rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz);
f32 projectedV2 = (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz);
// Kill speed along r. Convert one object's speed along r and transfer it to
// the other object.
obj2->velX += obj2->conversionRatio * projectedV1 * rx - projectedV2 * -rx;
obj2->velZ += obj2->conversionRatio * projectedV1 * rz - projectedV2 * -rz;
obj1->velX += -projectedV1 * rx + obj1->conversionRatio * projectedV2 * -rx;
obj1->velZ += -projectedV1 * rz + obj1->conversionRatio * projectedV2 * -rz;
//! Bully battery
}
BAD_RETURN(s32) init_bully_collision_data(struct BullyCollisionData *data, f32 posX, f32 posZ,
f32 forwardVel, s16 yaw, f32 conversionRatio, f32 radius) {
if (forwardVel < 0.0f) {
forwardVel *= -1.0f;
yaw += 0x8000;
}
data->radius = radius;
data->conversionRatio = conversionRatio;
data->posX = posX;
data->posZ = posZ;
data->velX = forwardVel * sins(yaw);
data->velZ = forwardVel * coss(yaw);
}
void mario_bonk_reflection(struct MarioState *m, u32 negateSpeed) {
if (m->wall != NULL) {
s16 wallAngle = atan2s(m->wall->normal.z, m->wall->normal.x);
m->faceAngle[1] = wallAngle - (s16)(m->faceAngle[1] - wallAngle);
play_sound((m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_BONK : SOUND_ACTION_BONK,
m->marioObj->header.gfx.cameraToObject);
} else {
play_sound(SOUND_ACTION_HIT, m->marioObj->header.gfx.cameraToObject);
}
if (negateSpeed) {
mario_set_forward_vel(m, -m->forwardVel);
} else {
m->faceAngle[1] += 0x8000;
}
}
u32 mario_update_quicksand(struct MarioState *m, f32 sinkingSpeed) {
if (m->action & ACT_FLAG_RIDING_SHELL) {
m->quicksandDepth = 0.0f;
} else {
if (m->quicksandDepth < 1.1f) {
m->quicksandDepth = 1.1f;
}
switch (m->floor->type) {
case SURFACE_SHALLOW_QUICKSAND:
if ((m->quicksandDepth += sinkingSpeed) >= 10.0f) {
m->quicksandDepth = 10.0f;
}
break;
case SURFACE_SHALLOW_MOVING_QUICKSAND:
if ((m->quicksandDepth += sinkingSpeed) >= 25.0f) {
m->quicksandDepth = 25.0f;
}
break;
case SURFACE_QUICKSAND:
case SURFACE_MOVING_QUICKSAND:
if ((m->quicksandDepth += sinkingSpeed) >= 60.0f) {
m->quicksandDepth = 60.0f;
}
break;
case SURFACE_DEEP_QUICKSAND:
case SURFACE_DEEP_MOVING_QUICKSAND:
if ((m->quicksandDepth += sinkingSpeed) >= 160.0f) {
update_mario_sound_and_camera(m);
return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0);
}
break;
case SURFACE_INSTANT_QUICKSAND:
case SURFACE_INSTANT_MOVING_QUICKSAND:
update_mario_sound_and_camera(m);
return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0);
break;
default:
m->quicksandDepth = 0.0f;
break;
}
}
return FALSE;
}
u32 mario_push_off_steep_floor(struct MarioState *m, u32 action, u32 actionArg) {
s16 floorDYaw = m->floorAngle - m->faceAngle[1];
if (floorDYaw > -0x4000 && floorDYaw < 0x4000) {
m->forwardVel = 16.0f;
m->faceAngle[1] = m->floorAngle;
} else {
m->forwardVel = -16.0f;
m->faceAngle[1] = m->floorAngle + 0x8000;
}
return set_mario_action(m, action, actionArg);
}
u32 mario_update_moving_sand(struct MarioState *m) {
struct Surface *floor = m->floor;
s32 floorType = floor->type;
if (floorType == SURFACE_DEEP_MOVING_QUICKSAND || floorType == SURFACE_SHALLOW_MOVING_QUICKSAND
|| floorType == SURFACE_MOVING_QUICKSAND || floorType == SURFACE_INSTANT_MOVING_QUICKSAND) {
s16 pushAngle = floor->force << 8;
f32 pushSpeed = sMovingSandSpeeds[floor->force >> 8];
m->vel[0] += pushSpeed * sins(pushAngle);
m->vel[2] += pushSpeed * coss(pushAngle);
return TRUE;
}
return FALSE;
}
u32 mario_update_windy_ground(struct MarioState *m) {
struct Surface *floor = m->floor;
if (floor->type == SURFACE_HORIZONTAL_WIND) {
f32 pushSpeed;
s16 pushAngle = floor->force << 8;
if (m->action & ACT_FLAG_MOVING) {
s16 pushDYaw = m->faceAngle[1] - pushAngle;
pushSpeed = m->forwardVel > 0.0f ? -m->forwardVel * 0.5f : -8.0f;
if (pushDYaw > -0x4000 && pushDYaw < 0x4000) {
pushSpeed *= -1.0f;
}
pushSpeed *= coss(pushDYaw);
} else {
pushSpeed = 3.2f + (gGlobalTimer % 4);
}
m->vel[0] += pushSpeed * sins(pushAngle);
m->vel[2] += pushSpeed * coss(pushAngle);
#if VERSION_JP
play_sound(SOUND_ENV_WIND2, m->marioObj->header.gfx.cameraToObject);
#endif
return TRUE;
}
return FALSE;
}
void stop_and_set_height_to_floor(struct MarioState *m) {
struct Object *marioObj = m->marioObj;
mario_set_forward_vel(m, 0.0f);
m->vel[1] = 0.0f;
//! This is responsible for some downwarps.
m->pos[1] = m->floorHeight;
vec3f_copy(marioObj->header.gfx.pos, m->pos);
vec3s_set(marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
}
s32 stationary_ground_step(struct MarioState *m) {
u32 takeStep;
struct Object *marioObj = m->marioObj;
u32 stepResult = GROUND_STEP_NONE;
mario_set_forward_vel(m, 0.0f);
takeStep = mario_update_moving_sand(m);
takeStep |= mario_update_windy_ground(m);
if (takeStep) {
stepResult = perform_ground_step(m);
} else {
//! This is responsible for several stationary downwarps.
m->pos[1] = m->floorHeight;
vec3f_copy(marioObj->header.gfx.pos, m->pos);
vec3s_set(marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
}
return stepResult;
}
static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) {
UNUSED struct Surface *lowerWall;
struct Surface *upperWall;
struct Surface *ceil;
struct Surface *floor;
f32 ceilHeight;
f32 floorHeight;
f32 waterLevel;
lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 24.0f);
upperWall = resolve_and_return_wall_collisions(nextPos, 60.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
waterLevel = find_water_level(nextPos[0], nextPos[2]);
m->wall = upperWall;
if (floor == NULL) {
return GROUND_STEP_HIT_WALL_STOP_QSTEPS;
}
if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) {
floorHeight = waterLevel;
floor = &gWaterSurfacePseudoFloor;
floor->originOffset = floorHeight; //! Wrong origin offset (no effect)
}
if (nextPos[1] > floorHeight + 100.0f) {
if (nextPos[1] + 160.0f >= ceilHeight) {
return GROUND_STEP_HIT_WALL_STOP_QSTEPS;
}
vec3f_copy(m->pos, nextPos);
m->floor = floor;
m->floorHeight = floorHeight;
return GROUND_STEP_LEFT_GROUND;
}
if (floorHeight + 160.0f >= ceilHeight) {
return GROUND_STEP_HIT_WALL_STOP_QSTEPS;
}
vec3f_set(m->pos, nextPos[0], floorHeight, nextPos[2]);
m->floor = floor;
m->floorHeight = floorHeight;
if (upperWall != NULL) {
s16 wallDYaw = atan2s(upperWall->normal.z, upperWall->normal.x) - m->faceAngle[1];
if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) {
return GROUND_STEP_NONE;
}
if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) {
return GROUND_STEP_NONE;
}
return GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS;
}
return GROUND_STEP_NONE;
}
s32 perform_ground_step(struct MarioState *m) {
s32 i;
u32 stepResult;
Vec3f intendedPos;
for (i = 0; i < 4; i++) {
intendedPos[0] = m->pos[0] + m->floor->normal.y * (m->vel[0] / 4.0f);
intendedPos[2] = m->pos[2] + m->floor->normal.y * (m->vel[2] / 4.0f);
intendedPos[1] = m->pos[1];
stepResult = perform_ground_quarter_step(m, intendedPos);
if (stepResult == GROUND_STEP_LEFT_GROUND || stepResult == GROUND_STEP_HIT_WALL_STOP_QSTEPS) {
break;
}
}
m->terrainSoundAddend = mario_get_terrain_sound_addend(m);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) {
stepResult = GROUND_STEP_HIT_WALL;
}
return stepResult;
}
u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos) {
struct Surface *ledgeFloor;
Vec3f ledgePos;
f32 displacementX;
f32 displacementZ;
if (m->vel[1] > 0) {
return FALSE;
}
displacementX = nextPos[0] - intendedPos[0];
displacementZ = nextPos[2] - intendedPos[2];
// Only ledge grab if the wall displaced Mario in the opposite direction of
// his velocity.
if (displacementX * m->vel[0] + displacementZ * m->vel[2] > 0.0f) {
return FALSE;
}
//! Since the search for floors starts at y + 160, we will sometimes grab
// a higher ledge than expected (glitchy ledge grab)
ledgePos[0] = nextPos[0] - wall->normal.x * 60.0f;
ledgePos[2] = nextPos[2] - wall->normal.z * 60.0f;
ledgePos[1] = find_floor(ledgePos[0], nextPos[1] + 160.0f, ledgePos[2], &ledgeFloor);
if (ledgePos[1] - nextPos[1] <= 100.0f) {
return FALSE;
}
vec3f_copy(m->pos, ledgePos);
m->floor = ledgeFloor;
m->floorHeight = ledgePos[1];
m->floorAngle = atan2s(ledgeFloor->normal.z, ledgeFloor->normal.x);
m->faceAngle[0] = 0;
m->faceAngle[1] = atan2s(wall->normal.z, wall->normal.x) + 0x8000;
return TRUE;
}
s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepArg) {
s16 wallDYaw;
Vec3f nextPos;
struct Surface *upperWall;
struct Surface *lowerWall;
struct Surface *ceil;
struct Surface *floor;
f32 ceilHeight;
f32 floorHeight;
f32 waterLevel;
vec3f_copy(nextPos, intendedPos);
upperWall = resolve_and_return_wall_collisions(nextPos, 150.0f, 50.0f);
lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
waterLevel = find_water_level(nextPos[0], nextPos[2]);
m->wall = NULL;
//! The water pseudo floor is not referenced when your intended qstep is
// out of bounds, so it won't detect you as landing.
if (floor == NULL) {
if (nextPos[1] <= m->floorHeight) {
m->pos[1] = m->floorHeight;
return AIR_STEP_LANDED;
}
m->pos[1] = nextPos[1];
return AIR_STEP_HIT_WALL;
}
if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) {
floorHeight = waterLevel;
floor = &gWaterSurfacePseudoFloor;
floor->originOffset = floorHeight; //! Incorrect origin offset (no effect)
}
//! This check uses f32, but findFloor uses short (overflow jumps)
if (nextPos[1] <= floorHeight) {
if (ceilHeight - floorHeight > 160.0f) {
m->pos[0] = nextPos[0];
m->pos[2] = nextPos[2];
m->floor = floor;
m->floorHeight = floorHeight;
}
//! When ceilHeight - floorHeight <= 160, the step result says that
// Mario landed, but his movement is cancelled and his referenced floor
// isn't updated (pedro spots)
m->pos[1] = floorHeight;
return AIR_STEP_LANDED;
}
if (nextPos[1] + 160.0f > ceilHeight) {
if (m->vel[1] >= 0.0f) {
m->vel[1] = 0.0f;
//! Uses referenced ceiling instead of ceil (ceiling hang upwarp)
if ((stepArg & AIR_STEP_CHECK_HANG) && m->ceil != NULL
&& m->ceil->type == SURFACE_HANGABLE) {
return AIR_STEP_GRABBED_CEILING;
}
return AIR_STEP_NONE;
}
//! Potential subframe downwarp->upwarp?
if (nextPos[1] <= m->floorHeight) {
m->pos[1] = m->floorHeight;
return AIR_STEP_LANDED;
}
m->pos[1] = nextPos[1];
return AIR_STEP_HIT_WALL;
}
//! When the wall is not completely vertical or there is a slight wall
// misalignment, you can activate these conditions in unexpected situations
if ((stepArg & AIR_STEP_CHECK_LEDGE_GRAB) && upperWall == NULL && lowerWall != NULL) {
if (check_ledge_grab(m, lowerWall, intendedPos, nextPos)) {
return AIR_STEP_GRABBED_LEDGE;
}
vec3f_copy(m->pos, nextPos);
m->floor = floor;
m->floorHeight = floorHeight;
return AIR_STEP_NONE;
}
vec3f_copy(m->pos, nextPos);
m->floor = floor;
m->floorHeight = floorHeight;
if (upperWall != NULL || lowerWall != NULL) {
m->wall = upperWall != NULL ? upperWall : lowerWall;
wallDYaw = atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1];
if (m->wall->type == SURFACE_BURNING) {
return AIR_STEP_HIT_LAVA_WALL;
}
if (wallDYaw < -0x6000 || wallDYaw > 0x6000) {
m->flags |= MARIO_UNKNOWN_30;
return AIR_STEP_HIT_WALL;
}
}
return AIR_STEP_NONE;
}
void apply_twirl_gravity(struct MarioState *m) {
f32 terminalVelocity;
f32 heaviness = 1.0f;
if (m->angleVel[1] > 1024) {
heaviness = 1024.0f / m->angleVel[1];
}
terminalVelocity = -75.0f * heaviness;
m->vel[1] -= 4.0f * heaviness;
if (m->vel[1] < terminalVelocity) {
m->vel[1] = terminalVelocity;
}
}
u32 should_strengthen_gravity_for_jump_ascent(struct MarioState *m) {
if (!(m->flags & MARIO_UNKNOWN_08)) {
return FALSE;
}
if (m->action & (ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)) {
return FALSE;
}
if (!(m->input & INPUT_A_DOWN) && m->vel[1] > 20.0f) {
return (m->action & ACT_FLAG_CONTROL_JUMP_HEIGHT) != 0;
}
return FALSE;
}
void apply_gravity(struct MarioState *m) {
if (m->action == ACT_TWIRLING && m->vel[1] < 0.0f) {
apply_twirl_gravity(m);
} else if (m->action == ACT_SHOT_FROM_CANNON) {
m->vel[1] -= 1.0f;
if (m->vel[1] < -75.0f) {
m->vel[1] = -75.0f;
}
} else if (m->action == ACT_LONG_JUMP || m->action == ACT_SLIDE_KICK
|| m->action == ACT_BBH_ENTER_SPIN) {
m->vel[1] -= 2.0f;
if (m->vel[1] < -75.0f) {
m->vel[1] = -75.0f;
}
} else if (m->action == ACT_LAVA_BOOST || m->action == ACT_FALL_AFTER_STAR_GRAB) {
m->vel[1] -= 3.2f;
if (m->vel[1] < -65.0f) {
m->vel[1] = -65.0f;
}
} else if (m->action == ACT_GETTING_BLOWN) {
m->vel[1] -= m->unkC4;
if (m->vel[1] < -75.0f) {
m->vel[1] = -75.0f;
}
} else if (should_strengthen_gravity_for_jump_ascent(m)) {
m->vel[1] /= 4.0f;
} else if (m->action & ACT_FLAG_METAL_WATER) {
m->vel[1] -= 1.6f;
if (m->vel[1] < -16.0f) {
m->vel[1] = -16.0f;
}
} else if ((m->flags & MARIO_WING_CAP) && m->vel[1] < 0.0f && (m->input & INPUT_A_DOWN)) {
m->marioBodyState->wingFlutter = TRUE;
m->vel[1] -= 2.0f;
if (m->vel[1] < -37.5f) {
if ((m->vel[1] += 4.0f) > -37.5f) {
m->vel[1] = -37.5f;
}
}
} else {
m->vel[1] -= 4.0f;
if (m->vel[1] < -75.0f) {
m->vel[1] = -75.0f;
}
}
}
void apply_vertical_wind(struct MarioState *m) {
f32 maxVelY;
f32 offsetY;
if (m->action != ACT_GROUND_POUND) {
offsetY = m->pos[1] - -1500.0f;
if (m->floor->type == SURFACE_VERTICAL_WIND && -3000.0f < offsetY && offsetY < 2000.0f) {
if (offsetY >= 0.0f) {
maxVelY = 10000.0f / (offsetY + 200.0f);
} else {
maxVelY = 50.0f;
}
if (m->vel[1] < maxVelY) {
if ((m->vel[1] += maxVelY / 8.0f) > maxVelY) {
m->vel[1] = maxVelY;
}
}
#ifdef VERSION_JP
play_sound(SOUND_ENV_WIND2, m->marioObj->header.gfx.cameraToObject);
#endif
}
}
}
s32 perform_air_step(struct MarioState *m, u32 stepArg) {
Vec3f intendedPos;
s32 i;
s32 quarterStepResult;
s32 stepResult = AIR_STEP_NONE;
m->wall = NULL;
for (i = 0; i < 4; i++) {
intendedPos[0] = m->pos[0] + m->vel[0] / 4.0f;
intendedPos[1] = m->pos[1] + m->vel[1] / 4.0f;
intendedPos[2] = m->pos[2] + m->vel[2] / 4.0f;
quarterStepResult = perform_air_quarter_step(m, intendedPos, stepArg);
//! On one qf, hit OOB/ceil/wall to store the 2 return value, and continue
// getting 0s until your last qf. Graze a wall on your last qf, and it will
// return the stored 2 with a sharply angled reference wall. (some gwks)
if (quarterStepResult != AIR_STEP_NONE) {
stepResult = quarterStepResult;
}
if (quarterStepResult == AIR_STEP_LANDED || quarterStepResult == AIR_STEP_GRABBED_LEDGE
|| quarterStepResult == AIR_STEP_GRABBED_CEILING
|| quarterStepResult == AIR_STEP_HIT_LAVA_WALL) {
break;
}
}
if (m->vel[1] >= 0.0f) {
m->peakHeight = m->pos[1];
}
m->terrainSoundAddend = mario_get_terrain_sound_addend(m);
if (m->action != ACT_FLYING) {
apply_gravity(m);
}
apply_vertical_wind(m);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
return stepResult;
}
// They had these functions the whole time and never used them? Lol
void set_vel_from_pitch_and_yaw(struct MarioState *m) {
m->vel[0] = m->forwardVel * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
m->vel[1] = m->forwardVel * sins(m->faceAngle[0]);
m->vel[2] = m->forwardVel * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
}
void set_vel_from_yaw(struct MarioState *m) {
m->vel[0] = m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);
m->vel[1] = 0.0f;
m->vel[2] = m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef MARIO_STEP_H
#define MARIO_STEP_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
struct BullyCollisionData {
/*0x00*/ f32 conversionRatio;
/*0x04*/ f32 radius;
/*0x08*/ f32 posX;
/*0x0C*/ f32 posZ;
/*0x10*/ f32 velX;
/*0x14*/ f32 velZ;
};
extern struct Surface gWaterSurfacePseudoFloor;
f32 get_additive_y_vel_for_jumps(void);
void stub_mario_step_1(struct MarioState *);
void stub_mario_step_2(void);
void mario_bonk_reflection(struct MarioState *, u32);
void transfer_bully_speed(struct BullyCollisionData *obj1, struct BullyCollisionData *obj2);
BAD_RETURN(s32) init_bully_collision_data(struct BullyCollisionData *data, f32 posX, f32 posZ,
f32 forwardVel, s16 yaw, f32 conversionRatio, f32 radius);
u32 mario_update_quicksand(struct MarioState *, f32);
u32 mario_push_off_steep_floor(struct MarioState *, u32, u32);
u32 mario_update_moving_sand(struct MarioState *);
u32 mario_update_windy_ground(struct MarioState *);
void stop_and_set_height_to_floor(struct MarioState *);
s32 stationary_ground_step(struct MarioState *);
s32 perform_ground_step(struct MarioState *);
s32 perform_air_step(struct MarioState *, u32);
#endif // MARIO_STEP_H
+308
View File
@@ -0,0 +1,308 @@
/**
* This file just hacks a bunch of stuff together to get a valid Object and GraphNode for Mario
*/
#include <stdlib.h>
#include "mario.h"
#include "../shim.h"
#include "../engine/math_util.h"
#include "../include/object_fields.h"
/* activeFlags */
#define ACTIVE_FLAG_DEACTIVATED 0 // 0x0000
#define ACTIVE_FLAG_ACTIVE (1 << 0) // 0x0001
#define ACTIVE_FLAG_FAR_AWAY (1 << 1) // 0x0002
#define ACTIVE_FLAG_UNK2 (1 << 2) // 0x0004
#define ACTIVE_FLAG_IN_DIFFERENT_ROOM (1 << 3) // 0x0008
#define ACTIVE_FLAG_UNIMPORTANT (1 << 4) // 0x0010
#define ACTIVE_FLAG_INITIATED_TIME_STOP (1 << 5) // 0x0020
#define ACTIVE_FLAG_MOVE_THROUGH_GRATE (1 << 6) // 0x0040
#define ACTIVE_FLAG_DITHERED_ALPHA (1 << 7) // 0x0080
#define ACTIVE_FLAG_UNK8 (1 << 8) // 0x0100
#define ACTIVE_FLAG_UNK9 (1 << 9) // 0x0200
#define ACTIVE_FLAG_UNK10 (1 << 10) // 0x0400
// The discriminant for different types of geo nodes
#define GRAPH_NODE_TYPE_ROOT 0x001
#define GRAPH_NODE_TYPE_ORTHO_PROJECTION 0x002
#define GRAPH_NODE_TYPE_PERSPECTIVE (0x003 | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_MASTER_LIST 0x004
#define GRAPH_NODE_TYPE_START 0x00A
#define GRAPH_NODE_TYPE_LEVEL_OF_DETAIL 0x00B
#define GRAPH_NODE_TYPE_SWITCH_CASE (0x00C | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_CAMERA (0x014 | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_TRANSLATION_ROTATION 0x015
#define GRAPH_NODE_TYPE_TRANSLATION 0x016
#define GRAPH_NODE_TYPE_ROTATION 0x017
#define GRAPH_NODE_TYPE_OBJECT 0x018
#define GRAPH_NODE_TYPE_ANIMATED_PART 0x019
#define GRAPH_NODE_TYPE_BILLBOARD 0x01A
#define GRAPH_NODE_TYPE_DISPLAY_LIST 0x01B
#define GRAPH_NODE_TYPE_SCALE 0x01C
#define GRAPH_NODE_TYPE_SHADOW 0x028
#define GRAPH_NODE_TYPE_OBJECT_PARENT 0x029
#define GRAPH_NODE_TYPE_GENERATED_LIST (0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_BACKGROUND (0x02C | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_HELD_OBJ (0x02E | GRAPH_NODE_TYPE_FUNCTIONAL)
#define GRAPH_NODE_TYPE_CULLING_RADIUS 0x02F
/* respawnInfoType */
#define RESPAWN_INFO_TYPE_NULL 0
#define RESPAWN_INFO_TYPE_32 1
#define RESPAWN_INFO_TYPE_16 2
#define GRAPH_RENDER_ACTIVE (1 << 0)
#define GRAPH_RENDER_CHILDREN_FIRST (1 << 1)
#define GRAPH_RENDER_BILLBOARD (1 << 2)
#define GRAPH_RENDER_Z_BUFFER (1 << 3)
#define GRAPH_RENDER_INVISIBLE (1 << 4)
#define GRAPH_RENDER_HAS_ANIMATION (1 << 5)
static Vec3f gVec3fZero = { 0.0f, 0.0f, 0.0f };
static Vec3s gVec3sZero = { 0, 0, 0 };
static Vec3f gVec3fOne = { 1.0f, 1.0f, 1.0f };
static struct GraphNodeObject *init_graph_node_object( Vec3f pos, Vec3s angle, Vec3f scale) {
struct GraphNodeObject *graphNode = malloc(sizeof(struct GraphNodeObject));
//init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT);
graphNode->node.type = GRAPH_NODE_TYPE_OBJECT;
graphNode->node.flags = GRAPH_RENDER_ACTIVE;
graphNode->node.prev = &graphNode->node;
graphNode->node.next = &graphNode->node;
graphNode->node.parent = NULL;
graphNode->node.children = NULL;
vec3f_copy(graphNode->pos, pos);
vec3f_copy(graphNode->scale, scale);
vec3s_copy(graphNode->angle, angle);
vec3f_copy(graphNode->cameraToObject, gVec3fZero);
graphNode->sharedChild = NULL;
graphNode->throwMatrix = NULL;
graphNode->animInfo.animID = 0;
graphNode->animInfo.curAnim = NULL;
graphNode->animInfo.animFrame = 0;
graphNode->animInfo.animFrameAccelAssist = 0;
graphNode->animInfo.animAccel = 0x10000;
graphNode->animInfo.animTimer = 0;
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
return graphNode;
}
static struct Object *try_allocate_object(void) {
struct ObjectNode *nextObj;
nextObj = (struct ObjectNode *) malloc(sizeof(struct Object));
nextObj->prev = NULL;
nextObj->next = NULL;
init_graph_node_object(gVec3fZero, gVec3sZero, gVec3fOne);
return (struct Object *) nextObj;
}
static struct Object *allocate_object(void) {
s32 i;
struct Object *obj = try_allocate_object();
// Initialize object fields
obj->activeFlags = ACTIVE_FLAG_ACTIVE | ACTIVE_FLAG_UNK8;
obj->parentObj = obj;
obj->prevObj = NULL;
obj->collidedObjInteractTypes = 0;
obj->numCollidedObjs = 0;
for (i = 0; i < 0x50; i++) {
obj->rawData.asS32[i] = 0;
obj->ptrData.asVoidPtr[i] = NULL;
}
obj->unused1 = 0;
obj->bhvStackIndex = 0;
obj->bhvDelayTimer = 0;
obj->hitboxRadius = 37.0f; // Override directly for Mario
obj->hitboxHeight = 160.0f; //
obj->hurtboxRadius = 0.0f;
obj->hurtboxHeight = 0.0f;
obj->hitboxDownOffset = 0.0f;
obj->unused2 = 0;
obj->platform = NULL;
obj->collisionData = NULL;
obj->oIntangibleTimer = -1;
obj->oDamageOrCoinValue = 0;
obj->oHealth = 2048;
obj->oCollisionDistance = 1000.0f;
if (gCurrLevelNum == LEVEL_TTC) {
obj->oDrawingDistance = 2000.0f;
} else {
obj->oDrawingDistance = 4000.0f;
}
mtxf_identity(obj->transform);
obj->respawnInfoType = RESPAWN_INFO_TYPE_NULL;
obj->respawnInfo = NULL;
obj->oDistanceToMario = 19000.0f;
obj->oRoom = -1;
obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
obj->header.gfx.pos[0] = -10000.0f;
obj->header.gfx.pos[1] = -10000.0f;
obj->header.gfx.pos[2] = -10000.0f;
obj->header.gfx.throwMatrix = NULL;
return obj;
}
static struct Object *create_object(void) {
struct Object *obj;
obj = allocate_object();
obj->curBhvCommand = NULL;
obj->behavior = NULL;
return obj;
}
static void geo_obj_init(struct GraphNodeObject *graphNode, void *sharedChild, Vec3f pos, Vec3s angle) {
vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f);
vec3f_copy(graphNode->pos, pos);
vec3s_copy(graphNode->angle, angle);
graphNode->sharedChild = sharedChild;
graphNode->unk4C = 0;
graphNode->throwMatrix = NULL;
graphNode->animInfo.curAnim = NULL;
graphNode->node.flags |= GRAPH_RENDER_ACTIVE;
graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE;
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD;
}
static struct Object *spawn_object_at_origin(void) {
struct Object *obj;
obj = create_object();
obj->parentObj = NULL;
obj->header.gfx.areaIndex = 0;
obj->header.gfx.activeAreaIndex = 0;
// geo_obj_init((struct GraphNodeObject *) &obj->header.gfx, gLoadedGraphNodes[model], gVec3fZero, gVec3sZero);
geo_obj_init((struct GraphNodeObject *) &obj->header.gfx, NULL, gVec3fZero, gVec3sZero);
return obj;
}
/**
* Copy position, velocity, and angle variables from MarioState to the Mario
* object.
*/
static void copy_mario_state_to_object(void) {
s32 i = 0;
// L is real
if (gCurrentObject != gMarioObject) {
i += 1;
}
gCurrentObject->oVelX = gMarioState->vel[0];
gCurrentObject->oVelY = gMarioState->vel[1];
gCurrentObject->oVelZ = gMarioState->vel[2];
gCurrentObject->oPosX = gMarioState->pos[0];
gCurrentObject->oPosY = gMarioState->pos[1];
gCurrentObject->oPosZ = gMarioState->pos[2];
gCurrentObject->oMoveAnglePitch = gCurrentObject->header.gfx.angle[0];
gCurrentObject->oMoveAngleYaw = gCurrentObject->header.gfx.angle[1];
gCurrentObject->oMoveAngleRoll = gCurrentObject->header.gfx.angle[2];
gCurrentObject->oFaceAnglePitch = gCurrentObject->header.gfx.angle[0];
gCurrentObject->oFaceAngleYaw = gCurrentObject->header.gfx.angle[1];
gCurrentObject->oFaceAngleRoll = gCurrentObject->header.gfx.angle[2];
gCurrentObject->oAngleVelPitch = gMarioState->angleVel[0];
gCurrentObject->oAngleVelYaw = gMarioState->angleVel[1];
gCurrentObject->oAngleVelRoll = gMarioState->angleVel[2];
}
struct Object *hack_allocate_mario(void)
{
return spawn_object_at_origin();
}
/**
* Mario's primary behavior update function.
*/
void bhv_mario_update(void) {
u32 particleFlags = 0;
// s32 i;
gCurrentObject = gMarioObject;
particleFlags = execute_mario_action(gCurrentObject);
gCurrentObject->oMarioParticleFlags = particleFlags;
// Mario code updates MarioState's versions of position etc, so we need
// to sync it with the Mario object
copy_mario_state_to_object();
// i = 0;
// while (sParticleTypes[i].particleFlag != 0) {
// if (particleFlags & sParticleTypes[i].particleFlag) {
// spawn_particle(sParticleTypes[i].activeParticleFlag, sParticleTypes[i].model,
// sParticleTypes[i].behavior);
// }
// i++;
// }
}
void create_transformation_from_matrices(Mat4 a0, Mat4 a1, Mat4 a2) {
f32 spC, sp8, sp4;
spC = a2[3][0] * a2[0][0] + a2[3][1] * a2[0][1] + a2[3][2] * a2[0][2];
sp8 = a2[3][0] * a2[1][0] + a2[3][1] * a2[1][1] + a2[3][2] * a2[1][2];
sp4 = a2[3][0] * a2[2][0] + a2[3][1] * a2[2][1] + a2[3][2] * a2[2][2];
a0[0][0] = a1[0][0] * a2[0][0] + a1[0][1] * a2[0][1] + a1[0][2] * a2[0][2];
a0[0][1] = a1[0][0] * a2[1][0] + a1[0][1] * a2[1][1] + a1[0][2] * a2[1][2];
a0[0][2] = a1[0][0] * a2[2][0] + a1[0][1] * a2[2][1] + a1[0][2] * a2[2][2];
a0[1][0] = a1[1][0] * a2[0][0] + a1[1][1] * a2[0][1] + a1[1][2] * a2[0][2];
a0[1][1] = a1[1][0] * a2[1][0] + a1[1][1] * a2[1][1] + a1[1][2] * a2[1][2];
a0[1][2] = a1[1][0] * a2[2][0] + a1[1][1] * a2[2][1] + a1[1][2] * a2[2][2];
a0[2][0] = a1[2][0] * a2[0][0] + a1[2][1] * a2[0][1] + a1[2][2] * a2[0][2];
a0[2][1] = a1[2][0] * a2[1][0] + a1[2][1] * a2[1][1] + a1[2][2] * a2[1][2];
a0[2][2] = a1[2][0] * a2[2][0] + a1[2][1] * a2[2][1] + a1[2][2] * a2[2][2];
a0[3][0] = a1[3][0] * a2[0][0] + a1[3][1] * a2[0][1] + a1[3][2] * a2[0][2] - spC;
a0[3][1] = a1[3][0] * a2[1][0] + a1[3][1] * a2[1][1] + a1[3][2] * a2[1][2] - sp8;
a0[3][2] = a1[3][0] * a2[2][0] + a1[3][1] * a2[2][1] + a1[3][2] * a2[2][2] - sp4;
a0[0][3] = 0;
a0[1][3] = 0;
a0[2][3] = 0;
a0[3][3] = 1.0f;
}
void obj_update_pos_from_parent_transformation(Mat4 a0, struct Object *a1) {
f32 spC = a1->oParentRelativePosX;
f32 sp8 = a1->oParentRelativePosY;
f32 sp4 = a1->oParentRelativePosZ;
a1->oPosX = spC * a0[0][0] + sp8 * a0[1][0] + sp4 * a0[2][0] + a0[3][0];
a1->oPosY = spC * a0[0][1] + sp8 * a0[1][1] + sp4 * a0[2][1] + a0[3][1];
a1->oPosZ = spC * a0[0][2] + sp8 * a0[1][2] + sp4 * a0[2][2] + a0[3][2];
}
void obj_set_gfx_pos_from_pos(struct Object *obj) {
obj->header.gfx.pos[0] = obj->oPosX;
obj->header.gfx.pos[1] = obj->oPosY;
obj->header.gfx.pos[2] = obj->oPosZ;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "../include/types.h"
struct Object *hack_allocate_mario(void);
void bhv_mario_update(void);
void create_transformation_from_matrices(Mat4 a0, Mat4 a1, Mat4 a2);
void obj_update_pos_from_parent_transformation(Mat4 a0, struct Object *a1);
void obj_set_gfx_pos_from_pos(struct Object *obj);
+181
View File
@@ -0,0 +1,181 @@
#include <math.h>
#include "../engine/math_util.h"
#include "../engine/surface_collision.h"
#include "level_update.h"
#include "../include/object_fields.h"
#include "object_stuff.h"
#include "platform_displacement.h"
#include "../shim.h"
struct SurfaceObjectTransform *gMarioPlatform = NULL;
#define absfx( x ) ( (x) < 0.0f ? -(x) : (x) )
/**
* Determine if Mario is standing on a platform object, meaning that he is
* within 4 units of the floor. Set his referenced platform object accordingly.
*/
void update_mario_platform(void) {
struct Surface *floor;
UNUSED u32 unused;
f32 marioX;
f32 marioY;
f32 marioZ;
f32 floorHeight;
u32 awayFromFloor;
if (gMarioObject == NULL) {
return;
}
//! If Mario moves onto a rotating platform in a PU, the find_floor call
// will detect the platform and he will end up receiving a large amount
// of displacement since he is considered to be far from the platform's
// axis of rotation.
marioX = gMarioObject->oPosX;
marioY = gMarioObject->oPosY;
marioZ = gMarioObject->oPosZ;
floorHeight = find_floor(marioX, marioY, marioZ, &floor);
if (absfx(marioY - floorHeight) < 4.0f) {
awayFromFloor = 0;
} else {
awayFromFloor = 1;
}
switch (awayFromFloor) {
case 1:
gMarioPlatform = NULL;
gMarioObject->platform = NULL;
break;
case 0:
if (floor != NULL && floor->object != NULL) {
gMarioPlatform = (struct SurfaceObjectTransform *)floor->object;
gMarioObject->platform = floor->object;
} else {
gMarioPlatform = NULL;
gMarioObject->platform = NULL;
}
break;
}
}
/**
* Get Mario's position and store it in x, y, and z.
*/
static void get_mario_pos(f32 *x, f32 *y, f32 *z) {
*x = gMarioState->pos[0];
*y = gMarioState->pos[1];
*z = gMarioState->pos[2];
}
/**
* Set Mario's position.
*/
static void set_mario_pos(f32 x, f32 y, f32 z) {
gMarioState->pos[0] = x;
gMarioState->pos[1] = y;
gMarioState->pos[2] = z;
}
/**
* Apply one frame of platform rotation to Mario or an object using the given
* platform. If isMario is false, use gCurrentObject.
*/
void apply_platform_displacement(u32 isMario, struct SurfaceObjectTransform *platform) {
f32 x;
f32 y;
f32 z;
f32 platformPosX;
f32 platformPosY;
f32 platformPosZ;
Vec3f currentObjectOffset;
Vec3f relativeOffset;
Vec3f newObjectOffset;
Vec3s rotation;
UNUSED s16 unused1;
UNUSED s16 unused2;
UNUSED s16 unused3;
f32 displaceMatrix[4][4];
rotation[0] = platform->aAngleVelPitch;
rotation[1] = platform->aAngleVelYaw;
rotation[2] = platform->aAngleVelRoll;
// if (isMario) {
// D_8032FEC0 = 0;
get_mario_pos(&x, &y, &z);
// } else {
// x = gCurrentObject->aPosX;
// y = gCurrentObject->aPosY;
// z = gCurrentObject->aPosZ;
// }
x += platform->aVelX;
z += platform->aVelZ;
if (rotation[0] != 0 || rotation[1] != 0 || rotation[2] != 0) {
unused1 = rotation[0];
unused2 = rotation[2];
unused3 = platform->aFaceAngleYaw;
if (isMario) {
gMarioState->faceAngle[1] += rotation[1];
}
platformPosX = platform->aPosX;
platformPosY = platform->aPosY;
platformPosZ = platform->aPosZ;
currentObjectOffset[0] = x - platformPosX;
currentObjectOffset[1] = y - platformPosY;
currentObjectOffset[2] = z - platformPosZ;
rotation[0] = platform->aFaceAnglePitch - platform->aAngleVelPitch;
rotation[1] = platform->aFaceAngleYaw - platform->aAngleVelYaw;
rotation[2] = platform->aFaceAngleRoll - platform->aAngleVelRoll;
mtxf_rotate_zxy_and_translate(displaceMatrix, currentObjectOffset, rotation);
linear_mtxf_transpose_mul_vec3f(displaceMatrix, relativeOffset, currentObjectOffset);
rotation[0] = platform->aFaceAnglePitch;
rotation[1] = platform->aFaceAngleYaw;
rotation[2] = platform->aFaceAngleRoll;
mtxf_rotate_zxy_and_translate(displaceMatrix, currentObjectOffset, rotation);
linear_mtxf_mul_vec3f(displaceMatrix, newObjectOffset, relativeOffset);
x = platformPosX + newObjectOffset[0];
y = platformPosY + newObjectOffset[1];
z = platformPosZ + newObjectOffset[2];
}
// if (isMario) {
set_mario_pos(x, y, z);
// } else {
// gCurrentObject->oPosX = x;
// gCurrentObject->oPosY = y;
// gCurrentObject->oPosZ = z;
// }
}
/**
* If Mario's platform is not null, apply platform displacement.
*/
void apply_mario_platform_displacement(void) {
struct SurfaceObjectTransform *platform = gMarioPlatform;
if (gMarioObject != NULL && platform != NULL) {
apply_platform_displacement(TRUE, platform);
}
}
/**
* Set Mario's platform to NULL.
*/
void clear_mario_platform(void) {
gMarioPlatform = NULL;
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef PLATFORM_DISPLACEMENT_H
#define PLATFORM_DISPLACEMENT_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
void update_mario_platform(void);
void apply_mario_platform_displacement(void);
void clear_mario_platform(void);
#endif // PLATFORM_DISPLACEMENT_H
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
#ifndef RENDERING_GRAPH_NODE_H
#define RENDERING_GRAPH_NODE_H
#include "../include/PR/ultratypes.h"
#include "../engine/graph_node.h"
extern struct GraphNodeRoot *gCurGraphNodeRoot;
extern struct GraphNodeMasterList *gCurGraphNodeMasterList;
extern struct GraphNodePerspective *gCurGraphNodeCamFrustum;
extern struct GraphNodeCamera *gCurGraphNodeCamera;
extern struct GraphNodeObject *gCurGraphNodeObject;
extern struct GraphNodeHeldObject *gCurGraphNodeHeldObject;
extern u16 gAreaUpdateCounter;
// after processing an object, the type is reset to this
#define ANIM_TYPE_NONE 0
// Not all parts have full animation: to save space, some animations only
// have xz, y, or no translation at all. All animations have rotations though
#define ANIM_TYPE_TRANSLATION 1
#define ANIM_TYPE_VERTICAL_TRANSLATION 2
#define ANIM_TYPE_LATERAL_TRANSLATION 3
#define ANIM_TYPE_NO_TRANSLATION 4
// Every animation includes rotation, after processing any of the above
// translation types the type is set to this
#define ANIM_TYPE_ROTATION 5
void geo_process_node_and_siblings(struct GraphNode *firstNode);
//void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor);
void geo_process_root_hack_single_node(struct GraphNode *node);
#endif // RENDERING_GRAPH_NODE_H
+175
View File
@@ -0,0 +1,175 @@
#ifndef SAVE_FILE_H
#define SAVE_FILE_H
#include "../include/PR/ultratypes.h"
#include "../include/types.h"
#include "area.h"
// #include "course_table.h"
// ===== PATCH =====
#define COURSE_COUNT 120
#define COURSE_STAGES_COUNT 15
// =================
#define EEPROM_SIZE 0x200
#define NUM_SAVE_FILES 4
struct SaveBlockSignature
{
u16 magic;
u16 chksum;
};
struct SaveFile
{
// Location of lost cap.
// Note: the coordinates get set, but are never actually used, since the
// cap can always be found in a fixed spot within the course
u8 capLevel;
u8 capArea;
Vec3s capPos;
u32 flags;
// Star flags for each course.
// The most significant bit of the byte *following* each course is set if the
// cannon is open.
u8 courseStars[COURSE_COUNT];
u8 courseCoinScores[COURSE_STAGES_COUNT];
struct SaveBlockSignature signature;
};
enum SaveFileIndex {
SAVE_FILE_A,
SAVE_FILE_B,
SAVE_FILE_C,
SAVE_FILE_D
};
struct MainMenuSaveData
{
// Each save file has a 2 bit "age" for each course. The higher this value,
// the older the high score is. This is used for tie-breaking when displaying
// on the high score screen.
u32 coinScoreAges[NUM_SAVE_FILES];
u16 soundMode;
#ifdef VERSION_EU
u16 language;
#define SUBTRAHEND 8
#else
#define SUBTRAHEND 6
#endif
// Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU)
u8 filler[ 128 ]; // EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))];
struct SaveBlockSignature signature;
};
struct SaveBuffer
{
// Each of the four save files has two copies. If one is bad, the other is used as a backup.
struct SaveFile files[NUM_SAVE_FILES][2];
// The main menu data has two copies. If one is bad, the other is used as a backup.
// struct MainMenuSaveData menuData[0];
};
extern u8 gLastCompletedCourseNum;
extern u8 gLastCompletedStarNum;
extern s8 sUnusedGotGlobalCoinHiScore;
extern u8 gGotFileCoinHiScore;
extern u8 gCurrCourseStarFlags;
extern u8 gSpecialTripleJump;
extern s8 gLevelToCourseNumTable[];
// game progress flags
#define SAVE_FLAG_FILE_EXISTS /* 0x00000001 */ (1 << 0)
#define SAVE_FLAG_HAVE_WING_CAP /* 0x00000002 */ (1 << 1)
#define SAVE_FLAG_HAVE_METAL_CAP /* 0x00000004 */ (1 << 2)
#define SAVE_FLAG_HAVE_VANISH_CAP /* 0x00000008 */ (1 << 3)
#define SAVE_FLAG_HAVE_KEY_1 /* 0x00000010 */ (1 << 4)
#define SAVE_FLAG_HAVE_KEY_2 /* 0x00000020 */ (1 << 5)
#define SAVE_FLAG_UNLOCKED_BASEMENT_DOOR /* 0x00000040 */ (1 << 6)
#define SAVE_FLAG_UNLOCKED_UPSTAIRS_DOOR /* 0x00000080 */ (1 << 7)
#define SAVE_FLAG_DDD_MOVED_BACK /* 0x00000100 */ (1 << 8)
#define SAVE_FLAG_MOAT_DRAINED /* 0x00000200 */ (1 << 9)
#define SAVE_FLAG_UNLOCKED_PSS_DOOR /* 0x00000400 */ (1 << 10)
#define SAVE_FLAG_UNLOCKED_WF_DOOR /* 0x00000800 */ (1 << 11)
#define SAVE_FLAG_UNLOCKED_CCM_DOOR /* 0x00001000 */ (1 << 12)
#define SAVE_FLAG_UNLOCKED_JRB_DOOR /* 0x00002000 */ (1 << 13)
#define SAVE_FLAG_UNLOCKED_BITDW_DOOR /* 0x00004000 */ (1 << 14)
#define SAVE_FLAG_UNLOCKED_BITFS_DOOR /* 0x00008000 */ (1 << 15)
#define SAVE_FLAG_CAP_ON_GROUND /* 0x00010000 */ (1 << 16)
#define SAVE_FLAG_CAP_ON_KLEPTO /* 0x00020000 */ (1 << 17)
#define SAVE_FLAG_CAP_ON_UKIKI /* 0x00040000 */ (1 << 18)
#define SAVE_FLAG_CAP_ON_MR_BLIZZARD /* 0x00080000 */ (1 << 19)
#define SAVE_FLAG_UNLOCKED_50_STAR_DOOR /* 0x00100000 */ (1 << 20)
#define SAVE_FLAG_COLLECTED_TOAD_STAR_1 /* 0x01000000 */ (1 << 24)
#define SAVE_FLAG_COLLECTED_TOAD_STAR_2 /* 0x02000000 */ (1 << 25)
#define SAVE_FLAG_COLLECTED_TOAD_STAR_3 /* 0x04000000 */ (1 << 26)
#define SAVE_FLAG_COLLECTED_MIPS_STAR_1 /* 0x08000000 */ (1 << 27)
#define SAVE_FLAG_COLLECTED_MIPS_STAR_2 /* 0x10000000 */ (1 << 28)
#define SAVE_FLAG_TO_STAR_FLAG(cmd) (((cmd) >> 24) & 0x7F)
#define STAR_FLAG_TO_SAVE_FLAG(cmd) ((cmd) << 24)
// Variable for setting a warp checkpoint.
// possibly a WarpDest struct where arg is a union. TODO: Check?
struct WarpCheckpoint {
/*0x00*/ u8 actNum;
/*0x01*/ u8 courseNum;
/*0x02*/ u8 levelID;
/*0x03*/ u8 areaNum;
/*0x04*/ u8 warpNode;
};
extern struct WarpCheckpoint gWarpCheckpoint;
extern s8 gMainMenuDataModified;
extern s8 gSaveFileModified;
void save_file_do_save(s32 fileIndex);
void save_file_erase(s32 fileIndex);
BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex);
void save_file_load_all(void);
void save_file_reload(void);
void save_file_collect_star_or_key(s16 coinScore, s16 starIndex);
s32 save_file_exists(s32 fileIndex);
u32 save_file_get_max_coin_score(s32 courseIndex);
s32 save_file_get_course_star_count(s32 fileIndex, s32 courseIndex);
s32 save_file_get_total_star_count(s32 fileIndex, s32 minCourse, s32 maxCourse);
void save_file_set_flags(u32 flags);
void save_file_clear_flags(u32 flags);
u32 save_file_get_flags(void);
u32 save_file_get_star_flags(s32 fileIndex, s32 courseIndex);
void save_file_set_star_flags(s32 fileIndex, s32 courseIndex, u32 starFlags);
s32 save_file_get_course_coin_score(s32 fileIndex, s32 courseIndex);
s32 save_file_is_cannon_unlocked(void);
void save_file_set_cannon_unlocked(void);
void save_file_set_cap_pos(s16 x, s16 y, s16 z);
s32 save_file_get_cap_pos(Vec3s capPos);
void save_file_set_sound_mode(u16 mode);
u16 save_file_get_sound_mode(void);
void save_file_move_cap_to_default_location(void);
void disable_warp_checkpoint(void);
void check_if_should_set_warp_checkpoint(struct WarpNode *warpNode);
s32 check_warp_checkpoint(struct WarpNode *warpNode);
#ifdef VERSION_EU
enum EuLanguages {
LANGUAGE_ENGLISH,
LANGUAGE_FRENCH,
LANGUAGE_GERMAN
};
void eu_set_language(u16 language);
u16 eu_get_language(void);
#endif
#endif // SAVE_FILE_H
+3
View File
@@ -0,0 +1,3 @@
#include "global_state.h"
struct GlobalState *gState = 0;
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include "include/types.h"
#include "game/area.h"
struct GlobalState
{
// interaction.c
u8 sDelayInvincTimer;
s16 sInvulnerable;
// mario_actions_moving.c
Mat4 sFloorAlignMatrix;
// mario_actions_submerged.c
s16 sWasAtSurface;
s16 sSwimStrength;
s16 D_80339FD0;
s16 D_80339FD2;
f32 D_80339FD4;
// mario_misc.c
struct MarioBodyState gBodyStates[2];
// platform_displacement.c
void *gMarioPlatform;
// misc
u32 gGlobalTimer;
u8 gSpecialTripleJump;
s16 gCurrLevelNum;
s16 gCameraMovementFlags;
u32 gAudioRandom;
s8 gShowDebugText;
s8 gDebugLevelSelect;
s16 gCurrSaveFileNum;
struct Controller gController;
struct SpawnInfo gMarioSpawnInfoVal;
struct SpawnInfo *gMarioSpawnInfo;
struct Area *gCurrentArea;
struct Object *gCurrentObject;
struct Object *gMarioObject;
struct MarioAnimation D_80339D10;
struct MarioState gMarioStateVal;
struct MarioState *gMarioState;
};
extern struct GlobalState *gState;
File diff suppressed because it is too large Load Diff
+207
View File
@@ -0,0 +1,207 @@
/*====================================================================
* os_cont.h
*
* Copyright 1995, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
* Inc.; the contents of this file may not be disclosed to third
* parties, copied or duplicated in any form, in whole or in part,
* without the prior written permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to
* restrictions as set forth in subdivision (c)(1)(ii) of the Rights
* in Technical Data and Computer Software clause at DFARS
* 252.227-7013, and/or in similar or successor clauses in the FAR,
* DOD or NASA FAR Supplement. Unpublished - rights reserved under the
* Copyright Laws of the United States.
*====================================================================*/
/*---------------------------------------------------------------------*
Copyright (C) 1998 Nintendo. (Originated by SGI)
$RCSfile: os_cont.h,v $
$Revision: 1.1 $
$Date: 1998/10/09 08:01:05 $
*---------------------------------------------------------------------*/
#ifndef _OS_CONT_H_
#define _OS_CONT_H_
#ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" {
#endif
#include "ultratypes.h"
//#include "os_message.h"
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
/**************************************************************************
*
* Type definitions
*
*/
/*
* Structure for controllers
*/
typedef struct {
u16 type; /* Controller Type */
u8 status; /* Controller status */
u8 errnum;
}OSContStatus;
typedef struct {
u16 button;
s8 stick_x; /* -80 <= stick_x <= 80 */
s8 stick_y; /* -80 <= stick_y <= 80 */
u8 errnum;
} OSContPad;
typedef struct {
void *address; /* Ram pad Address: 11 bits */
u8 databuffer[32]; /* address of the data buffer */
u8 addressCrc; /* CRC code for address */
u8 dataCrc; /* CRC code for data */
u8 errnum;
} OSContRamIo;
#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */
/**************************************************************************
*
* Global definitions
*
*/
/*
* Controllers number
*/
#ifndef _HW_VERSION_1
#define MAXCONTROLLERS 4
#else
#define MAXCONTROLLERS 6
#endif
/* controller errors */
#define CONT_NO_RESPONSE_ERROR 0x8
#define CONT_OVERRUN_ERROR 0x4
#ifdef _HW_VERSION_1
#define CONT_FRAME_ERROR 0x2
#define CONT_COLLISION_ERROR 0x1
#endif
/* Controller type */
#define CONT_ABSOLUTE 0x0001
#define CONT_RELATIVE 0x0002
#define CONT_JOYPORT 0x0004
#define CONT_EEPROM 0x8000
#define CONT_EEP16K 0x4000
#define CONT_TYPE_MASK 0x1f07
#define CONT_TYPE_NORMAL 0x0005
#define CONT_TYPE_MOUSE 0x0002
#define CONT_TYPE_VOICE 0x0100
/* Controller status */
#define CONT_CARD_ON 0x01
#define CONT_CARD_PULL 0x02
#define CONT_ADDR_CRC_ER 0x04
#define CONT_EEPROM_BUSY 0x80
/* Buttons */
#define CONT_A 0x8000
#define CONT_B 0x4000
#define CONT_G 0x2000
#define CONT_START 0x1000
#define CONT_UP 0x0800
#define CONT_DOWN 0x0400
#define CONT_LEFT 0x0200
#define CONT_RIGHT 0x0100
#define CONT_L 0x0020
#define CONT_R 0x0010
#define CONT_E 0x0008
#define CONT_D 0x0004
#define CONT_C 0x0002
#define CONT_F 0x0001
/* Nintendo's official button names */
#define A_BUTTON CONT_A
#define B_BUTTON CONT_B
#define L_TRIG CONT_L
#define R_TRIG CONT_R
#define Z_TRIG CONT_G
#define START_BUTTON CONT_START
#define U_JPAD CONT_UP
#define L_JPAD CONT_LEFT
#define R_JPAD CONT_RIGHT
#define D_JPAD CONT_DOWN
#define U_CBUTTONS CONT_E
#define L_CBUTTONS CONT_C
#define R_CBUTTONS CONT_F
#define D_CBUTTONS CONT_D
/* Controller error number */
#define CONT_ERR_NO_CONTROLLER PFS_ERR_NOPACK /* 1 */
#define CONT_ERR_CONTRFAIL CONT_OVERRUN_ERROR /* 4 */
#define CONT_ERR_INVALID PFS_ERR_INVALID /* 5 */
#define CONT_ERR_DEVICE PFS_ERR_DEVICE /* 11 */
#define CONT_ERR_NOT_READY 12
#define CONT_ERR_VOICE_MEMORY 13
#define CONT_ERR_VOICE_WORD 14
#define CONT_ERR_VOICE_NO_RESPONSE 15
//
// #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
//
// /**************************************************************************
// *
// * Macro definitions
// *
// */
//
//
// /**************************************************************************
// *
// * Extern variables
// *
// */
//
//
// /**************************************************************************
// *
// * Function prototypes
// *
// */
//
// /* Controller interface */
//
// extern s32 osContInit(OSMesgQueue *, u8 *, OSContStatus *);
// extern s32 osContReset(OSMesgQueue *, OSContStatus *);
// extern s32 osContStartQuery(OSMesgQueue *);
// extern s32 osContStartReadData(OSMesgQueue *);
// #ifndef _HW_VERSION_1
// extern s32 osContSetCh(u8);
// #endif
// extern void osContGetQuery(OSContStatus *);
// extern void osContGetReadData(OSContPad *);
//
//
// #endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */
//
// #ifdef _LANGUAGE_C_PLUS_PLUS
// }
// #endif
#endif /* !_OS_CONT_H_ */
+44
View File
@@ -0,0 +1,44 @@
#ifndef _ULTRA64_TYPES_H_
#define _ULTRA64_TYPES_H_
#ifndef NULL
#define NULL (void *)0
#endif
#define TRUE 1
#define FALSE 0
typedef signed char s8;
typedef unsigned char u8;
typedef signed short int s16;
typedef unsigned short int u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long int s64;
typedef unsigned long long int u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;
typedef float f32;
typedef double f64;
#ifdef TARGET_N64
typedef u32 size_t;
typedef s32 ssize_t;
typedef u32 uintptr_t;
typedef s32 intptr_t;
typedef s32 ptrdiff_t;
#else
#include <stddef.h>
#include <stdint.h>
typedef ptrdiff_t ssize_t;
#endif
#endif
+561
View File
@@ -0,0 +1,561 @@
#ifndef AUDIO_DEFINES_H
#define AUDIO_DEFINES_H
// Sound Magic Definition:
// First Byte (Upper Nibble): Sound Bank (not the same as audio bank!)
// First Byte (Lower Nibble): Bitflags for audio playback?
// Second Byte: Sound ID
// Third Byte: Priority
// Fourth Byte (Upper Nibble): More bitflags
// Fourth Byte (Lower Nibble): Sound Status (this is set to SOUND_STATUS_PLAYING when passed to the audio driver.)
#define SOUND_ARG_LOAD(bank, playFlags, soundID, priority, flags2) (((u32) (bank) << 28) | \
((u32) (playFlags) << 24) | ((u32) (soundID) << 16) | ((u32) (priority) << 8) | \
((u32) (flags2) << 4) | SOUND_STATUS_STARTING)
#define SOUNDARGS_MASK_BANK 0xF0000000
#define SOUNDARGS_MASK_SOUNDID 0x00FF0000
#define SOUNDARGS_MASK_PRIORITY 0x0000FF00
#define SOUNDARGS_MASK_STATUS 0x0000000F
#define SOUNDARGS_SHIFT_BANK 28
#define SOUNDARGS_SHIFT_SOUNDID 16
#define SOUNDARGS_SHIFT_PRIORITY 8
/* Audio Status */
#define SOUND_STATUS_STOPPED 0
#define SOUND_STATUS_STARTING 1
#define SOUND_STATUS_PLAYING 2
/* Audio lower bitflags. TODO: Figure out what these mean and use them below. */
#define SOUND_LO_BITFLAG_UNK1 0x10 // fade in?
#define SOUND_NO_ECHO 0x20 // not in JP
#define SOUND_LO_BITFLAG_UNK8 0x80 // restart playing on each play_sound call?
/* Audio playback bitflags. */
#define SOUND_NO_VOLUME_LOSS 0x1000000 // No volume loss with distance
#define SOUND_VIBRATO 0x2000000 // Randomly alter frequency each audio frame
#define SOUND_NO_PRIORITY_LOSS 0x4000000 // Do not prioritize closer sounds
#define SOUND_NO_FREQUENCY_LOSS 0x8000000 // Frequency scale does not change with distance
// silence
#define NO_SOUND 0
/**
* The table below defines all sounds that exist in the game, and which flags
* they are used with. If a sound is used with multiple sets of flags (e.g.
* different priorities), they are gives distinguishing suffixes.
* A _2 suffix means the sound is the same despite a different sound ID.
* Some sounds are unused by the game, and given as hexadecimal literals rather
* than SOUND_ARG_LOAD calls.
*/
/* Terrain sounds */
/**
* Terrain-dependent action sounds. mario_get_terrain_sound_addend computes a
* sound terrain type between 0 and 7, depending on the terrain type of the
* level and the floor type that Mario is standing on. That value is then added
* to the sound ID for the TERRAIN_* sounds.
*/
#define SOUND_TERRAIN_DEFAULT 0 // e.g. air
#define SOUND_TERRAIN_GRASS 1
#define SOUND_TERRAIN_WATER 2
#define SOUND_TERRAIN_STONE 3
#define SOUND_TERRAIN_SPOOKY 4 // squeaky floor
#define SOUND_TERRAIN_SNOW 5
#define SOUND_TERRAIN_ICE 6
#define SOUND_TERRAIN_SAND 7
#define SOUND_ACTION_TERRAIN_JUMP SOUND_ARG_LOAD(0, 4, 0x00, 0x80, 8)
#define SOUND_ACTION_TERRAIN_LANDING SOUND_ARG_LOAD(0, 4, 0x08, 0x80, 8)
#define SOUND_ACTION_TERRAIN_STEP SOUND_ARG_LOAD(0, 6, 0x10, 0x80, 8)
#define SOUND_ACTION_TERRAIN_BODY_HIT_GROUND SOUND_ARG_LOAD(0, 4, 0x18, 0x80, 8)
#define SOUND_ACTION_TERRAIN_STEP_TIPTOE SOUND_ARG_LOAD(0, 6, 0x20, 0x80, 8)
#define SOUND_ACTION_TERRAIN_STUCK_IN_GROUND SOUND_ARG_LOAD(0, 4, 0x48, 0x80, 8)
#define SOUND_ACTION_TERRAIN_HEAVY_LANDING SOUND_ARG_LOAD(0, 4, 0x60, 0x80, 8)
#define SOUND_ACTION_METAL_JUMP SOUND_ARG_LOAD(0, 4, 0x28, 0x90, 8)
#define SOUND_ACTION_METAL_LANDING SOUND_ARG_LOAD(0, 4, 0x29, 0x90, 8)
#define SOUND_ACTION_METAL_STEP SOUND_ARG_LOAD(0, 4, 0x2A, 0x90, 8)
#define SOUND_ACTION_METAL_HEAVY_LANDING SOUND_ARG_LOAD(0, 4, 0x2B, 0x90, 8)
#define SOUND_ACTION_CLAP_HANDS_COLD SOUND_ARG_LOAD(0, 6, 0x2C, 0x00, 8)
#define SOUND_ACTION_HANGING_STEP SOUND_ARG_LOAD(0, 4, 0x2D, 0xA0, 8)
#define SOUND_ACTION_QUICKSAND_STEP SOUND_ARG_LOAD(0, 4, 0x2E, 0x00, 8)
#define SOUND_ACTION_METAL_STEP_TIPTOE SOUND_ARG_LOAD(0, 4, 0x2F, 0x90, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN430 SOUND_ARG_LOAD(0, 4, 0x30, 0xC0, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN431 SOUND_ARG_LOAD(0, 4, 0x31, 0x60, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN432 SOUND_ARG_LOAD(0, 4, 0x32, 0x80, 8)
#define SOUND_ACTION_SWIM SOUND_ARG_LOAD(0, 4, 0x33, 0x80, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN434 SOUND_ARG_LOAD(0, 4, 0x34, 0x80, 8)
#define SOUND_ACTION_THROW SOUND_ARG_LOAD(0, 4, 0x35, 0x80, 8)
#define SOUND_ACTION_KEY_SWISH SOUND_ARG_LOAD(0, 4, 0x36, 0x80, 8)
#define SOUND_ACTION_SPIN SOUND_ARG_LOAD(0, 4, 0x37, 0x80, 8)
#define SOUND_ACTION_TWIRL SOUND_ARG_LOAD(0, 4, 0x38, 0x80, 8) // same sound as spin
/* not verified */ #define SOUND_ACTION_CLIMB_UP_TREE SOUND_ARG_LOAD(0, 4, 0x3A, 0x80, 8)
/* not verified */ #define SOUND_ACTION_CLIMB_DOWN_TREE 0x003B
/* not verified */ #define SOUND_ACTION_UNK3C 0x003C
/* not verified */ #define SOUND_ACTION_UNKNOWN43D SOUND_ARG_LOAD(0, 4, 0x3D, 0x80, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN43E SOUND_ARG_LOAD(0, 4, 0x3E, 0x80, 8)
/* not verified */ #define SOUND_ACTION_PAT_BACK SOUND_ARG_LOAD(0, 4, 0x3F, 0x80, 8)
#define SOUND_ACTION_BRUSH_HAIR SOUND_ARG_LOAD(0, 4, 0x40, 0x80, 8)
/* not verified */ #define SOUND_ACTION_CLIMB_UP_POLE SOUND_ARG_LOAD(0, 4, 0x41, 0x80, 8)
#define SOUND_ACTION_METAL_BONK SOUND_ARG_LOAD(0, 4, 0x42, 0x80, 8)
#define SOUND_ACTION_UNSTUCK_FROM_GROUND SOUND_ARG_LOAD(0, 4, 0x43, 0x80, 8)
/* not verified */ #define SOUND_ACTION_HIT SOUND_ARG_LOAD(0, 4, 0x44, 0xC0, 8)
/* not verified */ #define SOUND_ACTION_HIT_2 SOUND_ARG_LOAD(0, 4, 0x44, 0xB0, 8)
/* not verified */ #define SOUND_ACTION_HIT_3 SOUND_ARG_LOAD(0, 4, 0x44, 0xA0, 8)
#define SOUND_ACTION_BONK SOUND_ARG_LOAD(0, 4, 0x45, 0xA0, 8)
#define SOUND_ACTION_SHRINK_INTO_BBH SOUND_ARG_LOAD(0, 4, 0x46, 0xA0, 8)
#define SOUND_ACTION_SWIM_FAST SOUND_ARG_LOAD(0, 4, 0x47, 0xA0, 8)
#define SOUND_ACTION_METAL_JUMP_WATER SOUND_ARG_LOAD(0, 4, 0x50, 0x90, 8)
#define SOUND_ACTION_METAL_LAND_WATER SOUND_ARG_LOAD(0, 4, 0x51, 0x90, 8)
#define SOUND_ACTION_METAL_STEP_WATER SOUND_ARG_LOAD(0, 4, 0x52, 0x90, 8)
/* not verified */ #define SOUND_ACTION_UNK53 0x0053
/* not verified */ #define SOUND_ACTION_UNK54 0x0054
/* not verified */ #define SOUND_ACTION_UNK55 0x0055
/* not verified */ #define SOUND_ACTION_FLYING_FAST SOUND_ARG_LOAD(0, 4, 0x56, 0x80, 8) // "swoop"?
#define SOUND_ACTION_TELEPORT SOUND_ARG_LOAD(0, 4, 0x57, 0xC0, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN458 SOUND_ARG_LOAD(0, 4, 0x58, 0xA0, 8)
/* not verified */ #define SOUND_ACTION_BOUNCE_OFF_OBJECT SOUND_ARG_LOAD(0, 4, 0x59, 0xB0, 8)
/* not verified */ #define SOUND_ACTION_SIDE_FLIP_UNK SOUND_ARG_LOAD(0, 4, 0x5A, 0x80, 8)
#define SOUND_ACTION_READ_SIGN SOUND_ARG_LOAD(0, 4, 0x5B, 0xFF, 8)
/* not verified */ #define SOUND_ACTION_UNKNOWN45C SOUND_ARG_LOAD(0, 4, 0x5C, 0x80, 8)
/* not verified */ #define SOUND_ACTION_UNK5D 0x005D
/* not verified */ #define SOUND_ACTION_INTRO_UNK45E SOUND_ARG_LOAD(0, 4, 0x5E, 0x80, 8)
/* not verified */ #define SOUND_ACTION_INTRO_UNK45F SOUND_ARG_LOAD(0, 4, 0x5F, 0x80, 8)
/* Moving Sound Effects */
// Terrain-dependent moving sounds; a value 0-7 is added to the sound ID before
// playing. See higher up for the different terrain types.
#define SOUND_MOVING_TERRAIN_SLIDE SOUND_ARG_LOAD(1, 4, 0x00, 0x00, 0)
#define SOUND_MOVING_TERRAIN_RIDING_SHELL SOUND_ARG_LOAD(1, 4, 0x20, 0x00, 0)
#define SOUND_MOVING_LAVA_BURN SOUND_ARG_LOAD(1, 4, 0x10, 0x00, 0) // ?
#define SOUND_MOVING_SLIDE_DOWN_POLE SOUND_ARG_LOAD(1, 4, 0x11, 0x00, 0) // ?
#define SOUND_MOVING_SLIDE_DOWN_TREE SOUND_ARG_LOAD(1, 4, 0x12, 0x80, 0)
#define SOUND_MOVING_QUICKSAND_DEATH SOUND_ARG_LOAD(1, 4, 0x14, 0x00, 0)
#define SOUND_MOVING_SHOCKED SOUND_ARG_LOAD(1, 4, 0x16, 0x00, 0)
#define SOUND_MOVING_FLYING SOUND_ARG_LOAD(1, 4, 0x17, 0x00, 0)
#define SOUND_MOVING_ALMOST_DROWNING SOUND_ARG_LOAD(1, 0xC, 0x18, 0x00, 0)
#define SOUND_MOVING_AIM_CANNON SOUND_ARG_LOAD(1, 0xD, 0x19, 0x20, 0)
#define SOUND_MOVING_UNK1A 0x101A // ?
#define SOUND_MOVING_RIDING_SHELL_LAVA SOUND_ARG_LOAD(1, 4, 0x28, 0x00, 0)
/* Mario Sound Effects */
// A random number 0-2 is added to the sound ID before playing, producing Yah/Wah/Hoo
#define SOUND_MARIO_YAH_WAH_HOO SOUND_ARG_LOAD(2, 4, 0x00, 0x80, 8)
/* not verified */ #define SOUND_MARIO_HOOHOO SOUND_ARG_LOAD(2, 4, 0x03, 0x80, 8)
/* not verified */ #define SOUND_MARIO_YAHOO SOUND_ARG_LOAD(2, 4, 0x04, 0x80, 8)
/* not verified */ #define SOUND_MARIO_UH SOUND_ARG_LOAD(2, 4, 0x05, 0x80, 8)
/* not verified */ #define SOUND_MARIO_HRMM SOUND_ARG_LOAD(2, 4, 0x06, 0x80, 8)
/* not verified */ #define SOUND_MARIO_WAH2 SOUND_ARG_LOAD(2, 4, 0x07, 0x80, 8)
/* not verified */ #define SOUND_MARIO_WHOA SOUND_ARG_LOAD(2, 4, 0x08, 0xC0, 8)
/* not verified */ #define SOUND_MARIO_EEUH SOUND_ARG_LOAD(2, 4, 0x09, 0x80, 8)
/* not verified */ #define SOUND_MARIO_ATTACKED SOUND_ARG_LOAD(2, 4, 0x0A, 0xFF, 8)
/* not verified */ #define SOUND_MARIO_OOOF SOUND_ARG_LOAD(2, 4, 0x0B, 0x80, 8)
/* not verified */ #define SOUND_MARIO_OOOF2 SOUND_ARG_LOAD(2, 4, 0x0B, 0xD0, 8)
#define SOUND_MARIO_HERE_WE_GO SOUND_ARG_LOAD(2, 4, 0x0C, 0x80, 8)
/* not verified */ #define SOUND_MARIO_YAWNING SOUND_ARG_LOAD(2, 4, 0x0D, 0x80, 8)
#define SOUND_MARIO_SNORING1 SOUND_ARG_LOAD(2, 4, 0x0E, 0x80, 8)
#define SOUND_MARIO_SNORING2 SOUND_ARG_LOAD(2, 4, 0x0F, 0x80, 8)
/* not verified */ #define SOUND_MARIO_WAAAOOOW SOUND_ARG_LOAD(2, 4, 0x10, 0xC0, 8)
/* not verified */ #define SOUND_MARIO_HAHA SOUND_ARG_LOAD(2, 4, 0x11, 0x80, 8)
/* not verified */ #define SOUND_MARIO_HAHA_2 SOUND_ARG_LOAD(2, 4, 0x11, 0xF0, 8)
/* not verified */ #define SOUND_MARIO_UH2 SOUND_ARG_LOAD(2, 4, 0x13, 0xD0, 8)
/* not verified */ #define SOUND_MARIO_UH2_2 SOUND_ARG_LOAD(2, 4, 0x13, 0x80, 8)
/* not verified */ #define SOUND_MARIO_ON_FIRE SOUND_ARG_LOAD(2, 4, 0x14, 0xA0, 8)
/* not verified */ #define SOUND_MARIO_DYING SOUND_ARG_LOAD(2, 4, 0x15, 0xFF, 8)
#define SOUND_MARIO_PANTING_COLD SOUND_ARG_LOAD(2, 4, 0x16, 0x80, 8)
// A random number 0-2 is added to the sound ID before playing
#define SOUND_MARIO_PANTING SOUND_ARG_LOAD(2, 4, 0x18, 0x80, 8)
#define SOUND_MARIO_COUGHING1 SOUND_ARG_LOAD(2, 4, 0x1B, 0x80, 8)
#define SOUND_MARIO_COUGHING2 SOUND_ARG_LOAD(2, 4, 0x1C, 0x80, 8)
#define SOUND_MARIO_COUGHING3 SOUND_ARG_LOAD(2, 4, 0x1D, 0x80, 8)
#define SOUND_MARIO_PUNCH_YAH SOUND_ARG_LOAD(2, 4, 0x1E, 0x80, 8)
#define SOUND_MARIO_PUNCH_HOO SOUND_ARG_LOAD(2, 4, 0x1F, 0x80, 8)
#define SOUND_MARIO_MAMA_MIA SOUND_ARG_LOAD(2, 4, 0x20, 0x80, 8)
#define SOUND_MARIO_OKEY_DOKEY 0x2021
#define SOUND_MARIO_GROUND_POUND_WAH SOUND_ARG_LOAD(2, 4, 0x22, 0x80, 8)
#define SOUND_MARIO_DROWNING SOUND_ARG_LOAD(2, 4, 0x23, 0xF0, 8)
#define SOUND_MARIO_PUNCH_WAH SOUND_ARG_LOAD(2, 4, 0x24, 0x80, 8)
/* Mario Sound Effects (US/EU only) */
#define SOUND_PEACH_DEAR_MARIO SOUND_ARG_LOAD(2, 4, 0x28, 0xFF, 8)
// A random number 0-4 is added to the sound ID before playing, producing one of
// Yahoo! (60% chance), Waha! (20%), or Yippee! (20%).
#define SOUND_MARIO_YAHOO_WAHA_YIPPEE SOUND_ARG_LOAD(2, 4, 0x2B, 0x80, 8)
#define SOUND_MARIO_DOH SOUND_ARG_LOAD(2, 4, 0x30, 0x80, 8)
#define SOUND_MARIO_GAME_OVER SOUND_ARG_LOAD(2, 4, 0x31, 0xFF, 8)
#define SOUND_MARIO_HELLO SOUND_ARG_LOAD(2, 4, 0x32, 0xFF, 8)
#define SOUND_MARIO_PRESS_START_TO_PLAY SOUND_ARG_LOAD(2, 4, 0x33, 0xFF, 0xA)
#define SOUND_MARIO_TWIRL_BOUNCE SOUND_ARG_LOAD(2, 4, 0x34, 0x80, 8)
#define SOUND_MARIO_SNORING3 SOUND_ARG_LOAD(2, 4, 0x35, 0xFF, 8)
#define SOUND_MARIO_SO_LONGA_BOWSER SOUND_ARG_LOAD(2, 4, 0x36, 0x80, 8)
#define SOUND_MARIO_IMA_TIRED SOUND_ARG_LOAD(2, 4, 0x37, 0x80, 8)
/* Princess Peach Sound Effects (US/EU only) */
#define SOUND_PEACH_MARIO SOUND_ARG_LOAD(2, 4, 0x38, 0xFF, 8)
#define SOUND_PEACH_POWER_OF_THE_STARS SOUND_ARG_LOAD(2, 4, 0x39, 0xFF, 8)
#define SOUND_PEACH_THANKS_TO_YOU SOUND_ARG_LOAD(2, 4, 0x3A, 0xFF, 8)
#define SOUND_PEACH_THANK_YOU_MARIO SOUND_ARG_LOAD(2, 4, 0x3B, 0xFF, 8)
#define SOUND_PEACH_SOMETHING_SPECIAL SOUND_ARG_LOAD(2, 4, 0x3C, 0xFF, 8)
#define SOUND_PEACH_BAKE_A_CAKE SOUND_ARG_LOAD(2, 4, 0x3D, 0xFF, 8)
#define SOUND_PEACH_FOR_MARIO SOUND_ARG_LOAD(2, 4, 0x3E, 0xFF, 8)
#define SOUND_PEACH_MARIO2 SOUND_ARG_LOAD(2, 4, 0x3F, 0xFF, 8)
/* General Sound Effects */
#define SOUND_GENERAL_ACTIVATE_CAP_SWITCH SOUND_ARG_LOAD(3, 0, 0x00, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_FLAME_OUT SOUND_ARG_LOAD(3, 0, 0x03, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_OPEN_WOOD_DOOR SOUND_ARG_LOAD(3, 0, 0x04, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_CLOSE_WOOD_DOOR SOUND_ARG_LOAD(3, 0, 0x05, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_OPEN_IRON_DOOR SOUND_ARG_LOAD(3, 0, 0x06, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_CLOSE_IRON_DOOR SOUND_ARG_LOAD(3, 0, 0x07, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_BUBBLES 0x3008
/* not verified */ #define SOUND_GENERAL_MOVING_WATER SOUND_ARG_LOAD(3, 0, 0x09, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_SWISH_WATER SOUND_ARG_LOAD(3, 0, 0x0A, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_QUIET_BUBBLE SOUND_ARG_LOAD(3, 0, 0x0B, 0x00, 8)
#define SOUND_GENERAL_VOLCANO_EXPLOSION SOUND_ARG_LOAD(3, 0, 0x0C, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_QUIET_BUBBLE2 SOUND_ARG_LOAD(3, 0, 0x0D, 0x00, 8)
#define SOUND_GENERAL_CASTLE_TRAP_OPEN SOUND_ARG_LOAD(3, 0, 0x0E, 0x80, 8)
#define SOUND_GENERAL_WALL_EXPLOSION SOUND_ARG_LOAD(3, 0, 0x0F, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_COIN SOUND_ARG_LOAD(3, 8, 0x11, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_COIN_WATER SOUND_ARG_LOAD(3, 8, 0x12, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_SHORT_STAR SOUND_ARG_LOAD(3, 0, 0x16, 0x00, 9)
/* not verified */ #define SOUND_GENERAL_BIG_CLOCK SOUND_ARG_LOAD(3, 0, 0x17, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_LOUD_POUND 0x3018 // _TERRAIN?
/* not verified */ #define SOUND_GENERAL_LOUD_POUND2 0x3019
/* not verified */ #define SOUND_GENERAL_SHORT_POUND1 0x301A
/* not verified */ #define SOUND_GENERAL_SHORT_POUND2 0x301B
/* not verified */ #define SOUND_GENERAL_SHORT_POUND3 0x301C
/* not verified */ #define SOUND_GENERAL_SHORT_POUND4 0x301D
/* not verified */ #define SOUND_GENERAL_SHORT_POUND5 0x301E
/* not verified */ #define SOUND_GENERAL_SHORT_POUND6 0x301F
#define SOUND_GENERAL_OPEN_CHEST SOUND_ARG_LOAD(3, 1, 0x20, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_CLAM_SHELL1 SOUND_ARG_LOAD(3, 1, 0x22, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_BOX_LANDING SOUND_ARG_LOAD(3, 0, 0x24, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BOX_LANDING_2 SOUND_ARG_LOAD(3, 2, 0x24, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN1 SOUND_ARG_LOAD(3, 0, 0x25, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN1_2 SOUND_ARG_LOAD(3, 2, 0x25, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_CLAM_SHELL2 SOUND_ARG_LOAD(3, 0, 0x26, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_CLAM_SHELL3 SOUND_ARG_LOAD(3, 0, 0x27, 0x40, 8)
#ifdef VERSION_JP
#define SOUND_GENERAL_PAINTING_EJECT SOUND_ARG_LOAD(3, 8, 0x28, 0x00, 8)
#else
#define SOUND_GENERAL_PAINTING_EJECT SOUND_ARG_LOAD(3, 9, 0x28, 0x00, 8)
#endif
#define SOUND_GENERAL_LEVEL_SELECT_CHANGE SOUND_ARG_LOAD(3, 0, 0x2B, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_PLATFORM SOUND_ARG_LOAD(3, 0, 0x2D, 0x80, 8)
#define SOUND_GENERAL_DONUT_PLATFORM_EXPLOSION SOUND_ARG_LOAD(3, 0, 0x2E, 0x20, 8)
#define SOUND_GENERAL_BOWSER_BOMB_EXPLOSION SOUND_ARG_LOAD(3, 1, 0x2F, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_COIN_SPURT SOUND_ARG_LOAD(3, 0, 0x30, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_COIN_SPURT_2 SOUND_ARG_LOAD(3, 8, 0x30, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_COIN_SPURT_EU SOUND_ARG_LOAD(3, 8, 0x30, 0x20, 8)
/* not verified */ #define SOUND_GENERAL_EXPLOSION6 0x3031
/* not verified */ #define SOUND_GENERAL_UNK32 0x3032
/* not verified */ #define SOUND_GENERAL_BOAT_TILT1 SOUND_ARG_LOAD(3, 0, 0x34, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_BOAT_TILT2 SOUND_ARG_LOAD(3, 0, 0x35, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_COIN_DROP SOUND_ARG_LOAD(3, 0, 0x36, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN3_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x37, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN3 SOUND_ARG_LOAD(3, 0, 0x37, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN3_2 SOUND_ARG_LOAD(3, 8, 0x37, 0x80, 8)
#define SOUND_GENERAL_PENDULUM_SWING SOUND_ARG_LOAD(3, 0, 0x38, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_CHAIN_CHOMP1 SOUND_ARG_LOAD(3, 0, 0x39, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_CHAIN_CHOMP2 SOUND_ARG_LOAD(3, 0, 0x3A, 0x00, 8)
#define SOUND_GENERAL_DOOR_TURN_KEY SOUND_ARG_LOAD(3, 0, 0x3B, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_MOVING_IN_SAND SOUND_ARG_LOAD(3, 0, 0x3C, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN4_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x3D, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNKNOWN4 SOUND_ARG_LOAD(3, 0, 0x3D, 0x80, 8)
#define SOUND_GENERAL_MOVING_PLATFORM_SWITCH SOUND_ARG_LOAD(3, 0, 0x3E, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_CAGE_OPEN SOUND_ARG_LOAD(3, 0, 0x3F, 0xA0, 8)
/* not verified */ #define SOUND_GENERAL_QUIET_POUND1_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x40, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_QUIET_POUND1 SOUND_ARG_LOAD(3, 0, 0x40, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_BREAK_BOX SOUND_ARG_LOAD(3, 0, 0x41, 0xC0, 8)
#define SOUND_GENERAL_DOOR_INSERT_KEY SOUND_ARG_LOAD(3, 0, 0x42, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_QUIET_POUND2 SOUND_ARG_LOAD(3, 0, 0x43, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BIG_POUND SOUND_ARG_LOAD(3, 0, 0x44, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNK45 SOUND_ARG_LOAD(3, 0, 0x45, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNK46_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x46, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_UNK46 SOUND_ARG_LOAD(3, 0, 0x46, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_CANNON_UP SOUND_ARG_LOAD(3, 0, 0x47, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_GRINDEL_ROLL SOUND_ARG_LOAD(3, 0, 0x48, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_EXPLOSION7 0x3049
/* not verified */ #define SOUND_GENERAL_SHAKE_COFFIN 0x304A
/* not verified */ #define SOUND_GENERAL_RACE_GUN_SHOT SOUND_ARG_LOAD(3, 1, 0x4D, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_STAR_DOOR_OPEN SOUND_ARG_LOAD(3, 0, 0x4E, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_STAR_DOOR_CLOSE SOUND_ARG_LOAD(3, 0, 0x4F, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_POUND_ROCK SOUND_ARG_LOAD(3, 0, 0x56, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_STAR_APPEARS SOUND_ARG_LOAD(3, 0, 0x57, 0xFF, 9)
#define SOUND_GENERAL_COLLECT_1UP SOUND_ARG_LOAD(3, 0, 0x58, 0xFF, 8)
/* not verified */ #define SOUND_GENERAL_BUTTON_PRESS_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x5A, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BUTTON_PRESS SOUND_ARG_LOAD(3, 0, 0x5A, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_BUTTON_PRESS_2_LOWPRIO SOUND_ARG_LOAD(3, 1, 0x5A, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BUTTON_PRESS_2 SOUND_ARG_LOAD(3, 1, 0x5A, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_ELEVATOR_MOVE SOUND_ARG_LOAD(3, 0, 0x5B, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_ELEVATOR_MOVE_2 SOUND_ARG_LOAD(3, 1, 0x5B, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_SWISH_AIR SOUND_ARG_LOAD(3, 0, 0x5C, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_SWISH_AIR_2 SOUND_ARG_LOAD(3, 1, 0x5C, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_HAUNTED_CHAIR SOUND_ARG_LOAD(3, 0, 0x5D, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_SOFT_LANDING SOUND_ARG_LOAD(3, 0, 0x5E, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_HAUNTED_CHAIR_MOVE SOUND_ARG_LOAD(3, 0, 0x5F, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BOWSER_PLATFORM SOUND_ARG_LOAD(3, 0, 0x62, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_BOWSER_PLATFORM_2 SOUND_ARG_LOAD(3, 1, 0x62, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_HEART_SPIN SOUND_ARG_LOAD(3, 0, 0x64, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_POUND_WOOD_POST SOUND_ARG_LOAD(3, 0, 0x65, 0xC0, 8)
/* not verified */ #define SOUND_GENERAL_WATER_LEVEL_TRIG SOUND_ARG_LOAD(3, 0, 0x66, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_SWITCH_DOOR_OPEN SOUND_ARG_LOAD(3, 0, 0x67, 0xA0, 8)
/* not verified */ #define SOUND_GENERAL_RED_COIN SOUND_ARG_LOAD(3, 0, 0x68, 0x90, 8)
/* not verified */ #define SOUND_GENERAL_BIRDS_FLY_AWAY SOUND_ARG_LOAD(3, 0, 0x69, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_METAL_POUND SOUND_ARG_LOAD(3, 0, 0x6B, 0x80, 8)
/* not verified */ #define SOUND_GENERAL_BOING1 SOUND_ARG_LOAD(3, 0, 0x6C, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_BOING2_LOWPRIO SOUND_ARG_LOAD(3, 0, 0x6D, 0x20, 8)
/* not verified */ #define SOUND_GENERAL_BOING2 SOUND_ARG_LOAD(3, 0, 0x6D, 0x40, 8)
/* not verified */ #define SOUND_GENERAL_YOSHI_WALK SOUND_ARG_LOAD(3, 0, 0x6E, 0x20, 8)
/* not verified */ #define SOUND_GENERAL_ENEMY_ALERT1 SOUND_ARG_LOAD(3, 0, 0x6F, 0x30, 8)
/* not verified */ #define SOUND_GENERAL_YOSHI_TALK SOUND_ARG_LOAD(3, 0, 0x70, 0x30, 8)
/* not verified */ #define SOUND_GENERAL_SPLATTERING SOUND_ARG_LOAD(3, 0, 0x71, 0x30, 8)
/* not verified */ #define SOUND_GENERAL_BOING3 0x3072
/* not verified */ #define SOUND_GENERAL_GRAND_STAR SOUND_ARG_LOAD(3, 0, 0x73, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_GRAND_STAR_JUMP SOUND_ARG_LOAD(3, 0, 0x74, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_BOAT_ROCK SOUND_ARG_LOAD(3, 0, 0x75, 0x00, 8)
/* not verified */ #define SOUND_GENERAL_VANISH_SFX SOUND_ARG_LOAD(3, 0, 0x76, 0x20, 8)
/* Environment Sound Effects */
/* not verified */ #define SOUND_ENV_WATERFALL1 SOUND_ARG_LOAD(4, 0, 0x00, 0x00, 0)
/* not verified */ #define SOUND_ENV_WATERFALL2 SOUND_ARG_LOAD(4, 0, 0x01, 0x00, 0)
/* not verified */ #define SOUND_ENV_ELEVATOR1 SOUND_ARG_LOAD(4, 0, 0x02, 0x00, 0)
/* not verified */ #define SOUND_ENV_DRONING1 SOUND_ARG_LOAD(4, 1, 0x03, 0x00, 0)
/* not verified */ #define SOUND_ENV_DRONING2 SOUND_ARG_LOAD(4, 0, 0x04, 0x00, 0)
/* not verified */ #define SOUND_ENV_WIND1 SOUND_ARG_LOAD(4, 0, 0x05, 0x00, 0)
/* not verified */ #define SOUND_ENV_MOVING_SAND_SNOW 0x4006
/* not verified */ #define SOUND_ENV_UNK07 0x4007
/* not verified */ #define SOUND_ENV_ELEVATOR2 SOUND_ARG_LOAD(4, 0, 0x08, 0x00, 0)
/* not verified */ #define SOUND_ENV_WATER SOUND_ARG_LOAD(4, 0, 0x09, 0x00, 0)
/* not verified */ #define SOUND_ENV_UNKNOWN2 SOUND_ARG_LOAD(4, 0, 0x0A, 0x00, 0)
/* not verified */ #define SOUND_ENV_BOAT_ROCKING1 SOUND_ARG_LOAD(4, 0, 0x0B, 0x00, 0)
/* not verified */ #define SOUND_ENV_ELEVATOR3 SOUND_ARG_LOAD(4, 0, 0x0C, 0x00, 0)
/* not verified */ #define SOUND_ENV_ELEVATOR4 SOUND_ARG_LOAD(4, 0, 0x0D, 0x00, 0)
/* not verified */ #define SOUND_ENV_ELEVATOR4_2 SOUND_ARG_LOAD(4, 1, 0x0D, 0x00, 0)
/* not verified */ #define SOUND_ENV_MOVINGSAND SOUND_ARG_LOAD(4, 0, 0x0E, 0x00, 0)
/* not verified */ #define SOUND_ENV_MERRY_GO_ROUND_CREAKING SOUND_ARG_LOAD(4, 0, 0x0F, 0x40, 0)
/* not verified */ #define SOUND_ENV_WIND2 SOUND_ARG_LOAD(4, 0, 0x10, 0x80, 0)
/* not verified */ #define SOUND_ENV_UNK12 0x4012
/* not verified */ #define SOUND_ENV_SLIDING SOUND_ARG_LOAD(4, 0, 0x13, 0x00, 0)
/* not verified */ #define SOUND_ENV_STAR SOUND_ARG_LOAD(4, 0, 0x14, 0x00, 1)
/* not verified */ #define SOUND_ENV_UNKNOWN4 SOUND_ARG_LOAD(4, 1, 0x15, 0x00, 0)
/* not verified */ #define SOUND_ENV_WATER_DRAIN SOUND_ARG_LOAD(4, 1, 0x16, 0x00, 0)
/* not verified */ #define SOUND_ENV_METAL_BOX_PUSH SOUND_ARG_LOAD(4, 0, 0x17, 0x80, 0)
/* not verified */ #define SOUND_ENV_SINK_QUICKSAND SOUND_ARG_LOAD(4, 0, 0x18, 0x80, 0)
/* Object Sound Effects */
#define SOUND_OBJ_SUSHI_SHARK_WATER_SOUND SOUND_ARG_LOAD(5, 0, 0x00, 0x80, 8)
#define SOUND_OBJ_MRI_SHOOT SOUND_ARG_LOAD(5, 0, 0x01, 0x00, 8)
#define SOUND_OBJ_BABY_PENGUIN_WALK SOUND_ARG_LOAD(5, 0, 0x02, 0x00, 8)
#define SOUND_OBJ_BOWSER_WALK SOUND_ARG_LOAD(5, 0, 0x03, 0x00, 8)
#define SOUND_OBJ_BOWSER_TAIL_PICKUP SOUND_ARG_LOAD(5, 0, 0x05, 0x00, 8)
#define SOUND_OBJ_BOWSER_DEFEATED SOUND_ARG_LOAD(5, 0, 0x06, 0x00, 8)
#define SOUND_OBJ_BOWSER_SPINNING SOUND_ARG_LOAD(5, 0, 0x07, 0x00, 8)
#define SOUND_OBJ_BOWSER_INHALING SOUND_ARG_LOAD(5, 0, 0x08, 0x00, 8)
#define SOUND_OBJ_BIG_PENGUIN_WALK SOUND_ARG_LOAD(5, 0, 0x09, 0x80, 8)
#define SOUND_OBJ_BOO_BOUNCE_TOP SOUND_ARG_LOAD(5, 0, 0x0A, 0x00, 8)
#define SOUND_OBJ_BOO_LAUGH_SHORT SOUND_ARG_LOAD(5, 0, 0x0B, 0x00, 8)
#define SOUND_OBJ_THWOMP SOUND_ARG_LOAD(5, 0, 0x0C, 0xA0, 8)
/* not verified */ #define SOUND_OBJ_CANNON1 SOUND_ARG_LOAD(5, 0, 0x0D, 0xF0, 8)
/* not verified */ #define SOUND_OBJ_CANNON2 SOUND_ARG_LOAD(5, 0, 0x0E, 0xF0, 8)
/* not verified */ #define SOUND_OBJ_CANNON3 SOUND_ARG_LOAD(5, 0, 0x0F, 0xF0, 8)
/* not verified */ #define SOUND_OBJ_JUMP_WALK_WATER 0x5012
/* not verified */ #define SOUND_OBJ_UNKNOWN2 SOUND_ARG_LOAD(5, 0, 0x13, 0x00, 8)
#define SOUND_OBJ_MRI_DEATH SOUND_ARG_LOAD(5, 0, 0x14, 0x00, 8)
/* not verified */ #define SOUND_OBJ_POUNDING1 SOUND_ARG_LOAD(5, 0, 0x15, 0x50, 8)
/* not verified */ #define SOUND_OBJ_POUNDING1_HIGHPRIO SOUND_ARG_LOAD(5, 0, 0x15, 0x80, 8)
#define SOUND_OBJ_WHOMP_LOWPRIO SOUND_ARG_LOAD(5, 0, 0x16, 0x60, 8)
#define SOUND_OBJ_KING_BOBOMB SOUND_ARG_LOAD(5, 0, 0x16, 0x80, 8)
/* not verified */ #define SOUND_OBJ_BULLY_METAL SOUND_ARG_LOAD(5, 0, 0x17, 0x80, 8)
/* not verified */ #define SOUND_OBJ_BULLY_EXPLODE SOUND_ARG_LOAD(5, 0, 0x18, 0xA0, 8)
/* not verified */ #define SOUND_OBJ_BULLY_EXPLODE_2 SOUND_ARG_LOAD(5, 1, 0x18, 0xA0, 8)
/* not verified */ #define SOUND_OBJ_POUNDING_CANNON SOUND_ARG_LOAD(5, 0, 0x1A, 0x50, 8)
/* not verified */ #define SOUND_OBJ_BULLY_WALK SOUND_ARG_LOAD(5, 0, 0x1B, 0x30, 8)
/* not verified */ #define SOUND_OBJ_UNKNOWN3 SOUND_ARG_LOAD(5, 0, 0x1D, 0x80, 8)
/* not verified */ #define SOUND_OBJ_UNKNOWN4 SOUND_ARG_LOAD(5, 0, 0x1E, 0xA0, 8)
#define SOUND_OBJ_BABY_PENGUIN_DIVE SOUND_ARG_LOAD(5, 0, 0x1F, 0x40, 8)
#define SOUND_OBJ_GOOMBA_WALK SOUND_ARG_LOAD(5, 0, 0x20, 0x00, 8)
#define SOUND_OBJ_UKIKI_CHATTER_LONG SOUND_ARG_LOAD(5, 0, 0x21, 0x00, 8)
#define SOUND_OBJ_MONTY_MOLE_ATTACK SOUND_ARG_LOAD(5, 0, 0x22, 0x00, 8)
#define SOUND_OBJ_EVIL_LAKITU_THROW SOUND_ARG_LOAD(5, 0, 0x22, 0x20, 8)
/* not verified */ #define SOUND_OBJ_UNK23 0x5023
#define SOUND_OBJ_DYING_ENEMY1 SOUND_ARG_LOAD(5, 0, 0x24, 0x40, 8)
/* not verified */ #define SOUND_OBJ_CANNON4 SOUND_ARG_LOAD(5, 0, 0x25, 0x40, 8)
/* not verified */ #define SOUND_OBJ_DYING_ENEMY2 0x5026
#define SOUND_OBJ_BOBOMB_WALK SOUND_ARG_LOAD(5, 0, 0x27, 0x00, 8)
/* not verified */ #define SOUND_OBJ_SOMETHING_LANDING SOUND_ARG_LOAD(5, 0, 0x28, 0x80, 8)
/* not verified */ #define SOUND_OBJ_DIVING_IN_WATER SOUND_ARG_LOAD(5, 0, 0x29, 0xA0, 8)
/* not verified */ #define SOUND_OBJ_SNOW_SAND1 SOUND_ARG_LOAD(5, 0, 0x2A, 0x00, 8)
/* not verified */ #define SOUND_OBJ_SNOW_SAND2 SOUND_ARG_LOAD(5, 0, 0x2B, 0x00, 8)
#define SOUND_OBJ_DEFAULT_DEATH SOUND_ARG_LOAD(5, 0, 0x2C, 0x80, 8)
#define SOUND_OBJ_BIG_PENGUIN_YELL SOUND_ARG_LOAD(5, 0, 0x2D, 0x00, 8)
#define SOUND_OBJ_WATER_BOMB_BOUNCING SOUND_ARG_LOAD(5, 0, 0x2E, 0x80, 8)
#define SOUND_OBJ_GOOMBA_ALERT SOUND_ARG_LOAD(5, 0, 0x2F, 0x00, 8)
#define SOUND_OBJ_WIGGLER_JUMP SOUND_ARG_LOAD(5, 0, 0x2F, 0x60, 8)
/* not verified */ #define SOUND_OBJ_STOMPED SOUND_ARG_LOAD(5, 0, 0x30, 0x80, 8)
/* not verified */ #define SOUND_OBJ_UNKNOWN6 SOUND_ARG_LOAD(5, 0, 0x31, 0x00, 8)
/* not verified */ #define SOUND_OBJ_DIVING_INTO_WATER SOUND_ARG_LOAD(5, 0, 0x32, 0x40, 8)
#define SOUND_OBJ_PIRANHA_PLANT_SHRINK SOUND_ARG_LOAD(5, 0, 0x33, 0x40, 8)
#define SOUND_OBJ_KOOPA_THE_QUICK_WALK SOUND_ARG_LOAD(5, 0, 0x34, 0x20, 8)
#define SOUND_OBJ_KOOPA_WALK SOUND_ARG_LOAD(5, 0, 0x35, 0x00, 8)
#define SOUND_OBJ_BULLY_WALKING SOUND_ARG_LOAD(5, 0, 0x36, 0x60, 8)
#define SOUND_OBJ_DORRIE SOUND_ARG_LOAD(5, 0, 0x37, 0x60, 8)
#define SOUND_OBJ_BOWSER_LAUGH SOUND_ARG_LOAD(5, 0, 0x38, 0x80, 8)
#define SOUND_OBJ_UKIKI_CHATTER_SHORT SOUND_ARG_LOAD(5, 0, 0x39, 0x00, 8)
#define SOUND_OBJ_UKIKI_CHATTER_IDLE SOUND_ARG_LOAD(5, 0, 0x3A, 0x00, 8)
#define SOUND_OBJ_UKIKI_STEP_DEFAULT SOUND_ARG_LOAD(5, 0, 0x3B, 0x00, 8)
#define SOUND_OBJ_UKIKI_STEP_LEAVES SOUND_ARG_LOAD(5, 0, 0x3C, 0x00, 8)
#define SOUND_OBJ_KOOPA_TALK SOUND_ARG_LOAD(5, 0, 0x3D, 0xA0, 8)
#define SOUND_OBJ_KOOPA_DAMAGE SOUND_ARG_LOAD(5, 0, 0x3E, 0xA0, 8)
/* not verified */ #define SOUND_OBJ_KLEPTO1 SOUND_ARG_LOAD(5, 0, 0x3F, 0x40, 8)
/* not verified */ #define SOUND_OBJ_KLEPTO2 SOUND_ARG_LOAD(5, 0, 0x40, 0x60, 8)
#define SOUND_OBJ_KING_BOBOMB_TALK SOUND_ARG_LOAD(5, 0, 0x41, 0x00, 8)
#define SOUND_OBJ_KING_BOBOMB_JUMP SOUND_ARG_LOAD(5, 0, 0x46, 0x80, 8)
#define SOUND_OBJ_KING_WHOMP_DEATH SOUND_ARG_LOAD(5, 1, 0x47, 0xC0, 8)
#define SOUND_OBJ_BOO_LAUGH_LONG SOUND_ARG_LOAD(5, 0, 0x48, 0x00, 8)
/* not verified */ #define SOUND_OBJ_EEL SOUND_ARG_LOAD(5, 0, 0x4A, 0x00, 8)
/* not verified */ #define SOUND_OBJ_EEL_2 SOUND_ARG_LOAD(5, 2, 0x4A, 0x00, 8)
#define SOUND_OBJ_EYEROK_SHOW_EYE SOUND_ARG_LOAD(5, 2, 0x4B, 0x00, 8)
#define SOUND_OBJ_MR_BLIZZARD_ALERT SOUND_ARG_LOAD(5, 0, 0x4C, 0x00, 8)
#define SOUND_OBJ_SNUFIT_SHOOT SOUND_ARG_LOAD(5, 0, 0x4D, 0x00, 8)
#define SOUND_OBJ_SKEETER_WALK SOUND_ARG_LOAD(5, 0, 0x4E, 0x00, 8)
/* not verified */ #define SOUND_OBJ_WALKING_WATER SOUND_ARG_LOAD(5, 0, 0x4F, 0x00, 8)
#define SOUND_OBJ_BIRD_CHIRP3 SOUND_ARG_LOAD(5, 0, 0x51, 0x40, 0)
#define SOUND_OBJ_PIRANHA_PLANT_APPEAR SOUND_ARG_LOAD(5, 0, 0x54, 0x20, 8)
#define SOUND_OBJ_FLAME_BLOWN SOUND_ARG_LOAD(5, 0, 0x55, 0x80, 8)
#define SOUND_OBJ_MAD_PIANO_CHOMPING SOUND_ARG_LOAD(5, 2, 0x56, 0x40, 8)
#define SOUND_OBJ_BOBOMB_BUDDY_TALK SOUND_ARG_LOAD(5, 0, 0x58, 0x40, 8)
/* not verified */ #define SOUND_OBJ_SPINY_UNK59 SOUND_ARG_LOAD(5, 0, 0x59, 0x10, 8)
#define SOUND_OBJ_WIGGLER_HIGH_PITCH SOUND_ARG_LOAD(5, 0, 0x5C, 0x40, 8)
#define SOUND_OBJ_HEAVEHO_TOSSED SOUND_ARG_LOAD(5, 0, 0x5D, 0x40, 8)
/* not verified */ #define SOUND_OBJ_WIGGLER_DEATH 0x505E
#define SOUND_OBJ_BOWSER_INTRO_LAUGH SOUND_ARG_LOAD(5, 0, 0x5F, 0x80, 9)
/* not verified */ #define SOUND_OBJ_ENEMY_DEATH_HIGH SOUND_ARG_LOAD(5, 0, 0x60, 0xB0, 8)
/* not verified */ #define SOUND_OBJ_ENEMY_DEATH_LOW SOUND_ARG_LOAD(5, 0, 0x61, 0xB0, 8)
#define SOUND_OBJ_SWOOP_DEATH SOUND_ARG_LOAD(5, 0, 0x62, 0xB0, 8)
#define SOUND_OBJ_KOOPA_FLYGUY_DEATH SOUND_ARG_LOAD(5, 0, 0x63, 0xB0, 8)
#define SOUND_OBJ_POKEY_DEATH SOUND_ARG_LOAD(5, 0, 0x63, 0xC0, 8)
/* not verified */ #define SOUND_OBJ_SNOWMAN_BOUNCE SOUND_ARG_LOAD(5, 0, 0x64, 0xC0, 8)
#define SOUND_OBJ_SNOWMAN_EXPLODE SOUND_ARG_LOAD(5, 0, 0x65, 0xD0, 8)
/* not verified */ #define SOUND_OBJ_POUNDING_LOUD SOUND_ARG_LOAD(5, 0, 0x68, 0x40, 8)
/* not verified */ #define SOUND_OBJ_MIPS_RABBIT SOUND_ARG_LOAD(5, 0, 0x6A, 0x00, 8)
/* not verified */ #define SOUND_OBJ_MIPS_RABBIT_WATER SOUND_ARG_LOAD(5, 0, 0x6C, 0x00, 8)
#define SOUND_OBJ_EYEROK_EXPLODE SOUND_ARG_LOAD(5, 0, 0x6D, 0x00, 8)
#define SOUND_OBJ_CHUCKYA_DEATH SOUND_ARG_LOAD(5, 1, 0x6E, 0x00, 8)
#define SOUND_OBJ_WIGGLER_TALK SOUND_ARG_LOAD(5, 0, 0x6F, 0x00, 8)
#define SOUND_OBJ_WIGGLER_ATTACKED SOUND_ARG_LOAD(5, 0, 0x70, 0x60, 8)
#define SOUND_OBJ_WIGGLER_LOW_PITCH SOUND_ARG_LOAD(5, 0, 0x71, 0x20, 8)
#define SOUND_OBJ_SNUFIT_SKEETER_DEATH SOUND_ARG_LOAD(5, 0, 0x72, 0xC0, 8)
#define SOUND_OBJ_BUBBA_CHOMP SOUND_ARG_LOAD(5, 0, 0x73, 0x40, 8)
#define SOUND_OBJ_ENEMY_DEFEAT_SHRINK SOUND_ARG_LOAD(5, 0, 0x74, 0x40, 8)
#define SOUND_AIR_BOWSER_SPIT_FIRE SOUND_ARG_LOAD(6, 0, 0x00, 0x00, 0)
#define SOUND_AIR_UNK01 0x6001 // ?
#define SOUND_AIR_LAKITU_FLY SOUND_ARG_LOAD(6, 0, 0x02, 0x80, 0)
#define SOUND_AIR_LAKITU_FLY_HIGHPRIO SOUND_ARG_LOAD(6, 0, 0x02, 0xFF, 0)
#define SOUND_AIR_AMP_BUZZ SOUND_ARG_LOAD(6, 0, 0x03, 0x40, 0)
#define SOUND_AIR_BLOW_FIRE SOUND_ARG_LOAD(6, 0, 0x04, 0x80, 0)
#define SOUND_AIR_BLOW_WIND SOUND_ARG_LOAD(6, 0, 0x04, 0x40, 0)
#define SOUND_AIR_ROUGH_SLIDE SOUND_ARG_LOAD(6, 0, 0x05, 0x00, 0)
#define SOUND_AIR_HEAVEHO_MOVE SOUND_ARG_LOAD(6, 0, 0x06, 0x40, 0)
#define SOUND_AIR_UNK07 0x6007 // ?
#define SOUND_AIR_BOBOMB_LIT_FUSE SOUND_ARG_LOAD(6, 0, 0x08, 0x60, 0)
#define SOUND_AIR_HOWLING_WIND SOUND_ARG_LOAD(6, 0, 0x09, 0x80, 0)
#define SOUND_AIR_CHUCKYA_MOVE SOUND_ARG_LOAD(6, 0, 0x0A, 0x40, 0)
#define SOUND_AIR_PEACH_TWINKLE SOUND_ARG_LOAD(6, 0, 0x0B, 0x40, 0)
#define SOUND_AIR_CASTLE_OUTDOORS_AMBIENT SOUND_ARG_LOAD(6, 0, 0x10, 0x40, 0)
/* Menu Sound Effects */
#define SOUND_MENU_CHANGE_SELECT SOUND_ARG_LOAD(7, 0, 0x00, 0xF8, 8)
/* not verified */ #define SOUND_MENU_REVERSE_PAUSE 0x7001
#define SOUND_MENU_PAUSE SOUND_ARG_LOAD(7, 0, 0x02, 0xF0, 8)
#define SOUND_MENU_PAUSE_HIGHPRIO SOUND_ARG_LOAD(7, 0, 0x02, 0xFF, 8)
#define SOUND_MENU_PAUSE_2 SOUND_ARG_LOAD(7, 0, 0x03, 0xFF, 8)
#define SOUND_MENU_MESSAGE_APPEAR SOUND_ARG_LOAD(7, 0, 0x04, 0x00, 8)
#define SOUND_MENU_MESSAGE_DISAPPEAR SOUND_ARG_LOAD(7, 0, 0x05, 0x00, 8)
#define SOUND_MENU_CAMERA_ZOOM_IN SOUND_ARG_LOAD(7, 0, 0x06, 0x00, 8)
#define SOUND_MENU_CAMERA_ZOOM_OUT SOUND_ARG_LOAD(7, 0, 0x07, 0x00, 8)
#define SOUND_MENU_PINCH_MARIO_FACE SOUND_ARG_LOAD(7, 0, 0x08, 0x00, 8)
#define SOUND_MENU_LET_GO_MARIO_FACE SOUND_ARG_LOAD(7, 0, 0x09, 0x00, 8)
#define SOUND_MENU_HAND_APPEAR SOUND_ARG_LOAD(7, 0, 0x0A, 0x00, 8)
#define SOUND_MENU_HAND_DISAPPEAR SOUND_ARG_LOAD(7, 0, 0x0B, 0x00, 8)
/* not verified */ #define SOUND_MENU_UNK0C SOUND_ARG_LOAD(7, 0, 0x0C, 0x00, 8)
/* not verified */ #define SOUND_MENU_POWER_METER SOUND_ARG_LOAD(7, 0, 0x0D, 0x00, 8)
#define SOUND_MENU_CAMERA_BUZZ SOUND_ARG_LOAD(7, 0, 0x0E, 0x00, 8)
#define SOUND_MENU_CAMERA_TURN SOUND_ARG_LOAD(7, 0, 0x0F, 0x00, 8)
/* not verified */ #define SOUND_MENU_UNK10 0x7010
#define SOUND_MENU_CLICK_FILE_SELECT SOUND_ARG_LOAD(7, 0, 0x11, 0x00, 8)
/* not verified */ #define SOUND_MENU_MESSAGE_NEXT_PAGE SOUND_ARG_LOAD(7, 0, 0x13, 0x00, 8)
#define SOUND_MENU_COIN_ITS_A_ME_MARIO SOUND_ARG_LOAD(7, 0, 0x14, 0x00, 8)
#define SOUND_MENU_YOSHI_GAIN_LIVES SOUND_ARG_LOAD(7, 0, 0x15, 0x00, 8)
#define SOUND_MENU_ENTER_PIPE SOUND_ARG_LOAD(7, 0, 0x16, 0xA0, 8)
#define SOUND_MENU_EXIT_PIPE SOUND_ARG_LOAD(7, 0, 0x17, 0xA0, 8)
#define SOUND_MENU_BOWSER_LAUGH SOUND_ARG_LOAD(7, 0, 0x18, 0x80, 8)
#define SOUND_MENU_ENTER_HOLE SOUND_ARG_LOAD(7, 1, 0x19, 0x80, 8)
/* not verified */ #define SOUND_MENU_CLICK_CHANGE_VIEW SOUND_ARG_LOAD(7, 0, 0x1A, 0x80, 8)
/* not verified */ #define SOUND_MENU_CAMERA_UNUSED1 0x701B
/* not verified */ #define SOUND_MENU_CAMERA_UNUSED2 0x701C
/* not verified */ #define SOUND_MENU_MARIO_CASTLE_WARP SOUND_ARG_LOAD(7, 0, 0x1D, 0xB0, 8)
#define SOUND_MENU_STAR_SOUND SOUND_ARG_LOAD(7, 0, 0x1E, 0xFF, 8)
#define SOUND_MENU_THANK_YOU_PLAYING_MY_GAME SOUND_ARG_LOAD(7, 0, 0x1F, 0xFF, 8)
/* not verified */ #define SOUND_MENU_READ_A_SIGN 0x7020
/* not verified */ #define SOUND_MENU_EXIT_A_SIGN 0x7021
/* not verified */ #define SOUND_MENU_MARIO_CASTLE_WARP2 SOUND_ARG_LOAD(7, 0, 0x22, 0x20, 8)
#define SOUND_MENU_STAR_SOUND_OKEY_DOKEY SOUND_ARG_LOAD(7, 0, 0x23, 0xFF, 8)
#define SOUND_MENU_STAR_SOUND_LETS_A_GO SOUND_ARG_LOAD(7, 0, 0x24, 0xFF, 8)
// US/EU only; an index between 0-7 or 0-4 is added to the sound ID before
// playing, producing the same sound with different pitch.
#define SOUND_MENU_COLLECT_RED_COIN SOUND_ARG_LOAD(7, 8, 0x28, 0x90, 8)
#define SOUND_MENU_COLLECT_SECRET SOUND_ARG_LOAD(7, 0, 0x30, 0x20, 8)
// Channel 8 loads sounds from the same place as channel 3, making it possible
// to play two channel 3 sounds at once (since just one sound from each channel
// can play at a given time).
#define SOUND_GENERAL2_BOBOMB_EXPLOSION SOUND_ARG_LOAD(8, 0, 0x2E, 0x20, 8)
#define SOUND_GENERAL2_PURPLE_SWITCH SOUND_ARG_LOAD(8, 0, 0x3E, 0xC0, 8)
#define SOUND_GENERAL2_ROTATING_BLOCK_CLICK SOUND_ARG_LOAD(8, 0, 0x40, 0x00, 8)
#define SOUND_GENERAL2_SPINDEL_ROLL SOUND_ARG_LOAD(8, 0, 0x48, 0x20, 8)
#define SOUND_GENERAL2_PYRAMID_TOP_SPIN SOUND_ARG_LOAD(8, 1, 0x4B, 0xE0, 8)
#define SOUND_GENERAL2_PYRAMID_TOP_EXPLOSION SOUND_ARG_LOAD(8, 1, 0x4C, 0xF0, 8)
#define SOUND_GENERAL2_BIRD_CHIRP2 SOUND_ARG_LOAD(8, 0, 0x50, 0x40, 0)
#define SOUND_GENERAL2_SWITCH_TICK_FAST SOUND_ARG_LOAD(8, 0, 0x54, 0xF0, 1)
#define SOUND_GENERAL2_SWITCH_TICK_SLOW SOUND_ARG_LOAD(8, 0, 0x55, 0xF0, 1)
#define SOUND_GENERAL2_STAR_APPEARS SOUND_ARG_LOAD(8, 0, 0x57, 0xFF, 9)
#define SOUND_GENERAL2_ROTATING_BLOCK_ALERT SOUND_ARG_LOAD(8, 0, 0x59, 0x00, 8)
#define SOUND_GENERAL2_BOWSER_EXPLODE SOUND_ARG_LOAD(8, 0, 0x60, 0x00, 8)
#define SOUND_GENERAL2_BOWSER_KEY SOUND_ARG_LOAD(8, 0, 0x61, 0x00, 8)
#define SOUND_GENERAL2_1UP_APPEAR SOUND_ARG_LOAD(8, 0, 0x63, 0xD0, 8)
#define SOUND_GENERAL2_RIGHT_ANSWER SOUND_ARG_LOAD(8, 0, 0x6A, 0xA0, 8)
// Channel 9 loads sounds from the same place as channel 5.
#define SOUND_OBJ2_BOWSER_ROAR SOUND_ARG_LOAD(9, 0, 0x04, 0x00, 8)
#define SOUND_OBJ2_PIRANHA_PLANT_BITE SOUND_ARG_LOAD(9, 0, 0x10, 0x50, 8)
#define SOUND_OBJ2_PIRANHA_PLANT_DYING SOUND_ARG_LOAD(9, 0, 0x11, 0x60, 8)
#define SOUND_OBJ2_BOWSER_PUZZLE_PIECE_MOVE SOUND_ARG_LOAD(9, 0, 0x19, 0x20, 8)
#define SOUND_OBJ2_BULLY_ATTACKED SOUND_ARG_LOAD(9, 0, 0x1C, 0x00, 8)
#define SOUND_OBJ2_KING_BOBOMB_DAMAGE SOUND_ARG_LOAD(9, 1, 0x42, 0x40, 8)
#define SOUND_OBJ2_SCUTTLEBUG_WALK SOUND_ARG_LOAD(9, 0, 0x43, 0x40, 8)
#define SOUND_OBJ2_SCUTTLEBUG_ALERT SOUND_ARG_LOAD(9, 0, 0x44, 0x40, 8)
#define SOUND_OBJ2_BABY_PENGUIN_YELL SOUND_ARG_LOAD(9, 0, 0x45, 0x00, 8)
#define SOUND_OBJ2_SWOOP SOUND_ARG_LOAD(9, 0, 0x49, 0x00, 8)
#define SOUND_OBJ2_BIRD_CHIRP1 SOUND_ARG_LOAD(9, 0, 0x52, 0x40, 0)
#define SOUND_OBJ2_LARGE_BULLY_ATTACKED SOUND_ARG_LOAD(9, 0, 0x57, 0x00, 8)
#define SOUND_OBJ2_EYEROK_SOUND_SHORT SOUND_ARG_LOAD(9, 3, 0x5A, 0x00, 8)
#define SOUND_OBJ2_WHOMP_SOUND_SHORT SOUND_ARG_LOAD(9, 3, 0x5A, 0xC0, 8)
#define SOUND_OBJ2_EYEROK_SOUND_LONG SOUND_ARG_LOAD(9, 2, 0x5B, 0x00, 8)
#define SOUND_OBJ2_BOWSER_TELEPORT SOUND_ARG_LOAD(9, 0, 0x66, 0x80, 8)
#define SOUND_OBJ2_MONTY_MOLE_APPEAR SOUND_ARG_LOAD(9, 0, 0x67, 0x80, 8)
#define SOUND_OBJ2_BOSS_DIALOG_GRUNT SOUND_ARG_LOAD(9, 0, 0x69, 0x40, 8)
#define SOUND_OBJ2_MRI_SPINNING SOUND_ARG_LOAD(9, 0, 0x6B, 0x00, 8)
#endif // AUDIO_DEFINES_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef COMMAND_MACROS_BASE_H
#define COMMAND_MACROS_BASE_H
#include "PR/gbi.h"
#if IS_BIG_ENDIAN
#if IS_64_BIT
#define CMD_BBBB(a, b, c, d) ((uintptr_t)(_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 8, 8) | _SHIFTL(d, 0, 8)) << 32)
#define CMD_BBH(a, b, c) ((uintptr_t)(_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 0, 16)) << 32)
#define CMD_HH(a, b) ((uintptr_t)(_SHIFTL(a, 16, 16) | _SHIFTL(b, 0, 16)) << 32)
#define CMD_W(a) ((uintptr_t)(a) << 32)
#else
#define CMD_BBBB(a, b, c, d) (_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 8, 8) | _SHIFTL(d, 0, 8))
#define CMD_BBH(a, b, c) (_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 0, 16))
#define CMD_HH(a, b) (_SHIFTL(a, 16, 16) | _SHIFTL(b, 0, 16))
#define CMD_W(a) (a)
#endif
#else
#define CMD_BBBB(a, b, c, d) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 8) | _SHIFTL(d, 24, 8))
#define CMD_BBH(a, b, c) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 16))
#define CMD_HH(a, b) (_SHIFTL(a, 0, 16) | _SHIFTL(b, 16, 16))
#define CMD_W(a) (a)
#endif
#define CMD_PTR(a) ((uintptr_t)(a))
#define CMD_HHHHHH(a, b, c, d, e, f) CMD_HH(a, b), CMD_HH(c, d), CMD_HH(e, f)
#endif // COMMAND_MACROS_BASE_H
+432
View File
@@ -0,0 +1,432 @@
#ifndef GEO_COMMANDS_H
#define GEO_COMMANDS_H
#include "command_macros_base.h"
//#include "game/shadow.h"
//#include "game/object_helpers.h"
//#include "game/behavior_actions.h"
//#include "game/segment2.h"
#include "../game/mario_misc.h"
#include "../game/mario_actions_cutscene.h"
// sky background params
#define BACKGROUND_OCEAN_SKY 0
#define BACKGROUND_FLAMING_SKY 1
#define BACKGROUND_UNDERWATER_CITY 2
#define BACKGROUND_BELOW_CLOUDS 3
#define BACKGROUND_SNOW_MOUNTAINS 4
#define BACKGROUND_DESERT 5
#define BACKGROUND_HAUNTED 6
#define BACKGROUND_GREEN_SKY 7
#define BACKGROUND_ABOVE_CLOUDS 8
#define BACKGROUND_PURPLE_SKY 9
// geo layout macros
/**
* 0x00: Branch and store return address
* 0x04: scriptTarget, segment address of geo layout
*/
#define GEO_BRANCH_AND_LINK(scriptTarget) \
CMD_BBH(0x00, 0x00, 0x0000), \
CMD_PTR(scriptTarget)
/**
* 0x01: Terminate geo layout
* 0x01-0x03: unused
*/
#define GEO_END() \
CMD_BBH(0x01, 0x00, 0x0000)
/**
* 0x02: Branch
* 0x01: if 1, store next geo layout address on stack
* 0x02-0x03: unused
* 0x04: scriptTarget, segment address of geo layout
*/
#define GEO_BRANCH(type, scriptTarget) \
CMD_BBH(0x02, type, 0x0000), \
CMD_PTR(scriptTarget)
/**
* 0x03: Return from branch
* 0x01-0x03: unused
*/
#define GEO_RETURN() \
CMD_BBH(0x03, 0x00, 0x0000)
/**
* 0x04: Open node
* 0x01-0x03: unused
*/
#define GEO_OPEN_NODE() \
CMD_BBH(0x04, 0x00, 0x0000)
/**
* 0x05: Close node
* 0x01-0x03: unused
*/
#define GEO_CLOSE_NODE() \
CMD_BBH(0x05, 0x00, 0x0000)
/**
* 0x06: Register the current node at the given index in the gGeoViews array
* 0x01: unused
* 0x02: s16 index
*/
#define GEO_ASSIGN_AS_VIEW(index) \
CMD_BBH(0x06, 0x00, index)
/**
* 0x07: Update current scene graph node flags
* 0x01: u8 operation (0 = reset, 1 = set, 2 = clear)
* 0x02: s16 bits
*/
#define GEO_UPDATE_NODE_FLAGS(operation, flagBits) \
CMD_BBH(0x07, operation, flagBits)
/**
* 0x08: Create screen area scene graph node
* 0x01: unused
* 0x02: s16 num entries (+2) to allocate
* 0x04: s16 x
* 0x06: s16 y
* 0x08: s16 width
* 0x0A: s16 height
*/
#define GEO_NODE_SCREEN_AREA(numEntries, x, y, width, height) \
CMD_BBH(0x08, 0x00, numEntries), \
CMD_HH(x, y), \
CMD_HH(width, height)
/**
* 0x09: Create orthographic projection scene graph node
* 0x02: s16 scale as percentage
*/
#define GEO_NODE_ORTHO(scale) \
CMD_BBH(0x09, 0x00, scale)
/**
* 0x0A: Create camera frustum scene graph node
* 0x01: u8 if nonzero, enable function field
* 0x02: s16 field of view
* 0x04: s16 near
* 0x06: s16 far
* 0x08: [GraphNodeFunc function]
*/
#define GEO_CAMERA_FRUSTUM(fov, near, far) \
CMD_BBH(0x0A, 0x00, fov), \
CMD_HH(near, far)
#define GEO_CAMERA_FRUSTUM_WITH_FUNC(fov, near, far, func) \
CMD_BBH(0x0A, 0x01, fov), \
CMD_HH(near, far), \
CMD_PTR(func)
/**
* 0x0B: Create a root scene graph node
* 0x01-0x03: unused
*/
#define GEO_NODE_START() \
CMD_BBH(0x0B, 0x00, 0x0000)
/**
* 0x0C: Create zbuffer-toggling scene graph node
* 0x01: u8 enableZBuffer (1 = on, 0 = off)
* 0x02-0x03: unused
*/
#define GEO_ZBUFFER(enable) \
CMD_BBH(0x0C, enable, 0x0000)
/**
* 0x0D: Create render range scene graph node
* 0x01-0x03: unused
* 0x04: s16 minDistance
* 0x06: s16 maxDistance
*/
#define GEO_RENDER_RANGE(minDistance, maxDistance) \
CMD_BBH(0x0D, 0x00, 0x0000), \
CMD_HH(minDistance, maxDistance)
/**
* 0x0E: Create switch-case scene graph node
* 0x01: unused
* 0x02: s16 numCases
* 0x04: GraphNodeFunc caseSelectorFunc
*/
#define GEO_SWITCH_CASE(count, function) \
CMD_BBH(0x0E, 0x00, count), \
CMD_PTR(function)
/**
* 0x0F: Create a camera scene graph node.
* 0x01: unused
* 0x02: s16 camera type
* 0x04: s16 posX
* 0x06: s16 posY
* 0x08: s16 posZ
* 0x0A: s16 focusX
* 0x0C: s16 focusY
* 0x0E: s16 focusZ
* 0x10: GraphNodeFunc function
*/
#define GEO_CAMERA(type, x1, y1, z1, x2, y2, z2, function) \
CMD_BBH(0x0F, 0x00, type), \
CMD_HHHHHH(x1, y1, z1, x2, y2, z2), \
CMD_PTR(function)
/**
* 0x10: Create translation & rotation scene graph node with optional display list
* Four different versions of 0x10
* cmd+0x01: u8 params
* 0b1000_0000: if set, enable displayList field and drawingLayer
* 0b0111_0000: fieldLayout (determines how rest of data is formatted
* 0b0000_1111: drawingLayer
*
* fieldLayout = 0: Translate & Rotate
* 0x04: s16 xTranslation
* 0x06: s16 yTranslation
* 0x08: s16 zTranslation
* 0x0A: s16 xRotation
* 0x0C: s16 yRotation
* 0x0E: s16 zRotation
* 0x10: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_TRANSLATE_ROTATE(layer, tx, ty, tz, rx, ry, rz) \
CMD_BBH(0x10, (0x00 | layer), 0x0000), \
CMD_HHHHHH(tx, ty, tz, rx, ry, rz)
#define GEO_TRANSLATE_ROTATE_WITH_DL(layer, tx, ty, tz, rx, ry, rz, displayList) \
CMD_BBH(0x10, (0x00 | layer | 0x80), 0x0000), \
CMD_HHHHHH(tx, ty, tz, rx, ry, rz), \
CMD_PTR(displayList)
/**
* fieldLayout = 1: Translate
* 0x02: s16 xTranslation
* 0x04: s16 yTranslation
* 0x06: s16 zTranslation
* 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_TRANSLATE(layer, tx, ty, tz) \
CMD_BBH(0x10, (0x10 | layer), tx), \
CMD_HH(ty, tz)
#define GEO_TRANSLATE_WITH_DL(layer, tx, ty, tz, displayList) \
CMD_BBH(0x10, (0x10 | layer | 0x80), tx), \
CMD_HH(ty, tz), \
CMD_PTR(displayList)
/**
* fieldLayout = 2: Rotate
* 0x02: s16 xRotation
* 0x04: s16 yRotation
* 0x06: s16 zRotation
* 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_ROTATE(layer, rx, ry, rz) \
CMD_BBH(0x10, (0x20 | layer), rx), \
CMD_HH(ry, rz)
#define GEO_ROTATE_WITH_DL(layer, rx, ry, rz, displayList) \
CMD_BBH(0x10, (0x20 | layer | 0x80), rx), \
CMD_HH(ry, rz), \
CMD_PTR(displayList)
/**
* fieldLayout = 3: Rotate Y
* 0x02: s16 yRotation
* 0x04: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_ROTATE_Y(layer, ry) \
CMD_BBH(0x10, (0x30 | layer), ry)
#define GEO_ROTATE_Y_WITH_DL(layer, ry, displayList) \
CMD_BBH(0x10, (0x30 | layer | 0x80), ry), \
CMD_PTR(displayList)
/**
* 0x11: Create translation scene graph node with optional display list
* 0x01: u8 params
* 0b1000_0000: if set, enable displayList field and drawingLayer
* 0b0000_1111: drawingLayer
* 0x02: s16 translationX
* 0x04: s16 translationY
* 0x06: s16 translationZ
* 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_TRANSLATE_NODE(layer, ux, uy, uz) \
CMD_BBH(0x11, layer, ux), \
CMD_HH(uy, uz)
#define GEO_TRANSLATE_NODE_WITH_DL(layer, ux, uy, uz, displayList) \
CMD_BBH(0x11, (layer | 0x80), ux), \
CMD_HH(uy, uz), \
CMD_PTR(displayList)
/**
* 0x12: Create rotation scene graph node with optional display list
* 0x01: u8 params
* 0b1000_0000: if set, enable displayList field and drawingLayer
* 0b0000_1111: drawingLayer
* 0x02: s16 rotationX
* 0x04: s16 rotationY
* 0x06: s16 rotationZ
* 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
*/
#define GEO_ROTATION_NODE(layer, ux, uy, uz) \
CMD_BBH(0x12, layer, ux), \
CMD_HH(uy, uz)
#define GEO_ROTATION_NODE_WITH_DL(layer, ux, uy, uz, displayList) \
CMD_BBH(0x12, (layer | 0x80), ux), \
CMD_HH(uy, uz), \
CMD_PTR(displayList)
/**
* 0x13: Create a scene graph node that is rotated by the object's animation.
* 0x01: u8 drawingLayer
* 0x02: s16 xTranslation
* 0x04: s16 yTranslation
* 0x06: s16 zTranslation
* 0x08: u32 displayList: dislay list segmented address
*/
#define GEO_ANIMATED_PART(layer, x, y, z, displayList) \
CMD_BBH(0x13, layer, x), \
CMD_HH(y, z), \
CMD_PTR(displayList)
/**
* 0x14: Create billboarding node with optional display list
* 0x01: u8 params
* 0b1000_0000: if set, enable displayList field and drawingLayer
* 0b0000_1111: drawingLayer
* 0x02: s16 xTranslation
* 0x04: s16 yTranslation
* 0x06: s16 zTranslation
* 0x08: [u32 displayList: if MSbit of params is set, display list segmented address]
*/
#define GEO_BILLBOARD_WITH_PARAMS(layer, tx, ty, tz) \
CMD_BBH(0x14, layer, tx), \
CMD_HH(ty, tz)
#define GEO_BILLBOARD_WITH_PARAMS_AND_DL(layer, tx, ty, tz, displayList) \
CMD_BBH(0x14, (layer | 0x80), tx), \
CMD_HH(ty, tz), \
CMD_PTR(displayList)
#define GEO_BILLBOARD() \
GEO_BILLBOARD_WITH_PARAMS(0, 0, 0, 0)
/**
* 0x15: Create plain display list scene graph node
* 0x01: u8 drawingLayer
* 0x02-0x03: unused
* 0x04: u32 displayList: display list segmented address
*/
#define GEO_DISPLAY_LIST(layer, displayList) \
CMD_BBH(0x15, layer, 0x0000), \
CMD_PTR(displayList)
/**
* 0x16: Create shadow scene graph node
* 0x01: unused
* 0x02: s16 shadowType (cast to u8)
* 0x04: s16 shadowSolidity (cast to u8)
* 0x06: s16 shadowScale
*/
#define GEO_SHADOW(type, solidity, scale) \
CMD_BBH(0x16, 0x00, type), \
CMD_HH(solidity, scale)
/**
* 0x17: Create render object scene graph node
* 0x01-0x03: unused
*/
#define GEO_RENDER_OBJ() \
CMD_BBH(0x17, 0x00, 0x0000)
/**
* 0x18: Create dynamically generated displaylist scene graph node
* 0x01: unused
* 0x02: s16 parameter
* 0x04: GraphNodeFunc function
*/
#define GEO_ASM(param, function) \
CMD_BBH(0x18, 0x00, param), \
CMD_PTR(function)
/**
* 0x19: Create background scene graph node
* 0x02: s16 background: background ID, or RGBA5551 color if backgroundFunc is null
* 0x04: GraphNodeFunc backgroundFunc
*/
#define GEO_BACKGROUND(background, function) \
CMD_BBH(0x19, 0x00, background), \
CMD_PTR(function)
#define GEO_BACKGROUND_COLOR(background) \
GEO_BACKGROUND(background, NULL)
/**
* 0x1A: No operation
*/
#define GEO_NOP_1A() \
CMD_BBH(0x1A, 0x00, 0x0000), \
CMD_HH(0x0000, 0x0000)
/**
* 0x1B: Copy the shared children from an object parent node from a specific view
* to a newly created object parent.
* 0x02: s16 index of array
*/
#define GEO_COPY_VIEW(index) \
CMD_BBH(0x1B, 0x00, index)
/**
* 0x1C: Create a held object scene graph node
* cmd+0x01: u8 unused
* cmd+0x02: s16 offsetX
* cmd+0x04: s16 offsetY
* cmd+0x06: s16 offsetZ
* cmd+0x08: GraphNodeFunc nodeFunc
*/
#define GEO_HELD_OBJECT(param, ux, uy, uz, nodeFunc) \
CMD_BBH(0x1C, param, ux), \
CMD_HH(uy, uz), \
CMD_PTR(nodeFunc)
/**
* 0x1D: Create scale scene graph node with optional display list
* 0x01: u8 params
* 0b1000_0000: if set, enable displayList field and drawingLayer
* 0b0000_1111: drawingLayer
* 0x02-0x03: unused
* 0x04: u32 scale (0x10000 = 1.0)
* 0x08: [u32 displayList: if MSbit of params is set, display list segment address]
*/
#define GEO_SCALE(layer, scale) \
CMD_BBH(0x1D, layer, 0x0000), \
CMD_W(scale)
#define GEO_SCALE_WITH_DL(layer, scale, displayList) \
CMD_BBH(0x1D, (layer | 0x80), 0x0000), \
CMD_W(scale), \
CMD_PTR(displayList)
/**
* 0x1E: No operation
*/
#define GEO_NOP_1E() \
CMD_BBH(0x1E, 0x00, 0x0000), \
CMD_HH(0x0000, 0x0000)
/**
* 0x1F: No operation
*/
#define GEO_NOP_1F() \
CMD_BBH(0x1F, 0x00, 0x0000), \
CMD_HH(0x0000, 0x0000), \
CMD_HH(0x0000, 0x0000), \
CMD_HH(0x0000, 0x0000)
/**
* 0x20: Create a scene graph node that specifies for an object the radius that
* is used for frustum culling.
* 0x01: unused
* 0x02: s16 cullingRadius
*/
#define GEO_CULLING_RADIUS(cullingRadius) \
CMD_BBH(0x20, 0x00, cullingRadius)
#endif // GEO_COMMANDS_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef LEVEL_MISC_MACROS_H
#define LEVEL_MISC_MACROS_H
#define MACRO_OBJECT_WITH_BEH_PARAM(preset, yaw, posX, posY, posZ, behParam) \
((s16)((yaw * 0x10 / 45) << 9) | (preset + 0x1F)), posX, posY, posZ, behParam
#define MACRO_OBJECT(preset, yaw, posX, posY, posZ) \
MACRO_OBJECT_WITH_BEH_PARAM(preset, yaw, posX, posY, posZ, 0)
#define MACRO_OBJECT_END() \
0x001E
#define SPECIAL_OBJECT(preset, posX, posY, posZ) \
preset, posX, posY, posZ
#define SPECIAL_OBJECT_WITH_YAW(preset, posX, posY, posZ, yaw) \
preset, posX, posY, posZ, yaw
#define SPECIAL_OBJECT_WITH_YAW_AND_PARAM(preset, posX, posY, posZ, yaw, param) \
preset, posX, posY, posZ, yaw, param
#define TRAJECTORY_POS(trajId, x, y, z) \
trajId, x, y, z
#define TRAJECTORY_END() \
-1
#endif // LEVEL_MISC_MACROS_H
+77
View File
@@ -0,0 +1,77 @@
#ifndef MACROS_H
#define MACROS_H
#include "platform_info.h"
#ifndef __sgi
#define GLOBAL_ASM(...)
#endif
// ===== PATCH =====
#define NON_MATCHING 1
#define AVOID_UB 1
// =================
#if !defined(__sgi) && (!defined(NON_MATCHING) || !defined(AVOID_UB))
// asm-process isn't supported outside of IDO, and undefined behavior causes
// crashes.
#error Matching build is only possible on IDO; please build with NON_MATCHING=1.
#endif
#define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0]))
#define GLUE(a, b) a ## b
#define GLUE2(a, b) GLUE(a, b)
// Avoid compiler warnings for unused variables
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
// Avoid undefined behaviour for non-returning functions
#ifdef __GNUC__
#define NORETURN __attribute__((noreturn))
#else
#define NORETURN
#endif
// Static assertions
#ifdef __GNUC__
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#else
#define STATIC_ASSERT(cond, msg) typedef char GLUE2(static_assertion_failed, __LINE__)[(cond) ? 1 : -1]
#endif
// Align to 8-byte boundary for DMA requirements
#ifdef __GNUC__
#define ALIGNED8 __attribute__((aligned(8)))
#else
#define ALIGNED8
#endif
// Align to 16-byte boundary for audio lib requirements
#ifdef __GNUC__
#define ALIGNED16 __attribute__((aligned(16)))
#else
#define ALIGNED16
#endif
#ifndef NO_SEGMENTED_MEMORY
// convert a virtual address to physical.
#define VIRTUAL_TO_PHYSICAL(addr) ((uintptr_t)(addr) & 0x1FFFFFFF)
// convert a physical address to virtual.
#define PHYSICAL_TO_VIRTUAL(addr) ((uintptr_t)(addr) | 0x80000000)
// another way of converting virtual to physical
#define VIRTUAL_TO_PHYSICAL2(addr) ((u8 *)(addr) - 0x80000000U)
#else
// no conversion needed other than cast
#define VIRTUAL_TO_PHYSICAL(addr) ((addr))
#define PHYSICAL_TO_VIRTUAL(addr) ((addr))
#define VIRTUAL_TO_PHYSICAL2(addr) ((void *)(addr))
#endif
#endif // MACROS_H
+219
View File
@@ -0,0 +1,219 @@
#ifndef MARIO_ANIMATION_IDS_H
#define MARIO_ANIMATION_IDS_H
/* Mario Animation IDs */
enum MarioAnimID
{
/* 0x00 */ MARIO_ANIM_SLOW_LEDGE_GRAB,
/* 0x01 */ MARIO_ANIM_FALL_OVER_BACKWARDS,
/* 0x02 */ MARIO_ANIM_BACKWARD_AIR_KB,
/* 0x03 */ MARIO_ANIM_DYING_ON_BACK,
/* 0x04 */ MARIO_ANIM_BACKFLIP,
/* 0x05 */ MARIO_ANIM_CLIMB_UP_POLE,
/* 0x06 */ MARIO_ANIM_GRAB_POLE_SHORT,
/* 0x07 */ MARIO_ANIM_GRAB_POLE_SWING_PART1,
/* 0x08 */ MARIO_ANIM_GRAB_POLE_SWING_PART2,
/* 0x09 */ MARIO_ANIM_HANDSTAND_IDLE,
/* 0x0A */ MARIO_ANIM_HANDSTAND_JUMP,
/* 0x0B */ MARIO_ANIM_START_HANDSTAND,
/* 0x0C */ MARIO_ANIM_RETURN_FROM_HANDSTAND,
/* 0x0D */ MARIO_ANIM_IDLE_ON_POLE,
/* 0x0E */ MARIO_ANIM_A_POSE,
/* 0x0F */ MARIO_ANIM_SKID_ON_GROUND,
/* 0x10 */ MARIO_ANIM_STOP_SKID,
/* 0x11 */ MARIO_ANIM_CROUCH_FROM_FAST_LONGJUMP,
/* 0x12 */ MARIO_ANIM_CROUCH_FROM_SLOW_LONGJUMP,
/* 0x13 */ MARIO_ANIM_FAST_LONGJUMP,
/* 0x14 */ MARIO_ANIM_SLOW_LONGJUMP,
/* 0x15 */ MARIO_ANIM_AIRBORNE_ON_STOMACH,
/* 0x16 */ MARIO_ANIM_WALK_WITH_LIGHT_OBJ,
/* 0x17 */ MARIO_ANIM_RUN_WITH_LIGHT_OBJ,
/* 0x18 */ MARIO_ANIM_SLOW_WALK_WITH_LIGHT_OBJ,
/* 0x19 */ MARIO_ANIM_SHIVERING_WARMING_HAND,
/* 0x1A */ MARIO_ANIM_SHIVERING_RETURN_TO_IDLE,
/* 0x1B */ MARIO_ANIM_SHIVERING,
/* 0x1C */ MARIO_ANIM_CLIMB_DOWN_LEDGE,
/* 0x1D */ MARIO_ANIM_CREDITS_WAVING,
/* 0x1E */ MARIO_ANIM_CREDITS_LOOK_UP,
/* 0x1F */ MARIO_ANIM_CREDITS_RETURN_FROM_LOOK_UP,
/* 0x20 */ MARIO_ANIM_CREDITS_RAISE_HAND,
/* 0x21 */ MARIO_ANIM_CREDITS_LOWER_HAND,
/* 0x22 */ MARIO_ANIM_CREDITS_TAKE_OFF_CAP,
/* 0x23 */ MARIO_ANIM_CREDITS_START_WALK_LOOK_UP,
/* 0x24 */ MARIO_ANIM_CREDITS_LOOK_BACK_THEN_RUN,
/* 0x25 */ MARIO_ANIM_FINAL_BOWSER_RAISE_HAND_SPIN,
/* 0x26 */ MARIO_ANIM_FINAL_BOWSER_WING_CAP_TAKE_OFF,
/* 0x27 */ MARIO_ANIM_CREDITS_PEACE_SIGN,
/* 0x28 */ MARIO_ANIM_STAND_UP_FROM_LAVA_BOOST,
/* 0x29 */ MARIO_ANIM_FIRE_LAVA_BURN,
/* 0x2A */ MARIO_ANIM_WING_CAP_FLY,
/* 0x2B */ MARIO_ANIM_HANG_ON_OWL,
/* 0x2C */ MARIO_ANIM_LAND_ON_STOMACH,
/* 0x2D */ MARIO_ANIM_AIR_FORWARD_KB,
/* 0x2E */ MARIO_ANIM_DYING_ON_STOMACH,
/* 0x2F */ MARIO_ANIM_SUFFOCATING,
/* 0x30 */ MARIO_ANIM_COUGHING,
/* 0x31 */ MARIO_ANIM_THROW_CATCH_KEY,
/* 0x32 */ MARIO_ANIM_DYING_FALL_OVER,
/* 0x33 */ MARIO_ANIM_IDLE_ON_LEDGE,
/* 0x34 */ MARIO_ANIM_FAST_LEDGE_GRAB,
/* 0x35 */ MARIO_ANIM_HANG_ON_CEILING,
/* 0x36 */ MARIO_ANIM_PUT_CAP_ON,
/* 0x37 */ MARIO_ANIM_TAKE_CAP_OFF_THEN_ON,
/* 0x38 */ MARIO_ANIM_QUICKLY_PUT_CAP_ON, // unused
/* 0x39 */ MARIO_ANIM_HEAD_STUCK_IN_GROUND,
/* 0x3A */ MARIO_ANIM_GROUND_POUND_LANDING,
/* 0x3B */ MARIO_ANIM_TRIPLE_JUMP_GROUND_POUND,
/* 0x3C */ MARIO_ANIM_START_GROUND_POUND,
/* 0x3D */ MARIO_ANIM_GROUND_POUND,
/* 0x3E */ MARIO_ANIM_BOTTOM_STUCK_IN_GROUND,
/* 0x3F */ MARIO_ANIM_IDLE_WITH_LIGHT_OBJ,
/* 0x40 */ MARIO_ANIM_JUMP_LAND_WITH_LIGHT_OBJ,
/* 0x41 */ MARIO_ANIM_JUMP_WITH_LIGHT_OBJ,
/* 0x42 */ MARIO_ANIM_FALL_LAND_WITH_LIGHT_OBJ,
/* 0x43 */ MARIO_ANIM_FALL_WITH_LIGHT_OBJ,
/* 0x44 */ MARIO_ANIM_FALL_FROM_SLIDING_WITH_LIGHT_OBJ,
/* 0x45 */ MARIO_ANIM_SLIDING_ON_BOTTOM_WITH_LIGHT_OBJ,
/* 0x46 */ MARIO_ANIM_STAND_UP_FROM_SLIDING_WITH_LIGHT_OBJ,
/* 0x47 */ MARIO_ANIM_RIDING_SHELL,
/* 0x48 */ MARIO_ANIM_WALKING,
/* 0x49 */ MARIO_ANIM_FORWARD_FLIP, // unused
/* 0x4A */ MARIO_ANIM_JUMP_RIDING_SHELL,
/* 0x4B */ MARIO_ANIM_LAND_FROM_DOUBLE_JUMP,
/* 0x4C */ MARIO_ANIM_DOUBLE_JUMP_FALL,
/* 0x4D */ MARIO_ANIM_SINGLE_JUMP,
/* 0x4E */ MARIO_ANIM_LAND_FROM_SINGLE_JUMP,
/* 0x4F */ MARIO_ANIM_AIR_KICK,
/* 0x50 */ MARIO_ANIM_DOUBLE_JUMP_RISE,
/* 0x51 */ MARIO_ANIM_START_FORWARD_SPINNING, // unused
/* 0x52 */ MARIO_ANIM_THROW_LIGHT_OBJECT,
/* 0x53 */ MARIO_ANIM_FALL_FROM_SLIDE_KICK,
/* 0x54 */ MARIO_ANIM_BEND_KNESS_RIDING_SHELL, // unused
/* 0x55 */ MARIO_ANIM_LEGS_STUCK_IN_GROUND,
/* 0x56 */ MARIO_ANIM_GENERAL_FALL,
/* 0x57 */ MARIO_ANIM_GENERAL_LAND,
/* 0x58 */ MARIO_ANIM_BEING_GRABBED,
/* 0x59 */ MARIO_ANIM_GRAB_HEAVY_OBJECT,
/* 0x5A */ MARIO_ANIM_SLOW_LAND_FROM_DIVE,
/* 0x5B */ MARIO_ANIM_FLY_FROM_CANNON,
/* 0x5C */ MARIO_ANIM_MOVE_ON_WIRE_NET_RIGHT,
/* 0x5D */ MARIO_ANIM_MOVE_ON_WIRE_NET_LEFT,
/* 0x5E */ MARIO_ANIM_MISSING_CAP,
/* 0x5F */ MARIO_ANIM_PULL_DOOR_WALK_IN,
/* 0x60 */ MARIO_ANIM_PUSH_DOOR_WALK_IN,
/* 0x61 */ MARIO_ANIM_UNLOCK_DOOR,
/* 0x62 */ MARIO_ANIM_START_REACH_POCKET, // unused, reaching keys maybe?
/* 0x63 */ MARIO_ANIM_REACH_POCKET, // unused
/* 0x64 */ MARIO_ANIM_STOP_REACH_POCKET, // unused
/* 0x65 */ MARIO_ANIM_GROUND_THROW,
/* 0x66 */ MARIO_ANIM_GROUND_KICK,
/* 0x67 */ MARIO_ANIM_FIRST_PUNCH,
/* 0x68 */ MARIO_ANIM_SECOND_PUNCH,
/* 0x69 */ MARIO_ANIM_FIRST_PUNCH_FAST,
/* 0x6A */ MARIO_ANIM_SECOND_PUNCH_FAST,
/* 0x6B */ MARIO_ANIM_PICK_UP_LIGHT_OBJ,
/* 0x6C */ MARIO_ANIM_PUSHING,
/* 0x6D */ MARIO_ANIM_START_RIDING_SHELL,
/* 0x6E */ MARIO_ANIM_PLACE_LIGHT_OBJ,
/* 0x6F */ MARIO_ANIM_FORWARD_SPINNING,
/* 0x70 */ MARIO_ANIM_BACKWARD_SPINNING,
/* 0x71 */ MARIO_ANIM_BREAKDANCE,
/* 0x72 */ MARIO_ANIM_RUNNING,
/* 0x73 */ MARIO_ANIM_RUNNING_UNUSED, // unused duplicate, originally part 2?
/* 0x74 */ MARIO_ANIM_SOFT_BACK_KB,
/* 0x75 */ MARIO_ANIM_SOFT_FRONT_KB,
/* 0x76 */ MARIO_ANIM_DYING_IN_QUICKSAND,
/* 0x77 */ MARIO_ANIM_IDLE_IN_QUICKSAND,
/* 0x78 */ MARIO_ANIM_MOVE_IN_QUICKSAND,
/* 0x79 */ MARIO_ANIM_ELECTROCUTION,
/* 0x7A */ MARIO_ANIM_SHOCKED,
/* 0x7B */ MARIO_ANIM_BACKWARD_KB,
/* 0x7C */ MARIO_ANIM_FORWARD_KB,
/* 0x7D */ MARIO_ANIM_IDLE_HEAVY_OBJ,
/* 0x7E */ MARIO_ANIM_STAND_AGAINST_WALL,
/* 0x7F */ MARIO_ANIM_SIDESTEP_LEFT,
/* 0x80 */ MARIO_ANIM_SIDESTEP_RIGHT,
/* 0x81 */ MARIO_ANIM_START_SLEEP_IDLE,
/* 0x82 */ MARIO_ANIM_START_SLEEP_SCRATCH,
/* 0x83 */ MARIO_ANIM_START_SLEEP_YAWN,
/* 0x84 */ MARIO_ANIM_START_SLEEP_SITTING,
/* 0x85 */ MARIO_ANIM_SLEEP_IDLE,
/* 0x86 */ MARIO_ANIM_SLEEP_START_LYING,
/* 0x87 */ MARIO_ANIM_SLEEP_LYING,
/* 0x88 */ MARIO_ANIM_DIVE,
/* 0x89 */ MARIO_ANIM_SLIDE_DIVE,
/* 0x8A */ MARIO_ANIM_GROUND_BONK,
/* 0x8B */ MARIO_ANIM_STOP_SLIDE_LIGHT_OBJ,
/* 0x8C */ MARIO_ANIM_SLIDE_KICK,
/* 0x8D */ MARIO_ANIM_CROUCH_FROM_SLIDE_KICK,
/* 0x8E */ MARIO_ANIM_SLIDE_MOTIONLESS, // unused
/* 0x8F */ MARIO_ANIM_STOP_SLIDE,
/* 0x90 */ MARIO_ANIM_FALL_FROM_SLIDE,
/* 0x91 */ MARIO_ANIM_SLIDE,
/* 0x92 */ MARIO_ANIM_TIPTOE,
/* 0x93 */ MARIO_ANIM_TWIRL_LAND,
/* 0x94 */ MARIO_ANIM_TWIRL,
/* 0x95 */ MARIO_ANIM_START_TWIRL,
/* 0x96 */ MARIO_ANIM_STOP_CROUCHING,
/* 0x97 */ MARIO_ANIM_START_CROUCHING,
/* 0x98 */ MARIO_ANIM_CROUCHING,
/* 0x99 */ MARIO_ANIM_CRAWLING,
/* 0x9A */ MARIO_ANIM_STOP_CRAWLING,
/* 0x9B */ MARIO_ANIM_START_CRAWLING,
/* 0x9C */ MARIO_ANIM_SUMMON_STAR,
/* 0x9D */ MARIO_ANIM_RETURN_STAR_APPROACH_DOOR,
/* 0x9E */ MARIO_ANIM_BACKWARDS_WATER_KB,
/* 0x9F */ MARIO_ANIM_SWIM_WITH_OBJ_PART1,
/* 0xA0 */ MARIO_ANIM_SWIM_WITH_OBJ_PART2,
/* 0xA1 */ MARIO_ANIM_FLUTTERKICK_WITH_OBJ,
/* 0xA2 */ MARIO_ANIM_WATER_ACTION_END_WITH_OBJ, // either swimming or flutterkicking
/* 0xA3 */ MARIO_ANIM_STOP_GRAB_OBJ_WATER,
/* 0xA4 */ MARIO_ANIM_WATER_IDLE_WITH_OBJ,
/* 0xA5 */ MARIO_ANIM_DROWNING_PART1,
/* 0xA6 */ MARIO_ANIM_DROWNING_PART2,
/* 0xA7 */ MARIO_ANIM_WATER_DYING,
/* 0xA8 */ MARIO_ANIM_WATER_FORWARD_KB,
/* 0xA9 */ MARIO_ANIM_FALL_FROM_WATER,
/* 0xAA */ MARIO_ANIM_SWIM_PART1,
/* 0xAB */ MARIO_ANIM_SWIM_PART2,
/* 0xAC */ MARIO_ANIM_FLUTTERKICK,
/* 0xAD */ MARIO_ANIM_WATER_ACTION_END, // either swimming or flutterkicking
/* 0xAE */ MARIO_ANIM_WATER_PICK_UP_OBJ,
/* 0xAF */ MARIO_ANIM_WATER_GRAB_OBJ_PART2,
/* 0xB0 */ MARIO_ANIM_WATER_GRAB_OBJ_PART1,
/* 0xB1 */ MARIO_ANIM_WATER_THROW_OBJ,
/* 0xB2 */ MARIO_ANIM_WATER_IDLE,
/* 0xB3 */ MARIO_ANIM_WATER_STAR_DANCE,
/* 0xB4 */ MARIO_ANIM_RETURN_FROM_WATER_STAR_DANCE,
/* 0xB5 */ MARIO_ANIM_GRAB_BOWSER,
/* 0xB6 */ MARIO_ANIM_SWINGING_BOWSER,
/* 0xB7 */ MARIO_ANIM_RELEASE_BOWSER,
/* 0xB8 */ MARIO_ANIM_HOLDING_BOWSER,
/* 0xB9 */ MARIO_ANIM_HEAVY_THROW,
/* 0xBA */ MARIO_ANIM_WALK_PANTING,
/* 0xBB */ MARIO_ANIM_WALK_WITH_HEAVY_OBJ,
/* 0xBC */ MARIO_ANIM_TURNING_PART1,
/* 0xBD */ MARIO_ANIM_TURNING_PART2,
/* 0xBE */ MARIO_ANIM_SLIDEFLIP_LAND,
/* 0XBF */ MARIO_ANIM_SLIDEFLIP,
/* 0xC0 */ MARIO_ANIM_TRIPLE_JUMP_LAND,
/* 0xC1 */ MARIO_ANIM_TRIPLE_JUMP,
/* 0xC2 */ MARIO_ANIM_FIRST_PERSON,
/* 0xC3 */ MARIO_ANIM_IDLE_HEAD_LEFT,
/* 0xC4 */ MARIO_ANIM_IDLE_HEAD_RIGHT,
/* 0xC5 */ MARIO_ANIM_IDLE_HEAD_CENTER,
/* 0xC6 */ MARIO_ANIM_HANDSTAND_LEFT,
/* 0xC7 */ MARIO_ANIM_HANDSTAND_RIGHT,
/* 0xC8 */ MARIO_ANIM_WAKE_FROM_SLEEP,
/* 0xC9 */ MARIO_ANIM_WAKE_FROM_LYING,
/* 0xCA */ MARIO_ANIM_START_TIPTOE,
/* 0xCB */ MARIO_ANIM_SLIDEJUMP, // pole jump and wall kick
/* 0xCC */ MARIO_ANIM_START_WALLKICK,
/* 0xCD */ MARIO_ANIM_STAR_DANCE,
/* 0xCE */ MARIO_ANIM_RETURN_FROM_STAR_DANCE,
/* 0xCF */ MARIO_ANIM_FORWARD_SPINNING_FLIP,
/* 0xD0 */ MARIO_ANIM_TRIPLE_JUMP_FLY
};
#endif // MARIO_ANIMATION_IDS_H
@@ -0,0 +1,45 @@
#ifndef MARIO_GEO_SWITCH_CASE_IDS_H
#define MARIO_GEO_SWITCH_CASE_IDS_H
/* Mario Geo-Switch-Case IDs */
enum MarioEyesGSCId
{
/*0x00*/ MARIO_EYES_BLINK,
/*0x01*/ MARIO_EYES_OPEN,
/*0x02*/ MARIO_EYES_HALF_CLOSED,
/*0x03*/ MARIO_EYES_CLOSED,
/*0x04*/ MARIO_EYES_LOOK_LEFT, // unused
/*0x05*/ MARIO_EYES_LOOK_RIGHT, // unused
/*0x06*/ MARIO_EYES_LOOK_UP, // unused
/*0x07*/ MARIO_EYES_LOOK_DOWN, // unused
/*0x08*/ MARIO_EYES_DEAD
};
enum MarioHandGSCId
{
/*0x00*/ MARIO_HAND_FISTS,
/*0x01*/ MARIO_HAND_OPEN,
/*0x02*/ MARIO_HAND_PEACE_SIGN,
/*0x03*/ MARIO_HAND_HOLDING_CAP,
/*0x04*/ MARIO_HAND_HOLDING_WING_CAP,
/*0x05*/ MARIO_HAND_RIGHT_OPEN
};
enum MarioCapGSCId
{
/*0x00*/ MARIO_HAS_DEFAULT_CAP_ON,
/*0x01*/ MARIO_HAS_DEFAULT_CAP_OFF,
/*0x02*/ MARIO_HAS_WING_CAP_ON,
/*0x03*/ MARIO_HAS_WING_CAP_OFF // unused
};
enum MarioGrabPosGSCId
{
/*0x00*/ GRAB_POS_NULL,
/*0x01*/ GRAB_POS_LIGHT_OBJ,
/*0x02*/ GRAB_POS_HEAVY_OBJ,
/*0x03*/ GRAB_POS_BOWSER
};
#endif // MARIO_GEO_SWITCH_CASE_IDS_H
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
#ifndef PLATFORM_INFO_H
#define PLATFORM_INFO_H
#ifdef TARGET_N64
#define IS_64_BIT 0
#define IS_BIG_ENDIAN 1
#else
#include <stdint.h>
#define IS_64_BIT (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFU)
#define IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#endif
#define DOUBLE_SIZE_ON_64_BIT(size) ((size) * (sizeof(void *) / 4))
#endif // PLATFORM_INFO_H
+45
View File
@@ -0,0 +1,45 @@
#ifndef SEQ_IDS_H
#define SEQ_IDS_H
#define SEQ_VARIATION 0x80
enum SeqId {
SEQ_SOUND_PLAYER, // 0x00
SEQ_EVENT_CUTSCENE_COLLECT_STAR, // 0x01
SEQ_MENU_TITLE_SCREEN, // 0x02
SEQ_LEVEL_GRASS, // 0x03
SEQ_LEVEL_INSIDE_CASTLE, // 0x04
SEQ_LEVEL_WATER, // 0x05
SEQ_LEVEL_HOT, // 0x06
SEQ_LEVEL_BOSS_KOOPA, // 0x07
SEQ_LEVEL_SNOW, // 0x08
SEQ_LEVEL_SLIDE, // 0x09
SEQ_LEVEL_SPOOKY, // 0x0A
SEQ_EVENT_PIRANHA_PLANT, // 0x0B
SEQ_LEVEL_UNDERGROUND, // 0x0C
SEQ_MENU_STAR_SELECT, // 0x0D
SEQ_EVENT_POWERUP, // 0x0E
SEQ_EVENT_METAL_CAP, // 0x0F
SEQ_EVENT_KOOPA_MESSAGE, // 0x10
SEQ_LEVEL_KOOPA_ROAD, // 0x11
SEQ_EVENT_HIGH_SCORE, // 0x12
SEQ_EVENT_MERRY_GO_ROUND, // 0x13
SEQ_EVENT_RACE, // 0x14
SEQ_EVENT_CUTSCENE_STAR_SPAWN, // 0x15
SEQ_EVENT_BOSS, // 0x16
SEQ_EVENT_CUTSCENE_COLLECT_KEY, // 0x17
SEQ_EVENT_ENDLESS_STAIRS, // 0x18
SEQ_LEVEL_BOSS_KOOPA_FINAL, // 0x19
SEQ_EVENT_CUTSCENE_CREDITS, // 0x1A
SEQ_EVENT_SOLVE_PUZZLE, // 0x1B
SEQ_EVENT_TOAD_MESSAGE, // 0x1C
SEQ_EVENT_PEACH_MESSAGE, // 0x1D
SEQ_EVENT_CUTSCENE_INTRO, // 0x1E
SEQ_EVENT_CUTSCENE_VICTORY, // 0x1F
SEQ_EVENT_CUTSCENE_ENDING, // 0x20
SEQ_MENU_FILE_SELECT, // 0x21
SEQ_EVENT_CUTSCENE_LAKITU, // 0x22 (not in JP)
SEQ_COUNT
};
#endif // SEQ_IDS_H
+435
View File
@@ -0,0 +1,435 @@
#ifndef SM64_H
#define SM64_H
// Global header for Super Mario 64
#include "types.h"
// #include "config.h"
// #include "object_fields.h"
// #include "object_constants.h"
#include "audio_defines.h"
// #include "model_ids.h"
// #include "mario_animation_ids.h"
// #include "mario_geo_switch_case_ids.h"
#include "surface_terrains.h"
#include "macros.h"
// Crash handler enhancement
#ifdef CRASH_SCREEN_INCLUDED
#define DEBUG_ASSERT(exp) do { if (!(exp)) _n64_assert(__FILE__, __LINE__, #exp, 1); } while (0)
#else
#define DEBUG_ASSERT(exp)
#endif
// Pointer casting is technically UB, and avoiding it gets rid of endian issues
// as well as a nice side effect.
#ifdef AVOID_UB
#define GET_HIGH_U16_OF_32(var) ((u16)((var) >> 16))
#define GET_HIGH_S16_OF_32(var) ((s16)((var) >> 16))
#define GET_LOW_U16_OF_32(var) ((u16)((var) & 0xFFFF))
#define GET_LOW_S16_OF_32(var) ((s16)((var) & 0xFFFF))
#define SET_HIGH_U16_OF_32(var, x) ((var) = ((var) & 0xFFFF) | ((x) << 16))
#define SET_HIGH_S16_OF_32(var, x) ((var) = ((var) & 0xFFFF) | ((x) << 16))
#else
#define GET_HIGH_U16_OF_32(var) (((u16 *)&(var))[0])
#define GET_HIGH_S16_OF_32(var) (((s16 *)&(var))[0])
#define GET_LOW_U16_OF_32(var) (((u16 *)&(var))[1])
#define GET_LOW_S16_OF_32(var) (((s16 *)&(var))[1])
#define SET_HIGH_U16_OF_32(var, x) ((((u16 *)&(var))[0]) = (x))
#define SET_HIGH_S16_OF_32(var, x) ((((s16 *)&(var))[0]) = (x))
#endif
// Layers
#define LAYER_FORCE 0
#define LAYER_OPAQUE 1
#define LAYER_OPAQUE_DECAL 2
#define LAYER_OPAQUE_INTER 3
#define LAYER_ALPHA 4
#define LAYER_TRANSPARENT 5
#define LAYER_TRANSPARENT_DECAL 6
#define LAYER_TRANSPARENT_INTER 7
#define INPUT_NONZERO_ANALOG 0x0001
#define INPUT_A_PRESSED 0x0002
#define INPUT_OFF_FLOOR 0x0004
#define INPUT_ABOVE_SLIDE 0x0008
#define INPUT_FIRST_PERSON 0x0010
#define INPUT_UNKNOWN_5 0x0020
#define INPUT_SQUISHED 0x0040
#define INPUT_A_DOWN 0x0080
#define INPUT_IN_POISON_GAS 0x0100
#define INPUT_IN_WATER 0x0200
#define INPUT_UNKNOWN_10 0x0400
#define INPUT_INTERACT_OBJ_GRABBABLE 0x0800
#define INPUT_UNKNOWN_12 0x1000
#define INPUT_B_PRESSED 0x2000
#define INPUT_Z_DOWN 0x4000
#define INPUT_Z_PRESSED 0x8000
#define GROUND_STEP_LEFT_GROUND 0
#define GROUND_STEP_NONE 1
#define GROUND_STEP_HIT_WALL 2
#define GROUND_STEP_HIT_WALL_STOP_QSTEPS 2
#define GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS 3
#define AIR_STEP_CHECK_LEDGE_GRAB 0x00000001
#define AIR_STEP_CHECK_HANG 0x00000002
#define AIR_STEP_NONE 0
#define AIR_STEP_LANDED 1
#define AIR_STEP_HIT_WALL 2
#define AIR_STEP_GRABBED_LEDGE 3
#define AIR_STEP_GRABBED_CEILING 4
#define AIR_STEP_HIT_LAVA_WALL 6
#define WATER_STEP_NONE 0
#define WATER_STEP_HIT_FLOOR 1
#define WATER_STEP_HIT_CEILING 2
#define WATER_STEP_CANCELLED 3
#define WATER_STEP_HIT_WALL 4
#define PARTICLE_DUST /* 0x00000001 */ (1 << 0)
#define PARTICLE_VERTICAL_STAR /* 0x00000002 */ (1 << 1)
#define PARTICLE_2 /* 0x00000004 */ (1 << 2)
#define PARTICLE_SPARKLES /* 0x00000008 */ (1 << 3)
#define PARTICLE_HORIZONTAL_STAR /* 0x00000010 */ (1 << 4)
#define PARTICLE_BUBBLE /* 0x00000020 */ (1 << 5)
#define PARTICLE_WATER_SPLASH /* 0x00000040 */ (1 << 6)
#define PARTICLE_IDLE_WATER_WAVE /* 0x00000080 */ (1 << 7)
#define PARTICLE_SHALLOW_WATER_WAVE /* 0x00000100 */ (1 << 8)
#define PARTICLE_PLUNGE_BUBBLE /* 0x00000200 */ (1 << 9)
#define PARTICLE_WAVE_TRAIL /* 0x00000400 */ (1 << 10)
#define PARTICLE_FIRE /* 0x00000800 */ (1 << 11)
#define PARTICLE_SHALLOW_WATER_SPLASH /* 0x00001000 */ (1 << 12)
#define PARTICLE_LEAF /* 0x00002000 */ (1 << 13)
#define PARTICLE_SNOW /* 0x00004000 */ (1 << 14)
#define PARTICLE_DIRT /* 0x00008000 */ (1 << 15)
#define PARTICLE_MIST_CIRCLE /* 0x00010000 */ (1 << 16)
#define PARTICLE_BREATH /* 0x00020000 */ (1 << 17)
#define PARTICLE_TRIANGLE /* 0x00040000 */ (1 << 18)
#define PARTICLE_19 /* 0x00080000 */ (1 << 19)
#define MODEL_STATE_NOISE_ALPHA 0x180
#define MODEL_STATE_METAL 0x200
#define MARIO_NORMAL_CAP 0x00000001
#define MARIO_VANISH_CAP 0x00000002
#define MARIO_METAL_CAP 0x00000004
#define MARIO_WING_CAP 0x00000008
#define MARIO_CAP_ON_HEAD 0x00000010
#define MARIO_CAP_IN_HAND 0x00000020
#define MARIO_METAL_SHOCK 0x00000040
#define MARIO_TELEPORTING 0x00000080
#define MARIO_UNKNOWN_08 0x00000100
#define MARIO_UNKNOWN_13 0x00002000
#define MARIO_ACTION_SOUND_PLAYED 0x00010000
#define MARIO_MARIO_SOUND_PLAYED 0x00020000
#define MARIO_UNKNOWN_18 0x00040000
#define MARIO_PUNCHING 0x00100000
#define MARIO_KICKING 0x00200000
#define MARIO_TRIPPING 0x00400000
#define MARIO_UNKNOWN_25 0x02000000
#define MARIO_UNKNOWN_30 0x40000000
#define MARIO_UNKNOWN_31 0x80000000
#define MARIO_SPECIAL_CAPS (MARIO_VANISH_CAP | MARIO_METAL_CAP | MARIO_WING_CAP)
#define MARIO_CAPS (MARIO_NORMAL_CAP | MARIO_SPECIAL_CAPS)
#define ACT_ID_MASK 0x000001FF
#define ACT_GROUP_MASK 0x000001C0
#define ACT_GROUP_STATIONARY /* 0x00000000 */ (0 << 6)
#define ACT_GROUP_MOVING /* 0x00000040 */ (1 << 6)
#define ACT_GROUP_AIRBORNE /* 0x00000080 */ (2 << 6)
#define ACT_GROUP_SUBMERGED /* 0x000000C0 */ (3 << 6)
#define ACT_GROUP_CUTSCENE /* 0x00000100 */ (4 << 6)
#define ACT_GROUP_AUTOMATIC /* 0x00000140 */ (5 << 6)
#define ACT_GROUP_OBJECT /* 0x00000180 */ (6 << 6)
#define ACT_FLAG_STATIONARY /* 0x00000200 */ (1 << 9)
#define ACT_FLAG_MOVING /* 0x00000400 */ (1 << 10)
#define ACT_FLAG_AIR /* 0x00000800 */ (1 << 11)
#define ACT_FLAG_INTANGIBLE /* 0x00001000 */ (1 << 12)
#define ACT_FLAG_SWIMMING /* 0x00002000 */ (1 << 13)
#define ACT_FLAG_METAL_WATER /* 0x00004000 */ (1 << 14)
#define ACT_FLAG_SHORT_HITBOX /* 0x00008000 */ (1 << 15)
#define ACT_FLAG_RIDING_SHELL /* 0x00010000 */ (1 << 16)
#define ACT_FLAG_INVULNERABLE /* 0x00020000 */ (1 << 17)
#define ACT_FLAG_BUTT_OR_STOMACH_SLIDE /* 0x00040000 */ (1 << 18)
#define ACT_FLAG_DIVING /* 0x00080000 */ (1 << 19)
#define ACT_FLAG_ON_POLE /* 0x00100000 */ (1 << 20)
#define ACT_FLAG_HANGING /* 0x00200000 */ (1 << 21)
#define ACT_FLAG_IDLE /* 0x00400000 */ (1 << 22)
#define ACT_FLAG_ATTACKING /* 0x00800000 */ (1 << 23)
#define ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION /* 0x01000000 */ (1 << 24)
#define ACT_FLAG_CONTROL_JUMP_HEIGHT /* 0x02000000 */ (1 << 25)
#define ACT_FLAG_ALLOW_FIRST_PERSON /* 0x04000000 */ (1 << 26)
#define ACT_FLAG_PAUSE_EXIT /* 0x08000000 */ (1 << 27)
#define ACT_FLAG_SWIMMING_OR_FLYING /* 0x10000000 */ (1 << 28)
#define ACT_FLAG_WATER_OR_TEXT /* 0x20000000 */ (1 << 29)
#define ACT_FLAG_THROWING /* 0x80000000 */ (1 << 31)
#define ACT_UNINITIALIZED 0x00000000 // (0x000)
// group 0x000: stationary actions
#define ACT_IDLE 0x0C400201 // (0x001 | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_START_SLEEPING 0x0C400202 // (0x002 | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_SLEEPING 0x0C000203 // (0x003 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_WAKING_UP 0x0C000204 // (0x004 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_PANTING 0x0C400205 // (0x005 | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_PANTING_UNUSED 0x08000206 // (0x006 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_IDLE 0x08000207 // (0x007 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_HEAVY_IDLE 0x08000208 // (0x008 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_STANDING_AGAINST_WALL 0x0C400209 // (0x009 | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_COUGHING 0x0C40020A // (0x00A | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_SHIVERING 0x0C40020B // (0x00B | ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_IN_QUICKSAND 0x0002020D // (0x00D | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_UNKNOWN_0002020E 0x0002020E // (0x00E | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_CROUCHING 0x0C008220 // (0x020 | ACT_FLAG_STATIONARY | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_START_CROUCHING 0x0C008221 // (0x021 | ACT_FLAG_STATIONARY | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_STOP_CROUCHING 0x0C008222 // (0x022 | ACT_FLAG_STATIONARY | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_START_CRAWLING 0x0C008223 // (0x023 | ACT_FLAG_STATIONARY | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_STOP_CRAWLING 0x0C008224 // (0x024 | ACT_FLAG_STATIONARY | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_SLIDE_KICK_SLIDE_STOP 0x08000225 // (0x025 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_SHOCKWAVE_BOUNCE 0x00020226 // (0x026 | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_FIRST_PERSON 0x0C000227 // (0x027 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_BACKFLIP_LAND_STOP 0x0800022F // (0x02F | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_JUMP_LAND_STOP 0x0C000230 // (0x030 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_DOUBLE_JUMP_LAND_STOP 0x0C000231 // (0x031 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_FREEFALL_LAND_STOP 0x0C000232 // (0x032 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_SIDE_FLIP_LAND_STOP 0x0C000233 // (0x033 | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_JUMP_LAND_STOP 0x08000234 // (0x034 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_FREEFALL_LAND_STOP 0x08000235 // (0x035 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_AIR_THROW_LAND 0x80000A36 // (0x036 | ACT_FLAG_STATIONARY | ACT_FLAG_AIR | ACT_FLAG_THROWING)
#define ACT_TWIRL_LAND 0x18800238 // (0x038 | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING | ACT_FLAG_PAUSE_EXIT | ACT_FLAG_SWIMMING_OR_FLYING)
#define ACT_LAVA_BOOST_LAND 0x08000239 // (0x039 | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_TRIPLE_JUMP_LAND_STOP 0x0800023A // (0x03A | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_LONG_JUMP_LAND_STOP 0x0800023B // (0x03B | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_GROUND_POUND_LAND 0x0080023C // (0x03C | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING)
#define ACT_BRAKING_STOP 0x0C00023D // (0x03D | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_BUTT_SLIDE_STOP 0x0C00023E // (0x03E | ACT_FLAG_STATIONARY | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_BUTT_SLIDE_STOP 0x0800043F // (0x03F | ACT_FLAG_MOVING | ACT_FLAG_PAUSE_EXIT)
// group 0x040: moving (ground) actions
#define ACT_WALKING 0x04000440 // (0x040 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_HOLD_WALKING 0x00000442 // (0x042 | ACT_FLAG_MOVING)
#define ACT_TURNING_AROUND 0x00000443 // (0x043 | ACT_FLAG_MOVING)
#define ACT_FINISH_TURNING_AROUND 0x00000444 // (0x044 | ACT_FLAG_MOVING)
#define ACT_BRAKING 0x04000445 // (0x045 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_RIDING_SHELL_GROUND 0x20810446 // (0x046 | ACT_FLAG_MOVING | ACT_FLAG_RIDING_SHELL | ACT_FLAG_ATTACKING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_HEAVY_WALKING 0x00000447 // (0x047 | ACT_FLAG_MOVING)
#define ACT_CRAWLING 0x04008448 // (0x048 | ACT_FLAG_MOVING | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_BURNING_GROUND 0x00020449 // (0x049 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_DECELERATING 0x0400044A // (0x04A | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_HOLD_DECELERATING 0x0000044B // (0x04B | ACT_FLAG_MOVING)
#define ACT_BEGIN_SLIDING 0x00000050 // (0x050)
#define ACT_HOLD_BEGIN_SLIDING 0x00000051 // (0x051)
#define ACT_BUTT_SLIDE 0x00840452 // (0x052 | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_ATTACKING)
#define ACT_STOMACH_SLIDE 0x008C0453 // (0x053 | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING)
#define ACT_HOLD_BUTT_SLIDE 0x00840454 // (0x054 | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_ATTACKING)
#define ACT_HOLD_STOMACH_SLIDE 0x008C0455 // (0x055 | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING)
#define ACT_DIVE_SLIDE 0x00880456 // (0x056 | ACT_FLAG_MOVING | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING)
#define ACT_MOVE_PUNCHING 0x00800457 // (0x057 | ACT_FLAG_MOVING | ACT_FLAG_ATTACKING)
#define ACT_CROUCH_SLIDE 0x04808459 // (0x059 | ACT_FLAG_MOVING | ACT_FLAG_SHORT_HITBOX | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_SLIDE_KICK_SLIDE 0x0080045A // (0x05A | ACT_FLAG_MOVING | ACT_FLAG_ATTACKING)
#define ACT_HARD_BACKWARD_GROUND_KB 0x00020460 // (0x060 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_HARD_FORWARD_GROUND_KB 0x00020461 // (0x061 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_BACKWARD_GROUND_KB 0x00020462 // (0x062 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_FORWARD_GROUND_KB 0x00020463 // (0x063 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_SOFT_BACKWARD_GROUND_KB 0x00020464 // (0x064 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_SOFT_FORWARD_GROUND_KB 0x00020465 // (0x065 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_GROUND_BONK 0x00020466 // (0x066 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_DEATH_EXIT_LAND 0x00020467 // (0x067 | ACT_FLAG_MOVING | ACT_FLAG_INVULNERABLE)
#define ACT_JUMP_LAND 0x04000470 // (0x070 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_FREEFALL_LAND 0x04000471 // (0x071 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_DOUBLE_JUMP_LAND 0x04000472 // (0x072 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_SIDE_FLIP_LAND 0x04000473 // (0x073 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_HOLD_JUMP_LAND 0x00000474 // (0x074 | ACT_FLAG_MOVING)
#define ACT_HOLD_FREEFALL_LAND 0x00000475 // (0x075 | ACT_FLAG_MOVING)
#define ACT_QUICKSAND_JUMP_LAND 0x00000476 // (0x076 | ACT_FLAG_MOVING)
#define ACT_HOLD_QUICKSAND_JUMP_LAND 0x00000477 // (0x077 | ACT_FLAG_MOVING)
#define ACT_TRIPLE_JUMP_LAND 0x04000478 // (0x078 | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_LONG_JUMP_LAND 0x00000479 // (0x079 | ACT_FLAG_MOVING)
#define ACT_BACKFLIP_LAND 0x0400047A // (0x07A | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
// group 0x080: airborne actions
#define ACT_JUMP 0x03000880 // (0x080 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_DOUBLE_JUMP 0x03000881 // (0x081 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_TRIPLE_JUMP 0x01000882 // (0x082 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_BACKFLIP 0x01000883 // (0x083 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_STEEP_JUMP 0x03000885 // (0x085 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_WALL_KICK_AIR 0x03000886 // (0x086 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_SIDE_FLIP 0x01000887 // (0x087 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_LONG_JUMP 0x03000888 // (0x088 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_WATER_JUMP 0x01000889 // (0x089 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_DIVE 0x0188088A // (0x08A | ACT_FLAG_AIR | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_FREEFALL 0x0100088C // (0x08C | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_TOP_OF_POLE_JUMP 0x0300088D // (0x08D | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_BUTT_SLIDE_AIR 0x0300088E // (0x08E | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_FLYING_TRIPLE_JUMP 0x03000894 // (0x094 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_SHOT_FROM_CANNON 0x00880898 // (0x098 | ACT_FLAG_AIR | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING)
#define ACT_FLYING 0x10880899 // (0x099 | ACT_FLAG_AIR | ACT_FLAG_DIVING | ACT_FLAG_ATTACKING | ACT_FLAG_SWIMMING_OR_FLYING)
#define ACT_RIDING_SHELL_JUMP 0x0281089A // (0x09A | ACT_FLAG_AIR | ACT_FLAG_RIDING_SHELL | ACT_FLAG_ATTACKING | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_RIDING_SHELL_FALL 0x0081089B // (0x09B | ACT_FLAG_AIR | ACT_FLAG_RIDING_SHELL | ACT_FLAG_ATTACKING)
#define ACT_VERTICAL_WIND 0x1008089C // (0x09C | ACT_FLAG_AIR | ACT_FLAG_DIVING | ACT_FLAG_SWIMMING_OR_FLYING)
#define ACT_HOLD_JUMP 0x030008A0 // (0x0A0 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_HOLD_FREEFALL 0x010008A1 // (0x0A1 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_HOLD_BUTT_SLIDE_AIR 0x010008A2 // (0x0A2 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_HOLD_WATER_JUMP 0x010008A3 // (0x0A3 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_TWIRLING 0x108008A4 // (0x0A4 | ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_SWIMMING_OR_FLYING)
#define ACT_FORWARD_ROLLOUT 0x010008A6 // (0x0A6 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_AIR_HIT_WALL 0x000008A7 // (0x0A7 | ACT_FLAG_AIR)
#define ACT_RIDING_HOOT 0x000004A8 // (0x0A8 | ACT_FLAG_MOVING)
#define ACT_GROUND_POUND 0x008008A9 // (0x0A9 | ACT_FLAG_AIR | ACT_FLAG_ATTACKING)
#define ACT_SLIDE_KICK 0x018008AA // (0x0AA | ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_AIR_THROW 0x830008AB // (0x0AB | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT | ACT_FLAG_THROWING)
#define ACT_JUMP_KICK 0x018008AC // (0x0AC | ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_BACKWARD_ROLLOUT 0x010008AD // (0x0AD | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_CRAZY_BOX_BOUNCE 0x000008AE // (0x0AE | ACT_FLAG_AIR)
#define ACT_SPECIAL_TRIPLE_JUMP 0x030008AF // (0x0AF | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
#define ACT_BACKWARD_AIR_KB 0x010208B0 // (0x0B0 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_FORWARD_AIR_KB 0x010208B1 // (0x0B1 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_HARD_FORWARD_AIR_KB 0x010208B2 // (0x0B2 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_HARD_BACKWARD_AIR_KB 0x010208B3 // (0x0B3 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_BURNING_JUMP 0x010208B4 // (0x0B4 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_BURNING_FALL 0x010208B5 // (0x0B5 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_SOFT_BONK 0x010208B6 // (0x0B6 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_LAVA_BOOST 0x010208B7 // (0x0B7 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_GETTING_BLOWN 0x010208B8 // (0x0B8 | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_THROWN_FORWARD 0x010208BD // (0x0BD | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
#define ACT_THROWN_BACKWARD 0x010208BE // (0x0BE | ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
// group 0x0C0: submerged actions
#define ACT_WATER_IDLE 0x380022C0 // (0x0C0 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_PAUSE_EXIT | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_WATER_IDLE 0x380022C1 // (0x0C1 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_PAUSE_EXIT | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_ACTION_END 0x300022C2 // (0x0C2 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_WATER_ACTION_END 0x300022C3 // (0x0C3 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_DROWNING 0x300032C4 // (0x0C4 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_BACKWARD_WATER_KB 0x300222C5 // (0x0C5 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_INVULNERABLE | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_FORWARD_WATER_KB 0x300222C6 // (0x0C6 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_INVULNERABLE | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_DEATH 0x300032C7 // (0x0C7 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_SHOCKED 0x300222C8 // (0x0C8 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_INVULNERABLE | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_BREASTSTROKE 0x300024D0 // (0x0D0 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_SWIMMING_END 0x300024D1 // (0x0D1 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_FLUTTER_KICK 0x300024D2 // (0x0D2 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_BREASTSTROKE 0x300024D3 // (0x0D3 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_SWIMMING_END 0x300024D4 // (0x0D4 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_HOLD_FLUTTER_KICK 0x300024D5 // (0x0D5 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_SHELL_SWIMMING 0x300024D6 // (0x0D6 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_THROW 0x300024E0 // (0x0E0 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_PUNCH 0x300024E1 // (0x0E1 | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_WATER_PLUNGE 0x300022E2 // (0x0E2 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_CAUGHT_IN_WHIRLPOOL 0x300222E3 // (0x0E3 | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_INVULNERABLE | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT)
#define ACT_METAL_WATER_STANDING 0x080042F0 // (0x0F0 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER | ACT_FLAG_PAUSE_EXIT)
#define ACT_HOLD_METAL_WATER_STANDING 0x080042F1 // (0x0F1 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER | ACT_FLAG_PAUSE_EXIT)
#define ACT_METAL_WATER_WALKING 0x000044F2 // (0x0F2 | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
#define ACT_HOLD_METAL_WATER_WALKING 0x000044F3 // (0x0F3 | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
#define ACT_METAL_WATER_FALLING 0x000042F4 // (0x0F4 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER)
#define ACT_HOLD_METAL_WATER_FALLING 0x000042F5 // (0x0F5 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER)
#define ACT_METAL_WATER_FALL_LAND 0x000042F6 // (0x0F6 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER)
#define ACT_HOLD_METAL_WATER_FALL_LAND 0x000042F7 // (0x0F7 | ACT_FLAG_STATIONARY | ACT_FLAG_METAL_WATER)
#define ACT_METAL_WATER_JUMP 0x000044F8 // (0x0F8 | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
#define ACT_HOLD_METAL_WATER_JUMP 0x000044F9 // (0x0F9 | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
#define ACT_METAL_WATER_JUMP_LAND 0x000044FA // (0x0FA | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
#define ACT_HOLD_METAL_WATER_JUMP_LAND 0x000044FB // (0x0FB | ACT_FLAG_MOVING | ACT_FLAG_METAL_WATER)
// group 0x100: cutscene actions
#define ACT_DISAPPEARED 0x00001300 // (0x100 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_INTRO_CUTSCENE 0x04001301 // (0x101 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_ALLOW_FIRST_PERSON)
#define ACT_STAR_DANCE_EXIT 0x00001302 // (0x102 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_STAR_DANCE_WATER 0x00001303 // (0x103 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_FALL_AFTER_STAR_GRAB 0x00001904 // (0x104 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_READING_AUTOMATIC_DIALOG 0x20001305 // (0x105 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_WATER_OR_TEXT)
#define ACT_READING_NPC_DIALOG 0x20001306 // (0x106 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_WATER_OR_TEXT)
#define ACT_STAR_DANCE_NO_EXIT 0x00001307 // (0x107 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_READING_SIGN 0x00001308 // (0x108 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_JUMBO_STAR_CUTSCENE 0x00001909 // (0x109 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_WAITING_FOR_DIALOG 0x0000130A // (0x10A | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_DEBUG_FREE_MOVE 0x0000130F // (0x10F | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_STANDING_DEATH 0x00021311 // (0x111 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_QUICKSAND_DEATH 0x00021312 // (0x112 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_ELECTROCUTION 0x00021313 // (0x113 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_SUFFOCATION 0x00021314 // (0x114 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_DEATH_ON_STOMACH 0x00021315 // (0x115 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_DEATH_ON_BACK 0x00021316 // (0x116 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_EATEN_BY_BUBBA 0x00021317 // (0x117 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)
#define ACT_END_PEACH_CUTSCENE 0x00001918 // (0x118 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_CREDITS_CUTSCENE 0x00001319 // (0x119 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_END_WAVING_CUTSCENE 0x0000131A // (0x11A | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_PULLING_DOOR 0x00001320 // (0x120 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_PUSHING_DOOR 0x00001321 // (0x121 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_WARP_DOOR_SPAWN 0x00001322 // (0x122 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_EMERGE_FROM_PIPE 0x00001923 // (0x123 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_SPAWN_SPIN_AIRBORNE 0x00001924 // (0x124 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_SPAWN_SPIN_LANDING 0x00001325 // (0x125 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_EXIT_AIRBORNE 0x00001926 // (0x126 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_EXIT_LAND_SAVE_DIALOG 0x00001327 // (0x127 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_DEATH_EXIT 0x00001928 // (0x128 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_UNUSED_DEATH_EXIT 0x00001929 // (0x129 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_FALLING_DEATH_EXIT 0x0000192A // (0x12A | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_SPECIAL_EXIT_AIRBORNE 0x0000192B // (0x12B | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_SPECIAL_DEATH_EXIT 0x0000192C // (0x12C | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_FALLING_EXIT_AIRBORNE 0x0000192D // (0x12D | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_UNLOCKING_KEY_DOOR 0x0000132E // (0x12E | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_UNLOCKING_STAR_DOOR 0x0000132F // (0x12F | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_ENTERING_STAR_DOOR 0x00001331 // (0x131 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_SPAWN_NO_SPIN_AIRBORNE 0x00001932 // (0x132 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_SPAWN_NO_SPIN_LANDING 0x00001333 // (0x133 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_BBH_ENTER_JUMP 0x00001934 // (0x134 | ACT_FLAG_AIR | ACT_FLAG_INTANGIBLE)
#define ACT_BBH_ENTER_SPIN 0x00001535 // (0x135 | ACT_FLAG_MOVING | ACT_FLAG_INTANGIBLE)
#define ACT_TELEPORT_FADE_OUT 0x00001336 // (0x136 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_TELEPORT_FADE_IN 0x00001337 // (0x137 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_SHOCKED 0x00020338 // (0x138 | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_SQUISHED 0x00020339 // (0x139 | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_HEAD_STUCK_IN_GROUND 0x0002033A // (0x13A | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_BUTT_STUCK_IN_GROUND 0x0002033B // (0x13B | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_FEET_STUCK_IN_GROUND 0x0002033C // (0x13C | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_PUTTING_ON_CAP 0x0000133D // (0x13D | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
// group 0x140: "automatic" actions
#define ACT_HOLDING_POLE 0x08100340 // (0x140 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE | ACT_FLAG_PAUSE_EXIT)
#define ACT_GRAB_POLE_SLOW 0x00100341 // (0x141 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE)
#define ACT_GRAB_POLE_FAST 0x00100342 // (0x142 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE)
#define ACT_CLIMBING_POLE 0x00100343 // (0x143 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE)
#define ACT_TOP_OF_POLE_TRANSITION 0x00100344 // (0x144 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE)
#define ACT_TOP_OF_POLE 0x00100345 // (0x145 | ACT_FLAG_STATIONARY | ACT_FLAG_ON_POLE)
#define ACT_START_HANGING 0x08200348 // (0x148 | ACT_FLAG_STATIONARY | ACT_FLAG_HANGING | ACT_FLAG_PAUSE_EXIT)
#define ACT_HANGING 0x00200349 // (0x149 | ACT_FLAG_STATIONARY | ACT_FLAG_HANGING)
#define ACT_HANG_MOVING 0x0020054A // (0x14A | ACT_FLAG_MOVING | ACT_FLAG_HANGING)
#define ACT_LEDGE_GRAB 0x0800034B // (0x14B | ACT_FLAG_STATIONARY | ACT_FLAG_PAUSE_EXIT)
#define ACT_LEDGE_CLIMB_SLOW_1 0x0000054C // (0x14C | ACT_FLAG_MOVING)
#define ACT_LEDGE_CLIMB_SLOW_2 0x0000054D // (0x14D | ACT_FLAG_MOVING)
#define ACT_LEDGE_CLIMB_DOWN 0x0000054E // (0x14E | ACT_FLAG_MOVING)
#define ACT_LEDGE_CLIMB_FAST 0x0000054F // (0x14F | ACT_FLAG_MOVING)
#define ACT_GRABBED 0x00020370 // (0x170 | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE)
#define ACT_IN_CANNON 0x00001371 // (0x171 | ACT_FLAG_STATIONARY | ACT_FLAG_INTANGIBLE)
#define ACT_TORNADO_TWIRLING 0x10020372 // (0x172 | ACT_FLAG_STATIONARY | ACT_FLAG_INVULNERABLE | ACT_FLAG_SWIMMING_OR_FLYING)
// group 0x180: object actions
#define ACT_PUNCHING 0x00800380 // (0x180 | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING)
#define ACT_PICKING_UP 0x00000383 // (0x183 | ACT_FLAG_STATIONARY)
#define ACT_DIVE_PICKING_UP 0x00000385 // (0x185 | ACT_FLAG_STATIONARY)
#define ACT_STOMACH_SLIDE_STOP 0x00000386 // (0x186 | ACT_FLAG_STATIONARY)
#define ACT_PLACING_DOWN 0x00000387 // (0x187 | ACT_FLAG_STATIONARY)
#define ACT_THROWING 0x80000588 // (0x188 | ACT_FLAG_MOVING | ACT_FLAG_THROWING)
#define ACT_HEAVY_THROW 0x80000589 // (0x189 | ACT_FLAG_MOVING | ACT_FLAG_THROWING)
#define ACT_PICKING_UP_BOWSER 0x00000390 // (0x190 | ACT_FLAG_STATIONARY)
#define ACT_HOLDING_BOWSER 0x00000391 // (0x191 | ACT_FLAG_STATIONARY)
#define ACT_RELEASING_BOWSER 0x00000392 // (0x192 | ACT_FLAG_STATIONARY)
/*
this input mask is unused by the controller,
but END_DEMO is used internally to signal
the demo to end. This button cannot
be pressed normally by a controller.
*/
#define END_DEMO (1 << 7)
#define VALID_BUTTONS (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | \
U_JPAD | D_JPAD | L_JPAD | R_JPAD | \
L_TRIG | R_TRIG | \
U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )
#define C_BUTTONS (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )
#endif // SM64_H
+93
View File
@@ -0,0 +1,93 @@
#ifndef SPECIAL_PRESET_NAMES_H
#define SPECIAL_PRESET_NAMES_H
enum SpecialPresets {
special_null_start,
special_yellow_coin,
special_yellow_coin_2,
special_unknown_3,
special_boo,
special_unknown_5,
special_lll_moving_octagonal_mesh_platform,
special_snow_ball,
special_lll_drawbridge_spawner,
special_empty_9,
special_lll_rotating_block_with_fire_bars,
special_lll_floating_wood_bridge,
special_tumbling_platform,
special_lll_rotating_hexagonal_ring,
special_lll_sinking_rectangular_platform,
special_lll_sinking_square_platforms,
special_lll_tilting_square_platform,
special_lll_bowser_puzzle,
special_mr_i,
special_small_bully,
special_big_bully,
special_empty_21,
special_empty_22,
special_empty_23,
special_empty_24,
special_empty_25,
special_moving_blue_coin,
special_jrb_chest,
special_water_ring,
special_mine,
special_empty_30,
special_empty_31,
special_butterfly,
special_bowser,
special_wf_rotating_wooden_platform,
special_small_bomp,
special_wf_sliding_platform,
special_tower_platform_group,
special_rotating_counter_clockwise,
special_wf_tumbling_bridge,
special_large_bomp,
special_level_geo_03 = 0x65,
special_level_geo_04,
special_level_geo_05,
special_level_geo_06,
special_level_geo_07,
special_level_geo_08,
special_level_geo_09,
special_level_geo_0A,
special_level_geo_0B,
special_level_geo_0C,
special_level_geo_0D,
special_level_geo_0E,
special_level_geo_0F,
special_level_geo_10,
special_level_geo_11,
special_level_geo_12,
special_level_geo_13,
special_level_geo_14,
special_level_geo_15,
special_level_geo_16,
special_bubble_tree,
special_spiky_tree,
special_snow_tree,
special_unknown_tree,
special_palm_tree,
special_wooden_door,
special_haunted_door = special_wooden_door,
special_unknown_door,
special_metal_door,
special_hmc_door,
special_unknown2_door,
special_wooden_door_warp,
special_unknown1_door_warp,
special_metal_door_warp,
special_unknown2_door_warp,
special_unknown3_door_warp,
special_castle_door_warp,
special_castle_door,
special_0stars_door,
special_1star_door,
special_3star_door,
special_key_door,
special_null_end = 0xFF
};
#endif // SPECIAL_PRESET_NAMES_H
+223
View File
@@ -0,0 +1,223 @@
#ifndef SURFACE_TERRAINS_H
#define SURFACE_TERRAINS_H
// Surface Types
#define SURFACE_DEFAULT 0x0000 // Environment default
#define SURFACE_BURNING 0x0001 // Lava / Frostbite (in SL), but is used mostly for Lava
#define SURFACE_0004 0x0004 // Unused, has no function and has parameters
#define SURFACE_HANGABLE 0x0005 // Ceiling that Mario can climb on
#define SURFACE_SLOW 0x0009 // Slow down Mario, unused
#define SURFACE_DEATH_PLANE 0x000A // Death floor
#define SURFACE_CLOSE_CAMERA 0x000B // Close camera
#define SURFACE_WATER 0x000D // Water, has no action, used on some waterboxes below
#define SURFACE_FLOWING_WATER 0x000E // Water (flowing), has parameters
#define SURFACE_INTANGIBLE 0x0012 // Intangible (Separates BBH mansion from merry-go-round, for room usage)
#define SURFACE_VERY_SLIPPERY 0x0013 // Very slippery, mostly used for slides
#define SURFACE_SLIPPERY 0x0014 // Slippery
#define SURFACE_NOT_SLIPPERY 0x0015 // Non-slippery, climbable
#define SURFACE_TTM_VINES 0x0016 // TTM vines, has no action defined
#define SURFACE_MGR_MUSIC 0x001A // Plays the Merry go round music, see handle_merry_go_round_music in bbh_merry_go_round.inc.c for more details
#define SURFACE_INSTANT_WARP_1B 0x001B // Instant warp to another area, used to warp between areas in WDW and the endless stairs to warp back
#define SURFACE_INSTANT_WARP_1C 0x001C // Instant warp to another area, used to warp between areas in WDW
#define SURFACE_INSTANT_WARP_1D 0x001D // Instant warp to another area, used to warp between areas in DDD, SSL and TTM
#define SURFACE_INSTANT_WARP_1E 0x001E // Instant warp to another area, used to warp between areas in DDD, SSL and TTM
#define SURFACE_SHALLOW_QUICKSAND 0x0021 // Shallow Quicksand (depth of 10 units)
#define SURFACE_DEEP_QUICKSAND 0x0022 // Quicksand (lethal, slow, depth of 160 units)
#define SURFACE_INSTANT_QUICKSAND 0x0023 // Quicksand (lethal, instant)
#define SURFACE_DEEP_MOVING_QUICKSAND 0x0024 // Moving quicksand (flowing, depth of 160 units)
#define SURFACE_SHALLOW_MOVING_QUICKSAND 0x0025 // Moving quicksand (flowing, depth of 25 units)
#define SURFACE_QUICKSAND 0x0026 // Moving quicksand (60 units)
#define SURFACE_MOVING_QUICKSAND 0x0027 // Moving quicksand (flowing, depth of 60 units)
#define SURFACE_WALL_MISC 0x0028 // Used for some walls, Cannon to adjust the camera, and some objects like Warp Pipe
#define SURFACE_NOISE_DEFAULT 0x0029 // Default floor with noise
#define SURFACE_NOISE_SLIPPERY 0x002A // Slippery floor with noise
#define SURFACE_HORIZONTAL_WIND 0x002C // Horizontal wind, has parameters
#define SURFACE_INSTANT_MOVING_QUICKSAND 0x002D // Quicksand (lethal, flowing)
#define SURFACE_ICE 0x002E // Slippery Ice, in snow levels and THI's water floor
#define SURFACE_LOOK_UP_WARP 0x002F // Look up and warp (Wing cap entrance)
#define SURFACE_HARD 0x0030 // Hard floor (Always has fall damage)
#define SURFACE_WARP 0x0032 // Surface warp
#define SURFACE_TIMER_START 0x0033 // Timer start (Peach's secret slide)
#define SURFACE_TIMER_END 0x0034 // Timer stop (Peach's secret slide)
#define SURFACE_HARD_SLIPPERY 0x0035 // Hard and slippery (Always has fall damage)
#define SURFACE_HARD_VERY_SLIPPERY 0x0036 // Hard and very slippery (Always has fall damage)
#define SURFACE_HARD_NOT_SLIPPERY 0x0037 // Hard and Non-slippery (Always has fall damage)
#define SURFACE_VERTICAL_WIND 0x0038 // Death at bottom with vertical wind
#define SURFACE_BOSS_FIGHT_CAMERA 0x0065 // Wide camera for BOB and WF bosses
#define SURFACE_CAMERA_FREE_ROAM 0x0066 // Free roam camera for THI and TTC
#define SURFACE_THI3_WALLKICK 0x0068 // Surface where there's a wall kick section in THI 3rd area, has no action defined
#define SURFACE_CAMERA_8_DIR 0x0069 // Surface that enables far camera for platforms, used in THI
#define SURFACE_CAMERA_MIDDLE 0x006E // Surface camera that returns to the middle, used on the 4 pillars of SSL
#define SURFACE_CAMERA_ROTATE_RIGHT 0x006F // Surface camera that rotates to the right (Bowser 1 & THI)
#define SURFACE_CAMERA_ROTATE_LEFT 0x0070 // Surface camera that rotates to the left (BOB & TTM)
#define SURFACE_CAMERA_BOUNDARY 0x0072 // Intangible Area, only used to restrict camera movement
#define SURFACE_NOISE_VERY_SLIPPERY_73 0x0073 // Very slippery floor with noise, unused
#define SURFACE_NOISE_VERY_SLIPPERY_74 0x0074 // Very slippery floor with noise, unused
#define SURFACE_NOISE_VERY_SLIPPERY 0x0075 // Very slippery floor with noise, used in CCM
#define SURFACE_NO_CAM_COLLISION 0x0076 // Surface with no cam collision flag
#define SURFACE_NO_CAM_COLLISION_77 0x0077 // Surface with no cam collision flag, unused
#define SURFACE_NO_CAM_COL_VERY_SLIPPERY 0x0078 // Surface with no cam collision flag, very slippery with noise (THI)
#define SURFACE_NO_CAM_COL_SLIPPERY 0x0079 // Surface with no cam collision flag, slippery with noise (CCM, PSS and TTM slides)
#define SURFACE_SWITCH 0x007A // Surface with no cam collision flag, non-slippery with noise, used by switches and Dorrie
#define SURFACE_VANISH_CAP_WALLS 0x007B // Vanish cap walls, pass through them with Vanish Cap
#define SURFACE_PAINTING_WOBBLE_A6 0x00A6 // Painting wobble (BOB Left)
#define SURFACE_PAINTING_WOBBLE_A7 0x00A7 // Painting wobble (BOB Middle)
#define SURFACE_PAINTING_WOBBLE_A8 0x00A8 // Painting wobble (BOB Right)
#define SURFACE_PAINTING_WOBBLE_A9 0x00A9 // Painting wobble (CCM Left)
#define SURFACE_PAINTING_WOBBLE_AA 0x00AA // Painting wobble (CCM Middle)
#define SURFACE_PAINTING_WOBBLE_AB 0x00AB // Painting wobble (CCM Right)
#define SURFACE_PAINTING_WOBBLE_AC 0x00AC // Painting wobble (WF Left)
#define SURFACE_PAINTING_WOBBLE_AD 0x00AD // Painting wobble (WF Middle)
#define SURFACE_PAINTING_WOBBLE_AE 0x00AE // Painting wobble (WF Right)
#define SURFACE_PAINTING_WOBBLE_AF 0x00AF // Painting wobble (JRB Left)
#define SURFACE_PAINTING_WOBBLE_B0 0x00B0 // Painting wobble (JRB Middle)
#define SURFACE_PAINTING_WOBBLE_B1 0x00B1 // Painting wobble (JRB Right)
#define SURFACE_PAINTING_WOBBLE_B2 0x00B2 // Painting wobble (LLL Left)
#define SURFACE_PAINTING_WOBBLE_B3 0x00B3 // Painting wobble (LLL Middle)
#define SURFACE_PAINTING_WOBBLE_B4 0x00B4 // Painting wobble (LLL Right)
#define SURFACE_PAINTING_WOBBLE_B5 0x00B5 // Painting wobble (SSL Left)
#define SURFACE_PAINTING_WOBBLE_B6 0x00B6 // Painting wobble (SSL Middle)
#define SURFACE_PAINTING_WOBBLE_B7 0x00B7 // Painting wobble (SSL Right)
#define SURFACE_PAINTING_WOBBLE_B8 0x00B8 // Painting wobble (Unused - Left)
#define SURFACE_PAINTING_WOBBLE_B9 0x00B9 // Painting wobble (Unused - Middle)
#define SURFACE_PAINTING_WOBBLE_BA 0x00BA // Painting wobble (Unused - Right)
#define SURFACE_PAINTING_WOBBLE_BB 0x00BB // Painting wobble (DDD - Left), makes the painting wobble if touched
#define SURFACE_PAINTING_WOBBLE_BC 0x00BC // Painting wobble (Unused, DDD - Middle)
#define SURFACE_PAINTING_WOBBLE_BD 0x00BD // Painting wobble (Unused, DDD - Right)
#define SURFACE_PAINTING_WOBBLE_BE 0x00BE // Painting wobble (WDW Left)
#define SURFACE_PAINTING_WOBBLE_BF 0x00BF // Painting wobble (WDW Middle)
#define SURFACE_PAINTING_WOBBLE_C0 0x00C0 // Painting wobble (WDW Right)
#define SURFACE_PAINTING_WOBBLE_C1 0x00C1 // Painting wobble (THI Tiny - Left)
#define SURFACE_PAINTING_WOBBLE_C2 0x00C2 // Painting wobble (THI Tiny - Middle)
#define SURFACE_PAINTING_WOBBLE_C3 0x00C3 // Painting wobble (THI Tiny - Right)
#define SURFACE_PAINTING_WOBBLE_C4 0x00C4 // Painting wobble (TTM Left)
#define SURFACE_PAINTING_WOBBLE_C5 0x00C5 // Painting wobble (TTM Middle)
#define SURFACE_PAINTING_WOBBLE_C6 0x00C6 // Painting wobble (TTM Right)
#define SURFACE_PAINTING_WOBBLE_C7 0x00C7 // Painting wobble (Unused, TTC - Left)
#define SURFACE_PAINTING_WOBBLE_C8 0x00C8 // Painting wobble (Unused, TTC - Middle)
#define SURFACE_PAINTING_WOBBLE_C9 0x00C9 // Painting wobble (Unused, TTC - Right)
#define SURFACE_PAINTING_WOBBLE_CA 0x00CA // Painting wobble (Unused, SL - Left)
#define SURFACE_PAINTING_WOBBLE_CB 0x00CB // Painting wobble (Unused, SL - Middle)
#define SURFACE_PAINTING_WOBBLE_CC 0x00CC // Painting wobble (Unused, SL - Right)
#define SURFACE_PAINTING_WOBBLE_CD 0x00CD // Painting wobble (THI Huge - Left)
#define SURFACE_PAINTING_WOBBLE_CE 0x00CE // Painting wobble (THI Huge - Middle)
#define SURFACE_PAINTING_WOBBLE_CF 0x00CF // Painting wobble (THI Huge - Right)
#define SURFACE_PAINTING_WOBBLE_D0 0x00D0 // Painting wobble (HMC & COTMC - Left), makes the painting wobble if touched
#define SURFACE_PAINTING_WOBBLE_D1 0x00D1 // Painting wobble (Unused, HMC & COTMC - Middle)
#define SURFACE_PAINTING_WOBBLE_D2 0x00D2 // Painting wobble (Unused, HMC & COTMC - Right)
#define SURFACE_PAINTING_WARP_D3 0x00D3 // Painting warp (BOB Left)
#define SURFACE_PAINTING_WARP_D4 0x00D4 // Painting warp (BOB Middle)
#define SURFACE_PAINTING_WARP_D5 0x00D5 // Painting warp (BOB Right)
#define SURFACE_PAINTING_WARP_D6 0x00D6 // Painting warp (CCM Left)
#define SURFACE_PAINTING_WARP_D7 0x00D7 // Painting warp (CCM Middle)
#define SURFACE_PAINTING_WARP_D8 0x00D8 // Painting warp (CCM Right)
#define SURFACE_PAINTING_WARP_D9 0x00D9 // Painting warp (WF Left)
#define SURFACE_PAINTING_WARP_DA 0x00DA // Painting warp (WF Middle)
#define SURFACE_PAINTING_WARP_DB 0x00DB // Painting warp (WF Right)
#define SURFACE_PAINTING_WARP_DC 0x00DC // Painting warp (JRB Left)
#define SURFACE_PAINTING_WARP_DD 0x00DD // Painting warp (JRB Middle)
#define SURFACE_PAINTING_WARP_DE 0x00DE // Painting warp (JRB Right)
#define SURFACE_PAINTING_WARP_DF 0x00DF // Painting warp (LLL Left)
#define SURFACE_PAINTING_WARP_E0 0x00E0 // Painting warp (LLL Middle)
#define SURFACE_PAINTING_WARP_E1 0x00E1 // Painting warp (LLL Right)
#define SURFACE_PAINTING_WARP_E2 0x00E2 // Painting warp (SSL Left)
#define SURFACE_PAINTING_WARP_E3 0x00E3 // Painting warp (SSL Medium)
#define SURFACE_PAINTING_WARP_E4 0x00E4 // Painting warp (SSL Right)
#define SURFACE_PAINTING_WARP_E5 0x00E5 // Painting warp (Unused - Left)
#define SURFACE_PAINTING_WARP_E6 0x00E6 // Painting warp (Unused - Medium)
#define SURFACE_PAINTING_WARP_E7 0x00E7 // Painting warp (Unused - Right)
#define SURFACE_PAINTING_WARP_E8 0x00E8 // Painting warp (DDD - Left)
#define SURFACE_PAINTING_WARP_E9 0x00E9 // Painting warp (DDD - Middle)
#define SURFACE_PAINTING_WARP_EA 0x00EA // Painting warp (DDD - Right)
#define SURFACE_PAINTING_WARP_EB 0x00EB // Painting warp (WDW Left)
#define SURFACE_PAINTING_WARP_EC 0x00EC // Painting warp (WDW Middle)
#define SURFACE_PAINTING_WARP_ED 0x00ED // Painting warp (WDW Right)
#define SURFACE_PAINTING_WARP_EE 0x00EE // Painting warp (THI Tiny - Left)
#define SURFACE_PAINTING_WARP_EF 0x00EF // Painting warp (THI Tiny - Middle)
#define SURFACE_PAINTING_WARP_F0 0x00F0 // Painting warp (THI Tiny - Right)
#define SURFACE_PAINTING_WARP_F1 0x00F1 // Painting warp (TTM Left)
#define SURFACE_PAINTING_WARP_F2 0x00F2 // Painting warp (TTM Middle)
#define SURFACE_PAINTING_WARP_F3 0x00F3 // Painting warp (TTM Right)
#define SURFACE_TTC_PAINTING_1 0x00F4 // Painting warp (TTC Left)
#define SURFACE_TTC_PAINTING_2 0x00F5 // Painting warp (TTC Medium)
#define SURFACE_TTC_PAINTING_3 0x00F6 // Painting warp (TTC Right)
#define SURFACE_PAINTING_WARP_F7 0x00F7 // Painting warp (SL Left)
#define SURFACE_PAINTING_WARP_F8 0x00F8 // Painting warp (SL Middle)
#define SURFACE_PAINTING_WARP_F9 0x00F9 // Painting warp (SL Right)
#define SURFACE_PAINTING_WARP_FA 0x00FA // Painting warp (THI Tiny - Left)
#define SURFACE_PAINTING_WARP_FB 0x00FB // Painting warp (THI Tiny - Middle)
#define SURFACE_PAINTING_WARP_FC 0x00FC // Painting warp (THI Tiny - Right)
#define SURFACE_WOBBLING_WARP 0x00FD // Pool warp (HMC & DDD)
#define SURFACE_TRAPDOOR 0x00FF // Bowser Left trapdoor, has no action defined
#define SURFACE_IS_QUICKSAND(cmd) (cmd >= 0x21 && cmd < 0x28) // Doesn't include SURFACE_INSTANT_MOVING_QUICKSAND
#define SURFACE_IS_NOT_HARD(cmd) (cmd != SURFACE_HARD && \
!(cmd >= 0x35 && cmd <= 0x37))
#define SURFACE_IS_PAINTING_WARP(cmd) (cmd >= 0xD3 && cmd < 0xFD)
#define SURFACE_CLASS_DEFAULT 0x0000
#define SURFACE_CLASS_VERY_SLIPPERY 0x0013
#define SURFACE_CLASS_SLIPPERY 0x0014
#define SURFACE_CLASS_NOT_SLIPPERY 0x0015
#define SURFACE_FLAG_DYNAMIC (1 << 0)
#define SURFACE_FLAG_NO_CAM_COLLISION (1 << 1)
#define SURFACE_FLAG_X_PROJECTION (1 << 3)
// These are effectively unique "surface" types like those defined higher
// And they are used as collision commands to load certain functions
#define TERRAIN_LOAD_VERTICES 0x0040 // Begins vertices list for collision triangles
#define TERRAIN_LOAD_CONTINUE 0x0041 // Stop loading vertices but continues to load other collision commands
#define TERRAIN_LOAD_END 0x0042 // End the collision list
#define TERRAIN_LOAD_OBJECTS 0x0043 // Loads in certain objects for level start
#define TERRAIN_LOAD_ENVIRONMENT 0x0044 // Loads water/HMC gas
#define TERRAIN_LOAD_IS_SURFACE_TYPE_LOW(cmd) (cmd < 0x40)
#define TERRAIN_LOAD_IS_SURFACE_TYPE_HIGH(cmd) (cmd >= 0x65)
// Terrain types defined by the level script command terrain_type (cmd_31)
#define TERRAIN_GRASS 0x0000
#define TERRAIN_STONE 0x0001
#define TERRAIN_SNOW 0x0002
#define TERRAIN_SAND 0x0003
#define TERRAIN_SPOOKY 0x0004
#define TERRAIN_WATER 0x0005
#define TERRAIN_SLIDE 0x0006
#define TERRAIN_MASK 0x0007
// These collision commands are unique "surface" types like those defined higher
// Collision Data Routine Initiate
#define COL_INIT() TERRAIN_LOAD_VERTICES
// Collision Vertices Read Initiate
#define COL_VERTEX_INIT(vtxNum) vtxNum
// Collision Vertex
#define COL_VERTEX(x, y, z) x, y, z
// Collision Tris Initiate
#define COL_TRI_INIT(surfType, triNum) surfType, triNum
// Collision Tri
#define COL_TRI(v1, v2, v3) v1, v2, v3
// Collision Tri With Special Params
#define COL_TRI_SPECIAL(v1, v2, v3, param) v1, v2, v3, param
// Collision Tris Stop Loading
#define COL_TRI_STOP() TERRAIN_LOAD_CONTINUE
// End Collision Data
#define COL_END() TERRAIN_LOAD_END
// Special Object Initiate
#define COL_SPECIAL_INIT(num) TERRAIN_LOAD_OBJECTS, num
// Water Boxes Initiate
#define COL_WATER_BOX_INIT(num) TERRAIN_LOAD_ENVIRONMENT, num
// Water Box
#define COL_WATER_BOX(id, x1, z1, x2, z2, y) id, x1, z1, x2, z2, y
#endif // SURFACE_TERRAINS_H
+348
View File
@@ -0,0 +1,348 @@
#ifndef TYPES_H
#define TYPES_H
// This file contains various data types used in Super Mario 64 that don't yet
// have an appropriate header.
// #include <ultra64.h>
#include "macros.h"
#include "PR/ultratypes.h"
// Certain functions are marked as having return values, but do not
// actually return a value. This causes undefined behavior, which we'd rather
// avoid on modern GCC. This only impacts -O2 and can matter for both the function
// itself and functions that call it.
#ifdef AVOID_UB
#define BAD_RETURN(cmd) void
#else
#define BAD_RETURN(cmd) cmd
#endif
struct Controller
{
/*0x00*/ s16 rawStickX; //
/*0x02*/ s16 rawStickY; //
/*0x04*/ float stickX; // [-64, 64] positive is right
/*0x08*/ float stickY; // [-64, 64] positive is up
/*0x0C*/ float stickMag; // distance from center [0, 64]
/*0x10*/ u16 buttonDown;
/*0x12*/ u16 buttonPressed;
///*0x14*/ OSContStatus *statusData;
///*0x18*/ OSContPad *controllerData;
#ifdef VERSION_SH
/*0x1C*/ int port;
#endif
};
typedef f32 Vec2f[2];
typedef f32 Vec3f[3]; // X, Y, Z, where Y is up
typedef s16 Vec3s[3];
typedef s32 Vec3i[3];
typedef f32 Vec4f[4];
typedef s16 Vec4s[4];
typedef f32 Mat4[4][4];
typedef uintptr_t GeoLayout;
typedef uintptr_t LevelScript;
typedef s16 Movtex;
typedef s16 MacroObject;
typedef s16 Collision;
typedef s16 Trajectory;
typedef s16 PaintingData;
typedef uintptr_t BehaviorScript;
enum SpTaskState {
SPTASK_STATE_NOT_STARTED,
SPTASK_STATE_RUNNING,
SPTASK_STATE_INTERRUPTED,
SPTASK_STATE_FINISHED,
SPTASK_STATE_FINISHED_DP
};
// struct SPTask
// {
// /*0x00*/ OSTask task;
// /*0x40*/ OSMesgQueue *msgqueue;
// /*0x44*/ OSMesg msg;
// /*0x48*/ enum SpTaskState state;
// }; // size = 0x4C, align = 0x8
//
// struct VblankHandler
// {
// OSMesgQueue *queue;
// OSMesg msg;
// };
#define ANIM_FLAG_NOLOOP (1 << 0) // 0x01
#define ANIM_FLAG_FORWARD (1 << 1) // 0x02
#define ANIM_FLAG_2 (1 << 2) // 0x04
#define ANIM_FLAG_HOR_TRANS (1 << 3) // 0x08
#define ANIM_FLAG_VERT_TRANS (1 << 4) // 0x10
#define ANIM_FLAG_5 (1 << 5) // 0x20
#define ANIM_FLAG_6 (1 << 6) // 0x40
#define ANIM_FLAG_7 (1 << 7) // 0x80
struct Animation {
/*0x00*/ s16 flags;
/*0x02*/ s16 animYTransDivisor;
/*0x04*/ s16 startFrame;
/*0x06*/ s16 loopStart;
/*0x08*/ s16 loopEnd;
/*0x0A*/ s16 unusedBoneCount;
/*0x0C*/ s16 *values;
/*0x10*/ u16 *index;
/*0x14*/ u32 length; // only used with Mario animations to determine how much to load. 0 otherwise.
};
#define ANIMINDEX_NUMPARTS(animindex) (sizeof(animindex) / sizeof(u16) / 6 - 1)
struct GraphNode
{
/*0x00*/ s16 type; // structure type
/*0x02*/ s16 flags; // hi = drawing layer, lo = rendering modes
/*0x04*/ struct GraphNode *prev;
/*0x08*/ struct GraphNode *next;
/*0x0C*/ struct GraphNode *parent;
/*0x10*/ struct GraphNode *children;
};
struct AnimInfo
{
/*0x00 0x38*/ s16 animID;
/*0x02 0x3A*/ s16 animYTrans;
/*0x04 0x3C*/ struct Animation *curAnim;
/*0x08 0x40*/ s16 animFrame;
/*0x0A 0x42*/ u16 animTimer;
/*0x0C 0x44*/ s32 animFrameAccelAssist;
/*0x10 0x48*/ s32 animAccel;
};
struct GraphNodeObject
{
/*0x00*/ struct GraphNode node;
/*0x14*/ struct GraphNode *sharedChild;
/*0x18*/ s8 areaIndex;
/*0x19*/ s8 activeAreaIndex;
/*0x1A*/ Vec3s angle;
/*0x20*/ Vec3f pos;
/*0x2C*/ Vec3f scale;
/*0x38*/ struct AnimInfo animInfo;
/*0x4C*/ struct SpawnInfo *unk4C;
/*0x50*/ Mat4 *throwMatrix; // matrix ptr
/*0x54*/ Vec3f cameraToObject;
};
struct ObjectNode
{
struct GraphNodeObject gfx;
struct ObjectNode *next;
struct ObjectNode *prev;
};
// NOTE: Since ObjectNode is the first member of Object, it is difficult to determine
// whether some of these pointers point to ObjectNode or Object.
struct Object
{
/*0x000*/ struct ObjectNode header;
/*0x068*/ struct Object *parentObj;
/*0x06C*/ struct Object *prevObj;
/*0x070*/ u32 collidedObjInteractTypes;
/*0x074*/ s16 activeFlags;
/*0x076*/ s16 numCollidedObjs;
/*0x078*/ struct Object *collidedObjs[4];
/*0x088*/
union
{
// Object fields. See object_fields.h.
u32 asU32[0x50];
s32 asS32[0x50];
s16 asS16[0x50][2];
f32 asF32[0x50];
#if !IS_64_BIT
s16 *asS16P[0x50];
s32 *asS32P[0x50];
struct Animation **asAnims[0x50];
struct Waypoint *asWaypoint[0x50];
struct ChainSegment *asChainSegment[0x50];
struct Object *asObject[0x50];
struct Surface *asSurface[0x50];
void *asVoidPtr[0x50];
const void *asConstVoidPtr[0x50];
#endif
} rawData;
#if IS_64_BIT
union {
s16 *asS16P[0x50];
s32 *asS32P[0x50];
struct Animation **asAnims[0x50];
struct Waypoint *asWaypoint[0x50];
struct ChainSegment *asChainSegment[0x50];
struct Object *asObject[0x50];
struct Surface *asSurface[0x50];
void *asVoidPtr[0x50];
const void *asConstVoidPtr[0x50];
} ptrData;
#endif
/*0x1C8*/ u32 unused1;
/*0x1CC*/ const BehaviorScript *curBhvCommand;
/*0x1D0*/ u32 bhvStackIndex;
/*0x1D4*/ uintptr_t bhvStack[8];
/*0x1F4*/ s16 bhvDelayTimer;
/*0x1F6*/ s16 respawnInfoType;
/*0x1F8*/ f32 hitboxRadius;
/*0x1FC*/ f32 hitboxHeight;
/*0x200*/ f32 hurtboxRadius;
/*0x204*/ f32 hurtboxHeight;
/*0x208*/ f32 hitboxDownOffset;
/*0x20C*/ const BehaviorScript *behavior;
/*0x210*/ u32 unused2;
/*0x214*/ struct Object *platform;
/*0x218*/ void *collisionData;
/*0x21C*/ Mat4 transform;
/*0x25C*/ void *respawnInfo;
};
struct ObjectHitbox
{
/*0x00*/ u32 interactType;
/*0x04*/ u8 downOffset;
/*0x05*/ s8 damageOrCoinValue;
/*0x06*/ s8 health;
/*0x07*/ s8 numLootCoins;
/*0x08*/ s16 radius;
/*0x0A*/ s16 height;
/*0x0C*/ s16 hurtboxRadius;
/*0x0E*/ s16 hurtboxHeight;
};
struct Waypoint
{
s16 flags;
Vec3s pos;
};
struct Surface
{
/*0x00*/ s16 type;
/*0x02*/ s16 force;
/*0x04*/ s8 flags;
/*0x05*/ s8 room;
/*0x06*/ s16 lowerY;
/*0x08*/ s16 upperY;
/*0x0A*/ Vec3s vertex1;
/*0x10*/ Vec3s vertex2;
/*0x16*/ Vec3s vertex3;
/*0x1C*/ struct {
f32 x;
f32 y;
f32 z;
} normal;
/*0x28*/ f32 originOffset;
/*0x2C*/ struct Object *object;
};
struct MarioBodyState
{
/*0x00*/ u32 action;
/*0x04*/ s8 capState; /// see MarioCapGSCId
/*0x05*/ s8 eyeState;
/*0x06*/ s8 handState;
/*0x07*/ s8 wingFlutter; /// whether Mario's wing cap wings are fluttering
/*0x08*/ s16 modelState;
/*0x0A*/ s8 grabPos;
/*0x0B*/ u8 punchState; /// 2 bits for type of punch, 6 bits for punch animation timer
/*0x0C*/ Vec3s torsoAngle;
/*0x12*/ Vec3s headAngle;
/*0x18*/ Vec3f heldObjLastPosition; /// also known as HOLP
u8 padding[4];
};
struct OffsetSizePair
{
u32 offset;
u32 size;
};
struct MarioAnimDmaRelatedThing
{
u32 count;
u8 *srcAddr;
struct OffsetSizePair anim[1]; // dynamic size
};
struct MarioAnimation
{
struct MarioAnimDmaRelatedThing *animDmaTable;
u8 *currentAnimAddr;
struct Animation *targetAnim;
u8 padding[4];
};
struct MarioState
{
/*0x00*/ u16 unk00;
/*0x02*/ u16 input;
/*0x04*/ u32 flags;
/*0x08*/ u32 particleFlags;
/*0x0C*/ u32 action;
/*0x10*/ u32 prevAction;
/*0x14*/ u32 terrainSoundAddend;
/*0x18*/ u16 actionState;
/*0x1A*/ u16 actionTimer;
/*0x1C*/ u32 actionArg;
/*0x20*/ f32 intendedMag;
/*0x24*/ s16 intendedYaw;
/*0x26*/ s16 invincTimer;
/*0x28*/ u8 framesSinceA;
/*0x29*/ u8 framesSinceB;
/*0x2A*/ u8 wallKickTimer;
/*0x2B*/ u8 doubleJumpTimer;
/*0x2C*/ Vec3s faceAngle;
/*0x32*/ Vec3s angleVel;
/*0x38*/ s16 slideYaw;
/*0x3A*/ s16 twirlYaw;
/*0x3C*/ Vec3f pos;
/*0x48*/ Vec3f vel;
/*0x54*/ f32 forwardVel;
/*0x58*/ f32 slideVelX;
/*0x5C*/ f32 slideVelZ;
/*0x60*/ struct Surface *wall;
/*0x64*/ struct Surface *ceil;
/*0x68*/ struct Surface *floor;
/*0x6C*/ f32 ceilHeight;
/*0x70*/ f32 floorHeight;
/*0x74*/ s16 floorAngle;
/*0x76*/ s16 waterLevel;
/*0x78*/ struct Object *interactObj;
/*0x7C*/ struct Object *heldObj;
/*0x80*/ struct Object *usedObj;
/*0x84*/ struct Object *riddenObj;
/*0x88*/ struct Object *marioObj;
/*0x8C*/ struct SpawnInfo *spawnInfo;
/*0x90*/ struct Area *area;
// /*0x94*/ struct PlayerCameraState *statusForCamera;
/*0x98*/ struct MarioBodyState *marioBodyState;
/*0x9C*/ struct Controller *controller;
/*0xA0*/ struct MarioAnimation *animation;
/*0xA4*/ u32 collidedObjInteractTypes;
/*0xA8*/ s16 numCoins;
/*0xAA*/ s16 numStars;
/*0xAC*/ s8 numKeys; // Unused key mechanic
/*0xAD*/ s8 numLives;
/*0xAE*/ s16 health;
/*0xB0*/ s16 unkB0;
/*0xB2*/ u8 hurtCounter;
/*0xB3*/ u8 healCounter;
/*0xB4*/ u8 squishTimer;
/*0xB5*/ u8 fadeWarpOpacity;
/*0xB6*/ u16 capTimer;
/*0xB8*/ s16 prevNumStarsForDialog;
/*0xBC*/ f32 peakHeight;
/*0xC0*/ f32 quicksandDepth;
/*0xC4*/ f32 unkC4;
};
#endif // TYPES_H
+153
View File
@@ -0,0 +1,153 @@
#include <string.h>
#include "shim.h"
#include "../load_anim_data.h"
u32 gGlobalTimer = 0;
u8 gSpecialTripleJump = FALSE;
s16 gCurrLevelNum = 0;
s16 gCameraMovementFlags = 0;
u32 gAudioRandom = 0;
s8 gShowDebugText = 0;
s8 gDebugLevelSelect = 0;
s16 gCurrSaveFileNum = 1;
struct Controller gController;
struct SpawnInfo gMarioSpawnInfoVal;
struct SpawnInfo *gMarioSpawnInfo = &gMarioSpawnInfoVal;
struct Area *gCurrentArea = NULL;
struct Object *gCurrentObject;
struct Object *gMarioObject = NULL;
struct PlayerCameraState gPlayerCameraState;
struct MarioAnimation D_80339D10;
struct MarioState gMarioStateVal;
struct MarioState *gMarioState = &gMarioStateVal;
SM64DebugPrintFunctionPtr gDebugPrint = NULL;
void hack_load_mario_animation_ex(struct MarioAnimation *a, u32 index)
{
if ((u32)a->currentAnimAddr == 1 + index)
return;
a->currentAnimAddr = (u8*)(1 + index);
a->targetAnim = &gLibSm64MarioAnimations[index];
}
void hack_load_mario_animation(struct MarioAnimation *a, u32 index)
{
// struct MarioAnimDmaRelatedThing *sp20 = a->animDmaTable;
// u8 *addr;
// u32 size;
//
// if (index < sp20->count) {
// addr = sp20->srcAddr + sp20->anim[index].offset;
// size = sp20->anim[index].size;
//
// if (a->currentAnimAddr != addr) {
// u32 a0 = sp20->anim[index].offset;
// u32 b0 = sp20->anim[index].size;
//
// memcpy( (u8*)a->targetAnim, (u8*)sp20 + a0, b0 );
// a->currentAnimAddr = addr;
//
// struct Animation *targetAnim = a->targetAnim;
// targetAnim->values =(void*)( (u8 *)targetAnim + (uintptr_t)targetAnim->values );
// targetAnim->index = (void*)( (u8 *)targetAnim + (uintptr_t)targetAnim->index );
// }
// }
}
void *segmented_to_virtual(const void *addr)
{
return (void*)addr;
}
void *virtual_to_segmented(u32 segment, const void *addr)
{
return (void*)addr;
}
void func_80320A4C(u8 bankIndex, u8 arg1)
{
}
void lower_background_noise(s32 a)
{
}
void raise_background_noise(s32 a)
{
}
void set_camera_mode(struct Camera *c, s16 mode, s16 frames)
{
}
void print_text_fmt_int(s32 x, s32 y, const char *str, s32 n)
{
}
s16 level_trigger_warp(struct MarioState *m, s32 warpOp)
{
return 0;
}
void play_cap_music(u16 seqArgs)
{
}
void fadeout_cap_music(void)
{
}
void stop_cap_music(void)
{
}
void play_infinite_stairs_music(void)
{
}
s32 save_file_get_total_star_count(s32 fileIndex, s32 minCourse, s32 maxCourse)
{
return 0;
}
u32 save_file_get_flags(void)
{
return 0;
}
void save_file_set_flags(u32 flags)
{
}
void save_file_clear_flags(u32 flags)
{
}
void spawn_wind_particles(s16 pitch, s16 yaw)
{
}
void set_camera_shake_from_hit(s16 shake)
{
}
void load_level_init_text(u32 arg)
{
}
void spawn_default_star(f32 sp20, f32 sp24, f32 sp28)
{
}
void play_shell_music(void)
{
}
void stop_shell_music(void)
{
}
u16 level_control_timer(s32 timerOp)
{
}
+96
View File
@@ -0,0 +1,96 @@
#pragma once
#include "include/types.h"
#include "game/area.h"
#include "game/level_update.h"
#include "../libsm64.h"
#define COURSE_MIN 0
#define COURSE_MAX 14
#define LEVEL_LLL 99
#define LEVEL_SSL 98
#define LEVEL_DDD 97
#define LEVEL_TTC 96
#define LEVEL_CASTLE 95
#define LEVEL_THI 94
// From graph_node.h, trying not to pull that in yet
#define GRAPH_RENDER_INVISIBLE (1 << 4)
#define play_sound(a,b) ({})
#define enable_time_stop() ({})
#define disable_time_stop() ({})
#define play_cutscene_music(a) ({})
struct SurfaceObjectTransform
{
float aPosX, aPosY, aPosZ;
float aVelX, aVelY, aVelZ;
s16 aFaceAnglePitch;
s16 aFaceAngleYaw;
s16 aFaceAngleRoll;
s16 aAngleVelPitch;
s16 aAngleVelYaw;
s16 aAngleVelRoll;
};
struct SurfaceNode
{
struct SurfaceNode *next;
struct Surface *surface;
};
extern u32 gGlobalTimer;
extern u8 gSpecialTripleJump;
extern s16 gCurrLevelNum;
extern s16 gCameraMovementFlags;
extern u32 gAudioRandom;
extern s8 gShowDebugText;
extern s8 gDebugLevelSelect;
extern s16 gCurrSaveFileNum;
extern struct Controller gController;
extern struct SpawnInfo gMarioSpawnInfoVal;
extern struct SpawnInfo *gMarioSpawnInfo;
extern struct Area *gCurrentArea;
extern struct Object *gCurrentObject;
extern struct Object *gMarioObject;
extern struct PlayerCameraState gPlayerCameraState;
extern struct MarioAnimation D_80339D10;
extern struct MarioState *gMarioState;
extern SM64DebugPrintFunctionPtr gDebugPrint;
#define DEBUG_LOG( ... ) do { \
if( gDebugPrint ) { \
char debugStr[1024]; \
sprintf( debugStr, __VA_ARGS__ ); \
gDebugPrint( debugStr ); \
} \
} while(0)
extern void hack_load_mario_animation_ex(struct MarioAnimation *a, u32 index);
extern void hack_load_mario_animation(struct MarioAnimation *a, u32 index);
extern void *segmented_to_virtual(const void *addr);
extern void *virtual_to_segmented(u32 segment, const void *addr);
extern void func_80320A4C(u8 bankIndex, u8 arg1);
extern void raise_background_noise(s32 a);
extern void lower_background_noise(s32 a);
extern void set_camera_mode(struct Camera *c, s16 mode, s16 frames);
extern void print_text_fmt_int(s32 x, s32 y, const char *str, s32 n);
extern s16 level_trigger_warp(struct MarioState *m, s32 warpOp);
extern void play_cap_music(u16 seqArgs);
extern void fadeout_cap_music(void);
extern void stop_cap_music(void);
extern void play_infinite_stairs_music(void);
extern s32 save_file_get_total_star_count(s32 fileIndex, s32 minCourse, s32 maxCourse);
extern u32 save_file_get_flags(void);
extern void save_file_set_flags(u32 flags);
extern void save_file_clear_flags(u32 flags);
extern void spawn_wind_particles(s16 pitch, s16 yaw);
extern void set_camera_shake_from_hit(s16 shake);
extern void load_level_init_text(u32 arg);
extern void spawn_default_star(f32 sp20, f32 sp24, f32 sp28);
extern void play_shell_music(void);
extern void stop_shell_music(void);
extern u16 level_control_timer(s32 timerOp);
+575
View File
@@ -0,0 +1,575 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if defined(_WIN32) || defined(_WIN64)
#include <io.h>
#include <fcntl.h>
#endif
#include "libmio0.h"
#include "utils.h"
// defines
#define MIO0_VERSION "0.1"
#define GET_BIT(buf, bit) ((buf)[(bit) / 8] & (1 << (7 - ((bit) % 8))))
// types
typedef struct
{
int *indexes;
int allocated;
int count;
int start;
} lookback;
// functions
#define LOOKBACK_COUNT 256
#define LOOKBACK_INIT_SIZE 128
static lookback *lookback_init(void)
{
lookback *lb = malloc(LOOKBACK_COUNT * sizeof(*lb));
for (int i = 0; i < LOOKBACK_COUNT; i++) {
lb[i].allocated = LOOKBACK_INIT_SIZE;
lb[i].indexes = malloc(lb[i].allocated * sizeof(*lb[i].indexes));
lb[i].count = 0;
lb[i].start = 0;
}
return lb;
}
static void lookback_free(lookback *lb)
{
for (int i = 0; i < LOOKBACK_COUNT; i++) {
free(lb[i].indexes);
}
free(lb);
}
static inline void lookback_push(lookback *lkbk, unsigned char val, int index)
{
lookback *lb = &lkbk[val];
if (lb->count == lb->allocated) {
lb->allocated *= 4;
lb->indexes = realloc(lb->indexes, lb->allocated * sizeof(*lb->indexes));
}
lb->indexes[lb->count++] = index;
}
static void PUT_BIT(unsigned char *buf, int bit, int val)
{
unsigned char mask = 1 << (7 - (bit % 8));
unsigned int offset = bit / 8;
buf[offset] = (buf[offset] & ~(mask)) | (val ? mask : 0);
}
// used to find longest matching stream in buffer
// buf: buffer
// start_offset: offset in buf to look back from
// max_search: max number of bytes to find
// found_offset: returned offset found (0 if none found)
// returns max length of matching stream (0 if none found)
static int find_longest(const unsigned char *buf, int start_offset, int max_search, int *found_offset, lookback *lkbk)
{
int best_length = 0;
int best_offset = 0;
int cur_length;
int search_len;
int farthest, off, i;
int lb_idx;
const unsigned char first = buf[start_offset];
lookback *lb = &lkbk[first];
// buf
// | off start max
// V |+i-> |+i-> |
// |--------------raw-data-----------------|
// |+i-> | |+i->
// +cur_length
// check at most the past 4096 values
farthest = MAX(start_offset - 4096, 0);
// find starting index
for (lb_idx = lb->start; lb_idx < lb->count && lb->indexes[lb_idx] < farthest; lb_idx++) {}
lb->start = lb_idx;
for ( ; lb_idx < lb->count && lb->indexes[lb_idx] < start_offset; lb_idx++) {
off = lb->indexes[lb_idx];
// check at most requested max or up until start
search_len = MIN(max_search, start_offset - off);
for (i = 0; i < search_len; i++) {
if (buf[start_offset + i] != buf[off + i]) {
break;
}
}
cur_length = i;
// if matched up until start, continue matching in already matched parts
if (cur_length == search_len) {
// check at most requested max less current length
search_len = max_search - cur_length;
for (i = 0; i < search_len; i++) {
if (buf[start_offset + cur_length + i] != buf[off + i]) {
break;
}
}
cur_length += i;
}
if (cur_length > best_length) {
best_offset = start_offset - off;
best_length = cur_length;
}
}
// return best reverse offset and length (may be 0)
*found_offset = best_offset;
return best_length;
}
// decode MIO0 header
// returns 1 if valid header, 0 otherwise
int mio0_decode_header(const unsigned char *buf, mio0_header_t *head)
{
if (!memcmp(buf, "MIO0", 4)) {
head->dest_size = read_u32_be(&buf[4]);
head->comp_offset = read_u32_be(&buf[8]);
head->uncomp_offset = read_u32_be(&buf[12]);
return 1;
}
return 0;
}
void mio0_encode_header(unsigned char *buf, const mio0_header_t *head)
{
memcpy(buf, "MIO0", 4);
write_u32_be(&buf[4], head->dest_size);
write_u32_be(&buf[8], head->comp_offset);
write_u32_be(&buf[12], head->uncomp_offset);
}
int mio0_decode(const unsigned char *in, unsigned char *out, unsigned int *end)
{
mio0_header_t head;
unsigned int bytes_written = 0;
int bit_idx = 0;
int comp_idx = 0;
int uncomp_idx = 0;
int valid;
// extract header
valid = mio0_decode_header(in, &head);
// verify MIO0 header
if (!valid) {
return -2;
}
// decode data
while (bytes_written < head.dest_size) {
if (GET_BIT(&in[MIO0_HEADER_LENGTH], bit_idx)) {
// 1 - pull uncompressed data
out[bytes_written] = in[head.uncomp_offset + uncomp_idx];
bytes_written++;
uncomp_idx++;
} else {
// 0 - read compressed data
int idx;
int length;
int i;
const unsigned char *vals = &in[head.comp_offset + comp_idx];
comp_idx += 2;
length = ((vals[0] & 0xF0) >> 4) + 3;
idx = ((vals[0] & 0x0F) << 8) + vals[1] + 1;
for (i = 0; i < length; i++) {
out[bytes_written] = out[bytes_written - idx];
bytes_written++;
}
}
bit_idx++;
}
if (end) {
*end = head.uncomp_offset + uncomp_idx;
}
return bytes_written;
}
int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out)
{
unsigned char *bit_buf;
unsigned char *comp_buf;
unsigned char *uncomp_buf;
unsigned int bit_length;
unsigned int comp_offset;
unsigned int uncomp_offset;
unsigned int bytes_proc = 0;
int bytes_written;
int bit_idx = 0;
int comp_idx = 0;
int uncomp_idx = 0;
lookback *lookbacks;
// initialize lookback buffer
lookbacks = lookback_init();
// allocate some temporary buffers worst case size
bit_buf = malloc((length + 7) / 8); // 1-bit/byte
comp_buf = malloc(length); // 16-bits/2bytes
uncomp_buf = malloc(length); // all uncompressed
memset(bit_buf, 0, (length + 7) / 8);
// encode data
// special case for first byte
lookback_push(lookbacks, in[0], 0);
uncomp_buf[uncomp_idx] = in[0];
uncomp_idx += 1;
bytes_proc += 1;
PUT_BIT(bit_buf, bit_idx++, 1);
while (bytes_proc < length) {
int offset;
int max_length = MIN(length - bytes_proc, 18);
int longest_match = find_longest(in, bytes_proc, max_length, &offset, lookbacks);
// push current byte before checking next longer match
lookback_push(lookbacks, in[bytes_proc], bytes_proc);
if (longest_match > 2) {
int lookahead_offset;
// lookahead to next byte to see if longer match
int lookahead_length = MIN(length - bytes_proc - 1, 18);
int lookahead_match = find_longest(in, bytes_proc + 1, lookahead_length, &lookahead_offset, lookbacks);
// better match found, use uncompressed + lookahead compressed
if ((longest_match + 1) < lookahead_match) {
// uncompressed byte
uncomp_buf[uncomp_idx] = in[bytes_proc];
uncomp_idx++;
PUT_BIT(bit_buf, bit_idx, 1);
bytes_proc++;
longest_match = lookahead_match;
offset = lookahead_offset;
bit_idx++;
lookback_push(lookbacks, in[bytes_proc], bytes_proc);
}
// first byte already pushed above
for (int i = 1; i < longest_match; i++) {
lookback_push(lookbacks, in[bytes_proc + i], bytes_proc + i);
}
// compressed block
comp_buf[comp_idx] = (((longest_match - 3) & 0x0F) << 4) |
(((offset - 1) >> 8) & 0x0F);
comp_buf[comp_idx + 1] = (offset - 1) & 0xFF;
comp_idx += 2;
PUT_BIT(bit_buf, bit_idx, 0);
bytes_proc += longest_match;
} else {
// uncompressed byte
uncomp_buf[uncomp_idx] = in[bytes_proc];
uncomp_idx++;
PUT_BIT(bit_buf, bit_idx, 1);
bytes_proc++;
}
bit_idx++;
}
// compute final sizes and offsets
// +7 so int division accounts for all bits
bit_length = ((bit_idx + 7) / 8);
// compressed data after control bits and aligned to 4-byte boundary
comp_offset = ALIGN(MIO0_HEADER_LENGTH + bit_length, 4);
uncomp_offset = comp_offset + comp_idx;
bytes_written = uncomp_offset + uncomp_idx;
// output header
memcpy(out, "MIO0", 4);
write_u32_be(&out[4], length);
write_u32_be(&out[8], comp_offset);
write_u32_be(&out[12], uncomp_offset);
// output data
memcpy(&out[MIO0_HEADER_LENGTH], bit_buf, bit_length);
memcpy(&out[comp_offset], comp_buf, comp_idx);
memcpy(&out[uncomp_offset], uncomp_buf, uncomp_idx);
// free allocated buffers
free(bit_buf);
free(comp_buf);
free(uncomp_buf);
lookback_free(lookbacks);
return bytes_written;
}
static FILE *mio0_open_out_file(const char *out_file) {
if (strcmp(out_file, "-") == 0) {
#if defined(_WIN32) || defined(_WIN64)
_setmode(_fileno(stdout), _O_BINARY);
#endif
return stdout;
} else {
return fopen(out_file, "wb");
}
}
int mio0_decode_file(const char *in_file, unsigned long offset, const char *out_file)
{
mio0_header_t head;
FILE *in;
FILE *out;
unsigned char *in_buf = NULL;
unsigned char *out_buf = NULL;
long file_size;
int ret_val = 0;
size_t bytes_read;
int bytes_decoded;
int bytes_written;
int valid;
in = fopen(in_file, "rb");
if (in == NULL) {
return 1;
}
// allocate buffer to read from offset to end of file
fseek(in, 0, SEEK_END);
file_size = ftell(in);
in_buf = malloc(file_size - offset);
fseek(in, offset, SEEK_SET);
// read bytes
bytes_read = fread(in_buf, 1, file_size - offset, in);
if (bytes_read != file_size - offset) {
ret_val = 2;
goto free_all;
}
// verify header
valid = mio0_decode_header(in_buf, &head);
if (!valid) {
ret_val = 3;
goto free_all;
}
out_buf = malloc(head.dest_size);
// decompress MIO0 encoded data
bytes_decoded = mio0_decode(in_buf, out_buf, NULL);
if (bytes_decoded < 0) {
ret_val = 3;
goto free_all;
}
// open output file
out = mio0_open_out_file(out_file);
if (out == NULL) {
ret_val = 4;
goto free_all;
}
// write data to file
bytes_written = fwrite(out_buf, 1, bytes_decoded, out);
if (bytes_written != bytes_decoded) {
ret_val = 5;
}
// clean up
if (out != stdout) {
fclose(out);
}
free_all:
if (out_buf) {
free(out_buf);
}
if (in_buf) {
free(in_buf);
}
fclose(in);
return ret_val;
}
int mio0_encode_file(const char *in_file, const char *out_file)
{
FILE *in;
FILE *out;
unsigned char *in_buf = NULL;
unsigned char *out_buf = NULL;
size_t file_size;
size_t bytes_read;
int bytes_encoded;
int bytes_written;
int ret_val = 0;
in = fopen(in_file, "rb");
if (in == NULL) {
return 1;
}
// allocate buffer to read entire contents of files
fseek(in, 0, SEEK_END);
file_size = ftell(in);
fseek(in, 0, SEEK_SET);
in_buf = malloc(file_size);
// read bytes
bytes_read = fread(in_buf, 1, file_size, in);
if (bytes_read != file_size) {
ret_val = 2;
goto free_all;
}
// allocate worst case length
out_buf = malloc(MIO0_HEADER_LENGTH + ((file_size+7)/8) + file_size);
// compress data in MIO0 format
bytes_encoded = mio0_encode(in_buf, file_size, out_buf);
// open output file
out = mio0_open_out_file(out_file);
if (out == NULL) {
ret_val = 4;
goto free_all;
}
// write data to file
bytes_written = fwrite(out_buf, 1, bytes_encoded, out);
if (bytes_written != bytes_encoded) {
ret_val = 5;
}
// clean up
if (out != stdout) {
fclose(out);
}
free_all:
if (out_buf) {
free(out_buf);
}
if (in_buf) {
free(in_buf);
}
fclose(in);
return ret_val;
}
// mio0 standalone executable
#ifdef MIO0_STANDALONE
typedef struct
{
char *in_filename;
char *out_filename;
unsigned int offset;
int compress;
} arg_config;
static arg_config default_config =
{
NULL,
NULL,
0,
1
};
static void print_usage(void)
{
ERROR("Usage: mio0 [-c / -d] [-o OFFSET] FILE [OUTPUT]\n"
"\n"
"mio0 v" MIO0_VERSION ": MIO0 compression and decompression tool\n"
"\n"
"Optional arguments:\n"
" -c compress raw data into MIO0 (default: compress)\n"
" -d decompress MIO0 into raw data\n"
" -o OFFSET starting offset in FILE (default: 0)\n"
"\n"
"File arguments:\n"
" FILE input file\n"
" [OUTPUT] output file (default: FILE.out), \"-\" for stdout\n");
exit(1);
}
// parse command line arguments
static void parse_arguments(int argc, char *argv[], arg_config *config)
{
int i;
int file_count = 0;
if (argc < 2) {
print_usage();
exit(1);
}
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] != '\0') {
switch (argv[i][1]) {
case 'c':
config->compress = 1;
break;
case 'd':
config->compress = 0;
break;
case 'o':
if (++i >= argc) {
print_usage();
}
config->offset = strtoul(argv[i], NULL, 0);
break;
default:
print_usage();
break;
}
} else {
switch (file_count) {
case 0:
config->in_filename = argv[i];
break;
case 1:
config->out_filename = argv[i];
break;
default: // too many
print_usage();
break;
}
file_count++;
}
}
if (file_count < 1) {
print_usage();
}
}
int main(int argc, char *argv[])
{
char out_filename[FILENAME_MAX];
arg_config config;
int ret_val;
// get configuration from arguments
config = default_config;
parse_arguments(argc, argv, &config);
if (config.out_filename == NULL) {
config.out_filename = out_filename;
sprintf(config.out_filename, "%s.out", config.in_filename);
}
// operation
if (config.compress) {
ret_val = mio0_encode_file(config.in_filename, config.out_filename);
} else {
ret_val = mio0_decode_file(config.in_filename, config.offset, config.out_filename);
}
switch (ret_val) {
case 1:
ERROR("Error opening input file \"%s\"\n", config.in_filename);
break;
case 2:
ERROR("Error reading from input file \"%s\"\n", config.in_filename);
break;
case 3:
ERROR("Error decoding MIO0 data. Wrong offset (0x%X)?\n", config.offset);
break;
case 4:
ERROR("Error opening output file \"%s\"\n", config.out_filename);
break;
case 5:
ERROR("Error writing bytes to output file \"%s\"\n", config.out_filename);
break;
}
return ret_val;
}
#endif // MIO0_STANDALONE
+50
View File
@@ -0,0 +1,50 @@
#ifndef LIBMIO0_H_
#define LIBMIO0_H_
// defines
#define MIO0_HEADER_LENGTH 16
// typedefs
typedef struct
{
unsigned int dest_size;
unsigned int comp_offset;
unsigned int uncomp_offset;
} mio0_header_t;
// function prototypes
// decode MIO0 header
// returns 1 if valid header, 0 otherwise
int mio0_decode_header(const unsigned char *buf, mio0_header_t *head);
// encode MIO0 header from struct
void mio0_encode_header(unsigned char *buf, const mio0_header_t *head);
// decode MIO0 data in memory
// in: buffer containing MIO0 data
// out: buffer for output data
// end: output offset of the last byte decoded from in (set to NULL if unwanted)
// returns bytes extracted to 'out' or negative value on failure
int mio0_decode(const unsigned char *in, unsigned char *out, unsigned int *end);
// encode MIO0 data in memory
// in: buffer containing raw data
// out: buffer for MIO0 data
// returns size of compressed data in 'out' including MIO0 header
int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out);
// decode an entire MIO0 block at an offset from file to output file
// in_file: input filename
// offset: offset to start decoding from in_file
// out_file: output filename
int mio0_decode_file(const char *in_file, unsigned long offset, const char *out_file);
// encode an entire file
// in_file: input filename containing raw data to be encoded
// out_file: output filename to write MIO0 compressed data to
int mio0_encode_file(const char *in_file, const char *out_file);
#endif // LIBMIO0_H_
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
#ifndef N64GRAPHICS_H_
#define N64GRAPHICS_H_
#include <stdint.h>
// intermediate formats
typedef struct _rgba
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
} rgba;
typedef struct _ia
{
uint8_t intensity;
uint8_t alpha;
} ia;
// CI palette
typedef struct
{
uint16_t data[256];
int max; // max number of entries
int used; // number of entries used
} palette_t;
//---------------------------------------------------------
// N64 RGBA/IA/I/CI -> intermediate RGBA/IA
//---------------------------------------------------------
// N64 raw RGBA16/RGBA32 -> intermediate RGBA
rgba *raw2rgba(const uint8_t *raw, int width, int height, int depth);
// N64 raw IA1/IA4/IA8/IA16 -> intermediate IA
ia *raw2ia(const uint8_t *raw, int width, int height, int depth);
// N64 raw I4/I8 -> intermediate IA
ia *raw2i(const uint8_t *raw, int width, int height, int depth);
//---------------------------------------------------------
// intermediate RGBA/IA -> N64 RGBA/IA/I/CI
// returns length written to 'raw' used or -1 on error
//---------------------------------------------------------
// intermediate RGBA -> N64 raw RGBA16/RGBA32
int rgba2raw(uint8_t *raw, const rgba *img, int width, int height, int depth);
// intermediate IA -> N64 raw IA1/IA4/IA8/IA16
int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
// intermediate IA -> N64 raw I4/I8
int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
//---------------------------------------------------------
// N64 CI <-> N64 RGBA16/IA16
//---------------------------------------------------------
// N64 CI raw data and palette to raw data (either RGBA16 or IA16)
uint8_t *ci2raw(const uint8_t *rawci, const uint8_t *palette, int width, int height, int ci_depth);
// convert from raw (RGBA16 or IA16) format to CI + palette
int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int ci_depth);
//---------------------------------------------------------
// intermediate RGBA/IA -> PNG
//---------------------------------------------------------
// intermediate RGBA write to PNG file
int rgba2png(const char *png_filename, const rgba *img, int width, int height);
// intermediate IA write to grayscale PNG file
int ia2png(const char *png_filename, const ia *img, int width, int height);
//---------------------------------------------------------
// PNG -> intermediate RGBA/IA
//---------------------------------------------------------
// PNG file -> intermediate RGBA
rgba *png2rgba(const char *png_filename, int *width, int *height);
// PNG file -> intermediate IA
ia *png2ia(const char *png_filename, int *width, int *height);
//---------------------------------------------------------
// version
//---------------------------------------------------------
// get version of underlying graphics reading library
const char *n64graphics_get_read_version(void);
// get version of underlying graphics writing library
const char *n64graphics_get_write_version(void);
#endif // N64GRAPHICS_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#include <sys/utime.h>
#else
#include <unistd.h>
#include <utime.h>
#endif
#include "utils.h"
// global verbosity setting
int g_verbosity = 0;
int read_s16_be(unsigned char *buf)
{
unsigned tmp = read_u16_be(buf);
int ret;
if (tmp > 0x7FFF) {
ret = -((int)0x10000 - (int)tmp);
} else {
ret = (int)tmp;
}
return ret;
}
float read_f32_be(unsigned char *buf)
{
union {uint32_t i; float f;} ret;
ret.i = read_u32_be(buf);
return ret.f;
}
int is_power2(unsigned int val)
{
while (((val & 1) == 0) && (val > 1)) {
val >>= 1;
}
return (val == 1);
}
void fprint_hex(FILE *fp, const unsigned char *buf, int length)
{
int i;
for (i = 0; i < length; i++) {
fprint_byte(fp, buf[i]);
fputc(' ', fp);
}
}
void fprint_hex_source(FILE *fp, const unsigned char *buf, int length)
{
int i;
for (i = 0; i < length; i++) {
if (i > 0) fputs(", ", fp);
fputs("0x", fp);
fprint_byte(fp, buf[i]);
}
}
void print_hex(const unsigned char *buf, int length)
{
fprint_hex(stdout, buf, length);
}
void swap_bytes(unsigned char *data, long length)
{
long i;
unsigned char tmp;
for (i = 0; i < length; i += 2) {
tmp = data[i];
data[i] = data[i+1];
data[i+1] = tmp;
}
}
void reverse_endian(unsigned char *data, long length)
{
long i;
unsigned char tmp;
for (i = 0; i < length; i += 4) {
tmp = data[i];
data[i] = data[i+3];
data[i+3] = tmp;
tmp = data[i+1];
data[i+1] = data[i+2];
data[i+2] = tmp;
}
}
long filesize(const char *filename)
{
struct stat st;
if (stat(filename, &st) == 0) {
return st.st_size;
}
return -1;
}
void touch_file(const char *filename)
{
int fd;
//fd = open(filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
fd = open(filename, O_WRONLY|O_CREAT, 0666);
if (fd >= 0) {
utime(filename, NULL);
close(fd);
}
}
long read_file(const char *file_name, unsigned char **data)
{
FILE *in;
unsigned char *in_buf = NULL;
long file_size;
long bytes_read;
in = fopen(file_name, "rb");
if (in == NULL) {
return -1;
}
// allocate buffer to read from offset to end of file
fseek(in, 0, SEEK_END);
file_size = ftell(in);
// sanity check
if (file_size > 256*MB) {
return -2;
}
in_buf = malloc(file_size);
fseek(in, 0, SEEK_SET);
// read bytes
bytes_read = fread(in_buf, 1, file_size, in);
if (bytes_read != file_size) {
return -3;
}
fclose(in);
*data = in_buf;
return bytes_read;
}
long write_file(const char *file_name, unsigned char *data, long length)
{
FILE *out;
long bytes_written;
// open output file
out = fopen(file_name, "wb");
if (out == NULL) {
perror(file_name);
return -1;
}
bytes_written = fwrite(data, 1, length, out);
fclose(out);
return bytes_written;
}
void generate_filename(const char *in_name, char *out_name, char *extension)
{
char tmp_name[FILENAME_MAX];
int len;
int i;
strcpy(tmp_name, in_name);
len = strlen(tmp_name);
for (i = len - 1; i > 0; i--) {
if (tmp_name[i] == '.') {
break;
}
}
if (i <= 0) {
i = len;
}
tmp_name[i] = '\0';
sprintf(out_name, "%s.%s", tmp_name, extension);
}
char *basename(const char *name)
{
const char *base = name;
while (*name) {
if (*name++ == '/') {
base = name;
}
}
return (char *)base;
}
void make_dir(const char *dir_name)
{
struct stat st = {0};
if (stat(dir_name, &st) == -1) {
mkdir(dir_name, 0755);
}
}
long copy_file(const char *src_name, const char *dst_name)
{
unsigned char *buf;
long bytes_written;
long bytes_read;
bytes_read = read_file(src_name, &buf);
if (bytes_read > 0) {
bytes_written = write_file(dst_name, buf, bytes_read);
if (bytes_written != bytes_read) {
bytes_read = -1;
}
free(buf);
}
return bytes_read;
}
void dir_list_ext(const char *dir, const char *extension, dir_list *list)
{
char *pool;
char *pool_ptr;
struct dirent *entry;
DIR *dfd;
int idx;
dfd = opendir(dir);
if (dfd == NULL) {
ERROR("Can't open '%s'\n", dir);
exit(1);
}
pool = malloc(FILENAME_MAX * MAX_DIR_FILES);
pool_ptr = pool;
idx = 0;
while ((entry = readdir(dfd)) != NULL && idx < MAX_DIR_FILES) {
if (!extension || str_ends_with(entry->d_name, extension)) {
sprintf(pool_ptr, "%s/%s", dir, entry->d_name);
list->files[idx] = pool_ptr;
pool_ptr += strlen(pool_ptr) + 1;
idx++;
}
}
list->count = idx;
closedir(dfd);
}
void dir_list_free(dir_list *list)
{
// assume first entry in array is allocated
if (list->files[0]) {
free(list->files[0]);
list->files[0] = NULL;
}
}
int str_ends_with(const char *str, const char *suffix)
{
if (!str || !suffix) {
return 0;
}
size_t len_str = strlen(str);
size_t len_suffix = strlen(suffix);
if (len_suffix > len_str) {
return 0;
}
return (0 == strncmp(str + len_str - len_suffix, suffix, len_suffix));
}
+153
View File
@@ -0,0 +1,153 @@
#ifndef UTILS_H_
#define UTILS_H_
#include <stdio.h>
// defines
// printing size_t varies by compiler
#if defined(_MSC_VER) || defined(__MINGW32__)
#define SIZE_T_FORMAT "%Iu"
#else
#define SIZE_T_FORMAT "%zu"
#endif
#define KB 1024
#define MB (1024 * KB)
// number of elements in statically declared array
#define DIM(S_ARR_) (sizeof(S_ARR_) / sizeof(S_ARR_[0]))
#define MIN(A_, B_) ((A_) < (B_) ? (A_) : (B_))
#define MAX(A_, B_) ((A_) > (B_) ? (A_) : (B_))
// align value to N-byte boundary
#define ALIGN(VAL_, ALIGNMENT_) (((VAL_) + ((ALIGNMENT_) - 1)) & ~((ALIGNMENT_) - 1))
// read/write u32/16 big/little endian
#define read_u32_be(buf) (unsigned int)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3]))
#define read_u32_le(buf) (unsigned int)(((buf)[1] << 24) + ((buf)[0] << 16) + ((buf)[3] << 8) + ((buf)[2]))
#define write_u32_be(buf, val) do { \
(buf)[0] = ((val) >> 24) & 0xFF; \
(buf)[1] = ((val) >> 16) & 0xFF; \
(buf)[2] = ((val) >> 8) & 0xFF; \
(buf)[3] = (val) & 0xFF; \
} while(0)
#define read_u16_be(buf) (((buf)[0] << 8) + ((buf)[1]))
#define write_u16_be(buf, val) do { \
(buf)[0] = ((val) >> 8) & 0xFF; \
(buf)[1] = ((val)) & 0xFF; \
} while(0)
// print nibbles and bytes
#define fprint_nibble(FP, NIB_) fputc((NIB_) < 10 ? ('0' + (NIB_)) : ('A' + (NIB_) - 0xA), FP)
#define fprint_byte(FP, BYTE_) do { \
fprint_nibble(FP, (BYTE_) >> 4); \
fprint_nibble(FP, (BYTE_) & 0x0F); \
} while(0)
#define print_nibble(NIB_) fprint_nibble(stdout, NIB_)
#define print_byte(BYTE_) fprint_byte(stdout, BYTE_)
// Windows compatibility
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <direct.h>
#define mkdir(DIR_, PERM_) _mkdir(DIR_)
#ifndef strcasecmp
#define strcasecmp(A, B) stricmp(A, B)
#endif
#endif
// typedefs
#define MAX_DIR_FILES 128
typedef struct
{
char *files[MAX_DIR_FILES];
int count;
} dir_list;
// global verbosity setting
extern int g_verbosity;
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
#define INFO(...) if (g_verbosity) printf(__VA_ARGS__)
#define INFO_HEX(...) if (g_verbosity) print_hex(__VA_ARGS__)
// functions
// convert two bytes in big-endian to signed int
int read_s16_be(unsigned char *buf);
// convert four bytes in big-endian to float
float read_f32_be(unsigned char *buf);
// determine if value is power of 2
// returns 1 if val is power of 2, 0 otherwise
int is_power2(unsigned int val);
// print buffer as hex bytes
// fp: file pointer
// buf: buffer to read bytes from
// length: length of buffer to print
void fprint_hex(FILE *fp, const unsigned char *buf, int length);
void fprint_hex_source(FILE *fp, const unsigned char *buf, int length);
void print_hex(const unsigned char *buf, int length);
// perform byteswapping to convert from v64 to z64 ordering
void swap_bytes(unsigned char *data, long length);
// reverse endian to convert from n64 to z64 ordering
void reverse_endian(unsigned char *data, long length);
// get size of file without opening it;
// returns file size or negative on error
long filesize(const char *file_name);
// update file timestamp to now, creating it if it doesn't exist
void touch_file(const char *filename);
// read entire contents of file into buffer
// returns file size or negative on error
long read_file(const char *file_name, unsigned char **data);
// write buffer to file
// returns number of bytes written out or -1 on failure
long write_file(const char *file_name, unsigned char *data, long length);
// generate an output file name from input name by replacing file extension
// in_name: input file name
// out_name: buffer to write output name in
// extension: new file extension to use
void generate_filename(const char *in_name, char *out_name, char *extension);
// extract base filename from file path
// name: path to file
// returns just the file name after the last '/'
char *basename(const char *name);
// make a directory if it doesn't exist
// dir_name: name of the directory
void make_dir(const char *dir_name);
// copy a file from src_name to dst_name. will not make directories
// src_name: source file name
// dst_name: destination file name
long copy_file(const char *src_name, const char *dst_name);
// list a directory, optionally filtering files by extension
// dir: directory to list files in
// extension: extension to filter files by (NULL if no filtering)
// list: output list and count
void dir_list_ext(const char *dir, const char *extension, dir_list *list);
// free associated date from a directory list
// list: directory list filled in by dir_list_ext() call
void dir_list_free(dir_list *list);
// determine if a string ends with another string
// str: string to check if ends with 'suffix'
// suffix: string to see if 'str' ends with
// returns 1 if 'str' ends with 'suffix'
int str_ends_with(const char *str, const char *suffix);
#endif // UTILS_H_