Fix the warning-flagged real bugs across the codebase (#691, 1 of 3) (#725)

* menu_items: fix the real-bug-tier compiler warnings (#691 batch 1)

Six fixes, all in menu_items.c, all verified by menu playtest on macOS:

- BSWAP16(*color0++) advanced the pointer twice per pixel on little-endian
  builds (the macro evaluates its argument twice) and mixed bytes from two
  different pixels. Read first, increment separately. Note: this function
  (func_8009A9FC) currently has no callers, so the corruption was latent,
  not live.
- func_8009B9D0 fell off the end on a lookup miss, returning garbage (the
  existing code comment already suspected this). The miss path now returns
  the display list head unchanged, i.e. draws nothing.
- update_ok_menu_item read an uninitialized stack slot for unknown menu
  item types; now selects an explicit no-animation value, matching what
  the garbage read did in practice.
- pause_menu_item_box_cursor: removed the three empty 'if (x2);' matching
  artifacts. The x/y/z spin state itself is untouched.
- func_800A1FB0: initialized var_s4/var_s5 against the guarded-but-warned
  switch default.
- func_800A54EC: initialized the pause cursor position pointer against its
  unreachable mode-switch default (would have been a null-deref class bug
  if mode values ever grew).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* collision: define the G_ENDDL opcode shifts, return 0 when no tyre surface found

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* replays: cast staff-ghost pointer comparisons, return 0 for empty ghost buffer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* update_objects: return 0 from conditional step helpers, fix TLUT pointer comparison, init train draw distances

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* render_player: remove the impossible lamp range (vanilla bug, never glowed on N64 either)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* math_util_2: return the vector, not the address of the parameter slot

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Crab: remove inner declaration shadowing the initialized objectIndex

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* editor: honor InverseMatrix failure (bool was compared against 2, always true)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Track.h: drop dead null checks on array members

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* shells: drop always-true angle and surface gates (behavior unchanged, s16 made them tautological)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* particles: make the no-return particle setters void

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* effects/stubs/skybox/main: align signatures with functions that return nothing

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* menus/save: type the pak status variable as s32, return BAD_READ on the fall-off path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* audio: remove uninitialized-read matching artifacts, init isSound

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* code_80005FD0/code_80086E70: init dead bomb kart pointer and the no_init variable

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* port/engine UI: fix printf-style format types and non-literal format string

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* render_objects: feed the unused texture param to the uninitialized img walker

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Format the changed lines per .clang-format

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Address review: strip explanatory comments, drop vec3f pointer returns

Comments moved to the PR record; the one flagged worth keeping stays.
vec3f_set_xyz/normalize/cross_product return void now since the out
argument is the interface and nothing used the pointer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Update actors_extended.c

* Add checkbox for 'Shells Shoot Straight' option

* Update render_player.c

* Update PortMenu.cpp

* Update render_player.c

* Update actors_extended.c

* Update render_player.c

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
This commit is contained in:
quarrel07
2026-08-01 23:29:56 -05:00
committed by GitHub
parent aa6c9c10ca
commit 8629bec320
41 changed files with 192 additions and 145 deletions
+1 -2
View File
@@ -186,8 +186,7 @@ s16 func_802B3FD0(Player* owner, struct ShellActor* shell) {
}
void func_802B4104(struct ShellActor* shell) {
if ((shell->unk30.surfaceDistance[0] < 0.0f) &&
((shell->unk30.unk48[1] < 0.25f) || (shell->unk30.unk48[1] > -0.25f))) {
if (shell->unk30.surfaceDistance[0] < 0.0f) {
destroy_destructable_actor((struct Actor*) shell);
func_800C98B8(shell->pos, shell->velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x54));
shell->flags |= 0x80;
-1
View File
@@ -1966,7 +1966,6 @@ void func_800C6108(u8 playerId) {
D_800E9E64[playerId] = (player->unk_098 / D_800E9DC4[playerId]) + D_800E9DD4[playerId];
if ((player->unk_098 < 1800.0f) && ((player->kartProps & THROTTLE) != THROTTLE)) {
D_800E9E64[playerId] = (player->unk_098 / D_800E9F7C[playerId].unk_34) + D_800E9F7C[playerId].unk_28;
if (D_800E9EC4) {} // ?
}
if (player->speed > 4.75f) {
if (D_800E9EB4[playerId] < (D_800E9F7C[playerId].unk_18 + 0.4f)) {
+1 -3
View File
@@ -246,7 +246,7 @@ void* alloc_bank_or_seq(struct SoundMultiPool* arg0, s32 arg1, s32 size, s32 arg
u16 secondVal;
s32 var_v1_2;
u8* table;
u8 isSound;
u8 isSound = 0;
if (arg3 == 0) {
tp = &arg0->temporary;
@@ -254,8 +254,6 @@ void* alloc_bank_or_seq(struct SoundMultiPool* arg0, s32 arg1, s32 size, s32 arg
if (arg0 == &gSeqLoadedPool) {
table = gSeqLoadStatus; isSound = 0;
} else {
// wtf?
firstVal += 0;
if (arg0 == &gBankLoadedPool) {
isSound = 1; table = gBankLoadStatus;
} else if (arg0 == &gUnusedLoadedPool) {
-2
View File
@@ -168,8 +168,6 @@ struct SPTask* create_next_audio_frame_task(void) {
index = gAudioTaskIndex;
gAudioTask->msgqueue = NULL;
// wtf?
writtenCmdsCopy += 0;
gAudioTask->msg.ptr = NULL;
task = &gAudioTask->task.t;
+1
View File
@@ -2989,6 +2989,7 @@ void set_bomb_kart_spawn_positions(void) {
BombKartSpawn* bombKartSpawn;
for (var_s3 = 0; var_s3 < NUM_BOMB_KARTS_VERSUS; var_s3++) {
bombKartSpawn = NULL;
// bombKartSpawn = &gBombKartSpawns[gCurrentCourseId][var_s3];
if (IsYoshiValley()) {
startingXPos = bombKartSpawn->startingXPos;
+3 -3
View File
@@ -2545,21 +2545,21 @@ void set_particle_position_and_rotation(Player* player, UnkPlayerStruct258* arg1
arg1->unk_010 = arg6;
}
s32 init_particle_player(UnkPlayerStruct258* arg0, s8 type, f32 arg2) {
void init_particle_player(UnkPlayerStruct258* arg0, s8 type, f32 arg2) {
arg0->isAlive = true;
arg0->type = type;
arg0->unk_01E = 0;
arg0->scale = arg2;
}
s32 set_particle_colour(UnkPlayerStruct258* arg0, s32 arg1, s16 arg2) {
void set_particle_colour(UnkPlayerStruct258* arg0, s32 arg1, s16 arg2) {
arg0->red = (u8) (arg1 >> 16);
arg0->green = (u8) (arg1 >> 8);
arg0->blue = (u8) arg1;
arg0->alpha = arg2;
}
s32 set_particle_colour_randomly_varried(UnkPlayerStruct258* arg0, s32 arg1, s16 arg2) {
void set_particle_colour_randomly_varried(UnkPlayerStruct258* arg0, s32 arg1, s16 arg2) {
s32 temp_v0;
temp_v0 = random_int(0x30);
+3 -3
View File
@@ -115,9 +115,9 @@ void func_8005D1F4(s32);
void func_8005D290(void);
void reset_player_particle_pool(Player*);
void set_particle_position_and_rotation(Player*, UnkPlayerStruct258*, f32, f32, f32, s8, s8);
s32 init_particle_player(UnkPlayerStruct258*, s8, f32);
s32 set_particle_colour(UnkPlayerStruct258*, s32, s16);
s32 set_particle_colour_randomly_varried(UnkPlayerStruct258*, s32, s16);
void init_particle_player(UnkPlayerStruct258*, s8, f32);
void set_particle_colour(UnkPlayerStruct258*, s32, s16);
void set_particle_colour_randomly_varried(UnkPlayerStruct258*, s32, s16);
void set_drift_particles(Player*, s16, s32, s8, s8);
void check_drift_particles_setup_valid(Player*, s16, s32, s8, s8);
void func_8005DAD0(void);
+1 -1
View File
@@ -1331,7 +1331,7 @@ void func_8008A1D0(s32 objectIndex, s32 cameraId, s32 arg2, s32 arg3) {
// This function is really cool, it tests the value of an unitialized local variable
UNUSED void func_8008A2CC(s32 objectIndex, s32 cameraId, u16 arg2) {
Camera* camera;
u32 no_init;
u32 no_init = 0;
u16 var_a2;
camera = &camera1[cameraId];
+1 -1
View File
@@ -29,7 +29,7 @@ s32 D_8018D990[8];
UNUSED void func_unnamed(void) {
}
s32 func_8008C1D8(UNUSED s32* arg0) {
void func_8008C1D8(UNUSED s32* arg0) {
}
void func_8008C1E0(UNUSED s32* arg0, UNUSED s32 arg1) {
+1 -1
View File
@@ -6,7 +6,7 @@
/* Function Prototypes */
void func_unnamed(void);
s32 func_8008C1D8(s32*);
void func_8008C1D8(s32*);
void func_8008C1E0(s32*, s32);
void func_unnamed1(s32);
void func_unnamed2(s32);
+3 -3
View File
@@ -65,13 +65,13 @@ FVector ScreenRayTrace() {
guPerspectiveF(perspMtx, &perspNorm, camera->fieldOfView, OTRGetAspectRatio(), CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
Mat4 inversePerspMtx;
if (InverseMatrix((float*)&perspMtx, (float*)&inversePerspMtx) != 2) {
if (InverseMatrix((float*) &perspMtx, (float*) &inversePerspMtx)) {
FVector4 rayEye = MultiplyMatrixVector(inversePerspMtx, (float*)&rayClip.x);
Mat4 lookAtMtx;
guLookAtF(lookAtMtx, camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0], camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]);
Mat4 inverseViewMtx;
if (InverseMatrix((float*)&lookAtMtx, (float*)&inverseViewMtx[0][0]) != 2) {
if (InverseMatrix((float*) &lookAtMtx, (float*) &inverseViewMtx[0][0])) {
rayEye.w = 0;
FVector4 invRayWor = MultiplyMatrixVector(inverseViewMtx, (float*)&rayEye.x);
@@ -206,7 +206,7 @@ FVector TransformVecDirection(const FVector& dir, const float mtx[4][4]) {
Ray RayToLocalSpace(MtxF mtx, const Ray& ray) {
MtxF inverse;
if (InverseMatrix((float*)&mtx, (float*)&inverse) != 2) {
if (InverseMatrix((float*) &mtx, (float*) &inverse)) {
FVector localRayOrigin = TransformVecByMatrix(ray.Origin, (float(*)[4])&inverse);
FVector localRayDir = TransformVecDirection(ray.Direction, (float(*)[4])&inverse);
return Ray{localRayOrigin, localRayDir.Normalize()};
-1
View File
@@ -100,7 +100,6 @@ void OCrab::DrawModel(s32 cameraId) {
func_8008A364(objectIndex, cameraId, 0x2AABU, 800);
if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) {
Camera* camera;
s32 objectIndex;
if (gObjectList[objectIndex].state >= 2) {
camera = &camera1[cameraId];
+3 -3
View File
@@ -120,9 +120,9 @@ typedef struct Properties {
#ifdef __cplusplus
nlohmann::json to_json() const {
nlohmann::json j;
j["Name"] = Name ? Name : "";
j["DebugName"] = DebugName ? DebugName : "";
j["TrackLength"] = TrackLength ? TrackLength : "";
j["Name"] = Name;
j["DebugName"] = DebugName;
j["TrackLength"] = TrackLength;
//j["AIBehaviour"] = AIBehaviour ? AIBehaviour : "";
j["LakituTowType"] = LakituTowType;
j["AIMaximumSeparation"] = AIMaximumSeparation;
+1 -1
View File
@@ -40,7 +40,7 @@ ABus::ABus(const SpawnParams& params) : AActor(params) {
BusCounts[PathIndex].push_back(PathPoint);
break;
case SpawnMode::AUTO: // Automatically distribute buses based on a specific path point
printf("vehicle path size %d\n", gVehiclePathSize);
printf("vehicle path size %zu\n", gVehiclePathSize);
PathPoint = GetVehiclePathPointDistributed(BusCounts[PathIndex], gVehiclePathSize);
BusCounts[PathIndex].push_back(PathPoint);
printf("train spawn path point: %d\n", PathPoint);
+1 -1
View File
@@ -41,7 +41,7 @@ ACar::ACar(const SpawnParams& params) : AActor(params) {
CarCounts[PathIndex].push_back(PathPoint);
break;
case SpawnMode::AUTO: // Automatically distribute cars based on a specific path point
printf("vehicle path size %d\n", gVehiclePathSize);
printf("vehicle path size %zu\n", gVehiclePathSize);
PathPoint = GetVehiclePathPointDistributed(CarCounts[PathIndex], gVehiclePathSize);
CarCounts[PathIndex].push_back(PathPoint);
printf("train spawn path point: %d\n", PathPoint);
+1 -1
View File
@@ -40,7 +40,7 @@ ATankerTruck::ATankerTruck(const SpawnParams& params) : AActor(params) {
TruckCounts[PathIndex].push_back(PathPoint);
break;
case SpawnMode::AUTO: // Automatically distribute trucks based on a specific path point
printf("vehicle path size %d\n", gVehiclePathSize);
printf("vehicle path size %zu\n", gVehiclePathSize);
PathPoint = GetVehiclePathPointDistributed(TruckCounts[PathIndex], gVehiclePathSize);
TruckCounts[PathIndex].push_back(PathPoint);
printf("train spawn path point: %d\n", PathPoint);
+1 -1
View File
@@ -57,7 +57,7 @@ ATrain::ATrain(const SpawnParams& params) : AActor(params) {
TrainCounts[pathIndex].push_back(pathPoint);
break;
case SpawnMode::AUTO: // Automatically distribute trains based on a specific path point
printf("vehicle path size %d\n", gVehiclePathSize);
printf("vehicle path size %zu\n", gVehiclePathSize);
pathPoint = GetVehiclePathPointDistributed(TrainCounts[pathIndex], gVehiclePathSize);
TrainCounts[pathIndex].push_back(pathPoint);
printf("train spawn path point: %d\n", pathPoint);
+1 -1
View File
@@ -40,7 +40,7 @@ ATruck::ATruck(const SpawnParams& params) : AActor(params) {
TruckCounts[PathIndex].push_back(PathPoint);
break;
case SpawnMode::AUTO: // Automatically distribute trucks based on a specific path point
printf("vehicle path size %d\n", gVehiclePathSize);
printf("vehicle path size %zu\n", gVehiclePathSize);
PathPoint = GetVehiclePathPointDistributed(TruckCounts[PathIndex], gVehiclePathSize);
TruckCounts[PathIndex].push_back(PathPoint);
printf("train spawn path point: %d\n", PathPoint);
+1 -1
View File
@@ -458,7 +458,7 @@ void end_master_display_list(void) {
// clear_frame_buffer from SM64, with a few edits
//! @todo Why did void* work for matching
void* clear_framebuffer(s32 color) {
void clear_framebuffer(s32 color) {
gDPPipeSync(gDisplayListHead++);
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
+1 -1
View File
@@ -77,7 +77,7 @@ void dispatch_audio_sptask(struct SPTask*);
void exec_display_list(struct SPTask*);
void init_rcp(void);
void end_master_display_list(void);
void* clear_framebuffer(s32);
void clear_framebuffer(s32);
void rendering_init(void);
void config_gfx_pool(void);
void display_and_vsync(void);
+3 -7
View File
@@ -332,29 +332,25 @@ s32 f32_step_towards(f32* value, f32 target, f32 step) {
return targetReached;
}
Vec3f* vec3f_set_xyz(Vec3f arg0, f32 arg1, f32 arg2, f32 arg3) {
void vec3f_set_xyz(Vec3f arg0, f32 arg1, f32 arg2, f32 arg3) {
arg0[0] = arg1;
arg0[1] = arg2;
arg0[2] = arg3;
return (Vec3f*) &arg0;
}
Vec3f* vec3f_normalize(Vec3f dest) {
void vec3f_normalize(Vec3f dest) {
f32 invsqrt = 1.0f / sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]);
dest[0] = dest[0] * invsqrt;
dest[1] = dest[1] * invsqrt;
dest[2] = dest[2] * invsqrt;
return (Vec3f*) &dest;
}
Vec3f* vec3f_cross_product(Vec3f dest, Vec3f arg1, Vec3f arg2) {
void vec3f_cross_product(Vec3f dest, Vec3f arg1, Vec3f arg2) {
dest[0] = (arg1[1] * arg2[2]) - (arg2[1] * arg1[2]);
dest[1] = (arg1[2] * arg2[0]) - (arg2[2] * arg1[0]);
dest[2] = (arg1[0] * arg2[1]) - (arg2[0] * arg1[1]);
return (Vec3f*) &dest;
}
UNUSED s32 is_within_distance_2d(f32 x1, f32 y1, f32 x2, f32 y2, f32 distance) {
+3 -3
View File
@@ -49,9 +49,9 @@ s32 s16_step_down_towards(s16*, s16, s16);
s32 u16_step_down_towards(u16*, s32, s32);
s32 s16_step_towards(s16*, s16, s16);
s32 f32_step_towards(f32*, f32, f32);
Vec3f* vec3f_set_xyz(Vec3f, f32, f32, f32);
Vec3f* vec3f_normalize(Vec3f dest);
Vec3f* vec3f_cross_product(Vec3f, Vec3f, Vec3f);
void vec3f_set_xyz(Vec3f, f32, f32, f32);
void vec3f_normalize(Vec3f dest);
void vec3f_cross_product(Vec3f, Vec3f, Vec3f);
s32 func_80041658(f32, f32);
f32 func_800416D8(f32 x, f32 z, u16 angle);
f32 func_80041724(f32, f32, u16);
+11 -13
View File
@@ -4314,7 +4314,8 @@ void func_8009A9FC(s32 arg0, s32 arg1, u32 arg2, s32 arg3) {
color0 = LOAD_ASSET(sMenuTextureList[sMenuTextureMap[arg0].offset]);
color1 = LOAD_ASSET(sMenuTextureList[sMenuTextureMap[arg1].offset]);
for (size_t i = 0; i < arg2; i++) {
temp_a0 = BSWAP16(*color0++);
temp_a0 = BSWAP16(*color0);
color0++;
red = (temp_a0 & 0xF800) >> 0xB;
green = (temp_a0 & 0x7C0) >> 6;
blue = (temp_a0 & 0x3E) >> 1;
@@ -4529,8 +4530,9 @@ Gfx* func_8009B9D0(Gfx* displayListHead, MenuTexture* textures) {
}
if (found) {
gSPDisplayList(displayListHead++, displayList);
return displayListHead;
}
// Texture not found: draw nothing.
return displayListHead;
}
Gfx* render_menu_textures(Gfx* arg0, MenuTexture* arg1, s32 column, s32 row) {
@@ -7388,8 +7390,8 @@ void func_800A1F30(UNUSED MenuItem* unused) {
void func_800A1FB0(MenuItem* arg0) {
Unk_D_800E70A0 spE0 = { 0 };
s32 i;
s32 var_s5;
s32 var_s4;
s32 var_s5 = SUB_MENU_COPY_PAK_FROM_GHOST_MIN;
s32 var_s4 = 0;
char spB8[3];
s32 var_s1;
char spA8[3];
@@ -8441,7 +8443,8 @@ void render_pause_battle(MenuItem* arg0) {
void func_800A54EC(void) {
Unk_D_800E70A0 sp50;
Unk_D_800E70A0* var_v1;
// Initialized against the (unreachable) default of the mode switch below.
Unk_D_800E70A0* var_v1 = &D_800E8538[0];
MenuItem* sp48;
s32 whyTheSequel;
s32 why;
@@ -8768,12 +8771,6 @@ void pause_menu_item_box_cursor(MenuItem* arg0, Unk_D_800E70A0* arg1) {
y2 += y1;
z2 += z1;
// clang-format off
if (x2);
if (y2);
if (z2);
// clang-format on
guScale(mtx, 1.2f, 1.2f, 1.2f);
guRotate(mtx2, y2, 0.0f, 1.0f, 0.0f);
guMtxCatL(mtx, mtx2, mtx);
@@ -10074,12 +10071,13 @@ const s8 D_800F0CA0[] = {
};
void update_ok_menu_item(MenuItem* arg0) {
s32 sp4;
s32 var_v0;
switch (arg0->type) {
default:
var_v0 = sp4; // wut?
// Was an uninitialized read; -1 hits no animation case below,
// which is what the garbage value did in practice.
var_v0 = -1;
break;
case MENU_ITEM_UI_OK:
var_v0 = D_800F0CA0[gMainMenuSelection - 1];
+1 -1
View File
@@ -238,7 +238,7 @@ void options_menu_act(struct Controller* controller, u16 controllerIdx) {
MenuItem* sp38;
s32 res;
struct_8018EE10_entry* sp30;
bool tempVar; // cursorWasMoved or communicateStoredAction
s32 tempVar; // cursorWasMoved or communicateStoredAction; also holds PFS_* status codes
UNUSED u32 pad;
btnAndStick = (controller->buttonPressed | controller->stickPressed);
+1 -3
View File
@@ -3824,9 +3824,7 @@ void func_80033AE0(Player* player, struct Controller* controller, s8 arg2) {
func_8002BD58(player);
}
player->effects &= 0xDFFFFFFF;
if (((s32) player->tyres[BACK_RIGHT].surfaceType) > 0xE) {
var_f12 = var_f12;
} else {
if (((s32) player->tyres[BACK_RIGHT].surfaceType) <= 0xE) {
var_f12 += D_800E3410[player->characterId][player->tyres[BACK_RIGHT].surfaceType];
}
if (((s32) player->tyres[BACK_LEFT].surfaceType) < 0xF) {
+1
View File
@@ -288,6 +288,7 @@ s32 CM_GetCrossingOnTriggered(uintptr_t* crossing) {
if (ptr) {
return ptr->OnTriggered;
}
return 0;
}
/**
+1
View File
@@ -333,5 +333,6 @@ void ContentBrowserWindow::AddActorContent(std::string search) {
}
}
ImGui::End();
return nullptr;
}
}
+6
View File
@@ -405,6 +405,9 @@ void PortMenu::AddEnhancements() {
AddWidget(path, "Enable Look Behind Camera", WIDGET_CVAR_CHECKBOX)
.CVar("gLookBehind")
.Options(CheckboxOptions().Tooltip("Press C-Left to look behind you"));
AddWidget(path, "Fix Visuals", WIDGET_CVAR_CHECKBOX)
.CVar("gFixVisuals")
.Options(CheckboxOptions().Tooltip("Fixes the second last lamp glow in Banshee Boardwalk"));
AddRulesets();
@@ -464,6 +467,9 @@ void PortMenu::AddRulesets() {
.CVar("gGoFish")
.Options(CheckboxOptions().Tooltip(
"Collect as many trophies as you can. Racer with the most trophies wins!"));
AddWidget(path, "Shells Shoot Straight", WIDGET_CVAR_CHECKBOX)
.CVar("gShellsShootStraight")
.Options(CheckboxOptions().Tooltip("Fixes a logic bug in the game code. No evidence if this is intended gameplay or not."));
AddWidget(path, "Track X Stretch", WIDGET_SLIDER_FLOAT)
.ValuePointer(&gVtxStretch[0])
.Options(UIWidgets::FloatSliderOptions().Min(0.1f).Max(10.0f).Step(0.1f).Format("%.2f"));
+1 -1
View File
@@ -61,7 +61,7 @@ namespace TrackEditor {
ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f);
// Display actor title
ImGui::Text(title);
ImGui::Text("%s", title);
// Display actor resource name. ex. mk:cloud
if (obj->ResourceName[0] != '\0') { // Params is unset for some train components
+3 -3
View File
@@ -389,15 +389,15 @@ namespace TrackEditor {
RGB8ToFloat((u8*)&D_800DC610[i].l->l.dir, direction);
// Edit the ambient RGB colour
ImGui::Text("Light %d - Ambient Colour", i + 1);
ImGui::Text("Light %zu - Ambient Colour", i + 1);
ImGui::ColorEdit3(("Ambient Colour " + std::to_string(i)).c_str(), ambient); // Modify ambient colour
// Edit the diffuse RGB colour
ImGui::Text("Light %d - Diffuse Colour", i + 1);
ImGui::Text("Light %zu - Diffuse Colour", i + 1);
ImGui::ColorEdit3(("Diffuse Colour " + std::to_string(i)).c_str(), diffuse); // Modify diffuse colour
// Edit the direction RGB colour (this could be represented as a direction vector)
ImGui::Text("Light %d - Direction", i + 1);
ImGui::Text("Light %zu - Direction", i + 1);
ImGui::ColorEdit3(("Direction Colour " + std::to_string(i)).c_str(), direction); // Modify direction vector colour
FloatToRGB8(ambient, (u8*)&D_800DC610[i].a.l.col);
+86 -63
View File
@@ -438,81 +438,104 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) {
if (parent->firePressed > 0.0f) { // Fires a shell and resets firePressed to zero
if (parent->shellIndices[0] > 0.0f) {
shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[0]);
if ((shell->rotAngle < 0x38E) || (shell->rotAngle >= -0x38D)) {
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[0]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[0]);
/**
* Below is a feature that continues holding triple shells until they are aiming forward.
* In decomp the three gShellsShootStraight conditions always evaluated to true,
* thus negating the feature from ever working.
* It has been re-added in for experimental purposes with slight adjustments
* to behave correctly and for clean code.
*/
if (CVarGetInteger("gShellsShootStraight", 0)) {
// Forces shell 1 to fire inside a cone of -5 to +5 degrees
if ((shell->rotAngle < -0x38E) || (shell->rotAngle > 0x38E)) {
break;
}
parent->shellIndices[0] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[0]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[0]);
}
parent->shellIndices[0] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
if (parent->shellIndices[1] > 0.0f) {
shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[1]);
if ((shell->rotAngle < 0xAA1) || (shell->rotAngle >= 0x38F)) {
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[1]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[1]);
if (CVarGetInteger("gShellsShootStraight", 0)) {
// Forces shell 2 to fire inside a cone of 5 to 14.95 degrees
if ((shell->rotAngle < 0x38E) || (shell->rotAngle > 0xAA1)) {
break;
}
parent->shellIndices[1] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[1]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[1]);
}
parent->shellIndices[1] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
if (parent->shellIndices[2] > 0.0f) {
shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[2]);
if ((shell->rotAngle < -0x38E) || (shell->rotAngle >= -0x71B)) {
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[2]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[2]);
if (CVarGetInteger("gShellsShootStraight", 0)) {
/**
* Forces shell 3 to fire inside a cone of -5 to -14.95 degrees
* -0xAA1 was originally -10 degrees (0x71C). However,
* shell 3 would continue looping for a bit so it's been adjusted to mirror shell 2
*/
if ((shell->rotAngle < -0xAA1) || (shell->rotAngle > -0x38E)) {
break;
}
parent->shellIndices[2] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
someVelocity[0] = 0;
someVelocity[1] = 0;
someVelocity[2] = 8;
func_802B64C4(someVelocity, player->rotation[1] + player->unk_0C0);
shell->velocity[0] = someVelocity[0];
shell->velocity[1] = someVelocity[1];
shell->velocity[2] = someVelocity[2];
shell->state = MOVING_SHELL;
shell->someTimer = 0x001E;
func_800C9060(parent->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04));
func_800C90F4(parent->playerId,
(player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00));
if (parent->type == ACTOR_TRIPLE_RED_SHELL) {
add_red_shell_in_unexpired_actor_list(parent->shellIndices[2]);
} else {
add_green_shell_in_unexpired_actor_list(parent->shellIndices[2]);
}
parent->shellIndices[2] = -1.0f;
parent->shellsAvailable -= 1;
parent->firePressed -= 1.0f;
break;
}
}
break;
+6 -6
View File
@@ -24,7 +24,7 @@ void nullify_displaylist(uintptr_t addr) {
Gfx* macro;
macro = (Gfx*) addr;
macro->words.w0 = (G_ENDDL << 24);
macro->words.w0 = ((u32) (G_ENDDL & 0xFF) << 24);
macro->words.w1 = 0;
}
@@ -689,10 +689,10 @@ UNUSED s32 detect_tyre_collision(KartTyre* tyre) {
}
tyre->baseHeight = tyreY;
tyre->surfaceType = 0;
//! @bug
// Another function that has a return value but doesn't have an explicit return statement in one of its codepaths.
// The return value at this point will be whatever was last returned by func_802AAE4C/func_802AB6C4/func_802AB288
// depending on which (if any) if statements were entered on the loop's last cycle
// Used to fall off the end here (see git history for the original @bug
// note): the return value was whatever the last helper call left behind.
// No surface was found, so report no collision.
return 0;
}
s32 is_colliding_with_drivable_surface(struct Collision* collision, f32 boundingBoxSize, f32 newX, f32 newY, f32 newZ,
@@ -2187,7 +2187,7 @@ void find_vtx_and_set_colours(Gfx* displayList, s8 alpha, u8 red, u8 green, u8 b
lo = gfx->words.w0;
hi = gfx->words.w1;
opcode = GFX_GET_OPCODE(lo);
if (opcode == (G_ENDDL << 24)) {
if (opcode == ((u32) (G_ENDDL & 0xFF) << 24)) {
break;
} else if (opcode == (G_DL << 24)) {
find_vtx_and_set_colours((Gfx*) hi, alpha, red, green, blue);
+3 -2
View File
@@ -257,7 +257,7 @@ UNUSED void func_802A40D4(void) {
UNUSED void func_802A40DC(void) {
}
UNUSED s32 set_viewport2(void) {
UNUSED void set_viewport2(void) {
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gScreenOneCtx->viewport));
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++,
@@ -623,7 +623,8 @@ void render_screens(ScreenContext* screen, s32 mode, s32 someId, s32 playerId) {
s32 screenId = screen - gScreenContexts;
if (NULL == camera) {
printf("[skybox_and_splitscreen.c] Skipping rendering for screen %d. This viewport has no camera\n", screen - gScreenContexts);
printf("[skybox_and_splitscreen.c] Skipping rendering for screen %ld. This viewport has no camera\n",
(long) (screen - gScreenContexts));
return;
}
+1 -1
View File
@@ -26,7 +26,7 @@ void func_802A40C4(void);
void func_802A40CC(void);
void func_802A40D4(void);
void func_802A40DC(void);
s32 set_viewport2(void);
void set_viewport2(void);
void set_viewport(void);
void select_framebuffer(void);
void func_802A4300(void);
+4 -2
View File
@@ -2181,11 +2181,13 @@ UNUSED void func_8004CD18(s32 arg0, s32 arg1, u8* texture) {
func_8004C91C(arg0, arg1, texture, 64, 64, 32);
}
UNUSED void func_8004CD48(s32 arg0, s32 arg1, UNUSED u8* texture, s32 width, s32 arg4, s32 height) {
UNUSED void func_8004CD48(s32 arg0, s32 arg1, u8* texture, s32 width, s32 arg4, s32 height) {
UNUSED s32 pad;
s32 var_s0;
s32 i;
u8* img;
// img was never initialized; the (formerly UNUSED) texture param is
// clearly what the loop was meant to walk.
u8* img = texture;
var_s0 = arg1 - (arg4 / 2);
gSPDisplayList(gDisplayListHead++, D_0D007FE0);
+13 -1
View File
@@ -1021,6 +1021,18 @@ void render_light_environment_on_player(Player* player, s8 arg1) {
D_80164B80[arg1] = 0;
}
} else if (IsBansheeBoardwalk()) {
/**
* @bug For the second last lamp
*
* The condition for this lamp does not work, and if it did,
* the lamp area extends nearly to the finishline.
* This adjustment places the lamp glow into a suitable area
*/
s16 bugFix = 0x288; // Original game value
if (CVarGetInteger("gFixVisuals", 0)) {
bugFix = 0x25F; // Bug fix
}
if (((gNearestPathPointByPlayerId[arg1] >= 0xD) && (gNearestPathPointByPlayerId[arg1] < 0x15)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x29) && (gNearestPathPointByPlayerId[arg1] < 0x39)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x46) && (gNearestPathPointByPlayerId[arg1] < 0x4E)) ||
@@ -1037,7 +1049,7 @@ void render_light_environment_on_player(Player* player, s8 arg1) {
((gNearestPathPointByPlayerId[arg1] >= 0x216) && (gNearestPathPointByPlayerId[arg1] < 0x21D)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x230) && (gNearestPathPointByPlayerId[arg1] < 0x23A)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x24C) && (gNearestPathPointByPlayerId[arg1] < 0x256)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x288) && (gNearestPathPointByPlayerId[arg1] < 0x269)) ||
((gNearestPathPointByPlayerId[arg1] >= bugFix) && (gNearestPathPointByPlayerId[arg1] < 0x269)) ||
((gNearestPathPointByPlayerId[arg1] >= 0x274) &&
(gNearestPathPointByPlayerId[arg1] < 0x27E))) { // under a lamp
change_player_color_effect_rgb(player, arg1, COLOR_LIGHT, 0.3f);
+6 -3
View File
@@ -72,11 +72,11 @@ void load_course_ghost(void) {
u8* ghost = (u8*) D_80162DC4;
size_t size = 0;
if (ghost == d_luigi_raceway_staff_ghost) {
if (ghost == (u8*) d_luigi_raceway_staff_ghost) {
size = 1046 * sizeof(StaffGhost);
} else if (ghost == d_mario_raceway_staff_ghost) {
} else if (ghost == (u8*) d_mario_raceway_staff_ghost) {
size = 935 * sizeof(StaffGhost);
} else if (ghost == d_royal_raceway_staff_ghost) {
} else if (ghost == (u8*) d_royal_raceway_staff_ghost) {
size = 1907 * sizeof(StaffGhost);
}
@@ -135,6 +135,9 @@ s32 func_800051C4(void) {
mio0encode((s32) sReplayGhostEncoded, (sReplayGhostBufferSize * 4) + 0x20, (s32) gReplayGhostCompressed);
return phi_v0 + 0x1e;
}
// Empty buffer used to fall off the end; report zero encoded size (the
// caller only checks this against an upper bound).
return 0;
}
void func_8000522C(void) {
+3
View File
@@ -689,6 +689,9 @@ s32 controller_pak_2_status(void) {
return PFS_PAK_BAD_READ;
}
}
// Reached when the pak was just marked BAD above; used to fall off the
// end and return garbage.
return PFS_PAK_BAD_READ;
}
s32 func_800B5F30(void) {
+6 -2
View File
@@ -1325,7 +1325,9 @@ void spawn_multiplayer_cameras(u32 mode) {
Vec3f spawn = {gPlayers[i].pos[0], gPlayers[i].pos[1], gPlayers[i].pos[2]};
camera = CM_AddCamera(spawn, gPlayers[i].rotation[1], mode);
if (!camera) {
CM_ThrowRuntimeError("[spawn_players] [spawn_multiplayer_cameras] NULL camera while attempting to create camera for player %d", i);
CM_ThrowRuntimeError("[spawn_players] [spawn_multiplayer_cameras] NULL camera while attempting to create "
"camera for player %zu",
i);
}
CM_AttachCamera(camera, i);
gScreenContexts[i].camera = camera;
@@ -1336,7 +1338,9 @@ void spawn_multiplayer_cameras(u32 mode) {
Vec3f spawn = {gPlayers[i].pos[0], gPlayers[i].pos[1], gPlayers[i].pos[2]};
camera = CM_AddLookBehindCamera(spawn, gPlayers[i].rotation[1], mode);
if (!camera) {
CM_ThrowRuntimeError("[spawn_players] [spawn_multiplayer_cameras] NULL camera while attempting to create LookBehind camera for player %d", i);
CM_ThrowRuntimeError("[spawn_players] [spawn_multiplayer_cameras] NULL camera while attempting to create "
"LookBehind camera for player %zu",
i);
}
CM_AttachCamera(camera, i);
gScreenContexts[i].lookBehindCamera = camera;
+1
View File
@@ -62,4 +62,5 @@ void osSpTaskYield(void) {
}
OSYieldResult osSpTaskYielded(OSTask* task) {
return 0;
}
+7 -3
View File
@@ -943,6 +943,7 @@ s32 func_80073B34(s32 arg0, s16* arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s
if (arg3 < *arg1) {
return func_80073A10(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
return 0;
}
bool func_80073B78(s32 arg0, s32 objectIndex, s16* arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7) {
@@ -1112,6 +1113,7 @@ s32 func_8007415C(s32 objectIndex, f32* arg1, f32 arg2, f32 arg3, f32 arg4, s32
if (*arg1 < arg3) {
return func_8007401C(objectIndex, arg1, arg2, arg3, arg4, arg5, arg6);
}
return 0;
}
s32 func_800741B4(s32 objectIndex, f32* arg1, f32 arg2, f32 arg3, f32 arg4, s32 arg5, s32 arg6) {
@@ -1223,7 +1225,7 @@ void func_800745C8(s32 objectIndex, const char** lakituTexturePtr) {
if ((gObjectList[objectIndex].status & 1) != 0) {
phi_a1 = 0;
if (gObjectList[objectIndex].tlutList != gObjectList[objectIndex].activeTLUT) {
if (gObjectList[objectIndex].tlutList != (const u8*) gObjectList[objectIndex].activeTLUT) {
gObjectList[objectIndex].activeTLUT = gObjectList[objectIndex].tlutList;
}
@@ -2910,7 +2912,8 @@ void func_8007D714(s32 arg0) {
}
void func_8007DDC0(s32 objectIndex) {
f32 sp2C;
// Initialized for the non-race CC modes the switch below doesn't cover.
f32 sp2C = 1150.0f;
Object* object;
object = &gObjectList[objectIndex];
@@ -2951,7 +2954,8 @@ void func_8007DDC0(s32 objectIndex) {
}
void func_8007E1F4(s32 objectIndex) {
f32 sp2C;
// Initialized for the non-race CC modes the check below doesn't cover.
f32 sp2C = 700.0f;
Object* object;
object = &gObjectList[objectIndex];