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
+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