Massive refactor
This commit is contained in:
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user