Files
SpaghettiKart/src/engine/objects/Crab.cpp
T
quarrel07 8629bec320 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>
2026-08-01 22:29:56 -06:00

235 lines
8.6 KiB
C++

#include <libultraship.h>
#include <libultra/gbi.h>
#include "Crab.h"
#include <vector>
#include "engine/CoreMath.h"
#include "port/Game.h"
#include "port/interpolation/FrameInterpolation.h"
extern "C" {
#include "macros.h"
#include "main.h"
#include "defines.h"
#include "camera.h"
#include "update_objects.h"
#include "render_objects.h"
#include "racing/actors.h"
#include "code_80057C60.h"
#include "code_80086E70.h"
#include "racing/math_util.h"
#include "math_util_2.h"
#include "code_80005FD0.h"
#include "textures/some_data.h"
#include "ending/ceremony_and_credits.h"
#include "assets/models/tracks/koopa_troopa_beach/koopa_troopa_beach_data.h"
#include "assets/textures/tracks/koopa_troopa_beach/koopa_troopa_beach_data.h"
#include "assets/models/common_data.h"
}
size_t OCrab::_count = 0;
OCrab::OCrab(const SpawnParams& params) : OObject(params) {
Name = "Crab";
ResourceName = "mk:crab";
_idx = _count;
_start = params.PatrolStart.value_or(FVector2D(0, 0));
_end = params.PatrolEnd.value_or(FVector2D(0, 0));
find_unused_obj_index(&_objectIndex);
init_object(_objectIndex, 0);
gObjectList[_objectIndex].pos[0] = gObjectList[_objectIndex].origin_pos[0] = _start.x * xOrientation;
gObjectList[_objectIndex].pos[2] = gObjectList[_objectIndex].origin_pos[2] = _start.z;
gObjectList[_objectIndex].unk_01C[0] = _end.x * xOrientation;
gObjectList[_objectIndex].unk_01C[2] = _end.z;
_count++;
}
void OCrab::SetSpawnParams(SpawnParams& params) {
params.Name = std::string(ResourceName);
params.PatrolStart = _start;
params.PatrolEnd = _end;
}
void OCrab::Tick(void) {
s32 objectIndex = _objectIndex;
if (gObjectList[objectIndex].state != 0) {
OCrab::func_80082B34(objectIndex);
func_8008A6DC(objectIndex, 500.0f);
OCrab::func_80082C30(objectIndex);
OCrab::func_80082E18(objectIndex);
}
}
Vtx common_vtx_crab[] = {
{ { { -32, -31, 0 }, 0, { 0, 0 }, { 255, 255, 255, 255 } } },
{ { { 31, -31, 0 }, 0, { 4032, 0 }, { 255, 255, 255, 255 } } },
{ { { 31, 31, 0 }, 0, { 4032, 3968 }, { 255, 255, 255, 255 } } },
{ { { -32, 31, 0 }, 0, { 0, 3968 }, { 255, 255, 255, 255 } } },
};
void OCrab::Draw(s32 cameraId) {
Camera* camera;
s32 objectIndex = _objectIndex;
if (gObjectList[objectIndex].state >= 2) {
camera = &camera1[cameraId];
FrameInterpolation_RecordOpenChild("crab", (_idx << 5) | cameraId);
func_8004A6EC(objectIndex, 0.5f);
FrameInterpolation_RecordCloseChild();
gObjectList[objectIndex].orientation[1] =
func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos);
FrameInterpolation_RecordOpenChild("crab2", (_idx << 5) | cameraId);
rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation,
gObjectList[objectIndex].sizeScaling);
gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007D78);
gDPLoadTLUT_pal256(gDisplayListHead++, gObjectList[objectIndex].activeTLUT);
rsp_load_texture((u8*) gObjectList[objectIndex].activeTexture, 64, 64);
gSPVertex(gDisplayListHead++, (uintptr_t) common_vtx_crab, 4, 0);
gSPDisplayList(gDisplayListHead++, (Gfx*) common_rectangle_display);
gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF);
FrameInterpolation_RecordCloseChild();
}
}
void OCrab::DrawModel(s32 cameraId) {
s32 someIndex;
s32 objectIndex = _objectIndex;
func_8008A364(objectIndex, cameraId, 0x2AABU, 800);
if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) {
Camera* camera;
if (gObjectList[objectIndex].state >= 2) {
camera = &camera1[cameraId];
FrameInterpolation_RecordOpenChild("crab3", (_idx << 5) | cameraId);
func_8004A6EC(objectIndex, 0.5f);
FrameInterpolation_RecordCloseChild();
gObjectList[objectIndex].orientation[1] =
func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos);
FrameInterpolation_RecordOpenChild("crab4", (_idx << 5) | cameraId);
rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation,
gObjectList[objectIndex].sizeScaling);
gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007D78);
gDPLoadTLUT_pal256(gDisplayListHead++, gObjectList[objectIndex].activeTLUT);
rsp_load_texture((u8*) gObjectList[objectIndex].activeTexture, 64, 64);
gSPVertex(gDisplayListHead++, (uintptr_t) common_vtx_crab, 4, 0);
gSPDisplayList(gDisplayListHead++, (Gfx*) common_rectangle_display);
gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF);
FrameInterpolation_RecordCloseChild();
}
}
}
void OCrab::init_ktb_crab(s32 objectIndex) {
Object* object;
init_texture_object(objectIndex, (uint8_t*) d_course_koopa_troopa_beach_crab_tlut,
(const char**) d_course_koopa_troopa_beach_crab_frames, 64, (u16) 64);
object = &gObjectList[objectIndex];
object->sizeScaling = 0.15f;
object->textureListIndex = 0;
object_next_state(objectIndex);
object->boundingBoxSize = 1;
set_object_flag(objectIndex, 0x04000420);
func_80086EAC(objectIndex, 0, 1);
set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f);
set_obj_orientation(objectIndex, 0U, 0U, 0x8000U);
object->unk_034 = 1.5f;
set_object_flag(objectIndex, 0x00000200);
}
void OCrab::func_80082B34(s32 objectIndex) {
switch (gObjectList[objectIndex].state) { /* irregular */
case 0:
break;
case 1:
OCrab::init_ktb_crab(objectIndex);
break;
case 2:
func_80072E54(objectIndex, 0, 3, 1, 2, -1);
break;
case 3:
func_80072E54(objectIndex, 4, 6, 1, 2, -1);
break;
}
if (gObjectList[objectIndex].state >= 2) {
func_80073514(objectIndex);
}
}
void OCrab::func_80082C30(s32 objectIndex) {
switch (gObjectList[objectIndex].unk_0AE) {
case 1:
if (func_80087A0C(objectIndex, gObjectList[objectIndex].origin_pos[0], gObjectList[objectIndex].unk_01C[0],
gObjectList[objectIndex].origin_pos[2], gObjectList[objectIndex].unk_01C[2]) != 0) {
func_800726CC(objectIndex, 3);
func_80086FD4(objectIndex);
}
break;
case 2:
if (func_80087104(objectIndex, 0x003CU) != 0) {
gObjectList[objectIndex].unk_034 = 0.8f;
func_800726CC(objectIndex, 2);
func_80086FD4(objectIndex);
}
break;
case 3:
if (func_80087954(objectIndex, 0x0000003C) != 0) {
func_80086FD4(objectIndex);
func_800726CC(objectIndex, 3);
}
break;
case 4:
if (func_80087104(objectIndex, 0x003CU) != 0) {
func_800726CC(objectIndex, 2);
func_80086FD4(objectIndex);
}
break;
case 5:
if (func_8008789C(objectIndex, 0x0000003C) != 0) {
func_800726CC(objectIndex, 3);
func_8008701C(objectIndex, 2);
}
break;
}
object_calculate_new_pos_offset(objectIndex);
if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) {
func_80088538(objectIndex);
gObjectList[objectIndex].pos[1] = (f32) (gObjectList[objectIndex].surfaceHeight + 2.5);
}
}
void OCrab::func_80082E18(s32 objectIndex) {
if (gObjectList[objectIndex].state >= 2) {
func_80089F24(objectIndex);
}
}
void OCrab::DrawEditorProperties() {
ImGui::Text("Start Location");
ImGui::SameLine();
if (ImGui::DragFloat2("##PathSpan", (float*)&_start)) {
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPathSpan")) {
_start = FVector2D(0.0f, 0.0f);
gObjectList[_objectIndex].pos[0] = gObjectList[_objectIndex].origin_pos[0] = _start.x * xOrientation;
gObjectList[_objectIndex].pos[2] = gObjectList[_objectIndex].origin_pos[2] = _start.z;
}
ImGui::Text("Patrol Location");
ImGui::SameLine();
if (ImGui::DragFloat2("##PatrolLoc", (float*)&_end)) {
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPatrolLoc")) {
_end = FVector2D(0.0f, 0.0f);
gObjectList[_objectIndex].unk_01C[0] = _end.x * xOrientation;
gObjectList[_objectIndex].unk_01C[2] = _end.z;
}
}