Unhardcoded floor and ceiling limits (#179)

* Unhardcoded ceiling and floor limits

* Revert "Unhardcoded ceiling and floor limits"

* Revert "Revert "Unhardcoded ceiling and floor limits""

This reverts commit 71b2da4c4b898cda73f211620d138b346370d2ce.

* Let's try that again
This commit is contained in:
Sunk 2022-09-12 22:58:01 -04:00 committed by GitHub
parent 94d5dfcf10
commit ffc06db874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 68 additions and 46 deletions

View File

@ -623,12 +623,16 @@
--- @field public yaw integer
--- @class LevelValues
--- @field public ceilHeightLimit integer
--- @field public coinsRequiredForCoinStar integer
--- @field public entryLevel LevelNum
--- @field public exitCastleArea integer
--- @field public exitCastleLevel LevelNum
--- @field public exitCastleWarpNode integer
--- @field public fixCollisionBugs integer
--- @field public floorLowerLimit integer
--- @field public floorLowerLimitMisc integer
--- @field public floorLowerLimitShadow integer
--- @field public metalCapDuration integer
--- @field public metalCapDurationCotmc integer
--- @field public pssSlideStarIndex integer

View File

@ -905,12 +905,16 @@
| Field | Type | Access |
| ----- | ---- | ------ |
| ceilHeightLimit | `integer` | |
| coinsRequiredForCoinStar | `integer` | |
| entryLevel | [enum LevelNum](constants.md#enum-LevelNum) | |
| exitCastleArea | `integer` | |
| exitCastleLevel | [enum LevelNum](constants.md#enum-LevelNum) | |
| exitCastleWarpNode | `integer` | |
| fixCollisionBugs | `integer` | |
| floorLowerLimit | `integer` | |
| floorLowerLimitMisc | `integer` | |
| floorLowerLimitShadow | `integer` | |
| metalCapDuration | `integer` | |
| metalCapDurationCotmc | `integer` | |
| pssSlideStarIndex | `integer` | |

View File

@ -380,7 +380,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32
// set pheight to highest value
if (gLevelValues.fixCollisionBugs) {
*pheight = CELL_HEIGHT_LIMIT;
*pheight = gLevelValues.ceilHeightLimit;
}
// Stay in this loop until out of ceilings.
@ -468,8 +468,8 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) {
s16 cellZ, cellX;
struct Surface *ceil, *dynamicCeil;
struct SurfaceNode *surfaceList;
f32 height = CELL_HEIGHT_LIMIT;
f32 dynamicHeight = CELL_HEIGHT_LIMIT;
f32 height = gLevelValues.ceilHeightLimit;
f32 dynamicHeight = gLevelValues.ceilHeightLimit;
s16 x, y, z;
//! (Parallel Universes) Because position is casted to an s16, reaching higher
@ -581,7 +581,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
// set pheight to lowest value
if (gLevelValues.fixCollisionBugs) {
*pheight = FLOOR_LOWER_LIMIT;
*pheight = gLevelValues.floorLowerLimit;
}
// Iterate through the list of floors until there are no more floors.
@ -736,7 +736,7 @@ f32 find_floor_height(f32 x, f32 y, f32 z) {
f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
struct SurfaceNode *surfaceList;
struct Surface *floor;
f32 floorHeight = FLOOR_LOWER_LIMIT;
f32 floorHeight = gLevelValues.floorLowerLimit;
// Would normally cause PUs, but dynamic floors unload at that range.
s16 x = (s16) xPos;
@ -764,8 +764,8 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
struct Surface *floor, *dynamicFloor;
struct SurfaceNode *surfaceList;
f32 height = FLOOR_LOWER_LIMIT;
f32 dynamicHeight = FLOOR_LOWER_LIMIT;
f32 height = gLevelValues.floorLowerLimit;
f32 dynamicHeight = gLevelValues.floorLowerLimit;
//! (Parallel Universes) Because position is casted to an s16, reaching higher
// float locations can return floors despite them not existing there.
@ -843,7 +843,7 @@ f32 find_water_level(f32 x, f32 z) {
s32 numRegions;
s16 val;
f32 loX, hiX, loZ, hiZ;
f32 waterLevel = FLOOR_LOWER_LIMIT;
f32 waterLevel = gLevelValues.floorLowerLimit;
s16 *p = gEnvironmentRegions;
if (p != NULL) {
@ -879,7 +879,7 @@ f32 find_poison_gas_level(f32 x, f32 z) {
UNUSED s32 unused;
s16 val;
f32 loX, hiX, loZ, hiZ;
f32 gasLevel = FLOOR_LOWER_LIMIT;
f32 gasLevel = gLevelValues.floorLowerLimit;
s16 *p = gEnvironmentRegions;
if (p != NULL) {

View File

@ -8,7 +8,7 @@
#include "engine/extended_bounds.h"
#define CELL_HEIGHT_LIMIT 20000
#define CEIL_HEIGHT_LIMIT 20000
#define FLOOR_LOWER_LIMIT -11000
#define FLOOR_LOWER_LIMIT_MISC (FLOOR_LOWER_LIMIT + 1000)
// same as FLOOR_LOWER_LIMIT_MISC, explicitly for shadow.c

View File

@ -32,7 +32,7 @@ void bhv_yellow_coin_init(void) {
cur_obj_update_floor_height();
if (500.0f < absf(o->oPosY - o->oFloorHeight))
cur_obj_set_model(smlua_model_util_load(E_MODEL_YELLOW_COIN_NO_SHADOW));
if (o->oFloorHeight < FLOOR_LOWER_LIMIT_MISC)
if (o->oFloorHeight < gLevelValues.floorLowerLimitMisc)
obj_mark_for_deletion(o);
}
@ -117,7 +117,7 @@ void bhv_coin_formation_spawn_loop(void) {
if (o->oCoinUnkF8) {
o->oPosY += 300.0f;
cur_obj_update_floor_height();
if (o->oPosY < o->oFloorHeight || o->oFloorHeight < FLOOR_LOWER_LIMIT_MISC)
if (o->oPosY < o->oFloorHeight || o->oFloorHeight < gLevelValues.floorLowerLimitMisc)
obj_mark_for_deletion(o);
else
o->oPosY = o->oFloorHeight;

View File

@ -259,7 +259,7 @@ void bhv_fish_loop(void)
// Delete fish if it's drifted to an area with no water.
if (gCurrLevelNum != LEVEL_UNKNOWN_32) {
if (o->oFishWaterLevel < FLOOR_LOWER_LIMIT_MISC) {
if (o->oFishWaterLevel < gLevelValues.floorLowerLimitMisc) {
obj_mark_for_deletion(o);
return;
}

View File

@ -51,7 +51,7 @@ void bhv_water_splash_spawn_droplets(void) {
if (o->oTimer == 0)
o->oPosY = find_water_level(o->oPosX, o->oPosZ);
if (o->oPosY > FLOOR_LOWER_LIMIT_MISC) // Make sure it is not at the default water level
if (o->oPosY > gLevelValues.floorLowerLimitMisc) // Make sure it is not at the default water level
for (i = 0; i < 3; i++)
spawn_water_droplet(o, &sWaterSplashDropletParams);
}
@ -88,7 +88,7 @@ void bhv_water_droplet_loop(void) {
} else if (o->oTimer > 20)
obj_mark_for_deletion(o);
}
if (waterLevel < FLOOR_LOWER_LIMIT_MISC)
if (waterLevel < gLevelValues.floorLowerLimitMisc)
obj_mark_for_deletion(o);
}

View File

@ -806,10 +806,10 @@ void set_camera_height(struct Camera *c, f32 goalHeight) {
}
}
approach_camera_height(c, goalHeight, 20.f);
if (camCeilHeight != CELL_HEIGHT_LIMIT) {
if (camCeilHeight != gLevelValues.ceilHeightLimit) {
camCeilHeight -= baseOff;
if ((c->pos[1] > camCeilHeight && sMarioGeometry.currFloorHeight + baseOff < camCeilHeight)
|| (sMarioGeometry.currCeilHeight != CELL_HEIGHT_LIMIT
|| (sMarioGeometry.currCeilHeight != gLevelValues.ceilHeightLimit
&& sMarioGeometry.currCeilHeight > camCeilHeight && c->pos[1] > camCeilHeight)) {
c->pos[1] = camCeilHeight;
}
@ -1504,7 +1504,7 @@ s32 update_fixed_camera(struct Camera *c, Vec3f focus, UNUSED Vec3f pos) {
vec3f_add(basePos, sCastleEntranceOffset);
if (sMarioGeometry.currFloorType != SURFACE_DEATH_PLANE
&& sMarioGeometry.currFloorHeight != FLOOR_LOWER_LIMIT) {
&& sMarioGeometry.currFloorHeight != gLevelValues.floorLowerLimit) {
goalHeight = sMarioGeometry.currFloorHeight + basePos[1] + heightOffset;
} else {
goalHeight = gLakituState.goalPos[1];
@ -1515,7 +1515,7 @@ s32 update_fixed_camera(struct Camera *c, Vec3f focus, UNUSED Vec3f pos) {
}
ceilHeight = find_ceil(c->pos[0], goalHeight - 100.f, c->pos[2], &ceiling);
if (ceilHeight != CELL_HEIGHT_LIMIT) {
if (ceilHeight != gLevelValues.ceilHeightLimit) {
if (goalHeight > (ceilHeight -= 125.f)) {
goalHeight = ceilHeight;
}
@ -1614,7 +1614,7 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
// When C-Down is not active, this
vec3f_set_dist_and_angle(focus, pos, focusDistance, 0x1000, yaw);
// Find the floor of the arena
pos[1] = find_floor(c->areaCenX, CELL_HEIGHT_LIMIT, c->areaCenZ, &floor);
pos[1] = find_floor(c->areaCenX, gLevelValues.ceilHeightLimit, c->areaCenZ, &floor);
if (floor != NULL) {
nx = floor->normal.x;
ny = floor->normal.y;
@ -2290,7 +2290,7 @@ s16 update_default_camera(struct Camera *c) {
// If there's water below the camera, decide whether to keep the camera above the water surface
waterHeight = find_water_level(cPos[0], cPos[2]);
if (waterHeight != FLOOR_LOWER_LIMIT) {
if (waterHeight != gLevelValues.floorLowerLimit) {
waterHeight += 125.f;
distFromWater = waterHeight - marioFloorHeight;
if (!(gCameraMovementFlags & CAM_MOVE_METAL_BELOW_WATER)) {
@ -2340,7 +2340,7 @@ s16 update_default_camera(struct Camera *c) {
// Make Lakitu fly above the gas
gasHeight = find_poison_gas_level(cPos[0], cPos[2]);
if (gasHeight != FLOOR_LOWER_LIMIT) {
if (gasHeight != gLevelValues.floorLowerLimit) {
if ((gasHeight += 130.f) > c->pos[1]) {
c->pos[1] = gasHeight;
}
@ -2351,7 +2351,7 @@ s16 update_default_camera(struct Camera *c) {
if (c->mode == CAMERA_MODE_FREE_ROAM) {
camFloorHeight -= 100.f;
}
ceilHeight = CELL_HEIGHT_LIMIT;
ceilHeight = gLevelValues.ceilHeightLimit;
vec3f_copy(c->focus, sMarioCamState->pos);
}
@ -2360,10 +2360,10 @@ s16 update_default_camera(struct Camera *c) {
if (sMarioCamState->pos[1] - 100.f > camFloorHeight) {
camFloorHeight = sMarioCamState->pos[1] - 100.f;
}
ceilHeight = CELL_HEIGHT_LIMIT;
ceilHeight = gLevelValues.ceilHeightLimit;
vec3f_copy(c->focus, sMarioCamState->pos);
}
if (camFloorHeight != FLOOR_LOWER_LIMIT) {
if (camFloorHeight != gLevelValues.floorLowerLimit) {
camFloorHeight += posHeight;
approach_camera_height(c, camFloorHeight, 20.f);
}
@ -2385,7 +2385,7 @@ s16 update_default_camera(struct Camera *c) {
vec3f_set_dist_and_angle(c->focus, c->pos, dist, tempPitch, tempYaw);
}
}
if (ceilHeight != CELL_HEIGHT_LIMIT) {
if (ceilHeight != gLevelValues.ceilHeightLimit) {
if (c->pos[1] > (ceilHeight -= 150.f)
&& (avoidStatus = is_range_behind_surface(c->pos, sMarioCamState->pos, ceil, 0, -1)) == 1) {
c->pos[1] = ceilHeight;
@ -2483,7 +2483,7 @@ s32 update_spiral_stairs_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
checkPos[2] = focus[2] + (cPos[2] - focus[2]) * 0.7f;
floorHeight = find_floor(checkPos[0], checkPos[1] + 50.f, checkPos[2], &floor);
if (floorHeight != FLOOR_LOWER_LIMIT) {
if (floorHeight != gLevelValues.floorLowerLimit) {
if (floorHeight < sMarioGeometry.currFloorHeight) {
floorHeight = sMarioGeometry.currFloorHeight;
}
@ -3031,7 +3031,7 @@ void update_lakitu(struct Camera *c) {
gLakituState.pos[1] + 20.0f,
gLakituState.pos[2], &floor);
gCheckingSurfaceCollisionsForCamera = false;
if (distToFloor != FLOOR_LOWER_LIMIT) {
if (distToFloor != gLevelValues.floorLowerLimit) {
if (gLakituState.pos[1] < (distToFloor += 100.0f)) {
gLakituState.pos[1] = distToFloor;
}
@ -5567,7 +5567,7 @@ s16 next_lakitu_state(Vec3f newPos, Vec3f newFoc, Vec3f curPos, Vec3f curFoc,
if (gCamera->cutscene != 0 || !(gCameraMovementFlags & CAM_MOVE_C_UP_MODE)) {
floorHeight = find_floor(newPos[0], newPos[1], newPos[2], &floor);
if (floorHeight != FLOOR_LOWER_LIMIT) {
if (floorHeight != gLevelValues.floorLowerLimit) {
if ((floorHeight += 125.f) > newPos[1]) {
newPos[1] = floorHeight;
}
@ -6819,19 +6819,19 @@ void resolve_geometry_collisions(Vec3f pos, UNUSED Vec3f lastGood) {
floorY = find_floor(pos[0], pos[1] + 50.f, pos[2], &surf);
ceilY = find_ceil(pos[0], pos[1] - 50.f, pos[2], &surf);
if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT == ceilY)) {
if ((gLevelValues.floorLowerLimit != floorY) && (gLevelValues.ceilHeightLimit == ceilY)) {
if (pos[1] < (floorY += 125.f)) {
pos[1] = floorY;
}
}
if ((FLOOR_LOWER_LIMIT == floorY) && (CELL_HEIGHT_LIMIT != ceilY)) {
if ((gLevelValues.floorLowerLimit == floorY) && (gLevelValues.ceilHeightLimit != ceilY)) {
if (pos[1] > (ceilY -= 125.f)) {
pos[1] = ceilY;
}
}
if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT != ceilY)) {
if ((gLevelValues.floorLowerLimit != floorY) && (gLevelValues.ceilHeightLimit != ceilY)) {
floorY += 125.f;
ceilY -= 125.f;
@ -6958,14 +6958,14 @@ void find_mario_floor_and_ceil(struct PlayerGeometry *pg) {
gCheckingSurfaceCollisionsForCamera = TRUE;
if (find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 10.f,
sMarioCamState->pos[2], &surf) != FLOOR_LOWER_LIMIT) {
sMarioCamState->pos[2], &surf) != gLevelValues.floorLowerLimit) {
pg->currFloorType = surf->type;
} else {
pg->currFloorType = 0;
}
if (find_ceil(sMarioCamState->pos[0], sMarioCamState->pos[1] - 10.f,
sMarioCamState->pos[2], &surf) != CELL_HEIGHT_LIMIT) {
sMarioCamState->pos[2], &surf) != gLevelValues.ceilHeightLimit) {
pg->currCeilType = surf->type;
} else {
pg->currCeilType = 0;
@ -8838,7 +8838,7 @@ BAD_RETURN(s32) cutscene_suffocation_stay_above_gas(struct Camera *c) {
cutscene_goto_cvar_pos(c, 400.f, 0x2800, 0x200, 0);
gasLevel = find_poison_gas_level(sMarioCamState->pos[0], sMarioCamState->pos[2]);
if (gasLevel != FLOOR_LOWER_LIMIT) {
if (gasLevel != gLevelValues.floorLowerLimit) {
if ((gasLevel += 130.f) > c->pos[1]) {
c->pos[1] = gasLevel;
}
@ -10227,7 +10227,7 @@ BAD_RETURN(s32) cutscene_exit_painting_start(struct Camera *c) {
offset_rotated(c->pos, sCutsceneVars[0].point, sCutsceneVars[2].point, sCutsceneVars[0].angle);
floorHeight = find_floor(c->pos[0], c->pos[1] + 10.f, c->pos[2], &floor);
if (floorHeight != FLOOR_LOWER_LIMIT) {
if (floorHeight != gLevelValues.floorLowerLimit) {
if (c->pos[1] < (floorHeight += 60.f)) {
c->pos[1] = floorHeight;
}

View File

@ -12,6 +12,7 @@
#include "textures.h"
#include "game/rendering_graph_node.h"
#include "pc/utils/misc.h"
#include "game/hardcoded.h"
/**
* This file implements environment effects that are not snow:
@ -160,14 +161,14 @@ void envfx_set_lava_bubble_position(s32 index, Vec3s centerPos) {
floorY = find_floor((gEnvFxBuffer + index)->xPos, centerY + 500, (gEnvFxBuffer + index)->zPos, &surface);
if (surface == NULL) {
(gEnvFxBuffer + index)->yPos = FLOOR_LOWER_LIMIT_MISC;
(gEnvFxBuffer + index)->yPos = gLevelValues.floorLowerLimitMisc;
return;
}
if (surface->type == SURFACE_BURNING) {
(gEnvFxBuffer + index)->yPos = floorY;
} else {
(gEnvFxBuffer + index)->yPos = FLOOR_LOWER_LIMIT_MISC;
(gEnvFxBuffer + index)->yPos = gLevelValues.floorLowerLimitMisc;
}
}

View File

@ -88,6 +88,10 @@ struct LevelValues gDefaultLevelValues = {
.UnagiStarPos = { 6833.0f, -3654.0f, 2230.0f },
.JetstreamRingStarPos = { 3400.0f, -3200.0f, -500.0f },
},
.ceilHeightLimit = 20000,
.floorLowerLimit = -11000,
.floorLowerLimitMisc = -10000,
.floorLowerLimitShadow = -10000,
};
struct LevelValues gLevelValues = { 0 };

View File

@ -53,6 +53,10 @@ struct LevelValues {
u16 metalCapDurationCotmc;
u16 vanishCapDurationVcutm;
struct StarPositions starPositions;
s16 ceilHeightLimit;
s16 floorLowerLimit;
s16 floorLowerLimitMisc;
s16 floorLowerLimitShadow;
};
extern struct LevelValues gLevelValues;

View File

@ -443,7 +443,7 @@ s16 object_step(void) {
f32 objZ = o->oPosZ;
f32 floorY;
f32 waterY = FLOOR_LOWER_LIMIT_MISC;
f32 waterY = gLevelValues.floorLowerLimitMisc;
f32 objVelX = o->oForwardVel * sins(o->oMoveAngleYaw);
f32 objVelZ = o->oForwardVel * coss(o->oMoveAngleYaw);

View File

@ -12,6 +12,7 @@
#include "segment2.h"
#include "shadow.h"
#include "sm64.h"
#include "game/hardcoded.h"
// Avoid Z-fighting
#define find_floor_height_and_data 0.4 + find_floor_height_and_data
@ -223,7 +224,7 @@ u8 dim_shadow_with_distance(u8 solidity, f32 distFromFloor) {
*/
f32 get_water_level_below_shadow(struct Shadow *s) {
f32 waterLevel = find_water_level(s->parentX, s->parentZ);
if (waterLevel < FLOOR_LOWER_LIMIT_SHADOW) {
if (waterLevel < gLevelValues.floorLowerLimitShadow) {
return 0;
} else if (s->parentY >= waterLevel && s->floorHeight <= waterLevel) {
gShadowAboveWaterOrLava = TRUE;
@ -266,7 +267,7 @@ s8 init_shadow(struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale,
} else if (floorGeometry != NULL) {
// Don't draw a shadow if the floor is lower than expected possible,
// or if the y-normal is negative (an unexpected result).
if (s->floorHeight < FLOOR_LOWER_LIMIT_SHADOW || floorGeometry->normalY <= 0.0) {
if (s->floorHeight < gLevelValues.floorLowerLimitShadow || floorGeometry->normalY <= 0.0) {
return 1;
}
@ -739,7 +740,7 @@ Gfx *create_shadow_circle_assuming_flat_ground(f32 xPos, f32 yPos, f32 zPos, s16
f32 floorHeight = find_floor_height_and_data(xPos, yPos, zPos, &dummy);
f32 radius = shadowScale / 2;
if (floorHeight < FLOOR_LOWER_LIMIT_SHADOW) {
if (floorHeight < gLevelValues.floorLowerLimitShadow) {
return NULL;
} else {
distBelowFloor = floorHeight - yPos;
@ -826,12 +827,12 @@ s32 get_shadow_height_solidity(f32 xPos, f32 yPos, f32 zPos, f32 *shadowHeight,
f32 waterLevel;
*shadowHeight = find_floor_height_and_data(xPos, yPos, zPos, &dummy);
if (*shadowHeight < FLOOR_LOWER_LIMIT_SHADOW) {
if (*shadowHeight < gLevelValues.floorLowerLimitShadow) {
return 1;
} else {
waterLevel = find_water_level(xPos, zPos);
if (waterLevel < FLOOR_LOWER_LIMIT_SHADOW) {
if (waterLevel < gLevelValues.floorLowerLimitShadow) {
// Dead if-statement. There may have been an assert here.
} else if (yPos >= waterLevel && waterLevel >= *shadowHeight) {
gShadowAboveWaterOrLava = TRUE;
@ -918,7 +919,7 @@ Gfx *create_shadow_below_xyz(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 s
// if we're interpolating and the shadow isn't valid, just give up
if (gRenderingInterpolated) {
if (height <= FLOOR_LOWER_LIMIT || pfloor == NULL) {
if (height <= gLevelValues.floorLowerLimit || pfloor == NULL) {
return gShadowInterpCurrent->gfx;
}
}

View File

@ -726,14 +726,18 @@ static struct LuaObjectField sLakituStateFields[LUA_LAKITU_STATE_FIELD_COUNT] =
{ "yaw", LVT_S16, offsetof(struct LakituState, yaw), false, LOT_NONE },
};
#define LUA_LEVEL_VALUES_FIELD_COUNT 16
#define LUA_LEVEL_VALUES_FIELD_COUNT 20
static struct LuaObjectField sLevelValuesFields[LUA_LEVEL_VALUES_FIELD_COUNT] = {
{ "ceilHeightLimit", LVT_S16, offsetof(struct LevelValues, ceilHeightLimit), false, LOT_NONE },
{ "coinsRequiredForCoinStar", LVT_S16, offsetof(struct LevelValues, coinsRequiredForCoinStar), false, LOT_NONE },
{ "entryLevel", LVT_S32, offsetof(struct LevelValues, entryLevel), false, LOT_NONE },
{ "exitCastleArea", LVT_S16, offsetof(struct LevelValues, exitCastleArea), false, LOT_NONE },
{ "exitCastleLevel", LVT_S32, offsetof(struct LevelValues, exitCastleLevel), false, LOT_NONE },
{ "exitCastleWarpNode", LVT_U8, offsetof(struct LevelValues, exitCastleWarpNode), false, LOT_NONE },
{ "fixCollisionBugs", LVT_U8, offsetof(struct LevelValues, fixCollisionBugs), false, LOT_NONE },
{ "floorLowerLimit", LVT_S16, offsetof(struct LevelValues, floorLowerLimit), false, LOT_NONE },
{ "floorLowerLimitMisc", LVT_S16, offsetof(struct LevelValues, floorLowerLimitMisc), false, LOT_NONE },
{ "floorLowerLimitShadow", LVT_S16, offsetof(struct LevelValues, floorLowerLimitShadow), false, LOT_NONE },
{ "metalCapDuration", LVT_U16, offsetof(struct LevelValues, metalCapDuration), false, LOT_NONE },
{ "metalCapDurationCotmc", LVT_U16, offsetof(struct LevelValues, metalCapDurationCotmc), false, LOT_NONE },
{ "pssSlideStarIndex", LVT_U8, offsetof(struct LevelValues, pssSlideStarIndex), false, LOT_NONE },