papermario/src/77480.c
HailSanta e342a33a20
star rod dx upstreaming (#1177)
* so far

* leftover

* first batch

* part zwei

* item name changes

* misspelling

* comments

* THE

* fix pal

* muurgle

---------

Co-authored-by: HailSanta <Hail2Santa@gmail.com>
2024-03-06 02:32:00 -05:00

1742 lines
55 KiB
C

#include "common.h"
#include "ld_addrs.h"
#include "world/actions.h"
#include "sprite.h"
#include "world/partner/watt.h"
#include "sprite/player.h"
#ifdef SHIFT
#define inspect_icon_VRAM inspect_icon_VRAM
#define speech_bubble_VRAM speech_bubble_VRAM
#define pulse_stone_VRAM pulse_stone_VRAM
#define i_spy_VRAM i_spy_VRAM
#else
#define inspect_icon_VRAM (void*)0x802B7000
#define speech_bubble_VRAM (void*)0x802B7000
#define pulse_stone_VRAM (void*)0x802B7000
#define i_spy_VRAM (void*)0x802B7000
#endif
#if VERSION_JP // TODO remove once segments are split
extern Addr i_spy_ROM_START;
extern Addr i_spy_ROM_END;
extern Addr pulse_stone_ROM_START;
extern Addr pulse_stone_ROM_END;
extern Addr speech_bubble_ROM_START;
extern Addr speech_bubble_ROM_END;
extern Addr inspect_icon_ROM_START;
extern Addr inspect_icon_ROM_END;
#endif
UNK_FUN_PTR(ISpyNotificationCallback);
UNK_FUN_PTR(PulseStoneNotificationCallback);
UNK_FUN_PTR(TalkNotificationCallback);
UNK_FUN_PTR(InteractNotificationCallback);
s32 D_8010C950;
PlayerStatus gPlayerStatus;
PlayerData gPlayerData;
extern f32 D_800F7B48;
extern s32 D_800F7B4C;
extern s32 WorldTattleInteractionID;
HitID player_raycast_down(f32*, f32*, f32*, f32*);
HitID player_raycast_up_corner(f32* x, f32* y, f32* z, f32* length);
HitID player_raycast_general(s32, f32, f32, f32, f32, f32, f32, f32*, f32*, f32*, f32*, f32*, f32*, f32*);
void player_get_slip_vector(f32* outX, f32* outY, f32 x, f32 y, f32 nX, f32 nY);
void phys_update_standard(void);
void phys_update_lava_reset(void);
void update_player_blink(void);
void check_for_ispy(void);
void render_ispy_icon(void);
void check_for_pulse_stone(void);
void clear_ispy_icon(void);
void render_pulse_stone_icon(void);
void clear_pulse_stone_icon(void);
void check_for_conversation_prompt(void);
void render_conversation_prompt(void);
void clear_conversation_prompt(void);
void check_for_interactables(void);
void render_interact_prompt(void);
void clear_interact_prompt(void);
void update_partner_timers(void);
void player_update_sprite(void);
s32 get_player_back_anim(s32 arg0);
void appendGfx_player(void* data);
void appendGfx_player_spin(void* data);
void update_player_shadow(void);
s32 partner_use_ability(void);
HitID player_raycast_below(f32 yaw, f32 diameter, f32* outX, f32* outY, f32* outZ, f32* outLength, f32* hitRx, f32* hitRz,
f32* hitDirX, f32* hitDirZ) {
f32 x, y, z, length;
f32 inputX, inputY, inputZ, inputLength;
f32 cosTheta;
f32 sinTheta;
f32 temp_f20;
f32 cosTemp;
f32 sinTemp;
s32 hitID;
s32 ret;
*hitRx = 0.0f;
*hitRz = 0.0f;
*hitDirX = 0.0f;
*hitDirZ = 0.0f;
inputLength = *outLength;
temp_f20 = diameter * 0.28f;
sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta);
sinTemp = temp_f20 * sinTheta;
cosTemp = -temp_f20 * cosTheta;
inputX = *outX;
inputY = *outY;
inputZ = *outZ;
x = inputX + sinTemp;
y = inputY;
z = inputZ + cosTemp;
length = inputLength;
hitID = player_raycast_down(&x, &y, &z, &length);
ret = NO_COLLIDER;
if (hitID > NO_COLLIDER && length <= fabsf(*outLength)) {
*hitRx = -gGameStatusPtr->playerGroundTraceAngles.x;
*hitRz = -gGameStatusPtr->playerGroundTraceAngles.z;
*outX = x;
*outY = y;
*outZ = z;
*outLength = length;
*hitDirX = sinTemp;
*hitDirZ = cosTemp;
ret = hitID;
}
x = inputX - sinTemp;
y = inputY;
z = inputZ - cosTemp;
length = inputLength;
hitID = player_raycast_down(&x, &y, &z, &length);
if (hitID > NO_COLLIDER && length <= fabsf(*outLength)) {
*hitRx = -gGameStatusPtr->playerGroundTraceAngles.x;
*hitRz = -gGameStatusPtr->playerGroundTraceAngles.z;
*outX = x;
*outY = y;
*outZ = z;
*outLength = length;
*hitDirX = -sinTemp;
*hitDirZ = -cosTemp;
ret = hitID;
}
x = inputX + cosTemp;
y = inputY;
z = inputZ + sinTemp;
length = inputLength;
hitID = player_raycast_down(&x, &y, &z, &length);
if (hitID > NO_COLLIDER && length <= fabsf(*outLength)) {
*hitRx = -gGameStatusPtr->playerGroundTraceAngles.x;
*hitRz = -gGameStatusPtr->playerGroundTraceAngles.z;
*outX = x;
*outY = y;
*outZ = z;
*outLength = length;
*hitDirX = sinTemp;
*hitDirZ = cosTemp;
ret = hitID;
}
x = inputX - cosTemp;
y = inputY;
z = inputZ - sinTemp;
length = inputLength;
hitID = player_raycast_down(&x, &y, &z, &length);
if (hitID > NO_COLLIDER && length <= fabsf(*outLength)) {
*hitRx = -gGameStatusPtr->playerGroundTraceAngles.x;
*hitRz = -gGameStatusPtr->playerGroundTraceAngles.z;
*outX = x;
*outY = y;
*outZ = z;
*outLength = length;
*hitDirX = -sinTemp;
*hitDirZ = -cosTemp;
ret = hitID;
}
x = inputX;
y = inputY;
z = inputZ;
length = inputLength;
hitID = player_raycast_down(&x, &y, &z, &length);
if (hitID > NO_COLLIDER && length <= fabsf(*outLength)) {
*hitRx = -gGameStatusPtr->playerGroundTraceAngles.x;
*hitRz = -gGameStatusPtr->playerGroundTraceAngles.z;
*outX = x;
*outY = y;
*outZ = z;
*outLength = length;
*hitDirX = 0.0f;
*hitDirZ = 0.0f;
ret = hitID;
}
if (ret <= NO_COLLIDER) {
*outX = x;
*outY = y;
*outZ = z;
}
return ret;
}
HitID player_raycast_below_cam_relative(PlayerStatus* playerStatus, f32* outX, f32* outY, f32* outZ, f32* outLength,
f32* hitRx, f32* hitRz, f32* hitDirX, f32* hitDirZ) {
f32 yaw = 0.0f;
if (playerStatus->spriteFacingAngle >= 90.0f && playerStatus->spriteFacingAngle < 270.0f) {
yaw = 180.0f;
}
return player_raycast_below(yaw - 90.0f + gCameras[gCurrentCameraID].curYaw, playerStatus->colliderDiameter,
outX, outY, outZ, outLength, hitRx, hitRz, hitDirX, hitDirZ);
}
HitID player_raycast_down(f32* x, f32* y, f32* z, f32* length) {
f32 hitX;
f32 hitY;
f32 hitZ;
f32 hitDepth;
f32 hitNx;
f32 hitNy;
f32 hitNz;
s32 entityID, colliderID;
Entity* entity;
s32 ret = NO_COLLIDER;
hitDepth = *length;
entityID = test_ray_entities(*x, *y, *z, 0.0f, -1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (entityID > NO_COLLIDER) {
entity = get_entity_by_index(entityID);
if (entity->alpha < 255) {
entity->collisionTimer = 4;
entity->flags |= ENTITY_FLAG_CONTINUOUS_COLLISION;
} else {
ret = entityID | COLLISION_WITH_ENTITY_BIT;
}
}
colliderID = test_ray_colliders(COLLIDER_FLAG_IGNORE_PLAYER, *x, *y, *z, 0, -1.0f, 0, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (colliderID > NO_COLLIDER) {
ret = colliderID;
}
if (ret > NO_COLLIDER) {
*length = hitDepth;
*x = hitX;
*y = hitY;
*z = hitZ;
gGameStatusPtr->playerGroundTraceNormal.x = hitNx;
gGameStatusPtr->playerGroundTraceNormal.y = hitNy;
gGameStatusPtr->playerGroundTraceNormal.z = hitNz;
PlayerNormalYaw = get_player_normal_yaw();
PlayerNormalPitch = get_player_normal_pitch();
gGameStatusPtr->playerGroundTraceAngles.x = atan2(0.0f, 0.0f, hitNz * 100.0, hitNy * 100.0);
gGameStatusPtr->playerGroundTraceAngles.y = 0.0f;
gGameStatusPtr->playerGroundTraceAngles.z = atan2(0.0f, 0.0f, hitNx * 100.0, hitNy * 100.0);
} else {
gGameStatusPtr->playerGroundTraceAngles.x = 0.0f;
gGameStatusPtr->playerGroundTraceAngles.y = 0.0f;
gGameStatusPtr->playerGroundTraceAngles.z = 0.0f;
}
return ret;
}
HitID player_raycast_up_corners(PlayerStatus* player, f32* posX, f32* posY, f32* posZ, f32* hitDepth, f32 yaw) {
f32 startX;
f32 startY;
f32 startZ;
f32 depth;
f32 theta;
f32 deltaZ;
f32 deltaX;
f32 x,y,z;
s32 ret;
s32 hitID;
f32 radius;
radius = player->colliderDiameter * 0.3f;
theta = DEG_TO_RAD(yaw);
deltaX = radius * sin_rad(theta);
deltaZ = -radius * cos_rad(theta);
x = *posX;
y = *posY;
z = *posZ;
depth = *hitDepth;
startX = x + deltaX;
startY = y;
startZ = z + deltaZ;
ret = NO_COLLIDER;
hitID = player_raycast_up_corner(&startX, &startY, &startZ, &depth);
if (hitID <= NO_COLLIDER) {
startX = x - deltaX;
startY = y;
startZ = z - deltaZ;
hitID = player_raycast_up_corner(&startX, &startY, &startZ, &depth);
}
if (hitID <= NO_COLLIDER) {
startX = x + deltaZ;
startY = y;
startZ = z + deltaX;
hitID = player_raycast_up_corner(&startX, &startY, &startZ, &depth);
}
if (hitID <= NO_COLLIDER) {
startX = x - deltaZ;
startY = y;
startZ = z - deltaX;
hitID = player_raycast_up_corner(&startX, &startY, &startZ, &depth);
}
if (hitID > NO_COLLIDER) {
*posX = startX;
*posY = startY;
*posZ = startZ;
*hitDepth = depth;
ret = hitID;
}
if (ret <= NO_COLLIDER) {
*posX = startX;
*posY = startY;
*posZ = startZ;
*hitDepth = 0;
}
return ret;
}
HitID player_raycast_up_corner(f32* x, f32* y, f32* z, f32* length) {
f32 hitX;
f32 hitY;
f32 hitZ;
f32 hitDepth;
f32 hitNx;
f32 hitNy;
f32 hitNz;
s32 hitID;
Entity* entity;
s32 ret;
f32 sx, sy, sz;
f32 sx2, sy2, sz2;
f32 startX, startY, startZ;
ret = NO_COLLIDER;
// needed to match
sx2 = sx = *x;
sy2 = sy = *y;
sz2 = sz = *z;
hitDepth = *length;
hitID = test_ray_colliders(COLLIDER_FLAG_IGNORE_PLAYER, sx, sy, sz, 0.0f, 1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (hitID > NO_COLLIDER && *length > hitDepth) {
*length = hitDepth;
ret = hitID;
*x = sx = sx2;
*y = sy = sy2;
*z = sz = sz2;
}
hitDepth = 10.0f;
hitID = test_ray_entities(*x, *y, *z, 0.0f, 1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
sx = sx2;
sy = sy2;
sz = sz2;
if (hitID > NO_COLLIDER && *length > hitDepth) {
get_entity_by_index(hitID);
ret = hitID | COLLISION_WITH_ENTITY_BIT;
*length = hitDepth;
*x = sx;
*y = sy;
*z = sz;
}
return ret;
}
HitID player_test_lateral_overlap(s32 mode, PlayerStatus* playerStatus, f32* x, f32* y, f32* z, f32 length, f32 yaw) {
f32 sinTheta;
f32 cosTheta;
f32 hitX;
f32 hitY;
f32 hitZ;
f32 hitDepth;
f32 hitNx;
f32 hitNy;
f32 hitNz;
f32 slipDx;
f32 slipDz;
f32 depthDiff;
f32 radius;
f32 originalDepth;
s32 hitID;
f32 height;
f32 targetDx;
f32 targetDz;
f32 dx;
f32 dz;
s32 ret;
radius = playerStatus->colliderDiameter * 0.5f;
ret = NO_COLLIDER;
if (!(playerStatus->flags & (PS_FLAG_FALLING | PS_FLAG_JUMPING))) {
height = playerStatus->colliderHeight * 0.286f;
} else {
height = 1.0f;
}
sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta);
cosTheta = -cosTheta;
hitDepth = length + radius;
hitID = player_raycast_general(mode, *x, *y + height, *z, sinTheta, 0, cosTheta, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (mode == 3) {
targetDx = 0.0f;
targetDz = 0.0f;
} else {
targetDx = length * sinTheta;
targetDz = length * cosTheta;
}
if (hitID > NO_COLLIDER) {
originalDepth = length + radius;
if (hitDepth <= originalDepth) {
depthDiff = hitDepth - originalDepth;
dx = depthDiff * sinTheta;
dz = depthDiff * cosTheta;
player_get_slip_vector(&slipDx, &slipDz, targetDx, targetDz, hitNx, hitNz);
*x += dx + slipDx;
*z += dz + slipDz;
ret = hitID;
}
}
*x += targetDx;
*z += targetDz;
return ret;
}
HitID player_raycast_general(s32 mode, f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ, f32* hitX,
f32* hitY, f32* hitZ, f32* hitDepth, f32*hitNx, f32* hitNy, f32* hitNz) {
f32 nAngleX;
f32 nAngleZ;
s32 entityID;
s32 colliderID;
Entity* entity;
s32 ignoreFlags;
s32 ret;
entityID = test_ray_entities(startX, startY, startZ, dirX, dirY, dirZ, hitX, hitY, hitZ, hitDepth, hitNx, hitNy,
hitNz);
ret = NO_COLLIDER;
if (entityID > NO_COLLIDER) {
entity = get_entity_by_index(entityID);
if (entity->alpha < 255) {
entity->collisionTimer = 0;
entity->flags |= ENTITY_FLAG_CONTINUOUS_COLLISION;
} else {
ret = entityID | COLLISION_WITH_ENTITY_BIT;
}
} else if (mode == PLAYER_COLLISION_3) {
ret = test_ray_colliders(COLLIDER_FLAG_IGNORE_SHELL, startX, startY, startZ, dirX, dirY, dirZ,
hitX, hitY, hitZ, hitDepth, hitNx, hitNy, hitNz);
}
if (mode == PLAYER_COLLISION_1 || mode == PLAYER_COLLISION_3) {
return ret;
}
if (mode == PLAYER_COLLISION_4) {
ignoreFlags = COLLIDER_FLAG_DOCK_WALL;
} else {
ignoreFlags = COLLIDER_FLAG_IGNORE_PLAYER;
}
colliderID = test_ray_colliders(ignoreFlags, startX, startY, startZ, dirX, dirY, dirZ,
hitX, hitY, hitZ, hitDepth, hitNx, hitNy, hitNz);
if (ret <= NO_COLLIDER) {
ret = colliderID;
}
if (ret > NO_COLLIDER) {
nAngleZ = 180.0f - atan2(0, 0, *hitNz * 100.0, *hitNy * 100.0);
nAngleX = 180.0f - atan2(0, 0, *hitNx * 100.0, *hitNy * 100.0);
if (!((nAngleZ == 90.0f && nAngleX == 90.0f) || fabs(nAngleZ) >= 30.0 || fabs(nAngleX) >= 30.0)) {
ret = NO_COLLIDER;
}
}
return ret;
}
HitID player_test_move_without_slipping(PlayerStatus* playerStatus, f32* x, f32* y, f32* z, f32 length, f32 yaw, s32* hasClimbableStep) {
f32 sinTheta;
f32 cosTheta;
f32 hitX;
f32 hitY;
f32 hitZ;
f32 hitDepth;
f32 hitNx;
f32 hitNy;
f32 hitNz;
f32 slipDx;
f32 slipDz;
f32 depth;
f32 radius;
f32 depthDiff;
f32 height;
s32 ret;
s32 hitID;
f32 targetDx;
f32 targetDz;
f32 dx, dz;
radius = playerStatus->colliderDiameter * 0.5f;
height = playerStatus->colliderHeight * 0.286f;
sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta);
depth = length + radius;
cosTheta = -cosTheta;
hitDepth = depth;
dx = radius * sinTheta;
ret = NO_COLLIDER;
hitID = player_raycast_general(PLAYER_COLLISION_0, *x, *y + 0.1, *z, sinTheta, 0, cosTheta, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (hitID > NO_COLLIDER && hitDepth <= depth) {
*hasClimbableStep = TRUE;
}
depth = length + radius;
hitDepth = depth;
dz = radius * cosTheta;
hitID = player_raycast_general(PLAYER_COLLISION_0, *x, *y + height, *z, sinTheta, 0, cosTheta, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
targetDx = 0.0f;
targetDz = 0.0f;
if (hitID > NO_COLLIDER && hitDepth <= depth) {
depthDiff = hitDepth - depth;
dx = depthDiff * sinTheta;
dz = depthDiff * cosTheta;
player_get_slip_vector(&slipDx, &slipDz, 0.0f, 0.0f, hitNx, hitNz);
*x += dx + slipDx;
*z += dz + slipDz;
ret = hitID;
}
*x += targetDx;
*z += targetDz;
return ret;
}
void player_get_slip_vector(f32* outX, f32* outY, f32 x, f32 y, f32 nX, f32 nY) {
f32 projectionLength = (x * nX) + (y * nY);
*outX = (x - projectionLength * nX) * 0.5f;
*outY = (y - projectionLength * nY) * 0.5f;
}
HitID player_test_move_with_slipping(PlayerStatus* playerStatus, f32* x, f32* y, f32* z, f32 length, f32 yaw) {
f32 sinTheta;
f32 cosTheta;
f32 hitX;
f32 hitY;
f32 hitZ;
f32 hitDepth;
f32 hitNx;
f32 hitNy;
f32 hitNz;
f32 slipDx;
f32 slipDz;
f32 radius;
f32 height;
s32 hitID;
f32 targetDx, targetDz;
f32 dx, dz;
f32 depthDiff;
s32 ret = NO_COLLIDER;
height = 0.0f;
if (!(playerStatus->flags & (PS_FLAG_JUMPING | PS_FLAG_FALLING))) {
height = 10.01f;
}
radius = playerStatus->colliderDiameter * 0.5f;
sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta);
cosTheta = -cosTheta;
hitDepth = length + radius;
targetDx = length * sinTheta;
targetDz = length * cosTheta;
hitID = player_raycast_general(PLAYER_COLLISION_0, *x, *y + height, *z, sinTheta, 0, cosTheta, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (hitID > NO_COLLIDER && (depthDiff = hitDepth, depthDiff <= length + radius)) {
depthDiff -= (length + radius);
dx = depthDiff * sinTheta;
dz = depthDiff * cosTheta;
player_get_slip_vector(&slipDx, &slipDz, targetDx, targetDz, hitNx, hitNz);
*x += dx + slipDx;
*z += dz + slipDz;
ret = hitID;
} else {
height = playerStatus->colliderHeight * 0.75;
hitID = player_raycast_general(PLAYER_COLLISION_0, *x, *y + height, *z, sinTheta, 0, cosTheta, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz);
if (hitID > NO_COLLIDER && (depthDiff = hitDepth, depthDiff <= length + radius)) {
depthDiff -= (length + radius);
dx = depthDiff * sinTheta;
dz = depthDiff * cosTheta;
player_get_slip_vector(&slipDx, &slipDz, targetDx, targetDz, hitNx, hitNz);
*x += dx + slipDx;
*z += dz + slipDz;
ret = hitID;
}
}
*x += targetDx;
*z += targetDz;
return ret;
}
// main function for player physics called from state step functions
void update_player(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
CollisionStatus* collisionStatus = &gCollisionStatus;
GameStatus* gameStatus;
update_partner_timers();
if ((playerStatus->timeInAir > 100) || (playerStatus->pos.y < -2000.0f)) {
if (!(playerStatus->animFlags & PA_FLAG_NO_OOB_RESPAWN)) {
playerStatus->timeInAir = 0;
playerStatus->pos.x = playerStatus->lastGoodPos.x;
playerStatus->pos.y = playerStatus->lastGoodPos.y;
playerStatus->pos.z = playerStatus->lastGoodPos.z;
if (playerStatus->animFlags & PA_FLAG_RIDING_PARTNER) {
Npc* partner;
playerStatus->animFlags |= PA_FLAG_DISMOUNTING_ALLOWED | PA_FLAG_INTERRUPT_USE_PARTNER;
partner = get_npc_unsafe(NPC_PARTNER);
partner->pos.x = playerStatus->lastGoodPos.x;
partner->pos.y = playerStatus->lastGoodPos.y + playerStatus->colliderHeight;
partner->pos.z = playerStatus->lastGoodPos.z;
partner->moveToPos.y = playerStatus->lastGoodPos.y;
} else {
playerStatus->timeInAir = 10;
}
}
}
collisionStatus->curWall = NO_COLLIDER;
collisionStatus->lastWallHammered = NO_COLLIDER;
collisionStatus->curInspect = NO_COLLIDER;
collisionStatus->floorBelow = TRUE;
update_player_input();
playerStatus->flags &= ~PS_FLAG_SPECIAL_LAND;
update_player_blink();
if (playerStatus->flags & PS_FLAG_NO_STATIC_COLLISION) {
phys_update_action_state();
if (!check_player_action_debug()) {
collision_main_lateral();
}
} else if (playerStatus->actionState != ACTION_STATE_HIT_LAVA) {
phys_update_standard();
} else {
phys_update_lava_reset();
}
if (playerStatus->flags & PS_FLAG_CUTSCENE_MOVEMENT) {
playerStatus->moveFrames--;
if (playerStatus->moveFrames <= 0) {
playerStatus->moveFrames = 0;
playerStatus->flags &= ~PS_FLAG_CUTSCENE_MOVEMENT;
}
}
if (!(playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS)) {
handle_floor_behavior();
}
player_update_sprite();
gameStatus = gGameStatusPtr;
gameStatus->playerPos.x = playerStatus->pos.x;
gameStatus->playerPos.y = playerStatus->pos.y;
gameStatus->playerPos.z = playerStatus->pos.z;
gameStatus->playerYaw = playerStatus->curYaw;
check_input_open_menus();
if (!(playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS)) {
check_input_status_bar();
}
update_player_shadow();
check_for_interactables();
check_for_conversation_prompt();
check_for_pulse_stone();
check_for_ispy();
playerStatus->pushVel.x = 0.0f;
playerStatus->pushVel.y = 0.0f;
playerStatus->pushVel.z = 0.0f;
playerStatus->flags &= ~PS_FLAG_SLIDING;
playerStatus->animFlags &= ~PA_FLAG_FORCE_USE_PARTNER;
}
void check_input_use_partner(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
PlayerData* playerData = &gPlayerData;
u32 actionState = playerStatus->actionState;
if (!(playerStatus->animFlags & PA_FLAG_8BIT_MARIO)
&& (playerStatus->animFlags & PA_FLAG_FORCE_USE_PARTNER || playerStatus->inputDisabledCount == 0)
&& (playerStatus->pressedButtons & BUTTON_C_DOWN && !(playerStatus->flags & PS_FLAG_NO_PARTNER_USAGE))
&& !(playerStatus->pressedButtons & BUTTON_B)
&& !(playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS)
&& actionState <= ACTION_STATE_RUN
) {
if (playerData->curPartner == PARTNER_GOOMBARIO) {
WorldTattleInteractionID = playerStatus->interactingWithID;
}
partner_use_ability();
}
}
void phys_update_standard(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
s32 flags;
check_input_use_partner();
phys_update_action_state();
if (!(playerStatus->flags & PS_FLAG_FLYING)) {
if (playerStatus->flags & PS_FLAG_JUMPING) {
phys_update_jump();
}
}
if (playerStatus->flags & PS_FLAG_FALLING) {
if (!(playerStatus->flags & PS_FLAG_FLYING)) {
phys_update_falling();
}
}
check_input_midair_jump();
if (playerStatus->actionState != ACTION_STATE_SLIDING) {
collision_main_lateral();
collision_check_player_overlaps();
if (collision_main_above() <= NO_COLLIDER && playerStatus->timeInAir == 0 &&
playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS) {
collision_lateral_peach();
}
if ((playerStatus->actionState != ACTION_STATE_ENEMY_FIRST_STRIKE)
&& (playerStatus->actionState != ACTION_STATE_STEP_UP)) {
phys_main_collision_below();
}
}
if (playerStatus->animFlags & PA_FLAG_WATT_IN_HANDS) {
world_watt_sync_held_position();
}
if (!(playerStatus->flags & PS_FLAG_CAMERA_DOESNT_FOLLOW)) {
gCameras[CAM_DEFAULT].targetPos.x = playerStatus->pos.x;
gCameras[CAM_DEFAULT].targetPos.y = playerStatus->pos.y;
gCameras[CAM_DEFAULT].targetPos.z = playerStatus->pos.z;
}
}
void phys_update_lava_reset(void) {
phys_update_action_state();
collision_main_lateral();
collision_lava_reset_check_additional_overlaps();
if (!(gPlayerStatusPtr->flags & PS_FLAG_CAMERA_DOESNT_FOLLOW)) {
Camera* camera = &gCameras[CAM_DEFAULT];
camera->targetPos.x = gPlayerStatusPtr->pos.x;
camera->targetPos.y = gPlayerStatusPtr->pos.y;
camera->targetPos.z = gPlayerStatusPtr->pos.z;
}
}
void clear_player_status(void) {
mem_clear(&gPlayerStatus, sizeof(gPlayerStatus));
}
void player_reset_data(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
mem_clear(playerStatus, sizeof(PlayerStatus));
playerStatus->flags = PS_FLAG_HAS_REFLECTION;
reset_player_status();
playerStatus->shadowID = create_shadow_type(SHADOW_VARYING_CIRCLE, playerStatus->pos.x, playerStatus->pos.y,
playerStatus->pos.z);
clear_world_menus();
clear_interact_prompt();
clear_conversation_prompt();
clear_pulse_stone_icon();
clear_ispy_icon();
func_800E5520();
}
b32 is_player_dismounted(void) {
if (gPartnerStatus.partnerActionState == PARTNER_ACTION_USE &&
(gPartnerStatus.actingPartner == PARTNER_WATT
|| gPartnerStatus.actingPartner == PARTNER_BOW
|| gPartnerStatus.actingPartner == PARTNER_SUSHIE
|| gPartnerStatus.actingPartner == PARTNER_PARAKARRY
|| gPartnerStatus.actingPartner == PARTNER_LAKILESTER)) {
return FALSE;
}
return TRUE;
}
s32 get_overriding_player_anim(s32 anim) {
PlayerStatus* playerStatus = &gPlayerStatus;
PartnerStatus* partnerStatus = &gPartnerStatus;
if (playerStatus->actionState == ACTION_STATE_USE_SPINNING_FLOWER
&& anim != ANIM_Mario1_Flail
&& anim != ANIM_Mario1_Jump
) {
return -1;
}
if (partnerStatus->partnerActionState != PARTNER_ACTION_NONE) {
if (partnerStatus->actingPartner == PARTNER_LAKILESTER && anim == ANIM_Mario1_Idle) {
anim = ANIM_MarioW2_RideLaki;
}
if (partnerStatus->partnerActionState != PARTNER_ACTION_NONE
&& partnerStatus->actingPartner == PARTNER_BOW
&& anim != ANIM_Mario1_Crouch
&& anim != ANIM_Mario1_Idle
) {
return -1;
}
}
if (anim == ANIM_Mario1_ThumbsUp && partnerStatus->partnerActionState == PARTNER_ACTION_USE) {
return -1;
}
if (anim == ANIM_MarioW1_Lift || anim == ANIM_Peach2_SpreadArms || anim == ANIM_Mario1_Idle) {
if (!(playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS)) {
if (!is_player_dismounted()) {
return -1;
}
} else if (!(playerStatus->animFlags & PA_FLAG_INVISIBLE)) {
anim = ANIM_Peach2_SpreadArms;
} else {
peach_set_disguise_anim(BasicPeachDisguiseAnims[playerStatus->peachDisguise].hold);
return -1;
}
} else if (playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS) {
if (playerStatus->peachItemHeld != PEACH_BAKING_NONE
&& (anim == ANIM_Peach2_RaiseArms || anim == ANIM_Peach2_Talk || anim == ANIM_Peach2_LowerArms)
) {
anim = ANIM_Peach3_PresentCompleteCake;
}
}
if (anim == ANIM_MarioW2_Collapse) {
exec_ShakeCam1(0, 0, 2);
}
return anim;
}
void suggest_player_anim_allow_backward(AnimID anim) {
PlayerStatus* playerStatus = &gPlayerStatus;
AnimID newAnim = get_overriding_player_anim(anim);
if (newAnim != -1) {
playerStatus->anim = newAnim;
playerStatus->animNotifyValue = 0;
playerStatus->flags &= ~PS_FLAG_FACE_FORWARD;
}
}
void force_player_anim(AnimID anim) {
PlayerStatus* playerStatus = &gPlayerStatus;
playerStatus->anim = anim;
playerStatus->animNotifyValue = 0;
playerStatus->flags &= ~PS_FLAG_FACE_FORWARD;
}
void suggest_player_anim_always_forward(AnimID anim) {
PlayerStatus* playerStatus = &gPlayerStatus;
AnimID newAnim = get_overriding_player_anim(anim);
if (newAnim != -1) {
playerStatus->anim = newAnim;
playerStatus->animNotifyValue = 0;
playerStatus->flags |= PS_FLAG_FACE_FORWARD;
}
}
void update_player_blink(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
s32 outtaSight = FALSE;
u8 phi_v1;
u8* alpha;
if (gPartnerStatus.actingPartner == PARTNER_BOW) {
outtaSight = gPartnerStatus.partnerActionState != PARTNER_ACTION_NONE;
}
if (playerStatus->blinkTimer > 0) {
playerStatus->blinkTimer--;
alpha = &playerStatus->curAlpha;
if (!(gGameStatusPtr->frameCounter & 1)) {
if (outtaSight) {
phi_v1 = 192;
} else {
phi_v1 = 255;
}
} else {
phi_v1 = 96;
}
*alpha = phi_v1;
if (!playerStatus->blinkTimer) {
if (outtaSight) {
playerStatus->curAlpha = 128;
playerStatus->flags |= PS_FLAG_HAZARD_INVINCIBILITY;
} else {
playerStatus->curAlpha = 255;
playerStatus->flags &= ~PS_FLAG_HAZARD_INVINCIBILITY;
}
} else {
playerStatus->flags |= PS_FLAG_HAZARD_INVINCIBILITY;
}
}
}
// dist_to_player2D
f32 get_xz_dist_to_player(f32 x, f32 z) {
PlayerStatus* playerStatus = &gPlayerStatus;
return dist2D(x, z, playerStatus->pos.x, playerStatus->pos.z);
}
void enable_player_shadow(void) {
get_shadow_by_index(gPlayerStatus.shadowID)->flags &= ~ENTITY_FLAG_HIDDEN;
}
void disable_player_shadow(void) {
get_shadow_by_index(gPlayerStatus.shadowID)->flags |= ENTITY_FLAG_HIDDEN;
}
s32 disable_player_static_collisions(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
playerStatus->flags |= PS_FLAG_NO_STATIC_COLLISION;
playerStatus->enableCollisionOverlapsCheck++;
return playerStatus->enableCollisionOverlapsCheck;
}
s32 enable_player_static_collisions(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
playerStatus->enableCollisionOverlapsCheck--;
if (playerStatus->enableCollisionOverlapsCheck == 0) {
playerStatus->flags &= ~PS_FLAG_NO_STATIC_COLLISION;
}
return playerStatus->enableCollisionOverlapsCheck;
}
s32 disable_player_input(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
playerStatus->flags |= PS_FLAG_INPUT_DISABLED;
playerStatus->inputDisabledCount++;
return playerStatus->inputDisabledCount;
}
s32 enable_player_input(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
playerStatus->inputDisabledCount--;
if (playerStatus->inputDisabledCount == 0) {
playerStatus->flags &= ~PS_FLAG_INPUT_DISABLED;
}
return playerStatus->inputDisabledCount;
}
void func_800E01DC(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
if (playerStatus->animFlags & PA_FLAG_INTERACT_PROMPT_AVAILABLE) {
playerStatus->flags |= PS_FLAG_INTERACTED;
}
}
b32 check_player_action_debug(void) {
b32 ret = FALSE;
if (gGameStatusPtr->debugScripts != DEBUG_SCRIPTS_NONE && (gGameStatusPtr->curButtons[0] & BUTTON_R)) {
if (gPartnerStatus.partnerActionState == PARTNER_ACTION_NONE) {
set_action_state(ACTION_STATE_IDLE);
}
ret = TRUE;
}
return ret;
}
void player_render_interact_prompts(void) {
render_conversation_prompt();
render_interact_prompt();
render_pulse_stone_icon();
render_ispy_icon();
}
void check_for_ispy(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
if (gCurrentHiddenPanels.activateISpy && ISpyNotificationCallback == NULL) {
if (!(playerStatus->animFlags &
(PA_FLAG_SPEECH_PROMPT_AVAILABLE | PA_FLAG_INTERACT_PROMPT_AVAILABLE))) {
DMA_COPY_SEGMENT(i_spy);
ISpyNotificationCallback = ispy_notification_setup;
}
}
if (ISpyNotificationCallback != NULL) {
ISpyNotificationCallback();
}
}
void render_ispy_icon(void) {
if ((gPlayerStatusPtr->animFlags & PA_FLAG_ISPY_VISIBLE) && (ISpyNotificationCallback != NULL)) {
appendGfx_ispy_icon();
}
}
void clear_ispy_icon(void) {
ISpyNotificationCallback = NULL;
gPlayerStatusPtr->animFlags &= ~PA_FLAG_ISPY_VISIBLE;
}
void check_for_pulse_stone(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
s32 dx, dy;
if (PulseStoneNotificationCallback == NULL) {
if (gPlayerStatus.animFlags & PA_FLAG_ISPY_VISIBLE) {
return;
}
if (gGameStatusPtr->areaID != AREA_SBK || gGameStatusPtr->isBattle) {
return;
}
dx = abs(gGameStatusPtr->mapID % 7 - 2);
dy = gGameStatusPtr->mapID / 7;
if ((dx + dy) > 5) {
return;
}
if (!(gPlayerStatus.animFlags & (PA_FLAG_USING_PULSE_STONE | PA_FLAG_PULSE_STONE_VISIBLE))) {
return;
}
if (gPlayerStatus.flags & PS_FLAG_PAUSED || gPlayerStatus.inputDisabledCount != 0) {
return;
}
if (!(gPlayerStatus.animFlags & (PA_FLAG_SPEECH_PROMPT_AVAILABLE | PA_FLAG_INTERACT_PROMPT_AVAILABLE))) {
DMA_COPY_SEGMENT(pulse_stone);
PulseStoneNotificationCallback = pulse_stone_notification_setup;
}
}
if (PulseStoneNotificationCallback != NULL) {
PulseStoneNotificationCallback();
}
}
void render_pulse_stone_icon(void) {
if ((gPlayerStatusPtr->animFlags & PA_FLAG_PULSE_STONE_VISIBLE) && (PulseStoneNotificationCallback != NULL)) {
appendGfx_pulse_stone_icon();
}
}
void clear_pulse_stone_icon(void) {
PulseStoneNotificationCallback = NULL;
gPlayerStatusPtr->animFlags &= ~PA_FLAG_PULSE_STONE_VISIBLE;
}
s32 has_valid_conversation_npc(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
Npc* npc = playerStatus->encounteredNPC;
s32 ret = FALSE;
s32 cond;
if (npc != NULL && !(npc->flags & NPC_FLAG_10000000)) {
cond = !(playerStatus->flags & PS_FLAG_INPUT_DISABLED) && (playerStatus->flags & PS_FLAG_HAS_CONVERSATION_NPC);
ret = cond;
}
return ret;
}
void check_for_conversation_prompt(void) {
if (gPlayerStatus.animFlags & PA_FLAG_ISPY_VISIBLE || InteractNotificationCallback || PulseStoneNotificationCallback != NULL) {
return;
}
if (TalkNotificationCallback == NULL) {
if (gPlayerStatus.inputDisabledCount || gPlayerStatus.flags & PS_FLAG_PAUSED) {
return;
}
if (has_valid_conversation_npc()) {
TalkNotificationCallback = NULL;
DMA_COPY_SEGMENT(speech_bubble);
TalkNotificationCallback = interact_speech_setup;
} else {
TalkNotificationCallback = NULL;
return;
}
}
if (TalkNotificationCallback != NULL) {
TalkNotificationCallback();
}
}
void render_conversation_prompt(void) {
if ((gPlayerStatusPtr->animFlags & PA_FLAG_SPEECH_PROMPT_AVAILABLE) && (TalkNotificationCallback != NULL)) {
appendGfx_speech_bubble();
}
}
void clear_conversation_prompt(void) {
TalkNotificationCallback = NULL;
gPlayerStatusPtr->animFlags &= ~PA_FLAG_SPEECH_PROMPT_AVAILABLE;
}
void func_800E06C0(s32 arg0) {
D_8010C950 = (arg0 == 1);
}
s32 func_800E06D8(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
Npc* npc = playerStatus->encounteredNPC;
s32 interactingID = playerStatus->interactingWithID;
s32 currentWall;
if (playerStatus->timeInAir != 0 || playerStatus->inputDisabledCount != 0) {
return FALSE;
}
if (gCollisionStatus.curWall == NO_COLLIDER) {
return FALSE;
}
if (playerStatus->flags & PS_FLAG_HAS_CONVERSATION_NPC
&& !(playerStatus->flags & PS_FLAG_INPUT_DISABLED)
&& npc != NULL
&& npc->flags & NPC_FLAG_10000000
) {
playerStatus->interactingWithID = NO_COLLIDER;
return TRUE;
}
currentWall = gCollisionStatus.curWall;
if (!(currentWall & COLLISION_WITH_ENTITY_BIT)) {
if (!should_collider_allow_interact(currentWall)) {
return FALSE;
}
} else if (!phys_can_player_interact()) {
playerStatus->interactingWithID = NO_COLLIDER;
return FALSE;
} else if (get_entity_type(currentWall) == ENTITY_TYPE_PUSH_BLOCK) {
return FALSE;
}
if (interactingID == currentWall) {
if (playerStatus->flags & PS_FLAG_INTERACTED) {
return FALSE;
}
} else {
playerStatus->flags &= ~PS_FLAG_INTERACTED;
}
playerStatus->interactingWithID = NO_COLLIDER;
return TRUE;
}
static const f32 padding = 0.0f;
void check_for_interactables(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
Npc* npc = gPlayerStatus.encounteredNPC;
s32 phi_s2;
if ((playerStatus->animFlags & PA_FLAG_ISPY_VISIBLE) || TalkNotificationCallback || PulseStoneNotificationCallback != NULL) {
return;
}
if (InteractNotificationCallback == NULL) {
s32 curInteraction = gCollisionStatus.curWall;
if (playerStatus->inputDisabledCount != 0) {
if (gPlayerStatus.interactingWithID != curInteraction) {
gPlayerStatus.interactingWithID = curInteraction;
}
return;
}
if (playerStatus->timeInAir != 0) {
return;
}
if (curInteraction == NO_COLLIDER) {
s32 floor = gCollisionStatus.curFloor;
if (floor > NO_COLLIDER && (floor & COLLISION_WITH_ENTITY_BIT)) {
phi_s2 = 1;
curInteraction = floor;
switch (get_entity_type(floor)) {
case ENTITY_TYPE_PADLOCK:
case ENTITY_TYPE_PADLOCK_RED_FRAME:
case ENTITY_TYPE_PADLOCK_RED_FACE:
case ENTITY_TYPE_PADLOCK_BLUE_FACE:
case ENTITY_TYPE_PUSH_BLOCK:
case ENTITY_TYPE_CHEST:
case ENTITY_TYPE_SIGNPOST:
curInteraction = NO_COLLIDER;
break;
}
} else if (
(!(playerStatus->flags & PS_FLAG_INPUT_DISABLED))
&& (playerStatus->flags & PS_FLAG_HAS_CONVERSATION_NPC)
&& (npc != NULL)
&& (npc->flags & NPC_FLAG_10000000)
) {
curInteraction = npc->npcID | COLLISION_WITH_NPC_BIT;
if (playerStatus->interactingWithID == curInteraction) {
return;
}
phi_s2 = 0;
} else {
playerStatus->interactingWithID = NO_COLLIDER;
playerStatus->flags &= ~PS_FLAG_INTERACTED;
return;
}
} else {
if (!(curInteraction & COLLISION_WITH_ENTITY_BIT)) {
phi_s2 = 0;
if (!(curInteraction & COLLISION_WITH_NPC_BIT)) {
if (!should_collider_allow_interact(curInteraction)) {
playerStatus->interactingWithID = NO_COLLIDER;
playerStatus->flags &= ~PS_FLAG_INTERACTED;
return;
}
}
} else {
if (!phys_can_player_interact()) {
phi_s2 = 1;
playerStatus->interactingWithID = NO_COLLIDER;
playerStatus->flags &= ~PS_FLAG_INTERACTED;
return;
}
phi_s2 = 1;
}
}
if (playerStatus->interactingWithID == curInteraction) {
if ((playerStatus->flags & PS_FLAG_INTERACTED)) {
return;
}
} else {
playerStatus->flags &= ~PS_FLAG_INTERACTED;
}
playerStatus->interactingWithID = curInteraction;
if ((phi_s2 == 0) || curInteraction > NO_COLLIDER && get_entity_by_index(curInteraction)->flags & ENTITY_FLAG_SHOWS_INSPECT_PROMPT) {
if (playerStatus->actionState == ACTION_STATE_IDLE || playerStatus->actionState == ACTION_STATE_WALK || playerStatus->actionState == ACTION_STATE_RUN) {
playerStatus->animFlags |= PA_FLAG_INTERACT_PROMPT_AVAILABLE;
func_800EF3D4(2);
}
}
}
if (!(playerStatus->animFlags & PA_FLAG_INTERACT_PROMPT_AVAILABLE)) {
func_800EF3D4(0);
partner_reset_tether_distance();
return;
}
if (InteractNotificationCallback == NULL) {
DMA_COPY_SEGMENT(inspect_icon);
InteractNotificationCallback = interact_inspect_setup;
}
if (InteractNotificationCallback != NULL) {
InteractNotificationCallback();
}
}
void appendGfx_interact_prompt(void);
void render_interact_prompt(void) {
if ((gPlayerStatusPtr->animFlags & PA_FLAG_INTERACT_PROMPT_AVAILABLE) && (InteractNotificationCallback != NULL)) {
appendGfx_interact_prompt();
}
}
void clear_interact_prompt(void) {
InteractNotificationCallback = NULL;
gPlayerStatusPtr->animFlags &= ~PA_FLAG_INTERACT_PROMPT_AVAILABLE;
}
void update_partner_timers(void) {
PlayerData* playerData = &gPlayerData;
if (!gGameStatusPtr->isBattle) {
s32 i;
for (i = 1; i < ARRAY_COUNT(playerData->partnerUnlockedTime); i++) {
if (playerData->partners[i].enabled) {
playerData->partnerUnlockedTime[i]++;
}
}
}
}
void player_update_sprite(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
f32 cameraYaw = gCameras[gCurrentCameraID].curYaw;
f32 camRelativeYaw = get_clamped_angle_diff(cameraYaw, playerStatus->curYaw);
s32 trueAnim;
s32 sprIndex;
f32 angle;
s32 direction;
f32 timescale;
D_800F7B48 = 0.0f;
if (camRelativeYaw < -5.0f && camRelativeYaw > -175.0f) {
camRelativeYaw = 0.0f;
direction = 0;
} else if (camRelativeYaw > 5.0f && camRelativeYaw < 175.0f) {
camRelativeYaw = 180.0f;
direction = 1;
} else {
// direction is close to flipping, use saved value
camRelativeYaw = PrevPlayerCamRelativeYaw;
direction = 2;
}
// detect direction change
if (PrevPlayerDirection != direction && direction != 2) {
PrevPlayerDirection = direction;
playerStatus->flipYaw[gCurrentCameraID] = (direction != 0) ? 180.0f : -180.0f;
if (fabsf(get_clamped_angle_diff(cameraYaw, playerStatus->curYaw)) >= 90.0f) {
playerStatus->flipYaw[gCurrentCameraID] = -playerStatus->flipYaw[gCurrentCameraID];
}
}
// handle sprite 'flipping' when changing direction
angle = playerStatus->flipYaw[gCurrentCameraID];
if (angle != 0.0f) {
if (angle < 0.0f) {
angle += 28.0f;
if (angle > 0.0f) {
angle = 0.0f;
}
}
if (angle > 0.0f) {
angle -= 28.0f;
if (angle < 0.0f) {
angle = 0.0f;
}
}
}
if (playerStatus->flags & PS_FLAG_NO_FLIPPING) {
angle = 0.0f;
}
playerStatus->flipYaw[gCurrentCameraID] = angle;
PrevPlayerCamRelativeYaw = angle = clamp_angle(camRelativeYaw);
angle = clamp_angle(playerStatus->flipYaw[gCurrentCameraID] + angle);
if (playerStatus->curSpeed == 0.0f) {
D_800F7B48 = 0.0f;
}
trueAnim = playerStatus->anim;
if (playerStatus->flags & PS_FLAG_SPINNING) {
playerStatus->trueAnimation = trueAnim;
} else {
sprIndex = (trueAnim >> 0x10) & 0xFF;
if (playerStatus->actionState != ACTION_STATE_TORNADO_JUMP && !(playerStatus->flags & PS_FLAG_ROTATION_LOCKED)) {
playerStatus->spriteFacingAngle = angle + D_800F7B48;
trueAnim = playerStatus->anim;
if (!(playerStatus->flags & PS_FLAG_FACE_FORWARD)
&& (sprIndex == SPR_Mario1 || sprIndex == SPR_MarioW1 || sprIndex == SPR_Peach1)
&& fabsf(get_clamped_angle_diff(cameraYaw, playerStatus->curYaw)) < 60.0f
) {
trueAnim = get_player_back_anim(trueAnim);
}
playerStatus->trueAnimation = trueAnim;
playerStatus->curYaw = playerStatus->targetYaw;
} else {
trueAnim = playerStatus->anim;
if (!(playerStatus->flags & PS_FLAG_FACE_FORWARD)
&& (sprIndex == SPR_Mario1 || sprIndex == SPR_MarioW1 || sprIndex == SPR_Peach1)
&& playerStatus->spriteFacingAngle < 350.0f && playerStatus->spriteFacingAngle > 190.0f
) {
trueAnim = get_player_back_anim(trueAnim);
}
playerStatus->trueAnimation = trueAnim;
}
}
timescale = 1.0f;
if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) {
timescale = 0.5f;
}
if (playerStatus->flags & PS_FLAG_TIME_STOPPED) {
timescale = 0.0f;
}
playerStatus->animNotifyValue = spr_update_player_sprite(PLAYER_SPRITE_MAIN, playerStatus->trueAnimation, timescale);
playerStatus->flags |= PS_FLAG_SPRITE_REDRAW;
}
s32 get_player_back_anim(s32 anim) {
s32 sprIndex = (anim >> 16) & 0xff;
s32 outAnim = 0;
if (sprIndex != SPR_Mario1) {
if (sprIndex != SPR_MarioW1 && sprIndex != SPR_Peach1) {
return anim;
}
if (sprIndex == SPR_Mario1) {
if (anim > ANIM_Mario1_SpinFall) {
return anim;
}
} else if (sprIndex == SPR_MarioW1) {
if (anim == ANIM_MarioW1_Lift) {
outAnim = ANIM_MarioW1_Lift_Back;
} else if (anim == ANIM_MarioW1_Toss) {
outAnim = ANIM_MarioW1_Toss_Back;
} else if (anim == ANIM_MarioW1_Smash1_Miss) {
outAnim = ANIM_MarioW1_Smash1_Miss_Back;
} else if (anim == ANIM_MarioW1_Smash1_Hit) {
outAnim = ANIM_MarioW1_Smash1_Hit_Back;
} else if (anim == ANIM_MarioW1_Smash2_Miss) {
outAnim = ANIM_MarioW1_Smash2_Miss_Back;
} else if (anim == ANIM_MarioW1_Smash2_Hit) {
outAnim = ANIM_MarioW1_Smash2_Hit_Back;
} else if (anim == ANIM_MarioW1_Smash3_Miss) {
outAnim = ANIM_MarioW1_Smash3_Miss_Back;
} else if (anim == ANIM_MarioW1_Smash3_Hit) {
outAnim = ANIM_MarioW1_Smash3_Hit_Back;
}
} else if (sprIndex == SPR_Peach1) {
if (anim > ANIM_Peach1_StepDown) {
outAnim = anim + 1;
}
}
} else if (anim > ANIM_Mario1_SpinFall) {
return anim;
}
if (outAnim != 0) {
return outAnim;
} else {
return anim | SPRITE_ID_BACK_FACING;
}
}
void render_player(void) {
if (gGameStatusPtr->debugScripts == DEBUG_SCRIPTS_NONE) {
render_player_model();
}
}
void render_player_model(void) {
RenderTask task;
RenderTask* rtPtr = &task;
PlayerStatus* playerStatus = &gPlayerStatus;
s32 x, y, z;
s8 renderModeTemp;
void (*appendGfx)(void*);
if (playerStatus->flags & PS_FLAG_SPRITE_REDRAW) {
playerStatus->flags &= ~PS_FLAG_SPRITE_REDRAW;
get_screen_coords(gCurrentCamID, playerStatus->pos.x, playerStatus->pos.y,
playerStatus->pos.z, &x, &y, &z);
if (!(playerStatus->flags & PS_FLAG_SPINNING)) {
if (playerStatus->curAlpha != playerStatus->prevAlpha) {
if (playerStatus->curAlpha < 254) {
if (!(playerStatus->animFlags & PA_FLAG_MAP_HAS_SWITCH)) {
renderModeTemp = RENDER_MODE_SURFACE_XLU_LAYER1;
} else {
renderModeTemp = RENDER_MODE_SURFACE_XLU_LAYER2;
}
playerStatus->renderMode = renderModeTemp;
set_player_imgfx_comp(PLAYER_SPRITE_MAIN, -1, IMGFX_SET_ALPHA, 0, 0, 0, playerStatus->curAlpha, 0);
} else {
playerStatus->renderMode = RENDER_MODE_ALPHATEST;
set_player_imgfx_comp(PLAYER_SPRITE_MAIN, -1, IMGFX_CLEAR, 0, 0, 0, 0, 0);
}
}
playerStatus->prevAlpha = playerStatus->curAlpha;
} else {
playerStatus->renderMode = RENDER_MODE_SURFACE_XLU_LAYER1;
playerStatus->prevAlpha = 0;
}
if (!(playerStatus->animFlags & PA_FLAG_INVISIBLE)) {
rtPtr->appendGfxArg = playerStatus;
rtPtr->dist = -z;
rtPtr->renderMode = playerStatus->renderMode;
if (!(playerStatus->flags & PS_FLAG_SPINNING)) {
appendGfx = appendGfx_player;
} else {
appendGfx = appendGfx_player_spin;
}
rtPtr->appendGfx = appendGfx;
queue_render_task(rtPtr);
}
func_800F0C9C();
}
}
void appendGfx_player(void* data) {
PlayerStatus* playerStatus = &gPlayerStatus;
Matrix4f sp20, sp60, spA0, spE0;
f32 temp_f0 = -gCameras[gCurrentCamID].curYaw;
s32 spriteIdx;
if (playerStatus->actionState == ACTION_STATE_SLIDING) {
guScaleF(spE0, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D);
guRotateF(sp20, temp_f0, 0.0f, 1.0f, 0.0f);
guMtxCatF(spE0, sp20, sp20);
guRotateF(spA0, playerStatus->spriteFacingAngle, 0.0f, 1.0f, 0.0f);
guMtxCatF(sp20, spA0, sp20);
guTranslateF(sp60, playerStatus->pos.x, playerStatus->pos.y - 1.0f, playerStatus->pos.z);
guMtxCatF(sp20, sp60, sp20);
spr_draw_player_sprite(PLAYER_SPRITE_MAIN, 0, 0, 0, sp20);
} else {
guRotateF(spA0, temp_f0, 0.0f, -1.0f, 0.0f);
guRotateF(sp20, clamp_angle(playerStatus->pitch), 0.0f, 0.0f, 1.0f);
guMtxCatF(spA0, sp20, sp20);
guTranslateF(sp60, 0.0f, -playerStatus->colliderHeight * 0.5f, 0.0f);
guMtxCatF(sp60, sp20, sp20);
guRotateF(spA0, temp_f0, 0.0f, 1.0f, 0.0f);
guMtxCatF(sp20, spA0, sp20);
guRotateF(spA0, playerStatus->spriteFacingAngle, 0.0f, 1.0f, 0.0f);
guMtxCatF(sp20, spA0, sp20);
guTranslateF(sp60, 0.0f, playerStatus->colliderHeight * 0.5f, 0.0f);
guMtxCatF(sp20, sp60, sp20);
guScaleF(spE0, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D);
guMtxCatF(sp20, spE0, sp20);
guTranslateF(sp60, playerStatus->pos.x, playerStatus->pos.y, playerStatus->pos.z);
guMtxCatF(sp20, sp60, sp20);
if (playerStatus->animFlags & PA_FLAG_SHIVERING) {
playerStatus->animFlags = playerStatus->animFlags & ~PA_FLAG_SHIVERING;
playerStatus->shiverTime = 22;
set_player_imgfx_comp(PLAYER_SPRITE_MAIN, -1, IMGFX_CLEAR, 0, 0, 0, 0, 0);
set_player_imgfx_all(playerStatus->anim, IMGFX_SET_ANIM, IMGFX_ANIM_SHIVER, 1, 1, 0, 0);
}
if (playerStatus->shiverTime != 0) {
playerStatus->shiverTime--;
if (playerStatus->shiverTime == 0) {
set_player_imgfx_comp(PLAYER_SPRITE_MAIN, -1, IMGFX_CLEAR, 0, 0, 0, 0, 0);
}
}
if (playerStatus->spriteFacingAngle >= 90.0f && playerStatus->spriteFacingAngle < 270.0f) {
spriteIdx = PLAYER_SPRITE_MAIN | DRAW_SPRITE_UPSIDE_DOWN;
} else {
spriteIdx = PLAYER_SPRITE_MAIN;
}
spr_draw_player_sprite(spriteIdx, 0, 0, 0, sp20);
}
D_800F7B4C++;
if (D_800F7B4C >= 3) {
D_800F7B4C = 0;
}
}
/// Only used when speedy spinning.
void appendGfx_player_spin(void* data) {
PlayerStatus* playerStatus = &gPlayerStatus;
Matrix4f mtx;
Matrix4f translation;
Matrix4f rotation;
Matrix4f scale;
f32 yaw;
f32 blurAngle;
s32 tint;
f32 px, py, pz;
s32 x, y, z;
s32 i;
s32 spriteIdx;
for (i = 0; i < 2; i++) {
yaw = -gCameras[gCurrentCamID].curYaw;
if (i == 0) {
if (playerStatus->spriteFacingAngle > 90.0f && playerStatus->spriteFacingAngle <= 180.0f) {
yaw = 180.0f - playerStatus->spriteFacingAngle;
} else {
if (playerStatus->spriteFacingAngle > 180.0f && playerStatus->spriteFacingAngle <= 270.0f) {
yaw = playerStatus->spriteFacingAngle - 180.0f;
} else if (playerStatus->spriteFacingAngle > 270.0f && playerStatus->spriteFacingAngle <= 360.0f) {
yaw = 360.0f - playerStatus->spriteFacingAngle;
} else {
yaw = playerStatus->spriteFacingAngle;
}
}
tint = yaw / 25.0f;
tint = 255 - (tint * 60);
if (tint < 100) {
tint = 100;
}
set_player_imgfx_all(PLAYER_SPRITE_MAIN, IMGFX_SET_COLOR, tint, tint, tint, 255, 0);
guRotateF(rotation, yaw, 0.0f, -1.0f, 0.0f);
guRotateF(mtx, clamp_angle(playerStatus->pitch), 0.0f, 0.0f, 1.0f);
guMtxCatF(rotation, mtx, mtx);
px = playerStatus->pos.x;
py = playerStatus->pos.y;
pz = playerStatus->pos.z;
} else {
blurAngle = phys_get_spin_history(i, &x, &y, &z);
if (y == 0x80000000) {
py = playerStatus->pos.y;
} else {
py = y;
}
px = playerStatus->pos.x;
pz = playerStatus->pos.z;
set_player_imgfx_comp(PLAYER_SPRITE_MAIN, -1, IMGFX_SET_ALPHA, 0, 0, 0, 64, 0);
guRotateF(mtx, yaw, 0.0f, -1.0f, 0.0f);
guRotateF(rotation, yaw, 0.0f, -1.0f, 0.0f);
guRotateF(mtx, blurAngle, 0.0f, 1.0f, 0.0f);
guMtxCatF(rotation, mtx, mtx);
}
guTranslateF(translation, 0.0f, -playerStatus->colliderHeight * 0.5f, 0.0f);
guMtxCatF(translation, mtx, mtx);
guRotateF(rotation, yaw, 0.0f, 1.0f, 0.0f);
guMtxCatF(mtx, rotation, mtx);
guRotateF(rotation, playerStatus->spriteFacingAngle, 0.0f, 1.0f, 0.0f);
guMtxCatF(mtx, rotation, mtx);
guTranslateF(translation, 0.0f, playerStatus->colliderHeight * 0.5f, 0.0f);
guMtxCatF(mtx, translation, mtx);
guScaleF(scale, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D, SPRITE_WORLD_SCALE_D);
guMtxCatF(mtx, scale, mtx);
guTranslateF(translation, px, py, pz);
guMtxCatF(mtx, translation, mtx);
if (playerStatus->spriteFacingAngle >= 90.0f && playerStatus->spriteFacingAngle < 270.0f) {
spriteIdx = PLAYER_SPRITE_MAIN | DRAW_SPRITE_UPSIDE_DOWN;
} else {
spriteIdx = PLAYER_SPRITE_MAIN;
}
spr_draw_player_sprite(spriteIdx, 0, 0, 0, mtx);
}
}
void update_player_shadow(void) {
PlayerStatus* playerStatus = &gPlayerStatus;
Shadow* shadow = get_shadow_by_index(gPlayerStatusPtr->shadowID);
Camera* camera = &gCameras[gCurrentCameraID];
f32 shadowScale = 0.0f;
f32 yawTemp = 0.0f;
f32 hitDirX, hitDirZ;
f32 hitRx, hitRz;
f32 x, y, z;
f32 playerX, playerZ;
s32 dist;
f32 raycastYaw;
if (playerStatus->spriteFacingAngle >= 90.0f && playerStatus->spriteFacingAngle < 270.0f) {
yawTemp = 180.0f;
}
raycastYaw = (yawTemp - 90.0f) + gCameras[gCurrentCameraID].curYaw;
shadow->pos.x = playerX = playerStatus->pos.x;
shadow->pos.z = playerZ = playerStatus->pos.z;
x = playerX;
y = playerStatus->pos.y + (playerStatus->colliderHeight / 3.5f);
z = playerZ;
shadowScale = 1024.0f;
gCollisionStatus.floorBelow = player_raycast_below(raycastYaw, playerStatus->colliderDiameter, &x, &y, &z,
&shadowScale, &hitRx, &hitRz, &hitDirX, &hitDirZ);
shadow->rot.x = hitRx;
shadow->rot.z = hitRz;
shadow->rot.y = clamp_angle(-camera->curYaw);
hitRx += 180.0f;
hitRz += 180.0f;
if (hitRx != 0.0f || hitRz != 0.0f) {
s32 dist = dist2D(x, z, playerStatus->pos.x, playerStatus->pos.z);
f32 tan = atan2(playerStatus->pos.x, playerStatus->pos.z, x, z);
s32 angleTemp = clamp_angle((-90.0f - tan) + get_player_normal_yaw());
if (gGameStatusPtr->playerGroundTraceNormal.y != 0.0f) {
y -= sqrtf(SQ(gGameStatusPtr->playerGroundTraceNormal.x) + SQ(gGameStatusPtr->playerGroundTraceNormal.z)) /
gGameStatusPtr->playerGroundTraceNormal.y * dist * sin_deg(angleTemp);
}
}
shadow->pos.y = y;
shadow->alpha = (f64)playerStatus->curAlpha / 2;
if (!(gGameStatusPtr->peachFlags & PEACH_FLAG_IS_PEACH)) {
set_standard_shadow_scale(shadow, shadowScale);
} else {
set_peach_shadow_scale(shadow, shadowScale);
}
}