You've already forked Microtransactions64
mirror of
https://github.com/Print-and-Panic/Microtransactions64.git
synced 2026-01-21 10:17:19 -08:00
Added water surface type patch
This commit is contained in:
@@ -110,12 +110,12 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode,
|
||||
|
||||
// Determine if checking for the camera or not.
|
||||
if (gCheckingSurfaceCollisionsForCamera) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Ignore camera only surfaces.
|
||||
if (surf->type == SURFACE_CAMERA_BOUNDARY) {
|
||||
if (surf->type == SURFACE_CAMERA_BOUNDARY || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32
|
||||
|
||||
// Determine if checking for the camera or not.
|
||||
if (gCheckingSurfaceCollisionsForCamera != 0) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Ignore camera only surfaces.
|
||||
else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
|
||||
else if (surf->type == SURFACE_CAMERA_BOUNDARY || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
||||
|
||||
// Determine if we are checking for the camera or not.
|
||||
if (gCheckingSurfaceCollisionsForCamera != 0) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
|
||||
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -468,6 +468,77 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
||||
return floor;
|
||||
}
|
||||
|
||||
static s16 check_within_triangle_bounds(s32 x, s32 z, struct Surface *surf) {
|
||||
register s32 x1, z1, x2, z2, x3, z3;
|
||||
x1 = surf->vertex1[0];
|
||||
z1 = surf->vertex1[2];
|
||||
x2 = surf->vertex2[0];
|
||||
z2 = surf->vertex2[2];
|
||||
|
||||
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) return FALSE;
|
||||
|
||||
x3 = surf->vertex3[0];
|
||||
z3 = surf->vertex3[2];
|
||||
|
||||
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) return FALSE;
|
||||
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) < 0) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Find the height of the floor at a given location
|
||||
static f32 get_floor_height_at_location(s32 x, s32 z, struct Surface *surf) {
|
||||
return -(x * surf->normal.x + surf->normal.z * z + surf->originOffset) / surf->normal.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through the list of water floors and find the first water floor under a given point.
|
||||
*/
|
||||
struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z,
|
||||
f32 *pheight) {
|
||||
register struct Surface *surf;
|
||||
struct Surface *floor = NULL;
|
||||
struct SurfaceNode *topSurfaceNode = surfaceNode;
|
||||
struct SurfaceNode *bottomSurfaceNode = surfaceNode;
|
||||
f32 height = FLOOR_LOWER_LIMIT;
|
||||
f32 bottomHeight = FLOOR_LOWER_LIMIT;
|
||||
|
||||
// Iterate through the list of water floors until there are no more water floors.
|
||||
while (bottomSurfaceNode != NULL) {
|
||||
f32 curBottomHeight = FLOOR_LOWER_LIMIT;
|
||||
surf = bottomSurfaceNode->surface;
|
||||
bottomSurfaceNode = bottomSurfaceNode->next;
|
||||
|
||||
if (surf->type != SURFACE_NEW_WATER_BOTTOM || !check_within_triangle_bounds(x, z, surf)) continue;
|
||||
|
||||
curBottomHeight = get_floor_height_at_location(x, z, surf);
|
||||
|
||||
if (curBottomHeight < y - 78.0f) continue;
|
||||
if (curBottomHeight >= y - 78.0f) bottomHeight = curBottomHeight;
|
||||
}
|
||||
|
||||
// Iterate through the list of water tops until there are no more water tops.
|
||||
while (topSurfaceNode != NULL) {
|
||||
f32 curHeight = FLOOR_LOWER_LIMIT;
|
||||
surf = topSurfaceNode->surface;
|
||||
topSurfaceNode = topSurfaceNode->next;
|
||||
|
||||
if (surf->type == SURFACE_NEW_WATER_BOTTOM || !check_within_triangle_bounds(x, z, surf)) continue;
|
||||
|
||||
curHeight = get_floor_height_at_location(x, z, surf);
|
||||
|
||||
if (bottomHeight != FLOOR_LOWER_LIMIT && curHeight > bottomHeight) continue;
|
||||
|
||||
if (curHeight > height) {
|
||||
height = curHeight;
|
||||
*pheight = curHeight;
|
||||
floor = surf;
|
||||
}
|
||||
}
|
||||
|
||||
return floor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the height of the highest floor below a point.
|
||||
*/
|
||||
@@ -579,10 +650,93 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the highest water floor under a given position and return the height.
|
||||
*/
|
||||
f32 find_water_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
|
||||
s16 cellZ, cellX;
|
||||
|
||||
struct Surface *floor = NULL;
|
||||
struct SurfaceNode *surfaceList;
|
||||
|
||||
f32 height = FLOOR_LOWER_LIMIT;
|
||||
|
||||
s16 x = (s16) xPos;
|
||||
s16 y = (s16) yPos;
|
||||
s16 z = (s16) zPos;
|
||||
|
||||
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
|
||||
return height;
|
||||
}
|
||||
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
|
||||
return height;
|
||||
}
|
||||
|
||||
// Each level is split into cells to limit load, find the appropriate cell.
|
||||
cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX;
|
||||
cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX;
|
||||
|
||||
// Check for surfaces that are a part of level geometry.
|
||||
surfaceList = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next;
|
||||
floor = find_water_floor_from_list(surfaceList, x, y, z, &height);
|
||||
|
||||
if (floor == NULL) {
|
||||
height = FLOOR_LOWER_LIMIT;
|
||||
} else {
|
||||
*pfloor = floor;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* ENVIRONMENTAL BOXES *
|
||||
**************************************************/
|
||||
|
||||
/**
|
||||
* Finds the height of water at a given location.
|
||||
*/
|
||||
f32 find_water_level_and_floor(f32 x, f32 z, struct Surface **pfloor) {
|
||||
s32 i;
|
||||
s32 numRegions;
|
||||
s16 val;
|
||||
f32 loX, hiX, loZ, hiZ;
|
||||
f32 waterLevel = FLOOR_LOWER_LIMIT;
|
||||
s16 *p = gEnvironmentRegions;
|
||||
struct Surface *floor = NULL;
|
||||
|
||||
if (gCheckingSurfaceCollisionsForCamera) {
|
||||
waterLevel = find_water_floor(x, gLakituState.pos[1], z, &floor);
|
||||
} else {
|
||||
waterLevel = find_water_floor(x, gMarioState->pos[1], z, &floor);
|
||||
}
|
||||
|
||||
if (p != NULL && waterLevel == FLOOR_LOWER_LIMIT) {
|
||||
numRegions = *p++;
|
||||
|
||||
for (i = 0; i < numRegions; i++) {
|
||||
val = *p++;
|
||||
loX = *p++;
|
||||
loZ = *p++;
|
||||
hiX = *p++;
|
||||
hiZ = *p++;
|
||||
|
||||
// If the location is within a water box and it is a water box.
|
||||
// Water is less than 50 val only, while above is gas and such.
|
||||
if (loX < x && x < hiX && loZ < z && z < hiZ && val < 50) {
|
||||
// Set the water height. Since this breaks, only return the first height.
|
||||
waterLevel = *p;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
} else {
|
||||
*pfloor = floor;
|
||||
}
|
||||
|
||||
return waterLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the height of water at a given location.
|
||||
*/
|
||||
@@ -593,8 +747,15 @@ f32 find_water_level(f32 x, f32 z) {
|
||||
f32 loX, hiX, loZ, hiZ;
|
||||
f32 waterLevel = FLOOR_LOWER_LIMIT;
|
||||
s16 *p = gEnvironmentRegions;
|
||||
struct Surface *floor;
|
||||
|
||||
if (p != NULL) {
|
||||
if (gCheckingSurfaceCollisionsForCamera) {
|
||||
waterLevel = find_water_floor(x, gLakituState.pos[1], z, &floor);
|
||||
} else {
|
||||
waterLevel = find_water_floor(x, gMarioState->pos[1], z, &floor);
|
||||
}
|
||||
|
||||
if (p != NULL && waterLevel == FLOOR_LOWER_LIMIT) {
|
||||
numRegions = *p++;
|
||||
|
||||
for (i = 0; i < numRegions; i++) {
|
||||
|
||||
@@ -40,6 +40,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil);
|
||||
f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo);
|
||||
f32 find_floor_height(f32 x, f32 y, f32 z);
|
||||
f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor);
|
||||
f32 find_water_level_and_floor(f32 x, f32 z, struct Surface **pfloor);
|
||||
f32 find_water_level(f32 x, f32 z);
|
||||
f32 find_poison_gas_level(f32 x, f32 z);
|
||||
void debug_surface_list_info(f32 xPos, f32 zPos);
|
||||
|
||||
@@ -93,6 +93,7 @@ static void clear_spatial_partition(SpatialPartitionCell *cells) {
|
||||
(*cells)[SPATIAL_PARTITION_FLOORS].next = NULL;
|
||||
(*cells)[SPATIAL_PARTITION_CEILS].next = NULL;
|
||||
(*cells)[SPATIAL_PARTITION_WALLS].next = NULL;
|
||||
(*cells)[SPATIAL_PARTITION_WATER].next = NULL;
|
||||
|
||||
cells++;
|
||||
}
|
||||
@@ -119,9 +120,10 @@ static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surfac
|
||||
s16 priority;
|
||||
s16 sortDir;
|
||||
s16 listIndex;
|
||||
s16 isWater = surface->type == SURFACE_NEW_WATER || surface->type == SURFACE_NEW_WATER_BOTTOM;
|
||||
|
||||
if (surface->normal.y > 0.01) {
|
||||
listIndex = SPATIAL_PARTITION_FLOORS;
|
||||
listIndex = isWater ? SPATIAL_PARTITION_WATER : SPATIAL_PARTITION_FLOORS;
|
||||
sortDir = 1; // highest to lowest, then insertion order
|
||||
} else if (surface->normal.y < -0.01) {
|
||||
listIndex = SPATIAL_PARTITION_CEILS;
|
||||
|
||||
@@ -21,10 +21,11 @@ enum
|
||||
{
|
||||
SPATIAL_PARTITION_FLOORS,
|
||||
SPATIAL_PARTITION_CEILS,
|
||||
SPATIAL_PARTITION_WALLS
|
||||
SPATIAL_PARTITION_WALLS,
|
||||
SPATIAL_PARTITION_WATER
|
||||
};
|
||||
|
||||
typedef struct SurfaceNode SpatialPartitionCell[3];
|
||||
typedef struct SurfaceNode SpatialPartitionCell[4];
|
||||
|
||||
// Needed for bs bss reordering memes.
|
||||
extern s32 unused8038BE90;
|
||||
|
||||
@@ -1167,6 +1167,24 @@ s32 transition_submerged_to_walking(struct MarioState *m) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transitions Mario from a submerged action to an airborne action.
|
||||
* You may want to change these actions to fit your hack
|
||||
*/
|
||||
s32 transition_submerged_to_airborne(struct MarioState *m) {
|
||||
set_camera_mode(m->area->camera, m->area->camera->defMode, 1);
|
||||
|
||||
vec3s_set(m->angleVel, 0, 0, 0);
|
||||
|
||||
if (m->heldObj == NULL) {
|
||||
if (m->input & INPUT_A_DOWN) return set_mario_action(m, ACT_DIVE, 0);
|
||||
else return set_mario_action(m, ACT_FREEFALL, 0);
|
||||
} else {
|
||||
if (m->input & INPUT_A_DOWN) return set_mario_action(m, ACT_HOLD_JUMP, 0);
|
||||
else return set_mario_action(m, ACT_HOLD_FREEFALL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the transition function typically for entering a submerged action for a
|
||||
* non-submerged action. This also applies the water surface camera preset.
|
||||
@@ -1175,7 +1193,8 @@ s32 set_water_plunge_action(struct MarioState *m) {
|
||||
m->forwardVel = m->forwardVel / 4.0f;
|
||||
m->vel[1] = m->vel[1] / 2.0f;
|
||||
|
||||
m->pos[1] = m->waterLevel - 100;
|
||||
// !BUG: Causes waterbox upwarp
|
||||
// m->pos[1] = m->waterLevel - 100;
|
||||
|
||||
m->faceAngle[2] = 0;
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ s32 hurt_and_set_mario_action(struct MarioState *m, u32 action, u32 actionArg, s
|
||||
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 transition_submerged_to_airborne(struct MarioState *m);
|
||||
s32 set_water_plunge_action(struct MarioState *m);
|
||||
s32 execute_mario_action(UNUSED struct Object *o);
|
||||
void init_mario(void);
|
||||
|
||||
@@ -1497,7 +1497,8 @@ static s32 act_hold_metal_water_fall_land(struct MarioState *m) {
|
||||
static s32 check_common_submerged_cancels(struct MarioState *m) {
|
||||
if (m->pos[1] > m->waterLevel - 80) {
|
||||
if (m->waterLevel - 80 > m->floorHeight) {
|
||||
m->pos[1] = m->waterLevel - 80;
|
||||
// m->pos[1] = m->waterLevel - 80; //! BUG: Downwarp swimming out of waterfalls
|
||||
return transition_submerged_to_airborne(m);
|
||||
} else {
|
||||
//! If you press B to throw the shell, there is a ~5 frame window
|
||||
// where your held object is the shell, but you are not in the
|
||||
|
||||
@@ -696,7 +696,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
|
||||
gMatStackFixed[gMatStackIndex] = mtx;
|
||||
if (gShadowAboveWaterOrLava == TRUE) {
|
||||
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4);
|
||||
} else if (gMarioOnIceOrCarpet == 1) {
|
||||
} else if (gMarioOnIceOrCarpet == 1 || gShadowAboveCustomWater == 1) {
|
||||
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5);
|
||||
} else {
|
||||
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6);
|
||||
|
||||
@@ -102,6 +102,7 @@ shadowRectangle rectangles[2] = {
|
||||
|
||||
// See shadow.h for documentation.
|
||||
s8 gShadowAboveWaterOrLava;
|
||||
s8 gShadowAboveCustomWater;
|
||||
s8 gMarioOnIceOrCarpet;
|
||||
s8 sMarioOnFlyingCarpet;
|
||||
s16 sSurfaceTypeBelowShadow;
|
||||
@@ -177,14 +178,15 @@ u8 dim_shadow_with_distance(u8 solidity, f32 distFromFloor) {
|
||||
* Return the water level below a shadow, or 0 if the water level is below
|
||||
* -10,000.
|
||||
*/
|
||||
f32 get_water_level_below_shadow(struct Shadow *s) {
|
||||
f32 waterLevel = find_water_level(s->parentX, s->parentZ);
|
||||
f32 get_water_level_below_shadow(struct Shadow *s, struct Surface **waterFloor) {
|
||||
f32 waterLevel = find_water_level_and_floor(s->parentX, s->parentZ, waterFloor);
|
||||
if (waterLevel < FLOOR_LOWER_LIMIT_SHADOW) {
|
||||
return 0;
|
||||
} else if (s->parentY >= waterLevel && s->floorHeight <= waterLevel) {
|
||||
gShadowAboveWaterOrLava = TRUE;
|
||||
return waterLevel;
|
||||
}
|
||||
return waterLevel;
|
||||
//! @bug Missing return statement. This compiles to return `waterLevel`
|
||||
//! incidentally.
|
||||
}
|
||||
@@ -201,6 +203,7 @@ s8 init_shadow(struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale,
|
||||
f32 waterLevel;
|
||||
f32 floorSteepness;
|
||||
struct FloorGeometry *floorGeometry;
|
||||
struct Surface *waterFloor = NULL;
|
||||
|
||||
s->parentX = xPos;
|
||||
s->parentY = yPos;
|
||||
@@ -208,18 +211,33 @@ s8 init_shadow(struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale,
|
||||
|
||||
s->floorHeight = find_floor_height_and_data(s->parentX, s->parentY, s->parentZ, &floorGeometry);
|
||||
|
||||
if (gEnvironmentRegions != 0) {
|
||||
waterLevel = get_water_level_below_shadow(s);
|
||||
}
|
||||
waterLevel = get_water_level_below_shadow(s, &waterFloor);
|
||||
|
||||
// if (gEnvironmentRegions != 0) {
|
||||
// waterLevel = get_water_level_below_shadow(s);
|
||||
// }
|
||||
|
||||
if (gShadowAboveWaterOrLava) {
|
||||
//! @bug Use of potentially undefined variable `waterLevel`
|
||||
s->floorHeight = waterLevel;
|
||||
|
||||
// Assume that the water is flat.
|
||||
s->floorNormalX = 0;
|
||||
s->floorNormalY = 1.0;
|
||||
s->floorNormalZ = 0;
|
||||
s->floorOriginOffset = -waterLevel;
|
||||
if (waterFloor != NULL) {
|
||||
s->floorNormalX = waterFloor->normal.x;
|
||||
s->floorNormalY = waterFloor->normal.y;
|
||||
s->floorNormalZ = waterFloor->normal.z;
|
||||
s->floorOriginOffset = waterFloor->originOffset;
|
||||
gShadowAboveWaterOrLava = FALSE;
|
||||
gShadowAboveCustomWater = TRUE;
|
||||
s->solidity = 200;
|
||||
} else {
|
||||
gShadowAboveCustomWater = FALSE;
|
||||
// Assume that the water is flat.
|
||||
s->floorNormalX = 0;
|
||||
s->floorNormalY = 1.0;
|
||||
s->floorNormalZ = 0;
|
||||
s->floorOriginOffset = -waterLevel;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Don't draw a shadow if the floor is lower than expected possible,
|
||||
// or if the y-normal is negative (an unexpected result).
|
||||
@@ -853,6 +871,7 @@ Gfx *create_shadow_below_xyz(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 s
|
||||
find_floor(xPos, yPos, zPos, &pfloor);
|
||||
|
||||
gShadowAboveWaterOrLava = FALSE;
|
||||
gShadowAboveCustomWater = FALSE;
|
||||
gMarioOnIceOrCarpet = 0;
|
||||
sMarioOnFlyingCarpet = 0;
|
||||
if (pfloor != NULL) {
|
||||
|
||||
@@ -38,6 +38,7 @@ extern s16 sSurfaceTypeBelowShadow;
|
||||
* Flag for if the current shadow is above water or lava.
|
||||
*/
|
||||
extern s8 gShadowAboveWaterOrLava;
|
||||
extern s8 gShadowAboveCustomWater;
|
||||
|
||||
/**
|
||||
* Flag for if Mario is on ice or a flying carpet.
|
||||
|
||||
Reference in New Issue
Block a user