mk64/src/cpu_vehicles_camera_path/path_utils.inc.c

850 lines
31 KiB
C

#include <ultra64.h>
#include <macros.h>
#include <defines.h>
#include <path.h>
#include <course.h>
#include "main.h"
#include "cpu_vehicles_camera_path.h"
bool are_in_curve(UNUSED s32 arg0, u16 pathPointIndex) {
s16 thing = gCurrentTrackConsecutiveCurveCountsPath[pathPointIndex];
if (thing > 0) {
return true;
}
return false;
}
bool is_far_from_path(s32 playerIndex) {
f32 value = gTrackPositionFactor[playerIndex];
if ((1.1f <= value) || (value <= -1.1f)) {
return true;
}
return false;
}
/**
* Calculates a factor representing where the player is positioned between left and right track boundaries
* Returns a value between -1.0 and 1.0:
* -1.0 = On the left boundary
* 0.0 = In the middle of the track
* 1.0 = On the right boundary
*
* @param posX Player's X position
* @param posZ Player's Z position
* @param pathPointIndex Current pathPoint index
* @param pathIndex Current path/track index
* @return Position factor between track boundaries
*/
f32 calculate_track_position_factor(f32 posX, f32 posZ, u16 pathPointIndex, s32 pathIndex) {
f32 leftX;
f32 leftZ;
f32 rightX;
f32 rightZ;
f32 boundarySquaredDistance;
f32 positionFactor;
TrackPathPoint* leftPathPoint;
TrackPathPoint* rightPathPoint;
leftPathPoint = &gTrackLeftPaths[pathIndex][pathPointIndex];
rightPathPoint = &gTrackRightPaths[pathIndex][pathPointIndex];
leftX = leftPathPoint->posX;
leftZ = leftPathPoint->posZ;
rightX = rightPathPoint->posX;
rightZ = rightPathPoint->posZ;
boundarySquaredDistance = ((rightX - leftX) * (rightX - leftX)) + ((rightZ - leftZ) * (rightZ - leftZ));
// Avoid division by zero for very close or identical boundary points
if (boundarySquaredDistance < 0.01f) {
return 0.0f;
}
// Calculate normalized position factor using vector projection
// Formula: 2 * (dot product of vectors) / (squared magnitude) - 1
// This maps the position to a -1 to 1 range
positionFactor =
((2.0f * ((rightX - leftX) * (posX - leftX) + (rightZ - leftZ) * (posZ - leftZ))) / boundarySquaredDistance) -
1.0f;
return positionFactor;
}
void update_player_position_factor(s32 playerId, u16 pathPointIndex, s32 pathIndex) {
UNUSED Vec3f pad;
gTrackPositionFactor[playerId] = 0.0f;
if ((s32) GET_COURSE_AIMaximumSeparation >= 0) {
if ((gPlayers[playerId].type & PLAYER_EXISTS) != 0) {
gTrackPositionFactor[playerId] = calculate_track_position_factor(
gPlayers[playerId].pos[0], gPlayers[playerId].pos[2], pathPointIndex, pathIndex);
}
}
}
void calculate_track_offset_position(u16 pathPointIndex, f32 lerpFactor, f32 offsetDistance, s16 pathIndex) {
UNUSED s32 pad[4];
f32 pathPointOneX;
f32 pathPointOneZ;
f32 pathPointTwoX;
f32 pathPointTwoZ;
UNUSED s32 pad2;
f32 xdiff;
f32 zdiff;
f32 segmentLength;
UNUSED f32 temp_f12;
UNUSED f32 temp_f2_2;
UNUSED TrackPathPoint* path;
TrackPathPoint* pathPointTwo;
TrackPathPoint* pathPointOne;
pathPointOne = &gTrackPaths[pathIndex][pathPointIndex];
pathPointOneX = pathPointOne->posX;
pathPointOneZ = pathPointOne->posZ;
pathPointTwo = &gTrackPaths[pathIndex][(pathPointIndex + 1) % gSelectedPathCount];
pathPointTwoX = pathPointTwo->posX;
pathPointTwoZ = pathPointTwo->posZ;
// Calculate vector between path point
zdiff = pathPointTwoZ - pathPointOneZ;
xdiff = pathPointTwoX - pathPointOneX;
if (xdiff && xdiff) {}
segmentLength = sqrtf((xdiff * xdiff) + (zdiff * zdiff));
if (segmentLength < 0.01f) {
gOffsetPosition[0] = pathPointTwoX;
gOffsetPosition[2] = pathPointTwoZ;
} else {
gOffsetPosition[0] =
((0.5f - (lerpFactor * 0.5f)) * (((offsetDistance * zdiff) / segmentLength) + pathPointOneX)) +
((1.0f - (0.5f - (lerpFactor * 0.5f))) * (((offsetDistance * -zdiff) / segmentLength) + pathPointOneX));
gOffsetPosition[2] =
((0.5f - (lerpFactor * 0.5f)) * (((offsetDistance * -xdiff) / segmentLength) + pathPointOneZ)) +
((1.0f - (0.5f - (lerpFactor * 0.5f))) * (((offsetDistance * xdiff) / segmentLength) + pathPointOneZ));
}
}
/**
* Calculates an interpolated position between left and right track paths.
*
* @param currentPathPoint Index of the current pathPoint
* @param trackOffset Value between 0.0 and 1.0 determining position between left (0.0) and right (1.0) path
* @param pathIndex Index of the track/path segment
*/
void set_track_offset_position(u16 pathPointIndex, f32 trackOffset, s16 pathIndex) {
TrackPathPoint* path1;
TrackPathPoint* path2;
f32 x1;
f32 z1;
f32 x3;
f32 z3;
f32 x2;
f32 z2;
f32 x4;
f32 z4;
f32 temp_f0;
f32 temp_f12;
path1 = &gTrackLeftPaths[pathIndex][pathPointIndex];
path2 = &gTrackRightPaths[pathIndex][pathPointIndex];
x1 = (f32) path1->posX;
z1 = (f32) path1->posZ;
x2 = (f32) path2->posX;
z2 = (f32) path2->posZ;
pathPointIndex += 1;
pathPointIndex = pathPointIndex % gPathCountByPathIndex[pathIndex];
path1 = &gTrackLeftPaths[pathIndex][pathPointIndex];
path2 = &gTrackRightPaths[pathIndex][pathPointIndex];
x3 = (f32) path1->posX;
z3 = (f32) path1->posZ;
x4 = (f32) path2->posX;
z4 = (f32) path2->posZ;
temp_f0 = 0.5f - (trackOffset / 2.0f);
temp_f12 = 1.0f - temp_f0;
gOffsetPosition[0] = ((temp_f0 * (x1 + x3)) / 2.0f) + ((temp_f12 * (x2 + x4)) / 2.0f);
gOffsetPosition[2] = ((temp_f0 * (z1 + z3)) / 2.0f) + ((temp_f12 * (z2 + z4)) / 2.0f);
}
s16 func_8000BD94(f32 posX, f32 posY, f32 posZ, s32 pathIndex) {
f32 x_dist;
f32 y_dist;
f32 z_dist;
f32 considerSquaredDistance;
f32 minimumSquaredDistance;
s32 considerPathPointIndex;
s32 pathPathPointCount;
s16 nearestPathPointIndex;
TrackPathPoint* pathPathPoints;
TrackPathPoint* considerPathPoint;
pathPathPoints = gTrackPaths[pathIndex];
pathPathPointCount = gPathCountByPathIndex[pathIndex];
considerPathPoint = &pathPathPoints[0];
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
minimumSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
nearestPathPointIndex = 0;
for (considerPathPointIndex = 1; considerPathPointIndex < pathPathPointCount;
considerPathPoint++, considerPathPointIndex++) {
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
considerSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (considerSquaredDistance < minimumSquaredDistance) {
nearestPathPointIndex = considerPathPointIndex;
minimumSquaredDistance = considerSquaredDistance;
}
}
return nearestPathPointIndex;
}
s16 find_closest_path_point_track_section(f32 posX, f32 posY, f32 posZ, u16 trackSectionId, s32* pathIndex) {
TrackPathPoint* pathPathPoints;
TrackPathPoint* considerPathPoint;
f32 x_dist;
f32 y_dist;
f32 z_dist;
f32 considerSquaredDistance;
f32 minimumSquaredDistance;
s32 considerPathPointIndex;
s32 pathPathPointCount;
s32 temp_t0;
s32 var_a1;
s32 var_t1;
s32 considerPathIndex;
s32 var_t4;
s16 nearestPathPointIndex;
minimumSquaredDistance = 1000000.0f;
temp_t0 = *pathIndex;
nearestPathPointIndex = 0;
var_t1 = 0;
var_a1 = 0;
pathPathPoints = gTrackPaths[temp_t0];
pathPathPointCount = gPathCountByPathIndex[temp_t0];
considerPathPoint = &pathPathPoints[0];
for (considerPathPointIndex = 0; considerPathPointIndex < pathPathPointCount;
considerPathPointIndex++, considerPathPoint++) {
if ((considerPathPoint->trackSectionId == trackSectionId) || (gCurrentCourseId == COURSE_AWARD_CEREMONY)) {
var_t1 = 1;
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
considerSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (considerSquaredDistance < minimumSquaredDistance) {
nearestPathPointIndex = considerPathPointIndex;
var_a1 = 1;
minimumSquaredDistance = considerSquaredDistance;
}
}
}
if (var_t1 == 0) {
for (considerPathIndex = 0; considerPathIndex < 4; considerPathIndex++) {
if ((considerPathIndex != temp_t0) && (gSizePath[considerPathIndex] >= 2)) {
pathPathPoints = gTrackPaths[considerPathIndex];
considerPathPoint = &pathPathPoints[0];
pathPathPointCount = gPathCountByPathIndex[considerPathIndex];
for (considerPathPointIndex = 0; considerPathPointIndex < pathPathPointCount;
considerPathPointIndex++, considerPathPoint++) {
if (considerPathPoint->trackSectionId == trackSectionId) {
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
considerSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (considerSquaredDistance < minimumSquaredDistance) {
nearestPathPointIndex = considerPathPointIndex;
var_t4 = considerPathIndex;
var_a1 = 2;
minimumSquaredDistance = considerSquaredDistance;
}
}
}
}
}
}
if (var_a1 == 0) {
pathPathPoints = gTrackPaths[0];
pathPathPointCount = gPathCountByPathIndex[0];
considerPathPoint = &pathPathPoints[0];
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
minimumSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
nearestPathPointIndex = 0;
for (considerPathPointIndex = 1; considerPathPointIndex < pathPathPointCount;
considerPathPoint++, considerPathPointIndex++) {
x_dist = (f32) considerPathPoint->posX - posX;
y_dist = (f32) considerPathPoint->posY - posY;
z_dist = (f32) considerPathPoint->posZ - posZ;
considerSquaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (considerSquaredDistance < minimumSquaredDistance) {
nearestPathPointIndex = considerPathPointIndex;
var_t4 = 0;
var_a1 = 2;
minimumSquaredDistance = considerSquaredDistance;
}
}
}
if (var_a1 == 2) {
*pathIndex = var_t4;
}
return nearestPathPointIndex;
}
/**
* Tries to find the path point nearest to (posX, posY, posZ)
* Only consider path in the same segment as trackSectionId
* Only considers path within 500 units of(posX, posY, posZ)
* Looks 3 path behind and 6 path ahead of pathPointIndex
**/
s16 update_path_index_with_track(f32 posX, f32 posY, f32 posZ, s16 pathPointIndex, s32 pathIndex, u16 trackSectionId) {
s16 nearestPathPointIndex;
s16 searchIndex;
s16 considerIndex;
s32 pathPathPointCount;
f32 x_dist;
f32 y_dist;
f32 z_dist;
f32 minimumDistance;
f32 squaredDistance;
TrackPathPoint* pathPathPoints;
TrackPathPoint* considerPathPoint;
nearestPathPointIndex = -1;
minimumDistance = 500.0f * 500.0f;
pathPathPointCount = gPathCountByPathIndex[pathIndex];
pathPathPoints = gTrackPaths[pathIndex];
for (searchIndex = pathPointIndex - 3; searchIndex < pathPointIndex + 7; searchIndex++) {
// Its possible for searchIndex to be less than 0 or greater than the number of path in a given path
// This is done to ensure we access gTrackPaths at a valid index
considerIndex = (searchIndex + pathPathPointCount) % pathPathPointCount;
considerPathPoint = &pathPathPoints[considerIndex];
if (considerPathPoint->trackSectionId == trackSectionId) {
x_dist = considerPathPoint->posX - posX;
y_dist = considerPathPoint->posY - posY;
z_dist = considerPathPoint->posZ - posZ;
squaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (squaredDistance < minimumDistance) {
minimumDistance = squaredDistance;
nearestPathPointIndex = considerIndex;
}
}
}
return nearestPathPointIndex;
}
/**
* Tries to find the path point nearest to (posX, posY, posZ)
* Only considers path within 400 units of (posX, posY, posZ)
* Looks 3 path behind and 6 path ahead of pathPointIndex
**/
s16 update_path_index(f32 posX, f32 posY, f32 posZ, s16 pathPointIndex, s32 pathIndex) {
s16 nearestPathPointIndex;
s16 searchIndex;
s16 considerIndex;
bool pathPointFound;
s32 pathPathPointCount;
f32 x_dist;
f32 y_dist;
f32 z_dist;
f32 minimumDistance;
f32 squaredDistance;
TrackPathPoint* pathPathPoints;
TrackPathPoint* considerPathPoint;
pathPointFound = false;
nearestPathPointIndex = -1;
minimumDistance = 400.0f * 400.0f;
pathPathPointCount = gPathCountByPathIndex[pathIndex];
pathPathPoints = gTrackPaths[pathIndex];
for (searchIndex = pathPointIndex - 3; searchIndex < pathPointIndex + 7; searchIndex++) {
// Its possible for searchIndex to be less than 0 or greater than the number of path in a given path
// This is done to ensure we access gTrackPaths at a valid index
considerIndex = (searchIndex + pathPathPointCount) % pathPathPointCount;
considerPathPoint = &pathPathPoints[considerIndex];
x_dist = considerPathPoint->posX - posX;
y_dist = considerPathPoint->posY - posY;
z_dist = considerPathPoint->posZ - posZ;
squaredDistance = (x_dist * x_dist) + (y_dist * y_dist) + (z_dist * z_dist);
if (squaredDistance < minimumDistance) {
minimumDistance = squaredDistance;
nearestPathPointIndex = considerIndex;
pathPointFound = true;
}
}
if (pathPointFound == false) {
for (searchIndex = pathPointIndex - 3; searchIndex < pathPointIndex + 7; searchIndex++) {
considerIndex = ((searchIndex + pathPathPointCount) % pathPathPointCount);
considerPathPoint = &pathPathPoints[considerIndex];
/**
* This fake match is done to stop the compiler from optimzing out considerPathPoint.
* Maybe if no pathPoint was found some debugging info was printed out, but come
* production time they removed the debug printing but not the loop?
**/
if (considerPathPoint && considerPathPoint) {};
}
}
return nearestPathPointIndex;
}
void tweak_path_index_wario_stadium(UNUSED f32 posX, f32 posY, UNUSED f32 posZ, s16* pathPointIndex, UNUSED s32 arg4) {
s16 var_v0;
var_v0 = *pathPointIndex;
if ((gCurrentCourseId == COURSE_WARIO_STADIUM) && (var_v0 >= 0x475) && (var_v0 < 0x480) && (posY < 0.0f)) {
var_v0 = 0x0398;
}
*pathPointIndex = var_v0;
}
void adjust_path_at_start_line(UNUSED f32 posX, UNUSED f32 posY, f32 posZ, s16* pathPointIndex, s32 pathIndex) {
s16 pathPoint;
pathPoint = *pathPointIndex;
if (pathPoint == 0) {
if (gPathStartZ < posZ) {
pathPoint = gPathCountByPathIndex[pathIndex] - 1;
}
} else if (((pathPoint + 1) == gPathCountByPathIndex[pathIndex]) && (posZ <= gPathStartZ)) {
pathPoint = 0;
}
*pathPointIndex = pathPoint;
}
s16 update_path_index_track_section(f32 posX, f32 posY, f32 posZ, Player* player, s32 playerId, s32* pathIndex) {
u16 trackSectionId;
s16 ret;
trackSectionId = get_track_section_id(player->collision.meshIndexZX);
if ((trackSectionId <= 0) || (trackSectionId >= 0x33)) {
trackSectionId = gPlayersTrackSectionId[playerId];
}
gPlayersTrackSectionId[playerId] = trackSectionId;
ret = find_closest_path_point_track_section(posX, posY, posZ, trackSectionId, pathIndex);
gPathIndexByPlayerId[playerId] = *pathIndex;
return ret;
}
/**
* Updates and validates a player's pathPoint position on the track
* Handles different logic for human players vs AI, and includes recovery mechanisms
*
* @param posX Current X position
* @param posY Current Y position
* @param posZ Current Z position
* @param pathPointIndex Current pathPoint index
* @param player Pointer to player structure
* @param playerId Player's ID
* @param pathIndex Current track path index
* @return New pathPoint index or -1 if invalid
*/
s16 update_player_path(f32 posX, f32 posY, f32 posZ, s16 pathPointIndex, Player* player, s32 playerId, s32 pathIndex) {
s16 newPathPoint;
UNUSED s16 stackPadding0;
UNUSED s32 stackPadding1;
UNUSED s32 stackPadding2;
TrackPathPoint* temp_v1;
// Human player handling (non-AI controlled)
if ((player->type & PLAYER_HUMAN) && !(player->type & PLAYER_CPU)) {
newPathPoint = update_path_index_with_track(posX, posY, posZ, pathPointIndex, pathIndex,
(u16) get_track_section_id(player->collision.meshIndexZX));
if (newPathPoint == -1) {
newPathPoint = update_path_index_track_section(posX, posY, posZ, player, playerId, &pathIndex);
}
} else { // AI or special case player handling
if (D_801631E0[playerId] == true) {
if (player->unk_0CA & UNK_0CA_LAKITU_RETRIEVAL) {
temp_v1 = &gTrackPaths[pathIndex][pathPointIndex];
player->pos[0] = (f32) temp_v1->posX;
player->pos[1] = (f32) temp_v1->posY;
player->pos[2] = (f32) temp_v1->posZ;
player->unk_0CA &= ~UNK_0CA_LAKITU_RETRIEVAL;
return pathPointIndex;
}
if (playerId == ((s32) D_80163488 % 8)) {
check_bounding_collision(&player->collision, 10.0f, posX, posY, posZ);
gPlayersTrackSectionId[playerId] = get_track_section_id(player->collision.meshIndexZX);
newPathPoint = update_path_index_with_track(posX, posY, posZ, pathPointIndex, pathIndex,
gPlayersTrackSectionId[playerId]);
if (newPathPoint == -1) {
newPathPoint = update_path_index(posX, posY, posZ, pathPointIndex, pathIndex);
}
if (newPathPoint == -1) {
newPathPoint = find_closest_path_point_track_section(posX, posY, posZ,
gPlayersTrackSectionId[playerId], &pathIndex);
temp_v1 = &gTrackPaths[pathIndex][newPathPoint];
player->pos[0] = (f32) temp_v1->posX;
player->pos[1] = (f32) temp_v1->posY;
player->pos[2] = (f32) temp_v1->posZ;
}
} else {
newPathPoint = update_path_index(posX, posY, posZ, pathPointIndex, pathIndex);
if (newPathPoint == -1) {
newPathPoint = func_8000BD94(posX, posY, posZ, pathIndex);
temp_v1 = &gTrackPaths[pathIndex][newPathPoint];
posX = (f32) temp_v1->posX;
posY = (f32) temp_v1->posY;
posZ = (f32) temp_v1->posZ;
player->pos[0] = posX;
player->pos[1] = posY;
player->pos[2] = posZ;
check_bounding_collision(&player->collision, 10.0f, posX, posY, posZ);
gPlayersTrackSectionId[playerId] = get_track_section_id(player->collision.meshIndexZX);
}
}
} else {
newPathPoint = update_path_index(posX, posY, posZ, pathPointIndex, pathIndex);
if (newPathPoint == -1) {
newPathPoint = update_path_index_track_section(posX, posY, posZ, player, playerId, &pathIndex);
}
}
tweak_path_index_wario_stadium(posX, posY, posZ, &newPathPoint, pathIndex);
}
adjust_path_at_start_line(posX, posY, posZ, &newPathPoint, pathIndex);
return newPathPoint;
}
s16 find_closest_vehicles_path_point(f32 xPos, UNUSED f32 yPos, f32 zPos, s16 pathPointIndex) {
f32 xdiff;
f32 zdiff;
f32 minimumDistance;
f32 considerSquaredDistance;
s16 realIndex;
s16 minimumIndex;
s16 considerIndex;
Path2D* considerPathPoint;
minimumDistance = 250000.0f;
minimumIndex = -1;
for (realIndex = pathPointIndex - 2; realIndex < pathPointIndex + 7; realIndex++) {
considerIndex = realIndex;
if (realIndex < 0) {
considerIndex = realIndex + gVehicle2DPathLength;
}
considerIndex %= gVehicle2DPathLength;
considerPathPoint = &gVehicle2DPathPoint[considerIndex];
xdiff = considerPathPoint->x - xPos;
zdiff = considerPathPoint->z - zPos;
considerSquaredDistance = (xdiff * xdiff) + (zdiff * zdiff);
if (considerSquaredDistance < minimumDistance) {
minimumDistance = considerSquaredDistance;
minimumIndex = considerIndex;
}
}
if (minimumIndex == -1) {
minimumIndex = pathPointIndex;
}
return minimumIndex;
}
s16 func_8000D24C(f32 posX, f32 posY, f32 posZ, s32* pathIndex) {
UNUSED s32 pad;
Collision sp24;
check_bounding_collision(&sp24, 10.0f, posX, posY, posZ);
return find_closest_path_point_track_section(posX, posY, posZ, get_track_section_id(sp24.meshIndexZX), pathIndex);
}
s16 func_8000D2B4(f32 posX, f32 posY, f32 posZ, s16 pathPointIndex, s32 pathIndex) {
s16 pathPoint;
pathPoint = update_path_index(posX, posY, posZ, pathPointIndex, pathIndex);
if (pathPoint == -1) {
pathPoint = func_8000D24C(posX, posY, posZ, &pathIndex);
}
adjust_path_at_start_line(posX, posY, posZ, &pathPoint, pathIndex);
return pathPoint;
}
s16 func_8000D33C(f32 posX, f32 posY, f32 posZ, s16 pathPointIndex, s32 pathIndex) {
s16 pathPoint;
pathPoint = update_path_index(posX, posY, posZ, pathPointIndex, pathIndex);
if (pathPoint == -1) {
pathPoint = func_8000D24C(posX, posY, posZ, &pathIndex);
}
return pathPoint;
}
f32 cpu_track_position_factor(s32 playerId) {
TrackPositionFactorInstruction* temp_v0;
f32 target;
f32 current;
temp_v0 = &gPlayerTrackPositionFactorInstruction[playerId];
current = temp_v0->current;
target = temp_v0->target;
if (current < target) {
current += temp_v0->step;
if (target < current) {
current = target;
}
} else if (target < current) {
current -= temp_v0->step;
if (current < target) {
current = target;
}
}
temp_v0->current = current;
return current;
}
void determine_ideal_cpu_position_offset(s32 playerId, u16 pathPoint) {
UNUSED s32 stackPadding0;
f32 sp48;
f32 sp44;
UNUSED s32 stackPadding1;
UNUSED s32 stackPadding2;
UNUSED s32 stackPadding3;
f32 stackPadding4;
f32 stackPadding5;
f32 sp2C;
s32 lookAheadDistance;
s16 curveCount;
u16 thing;
curveCount = gCurrentTrackConsecutiveCurveCountsPath[pathPoint];
lookAheadDistance = 6;
sp2C = cpu_track_position_factor(playerId);
thing = pathPoint;
switch (gCurrentCourseId) {
case COURSE_AWARD_CEREMONY:
lookAheadDistance = 1;
break;
case COURSE_TOADS_TURNPIKE:
lookAheadDistance = 7;
break;
case COURSE_YOSHI_VALLEY:
break;
default:
if (curveCount < 6) {
lookAheadDistance = 8;
} else if (curveCount >= 0x15) {
lookAheadDistance = 20;
}
break;
}
if (lookAheadDistance >= 8) {
if ((gTrackPositionFactor[playerId] > 0.75f) && (gCurrentTrackSectionTypesPath[thing] == RIGHT_LEANING_CURVE)) {
lookAheadDistance = 7;
}
if ((gTrackPositionFactor[playerId] < -0.75f) && (gCurrentTrackSectionTypesPath[thing] == LEFT_LEANING_CURVE)) {
lookAheadDistance = 7;
}
}
if (is_far_from_path(playerId) == true) {
lookAheadDistance = 5;
}
if (gCurrentPlayerLookAhead[playerId] < lookAheadDistance) {
gCurrentPlayerLookAhead[playerId]++;
}
if (lookAheadDistance < gCurrentPlayerLookAhead[playerId]) {
gCurrentPlayerLookAhead[playerId]--;
}
pathPoint = (gCurrentPlayerLookAhead[playerId] + pathPoint) % gSelectedPathCount;
set_track_offset_position(pathPoint, sp2C, gPlayerPathIndex);
sp48 = gOffsetPosition[0];
sp44 = gOffsetPosition[2];
set_track_offset_position(((pathPoint + 1) % gSelectedPathCount) & 0xFFFF, sp2C, gPlayerPathIndex);
stackPadding5 = gOffsetPosition[0];
gOffsetPosition[0] = (sp48 + stackPadding5) * 0.5f;
stackPadding4 = gOffsetPosition[2];
gOffsetPosition[2] = (sp44 + stackPadding4) * 0.5f;
}
s16 func_8000D6D0(Vec3f position, s16* pathPointIndex, f32 speed, f32 arg3, s16 pathIndex, s16 arg5) {
f32 temp1;
f32 temp2;
f32 midX;
UNUSED s16 stackPadding1;
s16 pathPoint1;
s16 pathPoint2;
f32 pad3;
f32 midY;
f32 pad4;
f32 midZ;
f32 distance;
f32 oldPosX;
f32 oldPosY;
f32 oldPosZ;
f32 var_f2;
f32 var_f12;
f32 var_f14;
s16 temp_v0;
s32 temp_v1;
f32 xdiff;
f32 ydiff;
f32 zdiff;
Vec3f oldPos;
TrackPathPoint* path;
path = gTrackPaths[pathIndex];
oldPos[0] = position[0];
oldPos[1] = position[1];
oldPos[2] = position[2];
oldPosX = position[0];
oldPosY = position[1];
oldPosZ = position[2];
temp_v0 = func_8000D2B4(oldPosX, oldPosY, oldPosZ, *pathPointIndex, (s32) pathIndex);
*pathPointIndex = temp_v0;
temp_v1 = temp_v0 + arg5;
pathPoint1 = temp_v1 % gPathCountByPathIndex[pathIndex];
pathPoint2 = (temp_v1 + 1) % gPathCountByPathIndex[pathIndex];
set_track_offset_position(pathPoint1, arg3, pathIndex);
pad3 = gOffsetPosition[0];
pad4 = gOffsetPosition[2];
set_track_offset_position(pathPoint2, arg3, pathIndex);
temp1 = gOffsetPosition[0];
temp2 = gOffsetPosition[2];
midY = (path[pathPoint1].posY + path[pathPoint2].posY) * 0.5f;
midX = (pad3 + temp1) * 0.5f;
midZ = (pad4 + temp2) * 0.5f;
xdiff = midX - oldPosX;
ydiff = midY - oldPosY;
zdiff = midZ - oldPosZ;
distance = sqrtf((xdiff * xdiff) + (ydiff * ydiff) + (zdiff * zdiff));
if (distance > 0.01f) {
var_f2 = ((xdiff * speed) / distance) + oldPosX;
var_f12 = ((ydiff * speed) / distance) + oldPosY;
var_f14 = ((zdiff * speed) / distance) + oldPosZ;
} else {
var_f2 = oldPosX;
var_f12 = oldPosY;
var_f14 = oldPosZ;
}
position[0] = var_f2;
position[1] = var_f12;
position[2] = var_f14;
return get_angle_between_path(oldPos, position);
}
s16 func_8000D940(Vec3f pos, s16* pathPointIndex, f32 speed, f32 arg3, s16 pathIndex) {
UNUSED f32 pad;
f32 thing1;
f32 thing2;
UNUSED s16 stackPadding1;
s16 pathPoint1;
s16 pathPoint2;
UNUSED s16 stackPadding2;
f32 pad2;
f32 midX;
f32 pad3;
f32 midY;
f32 midZ;
f32 distance;
f32 temp_f20;
f32 temp_f22;
f32 temp_f24;
f32 var_f2;
f32 var_f12;
f32 var_f14;
s16 temp_v0;
f32 xdiff;
f32 ydiff;
f32 zdiff;
s32 pathPointCount;
Vec3f sp54;
sp54[0] = pos[0];
sp54[1] = pos[1];
sp54[2] = pos[2];
pathPointCount = gPathCountByPathIndex[pathIndex];
temp_f20 = pos[0];
temp_f22 = pos[1];
temp_f24 = pos[2];
temp_v0 = func_8000D2B4(temp_f20, temp_f22, temp_f24, *pathPointIndex, (s32) pathIndex);
*pathPointIndex = temp_v0;
pathPoint1 = ((temp_v0 + pathPointCount) - 3) % pathPointCount;
pathPoint2 = ((temp_v0 + pathPointCount) - 4) % pathPointCount;
set_track_offset_position(pathPoint1, arg3, pathIndex);
pad2 = gOffsetPosition[0];
pad3 = gOffsetPosition[2];
set_track_offset_position(pathPoint2, arg3, pathIndex);
thing1 = gOffsetPosition[0];
thing2 = gOffsetPosition[2];
midY = (gTrackPaths[pathIndex][pathPoint1].posY + gTrackPaths[pathIndex][pathPoint2].posY) * 0.5f;
midX = (pad2 + thing1) * 0.5f;
midZ = (pad3 + thing2) * 0.5f;
xdiff = midX - temp_f20;
ydiff = midY - temp_f22;
zdiff = midZ - temp_f24;
distance = sqrtf((xdiff * xdiff) + (ydiff * ydiff) + (zdiff * zdiff));
if (distance > 0.01f) {
var_f2 = ((xdiff * speed) / distance) + temp_f20;
var_f12 = ((ydiff * speed) / distance) + temp_f22;
var_f14 = ((zdiff * speed) / distance) + temp_f24;
} else {
var_f2 = temp_f20;
var_f12 = temp_f22;
var_f14 = temp_f24;
}
pos[0] = var_f2;
pos[1] = var_f12;
pos[2] = var_f14;
return get_angle_between_path(sp54, pos);
}
s16 update_vehicle_following_path(Vec3f pos, s16* pathPointIndex, f32 speed) {
f32 origXPos;
f32 origYPos;
f32 origZPos;
UNUSED s32 stackPadding0;
UNUSED s32 stackPadding1;
UNUSED s32 stackPadding2;
UNUSED s32 stackPadding3;
UNUSED s32 stackPadding4;
UNUSED s32 stackPadding5;
UNUSED s32 stackPadding6;
UNUSED s32 stackPadding7;
UNUSED s32 stackPadding8;
f32 farPathPointAverageX;
f32 farPathPointAverageZ;
f32 x_dist;
f32 y_dist;
f32 distance;
f32 newX;
f32 newZ;
s16 newPathPointIndex;
s16 farPathPoint1;
s16 farPathPoint2;
Path2D* temp_a0;
Path2D* temp_a2;
Vec3f sp38;
origXPos = pos[0];
origYPos = pos[1];
origZPos = pos[2];
sp38[0] = pos[0];
sp38[1] = pos[1];
sp38[2] = pos[2];
newPathPointIndex = find_closest_vehicles_path_point(origXPos, origYPos, origZPos, *pathPointIndex);
*pathPointIndex = newPathPointIndex;
farPathPoint1 = (newPathPointIndex + 3) % gVehicle2DPathLength;
farPathPoint2 = (newPathPointIndex + 4) % gVehicle2DPathLength;
temp_a0 = &gVehicle2DPathPoint[farPathPoint1];
temp_a2 = &gVehicle2DPathPoint[farPathPoint2];
farPathPointAverageX = (temp_a0->x + temp_a2->x) * 0.5f;
farPathPointAverageZ = (temp_a0->z + temp_a2->z) * 0.5f;
x_dist = farPathPointAverageX - origXPos;
y_dist = farPathPointAverageZ - origZPos;
distance = sqrtf((x_dist * x_dist) + (y_dist * y_dist));
if (distance > 0.01f) {
newX = ((x_dist * speed) / distance) + origXPos;
newZ = ((y_dist * speed) / distance) + origZPos;
} else {
newX = origXPos;
newZ = origZPos;
}
pos[0] = newX;
pos[1] = origYPos;
pos[2] = newZ;
return get_angle_between_path(sp38, pos);
}