/** * This is the behavior file for the tilting inverted pyramids in BitFS/LLL. * The object essentially just tilts and moves Mario with it. */ /** * Creates a transform matrix on a variable passed in from given normals * and the object's position. */ void create_transform_from_normals(Mat4 transform, f32 xNorm, f32 yNorm, f32 zNorm) { Vec3f normal; Vec3f pos; pos[0] = o->oPosX; pos[1] = o->oPosY; pos[2] = o->oPosZ; normal[0] = xNorm; normal[1] = yNorm; normal[2] = zNorm; mtxf_align_terrain_normal(transform, normal, pos, 0); } /** * Initialize the object's transform matrix with Y being up. */ void bhv_platform_normals_init(void) { Mat4 *transform = &o->transform; o->oTiltingPyramidNormalX = 0.0f; o->oTiltingPyramidNormalY = 1.0f; o->oTiltingPyramidNormalZ = 0.0f; create_transform_from_normals(*transform, 0.0f, 1.0f, 0.0f); } /** * Returns a value that is src incremented/decremented by inc towards goal * until goal is reached. Does not overshoot. */ f32 approach_by_increment(f32 goal, f32 src, f32 inc) { f32 newVal; if (src <= goal) { if (goal - src < inc) { newVal = goal; } else { newVal = src + inc; } } else if (goal - src > -inc) { newVal = goal; } else { newVal = src - inc; } return newVal; } /** * Main behavior for the tilting pyramids in LLL/BitFS. These platforms calculate rough normals from Mario's position, * then gradually tilt back moving Mario with them. */ void bhv_tilting_inverted_pyramid_loop(void) { f32 dx; f32 dy; f32 dz; f32 d; Vec3f dist; Vec3f posBeforeRotation; Vec3f posAfterRotation; // Mario's position f32 mx; f32 my; f32 mz; s32 marioOnPlatform = FALSE; UNUSED s32 unused; Mat4 *transform = &o->transform; UNUSED s32 unused2[7]; f32 x = 0; f32 y = 0; f32 z = 0; u8 playersTouched = 0; for (int i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } if (gMarioStates[i].marioObj->platform != o) { continue; } x += gMarioStates[i].marioObj->oPosX; y += gMarioStates[i].marioObj->oPosY; z += gMarioStates[i].marioObj->oPosZ; playersTouched++; if (i == 0) { marioOnPlatform = TRUE; } } if (playersTouched > 0) { x /= (f32)playersTouched; y /= (f32)playersTouched; z /= (f32)playersTouched; get_mario_pos(&mx, &my, &mz); dist[0] = x - o->oPosX; dist[1] = y - o->oPosY; dist[2] = z - o->oPosZ; linear_mtxf_mul_vec3f(*transform, posBeforeRotation, dist); dx = x - o->oPosX; dy = 500.0f; dz = z - o->oPosZ; d = sqrtf(dx * dx + dy * dy + dz * dz); //! Always true since dy = 500, making d >= 500. if (d != 0.0f) { // Normalizing d = 1.0 / d; dx *= d; dy *= d; dz *= d; } else { dx = 0.0f; dy = 1.0f; dz = 0.0f; } /*if (o->oTiltingPyramidMarioOnPlatform == TRUE) marioOnPlatform++;*/ o->oTiltingPyramidMarioOnPlatform = TRUE; } else { dx = 0.0f; dy = 1.0f; dz = 0.0f; o->oTiltingPyramidMarioOnPlatform = FALSE; } // Approach the normals by 0.01f towards the new goal, then create a transform matrix and orient the object. // Outside of the other conditionals since it needs to tilt regardless of whether Mario is on. o->oTiltingPyramidNormalX = approach_by_increment(dx, o->oTiltingPyramidNormalX, 0.01f); o->oTiltingPyramidNormalY = approach_by_increment(dy, o->oTiltingPyramidNormalY, 0.01f); o->oTiltingPyramidNormalZ = approach_by_increment(dz, o->oTiltingPyramidNormalZ, 0.01f); create_transform_from_normals(*transform, o->oTiltingPyramidNormalX, o->oTiltingPyramidNormalY, o->oTiltingPyramidNormalZ); // If Mario is on the platform, adjust his position for the platform tilt. if (marioOnPlatform != FALSE) { linear_mtxf_mul_vec3f(*transform, posAfterRotation, dist); mx += posAfterRotation[0] - posBeforeRotation[0]; my += posAfterRotation[1] - posBeforeRotation[1]; mz += posAfterRotation[2] - posBeforeRotation[2]; set_mario_pos(mx, my, mz); } o->header.gfx.throwMatrix = transform; }