From 830922541296d049cd5c0689c1f610586f56bc75 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sat, 28 Dec 2024 00:25:41 -0700 Subject: [PATCH 1/7] Reimpl Lakitu --- include/mk64.h | 2 +- src/code_800029B0.c | 2 +- src/code_80057C60.c | 56 +- src/engine/Engine.h | 1 + src/engine/GarbageCollector.cpp | 31 ++ src/engine/GarbageCollector.h | 11 + src/engine/World.cpp | 29 +- src/engine/World.h | 9 +- src/engine/courses/Course.cpp | 1 + src/engine/courses/Course.h | 3 +- src/engine/courses/SherbetLand.cpp | 3 + src/engine/objects/Lakitu.cpp | 856 +++++++++++++++++++++++++++++ src/engine/objects/Lakitu.h | 82 +++ src/engine/objects/Object.cpp | 7 +- src/main.c | 3 + src/render_objects.c | 58 +- src/render_objects.h | 1 - src/update_objects.c | 799 --------------------------- src/update_objects.h | 1 - 19 files changed, 1047 insertions(+), 908 deletions(-) create mode 100644 src/engine/GarbageCollector.cpp create mode 100644 src/engine/GarbageCollector.h create mode 100644 src/engine/objects/Lakitu.cpp create mode 100644 src/engine/objects/Lakitu.h diff --git a/include/mk64.h b/include/mk64.h index a3068f13b..86eb1ff9a 100644 --- a/include/mk64.h +++ b/include/mk64.h @@ -104,7 +104,7 @@ enum SURFACE_TYPE { /* 0x10 */ ROPE_BRIDGE, // Bowser's Castle bridge 2, DK Jungle bridge /* 0x11 */ WOOD_BRIDGE, // Frappe Snowland bridge, Bowser's Castle bridge 1,3, Yoshi Valley bridge 2 /* 0xFC */ BOOST_RAMP_WOOD = 0xFC, // DK Jungle - /* 0xFD */ OUT_OF_BOUNDS, // DK Jungle river island + /* 0xFD */ OUT_OF_BOUNDS, // DK Jungle river island oob / out of bounds /* 0xFE */ BOOST_RAMP_ASPHALT, // Royal Raceway /* 0xFF */ RAMP // Koopa Troopa beach }; diff --git a/src/code_800029B0.c b/src/code_800029B0.c index d6a806430..14f82137b 100644 --- a/src/code_800029B0.c +++ b/src/code_800029B0.c @@ -322,7 +322,7 @@ void credits_spawn_actors(void) { // Stupid hack to sync segment 3 memory allocations with hard-coded address in data. gNextFreeMemoryAddress += 0x9000; destroy_all_actors(); - m_ClearActors(); + CM_CleanWorld(); CourseManager_CreditsSpawnActors(); diff --git a/src/code_80057C60.c b/src/code_80057C60.c index cab096140..549b2bc95 100644 --- a/src/code_80057C60.c +++ b/src/code_80057C60.c @@ -567,9 +567,6 @@ void render_object_p1(void) { //func_80054BE8(PLAYER_ONE); return; } - if (!gDemoMode) { - render_lakitu(PLAYER_ONE); - } render_object_for_player(PLAYER_ONE); } @@ -582,9 +579,6 @@ void render_object_p2(void) { G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); CourseManager_DrawBombKarts(PLAYER_TWO); //render_bomb_karts_wrap(PLAYER_TWO); - if (!gDemoMode) { - render_lakitu(PLAYER_TWO); - } render_object_for_player(PLAYER_TWO); } @@ -596,9 +590,6 @@ void render_object_p3(void) { G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); CourseManager_DrawBombKarts(PLAYER_THREE); //render_bomb_karts_wrap(PLAYER_THREE); - if (!gDemoMode) { - render_lakitu(PLAYER_THREE); - } render_object_for_player(PLAYER_THREE); } @@ -612,7 +603,7 @@ void render_object_p4(void) { CourseManager_DrawBombKarts(PLAYER_FOUR); //render_bomb_karts_wrap(PLAYER_FOUR); if ((!gDemoMode) && (gPlayerCountSelection1 == 4)) { - render_lakitu(PLAYER_FOUR); + //render_lakitu(PLAYER_FOUR); } render_object_for_player(PLAYER_FOUR); } @@ -805,7 +796,7 @@ void render_object_for_player(s32 cameraId) { } } -void render_snowing_effect(s32 arg0) { +void render_snowing_effect(s32 playerId) { if (GetCourse() == GetFrappeSnowland()) { if (gGamestate != 9) { if ((D_8015F894 == 0) && (gPlayerCountSelection1 == 1)) { @@ -814,8 +805,9 @@ void render_snowing_effect(s32 arg0) { } else { render_object_snowflakes_particles(); } - } else if (GetCourse() == GetSherbetLand()) { - render_ice_block(arg0); + } + if (CourseManager_GetProps()->LakituTowType == 1) { + render_ice_block(playerId); } } @@ -1253,7 +1245,7 @@ void func_8005995C(void) { void func_80059A88(s32 playerId) { func_80059820(playerId); if (!gDemoMode) { - update_object_lakitu(playerId); + //update_object_lakitu(playerId); // Moved to CourseManager_TickObjects60fps func_8007BB9C(playerId); } } @@ -1270,7 +1262,7 @@ void func_80059AC8(void) { } switch (gScreenModeSelection) { case SCREEN_MODE_1P: - if (gGamestate != 9) { + if (gGamestate != CREDITS_SEQUENCE) { func_80059A88(PLAYER_ONE); if (gModeSelection == TIME_TRIALS) { func_8005995C(); @@ -1294,6 +1286,9 @@ void func_80059AC8(void) { func_80059A88(PLAYER_FOUR); break; } + + CourseManager_TickObjects60fps(); + CourseManager_TickThwomps(); // func_8005A71C(); } @@ -1328,7 +1323,7 @@ void func_80059D00(void) { func_80059820(PLAYER_ONE); func_8005B914(); if (!gDemoMode) { - func_8007AA44(0); + //func_8007AA44(0); } func_80078C70(0); if (playerHUD[PLAYER_ONE].raceCompleteBool == 0) { @@ -1348,14 +1343,14 @@ void func_80059D00(void) { func_80059820(PLAYER_ONE); func_8005D0FC(PLAYER_ONE); if (!gDemoMode) { - func_8007AA44(0); + //func_8007AA44(0); } func_80078C70(1); func_8005D1F4(0); func_80059820(PLAYER_TWO); func_8005D0FC(PLAYER_TWO); if (!gDemoMode) { - func_8007AA44(1); + //func_8007AA44(1); } func_80078C70(2); func_8005D1F4(1); @@ -1366,14 +1361,14 @@ void func_80059D00(void) { func_80059820(PLAYER_ONE); func_8005D0FC(PLAYER_ONE); if (!gDemoMode) { - func_8007AA44(0); + //func_8007AA44(0); } func_80078C70(3); func_8005D1F4(0); func_80059820(PLAYER_TWO); func_8005D0FC(PLAYER_TWO); if (!gDemoMode) { - func_8007AA44(1); + //func_8007AA44(1); } func_80078C70(4); func_8005D1F4(1); @@ -1386,31 +1381,32 @@ void func_80059D00(void) { func_80059820(PLAYER_ONE); func_8005D0FC(PLAYER_ONE); if (!gDemoMode) { - func_8007AA44(0); + //func_8007AA44(0); } func_8005D1F4(0); func_80059820(PLAYER_TWO); func_8005D0FC(PLAYER_TWO); if (!gDemoMode) { - func_8007AA44(1); + //func_8007AA44(1); } func_8005D1F4(1); func_80059820(PLAYER_THREE); func_8005D0FC(PLAYER_THREE); if (!gDemoMode) { - func_8007AA44(2); + //func_8007AA44(2); } func_8005D1F4(2); if (gPlayerCountSelection1 == 4) { func_80059820(PLAYER_FOUR); func_8005D0FC(PLAYER_FOUR); if ((!gDemoMode) && (gPlayerCountSelection1 == 4)) { - func_8007AA44(3); + //func_8007AA44(3); } func_8005D1F4(3); } break; } + update_object(); CourseManager_TickObjects(); func_800744CC(); } @@ -1579,7 +1575,7 @@ void func_8005A71C(void) { void update_object(void) { - // CourseManager_UpdateCourseObjects(); + CourseManager_UpdateCourseObjects(); // CourseManager_TrainSmokeTick(); // CourseManager_TickPenguins(); // CourseManager_TickSeagulls(); @@ -1721,7 +1717,7 @@ void func_8005AAF0(void) { void func_8005AB20(void) { if ((gModeSelection == GRAND_PRIX) && (gPlayerCountSelection1 == 1)) { - func_8005AA6C(0x14); + func_8005AA6C(20); } } @@ -2396,7 +2392,7 @@ void func_8005B914(void) { } else if (D_8018D1CC < 0xC8) { func_8005B7A0(); } - if ((D_8018D1CC != 0) && (D_8018D1CC >= 0x14) && (D_8018D1CC < 0x1E)) { + if ((D_8018D1CC != 0) && (D_8018D1CC >= 20) && (D_8018D1CC < 0x1E)) { for (i = 0; i < 4; i++) { f32_step_towards(&D_8018D028[i], D_8018D0C8[i], D_8018D078[i]); if (D_8018D028[i] == D_8018D0C8[i]) { @@ -2604,7 +2600,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) { case 0: /* switch 1 */ break; case 1: /* switch 1 */ - func_80079084(playerId); + CM_ActivateSecondLapLakitu(playerId); // func_80079084(playerId); func_800C9060(playerId, SOUND_ARG_LOAD(0x19, 0x00, 0xF0, 0x15)); if ((GetCourse() == GetLuigiRaceway()) && (D_80165898 == 0) && (gModeSelection != (s32) TIME_TRIALS)) { @@ -2612,7 +2608,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) { } break; case 2: /* switch 1 */ - func_800790B4(playerId); + CM_ActivateFinalLapLakitu(playerId); // func_800790B4(playerId); break; case 3: /* switch 1 */ if ((D_8018D114 == 0) || (D_8018D114 == 1)) { @@ -2637,7 +2633,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) { playerHUD[playerId].totalTimeX = 0x0320; D_8016587C = (s32) 1; if (D_8018D20C == 0) { - func_80079054(playerId); + CM_ActivateFinishLakitu(playerId); // func_80079054(playerId); D_8018D20C = 1; if (gPlayerCount == (s8) 1) { D_8018D1CC = 0x00000064; diff --git a/src/engine/Engine.h b/src/engine/Engine.h index c25afa79c..45fa3a61d 100644 --- a/src/engine/Engine.h +++ b/src/engine/Engine.h @@ -27,6 +27,7 @@ typedef struct { const char* CourseLength; const char* AIBehaviour; const char* MinimapTexture; + s32 LakituTowType; s16 D_800E5548[2]; float AIMaximumSeparation; float AIMinimumSeparation; diff --git a/src/engine/GarbageCollector.cpp b/src/engine/GarbageCollector.cpp new file mode 100644 index 000000000..926620fe1 --- /dev/null +++ b/src/engine/GarbageCollector.cpp @@ -0,0 +1,31 @@ +#include "GarbageCollector.h" +#include "World.h" + +void RunGarbageCollector() { + //CleanActors(); + CleanObjects(); +} + +void CleanActors() { + // for (auto actor = gWorldInstance.Actors.begin(); actor != gWorldInstance.Actors.end();) { + // OObject* act = *actor; // Get a mutable copy + // if (act->PendingDestroy) { + // delete act; + // actor = gWorldInstance.Objects.erase(actor); // Remove from container + // continue; + // } + // actor++; + // } +} + +void CleanObjects() { + for (auto object = gWorldInstance.Objects.begin(); object != gWorldInstance.Objects.end();) { + OObject* obj = *object; // Get a mutable copy + if (obj->PendingDestroy) { + delete obj; + object = gWorldInstance.Objects.erase(object); // Remove from container + continue; + } + object++; + } +} \ No newline at end of file diff --git a/src/engine/GarbageCollector.h b/src/engine/GarbageCollector.h new file mode 100644 index 000000000..337d90e4a --- /dev/null +++ b/src/engine/GarbageCollector.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include "Object.h" +#include "World.h" + + +void RunGarbageCollector(); +void CleanActors(); +void CleanObjects(); diff --git a/src/engine/World.cpp b/src/engine/World.cpp index 429b402a0..b14c45219 100644 --- a/src/engine/World.cpp +++ b/src/engine/World.cpp @@ -235,13 +235,6 @@ void World::TickActors() { } } -void RemoveExpiredActors() { - // Actors.erase( - // std::remove_if(Actors.begin(), Actors.end(), - // [](const std::unique_ptr& actor) { return actor->uuid == 0; }), - // Actors.end()); -} - OObject* World::AddObject(OObject* object) { Objects.push_back(object); return Objects.back(); @@ -249,27 +242,25 @@ OObject* World::AddObject(OObject* object) { void World::TickObjects() { for (const auto& object : Objects) { - object->Tick(); + object->Tick(); } } +// Some objects such as lakitu are ticked in process_game_tick. +// This is a fallback to support those objects. Probably don't use this. +void World::TickObjects60fps() { + for (const auto& object : Objects) { + object->Tick60fps(); + } +} + + void World::DrawObjects(s32 cameraId) { for (const auto& object : Objects) { object->Draw(cameraId); } } -void World::ExpiredObjects() { - //this->Objects.erase( - // std::remove_if(this->Objects.begin(), this->Objects.end(), - // [](const std::unique_ptr& object) { return object->uuid == 0; }), // Example condition - // this->Objects.end()); -} - -void World::DestroyObjects() { - -} - Object* World::GetObjectByIndex(size_t index) { //if (index < this->Objects.size()) { // Assuming GameActor::a is accessible, use reinterpret_cast if needed diff --git a/src/engine/World.h b/src/engine/World.h index 2abb06fe0..403a708c2 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -12,7 +12,9 @@ #include "objects/Thwomp.h" #include "objects/Penguin.h" #include "objects/Seagull.h" +#include "objects/Lakitu.h" #include +#include #include "Actor.h" #include "particles/ParticleEmitter.h" @@ -89,6 +91,7 @@ class ACar; class TrainCrossing; class OThwomp; class OSeagull; +class OLakitu; class World { @@ -150,7 +153,6 @@ public: AActor* GetActor(size_t index); void TickActors(); - void RemoveExpiredActors(); AActor* ConvertActorToAActor(Actor* actor); Actor* ConvertAActorToActor(AActor* actor); @@ -158,9 +160,8 @@ public: CProperties* GetCourseProps(); void TickObjects(); + void TickObjects60fps(); void DrawObjects(s32 cameraId); - void ExpiredObjects(); - void DestroyObjects(); Object *GetObjectByIndex(size_t); void AddCup(Cup*); @@ -193,6 +194,8 @@ public: std::vector Objects; std::vector Emitters; + std::unordered_map Lakitus; + /** Actors */ void AddBoat(f32 speed, uint32_t waypoint); void AddTrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint); diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp index e5c9a0498..7d8fb3bff 100644 --- a/src/engine/courses/Course.cpp +++ b/src/engine/courses/Course.cpp @@ -28,6 +28,7 @@ Course::Course() { // Props.CourseLength = "567m"; // Props.Cup = FLOWER_CUP; // Props.CupIndex = 3; + Props.LakituTowType = (s32)OLakitu::LakituTowType::NORMAL; Props.AIBehaviour = D_0D008F28; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; diff --git a/src/engine/courses/Course.h b/src/engine/courses/Course.h index 72dd52639..381ba0340 100644 --- a/src/engine/courses/Course.h +++ b/src/engine/courses/Course.h @@ -6,7 +6,7 @@ // C-compatible function declaration #ifdef __cplusplus -//#include "World.h" +#include "engine/objects/Lakitu.h" extern "C" { #endif @@ -56,6 +56,7 @@ public: const char* CourseLength; const char* AIBehaviour; const char* MinimapTexture; + s32 LakituTowType; s16 D_800E5548[2]; float AIMaximumSeparation; float AIMinimumSeparation; diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp index fd97ba95e..e14b2c7e0 100644 --- a/src/engine/courses/SherbetLand.cpp +++ b/src/engine/courses/SherbetLand.cpp @@ -55,6 +55,9 @@ SherbetLand::SherbetLand() { Props.Name = "sherbet land"; Props.DebugName = "sherbet"; Props.CourseLength = "756m"; + + Props.LakituTowType = (s32)OLakitu::LakituTowType::ICE; + Props.AIBehaviour = D_0D009280; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; diff --git a/src/engine/objects/Lakitu.cpp b/src/engine/objects/Lakitu.cpp new file mode 100644 index 000000000..1c8547bc8 --- /dev/null +++ b/src/engine/objects/Lakitu.cpp @@ -0,0 +1,856 @@ +#include +#include +#include "Lakitu.h" +#include + +#include "port/Game.h" + +extern "C" { +#include "macros.h" +#include "main.h" +#include "actors.h" +#include "math_util.h" +#include "sounds.h" +#include "update_objects.h" +#include "render_player.h" +#include "external.h" +#include "bomb_kart.h" +#include "collision.h" +#include "code_80086E70.h" +#include "render_objects.h" +#include "code_80057C60.h" +#include "defines.h" +#include "code_80005FD0.h" +#include "math_util_2.h" +#include "collision.h" +#include "assets/bowsers_castle_data.h" +#include "ceremony_and_credits.h" +#include "objects.h" +#include "update_objects.h" +#include "render_objects.h" +#include "course_offsets.h" +#include "data/some_data.h" +#include "race_logic.h" +#include "effects.h" +#include "memory.h" +extern s8 gPlayerCount; +} + +OLakitu::OLakitu(s32 playerId, LakituType type) { + _playerId = playerId; + + init_object(gIndexLakituList[playerId], (s32)type); +} + +void OLakitu::Activate(LakituType type) { + init_object(gIndexLakituList[_playerId], (s32)type); +} + +void OLakitu::Tick() { + OLakitu::func_8007AA44(_playerId); +} + +void OLakitu::Tick60fps() { // update_object_lakitu + s32 playerId = _playerId; + s32 objectIndex = gIndexLakituList[playerId]; + + switch (gObjectList[objectIndex].unk_0D8) { + case 0: + break; + case 1: + OLakitu::update_object_lakitu_starter(objectIndex, playerId); + func_8008BFFC(objectIndex); + break; + case 2: + OLakitu::update_object_lakitu_checkered_flag(objectIndex, playerId); + func_8008BFFC(objectIndex); + break; + case 3: + OLakitu::update_object_lakitu_fishing(objectIndex, playerId); + break; + case 4: + OLakitu::update_object_lakitu_second_lap(objectIndex, playerId); + func_8008BFFC(objectIndex); + break; + case 5: + OLakitu::update_object_lakitu_final_lap(objectIndex, playerId); + func_8008BFFC(objectIndex); + break; + case 6: + OLakitu::update_object_lakitu_reverse(objectIndex, playerId); + func_8008BFFC(objectIndex); + break; + case 7: + OLakitu::update_object_lakitu_fishing2(objectIndex, playerId); + break; + } +} + +void OLakitu::Draw(s32 cameraId) { + UNUSED s32 stackPadding; + Camera* camera; + f32 var_f0; + f32 var_f2; + s32 objectIndex; + Object* object; + + objectIndex = gIndexLakituList[cameraId]; + camera = &camera1[cameraId]; + if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) { + object = &gObjectList[objectIndex]; + object->orientation[0] = 0; + object->orientation[1] = func_800418AC(object->pos[0], object->pos[2], camera->pos); + object->orientation[2] = 0x8000; + if (func_80072354(objectIndex, 2) != 0) { + draw_2d_texture_at(object->pos, object->orientation, object->sizeScaling, (u8*) object->activeTLUT, + (u8*)object->activeTexture, object->vertex, (s32) object->textureWidth, + (s32) object->textureHeight, (s32) object->textureWidth, + (s32) object->textureHeight / 2); + } else { + func_800485C4(object->pos, object->orientation, object->sizeScaling, (s32) object->primAlpha, + (u8*) object->activeTLUT, (u8*)object->activeTexture, object->vertex, (s32) object->textureWidth, + (s32) object->textureHeight, (s32) object->textureWidth, (s32) object->textureHeight / 2); + } + if (gScreenModeSelection == SCREEN_MODE_1P) { + var_f0 = object->pos[0] - camera->pos[0]; + var_f2 = object->pos[2] - camera->pos[2]; + if (var_f0 < 0.0f) { + var_f0 = -var_f0; + } + if (var_f2 < 0.0f) { + var_f2 = -var_f2; + } + if ((var_f0 + var_f2) <= 200.0) { + func_8004A630(&D_8018C0B0[cameraId], object->pos, 0.35f); + } + } + } +} + +void OLakitu::func_80079114(s32 objectIndex, s32 playerId, s32 arg2) { + s32 a; + if (gObjectList[objectIndex].state >= 2) { + if ((u8) gObjectList[objectIndex].unk_0D8 == 1) { + if (playerId == 0) { + func_80074894(objectIndex, gLakituTexturePtr); + return; + } + a = gIndexLakituList[0]; + gObjectList[objectIndex].activeTLUT = gObjectList[a].activeTLUT; + gObjectList[objectIndex].activeTexture = gObjectList[a].activeTexture; + if (0) {} + return; + } + switch (arg2) { + case 0: + func_800748F4(objectIndex, gLakituTexturePtr); + break; + case 1: + func_800748C4(objectIndex, gLakituTexturePtr); + break; + case 2: + func_80074894(objectIndex, gLakituTexturePtr); + break; + } + } +} + +void OLakitu::func_800791F0(s32 objectIndex, s32 playerId) { + Player* player = &gPlayerOne[playerId]; + + if ((gObjectList[objectIndex].unk_0D8 != 3) && (gObjectList[objectIndex].unk_0D8 != 7)) { + func_800722CC(objectIndex, 1); + if (CourseManager_GetProps()->LakituTowType == LakituTowType::ICE) { + player->unk_0CA &= 0xFFEF; + } + } + + if (CourseManager_GetProps()->LakituTowType == LakituTowType::ICE) { + func_800722CC(objectIndex, 0x00000010); + player->unk_0CA &= 0xFFDF; + } + func_800C9018(playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); +} + +static const char* sLakituTextures[] = { + gTextureLakituNoLights1, gTextureLakituNoLights2, gTextureLakituNoLights3, gTextureLakituNoLights4, + gTextureLakituNoLights5, gTextureLakituNoLights6, gTextureLakituNoLights7, gTextureLakituNoLights8, + gTextureLakituRedLights01, gTextureLakituRedLights02, gTextureLakituRedLights03, gTextureLakituRedLights04, + gTextureLakituRedLights05, gTextureLakituRedLights06, gTextureLakituRedLights07, gTextureLakituRedLights08, + gTextureLakituRedLights09, gTextureLakituRedLights10, gTextureLakituRedLights11, gTextureLakituRedLights12, + gTextureLakituRedLights13, gTextureLakituRedLights14, gTextureLakituRedLights15, gTextureLakituRedLights16, + gTextureLakituBlueLight1, gTextureLakituBlueLight2, gTextureLakituBlueLight3, gTextureLakituBlueLight4, + gTextureLakituBlueLight5, gTextureLakituBlueLight6, gTextureLakituBlueLight7, gTextureLakituBlueLight8, +}; + +void OLakitu::init_obj_lakitu_starter_and_checkered_flag(s32 objectIndex, s32 playerId) { + if (playerId == 0) { + D_801656F0 = 0; + D_8018D168 = 0; + } + + // u8 *tlut = (u8 *) LOAD_ASSET_RAW(common_tlut_lakitu_countdown); + // u8 *lights = (u8 *) LOAD_ASSET_RAW(gTextureLakituNoLights1); + + init_texture_object( + objectIndex, + (u8*) load_lakitu_tlut_x64(common_tlut_lakitu_countdown, ARRAY_COUNT(common_tlut_lakitu_countdown)), + sLakituTextures, 56, (u16) 72); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_lakitu); + gObjectList[objectIndex].vertex = vtx; + gObjectList[objectIndex].sizeScaling = 0.15f; + clear_object_flag(objectIndex, 0x00000010); + object_next_state(objectIndex); + gObjectList[objectIndex].unk_048 = D_8018D180; +} + +void OLakitu::update_object_lakitu_starter(s32 objectIndex, s32 arg1) { + UNUSED s32 pad; + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OLakitu::init_obj_lakitu_starter_and_checkered_flag(objectIndex, arg1); + break; + case 2: + set_and_run_timer_object(objectIndex, gObjectList[objectIndex].unk_048); + if ((gObjectList[objectIndex].timer == 0x00000055) && (gPlayerCount == 3) && (arg1 == 0)) { + D_8018D168 = 1; + } + break; + case 3: + set_object_flag(objectIndex, 0x00000010); + func_80086F10(objectIndex, 1, &D_800E67B8); // set a spline + object_next_state(objectIndex); + break; + case 4: + if ((set_and_run_timer_object(objectIndex, 0x0000001E) != false) && (gPlayerCount != 3) && (arg1 == 0)) { + D_8018D168 = 1; + } + break; + case 5: + set_and_run_timer_object(objectIndex, 0x0000001E); + break; + case 6: + func_80072E54(objectIndex, 1, 7, 1, 2, 0); + break; + case 7: + if (set_and_run_timer_object(objectIndex, 0x00000014) != 0) { + gObjectList[objectIndex].tlutList += 0x200; + if (arg1 == 0) { + play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT); + } + } + break; + case 8: + func_80072E54(objectIndex, 8, 0x0000000F, 1, 6, 0); + break; + case 9: + if ((set_and_run_timer_object(objectIndex, 8) != 0) && (arg1 == 0)) { + play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT); + } + break; + case 10: + if ((func_80072E54(objectIndex, 0x00000010, 0x00000017, 1, 6, 0) != 0) && (arg1 == 0)) { + D_801656F0 = 1; + } + break; + case 11: + if (set_and_run_timer_object(objectIndex, 8) != 0) { + gObjectList[objectIndex].tlutList += 0x200; + if (arg1 == 0) { + play_sound2(SOUND_ACTION_GREEN_LIGHT); + } + } + break; + case 12: + func_80072E54(objectIndex, 0x00000018, 0x0000001B, 1, 6, 0); + break; + case 13: + if (arg1 == 0) { + OLakitu::func_800729EC(objectIndex); + D_8018D160 = 1; + break; + } + object_next_state(objectIndex); + break; + case 14: + set_and_run_timer_object(objectIndex, 0x00000078); + break; + case 15: + func_80072428(objectIndex); + break; + } +} + +void OLakitu::func_800729EC(s32 objectIndex) { + u32 temp_v1 = 1; + s32 i; + + start_race(); + object_next_state(objectIndex); + D_8018D2BC = 1; + D_8018D2A4 = 1; + + if (GetCourse() != GetYoshiValley()) { + for (i = 0; i < gPlayerCount; i++) { + playerHUD[i].unk_81 = temp_v1; + } + } + func_8005AB20(); +} + +static const char* sLakituCheckeredList[] = { + gTextureLakituCheckeredFlag01, gTextureLakituCheckeredFlag02, gTextureLakituCheckeredFlag03, + gTextureLakituCheckeredFlag04, gTextureLakituCheckeredFlag05, gTextureLakituCheckeredFlag06, + gTextureLakituCheckeredFlag07, gTextureLakituCheckeredFlag08, gTextureLakituCheckeredFlag09, + gTextureLakituCheckeredFlag10, gTextureLakituCheckeredFlag11, gTextureLakituCheckeredFlag12, + gTextureLakituCheckeredFlag13, gTextureLakituCheckeredFlag14, gTextureLakituCheckeredFlag15, + gTextureLakituCheckeredFlag16, gTextureLakituCheckeredFlag17, gTextureLakituCheckeredFlag18, + gTextureLakituCheckeredFlag19, gTextureLakituCheckeredFlag20, gTextureLakituCheckeredFlag21, + gTextureLakituCheckeredFlag22, gTextureLakituCheckeredFlag23, gTextureLakituCheckeredFlag24, + gTextureLakituCheckeredFlag25, gTextureLakituCheckeredFlag26, gTextureLakituCheckeredFlag27, + gTextureLakituCheckeredFlag28, gTextureLakituCheckeredFlag29, gTextureLakituCheckeredFlag30, + gTextureLakituCheckeredFlag31, gTextureLakituCheckeredFlag32 +}; + +void OLakitu::init_obj_lakitu_checkered_flag(s32 objectIndex, s32 playerIndex) { + Object* object; + + OLakitu::func_800791F0(objectIndex, playerIndex); + + u8* tex = (u8*) LOAD_ASSET_RAW(common_tlut_lakitu_checkered_flag); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_also_lakitu); + + init_texture_object(objectIndex, (u8*) tex, sLakituCheckeredList, 0x48U, (u16) 0x00000038); + object = &gObjectList[objectIndex]; + object->activeTexture = *gObjectList[objectIndex].textureList; + object->vertex = vtx; + object->pos[2] = 5000.0f; + object->pos[1] = 5000.0f; + object->pos[0] = 5000.0f; + object->sizeScaling = 0.15f; + func_80086F10(objectIndex, 2, &D_800E6834); + clear_object_flag(objectIndex, 0x00000010); + object_next_state(objectIndex); +} + +void OLakitu::update_object_lakitu_checkered_flag(s32 objectIndex, s32 playerIndex) { + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OLakitu::init_obj_lakitu_checkered_flag(objectIndex, playerIndex); + break; + case 2: + set_object_flag(objectIndex, 0x00000010); + object_next_state(objectIndex); + break; + case 3: + func_80072E54(objectIndex, 0, 0x0000001F, 1, 2, -1); + break; + case 4: + func_80072428(objectIndex); + break; + } +} + +void OLakitu::func_800797AC(s32 playerId) { + s32 objectIndex; + Player* player; + + objectIndex = gIndexLakituList[playerId]; + player = &gPlayerOne[playerId]; + //if ((GetCourse() == GetSherbetLand()) && (player->unk_0CA & 1)) { + if ((CourseManager_GetProps()->LakituTowType == LakituTowType::ICE) && (player->unk_0CA & 1)) { + init_object(objectIndex, 7); + player->unk_0CA |= 0x10; + } else { + init_object(objectIndex, 3); + } + func_800722A4(objectIndex, 1); +} + +void OLakitu::func_80079860(s32 playerId) { + s32 objectIndex; + Player* player; + + objectIndex = gIndexLakituList[playerId]; + player = &gPlayerOne[playerId]; + if ((func_80072354(objectIndex, 1) != 0) && + (((func_802ABDF4(player->collision.meshIndexZX) != 0) && (player->collision.surfaceDistance[2] <= 3.0f)) || + (player->unk_0CA & 1) || ((player->surfaceType == OUT_OF_BOUNDS) && !(player->effects & 8)))) { + func_80090778(player); + OLakitu::func_800797AC(playerId); + } +} + +void OLakitu::func_8007993C(s32 objectIndex, Player* player) { + if (player->unk_0CA & 4) { + func_800722A4(objectIndex, 2); + gObjectList[objectIndex].primAlpha = player->unk_0C6; + return; + } + func_800722CC(objectIndex, 2); +} + +static const char* sLakituFishingTextures[] = { gTextureLakituFishing1, gTextureLakituFishing2, gTextureLakituFishing3, + gTextureLakituFishing4 }; + +void OLakitu::init_obj_lakitu_red_flag_fishing(s32 objectIndex, s32 arg1) { + + u8* tlut = (u8*) LOAD_ASSET_RAW(common_tlut_lakitu_fishing); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(D_0D005F30); + + OLakitu::func_800791F0(objectIndex, arg1); + init_texture_object(objectIndex, tlut, sLakituFishingTextures, 0x38U, (u16) 0x00000048); + gObjectList[objectIndex].vertex = vtx; + gObjectList[objectIndex].sizeScaling = 0.15f; + func_80086E70(objectIndex); + clear_object_flag(objectIndex, 0x00000010); + func_80073720(objectIndex); + object_next_state(objectIndex); + func_800C8F80((u8) arg1, 0x0100FA28); +} + +void OLakitu::func_80079A5C(s32 objectIndex, UNUSED Player* player) { + switch (gObjectList[objectIndex].unk_0AE) { + case 0: + break; + case 1: + gObjectList[objectIndex].origin_pos[2] = 0.0f; + gObjectList[objectIndex].origin_pos[1] = 0.0f; + gObjectList[objectIndex].origin_pos[0] = 0.0f; + gObjectList[objectIndex].offset[2] = 0.0f; + gObjectList[objectIndex].offset[0] = 0.0f; + gObjectList[objectIndex].offset[1] = 80.0f; + func_80086FD4(objectIndex); + break; + case 2: + if (f32_step_down_towards(&gObjectList[objectIndex].offset[1], 5.0f, 1.0f) != 0) { + func_80086F60(objectIndex); + } + break; + case 3: + if (f32_step_up_towards(&gObjectList[objectIndex].offset[1], 100.0f, 1.0f) != 0) { + func_80086F60(objectIndex); + } + break; + } +} + +void OLakitu::update_object_lakitu_fishing(s32 objectIndex, s32 playerId) { + Player* player = &gPlayerOne[playerId]; + + switch (gObjectList[objectIndex].state) { /* switch 1; irregular */ + case 0: /* switch 1 */ + break; + case 1: /* switch 1 */ + OLakitu::init_obj_lakitu_red_flag_fishing(objectIndex, playerId); + break; + case 2: /* switch 1 */ + set_object_flag(objectIndex, 0x00000010); + func_800736E0(objectIndex); + object_next_state(objectIndex); + break; + case 3: /* switch 1 */ + func_800730BC(objectIndex, 0, 3, 1, 2, -1); + break; + } + switch (gObjectList[objectIndex].unk_0D6) { + case 0: + break; + case 1: + if (func_80086FA4(objectIndex) != 0) { + func_80073654(objectIndex); + } + break; + case 2: + func_80090868(player); + func_80073654(objectIndex); + break; + case 3: + if (!(player->unk_0CA & 2)) { + func_80086EAC(objectIndex, 0, 3); + func_80073654(objectIndex); + } + break; + case 4: + if (func_80086FA4(objectIndex) != 0) { + func_80073654(objectIndex); + } + break; + case 5: + func_800722CC(objectIndex, 1); + func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); + func_80072428(objectIndex); + func_80073720(objectIndex); + break; + } + if (gObjectList[objectIndex].state >= 2) { + OLakitu::func_8007993C(objectIndex, player); + } + OLakitu::func_80079A5C(objectIndex, player); +} + +void OLakitu::update_object_lakitu_fishing2(s32 objectIndex, s32 playerId) { + Player* player = &gPlayerOne[playerId]; + + switch (gObjectList[objectIndex].state) { /* switch 1; irregular */ + case 0: /* switch 1 */ + break; + case 1: /* switch 1 */ + OLakitu::init_obj_lakitu_red_flag_fishing(objectIndex, playerId); + break; + case 2: /* switch 1 */ + set_object_flag(objectIndex, 0x00000010); + func_800736E0(objectIndex); + player->unk_0CA |= 0x80; + object_next_state(objectIndex); + break; + case 3: /* switch 1 */ + func_800730BC(objectIndex, 0, 3, 1, 2, -1); + break; + } + switch (gObjectList[objectIndex].unk_0D6) { + case 1: + if (func_80086FA4(objectIndex) != 0) { + func_800C9060((u8) playerId, 0x1900A055U); + func_80073654(objectIndex); + } + break; + case 2: + func_80090868(player); + func_800722A4(objectIndex, 4); + func_80073654(objectIndex); + break; + case 3: + if ((player->surfaceType == ICE) && !(player->unk_0CA & 1) && + ((f64) player->collision.surfaceDistance[2] <= 30.0)) { + func_800722A4(objectIndex, 8); + } + if (!(player->unk_0CA & 2)) { + func_80086EAC(objectIndex, 0, 3); + func_80073654(objectIndex); + } + break; + case 4: + func_8007375C(objectIndex, 0x0000001E); + break; + case 5: + player->unk_0CA &= 0xFF7F; + func_800722A4(objectIndex, 0x00000010); + func_800722A4(objectIndex, 0x00000020); + func_800722CC(objectIndex, 4); + func_800722CC(objectIndex, 8); + func_80073654(objectIndex); + func_800C9060((u8) playerId, 0x1900A056U); + break; + case 6: + if (func_8007375C(objectIndex, 0x000000A0) != 0) { + func_800722CC(objectIndex, 0x00000010); + player->unk_0CA &= 0xFFEF; + player->unk_0CA |= 0x20; + } + break; + case 7: + func_8007375C(objectIndex, 0x0000003C); + break; + case 8: + func_80073720(objectIndex); + func_80072428(objectIndex); + player->unk_0CA &= 0xFFDF; + func_800722CC(objectIndex, 1); + func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); + break; + } + + if (gObjectList[objectIndex].state >= 2) { + OLakitu::func_8007993C(objectIndex, player); + } + OLakitu::func_80079A5C(objectIndex, player); +} + +static const char* sLakituSecondLapTextures[] = { + gTextureLakituSecondLap01, gTextureLakituSecondLap02, gTextureLakituSecondLap03, gTextureLakituSecondLap04, + gTextureLakituSecondLap05, gTextureLakituSecondLap06, gTextureLakituSecondLap07, gTextureLakituSecondLap08, + gTextureLakituSecondLap09, gTextureLakituSecondLap10, gTextureLakituSecondLap11, gTextureLakituSecondLap12, + gTextureLakituSecondLap13, gTextureLakituSecondLap14, gTextureLakituSecondLap15, gTextureLakituSecondLap16 +}; + +void OLakitu::func_8007A060(s32 objectIndex, s32 playerIndex) { + Object* object; + + OLakitu::func_800791F0(objectIndex, playerIndex); + + u8* tlut = (u8*) LOAD_ASSET_RAW(common_tlut_lakitu_second_lap); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_also_lakitu); + + init_texture_object(objectIndex, tlut, sLakituSecondLapTextures, 0x48U, (u16) 0x00000038); + object = &gObjectList[objectIndex]; + object->activeTexture = *gObjectList[objectIndex].textureList; + object->vertex = vtx; + object->pos[2] = 5000.0f; + object->pos[1] = 5000.0f; + object->pos[0] = 5000.0f; + object->sizeScaling = 0.15f; + clear_object_flag(objectIndex, 0x00000010); + func_80086F10(objectIndex, 5, &D_800E694C); + object_next_state(objectIndex); +} + +void OLakitu::update_object_lakitu_second_lap(s32 objectIndex, s32 playerIndex) { + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OLakitu::func_8007A060(objectIndex, playerIndex); + break; + case 2: + set_object_flag(objectIndex, 0x00000010); + object_next_state(objectIndex); + break; + case 3: + set_and_run_timer_object(objectIndex, 0x00000014); + break; + case 4: + func_80072E54(objectIndex, 0, 0x0000000F, 1, 2, 1); + break; + case 5: + set_and_run_timer_object(objectIndex, 0x0000003C); + break; + case 6: + func_80072F88(objectIndex, 0x0000000F, 0, 1, 2, 1); + break; + case 7: + if (gObjectList[objectIndex].unk_0AE == 0) { + func_80072428(objectIndex); + } + break; + } +} + +static const char* sLakituFinalLapTextures[] = { + gTextureLakituFinalLap01, gTextureLakituFinalLap02, gTextureLakituFinalLap03, gTextureLakituFinalLap04, + gTextureLakituFinalLap05, gTextureLakituFinalLap06, gTextureLakituFinalLap07, gTextureLakituFinalLap08, + gTextureLakituFinalLap09, gTextureLakituFinalLap10, gTextureLakituFinalLap11, gTextureLakituFinalLap12, + gTextureLakituFinalLap13, gTextureLakituFinalLap14, gTextureLakituFinalLap15, gTextureLakituFinalLap16, +}; + +void OLakitu::func_8007A228(s32 objectIndex, s32 playerIndex) { + Object* object; + + OLakitu::func_800791F0(objectIndex, playerIndex); + + u8* tlut = (u8*) LOAD_ASSET_RAW(common_tlut_lakitu_final_lap); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_also_lakitu); + + init_texture_object(objectIndex, tlut, sLakituFinalLapTextures, 0x48U, (u16) 0x00000038); + object = &gObjectList[objectIndex]; + object->activeTexture = *gObjectList[objectIndex].textureList; + object->vertex = vtx; + object->pos[2] = 5000.0f; + object->pos[1] = 5000.0f; + object->pos[0] = 5000.0f; + object->sizeScaling = 0.15f; + clear_object_flag(objectIndex, 0x00000010); + func_80086F10(objectIndex, 5, &D_800E694C); + object_next_state(objectIndex); +} + +void OLakitu::update_object_lakitu_final_lap(s32 objectIndex, s32 playerIndex) { + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OLakitu::func_8007A228(objectIndex, playerIndex); + break; + case 2: + set_object_flag(objectIndex, 0x00000010); + object_next_state(objectIndex); + break; + case 3: + set_and_run_timer_object(objectIndex, 0x00000014); + break; + case 4: + func_80072E54(objectIndex, 0, 0x0000000F, 1, 2, 1); + break; + case 5: + set_and_run_timer_object(objectIndex, 0x0000003C); + break; + case 6: + func_80072F88(objectIndex, 0x0000000F, 0, 1, 2, 1); + break; + case 7: + if (gObjectList[objectIndex].unk_0AE == 0) { + func_80072428(objectIndex); + } + break; + } +} + +static const char* sLakituReverseTextures[] = { + gTextureLakituReverse01, gTextureLakituReverse02, gTextureLakituReverse03, gTextureLakituReverse04, + gTextureLakituReverse05, gTextureLakituReverse06, gTextureLakituReverse07, gTextureLakituReverse08, + gTextureLakituReverse09, gTextureLakituReverse10, gTextureLakituReverse11, gTextureLakituReverse12, + gTextureLakituReverse13, gTextureLakituReverse14, gTextureLakituReverse15, gTextureLakituReverse16 +}; + +void OLakitu::func_8007A3F0(s32 objectIndex, s32 arg1) { + f32 var = 5000.0f; + OLakitu::func_800791F0(objectIndex, arg1); + + u8* tlut = (u8*) LOAD_ASSET_RAW(common_tlut_lakitu_reverse); + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_also_lakitu); + + init_texture_object(objectIndex, tlut, sLakituReverseTextures, 72, (u16) 56); + gObjectList[objectIndex].activeTexture = *gObjectList[objectIndex].textureList; + gObjectList[objectIndex].vertex = vtx; + gObjectList[objectIndex].pos[2] = var; + gObjectList[objectIndex].pos[1] = var; + gObjectList[objectIndex].pos[0] = var; + gObjectList[objectIndex].sizeScaling = 0.15f; + clear_object_flag(objectIndex, 0x00000010); + func_80086F10(objectIndex, 6, &D_800E69B0); + gObjectList[objectIndex].unk_0D6 = 0; + object_next_state(objectIndex); + func_800C8F80((u8) arg1, 0x0100FA28); +} + +void OLakitu::update_object_lakitu_reverse(s32 objectIndex, s32 playerId) { + Player* sp2C = &gPlayerOne[playerId]; + + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OLakitu::func_8007A3F0(objectIndex, playerId); + break; + case 2: + set_object_flag(objectIndex, 0x00000010); + gObjectList[objectIndex].unk_0D6 = 1; + object_next_state(objectIndex); + break; + case 3: + func_800730BC(objectIndex, 0, 0x0000000F, 1, 2, -1); + break; + case 4: + func_80072428(objectIndex); + break; + } + switch (gObjectList[objectIndex].unk_0D6) { + case 1: + if ((gObjectList[objectIndex].state >= 3) && (!(sp2C->effects & 0x400000))) { + func_80086F10(objectIndex, 6, &D_800E69F4); + gObjectList[objectIndex].unk_0D6 = 2; + gObjectList[objectIndex].unk_04C = 0x00000050; + func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); + return; + } + return; + case 2: + gObjectList[objectIndex].unk_04C--; + if (gObjectList[objectIndex].unk_04C == 0) { + object_next_state(objectIndex); + gObjectList[objectIndex].unk_0D6 = 0; + } + break; + } +} + +void OLakitu::func_8007A66C(s32 objectIndex) { + Player* player = &gPlayers[_playerId]; + Camera* camera = &cameras[_playerId]; + u16 rot = 0x8000 - camera->rot[1]; + + gObjectList[objectIndex].pos[0] = + (player->pos[0] + + (coss(rot) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) - + (sins(rot) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); + gObjectList[objectIndex].pos[1] = + player->unk_074 + gObjectList[objectIndex].origin_pos[1] + gObjectList[objectIndex].offset[1]; + gObjectList[objectIndex].pos[2] = + (player->pos[2] + + (sins(rot) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) + + (coss(rot) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); +} + +void OLakitu::func_8007A778(s32 objectIndex) { + Player* player = &gPlayers[_playerId]; + Camera* camera = &cameras[_playerId]; + u16 rot = 0x8000 - camera->rot[1]; + + gObjectList[objectIndex].pos[0] = + (player->pos[0] + + (coss(rot) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) - + (sins(rot) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); + gObjectList[objectIndex].pos[1] = + player->pos[1] + gObjectList[objectIndex].origin_pos[1] + gObjectList[objectIndex].offset[1]; + gObjectList[objectIndex].pos[2] = + (player->pos[2] + + (sins(rot) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) + + (coss(rot) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); +} + +void OLakitu::func_8007A88C(s32 playerId) { + s32 objectIndex; + Player* player; + + objectIndex = gIndexLakituList[playerId]; + player = &gPlayerOne[playerId]; + + if ((gObjectList[objectIndex].state == 0) && (player->effects & 0x400000)) { + //func_800790E4(playerId); + init_object(gIndexLakituList[playerId], 6); + } +} + +void OLakitu::func_8007A910(s32 arg0) { + if (D_801657B4 == 0) { + OLakitu::func_8007A88C(arg0); + } + func_80079860(arg0); +} + +// animate lakitu? +void OLakitu::func_8007AA44(s32 playerId) { + s32 objectIndex; + + OLakitu::func_8007A910(playerId); + objectIndex = gIndexLakituList[playerId]; + gLakituTexturePtr = (const char**)&gLakituTextureBuffer[playerId]; + switch (gObjectList[objectIndex].unk_0D8) { + case 1: + OLakitu::func_80079114(objectIndex, playerId, 2); + OLakitu::func_8007A66C(objectIndex); + break; + case 2: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A66C(objectIndex); + break; + case 3: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A778(objectIndex); + break; + case 4: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A66C(objectIndex); + break; + case 5: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A66C(objectIndex); + break; + case 6: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A66C(objectIndex); + break; + case 7: + OLakitu::func_80079114(objectIndex, playerId, 0); + OLakitu::func_8007A778(objectIndex); + break; + case 0: + default: + break; + } +} + diff --git a/src/engine/objects/Lakitu.h b/src/engine/objects/Lakitu.h new file mode 100644 index 000000000..1944733ee --- /dev/null +++ b/src/engine/objects/Lakitu.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include "Object.h" +#include "World.h" + +extern "C" { +#include "macros.h" +#include "main.h" +#include "vehicles.h" +#include "waypoints.h" +#include "common_structs.h" +#include "objects.h" +#include "course_offsets.h" +} + +/** + * Note that you only want 1 lakitu spawned in per human player + * Otherwise Lakitu will animate faster than normal. + */ +class OLakitu : public OObject { +public: + enum LakituType : uint32_t { + STARTER = 1, + FINISH, // Checkered flag + TOW, // Picks up an out of bounds player + SECOND_LAP, + FINAL_LAP, + REVERSE, + TOW_ICE_CUBE, // Picks up an out of bounds player in sherbet land as an ice-cube + }; + + enum LakituTowType : uint16_t { + NORMAL, + ICE, // Used in sherbet land to put an ice-cube on the player + }; + +public: + explicit OLakitu(s32 playerId, LakituType type); + + void Activate(LakituType type); // Triggers Lakitu into a behaviour + + virtual void Tick() override; + virtual void Tick60fps() override; + virtual void Draw(s32 playerId) override; + + void func_80078F64(); + void func_80079054(s32 playerId); + void func_80079084(s32 playerId); + void func_800790B4(s32 playerId); + void func_800790E4(s32 playerId); + void func_80079114(s32 objectIndex, s32 playerId, s32 arg2); + void func_800791F0(s32 objectIndex, s32 playerId); + void init_obj_lakitu_starter_and_checkered_flag(s32 objectIndex, s32 playerId); + void update_object_lakitu_starter(s32 objectIndex, s32 arg1); + void func_800729EC(s32 objectIndex); + void init_obj_lakitu_checkered_flag(s32 objectIndex, s32 playerIndex); + void update_object_lakitu_checkered_flag(s32 objectIndex, s32 playerIndex); + void func_800797AC(s32 playerId); + void func_80079860(s32 playerId); + void func_8007993C(s32 objectIndex, Player* player); + void init_obj_lakitu_red_flag_fishing(s32 objectIndex, s32 arg1); + void func_80079A5C(s32 objectIndex, UNUSED Player* player); + void update_object_lakitu_fishing(s32 objectIndex, s32 playerId); + void update_object_lakitu_fishing2(s32 objectIndex, s32 playerId); + void func_8007A060(s32 objectIndex, s32 playerIndex); + void update_object_lakitu_second_lap(s32 objectIndex, s32 playerIndex); + void func_8007A228(s32 objectIndex, s32 playerIndex); + void update_object_lakitu_final_lap(s32 objectIndex, s32 playerIndex); + void func_8007A3F0(s32 objectIndex, s32 arg1); + void update_object_lakitu_reverse(s32 objectIndex, s32 playerId); + void func_8007A66C(s32 objectIndex); + void func_8007A778(s32 objectIndex); + void func_8007A88C(s32 playerId); + void func_8007A910(s32 arg0); + void func_8007AA44(s32 playerId); // animate lakitu + +private: + LakituType _type; + s32 _playerId; +}; diff --git a/src/engine/objects/Object.cpp b/src/engine/objects/Object.cpp index 74143a923..eab390aa1 100644 --- a/src/engine/objects/Object.cpp +++ b/src/engine/objects/Object.cpp @@ -13,8 +13,11 @@ extern "C" { OObject::OObject() {} // Virtual functions to be overridden by derived classes -void OObject::Tick() { } +void OObject::Tick() { } +void OObject::Tick60fps() {} void OObject::Draw(s32 cameraId) { } void OObject::Collision() {} void OObject::Expire() { } -void OObject::Destroy() { } +void OObject::Destroy() { + PendingDestroy = true; +} diff --git a/src/main.c b/src/main.c index 5b3a02a79..b932c7a12 100644 --- a/src/main.c +++ b/src/main.c @@ -897,6 +897,9 @@ void race_logic_loop(void) { FB_WriteFramebufferSliceToCPU(&gDisplayListHead, gPortFramebuffers[sRenderingFramebuffer], true); gDPFullSync(gDisplayListHead++); gSPEndDisplayList(gDisplayListHead++); + + // End of frame cleanup of actors, objects, etc. + CM_RunGarbageCollector(); } /** diff --git a/src/render_objects.c b/src/render_objects.c index 926602a37..ac53334fa 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -3501,7 +3501,7 @@ void func_8005285C(s32 arg0) { func_80043500(D_80183E40, D_80183E80, 0.02f, d_course_sherbet_land_dl_ice_block); } -void func_800528EC(s32 arg0) { +void func_800528EC(s32 playerId) { s32 var_s3; s32 objectIndex; Object* object; @@ -3517,7 +3517,7 @@ void func_800528EC(s32 arg0) { gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA); gSPClearGeometryMode(gDisplayListHead++, G_CULL_BOTH); gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_LIGHTING | G_SHADING_SMOOTH); - load_texture_block_ia16_nomirror(d_course_sherbet_land_ice, 0x00000020, 0x00000020); + load_texture_block_ia16_nomirror(d_course_sherbet_land_ice, 32, 32); if (gPlayerCountSelection1 < 3) { for (var_s3 = 0; var_s3 < gObjectParticle2_SIZE; var_s3++) { objectIndex = gObjectParticle2[var_s3]; @@ -3535,7 +3535,7 @@ void func_800528EC(s32 arg0) { objectIndex = gObjectParticle2[var_s3]; if (objectIndex != NULL_OBJECT_ID) { object = &gObjectList[objectIndex]; - if ((object->state > 0) && (arg0 == object->unk_084[7]) && (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX)) { + if ((object->state > 0) && (playerId == object->unk_084[7]) && (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX)) { rsp_set_matrix_transformation(object->pos, D_80183E80, object->sizeScaling); gSPVertex(gDisplayListHead++, D_0D005BD0, 3, 0); gSPDisplayList(gDisplayListHead++, D_0D006930); @@ -3548,8 +3548,7 @@ void func_800528EC(s32 arg0) { gSPTexture(gDisplayListHead++, 0x0001, 0x0001, 0, G_TX_RENDERTILE, G_OFF); } -void render_ice_block(s32 arg0) { - s32 playerId; +void render_ice_block(s32 playerId) { s32 objectIndex; // Lights1 D_800E4620l = *(Lights1 *) LOAD_ASSET(D_800E4620); D_800E4620.l[0].l.dir[0] = D_80165840[0]; @@ -3557,15 +3556,15 @@ void render_ice_block(s32 arg0) { D_800E4620.l[0].l.dir[2] = D_80165840[2]; gSPLight(gDisplayListHead++, &D_800E4620.l[0], LIGHT_1); gSPLight(gDisplayListHead++, &D_800E4620.a, LIGHT_2); - for (playerId = 0; playerId < gPlayerCountSelection1; playerId++) { - objectIndex = gIndexLakituList[playerId]; + for (size_t i = 0; i < gPlayerCountSelection1; i++) { + objectIndex = gIndexLakituList[i]; if (objectIndex) {} if (func_80072320(objectIndex, 4) != false) { - func_8005285C(playerId); + func_8005285C(i); } func_80072320(objectIndex, 0x00000010); } - func_800528EC(arg0); + func_800528EC(playerId); } void func_80052D70(s32 playerId) { @@ -3599,47 +3598,6 @@ void func_80052E30(UNUSED s32 arg0) { } } -void render_lakitu(s32 cameraId) { - UNUSED s32 stackPadding; - Camera* camera; - f32 var_f0; - f32 var_f2; - s32 objectIndex; - Object* object; - - objectIndex = gIndexLakituList[cameraId]; - camera = &camera1[cameraId]; - if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) { - object = &gObjectList[objectIndex]; - object->orientation[0] = 0; - object->orientation[1] = func_800418AC(object->pos[0], object->pos[2], camera->pos); - object->orientation[2] = 0x8000; - if (func_80072354(objectIndex, 2) != 0) { - draw_2d_texture_at(object->pos, object->orientation, object->sizeScaling, (u8*) object->activeTLUT, - object->activeTexture, object->vertex, (s32) object->textureWidth, - (s32) object->textureHeight, (s32) object->textureWidth, - (s32) object->textureHeight / 2); - } else { - func_800485C4(object->pos, object->orientation, object->sizeScaling, (s32) object->primAlpha, - (u8*) object->activeTLUT, object->activeTexture, object->vertex, (s32) object->textureWidth, - (s32) object->textureHeight, (s32) object->textureWidth, (s32) object->textureHeight / 2); - } - if (gScreenModeSelection == SCREEN_MODE_1P) { - var_f0 = object->pos[0] - D_8018CF14->pos[0]; - var_f2 = object->pos[2] - D_8018CF14->pos[2]; - if (var_f0 < 0.0f) { - var_f0 = -var_f0; - } - if (var_f2 < 0.0f) { - var_f2 = -var_f2; - } - if ((var_f0 + var_f2) <= 200.0) { - func_8004A630(&D_8018C0B0[cameraId], object->pos, 0.35f); - } - } - } -} - void func_80053D74(s32 objectIndex, UNUSED s32 arg1, s32 vertexIndex) { Object* object; diff --git a/src/render_objects.h b/src/render_objects.h index 8559ce6ca..ec95a0832 100644 --- a/src/render_objects.h +++ b/src/render_objects.h @@ -343,7 +343,6 @@ void render_object_snowmans_list_2(s32); void render_object_snowmans_list_1(s32); void render_object_snowmans(s32); -void render_lakitu(s32); void translate_thwomp_lights(s32); void thwomp_lights(s32); void render_object_thwomps_model(s32); diff --git a/src/update_objects.c b/src/update_objects.c index c3a9b5129..ba56a65a5 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -450,23 +450,6 @@ void set_type_object(s32 objectIndex, s32 arg1) { gObjectList[objectIndex].type = arg1; } -void func_800729EC(s32 objectIndex) { - u32 temp_v1 = 1; - s32 i; - - start_race(); - object_next_state(objectIndex); - D_8018D2BC = 1; - D_8018D2A4 = 1; - - if (GetCourse() != GetYoshiValley()) { - for (i = 0; i < gPlayerCount; i++) { - playerHUD[i].unk_81 = temp_v1; - } - } - func_8005AB20(); -} - UNUSED void func_80072A78(s32 objectIndex, s32 arg1) { gObjectList[objectIndex].textureListIndex = arg1; object_next_state(objectIndex); @@ -2890,788 +2873,6 @@ void func_80078C70(s32 arg0) { } } -void func_80078F64(void) { - switch (gScreenModeSelection) { /* irregular */ - case SCREEN_MODE_1P: - init_object(gIndexLakituList[0], 1); - break; - case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: - init_object(gIndexLakituList[0], 1); - init_object(gIndexLakituList[1], 1); - break; - case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: - init_object(gIndexLakituList[0], 1); - init_object(gIndexLakituList[1], 1); - break; - case SCREEN_MODE_3P_4P_SPLITSCREEN: - init_object(gIndexLakituList[0], 1); - init_object(gIndexLakituList[1], 1); - init_object(gIndexLakituList[2], 1); - init_object(gIndexLakituList[3], 1); - break; - } -} - -void func_80079054(s32 playerId) { - init_object(gIndexLakituList[playerId], 2); -} - -void func_80079084(s32 playerId) { - init_object(gIndexLakituList[playerId], 4); -} - -void func_800790B4(s32 playerId) { - init_object(gIndexLakituList[playerId], 5); -} - -void func_800790E4(s32 playerId) { - init_object(gIndexLakituList[playerId], 6); -} - -void func_80079114(s32 objectIndex, s32 playerId, s32 arg2) { - s32 a; - if (gObjectList[objectIndex].state >= 2) { - if ((u8) gObjectList[objectIndex].unk_0D8 == 1) { - if (playerId == 0) { - func_80074894(objectIndex, gLakituTexturePtr); - return; - } - a = gIndexLakituList[0]; - gObjectList[objectIndex].activeTLUT = gObjectList[a].activeTLUT; - gObjectList[objectIndex].activeTexture = gObjectList[a].activeTexture; - if (0) {} - return; - } - switch (arg2) { - case 0: - func_800748F4(objectIndex, gLakituTexturePtr); - break; - case 1: - func_800748C4(objectIndex, gLakituTexturePtr); - break; - case 2: - func_80074894(objectIndex, gLakituTexturePtr); - break; - } - } -} - -void func_800791F0(s32 objectIndex, s32 playerId) { - Player* player = &gPlayerOne[playerId]; - - if ((gObjectList[objectIndex].unk_0D8 != 3) && (gObjectList[objectIndex].unk_0D8 != 7)) { - func_800722CC(objectIndex, 1); - if (GetCourse() == GetSherbetLand()) { - player->unk_0CA &= 0xFFEF; - } - } else { - // ????? - } - if (GetCourse() == GetSherbetLand()) { - func_800722CC(objectIndex, 0x00000010); - player->unk_0CA &= 0xFFDF; - } - func_800C9018(playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); -} - -static const char* sLakituTextures[] = { - gTextureLakituNoLights1, gTextureLakituNoLights2, gTextureLakituNoLights3, gTextureLakituNoLights4, - gTextureLakituNoLights5, gTextureLakituNoLights6, gTextureLakituNoLights7, gTextureLakituNoLights8, - gTextureLakituRedLights01, gTextureLakituRedLights02, gTextureLakituRedLights03, gTextureLakituRedLights04, - gTextureLakituRedLights05, gTextureLakituRedLights06, gTextureLakituRedLights07, gTextureLakituRedLights08, - gTextureLakituRedLights09, gTextureLakituRedLights10, gTextureLakituRedLights11, gTextureLakituRedLights12, - gTextureLakituRedLights13, gTextureLakituRedLights14, gTextureLakituRedLights15, gTextureLakituRedLights16, - gTextureLakituBlueLight1, gTextureLakituBlueLight2, gTextureLakituBlueLight3, gTextureLakituBlueLight4, - gTextureLakituBlueLight5, gTextureLakituBlueLight6, gTextureLakituBlueLight7, gTextureLakituBlueLight8, -}; - -void init_obj_lakitu_red_flag_countdown(s32 objectIndex, s32 playerId) { - if (playerId == 0) { - D_801656F0 = 0; - D_8018D168 = 0; - } - - // u8 *tlut = (u8 *) LOAD_ASSET(common_tlut_lakitu_countdown); - // u8 *lights = (u8 *) LOAD_ASSET(gTextureLakituNoLights1); - - init_texture_object( - objectIndex, - (u8*) load_lakitu_tlut_x64(common_tlut_lakitu_countdown, ARRAY_COUNT(common_tlut_lakitu_countdown)), - sLakituTextures, 56, (u16) 72); - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_lakitu); - gObjectList[objectIndex].vertex = vtx; - gObjectList[objectIndex].sizeScaling = 0.15f; - clear_object_flag(objectIndex, 0x00000010); - object_next_state(objectIndex); - gObjectList[objectIndex].unk_048 = D_8018D180; -} - -void update_object_lakitu_countdown(s32 objectIndex, s32 arg1) { - UNUSED s32 pad; - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - init_obj_lakitu_red_flag_countdown(objectIndex, arg1); - break; - case 2: - set_and_run_timer_object(objectIndex, gObjectList[objectIndex].unk_048); - if ((gObjectList[objectIndex].timer == 0x00000055) && (gPlayerCount == 3) && (arg1 == 0)) { - D_8018D168 = 1; - } - break; - case 3: - set_object_flag(objectIndex, 0x00000010); - func_80086F10(objectIndex, 1, &D_800E67B8); // set a spline - object_next_state(objectIndex); - break; - case 4: - if ((set_and_run_timer_object(objectIndex, 0x0000001E) != false) && (gPlayerCount != 3) && (arg1 == 0)) { - D_8018D168 = 1; - } - break; - case 5: - set_and_run_timer_object(objectIndex, 0x0000001E); - break; - case 6: - func_80072E54(objectIndex, 1, 7, 1, 2, 0); - break; - case 7: - if (set_and_run_timer_object(objectIndex, 0x00000014) != 0) { - gObjectList[objectIndex].tlutList += 0x200; - if (arg1 == 0) { - play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT); - } - } - break; - case 8: - func_80072E54(objectIndex, 8, 0x0000000F, 1, 6, 0); - break; - case 9: - if ((set_and_run_timer_object(objectIndex, 8) != 0) && (arg1 == 0)) { - play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT); - } - break; - case 10: - if ((func_80072E54(objectIndex, 0x00000010, 0x00000017, 1, 6, 0) != 0) && (arg1 == 0)) { - D_801656F0 = 1; - } - break; - case 11: - if (set_and_run_timer_object(objectIndex, 8) != 0) { - gObjectList[objectIndex].tlutList += 0x200; - if (arg1 == 0) { - play_sound2(SOUND_ACTION_GREEN_LIGHT); - } - } - break; - case 12: - func_80072E54(objectIndex, 0x00000018, 0x0000001B, 1, 6, 0); - break; - case 13: - if (arg1 == 0) { - func_800729EC(objectIndex); - D_8018D160 = 1; - break; - } - object_next_state(objectIndex); - break; - case 14: - set_and_run_timer_object(objectIndex, 0x00000078); - break; - case 15: - func_80072428(objectIndex); - break; - } -} - -static const char* sLakituCheckeredList[] = { - gTextureLakituCheckeredFlag01, gTextureLakituCheckeredFlag02, gTextureLakituCheckeredFlag03, - gTextureLakituCheckeredFlag04, gTextureLakituCheckeredFlag05, gTextureLakituCheckeredFlag06, - gTextureLakituCheckeredFlag07, gTextureLakituCheckeredFlag08, gTextureLakituCheckeredFlag09, - gTextureLakituCheckeredFlag10, gTextureLakituCheckeredFlag11, gTextureLakituCheckeredFlag12, - gTextureLakituCheckeredFlag13, gTextureLakituCheckeredFlag14, gTextureLakituCheckeredFlag15, - gTextureLakituCheckeredFlag16, gTextureLakituCheckeredFlag17, gTextureLakituCheckeredFlag18, - gTextureLakituCheckeredFlag19, gTextureLakituCheckeredFlag20, gTextureLakituCheckeredFlag21, - gTextureLakituCheckeredFlag22, gTextureLakituCheckeredFlag23, gTextureLakituCheckeredFlag24, - gTextureLakituCheckeredFlag25, gTextureLakituCheckeredFlag26, gTextureLakituCheckeredFlag27, - gTextureLakituCheckeredFlag28, gTextureLakituCheckeredFlag29, gTextureLakituCheckeredFlag30, - gTextureLakituCheckeredFlag31, gTextureLakituCheckeredFlag32 -}; - -void init_obj_lakitu_red_flag(s32 objectIndex, s32 playerIndex) { - Object* object; - - func_800791F0(objectIndex, playerIndex); - - u8* tex = (u8*) LOAD_ASSET(common_tlut_lakitu_checkered_flag); - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_also_lakitu); - - init_texture_object(objectIndex, (u8*) tex, sLakituCheckeredList, 0x48U, (u16) 0x00000038); - object = &gObjectList[objectIndex]; - object->activeTexture = *gObjectList[objectIndex].textureList; - object->vertex = vtx; - object->pos[2] = 5000.0f; - object->pos[1] = 5000.0f; - object->pos[0] = 5000.0f; - object->sizeScaling = 0.15f; - func_80086F10(objectIndex, 2, &D_800E6834); - clear_object_flag(objectIndex, 0x00000010); - object_next_state(objectIndex); -} - -void update_object_lakitu_red_flag(s32 objectIndex, s32 playerIndex) { - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - init_obj_lakitu_red_flag(objectIndex, playerIndex); - break; - case 2: - set_object_flag(objectIndex, 0x00000010); - object_next_state(objectIndex); - break; - case 3: - func_80072E54(objectIndex, 0, 0x0000001F, 1, 2, -1); - break; - case 4: - func_80072428(objectIndex); - break; - } -} - -void func_800797AC(s32 playerId) { - s32 objectIndex; - Player* player; - - objectIndex = gIndexLakituList[playerId]; - player = &gPlayerOne[playerId]; - if ((GetCourse() == GetSherbetLand()) && (player->unk_0CA & 1)) { - init_object(objectIndex, 7); - player->unk_0CA |= 0x10; - } else { - init_object(objectIndex, 3); - } - func_800722A4(objectIndex, 1); -} - -void func_80079860(s32 playerId) { - s32 objectIndex; - Player* player; - - objectIndex = gIndexLakituList[playerId]; - player = &gPlayerOne[playerId]; - if ((func_80072354(objectIndex, 1) != 0) && - (((func_802ABDF4(player->collision.meshIndexZX) != 0) && (player->collision.surfaceDistance[2] <= 3.0f)) || - (player->unk_0CA & 1) || ((player->surfaceType == OUT_OF_BOUNDS) && !(player->effects & 8)))) { - func_80090778(player); - func_800797AC(playerId); - } -} - -void func_8007993C(s32 objectIndex, Player* player) { - if (player->unk_0CA & 4) { - func_800722A4(objectIndex, 2); - gObjectList[objectIndex].primAlpha = player->unk_0C6; - return; - } - func_800722CC(objectIndex, 2); -} - -static const char* sLakituFishingTextures[] = { gTextureLakituFishing1, gTextureLakituFishing2, gTextureLakituFishing3, - gTextureLakituFishing4 }; - -void init_obj_lakitu_red_flag_fishing(s32 objectIndex, s32 arg1) { - - u8* tlut = (u8*) LOAD_ASSET(common_tlut_lakitu_fishing); - Vtx* vtx = (Vtx*) LOAD_ASSET(D_0D005F30); - - func_800791F0(objectIndex, arg1); - init_texture_object(objectIndex, tlut, sLakituFishingTextures, 0x38U, (u16) 0x00000048); - gObjectList[objectIndex].vertex = vtx; - gObjectList[objectIndex].sizeScaling = 0.15f; - func_80086E70(objectIndex); - clear_object_flag(objectIndex, 0x00000010); - func_80073720(objectIndex); - object_next_state(objectIndex); - func_800C8F80((u8) arg1, 0x0100FA28); -} - -void func_80079A5C(s32 objectIndex, UNUSED Player* player) { - switch (gObjectList[objectIndex].unk_0AE) { - case 0: - break; - case 1: - gObjectList[objectIndex].origin_pos[2] = 0.0f; - gObjectList[objectIndex].origin_pos[1] = 0.0f; - gObjectList[objectIndex].origin_pos[0] = 0.0f; - gObjectList[objectIndex].offset[2] = 0.0f; - gObjectList[objectIndex].offset[0] = 0.0f; - gObjectList[objectIndex].offset[1] = 80.0f; - func_80086FD4(objectIndex); - break; - case 2: - if (f32_step_down_towards(&gObjectList[objectIndex].offset[1], 5.0f, 1.0f) != 0) { - func_80086F60(objectIndex); - } - break; - case 3: - if (f32_step_up_towards(&gObjectList[objectIndex].offset[1], 100.0f, 1.0f) != 0) { - func_80086F60(objectIndex); - } - break; - } -} - -void update_object_lakitu_fishing(s32 objectIndex, s32 playerId) { - Player* player = &gPlayerOne[playerId]; - - switch (gObjectList[objectIndex].state) { /* switch 1; irregular */ - case 0: /* switch 1 */ - break; - case 1: /* switch 1 */ - init_obj_lakitu_red_flag_fishing(objectIndex, playerId); - break; - case 2: /* switch 1 */ - set_object_flag(objectIndex, 0x00000010); - func_800736E0(objectIndex); - object_next_state(objectIndex); - break; - case 3: /* switch 1 */ - func_800730BC(objectIndex, 0, 3, 1, 2, -1); - break; - } - switch (gObjectList[objectIndex].unk_0D6) { - case 0: - break; - case 1: - if (func_80086FA4(objectIndex) != 0) { - func_80073654(objectIndex); - } - break; - case 2: - func_80090868(player); - func_80073654(objectIndex); - break; - case 3: - if (!(player->unk_0CA & 2)) { - func_80086EAC(objectIndex, 0, 3); - func_80073654(objectIndex); - } - break; - case 4: - if (func_80086FA4(objectIndex) != 0) { - func_80073654(objectIndex); - } - break; - case 5: - func_800722CC(objectIndex, 1); - func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); - func_80072428(objectIndex); - func_80073720(objectIndex); - break; - } - if (gObjectList[objectIndex].state >= 2) { - func_8007993C(objectIndex, player); - } - func_80079A5C(objectIndex, player); -} - -void update_object_lakitu_fishing2(s32 objectIndex, s32 playerId) { - Player* player = &gPlayerOne[playerId]; - - switch (gObjectList[objectIndex].state) { /* switch 1; irregular */ - case 0: /* switch 1 */ - break; - case 1: /* switch 1 */ - init_obj_lakitu_red_flag_fishing(objectIndex, playerId); - break; - case 2: /* switch 1 */ - set_object_flag(objectIndex, 0x00000010); - func_800736E0(objectIndex); - player->unk_0CA |= 0x80; - object_next_state(objectIndex); - break; - case 3: /* switch 1 */ - func_800730BC(objectIndex, 0, 3, 1, 2, -1); - break; - } - switch (gObjectList[objectIndex].unk_0D6) { - case 1: - if (func_80086FA4(objectIndex) != 0) { - func_800C9060((u8) playerId, 0x1900A055U); - func_80073654(objectIndex); - } - break; - case 2: - func_80090868(player); - func_800722A4(objectIndex, 4); - func_80073654(objectIndex); - break; - case 3: - if ((player->surfaceType == ICE) && !(player->unk_0CA & 1) && - ((f64) player->collision.surfaceDistance[2] <= 30.0)) { - func_800722A4(objectIndex, 8); - } - if (!(player->unk_0CA & 2)) { - func_80086EAC(objectIndex, 0, 3); - func_80073654(objectIndex); - } - break; - case 4: - func_8007375C(objectIndex, 0x0000001E); - break; - case 5: - player->unk_0CA &= 0xFF7F; - func_800722A4(objectIndex, 0x00000010); - func_800722A4(objectIndex, 0x00000020); - func_800722CC(objectIndex, 4); - func_800722CC(objectIndex, 8); - func_80073654(objectIndex); - func_800C9060((u8) playerId, 0x1900A056U); - break; - case 6: - if (func_8007375C(objectIndex, 0x000000A0) != 0) { - func_800722CC(objectIndex, 0x00000010); - player->unk_0CA &= 0xFFEF; - player->unk_0CA |= 0x20; - } - break; - case 7: - func_8007375C(objectIndex, 0x0000003C); - break; - case 8: - func_80073720(objectIndex); - func_80072428(objectIndex); - player->unk_0CA &= 0xFFDF; - func_800722CC(objectIndex, 1); - func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); - break; - } - - if (gObjectList[objectIndex].state >= 2) { - func_8007993C(objectIndex, player); - } - func_80079A5C(objectIndex, player); -} - -static const char* sLakituSecondLapTextures[] = { - gTextureLakituSecondLap01, gTextureLakituSecondLap02, gTextureLakituSecondLap03, gTextureLakituSecondLap04, - gTextureLakituSecondLap05, gTextureLakituSecondLap06, gTextureLakituSecondLap07, gTextureLakituSecondLap08, - gTextureLakituSecondLap09, gTextureLakituSecondLap10, gTextureLakituSecondLap11, gTextureLakituSecondLap12, - gTextureLakituSecondLap13, gTextureLakituSecondLap14, gTextureLakituSecondLap15, gTextureLakituSecondLap16 -}; - -void func_8007A060(s32 objectIndex, s32 playerIndex) { - Object* object; - - func_800791F0(objectIndex, playerIndex); - - u8* tlut = (u8*) LOAD_ASSET(common_tlut_lakitu_second_lap); - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_also_lakitu); - - init_texture_object(objectIndex, tlut, sLakituSecondLapTextures, 0x48U, (u16) 0x00000038); - object = &gObjectList[objectIndex]; - object->activeTexture = *gObjectList[objectIndex].textureList; - object->vertex = vtx; - object->pos[2] = 5000.0f; - object->pos[1] = 5000.0f; - object->pos[0] = 5000.0f; - object->sizeScaling = 0.15f; - clear_object_flag(objectIndex, 0x00000010); - func_80086F10(objectIndex, 5, &D_800E694C); - object_next_state(objectIndex); -} - -void update_object_lakitu_second_lap(s32 objectIndex, s32 playerIndex) { - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - func_8007A060(objectIndex, playerIndex); - break; - case 2: - set_object_flag(objectIndex, 0x00000010); - object_next_state(objectIndex); - break; - case 3: - set_and_run_timer_object(objectIndex, 0x00000014); - break; - case 4: - func_80072E54(objectIndex, 0, 0x0000000F, 1, 2, 1); - break; - case 5: - set_and_run_timer_object(objectIndex, 0x0000003C); - break; - case 6: - func_80072F88(objectIndex, 0x0000000F, 0, 1, 2, 1); - break; - case 7: - if (gObjectList[objectIndex].unk_0AE == 0) { - func_80072428(objectIndex); - } - break; - } -} - -static const char* sLakituFinalLapTextures[] = { - gTextureLakituFinalLap01, gTextureLakituFinalLap02, gTextureLakituFinalLap03, gTextureLakituFinalLap04, - gTextureLakituFinalLap05, gTextureLakituFinalLap06, gTextureLakituFinalLap07, gTextureLakituFinalLap08, - gTextureLakituFinalLap09, gTextureLakituFinalLap10, gTextureLakituFinalLap11, gTextureLakituFinalLap12, - gTextureLakituFinalLap13, gTextureLakituFinalLap14, gTextureLakituFinalLap15, gTextureLakituFinalLap16, -}; - -void func_8007A228(s32 objectIndex, s32 playerIndex) { - Object* object; - - func_800791F0(objectIndex, playerIndex); - - u8* tlut = (u8*) LOAD_ASSET(common_tlut_lakitu_final_lap); - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_also_lakitu); - - init_texture_object(objectIndex, tlut, sLakituFinalLapTextures, 0x48U, (u16) 0x00000038); - object = &gObjectList[objectIndex]; - object->activeTexture = *gObjectList[objectIndex].textureList; - object->vertex = vtx; - object->pos[2] = 5000.0f; - object->pos[1] = 5000.0f; - object->pos[0] = 5000.0f; - object->sizeScaling = 0.15f; - clear_object_flag(objectIndex, 0x00000010); - func_80086F10(objectIndex, 5, &D_800E694C); - object_next_state(objectIndex); -} - -void update_object_lakitu_final_lap(s32 objectIndex, s32 playerIndex) { - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - func_8007A228(objectIndex, playerIndex); - break; - case 2: - set_object_flag(objectIndex, 0x00000010); - object_next_state(objectIndex); - break; - case 3: - set_and_run_timer_object(objectIndex, 0x00000014); - break; - case 4: - func_80072E54(objectIndex, 0, 0x0000000F, 1, 2, 1); - break; - case 5: - set_and_run_timer_object(objectIndex, 0x0000003C); - break; - case 6: - func_80072F88(objectIndex, 0x0000000F, 0, 1, 2, 1); - break; - case 7: - if (gObjectList[objectIndex].unk_0AE == 0) { - func_80072428(objectIndex); - } - break; - } -} - -static const char* sLakituReverseTextures[] = { - gTextureLakituReverse01, gTextureLakituReverse02, gTextureLakituReverse03, gTextureLakituReverse04, - gTextureLakituReverse05, gTextureLakituReverse06, gTextureLakituReverse07, gTextureLakituReverse08, - gTextureLakituReverse09, gTextureLakituReverse10, gTextureLakituReverse11, gTextureLakituReverse12, - gTextureLakituReverse13, gTextureLakituReverse14, gTextureLakituReverse15, gTextureLakituReverse16 -}; - -void func_8007A3F0(s32 objectIndex, s32 arg1) { - f32 var = 5000.0f; - func_800791F0(objectIndex, arg1); - - u8* tlut = (u8*) LOAD_ASSET(common_tlut_lakitu_reverse); - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_also_lakitu); - - init_texture_object(objectIndex, tlut, sLakituReverseTextures, 72, (u16) 56); - gObjectList[objectIndex].activeTexture = *gObjectList[objectIndex].textureList; - gObjectList[objectIndex].vertex = vtx; - gObjectList[objectIndex].pos[2] = var; - gObjectList[objectIndex].pos[1] = var; - gObjectList[objectIndex].pos[0] = var; - gObjectList[objectIndex].sizeScaling = 0.15f; - clear_object_flag(objectIndex, 0x00000010); - func_80086F10(objectIndex, 6, &D_800E69B0); - gObjectList[objectIndex].unk_0D6 = 0; - object_next_state(objectIndex); - func_800C8F80((u8) arg1, 0x0100FA28); -} - -void update_object_lakitu_reverse(s32 objectIndex, s32 playerId) { - Player* sp2C = &gPlayerOne[playerId]; - - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - func_8007A3F0(objectIndex, playerId); - break; - case 2: - set_object_flag(objectIndex, 0x00000010); - gObjectList[objectIndex].unk_0D6 = 1; - object_next_state(objectIndex); - break; - case 3: - func_800730BC(objectIndex, 0, 0x0000000F, 1, 2, -1); - break; - case 4: - func_80072428(objectIndex); - break; - } - switch (gObjectList[objectIndex].unk_0D6) { /* switch 1; irregular */ - case 1: /* switch 1 */ - if ((gObjectList[objectIndex].state >= 3) && (!(sp2C->effects & 0x400000))) { - func_80086F10(objectIndex, 6, &D_800E69F4); - gObjectList[objectIndex].unk_0D6 = 2; - gObjectList[objectIndex].unk_04C = 0x00000050; - func_800C9018((u8) playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xFA, 0x28)); - return; - } - return; - case 2: /* switch 1 */ - gObjectList[objectIndex].unk_04C--; - if (gObjectList[objectIndex].unk_04C == 0) { - object_next_state(objectIndex); - gObjectList[objectIndex].unk_0D6 = 0; - } - break; - } -} - -void func_8007A66C(s32 objectIndex, Player* player, Camera* camera) { - u16 temp_t8; - - temp_t8 = 0x8000 - camera->rot[1]; - gObjectList[objectIndex].pos[0] = - (player->pos[0] + - (coss(temp_t8) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) - - (sins(temp_t8) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); - gObjectList[objectIndex].pos[1] = - player->unk_074 + gObjectList[objectIndex].origin_pos[1] + gObjectList[objectIndex].offset[1]; - gObjectList[objectIndex].pos[2] = - (player->pos[2] + - (sins(temp_t8) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) + - (coss(temp_t8) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); -} - -void func_8007A778(s32 objectIndex, Player* player, Camera* camera) { - u16 temp_t8; - - temp_t8 = 0x8000 - camera->rot[1]; - gObjectList[objectIndex].pos[0] = - (player->pos[0] + - (coss(temp_t8) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) - - (sins(temp_t8) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); - gObjectList[objectIndex].pos[1] = - player->pos[1] + gObjectList[objectIndex].origin_pos[1] + gObjectList[objectIndex].offset[1]; - gObjectList[objectIndex].pos[2] = - (player->pos[2] + - (sins(temp_t8) * (gObjectList[objectIndex].origin_pos[0] + gObjectList[objectIndex].offset[0]))) + - (coss(temp_t8) * (gObjectList[objectIndex].origin_pos[2] + gObjectList[objectIndex].offset[2])); -} - -UNUSED void func_8007A884(void) { -} - -void func_8007A88C(s32 playerId) { - s32 objectIndex; - Player* player; - - objectIndex = gIndexLakituList[playerId]; - player = &gPlayerOne[playerId]; - - if ((gObjectList[objectIndex].state == 0) && (player->effects & 0x400000)) { - func_800790E4(playerId); - } -} - -void func_8007A910(s32 arg0) { - if (D_801657B4 == 0) { - func_8007A88C(arg0); - } - func_80079860(arg0); -} - -void update_object_lakitu(s32 playerId) { - s32 objectIndex = gIndexLakituList[playerId]; - - switch (gObjectList[objectIndex].unk_0D8) { - case 0: - break; - case 1: - update_object_lakitu_countdown(objectIndex, playerId); - func_8008BFFC(objectIndex); - break; - case 2: - update_object_lakitu_red_flag(objectIndex, playerId); - func_8008BFFC(objectIndex); - break; - case 3: - update_object_lakitu_fishing(objectIndex, playerId); - break; - case 4: - update_object_lakitu_second_lap(objectIndex, playerId); - func_8008BFFC(objectIndex); - break; - case 5: - update_object_lakitu_final_lap(objectIndex, playerId); - func_8008BFFC(objectIndex); - break; - case 6: - update_object_lakitu_reverse(objectIndex, playerId); - func_8008BFFC(objectIndex); - break; - case 7: - update_object_lakitu_fishing2(objectIndex, playerId); - break; - } -} - -// animate lakitu? -void func_8007AA44(s32 playerId) { - s32 objectIndex; - - func_8007A910(playerId); - objectIndex = gIndexLakituList[playerId]; - gLakituTexturePtr = &gLakituTextureBuffer[playerId]; - switch (gObjectList[objectIndex].unk_0D8) { - case 1: - func_80079114(objectIndex, playerId, 2); - func_8007A66C(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 2: - func_80079114(objectIndex, playerId, 0); - func_8007A66C(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 3: - func_80079114(objectIndex, playerId, 0); - func_8007A778(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 4: - func_80079114(objectIndex, playerId, 0); - func_8007A66C(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 5: - func_80079114(objectIndex, playerId, 0); - func_8007A66C(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 6: - func_80079114(objectIndex, playerId, 0); - func_8007A66C(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 7: - func_80079114(objectIndex, playerId, 0); - func_8007A778(objectIndex, D_8018CF1C, D_8018CF14); - break; - case 0: - default: - break; - } -} void func_8007ABFC(s32 playerId, bool arg1) { s32 itemWindow; diff --git a/src/update_objects.h b/src/update_objects.h index bbaf92d9f..50ef50919 100644 --- a/src/update_objects.h +++ b/src/update_objects.h @@ -193,7 +193,6 @@ void func_800797AC(s32); void func_80079860(s32); void func_8007993C(s32, Player*); void func_80079A5C(s32, Player*); -void func_8007A66C(s32, Player*, Camera*); void func_8007A778(s32, Player*, Camera*); void func_8007A884(void); void func_8007A88C(s32); From 9c4b35206a2c697acc7345e91587c52a09240eb9 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sat, 28 Dec 2024 20:30:18 -0700 Subject: [PATCH 2/7] Fix podium ceremony. Wip particle emitters --- src/code_80057C60.c | 29 ++-- src/ending/code_80281780.c | 3 +- src/ending/code_80281780.h | 2 +- src/ending/code_80281C40.c | 2 +- src/engine/World.cpp | 16 ++ src/engine/World.h | 4 + src/engine/courses/PodiumCeremony.cpp | 8 +- src/engine/objects/CheepCheep.cpp | 1 - src/engine/objects/Object.h | 4 +- src/engine/objects/Podium.cpp | 30 ++-- src/engine/objects/Podium.h | 1 + src/engine/objects/Trophy.cpp | 92 +++++++++-- src/engine/objects/Trophy.h | 3 + src/engine/particles/StarEmitter.cpp | 152 ++++++++++++++++- src/engine/particles/StarEmitter.h | 11 +- src/main.c | 2 +- src/port/Game.cpp | 84 +++++++++- src/port/Game.h | 16 +- src/racing/actors.c | 4 +- src/racing/memory.c | 18 +- src/racing/memory.h | 1 - src/racing/race_logic.c | 2 +- src/render_objects.c | 12 -- src/render_objects.h | 2 - src/update_objects.c | 230 -------------------------- src/update_objects.h | 3 - 26 files changed, 407 insertions(+), 325 deletions(-) diff --git a/src/code_80057C60.c b/src/code_80057C60.c index 549b2bc95..a4fb77372 100644 --- a/src/code_80057C60.c +++ b/src/code_80057C60.c @@ -551,22 +551,21 @@ void render_object(u32 arg0) { } void render_object_p1(void) { - gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[0]), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[0]), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); - CourseManager_DrawBombKarts(PLAYER_ONE); - //render_bomb_karts_wrap(PLAYER_ONE); - if (gGamestate == ENDING) { - //func_80055F48(PLAYER_ONE); - //func_80056160(PLAYER_ONE); - //func_8005217C(PLAYER_ONE); - //func_80054BE8(PLAYER_ONE); - return; - } + CourseManager_DrawBombKarts(PLAYER_ONE); // render_bomb_karts_wrap(PLAYER_ONE); + + // if (gGamestate == ENDING) { + // //func_80055F48(PLAYER_ONE); + // //func_80056160(PLAYER_ONE); + // //func_8005217C(PLAYER_ONE); + // //func_80054BE8(PLAYER_ONE); + // return; + // } render_object_for_player(PLAYER_ONE); } @@ -690,8 +689,8 @@ void render_player_snow_effect_four(void) { } void render_object_for_player(s32 cameraId) { - CourseManager_DrawObjects(cameraId); + CM_DrawParticles(cameraId); // CourseManager_RenderCourseObjects(cameraId); // CourseManager_TrainSmokeDraw(cameraId); @@ -1408,6 +1407,7 @@ void func_80059D00(void) { } update_object(); CourseManager_TickObjects(); + CM_TickParticles(); func_800744CC(); } } @@ -1423,12 +1423,15 @@ void func_8005A070(void) { //func_80086604(); //func_80086D80(); //update_cheep_cheep(1); - func_80077640(); + //func_80077640(); + CourseManager_TickObjects(); + CM_TickParticles(); } else if (gGamestate == CREDITS_SEQUENCE) { func_80059820(PLAYER_ONE); func_80078C70(0); CourseManager_TickObjects(); - } else { + CM_TickParticles(); + } else { // normal gameplay func_80059D00(); } } diff --git a/src/ending/code_80281780.c b/src/ending/code_80281780.c index ca20c998c..ec370711c 100644 --- a/src/ending/code_80281780.c +++ b/src/ending/code_80281780.c @@ -89,7 +89,7 @@ void func_802818BC(void) { } } -void load_ceremony_cutscene(void) { +void setup_podium_ceremony(void) { Camera* camera = &cameras[0]; gCurrentCourseId = COURSE_ROYAL_RACEWAY; @@ -164,6 +164,7 @@ void load_ceremony_cutscene(void) { balloons_and_fireworks_init(); init_camera_podium_ceremony(); func_80093E60(); + CourseManager_SpawnActors(); D_801625F8 = (uintptr_t) gHeapEndPtr - gNextFreeMemoryAddress; D_801625FC = ((f32) D_801625F8 / 1000.0f); } diff --git a/src/ending/code_80281780.h b/src/ending/code_80281780.h index cb90e1053..47857bda6 100644 --- a/src/ending/code_80281780.h +++ b/src/ending/code_80281780.h @@ -6,7 +6,7 @@ void debug_switch_character_ceremony_cutscene(void); s32 func_80281880(s32 arg0); void func_802818BC(void); -void load_ceremony_cutscene(void); +void setup_podium_ceremony(void); extern s32 D_80287554; extern f32 D_801647A4; diff --git a/src/ending/code_80281C40.c b/src/ending/code_80281C40.c index ebdcd38f9..50a2b7839 100644 --- a/src/ending/code_80281C40.c +++ b/src/ending/code_80281C40.c @@ -131,7 +131,7 @@ void func_80281D00(void) { render_players_on_screen_one(); gSPDisplayList(gDisplayListHead++, VIRTUAL_TO_PHYSICAL2(&D_80284EE0)); update_actors_loop(); - render_object(PLAYER_ONE + SCREEN_MODE_1P); + render_object(RENDER_SCREEN_MODE_1P_PLAYER_ONE); func_80021B0C(); gSPDisplayList(gDisplayListHead++, VIRTUAL_TO_PHYSICAL2(&D_80284EE0)); func_80093F10(); diff --git a/src/engine/World.cpp b/src/engine/World.cpp index b14c45219..5cd85213b 100644 --- a/src/engine/World.cpp +++ b/src/engine/World.cpp @@ -254,6 +254,10 @@ void World::TickObjects60fps() { } } +ParticleEmitter* World::AddEmitter(ParticleEmitter* emitter) { + Emitters.push_back(emitter); + return Emitters.back(); +} void World::DrawObjects(s32 cameraId) { for (const auto& object : Objects) { @@ -261,6 +265,18 @@ void World::DrawObjects(s32 cameraId) { } } +void World::TickParticles() { + for (const auto& emitter : Emitters) { + emitter->Tick(); + } +} + +void World::DrawParticles(s32 cameraId) { + for (const auto& emitter : Emitters) { + emitter->Draw(cameraId); + } +} + Object* World::GetObjectByIndex(size_t index) { //if (index < this->Objects.size()) { // Assuming GameActor::a is accessible, use reinterpret_cast if needed diff --git a/src/engine/World.h b/src/engine/World.h index 403a708c2..3fa687e76 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -164,6 +164,10 @@ public: void DrawObjects(s32 cameraId); Object *GetObjectByIndex(size_t); + void TickParticles(); + void DrawParticles(s32 cameraId); + ParticleEmitter* AddEmitter(ParticleEmitter* emitter); + void AddCup(Cup*); void SetCup(Cup* cup); const char* GetCupName(); diff --git a/src/engine/courses/PodiumCeremony.cpp b/src/engine/courses/PodiumCeremony.cpp index 6f04bd291..5c4bbe7fb 100644 --- a/src/engine/courses/PodiumCeremony.cpp +++ b/src/engine/courses/PodiumCeremony.cpp @@ -165,11 +165,11 @@ void PodiumCeremony::SpawnActors() { spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_item_box_spawns)); spawn_piranha_plants((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_piranha_plant_spawn)); - gWorldInstance.AddObject(new OCheepCheep(FVector((f32)0xf37e, (f32)0x0013, (f32)0xfe22), OCheepCheep::CheepType::PODIUM_CEREMONY, IPathSpan(0, 0))); - gWorldInstance.AddObject(new OPodium(FVector((f32)0xf37e, (f32)0x0013, (f32)0xfe22))); + gWorldInstance.AddObject(new OCheepCheep(FVector((f32)-3202, (f32)19, (f32)-478), OCheepCheep::CheepType::PODIUM_CEREMONY, IPathSpan(0, 0))); + gWorldInstance.AddObject(new OPodium(FVector((f32)-3202, (f32)19, (f32)-478))); - FVector pos = {0,0,0}; - pos.y = 90.0f; + FVector pos = {0, 90.0f, 0}; + OTrophy::TrophyType type = OTrophy::TrophyType::BRONZE; switch(D_802874D8.unk1D) { case 0: // Bronze diff --git a/src/engine/objects/CheepCheep.cpp b/src/engine/objects/CheepCheep.cpp index e81ba7c24..10cdf6602 100644 --- a/src/engine/objects/CheepCheep.cpp +++ b/src/engine/objects/CheepCheep.cpp @@ -52,7 +52,6 @@ void OCheepCheep::Draw(s32 cameraId) { // func_8005217C Lights1* D_800E45C0l = (Lights1*) (D_800E45C0); Object* object; s32 temp_a3; - temp_a3 = indexObjectList2[0]; object = &gObjectList[temp_a3]; if (object->state >= 2) { diff --git a/src/engine/objects/Object.h b/src/engine/objects/Object.h index c41cfae6d..af2df81b5 100644 --- a/src/engine/objects/Object.h +++ b/src/engine/objects/Object.h @@ -11,14 +11,16 @@ class OObject { public: uint8_t uuid[16]; Object o; + bool PendingDestroy = false; virtual ~OObject() = default; explicit OObject(); virtual void Tick(); + virtual void Tick60fps(); virtual void Draw(s32 cameraId); virtual void Collision(); virtual void Expire(); - virtual void Destroy(); + virtual void Destroy(); // Mark object for deletion at the start of the next frame }; diff --git a/src/engine/objects/Podium.cpp b/src/engine/objects/Podium.cpp index 426a65b60..1922c98a5 100644 --- a/src/engine/objects/Podium.cpp +++ b/src/engine/objects/Podium.cpp @@ -27,24 +27,26 @@ extern Vec3s D_800E634C[]; OPodium::OPodium(const FVector& pos) { + _pos = pos; + for (size_t i = 0; i < NUM_PODIUMS; i++) { s32 objectIndex = indexObjectList1[i]; - init_object(objectIndex, 0); - set_obj_origin_pos(objectIndex, pos.x - 1.5, pos.y, pos.z); + //init_object(objectIndex, 0); + //set_obj_origin_pos(objectIndex, pos.x - 1.5, pos.y, pos.z); } } void OPodium::Tick() { // func_80086604 s32 objectIndex; - // if ((D_8016347C != 0) && (D_802874D8.unk1D < 3)) { - // if (D_801658C6 == 0) { - // for (size_t i = 0; i < 3; i++) { - // objectIndex = indexObjectList1[i]; - // init_object(objectIndex, 0); - // } - // D_801658C6 = 1; - // } - // } + if ((D_8016347C != 0) && (D_802874D8.unk1D < 3)) { + if (D_801658C6 == 0) { + for (size_t i = 0; i < 3; i++) { + objectIndex = indexObjectList1[i]; + init_object(objectIndex, 0); + } + D_801658C6 = 1; + } + } for (size_t i = 0; i != NUM_PODIUMS; i++) { objectIndex = indexObjectList1[i]; if (gObjectList[objectIndex].state != 0) { @@ -58,9 +60,9 @@ void OPodium::Draw(s32 cameraId) { // func_80055F48 for (size_t i = 0; i < NUM_PODIUMS; i++) { Object* object; - object = &gObjectList[i]; + object = &gObjectList[indexObjectList1[i]]; if (object->state >= 2) { - func_80043220(object->pos, object->direction_angle, object->sizeScaling, object->model); + //func_80043220(object->pos, object->direction_angle, object->sizeScaling, object->model); rsp_set_matrix_transformation(object->pos, object->direction_angle, object->sizeScaling); gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0077A0); gSPDisplayList(gDisplayListHead++, object->model); @@ -86,7 +88,7 @@ void OPodium::func_8008629C(s32 objectIndex, s32 arg1) { break; } gObjectList[objectIndex].sizeScaling = 1.0f; - //set_obj_origin_pos(objectIndex, D_800E634C[0][0] - 1.5, D_800E634C[0][1], D_800E634C[0][2]); + set_obj_origin_pos(objectIndex, _pos.x - 1.5, _pos.y, _pos.z); set_obj_origin_offset(objectIndex, 0.0f, -10.0f, 0.0f); set_obj_direction_angle(objectIndex, 0U, 0xF8E4U, 0U); gObjectList[objectIndex].unk_048 = 0; diff --git a/src/engine/objects/Podium.h b/src/engine/objects/Podium.h index 2b3a1033a..ea79d7232 100644 --- a/src/engine/objects/Podium.h +++ b/src/engine/objects/Podium.h @@ -35,4 +35,5 @@ public: private: s32 _idx; + FVector _pos; }; diff --git a/src/engine/objects/Trophy.cpp b/src/engine/objects/Trophy.cpp index 5ac54f5ec..c14cc23ca 100644 --- a/src/engine/objects/Trophy.cpp +++ b/src/engine/objects/Trophy.cpp @@ -24,7 +24,18 @@ OTrophy::OTrophy(const FVector& pos, TrophyType trophy, Behaviour bhv) { _spawnPos.y += 16.0f; // Adjust the height so the trophy sits on the surface when positioned to 0,0,0 _bhv = bhv; - init_object(objectIndex, 0); + if (bhv == OTrophy::Behaviour::PODIUM_CEREMONY) { + _toggleVisibility = &D_801658CE; + } else { + int8_t toggle = 1; + _toggleVisibility = &toggle; + _isMod = true; + } + + // This allows spawning for mods + if (*_toggleVisibility == true) { + init_object(objectIndex, 0); + } switch (trophy) { case TrophyType::GOLD: @@ -47,13 +58,6 @@ OTrophy::OTrophy(const FVector& pos, TrophyType trophy, Behaviour bhv) { break; } - if (OTrophy::Behaviour::PODIUM_CEREMONY) { - _toggleVisibility = &D_801658CE; - } else { - int8_t toggle = 1; - _toggleVisibility = &toggle; - } - // Set defaults for modded behaviours if (_bhv != OTrophy::Behaviour::PODIUM_CEREMONY) { gObjectList[objectIndex].sizeScaling = 0.025f; @@ -81,15 +85,15 @@ void OTrophy::Tick() { // func_80086D80 s32 objectIndex = indexObjectList1[3]; s32 var_s0; - // if ((D_801658CE != 0) && (D_801658DC == 0)) { - // temp_s2 = indexObjectList1[3]; - // init_object(temp_s2, 0); - // D_801658DC = 1; - // } + // Fallback for podium ceremony where the trophy is not spawned until it is needed + if ((*_toggleVisibility == true) && (D_801658DC == 0) && (_isMod == false)) { + init_object(objectIndex, 0); + D_801658DC = 1; + } switch(_bhv) { case OTrophy::Behaviour::PODIUM_CEREMONY: - if (gObjectList[objectIndex].state != 0) { + if (gObjectList[objectIndex].state != 0 && (*_toggleVisibility == true)) { OTrophy::func_80086C14(objectIndex); OTrophy::func_80086940(objectIndex); if (D_801658F4 != 0) { @@ -197,8 +201,7 @@ void OTrophy::Draw(s32 cameraId) { Mat4 someMatrix1; Mat4 someMatrix2; Object* object; - - if (_toggleVisibility) { + if (*_toggleVisibility == true) { object = &gObjectList[listIndex]; if (object->state >= 2) { gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[0]), @@ -332,3 +335,60 @@ void OTrophy::func_80086C6C(s32 objectIndex) { } func_800773D8(sp24, (s32) D_801658F4); } + +void OTrophy::func_800773D8(f32* arg0, s32 arg1) { + s32 objectIndex = add_unused_obj_index(gObjectParticle3, &gNextFreeObjectParticle3, gObjectParticle3_SIZE); + if (objectIndex != NULL_OBJECT_ID) { + func_80077138(objectIndex, arg0, arg1); + } +} + +void OTrophy::func_80077138(s32 objectIndex, Vec3f arg1, s32 arg2) { + s8 temp_v0_3; + Vec3s sp30; + + init_object(objectIndex, arg2); + gObjectList[objectIndex].unk_0D5 = 0x0C; + gObjectList[objectIndex].sizeScaling = 0.05f; + set_obj_origin_pos(objectIndex, arg1[0], arg1[1], arg1[2]); + set_obj_orientation(objectIndex, 0U, 0U, 0U); + set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); + switch (arg2) { + case 0: + gObjectList[objectIndex].velocity[1] = -1.0f; + gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x004BU) * 0.01) + 0.25); + gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; + func_8008751C(objectIndex); + gObjectList[objectIndex].unk_084[5] = 0x001E; + break; + case 1: + gObjectList[objectIndex].velocity[1] = 1.5f; + gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x0064U) * 0.01) + 0.5); + gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; + func_8008751C(objectIndex); + gObjectList[objectIndex].unk_084[5] = 0x0032; + break; + } + temp_v0_3 = random_int(0x000CU); + if (temp_v0_3 < 9) { + func_8005C674(temp_v0_3, &sp30[2], &sp30[1], sp30); + gObjectList[objectIndex].unk_048 = 0; + gObjectList[objectIndex].unk_084[0] = sp30[2]; + gObjectList[objectIndex].unk_084[1] = sp30[1]; + gObjectList[objectIndex].unk_084[2] = sp30[0]; + } else { + temp_v0_3 = random_int(3U); + func_8005C6B4(temp_v0_3, &sp30[2], &sp30[1], sp30); + gObjectList[objectIndex].unk_084[0] = sp30[2]; + gObjectList[objectIndex].unk_084[1] = sp30[1]; + gObjectList[objectIndex].unk_084[2] = sp30[0]; + gObjectList[objectIndex].unk_084[4] = temp_v0_3; + gObjectList[objectIndex].unk_048 = 1; + } + gObjectList[objectIndex].primAlpha = 0x00FF; + gObjectList[objectIndex].unk_084[3] = random_int(0x0800U) + 0x400; + if ((gObjectList[objectIndex].direction_angle[1] < 0x3000) || + (gObjectList[objectIndex].direction_angle[1] >= 0xB001)) { + gObjectList[objectIndex].unk_084[3] = -gObjectList[objectIndex].unk_084[3]; + } +} \ No newline at end of file diff --git a/src/engine/objects/Trophy.h b/src/engine/objects/Trophy.h index d413faf12..a227ef5b9 100644 --- a/src/engine/objects/Trophy.h +++ b/src/engine/objects/Trophy.h @@ -43,6 +43,8 @@ public: void func_80086940(s32 objectIndex); void func_80086C14(s32 objectIndex); void func_80086C6C(s32 objectIndex); + void func_800773D8(f32* arg0, s32 arg1); + void func_80077138(s32 objectIndex, Vec3f arg1, s32 arg2); private: @@ -52,4 +54,5 @@ private: Behaviour _bhv; int8_t *_toggleVisibility; Vec3f _oldPos; + bool _isMod = false; }; diff --git a/src/engine/particles/StarEmitter.cpp b/src/engine/particles/StarEmitter.cpp index b717f177d..14745d39a 100644 --- a/src/engine/particles/StarEmitter.cpp +++ b/src/engine/particles/StarEmitter.cpp @@ -6,10 +6,89 @@ extern "C" { #include "render_objects.h" #include "common_data.h" #include "code_80057C60.h" +#include "update_objects.h" +#include "code_80086E70.h" +#include "math_util.h" +#include "math_util_2.h" } -void StarEmitter::Tick() { +StarEmitter::StarEmitter(FVector pos) { + s32 objectIndex = add_unused_obj_index(gObjectParticle3, &gNextFreeObjectParticle3, gObjectParticle3_SIZE); + s8 temp_v0_3; + Vec3s sp30; + if (objectIndex == NULL_OBJECT_ID) { + return; + //func_80077138(objectIndex, arg0, arg1); + } + + D_801658F4 = 1; + + init_object(objectIndex, D_801658F4); + gObjectList[objectIndex].unk_0D5 = 0x0C; + gObjectList[objectIndex].sizeScaling = 0.05f; + set_obj_origin_pos(objectIndex, pos.x, pos.y, pos.z); + set_obj_orientation(objectIndex, 0U, 0U, 0U); + set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); + switch (D_801658F4) { + case 0: + gObjectList[objectIndex].velocity[1] = -1.0f; + gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x004BU) * 0.01) + 0.25); + gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; + func_8008751C(objectIndex); + gObjectList[objectIndex].unk_084[5] = 0x001E; + break; + case 1: + gObjectList[objectIndex].velocity[1] = 1.5f; + gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x0064U) * 0.01) + 0.5); + gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; + func_8008751C(objectIndex); + gObjectList[objectIndex].unk_084[5] = 0x0032; + break; + } + temp_v0_3 = random_int(0x000CU); + if (temp_v0_3 < 9) { + func_8005C674(temp_v0_3, &sp30[2], &sp30[1], sp30); + gObjectList[objectIndex].unk_048 = 0; + gObjectList[objectIndex].unk_084[0] = sp30[2]; + gObjectList[objectIndex].unk_084[1] = sp30[1]; + gObjectList[objectIndex].unk_084[2] = sp30[0]; + } else { + temp_v0_3 = random_int(3U); + func_8005C6B4(temp_v0_3, &sp30[2], &sp30[1], sp30); + gObjectList[objectIndex].unk_084[0] = sp30[2]; + gObjectList[objectIndex].unk_084[1] = sp30[1]; + gObjectList[objectIndex].unk_084[2] = sp30[0]; + gObjectList[objectIndex].unk_084[4] = temp_v0_3; + gObjectList[objectIndex].unk_048 = 1; + } + gObjectList[objectIndex].primAlpha = 0x00FF; + gObjectList[objectIndex].unk_084[3] = random_int(0x0800U) + 0x400; + if ((gObjectList[objectIndex].direction_angle[1] < 0x3000) || + (gObjectList[objectIndex].direction_angle[1] >= 0xB001)) { + gObjectList[objectIndex].unk_084[3] = -gObjectList[objectIndex].unk_084[3]; + } +} + +void StarEmitter::Tick() { // func_80077640 + s32 someIndex; + s32 objectIndex; + Object* object; + + for (someIndex = 0; someIndex < gObjectParticle3_SIZE; someIndex++) { + objectIndex = gObjectParticle3[someIndex]; + if (objectIndex != DELETED_OBJECT_ID) { + object = &gObjectList[objectIndex]; + printf("Tick Star %d\n", object->state); + if (object->state != 0) { + StarEmitter::func_80077450(objectIndex); + StarEmitter::func_80077584(objectIndex); + if (object->state == 0) { + delete_object_wrapper(&gObjectParticle3[someIndex]); + } + } + } + } } void StarEmitter::Draw(s32 cameraId) { // func_80054BE8 @@ -22,10 +101,79 @@ void StarEmitter::Draw(s32 cameraId) { // func_80054BE8 load_texture_block_ia8_nomirror(D_8018D488, 0x00000020, 0x00000020); func_8004B35C(0x000000FF, 0x000000FF, 0, 0x000000FF); D_80183E80[0] = 0; + printf("Draw Star\n"); for (var_s0 = 0; var_s0 < gObjectParticle3_SIZE; var_s0++) { temp_a0 = gObjectParticle3[var_s0]; if ((temp_a0 != -1) && (gObjectList[temp_a0].state >= 2)) { - func_80054AFC(temp_a0, camera->pos); + StarEmitter::func_80054AFC(temp_a0, camera->pos); } } } + +void StarEmitter::func_80054AFC(s32 objectIndex, Vec3f arg1) { + printf("Drawing Star!\n"); + D_80183E80[0] = func_800418E8(gObjectList[objectIndex].pos[2], gObjectList[objectIndex].pos[1], arg1); + D_80183E80[1] = func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], arg1); + D_80183E80[2] = (u16) gObjectList[objectIndex].orientation[2]; + func_8004B138((s32) gObjectList[objectIndex].unk_084[0], (s32) gObjectList[objectIndex].unk_084[1], + (s32) gObjectList[objectIndex].unk_084[2], (s32) gObjectList[objectIndex].primAlpha); + rsp_set_matrix_transformation(gObjectList[objectIndex].pos, (u16*) D_80183E80, + gObjectList[objectIndex].sizeScaling); + gSPVertex(gDisplayListHead++, (uintptr_t)D_0D005AE0, 4, 0); + gSPDisplayList(gDisplayListHead++, (Gfx*)common_rectangle_display); +} + +void StarEmitter::func_80077428(s32 objectIndex) { + object_next_state(objectIndex); + func_80086E70(objectIndex); +} + +void StarEmitter::func_80077584(s32 objectIndex) { + Object* object; + + object = &gObjectList[objectIndex]; + if ((object->unk_0AE != 0) && (object->unk_0AE == 1) && ((u8) object->unk_0D8 != 0)) { + if (object->velocity[1] >= -0.5) { + object->velocity[1] -= 0.15; + } else { + object->velocity[2] = 0.0f; + object->velocity[0] = 0.0f; + } + } + object->orientation[2] += object->unk_084[3]; + object_add_velocity_offset_xyz(objectIndex); + object_calculate_new_pos_offset(objectIndex); +} + +void StarEmitter::func_80077450(s32 objectIndex) { + UNUSED s16 stackPadding0; + s16 sp3C; + s16 sp3A; + s16 sp38; + + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + StarEmitter::func_80077428(objectIndex); + break; + case 2: + f32_step_up_towards(&gObjectList[objectIndex].sizeScaling, 0.1f, 0.01f); + if ((gObjectList[objectIndex].pos[1] <= gObjectList[objectIndex].unk_084[5]) && + (func_80073B00(objectIndex, &gObjectList[objectIndex].primAlpha, 0x000000FF, 0, 0x00000010, 0, 0) != + 0)) { + func_80086F60(objectIndex); + func_80072428(objectIndex); + } + break; + } + if (gObjectList[objectIndex].unk_048 != 0) { + printf("SOME THING\n"); + + gObjectList[objectIndex].unk_084[4] = (s16) ((s32) (gObjectList[objectIndex].unk_084[4] + 1) % 3); + func_8005C6B4(gObjectList[objectIndex].unk_084[4], &sp3C, &sp3A, &sp38); + gObjectList[objectIndex].unk_084[0] = sp3C; + gObjectList[objectIndex].unk_084[1] = sp3A; + gObjectList[objectIndex].unk_084[2] = sp38; + } +} \ No newline at end of file diff --git a/src/engine/particles/StarEmitter.h b/src/engine/particles/StarEmitter.h index 20841598c..285c959f4 100644 --- a/src/engine/particles/StarEmitter.h +++ b/src/engine/particles/StarEmitter.h @@ -3,6 +3,7 @@ #include #include #include "ParticleEmitter.h" +#include "World.h" extern "C" { #include "macros.h" @@ -27,14 +28,14 @@ public: f32 Diameter = 0.0f; // Waddle in a circle around the spawn point at this diameter. uint16_t MirrorModeAngleOffset; - explicit StarEmitter(Vec3f pos); + explicit StarEmitter(FVector pos); virtual void Tick() override; virtual void Draw(s32 cameraId) override; - void func_80086700(s32 objectIndex); - void func_80086940(s32 objectIndex); - void func_80086C14(s32 objectIndex); - void func_80086C6C(s32 objectIndex); + void func_80077428(s32 objectIndex); + void func_80077584(s32 objectIndex); + void func_80077450(s32 objectIndex); + void func_80054AFC(s32 objectIndex, Vec3f arg1); private: diff --git a/src/main.c b/src/main.c index b932c7a12..ed98b5f3f 100644 --- a/src/main.c +++ b/src/main.c @@ -1205,7 +1205,7 @@ void update_gamestate(void) { case ENDING: gCurrentlyLoadedCourseId = COURSE_NULL; init_segment_ending_sequences(); - load_ceremony_cutscene(); + setup_podium_ceremony(); break; case CREDITS_SEQUENCE: gCurrentlyLoadedCourseId = COURSE_NULL; diff --git a/src/port/Game.cpp b/src/port/Game.cpp index d6cf9643c..90869508e 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -31,8 +31,11 @@ #include "engine/courses/PodiumCeremony.h" +#include "engine/GarbageCollector.h" + #include "engine/TrainCrossing.h" -#include "src/engine/objects/BombKart.h" +#include "engine/objects/BombKart.h" +#include "engine/objects/Lakitu.h" #include "Smoke.h" @@ -365,7 +368,7 @@ extern "C" { } } - void CourseManager_DrawActor(Camera* camera, struct Actor* actor) { + void CourseManager_DrawActors(Camera* camera, struct Actor* actor) { AActor* a = gWorldInstance.ConvertActorToAActor(actor); if (a->IsMod()) { a->Draw(camera); @@ -384,12 +387,32 @@ extern "C" { } } + // A couple objects such as lakitu are ticked inside of process_game_tick which support 60fps. + // This is a fallback to support that. + void CourseManager_TickObjects60fps() { + if (gWorldInstance.CurrentCourse) { + gWorldInstance.TickObjects60fps(); + } + } + void CourseManager_DrawObjects(s32 cameraId) { if (gWorldInstance.CurrentCourse) { gWorldInstance.DrawObjects(cameraId); } } + void CM_TickParticles() { + if (gWorldInstance.CurrentCourse) { + gWorldInstance.TickParticles(); + } + } + + void CM_DrawParticles(s32 cameraId) { + if (gWorldInstance.CurrentCourse) { + gWorldInstance.DrawParticles(cameraId); + } + } + // Helps prevents users from forgetting to add a finishline to their course bool cm_DoesFinishlineExist() { for (AActor* actor : gWorldInstance.Actors) { @@ -503,6 +526,50 @@ extern "C" { } } + /** + * This should only be ran once per course, otherwise animation/timings might become sped up. + */ + void CM_SpawnStarterLakitu() { + if ((gDemoMode) || (gGamestate == CREDITS_SEQUENCE)) { + return; + } + + for (size_t i = 0; i < gPlayerCountSelection1; i++) { + OLakitu* lakitu = new OLakitu(i, OLakitu::LakituType::STARTER); + gWorldInstance.Lakitus[i] = lakitu; + gWorldInstance.AddObject(lakitu); + } + } + + // Checkered flag lakitu + void CM_ActivateFinishLakitu(s32 playerId) { + if ((gDemoMode) || (gGamestate == CREDITS_SEQUENCE)) { + return; + } + gWorldInstance.Lakitus[playerId]->Activate(OLakitu::LakituType::FINISH); + } + + void CM_ActivateSecondLapLakitu(s32 playerId) { + if ((gDemoMode) || (gGamestate == CREDITS_SEQUENCE)) { + return; + } + gWorldInstance.Lakitus[playerId]->Activate(OLakitu::LakituType::SECOND_LAP); + } + + void CM_ActivateFinalLapLakitu(s32 playerId) { + if ((gDemoMode) || (gGamestate == CREDITS_SEQUENCE)) { + return; + } + gWorldInstance.Lakitus[playerId]->Activate(OLakitu::LakituType::FINAL_LAP); + } + + void CM_ActivateReverseLakitu(s32 playerId) { + if ((gDemoMode) || (gGamestate == CREDITS_SEQUENCE)) { + return; + } + gWorldInstance.Lakitus[playerId]->Activate(OLakitu::LakituType::REVERSE); + } + extern Vec3su D_80165834; void CourseManager_TickThwomps() { // TickLights @@ -614,8 +681,14 @@ extern "C" { } } - void m_ClearActors(void) { + /** + * Clean up actors and other game objects. + */ + void CM_CleanWorld(void) { gWorldInstance.Actors.clear(); + gWorldInstance.Objects.clear(); + gWorldInstance.Emitters.clear(); + gWorldInstance.Lakitus.clear(); } struct Actor* m_AddBaseActor(void) { @@ -737,6 +810,11 @@ extern "C" { void* GetBattleCup(void) { return gBattleCup; } + + // End of frame cleanup of actors, objects, etc. + void CM_RunGarbageCollector(void) { + RunGarbageCollector(); + } } void push_frame() { diff --git a/src/port/Game.h b/src/port/Game.h index 008d86ef7..76ae4ac2d 100644 --- a/src/port/Game.h +++ b/src/port/Game.h @@ -43,15 +43,25 @@ void CourseManager_RenderCredits(); void CourseManager_SpawnActors(); +void CM_SpawnStarterLakitu(); +void CM_ActivateFinishLakitu(s32 playerId); +void CM_ActivateSecondLapLakitu(s32 playerId); +void CM_ActivateFinalLapLakitu(s32 playerId); +void CM_ActivateReverseLakitu(s32 playerId); + bool cm_DoesFinishlineExist(); void CourseManager_InitClouds(); -void CourseManager_DrawActor(Camera* camera, struct Actor* actor); +void CourseManager_DrawActors(Camera* camera, struct Actor* actor); void CourseManager_TickObjects(); +void CourseManager_TickObjects60fps(); void CourseManager_DrawObjects(s32 cameraId); +void CM_TickParticles(void); +void CM_DrawParticles(s32 cameraId); + void CourseManager_UpdateClouds(s32 arg0, Camera* camera); void CourseManager_Waypoints(Player* player, int8_t playerId); @@ -149,7 +159,7 @@ struct Actor* m_AddBaseActor(void); size_t m_GetActorSize(); size_t m_FindActorIndex(struct Actor* actor); void m_ActorCollision(Player* player, struct Actor* actor); -void m_ClearActors(void); +void CM_CleanWorld(void); void* GetMarioRaceway(void); @@ -205,6 +215,8 @@ void* GetBattleCup(void); void* GetCup(); +void CM_RunGarbageCollector(void); + #ifdef __cplusplus } #endif diff --git a/src/racing/actors.c b/src/racing/actors.c index bc031a568..45330916c 100644 --- a/src/racing/actors.c +++ b/src/racing/actors.c @@ -1214,7 +1214,7 @@ void init_actors_and_load_textures(void) { init_red_shell_texture(); destroy_all_actors(); - m_ClearActors(); + CM_CleanWorld(); spawn_course_actors(); CourseManager_VehiclesSpawn(); @@ -2428,7 +2428,7 @@ void render_course_actors(struct UnkStruct_800DC5EC* arg0) { } switch (actor->type) { default: // Draw custom actor - CourseManager_DrawActor(D_800DC5EC->camera, actor); + CourseManager_DrawActors(D_800DC5EC->camera, actor); break; case ACTOR_TREE_MARIO_RACEWAY: render_actor_tree_mario_raceway(camera, sBillBoardMtx, actor); diff --git a/src/racing/memory.c b/src/racing/memory.c index 4538fd1ec..ac16e7b51 100644 --- a/src/racing/memory.c +++ b/src/racing/memory.c @@ -489,7 +489,7 @@ u8* dma_textures(const char* texture, size_t arg1, size_t arg2) { #ifdef TARGET_N64 temp_v0 = (u8*) gNextFreeMemoryAddress; #else - //u8* tex = (u8*) LOAD_ASSET(texture); + u8* tex = (u8*) LOAD_ASSET(texture); temp_v0 = (u8*) allocate_memory(arg2); #endif @@ -504,8 +504,8 @@ u8* dma_textures(const char* texture, size_t arg1, size_t arg2) { mio0decode((u8*) temp_a0, temp_v0); gNextFreeMemoryAddress += arg2; #else - //memcpy(temp_v0, tex, arg2); - strcpy(temp_v0, texture); + memcpy(temp_v0, tex, arg2); + //strcpy(temp_v0, texture); #endif return temp_v0; } @@ -1483,10 +1483,6 @@ uintptr_t texSegEnd; size_t texSegSize; Gfx* testaaa; -/** - * @brief Loads & DMAs course data. Vtx, textures, displaylists, etc. - * @param courseId - */ u8* load_lakitu_tlut_x64(const char** textureList, size_t length) { // Calculate lakitu texture size to allocate size_t size = 0; @@ -1498,7 +1494,7 @@ u8* load_lakitu_tlut_x64(const char** textureList, size_t length) { gNextFreeMemoryAddress += size; size_t offset = 0; for (size_t i = 0; i < length; i++) { - u8* tex = (u8*) LOAD_ASSET(textureList[i]); + u8* tex = (u8*) LOAD_ASSET_RAW(textureList[i]); size_t texSize = ResourceGetTexSizeByName(textureList[i]); // printf("\nTEX SIZE: %X\n\n", texSize); memcpy(&textures[offset], tex, texSize); @@ -1507,9 +1503,13 @@ u8* load_lakitu_tlut_x64(const char** textureList, size_t length) { return textures; } +/** + * @brief Loads & DMAs course data. Vtx, textures, displaylists, etc. + * @param courseId + */ void load_course(s32 courseId) { printf("Loading Course %d\n", courseId); gNextFreeMemoryAddress = gFreeMemoryResetAnchor; - m_ClearActors(); + CM_CleanWorld(); LoadCourse(); } diff --git a/src/racing/memory.h b/src/racing/memory.h index 9fbcd2e6d..8f4fbe2b5 100644 --- a/src/racing/memory.h +++ b/src/racing/memory.h @@ -42,7 +42,6 @@ struct AllocOnlyPool { extern f32 vtxStretchY; -u8* load_lakitu_textures_x64(const char** textureList, size_t length); u8* load_lakitu_tlut_x64(const char** textureList, size_t length); void* get_next_available_memory_addr(uintptr_t); uintptr_t set_segment_base_addr(s32, void*); diff --git a/src/racing/race_logic.c b/src/racing/race_logic.c index 025b50d79..655a8093b 100644 --- a/src/racing/race_logic.c +++ b/src/racing/race_logic.c @@ -904,7 +904,7 @@ void func_8028FCBC(void) { D_800DC510 = 2; D_800DC5B0 = 0; D_800DC5B8 = 1; - func_80078F64(); + CM_SpawnStarterLakitu(); // func_80078F64(); if ((gModeSelection == TIME_TRIALS) && (D_80162DD6 == 0)) { phi_v0_4 = 0x1; for (i = 0; i < gCurrentCourseId; i++) { diff --git a/src/render_objects.c b/src/render_objects.c index ac53334fa..f747f50d2 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -3836,18 +3836,6 @@ void render_object_smoke_particles(s32 cameraId) { } } -void func_80054AFC(s32 objectIndex, Vec3f arg1) { - D_80183E80[0] = func_800418E8(gObjectList[objectIndex].pos[2], gObjectList[objectIndex].pos[1], arg1); - D_80183E80[1] = func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], arg1); - D_80183E80[2] = (u16) gObjectList[objectIndex].orientation[2]; - func_8004B138((s32) gObjectList[objectIndex].unk_084[0], (s32) gObjectList[objectIndex].unk_084[1], - (s32) gObjectList[objectIndex].unk_084[2], (s32) gObjectList[objectIndex].primAlpha); - rsp_set_matrix_transformation(gObjectList[objectIndex].pos, (u16*) D_80183E80, - gObjectList[objectIndex].sizeScaling); - gSPVertex(gDisplayListHead++, D_0D005AE0, 4, 0); - gSPDisplayList(gDisplayListHead++, common_rectangle_display); -} - void func_80055164(s32 objectIndex) { if (gObjectList[objectIndex].state >= 2) { gSPDisplayList(gDisplayListHead++, D_0D0077A0); diff --git a/src/render_objects.h b/src/render_objects.h index ec95a0832..045262029 100644 --- a/src/render_objects.h +++ b/src/render_objects.h @@ -358,7 +358,6 @@ void render_object_bowser_flame_particle(s32, s32); void render_object_bowser_flame(s32); void func_8005477C(s32, u8, Vec3f); void render_object_smoke_particles(s32); -void func_80054AFC(s32, Vec3f); void func_80054D00(s32, s32); void func_80054E10(s32); void func_80054EB8(s32); @@ -381,7 +380,6 @@ void func_80055CCC(s32, s32); void render_object_hot_air_balloon(s32); void func_80055EF4(s32, s32); void func_80055F48(s32); -void func_80055FA0(s32, s32); void func_80056160(s32); void render_object_neon(s32); diff --git a/src/update_objects.c b/src/update_objects.c index ba56a65a5..148ba7b50 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -2206,160 +2206,6 @@ void init_smoke_particles(s32 arg0) { } } -void func_80077138(s32 objectIndex, Vec3f arg1, s32 arg2) { - s8 temp_v0_3; - Vec3s sp30; - - init_object(objectIndex, arg2); - gObjectList[objectIndex].unk_0D5 = 0x0C; - gObjectList[objectIndex].sizeScaling = 0.05f; - set_obj_origin_pos(objectIndex, arg1[0], arg1[1], arg1[2]); - set_obj_orientation(objectIndex, 0U, 0U, 0U); - set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); - switch (arg2) { - case 0: - gObjectList[objectIndex].velocity[1] = -1.0f; - gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x004BU) * 0.01) + 0.25); - gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; - func_8008751C(objectIndex); - gObjectList[objectIndex].unk_084[5] = 0x001E; - break; - case 1: - gObjectList[objectIndex].velocity[1] = 1.5f; - gObjectList[objectIndex].unk_034 = (f32) ((random_int(0x0064U) * 0.01) + 0.5); - gObjectList[objectIndex].direction_angle[1] = random_int(0x0040U) << 0xA; - func_8008751C(objectIndex); - gObjectList[objectIndex].unk_084[5] = 0x0032; - break; - } - temp_v0_3 = random_int(0x000CU); - if (temp_v0_3 < 9) { - func_8005C674(temp_v0_3, &sp30[2], &sp30[1], sp30); - gObjectList[objectIndex].unk_048 = 0; - gObjectList[objectIndex].unk_084[0] = sp30[2]; - gObjectList[objectIndex].unk_084[1] = sp30[1]; - gObjectList[objectIndex].unk_084[2] = sp30[0]; - } else { - temp_v0_3 = random_int(3U); - func_8005C6B4(temp_v0_3, &sp30[2], &sp30[1], sp30); - gObjectList[objectIndex].unk_084[0] = sp30[2]; - gObjectList[objectIndex].unk_084[1] = sp30[1]; - gObjectList[objectIndex].unk_084[2] = sp30[0]; - gObjectList[objectIndex].unk_084[4] = temp_v0_3; - gObjectList[objectIndex].unk_048 = 1; - } - gObjectList[objectIndex].primAlpha = 0x00FF; - gObjectList[objectIndex].unk_084[3] = random_int(0x0800U) + 0x400; - if ((gObjectList[objectIndex].direction_angle[1] < 0x3000) || - (gObjectList[objectIndex].direction_angle[1] >= 0xB001)) { - gObjectList[objectIndex].unk_084[3] = -gObjectList[objectIndex].unk_084[3]; - } -} - -void func_800773D8(f32* arg0, s32 arg1) { - s32 objectIndex = add_unused_obj_index(gObjectParticle3, &gNextFreeObjectParticle3, gObjectParticle3_SIZE); - if (objectIndex != NULL_OBJECT_ID) { - func_80077138(objectIndex, arg0, arg1); - } -} - -void func_80077428(s32 arg0) { - object_next_state(arg0); - func_80086E70(arg0); -} - - - - - - - - - - - - - -void func_80077450(s32 objectIndex) { - UNUSED s16 stackPadding0; - s16 sp3C; - s16 sp3A; - s16 sp38; - - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - func_80077428(objectIndex); - break; - case 2: - f32_step_up_towards(&gObjectList[objectIndex].sizeScaling, 0.1f, 0.01f); - if ((gObjectList[objectIndex].pos[1] <= gObjectList[objectIndex].unk_084[5]) && - (func_80073B00(objectIndex, &gObjectList[objectIndex].primAlpha, 0x000000FF, 0, 0x00000010, 0, 0) != - 0)) { - func_80086F60(objectIndex); - func_80072428(objectIndex); - } - break; - } - if (gObjectList[objectIndex].unk_048 != 0) { - gObjectList[objectIndex].unk_084[4] = (s16) ((s32) (gObjectList[objectIndex].unk_084[4] + 1) % 3); - func_8005C6B4(gObjectList[objectIndex].unk_084[4], &sp3C, &sp3A, &sp38); - gObjectList[objectIndex].unk_084[0] = sp3C; - gObjectList[objectIndex].unk_084[1] = sp3A; - gObjectList[objectIndex].unk_084[2] = sp38; - } -} - -void func_80077584(s32 objectIndex) { - Object* object; - - object = &gObjectList[objectIndex]; - if ((object->unk_0AE != 0) && (object->unk_0AE == 1) && ((u8) object->unk_0D8 != 0)) { - if (object->velocity[1] >= -0.5) { - object->velocity[1] -= 0.15; - } else { - object->velocity[2] = 0.0f; - object->velocity[0] = 0.0f; - } - } - object->orientation[2] += object->unk_084[3]; - object_add_velocity_offset_xyz(objectIndex); - object_calculate_new_pos_offset(objectIndex); -} - -void func_80077640(void) { - s32 someIndex; - s32 objectIndex; - Object* object; - - for (someIndex = 0; someIndex < gObjectParticle3_SIZE; someIndex++) { - objectIndex = gObjectParticle3[someIndex]; - if (objectIndex != DELETED_OBJECT_ID) { - object = &gObjectList[objectIndex]; - if (object->state != 0) { - func_80077450(objectIndex); - func_80077584(objectIndex); - if (object->state == 0) { - delete_object_wrapper(&gObjectParticle3[someIndex]); - } - } - } - } -} - - - - - - - - - - - - - void init_object_leaf_particle(s32 objectIndex, Vec3f arg1, s32 num) { @@ -4375,54 +4221,6 @@ void func_8007DDC0(s32 objectIndex) { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void func_8007E1F4(s32 objectIndex) { f32 sp2C; Object* object; @@ -4555,34 +4353,6 @@ void func_8008153C(s32 objectIndex) { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - #ifdef NON_MATCHING // https://decomp.me/scratch/PYAg4 // Stack issue caused by the `test` variable, but removing it causes much, much larger differences diff --git a/src/update_objects.h b/src/update_objects.h index 50ef50919..8ac2848dd 100644 --- a/src/update_objects.h +++ b/src/update_objects.h @@ -160,9 +160,6 @@ void func_80076F2C(void); void init_object_smoke_particle2(s32, s32); void init_smoke_particles(s32); void func_800773D8(f32*, s32); -void func_80077428(s32); -void func_80077450(s32); -void func_80077584(s32); void func_80077640(void); void init_object_leaf_particle(s32, Vec3f, s32); s32 init_leaf_particle(Vec3f, s32); From e4737ce2f5bd75a3153dbe52684677964faa4ccc Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 29 Dec 2024 16:52:26 -0700 Subject: [PATCH 3/7] Impl Hedgehog and Flagpole --- .../update_objects/func_80082F1C.s | 4 +- include/objects.h | 2 +- src/data/some_data.c | 2 +- src/data/some_data.h | 2 +- src/engine/World.h | 16 ++ src/engine/courses/TestCourse.cpp | 11 +- src/engine/courses/YoshiValley.cpp | 59 +++-- src/engine/objects/Flagpole.cpp | 85 +++++++ src/engine/objects/Flagpole.h | 45 ++++ src/engine/objects/Hedgehog.cpp | 183 ++++++++++++++++ src/engine/objects/Hedgehog.h | 53 +++++ src/engine/objects/Seagull.cpp | 18 +- src/engine/objects/Seagull.h | 1 + src/engine/objects/Snowman.cpp | 49 ++++- src/engine/objects/Snowman.h | 2 + src/engine/particles/StarEmitter.cpp | 11 +- src/render_objects.c | 107 --------- src/render_objects.h | 6 - src/update_objects.c | 207 ------------------ src/update_objects.h | 5 - 20 files changed, 496 insertions(+), 372 deletions(-) create mode 100644 src/engine/objects/Flagpole.cpp create mode 100644 src/engine/objects/Flagpole.h create mode 100644 src/engine/objects/Hedgehog.cpp create mode 100644 src/engine/objects/Hedgehog.h diff --git a/asm/non_matchings/update_objects/func_80082F1C.s b/asm/non_matchings/update_objects/func_80082F1C.s index bc5df84bf..61ac0e470 100644 --- a/asm/non_matchings/update_objects/func_80082F1C.s +++ b/asm/non_matchings/update_objects/func_80082F1C.s @@ -28,8 +28,8 @@ glabel func_80082F1C /* 083B68 80082F68 0C01C922 */ jal object_next_state /* 083B6C 80082F6C E4440000 */ swc1 $f4, ($v0) /* 083B70 80082F70 8FA9002C */ lw $t1, 0x2c($sp) -/* 083B74 80082F74 3C0B800E */ lui $t3, %hi(D_800E5DF4) # $t3, 0x800e -/* 083B78 80082F78 256B5DF4 */ addiu $t3, %lo(D_800E5DF4) # addiu $t3, $t3, 0x5df4 +/* 083B74 80082F74 3C0B800E */ lui $t3, %hi(gFlagpoleSpawns) # $t3, 0x800e +/* 083B78 80082F78 256B5DF4 */ addiu $t3, %lo(gFlagpoleSpawns) # addiu $t3, $t3, 0x5df4 /* 083B7C 80082F7C 000950C0 */ sll $t2, $t1, 3 /* 083B80 80082F80 014B1021 */ addu $v0, $t2, $t3 /* 083B84 80082F84 844C0000 */ lh $t4, ($v0) diff --git a/include/objects.h b/include/objects.h index d4da8cd95..fecc902a3 100644 --- a/include/objects.h +++ b/include/objects.h @@ -223,7 +223,7 @@ typedef struct { /* 0x6 */ u16 rot; } YVFlagPoleSpawn; // size = 0x8; -extern YVFlagPoleSpawn D_800E5DF4[]; +extern YVFlagPoleSpawn gFlagpoleSpawns[]; #define NUM_CRABS 0xA diff --git a/src/data/some_data.c b/src/data/some_data.c index 431e60247..1a2acd086 100644 --- a/src/data/some_data.c +++ b/src/data/some_data.c @@ -439,7 +439,7 @@ s8 D_800E5DB4[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -YVFlagPoleSpawn D_800E5DF4[] = { +YVFlagPoleSpawn gFlagpoleSpawns[] = { { { 0xfc7a, 0x0046, 0xfa82 }, 0x3800 }, { { 0xfc4c, 0x0046, 0xfa03 }, 0x3800 }, { { 0xf786, 0x0000, 0x02d3 }, 0x0400 }, diff --git a/src/data/some_data.h b/src/data/some_data.h index 90b9b13ac..6ee5272b0 100644 --- a/src/data/some_data.h +++ b/src/data/some_data.h @@ -50,7 +50,7 @@ extern SplineData D_800E5D78; extern SplineData* D_800E5D9C[]; extern SplineData* D_800E5DB0; extern s8 D_800E5DB4[]; -extern YVFlagPoleSpawn D_800E5DF4[]; +extern YVFlagPoleSpawn gFlagpoleSpawns[]; extern HegdehogSpawn gHedgehogSpawns[]; extern Vec3s gHedgehogPatrolPoints[]; extern SnowmanSpawn gSnowmanSpawns[]; diff --git a/src/engine/World.h b/src/engine/World.h index 3fa687e76..1aa09fb57 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -35,6 +35,22 @@ struct FVector { } }; +/** + * For providing X and Z when you do not need Y + * Some actors set themselves on the surface automatically + * which means it does not use a Y coordinate + * The train follows a set Y value. The hedgehog's patrolPoint only uses X and Z. + */ +struct FVector2D { + float x, z; + + FVector2D& operator=(const FVector2D& other) { + x = other.x; + z = other.z; + return *this; + } +}; + struct FRotation { float pitch, yaw, roll; diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index ce8d8ca62..3f95dc56b 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -18,6 +18,9 @@ #include "engine/objects/CheepCheep.h" #include "engine/objects/Snowman.h" #include "engine/objects/TrashBin.h" +#include "engine/objects/Hedgehog.h" +#include "engine/objects/Flagpole.h" +#include "engine/particles/StarEmitter.h" extern "C" { #include "main.h" @@ -201,8 +204,12 @@ void TestCourse::SpawnActors() { // gWorldInstance.AddActor(new OSeagull(3, pos)); // gWorldInstance.AddObject(new OCheepCheep(FVector(0, 40, 0), OCheepCheep::CheepType::RACE, IPathSpan(0, 10))); // gWorldInstance.AddObject(new OTrophy(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH)); - gWorldInstance.AddObject(new OSnowman(FVector(0, 0, 0))); - gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), FRotation(0, 90, 0), 1.0f)); + //gWorldInstance.AddObject(new OSnowman(FVector(0, 0, 0))); + //gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), FRotation(0, 90, 0), 1.0f)); + +//gWorldInstance.AddEmitter(new StarEmitter(FVector(0,50,0))); + //gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9)); + //gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400)); } // Likely sets minimap boundaries diff --git a/src/engine/courses/YoshiValley.cpp b/src/engine/courses/YoshiValley.cpp index 770e5ae1d..25c11daf8 100644 --- a/src/engine/courses/YoshiValley.cpp +++ b/src/engine/courses/YoshiValley.cpp @@ -7,6 +7,8 @@ #include "World.h" #include "engine/actors/AFinishline.h" #include "engine/objects/BombKart.h" +#include "engine/objects/Hedgehog.h" +#include "engine/objects/Flagpole.h" #include "assets/yoshi_valley_data.h" #include "assets/boo_frames.h" @@ -147,6 +149,30 @@ void YoshiValley::SpawnActors() { vec3f_set(position, -2300.0f, 0.0f, 634.0f); position[0] *= gCourseDirection; add_actor_to_empty_slot(position, rotation, velocity, ACTOR_YOSHI_EGG); + + if (gGamestate != CREDITS_SEQUENCE) { + //! @bug Skip spawning in credits due to animation crash for now + gWorldInstance.AddObject(new OFlagpole(FVector(-902, 70, -1406), 0x3800)); + gWorldInstance.AddObject(new OFlagpole(FVector(-948, 70, -1533), 0x3800)); + gWorldInstance.AddObject(new OFlagpole(FVector(-2170, 0, 723), 0x400)); + gWorldInstance.AddObject(new OFlagpole(FVector(-2193, 0, 761), 0x400)); + + gWorldInstance.AddObject(new OHedgehog(FVector(-1683, -80, -88), FVector2D(-1650, -114), 9)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1636, -93, -147), FVector2D(-1661, -151), 9)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1628, -86, -108), FVector2D(-1666, -58), 9)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1676, -69, -30), FVector2D(-1651, -26), 9)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1227, -27, -989), FVector2D(-1194, -999), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1261, -41, -880), FVector2D(-1213, -864), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1342, -60, -830), FVector2D(-1249, -927), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1429, -78, -849), FVector2D(-1347, -866), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1492, -94, -774), FVector2D(-1427, -891), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1453, -87, -784), FVector2D(-1509, -809), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1488, 89, -852), FVector2D(-1464, -822), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-1301, 47, -904), FVector2D(-1537, -854), 26)); + gWorldInstance.AddObject(new OHedgehog(FVector(-2587, 56, -259), FVector2D(-2624, -241), 28)); + gWorldInstance.AddObject(new OHedgehog(FVector(-2493, 94, -454), FVector2D(-2505, -397), 28)); + gWorldInstance.AddObject(new OHedgehog(FVector(-2477, 3, -57), FVector2D(-2539, -66), 28)); + } } // Likely sets minimap boundaries @@ -158,31 +184,6 @@ void YoshiValley::MinimapSettings() { } void YoshiValley::InitCourseObjects() { - size_t objectId; - size_t i; - - //! @bug Skip spawning due to animation crash for now - if (gGamestate == CREDITS_SEQUENCE) { - return; - } - - for (i = 0; i < NUM_YV_FLAG_POLES; i++) { - init_object(indexObjectList1[i], 0); - } - if (gGamestate != CREDITS_SEQUENCE) { - for (i = 0; i < NUM_HEDGEHOGS; i++) { - objectId = indexObjectList2[i]; - init_object(objectId, 0); - gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = - gHedgehogSpawns[i].pos[0] * xOrientation; - gObjectList[objectId].pos[1] = gObjectList[objectId].surfaceHeight = - gHedgehogSpawns[i].pos[1] + 6.0; - gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = gHedgehogSpawns[i].pos[2]; - gObjectList[objectId].unk_0D5 = gHedgehogSpawns[i].unk_06; - gObjectList[objectId].unk_09C = gHedgehogPatrolPoints[i][0] * xOrientation; - gObjectList[objectId].unk_09E = gHedgehogPatrolPoints[i][2]; - } - } } void YoshiValley::SpawnVehicles() { @@ -210,17 +211,9 @@ void YoshiValley::SpawnVehicles() { } void YoshiValley::UpdateCourseObjects() { - func_80083080(); - if (gGamestate != CREDITS_SEQUENCE) { - update_hedgehogs(); - } } void YoshiValley::RenderCourseObjects(s32 cameraId) { - func_80055228(cameraId); - if (gGamestate != CREDITS_SEQUENCE) { - render_object_hedgehogs(cameraId); - } } void YoshiValley::SomeSounds() { diff --git a/src/engine/objects/Flagpole.cpp b/src/engine/objects/Flagpole.cpp new file mode 100644 index 000000000..682f74915 --- /dev/null +++ b/src/engine/objects/Flagpole.cpp @@ -0,0 +1,85 @@ +#include "Flagpole.h" +#include "World.h" + +extern "C" { +#include "code_800029B0.h" +#include "render_objects.h" +#include "update_objects.h" +#include "assets/yoshi_valley_data.h" +#include "assets/common_data.h" +#include "math_util.h" +#include "math_util_2.h" +#include "code_80086E70.h" +#include "code_80057C60.h" +} + +size_t OFlagpole::_count = 0; + +OFlagpole::OFlagpole(const FVector& pos, s16 direction) { + _idx = _count; + _pos = pos; + _direction = direction; + + init_object(indexObjectList1[_idx], 0); + + _count++; +} + +void OFlagpole::Tick() { // func_80083080 + s32 objectIndex = indexObjectList1[_idx]; + + if (gObjectList[objectIndex].state != 0) { + OFlagpole::func_80083018(objectIndex); + OFlagpole::func_80083060(objectIndex); + } +} + +void OFlagpole::Draw(s32 cameraId) { // func_80055228 + s32 objectIndex = indexObjectList1[_idx]; + + func_8008A364(objectIndex, cameraId, 0x4000U, 0x000005DC); + if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + OFlagpole::func_80055164(objectIndex); + } +} + +void OFlagpole::func_80055164(s32 objectIndex) { // func_80055164 + if (gObjectList[objectIndex].state >= 2) { + gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0077A0); + rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].direction_angle, + gObjectList[objectIndex].sizeScaling); + if (gIsGamePaused == 0) { + gObjectList[objectIndex].unk_0A2 = render_animated_model((Armature*) gObjectList[objectIndex].model, + (Animation**) gObjectList[objectIndex].vertex, 0, + gObjectList[objectIndex].unk_0A2); + } else { + render_animated_model((Armature*) gObjectList[objectIndex].model, + (Animation**) gObjectList[objectIndex].vertex, 0, gObjectList[objectIndex].unk_0A2); + } + } +} + +void OFlagpole::func_80082F1C(s32 objectIndex) { + gObjectList[objectIndex].model = (Gfx*) d_course_yoshi_valley_unk5; + gObjectList[objectIndex].vertex = (Vtx*) d_course_yoshi_valley_unk4; + gObjectList[objectIndex].sizeScaling = 0.027f; + object_next_state(objectIndex); + set_obj_origin_pos(objectIndex, _pos.x * xOrientation, _pos.y, _pos.z); + set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); + set_obj_direction_angle(objectIndex, 0U, _direction, 0U); +} + +void OFlagpole::func_80083018(s32 objectIndex) { + switch (gObjectList[objectIndex].state) { + case 1: + OFlagpole::func_80082F1C(objectIndex); + break; + case 0: + default: + break; + } +} + +void OFlagpole::func_80083060(s32 objectIndex) { + object_calculate_new_pos_offset(objectIndex); +} diff --git a/src/engine/objects/Flagpole.h b/src/engine/objects/Flagpole.h new file mode 100644 index 000000000..5824fcf18 --- /dev/null +++ b/src/engine/objects/Flagpole.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include "Object.h" + +#include "World.h" + +extern "C" { +#include "macros.h" +#include "main.h" +#include "vehicles.h" +#include "waypoints.h" +#include "common_structs.h" +#include "objects.h" +#include "camera.h" +#include "some_data.h" +} + +class OFlagpole : public OObject { +public: + explicit OFlagpole(const FVector& pos, s16 direction); + + ~OFlagpole() { + _count--; + } + + static size_t GetCount() { + return _count; + } + + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; + + void func_80055164(s32 objectIndex); + void func_80082F1C(s32 objectIndex); + void func_80083018(s32 objectIndex); + void func_80083060(s32 objectIndex); + +private: + FVector _pos; + s16 _direction; + static size_t _count; + size_t _idx; +}; diff --git a/src/engine/objects/Hedgehog.cpp b/src/engine/objects/Hedgehog.cpp new file mode 100644 index 000000000..133a1f38d --- /dev/null +++ b/src/engine/objects/Hedgehog.cpp @@ -0,0 +1,183 @@ +#include "Hedgehog.h" +#include "World.h" + +extern "C" { +#include "render_objects.h" +#include "update_objects.h" +#include "assets/yoshi_valley_data.h" +#include "assets/common_data.h" +#include "math_util.h" +#include "math_util_2.h" +#include "code_80086E70.h" +#include "code_80057C60.h" +} + +size_t OHedgehog::_count = 0; + +OHedgehog::OHedgehog(const FVector& pos, const FVector2D& patrolPoint, s16 unk) { + _idx = _count; + _pos = pos; + + s32 objectId = indexObjectList2[_idx]; + init_object(objectId, 0); + gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = pos.x * xOrientation; + gObjectList[objectId].pos[1] = gObjectList[objectId].surfaceHeight = pos.y + 6.0; + gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = pos.z; + gObjectList[objectId].unk_0D5 = (u8)unk; + gObjectList[objectId].unk_09C = patrolPoint.x * xOrientation; + gObjectList[objectId].unk_09E = patrolPoint.z; + + _count++; +} + +void OHedgehog::Tick() { + s32 objectIndex = indexObjectList2[_idx]; + + OHedgehog::func_800833D0(objectIndex, _idx); + OHedgehog::func_80083248(objectIndex); + OHedgehog::func_80083474(objectIndex); + + // This func clears a bit from all hedgehogs. This results in setting the height of all hedgehogs to zero. + // The solution is to only clear the bit from the current instance; `self` or `this` + //func_80072120(indexObjectList2, NUM_HEDGEHOGS); + clear_object_flag(objectIndex, 0x00600000); // The fix +} + +void OHedgehog::Draw(s32 cameraId) { + s32 objectIndex = indexObjectList2[_idx]; + u32 something = func_8008A364(objectIndex, cameraId, 0x4000U, 0x000003E8); + + if (CVarGetInteger("gNoCulling", 0) == 1) { + something = MIN(something, 0x52211U - 1); + } + if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + set_object_flag(objectIndex, 0x00200000); + if (something < 0x2711U) { + set_object_flag(objectIndex, 0x00000020); + } else { + clear_object_flag(objectIndex, 0x00000020); + } + if (something < 0x57E41U) { + set_object_flag(objectIndex, 0x00400000); + } + if (something < 0x52211U) { + OHedgehog::func_800555BC(objectIndex, cameraId); + } + } +} + +void OHedgehog::func_800555BC(s32 objectIndex, s32 cameraId) { + Camera* camera; + + if (gObjectList[objectIndex].state >= 2) { + camera = &camera1[cameraId]; + OHedgehog::func_8004A870(objectIndex, 0.7f); + gObjectList[objectIndex].orientation[1] = + func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos); + draw_2d_texture_at(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation, + gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, + (u8*)gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, 64, 64, 64, 32); + } +} + +void OHedgehog::func_8004A870(s32 objectIndex, f32 arg1) { + Mat4 mtx; + Object* object; + + if ((is_obj_flag_status_active(objectIndex, 0x00000020) != 0) && + (is_obj_flag_status_active(objectIndex, 0x00800000) != 0)) { + object = &gObjectList[objectIndex]; + D_80183E50[0] = object->pos[0]; + D_80183E50[1] = object->surfaceHeight + 0.8; + D_80183E50[2] = object->pos[2]; + set_transform_matrix(mtx, object->unk_01C, D_80183E50, 0U, arg1); + // convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], mtx); + // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxHud[gMatrixHudCount++]), + // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + AddHudMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007B98); + } +} + +const char* sHedgehogTexList[] = { d_course_yoshi_valley_hedgehog }; + +void OHedgehog::func_8008311C(s32 objectIndex, s32 arg1) { + Object* object; + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); + + init_texture_object(objectIndex, (u8*)d_course_yoshi_valley_hedgehog_tlut, sHedgehogTexList, 0x40U, (u16) 0x00000040); + object = &gObjectList[objectIndex]; + object->activeTLUT = d_course_yoshi_valley_hedgehog_tlut; + object->activeTexture = d_course_yoshi_valley_hedgehog; + object->vertex = vtx; + object->sizeScaling = 0.2f; + object->textureListIndex = 0; + object_next_state(objectIndex); + set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); + set_obj_orientation(objectIndex, 0U, 0U, 0x8000U); + object->unk_034 = ((arg1 % 6) * 0.1) + 0.5; + func_80086E70(objectIndex); + set_object_flag(objectIndex, 0x04000600); + object->boundingBoxSize = 2; +} + +void OHedgehog::func_80083248(s32 objectIndex) { + switch (gObjectList[objectIndex].unk_0AE) { + case 0: + break; + case 1: + if (func_80087A0C(objectIndex, gObjectList[objectIndex].origin_pos[0], gObjectList[objectIndex].unk_09C, + gObjectList[objectIndex].origin_pos[2], gObjectList[objectIndex].unk_09E) != 0) { + func_80086FD4(objectIndex); + } + break; + case 2: + func_800871AC(objectIndex, 0x0000003C); + break; + case 3: + if (func_80087A0C(objectIndex, gObjectList[objectIndex].unk_09C, gObjectList[objectIndex].origin_pos[0], + gObjectList[objectIndex].unk_09E, gObjectList[objectIndex].origin_pos[2]) != 0) { + func_80086FD4(objectIndex); + } + break; + case 4: + if (func_80087060(objectIndex, 0x0000003C) != 0) { + func_8008701C(objectIndex, 1); + } + break; + } + object_calculate_new_pos_offset(objectIndex); + if (is_obj_flag_status_active(objectIndex, 0x00200000) != 0) { + if (is_obj_flag_status_active(objectIndex, 0x00400000) != 0) { + func_8008861C(objectIndex); + } + gObjectList[objectIndex].pos[1] = gObjectList[objectIndex].surfaceHeight + 6.0; + } +} + +void OHedgehog::func_800833D0(s32 objectIndex, s32 arg1) { + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + OHedgehog::func_8008311C(objectIndex, arg1); + break; + case 2: + func_80072D3C(objectIndex, 0, 1, 4, -1); + break; + } + if (gObjectList[objectIndex].textureListIndex == 0) { + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); + gObjectList[objectIndex].vertex = vtx; + } else { + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(D_0D006130); + gObjectList[objectIndex].vertex = vtx; + } +} + +void OHedgehog::func_80083474(s32 objectIndex) { + if (gObjectList[objectIndex].state >= 2) { + func_80089F24(objectIndex); + } +} diff --git a/src/engine/objects/Hedgehog.h b/src/engine/objects/Hedgehog.h new file mode 100644 index 000000000..dab8cf15a --- /dev/null +++ b/src/engine/objects/Hedgehog.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include "Object.h" + +#include "World.h" + +extern "C" { +#include "macros.h" +#include "main.h" +#include "vehicles.h" +#include "waypoints.h" +#include "common_structs.h" +#include "objects.h" +#include "camera.h" +#include "some_data.h" +} + +/** + * @arg pos FVector xyz spawn position + * @arg patrolPoint FVector2D xz patrol to location. Actor automatically calculates the Y value + * @arg unk unknown. Likely actor type. + */ +class OHedgehog : public OObject { +public: + explicit OHedgehog(const FVector& pos, const FVector2D& patrolPoint, s16 unk); + + ~OHedgehog() { + _count--; + } + + static size_t GetCount() { + return _count; + } + + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; + + void func_800555BC(s32 objectIndex, s32 cameraId); + void func_8004A870(s32 objectIndex, f32 arg1); + + void func_8008311C(s32 objectIndex, s32 arg1); + void func_80083248(s32 objectIndex); + void func_800833D0(s32 objectIndex, s32 arg1); + void func_80083474(s32 objectIndex); + + +private: + FVector _pos; + static size_t _count; + size_t _idx; +}; diff --git a/src/engine/objects/Seagull.cpp b/src/engine/objects/Seagull.cpp index b641ab5b4..5f0b12a7e 100644 --- a/src/engine/objects/Seagull.cpp +++ b/src/engine/objects/Seagull.cpp @@ -124,11 +124,27 @@ void OSeagull::Draw(Camera* camera) { // render_object_seagulls _toggle = true; //} //if (is_obj_flag_status_active(var_s1, VISIBLE) != 0) { - func_800552BC(var_s1); + OSeagull::func_800552BC(var_s1); //} //} } +void OSeagull::func_800552BC(s32 objectIndex) { + if (gObjectList[objectIndex].state >= 2) { + rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].direction_angle, + gObjectList[objectIndex].sizeScaling); + gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0077D0); + if (gIsGamePaused == 0) { + gObjectList[objectIndex].unk_0A2 = render_animated_model((Armature*) gObjectList[objectIndex].model, + (Animation**) gObjectList[objectIndex].vertex, 0, + gObjectList[objectIndex].unk_0A2); + } else { + render_animated_model((Armature*) gObjectList[objectIndex].model, + (Animation**) gObjectList[objectIndex].vertex, 0, gObjectList[objectIndex].unk_0A2); + } + } +} + void OSeagull::func_8008275C(s32 objectIndex) { UNUSED s32 stackPadding; switch (gObjectList[objectIndex].unk_0DD) { diff --git a/src/engine/objects/Seagull.h b/src/engine/objects/Seagull.h index 798d25f8d..528da0708 100644 --- a/src/engine/objects/Seagull.h +++ b/src/engine/objects/Seagull.h @@ -26,6 +26,7 @@ public: virtual void Tick() override; virtual void Draw(Camera*) override; + void func_800552BC(s32 objectIndex); void func_8008275C(s32 objectIndex); void func_8008241C(s32 objectIndex, s32 arg1); diff --git a/src/engine/objects/Snowman.cpp b/src/engine/objects/Snowman.cpp index 93286845f..c05f464ef 100644 --- a/src/engine/objects/Snowman.cpp +++ b/src/engine/objects/Snowman.cpp @@ -17,8 +17,8 @@ static const char* sSnowmanHeadList[] = { d_course_frappe_snowland_snowman_head size_t OSnowman::_count = 0; OSnowman::OSnowman(const FVector& pos) { - _pos = pos; _idx = _count; + _pos = pos; s32 objectId = indexObjectList2[_idx]; init_object(objectId, 0); @@ -106,7 +106,7 @@ void OSnowman::func_800836F0(Vec3f pos) { if (objectIndex == NULL_OBJECT_ID) { break; } - func_80083538(objectIndex, pos, i, D_8018D3BC); + OSnowman::func_80083538(objectIndex, pos, i, D_8018D3BC); } } @@ -297,4 +297,47 @@ void OSnowman::func_80083B0C(s32 objectIndex) { gObjectList[objectIndex].boundingBoxSize = 2; gObjectList[objectIndex].unk_034 = 1.5f; set_object_flag(objectIndex, 0x04000210); -} \ No newline at end of file +} + + +void OSnowman::func_80083538(s32 objectIndex, Vec3f arg1, s32 arg2, s32 arg3) { + Object* object; + + init_object(objectIndex, 0); + object = &gObjectList[objectIndex]; + object->activeTexture = (const char*)d_course_frappe_snowland_snow; + object->textureList = (const char**)d_course_frappe_snowland_snow; + object->activeTLUT = d_course_frappe_snowland_snow_tlut; + object->tlutList = (u8*)d_course_frappe_snowland_snow_tlut; + object->sizeScaling = random_int(0x0064U); + object->sizeScaling = (object->sizeScaling * 0.001) + 0.05; + object->velocity[1] = random_int(0x0014U); + object->velocity[1] = (object->velocity[1] * 0.5) + 2.6; + object->unk_034 = random_int(0x000AU); + object->unk_034 = (object->unk_034 * 0.1) + 4.5; + object->direction_angle[1] = (arg2 << 0x10) / arg3; + object->origin_pos[0] = arg1[0]; + object->origin_pos[1] = arg1[1]; + object->origin_pos[2] = arg1[2]; + object->primAlpha = random_int(0x4000U) + 0x1000; +} + +void OSnowman::func_8008379C(s32 objectIndex) { + switch (gObjectList[objectIndex].state) { + case 0: + break; + case 1: + if (func_80087E08(objectIndex, gObjectList[objectIndex].velocity[1], 0.74f, + gObjectList[objectIndex].unk_034, gObjectList[objectIndex].direction_angle[1], + 0x00000064) != 0) { + object_next_state(objectIndex); + } + break; + case 2: + func_80086F60(objectIndex); + func_80072428(objectIndex); + break; + } + object_calculate_new_pos_offset(objectIndex); + gObjectList[objectIndex].orientation[2] += gObjectList[objectIndex].primAlpha; +} diff --git a/src/engine/objects/Snowman.h b/src/engine/objects/Snowman.h index cd2c09244..e3e2a0138 100644 --- a/src/engine/objects/Snowman.h +++ b/src/engine/objects/Snowman.h @@ -43,6 +43,8 @@ public: void func_80083BE4(s32); void func_800836F0(Vec3f); bool func_80073D0C(s32 objectIndex, s16* arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6); + void func_80083538(s32 objectIndex, Vec3f arg1, s32 arg2, s32 arg3); + void func_8008379C(s32 objectIndex); private: diff --git a/src/engine/particles/StarEmitter.cpp b/src/engine/particles/StarEmitter.cpp index 14745d39a..e700b4c8c 100644 --- a/src/engine/particles/StarEmitter.cpp +++ b/src/engine/particles/StarEmitter.cpp @@ -17,6 +17,11 @@ StarEmitter::StarEmitter(FVector pos) { s8 temp_v0_3; Vec3s sp30; + for (size_t i = 0; i < D_80165738; i++) { + find_unused_obj_index(&gObjectParticle3[i]); + init_object(gObjectParticle3[i], 0); + } + if (objectIndex == NULL_OBJECT_ID) { return; //func_80077138(objectIndex, arg0, arg1); @@ -84,7 +89,7 @@ void StarEmitter::Tick() { // func_80077640 StarEmitter::func_80077450(objectIndex); StarEmitter::func_80077584(objectIndex); if (object->state == 0) { - delete_object_wrapper(&gObjectParticle3[someIndex]); + //delete_object_wrapper(&gObjectParticle3[someIndex]); } } } @@ -101,10 +106,10 @@ void StarEmitter::Draw(s32 cameraId) { // func_80054BE8 load_texture_block_ia8_nomirror(D_8018D488, 0x00000020, 0x00000020); func_8004B35C(0x000000FF, 0x000000FF, 0, 0x000000FF); D_80183E80[0] = 0; - printf("Draw Star\n"); for (var_s0 = 0; var_s0 < gObjectParticle3_SIZE; var_s0++) { temp_a0 = gObjectParticle3[var_s0]; if ((temp_a0 != -1) && (gObjectList[temp_a0].state >= 2)) { + printf("Draw Star\n"); StarEmitter::func_80054AFC(temp_a0, camera->pos); } } @@ -163,7 +168,7 @@ void StarEmitter::func_80077450(s32 objectIndex) { (func_80073B00(objectIndex, &gObjectList[objectIndex].primAlpha, 0x000000FF, 0, 0x00000010, 0, 0) != 0)) { func_80086F60(objectIndex); - func_80072428(objectIndex); + //func_80072428(objectIndex); } break; } diff --git a/src/render_objects.c b/src/render_objects.c index f747f50d2..35a1ec775 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -1361,26 +1361,6 @@ void func_8004A7AC(s32 objectIndex, f32 arg1) { } } -void func_8004A870(s32 objectIndex, f32 arg1) { - Mat4 mtx; - Object* object; - - if ((is_obj_flag_status_active(objectIndex, 0x00000020) != 0) && - (is_obj_flag_status_active(objectIndex, 0x00800000) != 0)) { - object = &gObjectList[objectIndex]; - D_80183E50[0] = object->pos[0]; - D_80183E50[1] = object->surfaceHeight + 0.8; - D_80183E50[2] = object->pos[2]; - set_transform_matrix(mtx, object->unk_01C, D_80183E50, 0U, arg1); - // convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], mtx); - // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxHud[gMatrixHudCount++]), - // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - - AddHudMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(gDisplayListHead++, D_0D007B98); - } -} - void func_8004A9B8(f32 arg0) { rsp_set_matrix_transl_rot_scale(D_80183E50, D_80183E70, arg0); gSPDisplayList(gDisplayListHead++, D_0D007C10); @@ -3836,93 +3816,6 @@ void render_object_smoke_particles(s32 cameraId) { } } -void func_80055164(s32 objectIndex) { - if (gObjectList[objectIndex].state >= 2) { - gSPDisplayList(gDisplayListHead++, D_0D0077A0); - rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].direction_angle, - gObjectList[objectIndex].sizeScaling); - if (gIsGamePaused == 0) { - gObjectList[objectIndex].unk_0A2 = render_animated_model((Armature*) gObjectList[objectIndex].model, - (Animation**) gObjectList[objectIndex].vertex, 0, - gObjectList[objectIndex].unk_0A2); - } else { - render_animated_model((Armature*) gObjectList[objectIndex].model, - (Animation**) gObjectList[objectIndex].vertex, 0, gObjectList[objectIndex].unk_0A2); - } - } -} - -void func_80055228(s32 cameraId) { - s32 var_s1; - s32 temp_s0; - - for (var_s1 = 0; var_s1 < 4; var_s1++) { - temp_s0 = indexObjectList1[var_s1]; - func_8008A364(temp_s0, cameraId, 0x4000U, 0x000005DC); - if (is_obj_flag_status_active(temp_s0, VISIBLE) != 0) { - func_80055164(temp_s0); - } - } -} - -void func_800552BC(s32 objectIndex) { - if (gObjectList[objectIndex].state >= 2) { - rsp_set_matrix_transformation(gObjectList[objectIndex].pos, gObjectList[objectIndex].direction_angle, - gObjectList[objectIndex].sizeScaling); - gSPDisplayList(gDisplayListHead++, D_0D0077D0); - if (gIsGamePaused == 0) { - gObjectList[objectIndex].unk_0A2 = render_animated_model((Armature*) gObjectList[objectIndex].model, - (Animation**) gObjectList[objectIndex].vertex, 0, - gObjectList[objectIndex].unk_0A2); - } else { - render_animated_model((Armature*) gObjectList[objectIndex].model, - (Animation**) gObjectList[objectIndex].vertex, 0, gObjectList[objectIndex].unk_0A2); - } - } -} - -void func_800555BC(s32 objectIndex, s32 cameraId) { - Camera* camera; - - if (gObjectList[objectIndex].state >= 2) { - camera = &camera1[cameraId]; - func_8004A870(objectIndex, 0.7f); - gObjectList[objectIndex].orientation[1] = - func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos); - draw_2d_texture_at(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation, - gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, - gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, 64, 64, 64, 32); - } -} - -void render_object_hedgehogs(s32 arg0) { - s32 test; - u32 something; - s32 someIndex; - - for (someIndex = 0; someIndex < NUM_HEDGEHOGS; someIndex++) { - test = indexObjectList2[someIndex]; - something = func_8008A364(test, arg0, 0x4000U, 0x000003E8); - if (CVarGetInteger("gNoCulling", 0) == 1) { - something = MIN(something, 0x52211U - 1); - } - if (is_obj_flag_status_active(test, VISIBLE) != 0) { - set_object_flag(test, 0x00200000); - if (something < 0x2711U) { - set_object_flag(test, 0x00000020); - } else { - clear_object_flag(test, 0x00000020); - } - if (something < 0x57E41U) { - set_object_flag(test, 0x00400000); - } - if (something < 0x52211U) { - func_800555BC(test, arg0); - } - } - } -} - UNUSED void func_800557AC() { } diff --git a/src/render_objects.h b/src/render_objects.h index 045262029..ed14fb684 100644 --- a/src/render_objects.h +++ b/src/render_objects.h @@ -170,7 +170,6 @@ void func_8004A5E4(Vec3f, Vec3su, f32, u8*, Vtx*); void func_8004A630(Collision*, Vec3f, f32); void func_8004A6EC(s32, f32); void func_8004A7AC(s32, f32); -void func_8004A870(s32, f32); void func_8004A9B8(f32); void func_8004AA10(Vec3f, Vec3su, f32, u8*, Vtx*, s32, s32, s32, s32); void func_8004AAA0(s32, s32, u16, f32, u8*, Vtx*); @@ -242,7 +241,6 @@ void func_8004CD18(s32, s32, u8*); void func_8004CF9C(s32, s32, u8*, s32, s32, s32, s32); void func_8004CFF0(s32, s32, u8*, s32, s32, s32, s32); -void func_800552BC(s32); void func_800450C8(u8*, s32, s32); void func_80044F34(u8*, s32, s32); void func_8004D044(s32, s32, u8*, s32, s32, s32, s32, s32, s32, s32, s32); @@ -364,13 +362,9 @@ void func_80054EB8(s32); void func_80054F04(s32); void render_object_moles(s32); -void func_80055164(s32); void func_80055228(s32); -void func_800552BC(s32); void render_object_seagulls(s32); void render_object_crabs(s32); -void func_800555BC(s32, s32); -void render_object_hedgehogs(s32); void func_800557AC(void); void func_800557B4(s32, u32, u32); void render_object_train_penguins(s32); diff --git a/src/update_objects.c b/src/update_objects.c index 148ba7b50..80edaaf19 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -4353,213 +4353,6 @@ void func_8008153C(s32 objectIndex) { } } -#ifdef NON_MATCHING -// https://decomp.me/scratch/PYAg4 -// Stack issue caused by the `test` variable, but removing it causes much, much larger differences -//! @todo Fix flag animations -void func_80082F1C(s32 objectIndex, s32 arg1) { - YVFlagPoleSpawn* test; - gObjectList[objectIndex].model = (Gfx*) d_course_yoshi_valley_unk5; - gObjectList[objectIndex].vertex = (Vtx*) d_course_yoshi_valley_unk4; - gObjectList[objectIndex].sizeScaling = 0.027f; - // if (test->rot && test->rot) {} - test = &D_800E5DF4[arg1]; - object_next_state(objectIndex); - set_obj_origin_pos(objectIndex, test->pos[0] * xOrientation, test->pos[1], test->pos[2]); - set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); - set_obj_direction_angle(objectIndex, 0U, test->rot, 0U); -} -#else -GLOBAL_ASM("asm/non_matchings/update_objects/func_80082F1C.s") -#endif - -void func_80083018(s32 objectIndex, s32 arg1) { - switch (gObjectList[objectIndex].state) { - case 1: - func_80082F1C(objectIndex, arg1); - break; - case 0: - default: - break; - } -} - -void func_80083060(s32 objectIndex) { - object_calculate_new_pos_offset(objectIndex); -} - -void func_80083080(void) { - s32 objectIndex; - s32 var_s1; - - for (var_s1 = 0; var_s1 < NUM_YV_FLAG_POLES; var_s1++) { - objectIndex = indexObjectList1[var_s1]; - if (gObjectList[objectIndex].state != 0) { - func_80083018(objectIndex, var_s1); - func_80083060(objectIndex); - } - } -} - -const char* sHedgehogTexList[] = { d_course_yoshi_valley_hedgehog }; - -void func_8008311C(s32 objectIndex, s32 arg1) { - Object* object; - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_hedgehog); - - init_texture_object(objectIndex, d_course_yoshi_valley_hedgehog_tlut, sHedgehogTexList, 0x40U, (u16) 0x00000040); - object = &gObjectList[objectIndex]; - object->activeTLUT = d_course_yoshi_valley_hedgehog_tlut; - object->activeTexture = d_course_yoshi_valley_hedgehog; - object->vertex = vtx; - object->sizeScaling = 0.2f; - object->textureListIndex = 0; - object_next_state(objectIndex); - set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); - set_obj_orientation(objectIndex, 0U, 0U, 0x8000U); - object->unk_034 = ((arg1 % 6) * 0.1) + 0.5; - func_80086E70(objectIndex); - set_object_flag(objectIndex, 0x04000600); - object->boundingBoxSize = 2; -} - -void func_80083248(s32 objectIndex) { - switch (gObjectList[objectIndex].unk_0AE) { - case 0: - break; - case 1: - if (func_80087A0C(objectIndex, gObjectList[objectIndex].origin_pos[0], gObjectList[objectIndex].unk_09C, - gObjectList[objectIndex].origin_pos[2], gObjectList[objectIndex].unk_09E) != 0) { - func_80086FD4(objectIndex); - } - break; - case 2: - func_800871AC(objectIndex, 0x0000003C); - break; - case 3: - if (func_80087A0C(objectIndex, gObjectList[objectIndex].unk_09C, gObjectList[objectIndex].origin_pos[0], - gObjectList[objectIndex].unk_09E, gObjectList[objectIndex].origin_pos[2]) != 0) { - func_80086FD4(objectIndex); - } - break; - case 4: - if (func_80087060(objectIndex, 0x0000003C) != 0) { - func_8008701C(objectIndex, 1); - } - break; - } - object_calculate_new_pos_offset(objectIndex); - if (is_obj_flag_status_active(objectIndex, 0x00200000) != 0) { - if (is_obj_flag_status_active(objectIndex, 0x00400000) != 0) { - func_8008861C(objectIndex); - } - gObjectList[objectIndex].pos[1] = gObjectList[objectIndex].surfaceHeight + 6.0; - } -} - -void func_800833D0(s32 objectIndex, s32 arg1) { - switch (gObjectList[objectIndex].state) { /* irregular */ - case 0: - break; - case 1: - func_8008311C(objectIndex, arg1); - break; - case 2: - func_80072D3C(objectIndex, 0, 1, 4, -1); - break; - } - if (gObjectList[objectIndex].textureListIndex == 0) { - Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_hedgehog); - gObjectList[objectIndex].vertex = vtx; - } else { - Vtx* vtx = (Vtx*) LOAD_ASSET(D_0D006130); - gObjectList[objectIndex].vertex = vtx; - } -} - -void func_80083474(s32 objectIndex) { - if (gObjectList[objectIndex].state >= 2) { - func_80089F24(objectIndex); - } -} - -void update_hedgehogs(void) { - s32 temp_s1; - s32 var_s0; - - for (var_s0 = 0; var_s0 < NUM_HEDGEHOGS; var_s0++) { - temp_s1 = indexObjectList2[var_s0]; - func_800833D0(temp_s1, var_s0); - func_80083248(temp_s1); - func_80083474(temp_s1); - } - func_80072120(indexObjectList2, 0x0000000F); -} - -void func_80083538(s32 objectIndex, Vec3f arg1, s32 arg2, s32 arg3) { - Object* object; - - init_object(objectIndex, 0); - object = &gObjectList[objectIndex]; - object->activeTexture = d_course_frappe_snowland_snow; - object->textureList = d_course_frappe_snowland_snow; - object->activeTLUT = d_course_frappe_snowland_snow_tlut; - object->tlutList = d_course_frappe_snowland_snow_tlut; - object->sizeScaling = random_int(0x0064U); - object->sizeScaling = (object->sizeScaling * 0.001) + 0.05; - object->velocity[1] = random_int(0x0014U); - object->velocity[1] = (object->velocity[1] * 0.5) + 2.6; - object->unk_034 = random_int(0x000AU); - object->unk_034 = (object->unk_034 * 0.1) + 4.5; - object->direction_angle[1] = (arg2 << 0x10) / arg3; - object->origin_pos[0] = arg1[0]; - object->origin_pos[1] = arg1[1]; - object->origin_pos[2] = arg1[2]; - object->primAlpha = random_int(0x4000U) + 0x1000; -} - -void func_8008379C(s32 objectIndex) { - switch (gObjectList[objectIndex].state) { - case 0: - break; - case 1: - if (func_80087E08(objectIndex, gObjectList[objectIndex].velocity[1], 0.74f, - gObjectList[objectIndex].unk_034, gObjectList[objectIndex].direction_angle[1], - 0x00000064) != 0) { - object_next_state(objectIndex); - } - break; - case 2: - func_80086F60(objectIndex); - func_80072428(objectIndex); - break; - } - object_calculate_new_pos_offset(objectIndex); - gObjectList[objectIndex].orientation[2] += gObjectList[objectIndex].primAlpha; -} - -static const char* sSnowmanHeadList[] = { d_course_frappe_snowland_snowman_head }; - -void func_80083868(s32 objectIndex) { - Object* object; - Vtx* vtx = (Vtx*) LOAD_ASSET(D_0D0061B0); - init_texture_object(objectIndex, d_course_frappe_snowland_snowman_tlut, sSnowmanHeadList, 0x40U, (u16) 0x00000040); - object = &gObjectList[objectIndex]; - object->vertex = vtx; - object->sizeScaling = 0.1f; - object->textureListIndex = 0; - object_next_state(objectIndex); - set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); - object->orientation[0] = 0; - object->orientation[1] = 0; - object->orientation[2] = 0x8000; - object->primAlpha = random_int(0x2000U) - 0x1000; - func_80086E70(objectIndex); - object->unk_034 = 1.5f; - set_object_flag(objectIndex, 0x00000200); -} - - void func_80083F18(s32 objectIndex) { switch (gObjectList[objectIndex].state) { case 0: diff --git a/src/update_objects.h b/src/update_objects.h index 8ac2848dd..9e3cd61b7 100644 --- a/src/update_objects.h +++ b/src/update_objects.h @@ -304,16 +304,11 @@ void func_80082B34(s32, s32); void func_80082C30(s32); void func_80082E18(s32); void update_crabs(void); -void func_80082F1C(s32, s32); -void func_80083018(s32, s32); -void func_80083060(s32); void func_80083080(void); void func_8008311C(s32, s32); void func_80083248(s32); void func_800833D0(s32, s32); void func_80083474(s32); -void update_hedgehogs(void); -void func_80083538(s32, Vec3f, s32, s32); void func_8008379C(s32); void func_80083868(s32); void func_80083948(s32); From 64b9dcbb30c5007466c14da7d78d081189810308 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 29 Dec 2024 20:19:59 -0700 Subject: [PATCH 4/7] impl hot air balloon --- src/engine/courses/LuigiRaceway.cpp | 16 +-- src/engine/courses/TestCourse.cpp | 2 + src/engine/objects/HotAirBalloon.cpp | 174 +++++++++++++++++++++++++++ src/engine/objects/HotAirBalloon.h | 34 ++++++ src/render_objects.c | 44 ------- src/render_objects.h | 2 - src/update_objects.c | 96 --------------- 7 files changed, 218 insertions(+), 150 deletions(-) create mode 100644 src/engine/objects/HotAirBalloon.cpp create mode 100644 src/engine/objects/HotAirBalloon.h diff --git a/src/engine/courses/LuigiRaceway.cpp b/src/engine/courses/LuigiRaceway.cpp index 7740ebf49..6020b72d1 100644 --- a/src/engine/courses/LuigiRaceway.cpp +++ b/src/engine/courses/LuigiRaceway.cpp @@ -7,6 +7,7 @@ #include "World.h" #include "engine/objects/BombKart.h" #include "assets/luigi_raceway_data.h" +#include "engine/objects/HotAirBalloon.h" #include "engine/actors/AFinishline.h" extern "C" { @@ -168,6 +169,12 @@ void LuigiRaceway::SpawnActors() { gWorldInstance.AddActor(new AFinishline()); spawn_foliage((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_luigi_raceway_tree_spawn)); spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_luigi_raceway_item_box_spawns)); + + if (gGamestate == CREDITS_SEQUENCE) { + gWorldInstance.AddObject(new OHotAirBalloon(FVector(-1250.0f, 0.0f, 1110.0f))); + } else { // Normal gameplay + gWorldInstance.AddObject(new OHotAirBalloon(FVector(-176.0, 0.0f, -2323.0f))); + } } void LuigiRaceway::SpawnVehicles() { @@ -202,8 +209,7 @@ void LuigiRaceway::InitCourseObjects() { if (gModeSelection == GRAND_PRIX) { func_80070714(); } - D_80165898 = 0; - init_object(indexObjectList1[0], 0); + for (i = 0; i < D_80165738; i++) { find_unused_obj_index(&gObjectParticle3[i]); init_object(gObjectParticle3[i], 0); @@ -212,15 +218,9 @@ void LuigiRaceway::InitCourseObjects() { } void LuigiRaceway::UpdateCourseObjects() { - if (D_80165898 != 0) { - update_hot_air_balloon(); - } } void LuigiRaceway::RenderCourseObjects(s32 cameraId) { - if (D_80165898 != 0) { - render_object_hot_air_balloon(cameraId); - } } void LuigiRaceway::SomeSounds() { diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index 3f95dc56b..40b03059e 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -20,6 +20,7 @@ #include "engine/objects/TrashBin.h" #include "engine/objects/Hedgehog.h" #include "engine/objects/Flagpole.h" +#include "engine/objects/HotAirBalloon.h" #include "engine/particles/StarEmitter.h" extern "C" { @@ -210,6 +211,7 @@ void TestCourse::SpawnActors() { //gWorldInstance.AddEmitter(new StarEmitter(FVector(0,50,0))); //gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9)); //gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400)); + gWorldInstance.AddObject(new OHotAirBalloon(FVector(0.0, 20.0f, -200.0f))); } // Likely sets minimap boundaries diff --git a/src/engine/objects/HotAirBalloon.cpp b/src/engine/objects/HotAirBalloon.cpp new file mode 100644 index 000000000..234eef6d9 --- /dev/null +++ b/src/engine/objects/HotAirBalloon.cpp @@ -0,0 +1,174 @@ +#include "HotAirBalloon.h" +#include "World.h" +#include "port/Game.h" + +extern "C" { +#include "render_objects.h" +#include "update_objects.h" +#include "assets/luigi_raceway_data.h" +#include "assets/common_data.h" +#include "math_util.h" +#include "math_util_2.h" +#include "code_80086E70.h" +#include "code_80057C60.h" +#include "actors.h" +} + +OHotAirBalloon::OHotAirBalloon(const FVector& pos) { + _pos = pos; + + D_80165898 = 0; + + // Spawn balloon on second lap. + if (GetCourse() == GetLuigiRaceway()) { + _visible = (bool*)&D_80165898; + } else { // Spawn balloon on race start + bool mod = true; + _visible = &mod; + } + + init_object(indexObjectList1[0], 0); +} + +void OHotAirBalloon::Tick() { + s32 objectIndex = indexObjectList1[0]; + + if (*_visible) { + if (gObjectList[objectIndex].state != 0) { + OHotAirBalloon::func_80085768(objectIndex); + OHotAirBalloon::func_80085534(objectIndex); + object_calculate_new_pos_offset(objectIndex); + if (gObjectList[objectIndex].state >= 2) { + gActorHotAirBalloonItemBox->pos[0] = gObjectList[objectIndex].pos[0]; + gActorHotAirBalloonItemBox->pos[1] = gObjectList[objectIndex].pos[1] - 10.0; + gActorHotAirBalloonItemBox->pos[2] = gObjectList[objectIndex].pos[2]; + } + } + } +} + +void OHotAirBalloon::Draw(s32 cameraId) { + s32 objectIndex; + objectIndex = indexObjectList1[0]; + if (*_visible) { + if (gGamestate != CREDITS_SEQUENCE) { + func_8008A1D0(objectIndex, cameraId, 0x000005DC, 0x00000BB8); + if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + OHotAirBalloon::func_80055CCC(objectIndex, cameraId); + } + } else { + clear_object_flag(objectIndex, 0x00100000); + OHotAirBalloon::func_80055CCC(objectIndex, cameraId); + } + } +} + +void OHotAirBalloon::func_80055CCC(s32 objectIndex, s32 cameraId) { + UNUSED s32 pad; + f32 test; + Camera* camera; + + camera = &camera1[cameraId]; + if (gObjectList[objectIndex].state >= 2) { + func_8008A454(objectIndex, cameraId, 0x0000012C); + test = gObjectList[objectIndex].pos[1] - gObjectList[objectIndex].surfaceHeight; + func_8004A6EC(objectIndex, (20.0 / test) + 0.5); + if (is_obj_index_flag_status_inactive(objectIndex, 0x00100000) != 0) { + func_80043328(gObjectList[objectIndex].pos, (u16*) gObjectList[objectIndex].direction_angle, + gObjectList[objectIndex].sizeScaling, (Gfx*)d_course_luigi_raceway_dl_F960); + gSPDisplayList(gDisplayListHead++, (Gfx*)d_course_luigi_raceway_dl_F650); + } else { + D_80183E80[0] = (s16) gObjectList[objectIndex].direction_angle[0]; + D_80183E80[1] = + (s16) (func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos) + + 0x8000); + D_80183E80[2] = (u16) gObjectList[objectIndex].direction_angle[2]; + func_80043328(gObjectList[objectIndex].pos, D_80183E80, gObjectList[objectIndex].sizeScaling, + (Gfx*)d_course_luigi_raceway_dl_FBE0); + gSPDisplayList(gDisplayListHead++, (Gfx*)d_course_luigi_raceway_dl_FA20); + if (gPlayerCountSelection1 == 1) { + gObjectList[objectIndex].direction_angle[1] = 0; + } + } + } +} + +void OHotAirBalloon::init_hot_air_balloon(s32 objectIndex) { + gObjectList[objectIndex].sizeScaling = 1.0f; + gObjectList[objectIndex].model = (Gfx*)d_course_luigi_raceway_dl_F960; + if (gGamestate != CREDITS_SEQUENCE) { + set_obj_origin_pos(objectIndex, xOrientation * _pos.x, _pos.y, _pos.z); + set_obj_origin_offset(objectIndex, 0.0f, 300.0f, 0.0f); + } else { + set_obj_origin_pos(objectIndex, xOrientation * _pos.x, _pos.y, _pos.z); + set_obj_origin_offset(objectIndex, 0.0f, 300.0f, 0.0f); + } + func_8008B844(objectIndex); + func_800886F4(objectIndex); + func_80086EF0(objectIndex); + gObjectList[objectIndex].velocity[1] = -2.0f; + init_actor_hot_air_balloon_item_box(0.0f, 0.0f, 0.0f); + object_next_state(objectIndex); +} + +void OHotAirBalloon::func_80085534(s32 objectIndex) { + switch (gObjectList[objectIndex].unk_0AE) { + case 1: + if (gObjectList[objectIndex].offset[1] <= 18.0) { + func_80086FD4(objectIndex); + } + break; + case 2: + f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); + if (gObjectList[objectIndex].velocity[1] == 0.0) { + func_80086FD4(objectIndex); + } + break; + case 3: + func_800871AC(objectIndex, 1); + break; + case 4: + f32_step_towards(&gObjectList[objectIndex].velocity[1], 1.0f, 0.05f); + if (gObjectList[objectIndex].velocity[1] == 1.0) { + func_80086FD4(objectIndex); + } + break; + case 5: + func_800871AC(objectIndex, 90); + break; + case 6: + f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); + if (gObjectList[objectIndex].velocity[1] == 0.0) { + func_80086FD4(objectIndex); + } + break; + case 7: + f32_step_towards(&gObjectList[objectIndex].velocity[1], -1.0f, 0.05f); + if (gObjectList[objectIndex].velocity[1] == -1.0) { + func_80086FD4(objectIndex); + } + break; + case 8: + func_800871AC(objectIndex, 90); + break; + case 9: + f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); + if (func_80087060(objectIndex, 90) != 0) { + func_8008701C(objectIndex, 3); + } + break; + } + object_add_velocity_offset_y(objectIndex); + gObjectList[objectIndex].direction_angle[1] += 0x100; +} + +void OHotAirBalloon::func_80085768(s32 objectIndex) { + switch (gObjectList[objectIndex].state) { /* irregular */ + case 1: + OHotAirBalloon::init_hot_air_balloon(objectIndex); + break; + case 0: + case 2: + break; + } +} diff --git a/src/engine/objects/HotAirBalloon.h b/src/engine/objects/HotAirBalloon.h new file mode 100644 index 000000000..301e111c4 --- /dev/null +++ b/src/engine/objects/HotAirBalloon.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "Object.h" + +#include "World.h" + +extern "C" { +#include "macros.h" +#include "main.h" +#include "vehicles.h" +#include "waypoints.h" +#include "common_structs.h" +#include "objects.h" +#include "camera.h" +#include "some_data.h" +} + +class OHotAirBalloon : public OObject { +public: + explicit OHotAirBalloon(const FVector& pos); + + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; + void func_80055CCC(s32 objectIndex, s32 cameraId); + void init_hot_air_balloon(s32 objectIndex); + void func_80085534(s32 objectIndex); + void func_80085768(s32 objectIndex); + +private: + FVector _pos; + bool *_visible; +}; diff --git a/src/render_objects.c b/src/render_objects.c index 35a1ec775..0571da4ce 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -3931,50 +3931,6 @@ void render_object_chain_chomps(s32 cameraId) { } } -void func_80055CCC(s32 objectIndex, s32 cameraId) { - UNUSED s32 pad; - f32 test; - Camera* camera; - - camera = &camera1[cameraId]; - if (gObjectList[objectIndex].state >= 2) { - func_8008A454(objectIndex, cameraId, 0x0000012C); - test = gObjectList[objectIndex].pos[1] - gObjectList[objectIndex].surfaceHeight; - func_8004A6EC(objectIndex, (20.0 / test) + 0.5); - if (is_obj_index_flag_status_inactive(objectIndex, 0x00100000) != 0) { - func_80043328(gObjectList[objectIndex].pos, (u16*) gObjectList[objectIndex].direction_angle, - gObjectList[objectIndex].sizeScaling, d_course_luigi_raceway_dl_F960); - gSPDisplayList(gDisplayListHead++, d_course_luigi_raceway_dl_F650); - } else { - D_80183E80[0] = (s16) gObjectList[objectIndex].direction_angle[0]; - D_80183E80[1] = - (s16) (func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos) + - 0x8000); - D_80183E80[2] = (u16) gObjectList[objectIndex].direction_angle[2]; - func_80043328(gObjectList[objectIndex].pos, D_80183E80, gObjectList[objectIndex].sizeScaling, - d_course_luigi_raceway_dl_FBE0); - gSPDisplayList(gDisplayListHead++, d_course_luigi_raceway_dl_FA20); - if (gPlayerCountSelection1 == 1) { - gObjectList[objectIndex].direction_angle[1] = 0; - } - } - } -} - -void render_object_hot_air_balloon(s32 arg0) { - s32 objectIndex; - objectIndex = indexObjectList1[0]; - if (gGamestate != 9) { - func_8008A1D0(objectIndex, arg0, 0x000005DC, 0x00000BB8); - if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { - func_80055CCC(objectIndex, arg0); - } - } else { - clear_object_flag(objectIndex, 0x00100000); - func_80055CCC(objectIndex, arg0); - } -} - void func_80055EF4(s32 objectIndex, UNUSED s32 arg1) { Object* object; diff --git a/src/render_objects.h b/src/render_objects.h index ed14fb684..6474e8db2 100644 --- a/src/render_objects.h +++ b/src/render_objects.h @@ -370,8 +370,6 @@ void func_800557B4(s32, u32, u32); void render_object_train_penguins(s32); void func_80055AB8(s32, s32); void render_object_chain_chomps(s32); -void func_80055CCC(s32, s32); -void render_object_hot_air_balloon(s32); void func_80055EF4(s32, s32); void func_80055F48(s32); diff --git a/src/update_objects.c b/src/update_objects.c index 80edaaf19..e806d43d2 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -4434,102 +4434,6 @@ void func_800842C8(void) { } } -void init_hot_air_balloon(s32 objectIndex) { - gObjectList[objectIndex].sizeScaling = 1.0f; - gObjectList[objectIndex].model = d_course_luigi_raceway_dl_F960; - if (gGamestate != 9) { - set_obj_origin_pos(objectIndex, xOrientation * -176.0, 0.0f, -2323.0f); - set_obj_origin_offset(objectIndex, 0.0f, 300.0f, 0.0f); - } else { - set_obj_origin_pos(objectIndex, xOrientation * -1250.0, 0.0f, 1110.0f); - set_obj_origin_offset(objectIndex, 0.0f, 300.0f, 0.0f); - } - func_8008B844(objectIndex); - func_800886F4(objectIndex); - func_80086EF0(objectIndex); - gObjectList[objectIndex].velocity[1] = -2.0f; - init_actor_hot_air_balloon_item_box(0.0f, 0.0f, 0.0f); - object_next_state(objectIndex); -} - -void func_80085534(s32 objectIndex) { - switch (gObjectList[objectIndex].unk_0AE) { - case 1: - if (gObjectList[objectIndex].offset[1] <= 18.0) { - func_80086FD4(objectIndex); - } - break; - case 2: - f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); - if (gObjectList[objectIndex].velocity[1] == 0.0) { - func_80086FD4(objectIndex); - } - break; - case 3: - func_800871AC(objectIndex, 1); - break; - case 4: - f32_step_towards(&gObjectList[objectIndex].velocity[1], 1.0f, 0.05f); - if (gObjectList[objectIndex].velocity[1] == 1.0) { - func_80086FD4(objectIndex); - } - break; - case 5: - func_800871AC(objectIndex, 0x0000005A); - break; - case 6: - f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); - if (gObjectList[objectIndex].velocity[1] == 0.0) { - func_80086FD4(objectIndex); - } - break; - case 7: - f32_step_towards(&gObjectList[objectIndex].velocity[1], -1.0f, 0.05f); - if (gObjectList[objectIndex].velocity[1] == -1.0) { - func_80086FD4(objectIndex); - } - break; - case 8: - func_800871AC(objectIndex, 0x0000005A); - break; - case 9: - f32_step_towards(&gObjectList[objectIndex].velocity[1], 0.0f, 0.05f); - if (func_80087060(objectIndex, 0x0000005A) != 0) { - func_8008701C(objectIndex, 3); - } - break; - } - object_add_velocity_offset_y(objectIndex); - gObjectList[objectIndex].direction_angle[1] += 0x100; -} - -void func_80085768(s32 objectIndex) { - switch (gObjectList[objectIndex].state) { /* irregular */ - case 1: - init_hot_air_balloon(objectIndex); - break; - case 0: - case 2: - break; - } -} - -void update_hot_air_balloon(void) { - s32 objectIndex; - - objectIndex = indexObjectList1[0]; - if (gObjectList[objectIndex].state != 0) { - func_80085768(objectIndex); - func_80085534(objectIndex); - object_calculate_new_pos_offset(objectIndex); - if (gObjectList[objectIndex].state >= 2) { - gActorHotAirBalloonItemBox->pos[0] = gObjectList[objectIndex].pos[0]; - gActorHotAirBalloonItemBox->pos[1] = gObjectList[objectIndex].pos[1] - 10.0; - gActorHotAirBalloonItemBox->pos[2] = gObjectList[objectIndex].pos[2]; - } - } -} - void func_80085878(s32 objectIndex, s32 arg1) { TrackWaypoint* temp_v0; Object* object; From 08e4bf37979131e76e617beafb3f5ca6286e5ebb Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 29 Dec 2024 21:37:06 -0700 Subject: [PATCH 5/7] Fix Crab Impl --- src/engine/courses/KoopaTroopaBeach.cpp | 27 ++++++++++---------- src/engine/courses/TestCourse.cpp | 5 +++- src/engine/objects/Crab.cpp | 30 +++++++++++----------- src/engine/objects/Crab.h | 33 +++++++++++++++---------- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/engine/courses/KoopaTroopaBeach.cpp b/src/engine/courses/KoopaTroopaBeach.cpp index eb4c3c45f..daaba1ad8 100644 --- a/src/engine/courses/KoopaTroopaBeach.cpp +++ b/src/engine/courses/KoopaTroopaBeach.cpp @@ -7,6 +7,7 @@ #include "World.h" #include "engine/actors/AFinishline.h" #include "engine/objects/BombKart.h" +#include "engine/objects/Crab.h" #include "assets/koopa_troopa_beach_data.h" extern "C" { @@ -144,6 +145,19 @@ void KoopaTroopaBeach::SpawnActors() { init_actor_hot_air_balloon_item_box(328.0f * gCourseDirection, 70.0f, 2541.0f); spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_koopa_troopa_beach_item_box_spawns)); spawn_palm_trees((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_koopa_troopa_beach_tree_spawn)); + + if (gGamestate != CREDITS_SEQUENCE) { + gWorldInstance.AddObject(new OCrab(FVector2D(-1809, 625), FVector2D(-1666, 594))); + gWorldInstance.AddObject(new OCrab(FVector2D(-1852, 757), FVector2D(-1620, 740))); + gWorldInstance.AddObject(new OCrab(FVector2D(-1478, 1842), FVector2D(-1453, 1833))); + gWorldInstance.AddObject(new OCrab(FVector2D(-1418, 1967), FVector2D(-1455, 1962))); + gWorldInstance.AddObject(new OCrab(FVector2D(-1472, 2112), FVector2D(-1417, 2100))); + gWorldInstance.AddObject(new OCrab(FVector2D(-1389, 2152), FVector2D(-1335, 2136))); + gWorldInstance.AddObject(new OCrab(FVector2D(218, 693), FVector2D(69, 696))); + gWorldInstance.AddObject(new OCrab(FVector2D(235, 528), FVector2D(24, 501))); + gWorldInstance.AddObject(new OCrab(FVector2D(268, 406), FVector2D(101, 394))); + gWorldInstance.AddObject(new OCrab(FVector2D(223, 318), FVector2D(86, 308))); + } } void KoopaTroopaBeach::SpawnVehicles() { @@ -173,19 +187,6 @@ void KoopaTroopaBeach::InitCourseObjects() { size_t objectId; size_t i; - if (gGamestate != CREDITS_SEQUENCE) { - for (i = 0; i < NUM_CRABS; i++) { - objectId = indexObjectList1[i]; - init_object(objectId, 0); - gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = - gCrabSpawns[i].startX * xOrientation; - gObjectList[objectId].unk_01C[0] = gCrabSpawns[i].patrolX * xOrientation; - - gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = gCrabSpawns[i].startZ; - gObjectList[objectId].unk_01C[2] = gCrabSpawns[i].patrolZ; - } - } - if (gGamestate == CREDITS_SEQUENCE) { Vec3f pos = {-360.0f, 60.0f, -1300.0f}; for (size_t i = 0; i < NUM_SEAGULLS; i++) { diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index 40b03059e..682db53c5 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -21,6 +21,7 @@ #include "engine/objects/Hedgehog.h" #include "engine/objects/Flagpole.h" #include "engine/objects/HotAirBalloon.h" +#include "engine/objects/Crab.h" #include "engine/particles/StarEmitter.h" extern "C" { @@ -211,7 +212,9 @@ void TestCourse::SpawnActors() { //gWorldInstance.AddEmitter(new StarEmitter(FVector(0,50,0))); //gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9)); //gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400)); - gWorldInstance.AddObject(new OHotAirBalloon(FVector(0.0, 20.0f, -200.0f))); +// gWorldInstance.AddObject(new OHotAirBalloon(FVector(0.0, 20.0f, -200.0f))); + + gWorldInstance.AddObject(new OCrab(FVector2D(0, 0), FVector2D(0, -200))); } // Likely sets minimap boundaries diff --git a/src/engine/objects/Crab.cpp b/src/engine/objects/Crab.cpp index cfb84f259..b05bc85e3 100644 --- a/src/engine/objects/Crab.cpp +++ b/src/engine/objects/Crab.cpp @@ -23,25 +23,28 @@ extern "C" { #include "assets/koopa_troopa_beach_data.h" } -OCrab::OCrab(s32 i, Vec3f pos) { +size_t OCrab::_count = 0; + +OCrab::OCrab(const FVector2D& start, const FVector2D& end) { s32 objectId; - //for (i = 0; i < NUM_CRABS; i++) { - _idx = i; - objectId = indexObjectList1[i]; + _idx = _count; + _start = start; + _end = end; + + objectId = indexObjectList1[_idx]; init_object(objectId, 0); - gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = - gCrabSpawns[i].startX * xOrientation; + gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = start.x * xOrientation; + gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = start.z; - gObjectList[objectId].unk_01C[0] = gCrabSpawns[i].patrolX * xOrientation; + gObjectList[objectId].unk_01C[0] = end.x * xOrientation; + gObjectList[objectId].unk_01C[2] = end.z; - gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = gCrabSpawns[i].startZ; - gObjectList[objectId].unk_01C[2] = gCrabSpawns[i].patrolZ; + _count++; } void OCrab::Tick(void) { s32 objectIndex; - //for (var_s1 = 0; var_s1 < NUM_CRABS; var_s1++) { objectIndex = indexObjectList1[_idx]; if (gObjectList[objectIndex].state != 0) { OCrab::func_80082B34(objectIndex); @@ -49,12 +52,11 @@ void OCrab::Tick(void) { OCrab::func_80082C30(objectIndex); OCrab::func_80082E18(objectIndex); } - //} } -void OCrab::Draw(s32 objectIndex, s32 cameraId) { +void OCrab::Draw(s32 cameraId) { Camera* camera; - + s32 objectIndex = indexObjectList1[_idx]; if (gObjectList[objectIndex].state >= 2) { Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); camera = &camera1[cameraId]; @@ -72,7 +74,6 @@ void OCrab::DrawModel(s32 cameraId) { s32 someIndex; s32 test; - //for (someIndex = 0; someIndex < NUM_CRABS; someIndex++) { test = indexObjectList1[_idx]; func_8008A364(test, cameraId, 0x2AABU, 800); if (is_obj_flag_status_active(test, VISIBLE) != 0) { @@ -86,7 +87,6 @@ void OCrab::DrawModel(s32 cameraId) { draw_2d_texture_at(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation, gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, (u8*)gObjectList[objectIndex].activeTexture, (Vtx*)common_vtx_hedgehog, 0x00000040, 0x00000040, 0x00000040, 0x00000020); } } - //} } void OCrab::init_ktb_crab(s32 objectIndex) { diff --git a/src/engine/objects/Crab.h b/src/engine/objects/Crab.h index 697a8bd7b..281b080ca 100644 --- a/src/engine/objects/Crab.h +++ b/src/engine/objects/Crab.h @@ -2,6 +2,8 @@ #include #include +#include "engine/objects/Object.h" +#include "World.h" extern "C" { #include "macros.h" @@ -14,20 +16,23 @@ extern "C" { #include "some_data.h" } - -class OCrab { +/** + * @arg start x and z spawn location + * @arg end x and z patrol location + * + * Crab patrols between start and end. + * The game automatically places the actor on the course surface. + * Therefore, providing a Y height is unnecessary. + * + * Crab appears to have a maximum patrolling distance and will patrol between + * end --> max distance rather than start --> end or start --> max distance. + */ +class OCrab : public OObject { public: - enum Behaviour : uint16_t { - }; + explicit OCrab(const FVector2D& start, const FVector2D& end); -public: - f32 Diameter = 0.0f; // Waddle in a circle around the spawn point at this diameter. - uint16_t MirrorModeAngleOffset; - - explicit OCrab(s32 i, Vec3f pos); - - void Tick(); - void Draw(s32 objectIndex, s32 cameraId); + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; void DrawModel(s32 cameraId); void init_ktb_crab(s32 objectIndex); @@ -36,6 +41,8 @@ public: void func_80082E18(s32 objectIndex); private: - + FVector2D _start; + FVector2D _end; + static size_t _count; s32 _idx; }; From 2bd41c6d90995cff7387e11374843cbe9e62b10f Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 29 Dec 2024 23:57:26 -0700 Subject: [PATCH 6/7] Fix Seagull, classes count their own instances --> cleanup --- src/code_80057C60.c | 12 --- src/engine/Smoke.cpp | 8 +- src/engine/TrainCrossing.cpp | 2 +- src/engine/World.cpp | 76 +------------- src/engine/World.h | 27 +---- src/engine/courses/BowsersCastle.cpp | 83 +++++++-------- src/engine/courses/DKJungle.cpp | 3 +- src/engine/courses/KalimariDesert.cpp | 3 +- src/engine/courses/KoopaTroopaBeach.cpp | 39 +++---- src/engine/courses/KoopaTroopaBeach.h | 2 + src/engine/courses/SherbetLand.cpp | 129 ++++++++++++------------ src/engine/courses/ToadsTurnpike.cpp | 12 ++- src/engine/objects/BombKart.cpp | 10 +- src/engine/objects/BombKart.h | 14 ++- src/engine/objects/Hedgehog.h | 2 +- src/engine/objects/Penguin.cpp | 18 ++-- src/engine/objects/Penguin.h | 21 +++- src/engine/objects/Seagull.cpp | 127 ++++++++++------------- src/engine/objects/Seagull.h | 32 +++--- src/engine/objects/Thwomp.cpp | 28 +++-- src/engine/objects/Thwomp.h | 20 +++- src/engine/vehicles/Boat.cpp | 8 +- src/engine/vehicles/Boat.h | 12 ++- src/engine/vehicles/Bus.cpp | 8 +- src/engine/vehicles/Bus.h | 13 ++- src/engine/vehicles/Car.cpp | 8 +- src/engine/vehicles/Car.h | 12 ++- src/engine/vehicles/TankerTruck.cpp | 8 +- src/engine/vehicles/TankerTruck.h | 13 ++- src/engine/vehicles/Train.cpp | 8 +- src/engine/vehicles/Train.h | 17 +++- src/engine/vehicles/Truck.cpp | 8 +- src/engine/vehicles/Truck.h | 13 ++- src/port/Game.cpp | 57 ----------- src/port/Game.h | 12 --- 35 files changed, 422 insertions(+), 443 deletions(-) diff --git a/src/code_80057C60.c b/src/code_80057C60.c index a4fb77372..d9be361fa 100644 --- a/src/code_80057C60.c +++ b/src/code_80057C60.c @@ -692,12 +692,6 @@ void render_object_for_player(s32 cameraId) { CourseManager_DrawObjects(cameraId); CM_DrawParticles(cameraId); - // CourseManager_RenderCourseObjects(cameraId); - // CourseManager_TrainSmokeDraw(cameraId); - // CourseManager_DrawThwomps(cameraId); - // CourseManager_DrawPenguins(cameraId); - // CourseManager_DrawSeagulls(cameraId); - // switch (gCurrentCourseId) { // case COURSE_MARIO_RACEWAY: // break; @@ -1287,9 +1281,6 @@ void func_80059AC8(void) { } CourseManager_TickObjects60fps(); - - CourseManager_TickThwomps(); // func_8005A71C(); - } } @@ -1579,9 +1570,6 @@ void func_8005A71C(void) { void update_object(void) { CourseManager_UpdateCourseObjects(); - // CourseManager_TrainSmokeTick(); - // CourseManager_TickPenguins(); - // CourseManager_TickSeagulls(); // switch (gCurrentCourseId) { // case COURSE_MARIO_RACEWAY: diff --git a/src/engine/Smoke.cpp b/src/engine/Smoke.cpp index 9d74397dc..9841bfffb 100644 --- a/src/engine/Smoke.cpp +++ b/src/engine/Smoke.cpp @@ -24,7 +24,7 @@ void TrainSmokeTick() { Object* object; for (auto& vehicle : gWorldInstance.Vehicles) { - if (auto train = dynamic_cast(vehicle.get())) { + if (auto train = dynamic_cast(vehicle)) { if (train->SmokeTimer != 0) { train->SmokeTimer -= 1; } @@ -48,7 +48,7 @@ void TrainSmokeTick() { train->SmokeTimer = 100; } } - } else if (auto boat = dynamic_cast(vehicle.get())) { + } else if (auto boat = dynamic_cast(vehicle)) { if (boat->SmokeTimer != 0) { boat->SmokeTimer -= 1; } @@ -79,7 +79,7 @@ void TrainSmokeTick() { void TrainSmokeDraw(s32 cameraId) { Camera* camera = &camera1[cameraId]; for (auto& vehicle : gWorldInstance.Vehicles) { - if (auto train = dynamic_cast(vehicle.get())) { + if (auto train = dynamic_cast(vehicle)) { gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0); load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32); func_8004B72C(255, 255, 255, 255, 255, 255, 255); @@ -92,7 +92,7 @@ void TrainSmokeDraw(s32 cameraId) { render_object_train_smoke_particle(train->SmokeParticles[i], cameraId); } } - } else if (auto boat = dynamic_cast(vehicle.get())) { + } else if (auto boat = dynamic_cast(vehicle)) { gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0); load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32); diff --git a/src/engine/TrainCrossing.cpp b/src/engine/TrainCrossing.cpp index 13232c962..98c7c766b 100644 --- a/src/engine/TrainCrossing.cpp +++ b/src/engine/TrainCrossing.cpp @@ -30,7 +30,7 @@ void TrainCrossing::CrossingTrigger() { for (const auto& vehicle : gWorldInstance.Vehicles) { - if (auto train = dynamic_cast(vehicle.get())) {; + if (auto train = dynamic_cast(vehicle)) {; f32 radius = DynamicRadius(train->Locomotive.position, train->Locomotive.velocity, Position); if (Distance(train->Locomotive.position, Position) < radius) { diff --git a/src/engine/World.cpp b/src/engine/World.cpp index 5cd85213b..ded60a262 100644 --- a/src/engine/World.cpp +++ b/src/engine/World.cpp @@ -3,14 +3,7 @@ #include "Cup.h" #include "courses/Course.h" #include "vehicles/Vehicle.h" -#include "vehicles/Train.h" -#include "vehicles/Boat.h" -#include "vehicles/Truck.h" -#include "vehicles/Bus.h" -#include "vehicles/TankerTruck.h" -#include "vehicles/Car.h" #include "objects/BombKart.h" -#include "objects/Penguin.h" #include "TrainCrossing.h" #include #include "objects/Object.h" @@ -40,53 +33,13 @@ void World::SetCourseFromCup() { CurrentCourse = CurrentCup->GetCourse(); } -// Required for spawning vehicles in divisions across path points -static size_t trains; -static size_t trucks; -static size_t busses; -static size_t tankerTrucks; -static size_t cars; -static size_t boats; -static size_t thwomps; -static size_t penguins; -static size_t seagulls; -/** - * Note that you can only remove the tender if there are no carriages - * @arg waypoint initial waypoint to spawn at. - */ -void World::AddTrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(trains, tender, numCarriages, speed, waypoint)); - trains++; -} - -void World::AddBoat(f32 speed, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(boats, speed, waypoint)); - boats++; -} - -void World::AddTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(trucks, speedA, speedB, path, waypoint)); - trucks++; -} - -void World::AddBus(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(busses, speedA, speedB, path, waypoint)); - busses++; -} - -void World::AddTankerTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(tankerTrucks, speedA, speedB, path, waypoint)); - tankerTrucks++; -} - -void World::AddCar(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { - Vehicles.push_back(std::make_unique(cars, speedA, speedB, path, waypoint)); - cars++; +AVehicle* World::AddVehicle(AVehicle* vehicle) { + Vehicles.push_back(vehicle); + return Vehicles.back(); } void World::ClearVehicles(void) { - trains = trucks = busses = tankerTrucks = cars = boats = thwomps = 0; Vehicles.clear(); } @@ -97,28 +50,7 @@ TrainCrossing* World::AddCrossing(Vec3f position, u32 waypointMin, u32 waypointM } void World::AddBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C) { - BombKarts.push_back(std::make_unique(pos, waypoint, waypointIndex, state, unk_3C)); -} - -void World::AddThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) { - Thwomps.push_back( - std::make_unique(thwomps, x, z, direction, scale, behaviour, primAlpha, boundingBoxSize)); - thwomps++; - gNumActiveThwomps = thwomps; -} - -std::shared_ptr World::AddPenguin(Vec3f pos, u16 direction, OPenguin::PenguinType type, OPenguin::Behaviour behaviour) { - auto penguin = std::make_shared(penguins, pos, direction, type, behaviour); - Penguins.push_back(penguin); - penguins++; - return penguin; -} - -std::shared_ptr World::AddSeagull(Vec3f pos) { - auto seagull = std::make_shared(seagulls, pos); - Seagulls.push_back(seagull); - seagulls++; - return seagull; + BombKarts.push_back(new OBombKart(pos, waypoint, waypointIndex, state, unk_3C)); } u32 World::GetCupIndex() { diff --git a/src/engine/World.h b/src/engine/World.h index 1aa09fb57..4fdf55bc8 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -102,11 +102,8 @@ class OObject; class Cup; // <-- Forward declaration class Course; class AVehicle; -class ATrain; -class ACar; +class OBombKart; class TrainCrossing; -class OThwomp; -class OSeagull; class OLakitu; class World { @@ -212,33 +209,19 @@ public: std::vector Actors; std::vector Objects; + std::vector Vehicles; + std::vector BombKarts; std::vector Emitters; std::unordered_map Lakitus; - /** Actors */ - void AddBoat(f32 speed, uint32_t waypoint); - void AddTrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint); - void AddTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); - void AddBus(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); - void AddTankerTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); - void AddCar(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); - std::vector> Vehicles; + AVehicle* AddVehicle(AVehicle* vehicle); + void ClearVehicles(void); /** Objects **/ - std::vector> BombKarts; void AddBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C); - std::vector> Thwomps; - void AddThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize = 7); - - std::vector> Penguins; - std::shared_ptr AddPenguin(Vec3f pos, u16 direction, OPenguin::PenguinType type, OPenguin::Behaviour behaviour); - - std::vector> Seagulls; - std::shared_ptr AddSeagull(Vec3f pos); - TrainCrossing* AddCrossing(Vec3f position, u32 waypointMin, u32 waypointMax, f32 approachRadius, f32 exitRadius); std::vector> Crossings; diff --git a/src/engine/courses/BowsersCastle.cpp b/src/engine/courses/BowsersCastle.cpp index d5766b668..49ae93385 100644 --- a/src/engine/courses/BowsersCastle.cpp +++ b/src/engine/courses/BowsersCastle.cpp @@ -7,6 +7,7 @@ #include "World.h" #include "engine/actors/AFinishline.h" #include "engine/objects/BombKart.h" +#include "engine/objects/Thwomp.h" #include "bowsers_castle_data.h" extern "C" { @@ -153,6 +154,47 @@ void BowsersCastle::SpawnActors() { spawn_foliage((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_bowsers_castle_tree_spawn)); spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_bowsers_castle_item_box_spawns)); + + switch (gCCSelection) { + case CC_100: + case CC_EXTRA: + gWorldInstance.AddObject(new OThwomp(0x0320, 0xf92a, 0xC000, 1.0f, 1, 0)); + gWorldInstance.AddObject(new OThwomp(0x044c, 0xf92a, 0xC000, 1.0f, 1, 1)); + gWorldInstance.AddObject(new OThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, 2, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, 2, 1)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5bf, 0xC000, 1.0f, 4, 0)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf597, 0xC000, 1.0f, 4, 1)); + gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0)); + gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0)); + gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1)); + break; + case CC_50: + gWorldInstance.AddObject(new OThwomp(0x3B6, 0xF92A, 0xC000, 1.0f, 1, 0)); + gWorldInstance.AddObject(new OThwomp(0x0352, 0xf95c, 0xC000, 1.0f, 2, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5b0, 0xC000, 1.0f, 4, 0)); + gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0)); + gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0)); + gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1)); + break; + case CC_150: + gWorldInstance.AddObject(new OThwomp(0x0320, 0xf92a, 0xC000, 1.0f, 1, 0)); + gWorldInstance.AddObject(new OThwomp(0x044c, 0xf92a, 0xC000, 1.0f, 1, 1)); + gWorldInstance.AddObject(new OThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, 2, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, 2, 1)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0)); + gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5c9, 0xC000, 1.0f, 4, 0)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5ab, 0xC000, 1.0f, 4, 1)); + gWorldInstance.AddObject(new OThwomp(0x091a, 0xf58d, 0xC000, 1.0f, 4, 2)); + gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0)); + gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0)); + gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1)); + break; + } } void BowsersCastle::SpawnVehicles() { @@ -181,47 +223,6 @@ void BowsersCastle::InitCourseObjects() { size_t objectId; size_t i; - switch (gCCSelection) { - case CC_100: - case CC_EXTRA: - gWorldInstance.AddThwomp(0x0320, 0xf92a, 0xC000, 1.0f, 1, 0); - gWorldInstance.AddThwomp(0x044c, 0xf92a, 0xC000, 1.0f, 1, 1); - gWorldInstance.AddThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, 2, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, 2, 1); - gWorldInstance.AddThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1); - gWorldInstance.AddThwomp(0x091a, 0xf5bf, 0xC000, 1.0f, 4, 0); - gWorldInstance.AddThwomp(0x091a, 0xf597, 0xC000, 1.0f, 4, 1); - gWorldInstance.AddThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0); - gWorldInstance.AddThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0); - gWorldInstance.AddThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1); - break; - case CC_50: - gWorldInstance.AddThwomp(0x3B6, 0xF92A, 0xC000, 1.0f, 1, 0); - gWorldInstance.AddThwomp(0x0352, 0xf95c, 0xC000, 1.0f, 2, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1); - gWorldInstance.AddThwomp(0x091a, 0xf5b0, 0xC000, 1.0f, 4, 0); - gWorldInstance.AddThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0); - gWorldInstance.AddThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0); - gWorldInstance.AddThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1); - break; - case CC_150: - gWorldInstance.AddThwomp(0x0320, 0xf92a, 0xC000, 1.0f, 1, 0); - gWorldInstance.AddThwomp(0x044c, 0xf92a, 0xC000, 1.0f, 1, 1); - gWorldInstance.AddThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, 2, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, 2, 1); - gWorldInstance.AddThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, 3, 0); - gWorldInstance.AddThwomp(0x04b0, 0xf592, 0xC000, 1.0f, 3, 1); - gWorldInstance.AddThwomp(0x091a, 0xf5c9, 0xC000, 1.0f, 4, 0); - gWorldInstance.AddThwomp(0x091a, 0xf5ab, 0xC000, 1.0f, 4, 1); - gWorldInstance.AddThwomp(0x091a, 0xf58d, 0xC000, 1.0f, 4, 2); - gWorldInstance.AddThwomp(0x0596, 0xf92f, 0xC000, 1.5f, 6, 0); - gWorldInstance.AddThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, 5, 0); - gWorldInstance.AddThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, 5, 1); - break; - } - // Handle the big statue's fire breath objectId = indexObjectList2[0]; init_object(objectId, 0); diff --git a/src/engine/courses/DKJungle.cpp b/src/engine/courses/DKJungle.cpp index 941ccdb22..9daf7ad3f 100644 --- a/src/engine/courses/DKJungle.cpp +++ b/src/engine/courses/DKJungle.cpp @@ -9,6 +9,7 @@ #include "engine/objects/BombKart.h" #include "assets/dks_jungle_parkway_data.h" +#include "engine/vehicles/Boat.h" #include "engine/vehicles/Utils.h" extern "C" { @@ -278,7 +279,7 @@ void DKJungle::SpawnVehicles() { // The original game only ran vehicle logic every second frame. // Thus the speed gets divided by two to set speed to match properly - gWorldInstance.AddBoat((0.6666666f)/4, 0); + gWorldInstance.AddVehicle(new ABoat((0.6666666f)/4, 0)); if (gModeSelection == VERSUS) { Vec3f pos = {0, 0, 0}; diff --git a/src/engine/courses/KalimariDesert.cpp b/src/engine/courses/KalimariDesert.cpp index 2440e8b01..8f00441ec 100644 --- a/src/engine/courses/KalimariDesert.cpp +++ b/src/engine/courses/KalimariDesert.cpp @@ -10,6 +10,7 @@ #include "kalimari_desert_data.h" #include "engine/vehicles/Utils.h" +#include "engine/vehicles/Train.h" #include "engine/vehicles/Vehicle.h" extern "C" { @@ -237,7 +238,7 @@ void KalimariDesert::SpawnVehicles() { } } - gWorldInstance.AddTrain(_tender, _numCarriages, 2.5f, waypoint); + gWorldInstance.AddVehicle(new ATrain(_tender, _numCarriages, 2.5f, waypoint)); } if (gModeSelection == VERSUS) { diff --git a/src/engine/courses/KoopaTroopaBeach.cpp b/src/engine/courses/KoopaTroopaBeach.cpp index daaba1ad8..499a62bf7 100644 --- a/src/engine/courses/KoopaTroopaBeach.cpp +++ b/src/engine/courses/KoopaTroopaBeach.cpp @@ -158,6 +158,26 @@ void KoopaTroopaBeach::SpawnActors() { gWorldInstance.AddObject(new OCrab(FVector2D(268, 406), FVector2D(101, 394))); gWorldInstance.AddObject(new OCrab(FVector2D(223, 318), FVector2D(86, 308))); } + + if (gGamestate == CREDITS_SEQUENCE) { + for (size_t i = 0; i < NUM_SEAGULLS; i++) { + //gWorldInstance.AddObject(new OSeagull(FVector(-360.0f, 60.0f, -1300.0f))); + Vec3f pos = {-360.0f, 60.0f, -1300.0f}; + gWorldInstance.AddObject(new OSeagull(pos)); + } + } else { // Normal gameplay + for (size_t i = 0; i < 4; i++) { + Vec3f pos = {-985.0f, 15.0f, 1200.0f}; + gWorldInstance.AddObject(new OSeagull(pos)); + //gWorldInstance.AddObject(new OSeagull(FVector(-985.0f, 15.0f, 1200.0f))); + } + + for (size_t i = 0; i < 6; i++) { + //gWorldInstance.AddObject(new OSeagull(FVector(328.0f, 20.0f, 2541.0f))); + Vec3f pos2 = {328.0f, 20.0f, 2541.0f}; + gWorldInstance.AddObject(new OSeagull(pos2)); + } + } } void KoopaTroopaBeach::SpawnVehicles() { @@ -184,25 +204,6 @@ void KoopaTroopaBeach::MinimapSettings() { } void KoopaTroopaBeach::InitCourseObjects() { - size_t objectId; - size_t i; - - if (gGamestate == CREDITS_SEQUENCE) { - Vec3f pos = {-360.0f, 60.0f, -1300.0f}; - for (size_t i = 0; i < NUM_SEAGULLS; i++) { - gWorldInstance.AddSeagull(pos); - } - } else { // Normal gameplay - Vec3f pos = {-985.0f, 15.0f, 1200.0f}; - for (size_t i = 0; i < 4; i++) { - gWorldInstance.AddSeagull(pos); - } - - Vec3f pos2 = {328.0f, 20.0f, 2541.0f}; - for (size_t i = 0; i < 6; i++) { - gWorldInstance.AddSeagull(pos2); - } - } } void KoopaTroopaBeach::UpdateCourseObjects() { diff --git a/src/engine/courses/KoopaTroopaBeach.h b/src/engine/courses/KoopaTroopaBeach.h index 4dc51313e..8237b7628 100644 --- a/src/engine/courses/KoopaTroopaBeach.h +++ b/src/engine/courses/KoopaTroopaBeach.h @@ -3,6 +3,8 @@ #include #include "Course.h" +#include "World.h" + extern "C" { #include "assets/koopa_troopa_beach_vertices.h" #include "assets/koopa_troopa_beach_displaylists.h" diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp index e14b2c7e0..0153bf0a8 100644 --- a/src/engine/courses/SherbetLand.cpp +++ b/src/engine/courses/SherbetLand.cpp @@ -134,6 +134,72 @@ void SherbetLand::SpawnActors() { gWorldInstance.AddActor(new AFinishline()); spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_sherbet_land_item_box_spawns)); + + + +// Originally, multiplayer did not spawn the big penguin +// if (gPlayerCountSelection1 == 1) { + Vec3f pos = {-383.0f, 2.0f, -690.0f}; + gWorldInstance.AddObject(new OPenguin(pos, 0, OPenguin::PenguinType::EMPEROR, OPenguin::Behaviour::STRUT)); +// } + + //! @bug Skip spawning penguins due to animation crash for now + if (gGamestate == CREDITS_SEQUENCE) { + return; + } + + Vec3f pos2 = {-2960.0f, -80.0f, 1521.0f}; + auto penguin = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos2, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + auto penguin2 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos2, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + penguin->Diameter = penguin2->Diameter = 100.0f; + + Vec3f pos3 = {-2490.0f, -80.0f, 1612.0f}; + auto penguin3 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos3, 0x100, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + auto penguin4 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos3, 0x100, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + penguin3->Diameter = penguin4->Diameter = 80.0f; + + Vec3f pos4 = {-2098.0f, -80.0f, 1624.0f}; + auto penguin5 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos4, 0xFF00, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + auto penguin6 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos4, 0xFF00, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + penguin5->Diameter = penguin6->Diameter = 80.0f; + + + Vec3f pos5 = {-2080.0f, -80.0f, 1171.0f}; + auto penguin7 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos5, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + auto penguin8 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos5, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); + penguin7->Diameter = penguin8->Diameter = 80.0f; + + + if (gGamestate == CREDITS_SEQUENCE) { + Vec3f pos6 = {380.0, 0.0f, -535.0f}; + auto penguin9 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos6, 0x9000, OPenguin::PenguinType::CREDITS, OPenguin::Behaviour::SLIDE3))); + penguin9->MirrorModeAngleOffset = -0x4000; + } else { + Vec3f pos6 = {146.0f, 0.0f, -380.0f}; + auto penguin9 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos6, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE3))); + penguin9->MirrorModeAngleOffset = -0x4000; + } + + Vec3f pos7 = {380.0f, 0.0f, -766.0f}; + auto penguin10 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos7, 0x5000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE4))); + penguin10->MirrorModeAngleOffset = 0x8000; + + Vec3f pos8 = {-2300.0f, 0.0f, -210.0f}; + auto penguin11 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos8, 0xC000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); + penguin11->MirrorModeAngleOffset = 0x8000; + + Vec3f pos9 = {-2500.0f, 0.0f, -250.0f}; + auto penguin12 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos9, 0x4000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); + penguin12->MirrorModeAngleOffset = 0x8000; + + Vec3f pos10 = {-535.0f, 0.0f, 875.0f}; + auto penguin13 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos10, 0x8000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); + penguin13->MirrorModeAngleOffset = -0x4000; + + Vec3f pos11 = {-250.0f, 0.0f, 953.0f}; + auto penguin14 = reinterpret_cast(gWorldInstance.AddObject(new OPenguin(pos11, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); + penguin14->MirrorModeAngleOffset = -0x4000; + } void SherbetLand::SpawnVehicles() { @@ -163,69 +229,6 @@ void SherbetLand::MinimapSettings() { } void SherbetLand::InitCourseObjects() { - //! @bug Skip spawning penguins due to animation crash for now - if (gGamestate == CREDITS_SEQUENCE) { - return; - } - -// Originally, multiplayer did not spawn the big penguin -// if (gPlayerCountSelection1 == 1) { - Vec3f pos = {-383.0f, 2.0f, -690.0f}; - gWorldInstance.AddPenguin(pos, 0, OPenguin::PenguinType::EMPEROR, OPenguin::Behaviour::STRUT); -// } - - - Vec3f pos2 = {-2960.0f, -80.0f, 1521.0f}; - auto penguin = gWorldInstance.AddPenguin(pos2, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - auto penguin2 = gWorldInstance.AddPenguin(pos2, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - penguin->Diameter = penguin2->Diameter = 100.0f; - - Vec3f pos3 = {-2490.0f, -80.0f, 1612.0f}; - auto penguin3 = gWorldInstance.AddPenguin(pos3, 0x100, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - auto penguin4 = gWorldInstance.AddPenguin(pos3, 0x100, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - penguin3->Diameter = penguin4->Diameter = 80.0f; - - Vec3f pos4 = {-2098.0f, -80.0f, 1624.0f}; - auto penguin5 = gWorldInstance.AddPenguin(pos4, 0xFF00, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - auto penguin6 = gWorldInstance.AddPenguin(pos4, 0xFF00, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - penguin5->Diameter = penguin6->Diameter = 80.0f; - - - Vec3f pos5 = {-2080.0f, -80.0f, 1171.0f}; - auto penguin7 = gWorldInstance.AddPenguin(pos5, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - auto penguin8 = gWorldInstance.AddPenguin(pos5, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE); - penguin7->Diameter = penguin8->Diameter = 80.0f; - - - if (gGamestate == CREDITS_SEQUENCE) { - Vec3f pos6 = {380.0, 0.0f, -535.0f}; - auto penguin9 = gWorldInstance.AddPenguin(pos6, 0x9000, OPenguin::PenguinType::CREDITS, OPenguin::Behaviour::SLIDE3); - penguin9->MirrorModeAngleOffset = -0x4000; - } else { - Vec3f pos6 = {146.0f, 0.0f, -380.0f}; - auto penguin9 = gWorldInstance.AddPenguin(pos6, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE3); - penguin9->MirrorModeAngleOffset = -0x4000; - } - - Vec3f pos7 = {380.0f, 0.0f, -766.0f}; - auto penguin10 = gWorldInstance.AddPenguin(pos7, 0x5000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE4); - penguin10->MirrorModeAngleOffset = 0x8000; - - Vec3f pos8 = {-2300.0f, 0.0f, -210.0f}; - auto penguin11 = gWorldInstance.AddPenguin(pos8, 0xC000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6); - penguin11->MirrorModeAngleOffset = 0x8000; - - Vec3f pos9 = {-2500.0f, 0.0f, -250.0f}; - auto penguin12 = gWorldInstance.AddPenguin(pos9, 0x4000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6); - penguin12->MirrorModeAngleOffset = 0x8000; - - Vec3f pos10 = {-535.0f, 0.0f, 875.0f}; - auto penguin13 = gWorldInstance.AddPenguin(pos10, 0x8000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6); - penguin13->MirrorModeAngleOffset = -0x4000; - - Vec3f pos11 = {-250.0f, 0.0f, 953.0f}; - auto penguin14 = gWorldInstance.AddPenguin(pos11, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6); - penguin14->MirrorModeAngleOffset = -0x4000; } void SherbetLand::UpdateCourseObjects() { diff --git a/src/engine/courses/ToadsTurnpike.cpp b/src/engine/courses/ToadsTurnpike.cpp index 4acdcd466..47ed10111 100644 --- a/src/engine/courses/ToadsTurnpike.cpp +++ b/src/engine/courses/ToadsTurnpike.cpp @@ -8,6 +8,10 @@ #include "engine/objects/BombKart.h" #include "assets/toads_turnpike_data.h" #include "engine/actors/AFinishline.h" +#include "engine/vehicles/Bus.h" +#include "engine/vehicles/Car.h" +#include "engine/vehicles/Truck.h" +#include "engine/vehicles/TankerTruck.h" #include "engine/vehicles/Utils.h" @@ -257,22 +261,22 @@ void ToadsTurnpike::SpawnVehicles() { for (size_t i = 0; i < _numTrucks; i++) { waypoint = CalculateWaypointDistribution(i, _numTrucks, gWaypointCountByPathIndex[0], 0); - gWorldInstance.AddTruck(a, b, &D_80164550[0][0], waypoint); + gWorldInstance.AddVehicle(new ATruck(a, b, &D_80164550[0][0], waypoint)); } for (size_t i = 0; i < _numBuses; i++) { waypoint = CalculateWaypointDistribution(i, _numBuses, gWaypointCountByPathIndex[0], 75); - gWorldInstance.AddBus(a, b,&D_80164550[0][0], waypoint); + gWorldInstance.AddVehicle(new ABus(a, b,&D_80164550[0][0], waypoint)); } for (size_t i = 0; i < _numTankerTrucks; i++) { waypoint = CalculateWaypointDistribution(i, _numTankerTrucks, gWaypointCountByPathIndex[0], 50); - gWorldInstance.AddTankerTruck(a, b, &D_80164550[0][0], waypoint); + gWorldInstance.AddVehicle(new ATankerTruck(a, b, &D_80164550[0][0], waypoint)); } for (size_t i = 0; i < _numCars; i++) { waypoint = CalculateWaypointDistribution(i, _numCars, gWaypointCountByPathIndex[0], 25); - gWorldInstance.AddCar(a, b, &D_80164550[0][0], waypoint); + gWorldInstance.AddVehicle(new ACar(a, b, &D_80164550[0][0], waypoint)); } if (gModeSelection == VERSUS) { diff --git a/src/engine/objects/BombKart.cpp b/src/engine/objects/BombKart.cpp index 42506f826..c33b4b107 100644 --- a/src/engine/objects/BombKart.cpp +++ b/src/engine/objects/BombKart.cpp @@ -26,8 +26,10 @@ extern "C" { extern s8 gPlayerCount; } -OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C) { +size_t OBombKart::_count = 0; +OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C) { + _idx = _count; Vec3f _pos = {0, 0, 0}; if (waypoint) { // Spawn kart on waypoint @@ -68,6 +70,8 @@ OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, WheelPos[3][1] = _pos[1]; WheelPos[3][2] = _pos[2]; check_bounding_collision(&_Collision, 2.0f, _pos[0], _pos[1], _pos[2]); + + _count++; } void OBombKart::Spawn() { @@ -334,9 +338,7 @@ void OBombKart::Draw(s32 cameraId) { } if (GetCourse() == GetPodiumCeremony()) { - // This isn't functionally equivallent. - // Technicaly it should be if (kart[0].WaypointIndex < 16) - if (WaypointIndex < 16) { + if ((_idx == 0) && (WaypointIndex < 16)) { return; } else { cameraId = PLAYER_FOUR; diff --git a/src/engine/objects/BombKart.h b/src/engine/objects/BombKart.h index 4500e41c2..7ceba7ecb 100644 --- a/src/engine/objects/BombKart.h +++ b/src/engine/objects/BombKart.h @@ -5,6 +5,8 @@ #include #include "engine/Matrix.h" +#include "World.h" + extern "C" { #include "macros.h" #include "main.h" @@ -53,16 +55,26 @@ public: // Set waypoint to NULL if using a spawn position and not a waypoint. explicit OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C); + ~OBombKart() { + _count--; + } + + static size_t GetCount() { + return _count; + } + void Spawn(); void BeginPlay(); void Tick(); - void Draw(s32 playerId); + void Draw(s32 cameraId); void DrawBattle(s32 cameraId); void Collision(s32 playerId, Player* player); void SomeRender(Vec3f arg1); void LoadMtx(); void Waypoint(s32 screenId); private: + static size_t _count; + s32 _idx; Player* FindTarget(); void Chase(Player*, Vec3f pos); diff --git a/src/engine/objects/Hedgehog.h b/src/engine/objects/Hedgehog.h index dab8cf15a..2057d894d 100644 --- a/src/engine/objects/Hedgehog.h +++ b/src/engine/objects/Hedgehog.h @@ -4,7 +4,7 @@ #include #include "Object.h" -#include "World.h" +#include "engine/World.h" extern "C" { #include "macros.h" diff --git a/src/engine/objects/Penguin.cpp b/src/engine/objects/Penguin.cpp index c126174a1..c690e1ef2 100644 --- a/src/engine/objects/Penguin.cpp +++ b/src/engine/objects/Penguin.cpp @@ -33,16 +33,19 @@ extern "C" { extern s8 gPlayerCount; } -OPenguin::OPenguin(s32 i, Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour) { - if (i >= 32) { - printf("MAX penguin REACHED (32), skipping\n"); - return; - } - _idx = i; +size_t OPenguin::_count = 0; + +OPenguin::OPenguin(Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour) { + _idx = _count; _type = type; _bhv = behaviour; - s32 objectIndex = indexObjectList1[i]; + if (_idx >= 32) { + printf("MAX penguin REACHED (32), skipping\n"); + return; + } + + s32 objectIndex = indexObjectList1[_idx]; init_object(objectIndex, 0); Object *object = &gObjectList[objectIndex]; @@ -73,6 +76,7 @@ OPenguin::OPenguin(s32 i, Vec3f pos, u16 direction, PenguinType type, Behaviour break; } + _count++; } void OPenguin::Tick(void) { diff --git a/src/engine/objects/Penguin.h b/src/engine/objects/Penguin.h index 0e9c36f49..63c2207c1 100644 --- a/src/engine/objects/Penguin.h +++ b/src/engine/objects/Penguin.h @@ -2,6 +2,8 @@ #include #include +#include "engine/World.h" +#include "engine/objects/Object.h" extern "C" { #include "macros.h" @@ -13,7 +15,7 @@ extern "C" { #include "course_offsets.h" } -class OPenguin { +class OPenguin : public OObject { public: enum PenguinType : uint32_t { CHICK, @@ -36,10 +38,19 @@ public: f32 Diameter = 0.0f; // Waddle in a circle around the spawn point at this diameter. uint16_t MirrorModeAngleOffset; - explicit OPenguin(s32 i, Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour); + explicit OPenguin(Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour); - void Tick(); - void Draw(s32 playerId); + ~OPenguin() { + _count--; + } + + static size_t GetCount() { + return _count; + } + + + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; private: void Behaviours(s32 objectIndex, s32 arg1); void EmperorPenguin(s32 objectIndex); @@ -51,7 +62,7 @@ private: void OtherPenguin(s32 objectIndex); void InitOtherPenguin(s32 objectIndex); - + static size_t _count; s32 _idx; PenguinType _type; Behaviour _bhv; diff --git a/src/engine/objects/Seagull.cpp b/src/engine/objects/Seagull.cpp index 5f0b12a7e..cced70348 100644 --- a/src/engine/objects/Seagull.cpp +++ b/src/engine/objects/Seagull.cpp @@ -1,8 +1,8 @@ #include #include #include "Seagull.h" -#include "engine/Actor.h" #include +#include "World.h" #include "port/Game.h" @@ -29,9 +29,14 @@ extern SplineData D_800E6280; SplineData* D_800E633C[] = { &D_800E6034, &D_800E60F0, &D_800E61B4, &D_800E6280 }; -OSeagull::OSeagull(s32 i, Vec3f pos) { - size_t objectId; - _idx = i; +size_t OSeagull::_count = 0; + +OSeagull::OSeagull(Vec3f pos) { + size_t objectIndex; + _idx = _count; + _pos[0] = pos[0]; + _pos[1] = pos[1]; + _pos[2] = pos[2]; s16 randZ; s16 randX; @@ -40,60 +45,48 @@ OSeagull::OSeagull(s32 i, Vec3f pos) { randY = random_int(20); randZ = random_int(200) + -100.0; - SpawnPos[0] = pos[0] + randX; - SpawnPos[1] = pos[1] + randY; - SpawnPos[2] = pos[2] + randZ; - //for (i = 0; i < NUM_SEAGULLS; i++) { - //objectId = indexObjectList2[i]; - //init_object(objectId, 0); + objectIndex = indexObjectList2[_idx]; + init_object(objectIndex, 0); - //set_obj_origin_pos(objectId, pos[0], pos[1], pos[2]); - //if (i < (NUM_SEAGULLS / 2)) { - //gObjectList[objectId].unk_0D5 = 0; - //} else { - // gObjectList[objectId].unk_0D5 = 1; - //} - //} + set_obj_origin_pos(objectIndex, pos[0], pos[1], pos[2]); + if (_idx < (NUM_SEAGULLS / 2)) { + gObjectList[objectIndex].unk_0D5 = 0; + } else { + gObjectList[objectIndex].unk_0D5 = 1; + } + + _count++; } -bool OSeagull::IsMod() { return true; } - void OSeagull::Tick() { Object* object; - UNUSED s32* var_s4; - s32 temp_s0; + s32 objectIndex = indexObjectList2[_idx]; - //for (var_s3 = 0; var_s3 < NUM_SEAGULLS; var_s3++) { - //temp_s0 = indexObjectList2[_idx]; - - //object = &gObjectList[temp_s0]; - if (_state == 0) { + object = &gObjectList[objectIndex]; + if (object->state == 0) { return; } - OSeagull::func_80082714(temp_s0, _idx); - OSeagull::func_8008275C(temp_s0); - if (_toggle) { - _toggle = false; + OSeagull::func_80082714(objectIndex, _idx); + OSeagull::func_8008275C(objectIndex); + if (func_80072320(objectIndex, 2) != 0) { + func_800722CC(objectIndex, 2); if (D_80165A90 != 0) { D_80165A90 = 0; D_80183E40[0] = 0.0f; D_80183E40[1] = 0.0f; D_80183E40[2] = 0.0f; if (gGamestate != CREDITS_SEQUENCE) { - func_800C98B8(Pos, D_80183E40, SOUND_ARG_LOAD(0x19, 0x01, 0x70, 0x43)); + func_800C98B8(object->pos, D_80183E40, SOUND_ARG_LOAD(0x19, 0x01, 0x70, 0x43)); } else { - //temp_s0 = indexObjectList2[1]; - //! @todo confirm this is equivallent to indexObjectList2[1]; - if (_idx == 1) { - if (gCutsceneShotTimer <= 150) { - //object = &gObjectList[temp_s0]; - func_800C98B8(Pos, D_80183E40, SOUND_ARG_LOAD(0x19, 0x01, 0x70, 0x43)); - } + objectIndex = indexObjectList2[1]; + if (gCutsceneShotTimer <= 150) { + object = &gObjectList[objectIndex]; + func_800C98B8(object->pos, D_80183E40, SOUND_ARG_LOAD(0x19, 0x01, 0x70, 0x43)); } } } @@ -114,19 +107,16 @@ void OSeagull::Tick() { D_80165908 = 0; } -void OSeagull::Draw(Camera* camera) { // render_object_seagulls - s32 var_s1; - //for (i = 0; i < NUM_SEAGULLS; i++) { - var_s1 = indexObjectList2[_idx]; - //! @todo: Quick hack to let seagull work in actor system. Should be cameraId not camera->playerId - //if (func_8008A364(var_s1, camera->playerId, 0x5555U, 0x000005DC) < 0x9C401 && CVarGetInteger("gNoCulling", 0) == 0) { - D_80165908 = 1; - _toggle = true; - //} - //if (is_obj_flag_status_active(var_s1, VISIBLE) != 0) { - OSeagull::func_800552BC(var_s1); - //} - //} +void OSeagull::Draw(s32 cameraId) { // render_object_seagulls + s32 objectIndex = indexObjectList2[_idx]; + + if (func_8008A364(objectIndex, cameraId, 0x5555U, 0x000005DC) < 0x9C401 && CVarGetInteger("gNoCulling", 0) == 0) { + D_80165908 = 1; + _toggle = true; + } + if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + OSeagull::func_800552BC(objectIndex); + } } void OSeagull::func_800552BC(s32 objectIndex) { @@ -155,11 +145,11 @@ void OSeagull::func_8008275C(s32 objectIndex) { case 2: func_8008B78C(objectIndex); vec3f_copy(gObjectList[objectIndex].unk_01C, gObjectList[objectIndex].pos); - func_8000D940(SpawnPos, (s16*) &gObjectList[objectIndex].unk_0C6, + func_8000D940(gObjectList[objectIndex].origin_pos, (s16*) &gObjectList[objectIndex].unk_0C6, gObjectList[objectIndex].unk_034, 0.0f, 0); - Offset[0] *= 2.0; - Offset[1] *= 2.5; - Offset[2] *= 2.0; + gObjectList[objectIndex].offset[0] *= 2.0; + gObjectList[objectIndex].offset[1] *= 2.5; + gObjectList[objectIndex].offset[2] *= 2.0; object_calculate_new_pos_offset(objectIndex); gObjectList[objectIndex].direction_angle[1] = get_angle_between_two_vectors(gObjectList[objectIndex].unk_01C, gObjectList[objectIndex].pos); @@ -169,31 +159,26 @@ void OSeagull::func_8008275C(s32 objectIndex) { } void OSeagull::func_8008241C(s32 objectIndex, s32 arg1) { - UNUSED s16 stackPadding0; + s16 randZ; + s16 randX; + s16 randY; gObjectList[objectIndex].unk_0D8 = 1; gObjectList[objectIndex].model = (Gfx*) d_course_koopa_troopa_beach_unk4; gObjectList[objectIndex].vertex = (Vtx*) d_course_koopa_troopa_beach_unk_data5; gObjectList[objectIndex].sizeScaling = 0.2f; gObjectList[objectIndex].unk_0DD = 1; - // if (gGamestate == CREDITS_SEQUENCE) { - // set_obj_origin_pos(objectIndex, randX + -360.0, randY + 60.0, randZ + -1300.0); - // } else if (gObjectList[objectIndex].unk_0D5 != 0) { - // set_obj_origin_pos(objectIndex, (randX + 328.0) * xOrientation, randY + 20.0, randZ + 2541.0); - // } else { - // set_obj_origin_pos(objectIndex, (randX + -985.0) * xOrientation, randY + 15.0, randZ + 1200.0); - // } + randX = random_int(0x00C8) + -100.0; + randY = random_int(0x0014); + randZ = random_int(0x00C8) + -100.0; + + set_obj_origin_pos(objectIndex, (randX + _pos[0]) * xOrientation, randY + _pos[1], randZ + _pos[2]); set_obj_direction_angle(objectIndex, 0U, 0U, 0U); gObjectList[objectIndex].unk_034 = 1.0f; func_80086EF0(objectIndex); - //gObjectList[objectIndex].spline = D_800E633C[arg1 % 4]; - spline = D_800E633C[arg1 % 4]; - //set_object_flag(objectIndex, 0x800); - //object_next_state(objectIndex); - _status |= 0x800; - _timer = 0; - _status &= ~0x2000; - _state++; + gObjectList[objectIndex].spline = D_800E633C[arg1 % 4]; + set_object_flag(objectIndex, 0x00000800); + object_next_state(objectIndex); } diff --git a/src/engine/objects/Seagull.h b/src/engine/objects/Seagull.h index 528da0708..d575e3721 100644 --- a/src/engine/objects/Seagull.h +++ b/src/engine/objects/Seagull.h @@ -2,7 +2,9 @@ #include #include -#include "engine/Actor.h" +#include "Object.h" + +#include "engine/World.h" extern "C" { #include "macros.h" @@ -11,34 +13,34 @@ extern "C" { #include "waypoints.h" #include "common_structs.h" #include "objects.h" -#include "course_offsets.h" -#include "some_data.h" +#include "camera.h" } -class OSeagull : public AActor { +class OSeagull : public OObject { public: - enum Behaviour : uint16_t { - }; + explicit OSeagull(Vec3f pos); -public: - explicit OSeagull(s32 i, Vec3f pos); + ~OSeagull() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Tick() override; - virtual void Draw(Camera*) override; + virtual void Draw(s32 cameraId) override; + void func_800552BC(s32 objectIndex); void func_8008275C(s32 objectIndex); void func_8008241C(s32 objectIndex, s32 arg1); void func_80082714(s32 objectIndex, s32 arg1); - virtual bool IsMod() override; - Vec3f Offset; - Vec3f SpawnPos; private: + Vec3f _pos; + static size_t _count; s32 _idx; - s32 _state; - s32 _timer; - s32 _status; bool _toggle; SplineData *spline; diff --git a/src/engine/objects/Thwomp.cpp b/src/engine/objects/Thwomp.cpp index 87d670cfd..afa12b03b 100644 --- a/src/engine/objects/Thwomp.cpp +++ b/src/engine/objects/Thwomp.cpp @@ -44,16 +44,19 @@ f32 D_800E594C[][2] = { s16 D_800E597C[] = { 0x0000, 0x0000, 0x4000, 0x8000, 0x8000, 0xc000 }; -OThwomp::OThwomp(s32 i, s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) { - if (i >= 32) { - printf("MAX THWOMPS REACHED (32), skipping\n"); - return; - } - _idx = i; +size_t OThwomp::_count = 0; + +OThwomp::OThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) { + _idx = _count; _faceDirection = direction; _boundingBoxSize = boundingBoxSize; State = (States)behaviour; - s32 objectId = indexObjectList1[i]; + + if (_idx >= 32) { + printf("MAX THWOMPS REACHED (32), skipping\n"); + return; + } + s32 objectId = indexObjectList1[_idx]; init_object(objectId, 0); gObjectList[objectId].origin_pos[0] = x * xOrientation; gObjectList[objectId].origin_pos[2] = z; @@ -66,9 +69,11 @@ OThwomp::OThwomp(s32 i, s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s } gObjectList[objectId].sizeScaling = scale; + + _count++; } -void OThwomp::Tick() { // func_80081210 +void OThwomp::Tick60fps() { // func_80081210 Player* player; s32 objectIndex; s32 var_s2_3; @@ -80,6 +85,13 @@ void OThwomp::Tick() { // func_80081210 OThwomp::func_8007F8D8(); + // Tick lights only one time. This gets applied to every thwomp. + // Running this more than once per frame will result in the lights moving at a high rate of speed. + if (_idx == 0) { + D_80165834[0] += 0x100; + D_80165834[1] += 0x200; + } + objectIndex = indexObjectList1[_idx]; if (gObjectList[objectIndex].state != 0) { switch (State) { diff --git a/src/engine/objects/Thwomp.h b/src/engine/objects/Thwomp.h index f64318e4d..22c674bb5 100644 --- a/src/engine/objects/Thwomp.h +++ b/src/engine/objects/Thwomp.h @@ -3,6 +3,9 @@ #include #include +#include "engine/World.h" +#include "engine/objects/Object.h" + extern "C" { #include "macros.h" #include "main.h" @@ -27,7 +30,7 @@ extern "C" { * @arg primAlpha unknown * @arg boundingBoxSize optional. The size of the bounding box for the thwomp. Default value is 12 */ -class OThwomp { +class OThwomp : public OObject { private: enum States : uint16_t { DISABLED, @@ -42,12 +45,20 @@ private: public: States State = States::DISABLED; - explicit OThwomp(s32 i, s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize); + explicit OThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize = 7); - void Tick(); + ~OThwomp() { + _count--; + } + + static size_t GetCount() { + return _count; + } + + virtual void Tick60fps() override; + virtual void Draw(s32 cameraId) override; void SetVisibility(s32 objectIndex); void func_80080B28(s32 objectIndex, s32 playerId); - void Draw(s32 playerId); void DrawModel(s32); void TranslateThwompLights(); void ThwompLights(s32 objectIndex); @@ -100,6 +111,7 @@ public: void func_8007E63C(s32 objectIndex); private: + static size_t _count; s32 _idx; s16 _faceDirection; //! @todo Write this better. This effects the squish size and the bounding box size. diff --git a/src/engine/vehicles/Boat.cpp b/src/engine/vehicles/Boat.cpp index c1d7803bb..6a3c2beb1 100644 --- a/src/engine/vehicles/Boat.cpp +++ b/src/engine/vehicles/Boat.cpp @@ -14,10 +14,12 @@ extern "C" { extern s8 gPlayerCount; } -ABoat::ABoat(size_t idx, f32 speed, u32 waypoint) { +size_t ABoat::_count = 0; + +ABoat::ABoat(f32 speed, u32 waypoint) { Path2D* temp_a2; u16 waypointOffset; - Index = idx; + Index = _count; Speed = speed; // Set to the default value @@ -36,6 +38,8 @@ ABoat::ABoat(size_t idx, f32 speed, u32 waypoint) { Velocity[0] = 0.0f; Velocity[1] = 0.0f; Velocity[2] = 0.0f; + + _count++; } void ABoat::Spawn() { diff --git a/src/engine/vehicles/Boat.h b/src/engine/vehicles/Boat.h index 988f498ab..4a1e2d124 100644 --- a/src/engine/vehicles/Boat.h +++ b/src/engine/vehicles/Boat.h @@ -30,7 +30,15 @@ class ABoat : public AVehicle { int16_t AnotherSmokeTimer = 0; int16_t SmokeTimer = 0; - explicit ABoat(size_t idx, f32 speed, uint32_t waypoint); + explicit ABoat(f32 speed, uint32_t waypoint); + + ~ABoat() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Spawn() override; virtual void BeginPlay() override; @@ -38,5 +46,7 @@ class ABoat : public AVehicle { virtual void Draw(s32 playerId) override; virtual void Collision(s32 playerId, Player* player) override; virtual s32 AddSmoke(size_t, Vec3f, f32); +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/engine/vehicles/Bus.cpp b/src/engine/vehicles/Bus.cpp index 36bb576c6..c8b81b4c5 100644 --- a/src/engine/vehicles/Bus.cpp +++ b/src/engine/vehicles/Bus.cpp @@ -16,12 +16,14 @@ extern "C" { extern s8 gPlayerCount; } -ABus::ABus(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { +size_t ABus::_count = 0; + +ABus::ABus(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; - Index = idx; + Index = _count; waypointOffset = waypoint; temp_v0 = &path[waypointOffset]; @@ -54,6 +56,8 @@ ABus::ABus(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t way func_8000D940(Position, (s16*) &WaypointIndex, Speed, SomeMultiplierTheSequel, 0); } D_801631C8 = 10; + + _count++; } void ABus::Spawn() { diff --git a/src/engine/vehicles/Bus.h b/src/engine/vehicles/Bus.h index ff75d5aff..a7ba3d3e5 100644 --- a/src/engine/vehicles/Bus.h +++ b/src/engine/vehicles/Bus.h @@ -33,11 +33,22 @@ class ABus : public AVehicle { f32 SomeArg4 = 12.5f; u32 SoundBits = SOUND_ARG_LOAD(0x51, 0x01, 0x80, 0x03); - explicit ABus(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + explicit ABus(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + + ~ABus() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Spawn() override; virtual void BeginPlay() override; virtual void Tick() override; virtual void Draw(s32 playerId) override; virtual void Collision(s32 playerId, Player* player) override; + +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/engine/vehicles/Car.cpp b/src/engine/vehicles/Car.cpp index 604fe5f2f..8f8d24d1f 100644 --- a/src/engine/vehicles/Car.cpp +++ b/src/engine/vehicles/Car.cpp @@ -16,12 +16,14 @@ extern "C" { extern s8 gPlayerCount; } -ACar::ACar(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { +size_t ACar::_count = 0; + +ACar::ACar(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; - Index = idx; + Index = _count; waypointOffset = waypoint; temp_v0 = &path[waypointOffset]; @@ -54,6 +56,8 @@ ACar::ACar(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t way func_8000D940(Position, (s16*) &WaypointIndex, Speed, SomeMultiplierTheSequel, 0); } D_801631C8 = 10; + + _count++; } void ACar::Spawn() { diff --git a/src/engine/vehicles/Car.h b/src/engine/vehicles/Car.h index 8ac7421aa..6613e4c56 100644 --- a/src/engine/vehicles/Car.h +++ b/src/engine/vehicles/Car.h @@ -16,7 +16,15 @@ class AVehicle; // Forward declare class ACar : public AVehicle { public: - explicit ACar(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + explicit ACar(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + + ~ACar() { + _count--; + } + + static size_t GetCount() { + return _count; + } const char* Type; size_t Index; @@ -40,4 +48,6 @@ class ACar : public AVehicle { virtual void Tick() override; virtual void Draw(s32 playerId) override; virtual void Collision(s32 playerId, Player* player) override; +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/engine/vehicles/TankerTruck.cpp b/src/engine/vehicles/TankerTruck.cpp index 8acd7984c..2c32d5bd6 100644 --- a/src/engine/vehicles/TankerTruck.cpp +++ b/src/engine/vehicles/TankerTruck.cpp @@ -16,12 +16,14 @@ extern "C" { extern s8 gPlayerCount; } -ATankerTruck::ATankerTruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { +size_t ATankerTruck::_count = 0; + +ATankerTruck::ATankerTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; - Index = idx; + Index = _count; waypointOffset = waypoint; temp_v0 = &path[waypointOffset]; @@ -54,6 +56,8 @@ ATankerTruck::ATankerTruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* pa func_8000D940(Position, (s16*) &WaypointIndex, Speed, SomeMultiplierTheSequel, 0); } D_801631C8 = 10; + + _count++; } void ATankerTruck::Spawn() { diff --git a/src/engine/vehicles/TankerTruck.h b/src/engine/vehicles/TankerTruck.h index 961d5a0fb..fdf838d99 100644 --- a/src/engine/vehicles/TankerTruck.h +++ b/src/engine/vehicles/TankerTruck.h @@ -33,11 +33,22 @@ class ATankerTruck : public AVehicle { f32 SomeArg4 = 12.5f; u32 SoundBits = SOUND_ARG_LOAD(0x51, 0x01, 0x80, 0x03); - explicit ATankerTruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + explicit ATankerTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + + ~ATankerTruck() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Spawn() override; virtual void BeginPlay() override; virtual void Tick() override; virtual void Draw(s32 playerId) override; virtual void Collision(s32 playerId, Player* player) override; + +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/engine/vehicles/Train.cpp b/src/engine/vehicles/Train.cpp index c34ac1cf3..0e9af21ed 100644 --- a/src/engine/vehicles/Train.cpp +++ b/src/engine/vehicles/Train.cpp @@ -22,12 +22,14 @@ extern "C" { // #include "common_structs.h" } -ATrain::ATrain(size_t idx, ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint) { +size_t ATrain::_count = 0; + +ATrain::ATrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint) { u16 waypointOffset; TrainCarStuff* ptr1; Path2D* pos; - Index = idx; + Index = _count; Speed = speed; // Set to the default value @@ -73,6 +75,8 @@ ATrain::ATrain(size_t idx, ATrain::TenderStatus tender, size_t numCarriages, f32 NumCars = NUM_TENDERS + numCarriages; AnotherSmokeTimer = 0; + + _count++; } void ATrain::Spawn() { diff --git a/src/engine/vehicles/Train.h b/src/engine/vehicles/Train.h index 0964c8cf9..e2c1d89f4 100644 --- a/src/engine/vehicles/Train.h +++ b/src/engine/vehicles/Train.h @@ -11,6 +11,10 @@ extern "C" { class AVehicle; // Forward declare +/** + * Note that you can only remove the tender if there are no carriages + * @arg waypoint initial waypoint to spawn at. + */ class ATrain : public AVehicle { public: @@ -35,7 +39,15 @@ class ATrain : public AVehicle { int16_t AnotherSmokeTimer = 0; int16_t SmokeTimer = 0; - explicit ATrain(size_t idx, ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint); + explicit ATrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint); + + ~ATrain() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Spawn() override; virtual void BeginPlay() override; @@ -44,4 +56,7 @@ class ATrain : public AVehicle { virtual void Collision(s32 playerId, Player* player) override; s32 AddSmoke(s32 trainIndex, Vec3f pos, f32 velocity); void SyncComponents(TrainCarStuff* trainCar, s16 orientationY); + +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/engine/vehicles/Truck.cpp b/src/engine/vehicles/Truck.cpp index 139edc644..c865fed70 100644 --- a/src/engine/vehicles/Truck.cpp +++ b/src/engine/vehicles/Truck.cpp @@ -16,12 +16,14 @@ extern "C" { extern s8 gPlayerCount; } -ATruck::ATruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { +size_t ATruck::_count = 0; + +ATruck::ATruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; - Index = idx; + Index = _count; waypointOffset = waypoint; temp_v0 = &path[waypointOffset]; @@ -54,6 +56,8 @@ ATruck::ATruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t func_8000D940(Position, (s16*) &WaypointIndex, Speed, SomeMultiplierTheSequel, 0); } D_801631C8 = 10; + + _count++; } void ATruck::Spawn() { diff --git a/src/engine/vehicles/Truck.h b/src/engine/vehicles/Truck.h index 8781feaad..f9f65b2fc 100644 --- a/src/engine/vehicles/Truck.h +++ b/src/engine/vehicles/Truck.h @@ -33,11 +33,22 @@ class ATruck : public AVehicle { f32 SomeArg4 = 12.5f; u32 SoundBits = SOUND_ARG_LOAD(0x51, 0x01, 0x80, 0x03); - explicit ATruck(size_t idx, f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + explicit ATruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint); + + ~ATruck() { + _count--; + } + + static size_t GetCount() { + return _count; + } virtual void Spawn() override; virtual void BeginPlay() override; virtual void Tick() override; virtual void Draw(s32 playerId) override; virtual void Collision(s32 playerId, Player* player) override; + +private: + static size_t _count; }; \ No newline at end of file diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 90869508e..70634713a 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -301,8 +301,6 @@ extern "C" { gWorldInstance.ClearVehicles(); gWorldInstance.Crossings.clear(); gWorldInstance.BombKarts.clear(); - gWorldInstance.Thwomps.clear(); - gWorldInstance.Penguins.clear(); } void CourseManager_CrossingTrigger() { @@ -570,61 +568,6 @@ extern "C" { gWorldInstance.Lakitus[playerId]->Activate(OLakitu::LakituType::REVERSE); } - extern Vec3su D_80165834; - void CourseManager_TickThwomps() { - // TickLights - if (gWorldInstance.Thwomps.size()) { - D_80165834[0] += 0x100; - D_80165834[1] += 0x200; - } - - for (auto& thwomp : gWorldInstance.Thwomps) { - if (thwomp) { - thwomp->Tick(); - } - } - } - - void CourseManager_DrawThwomps(s32 cameraId) { - for (auto& thwomp : gWorldInstance.Thwomps) { - if (thwomp) { - thwomp->Draw(cameraId); - } - } - } - - void CourseManager_TickPenguins(void) { - for (auto& penguin : gWorldInstance.Penguins) { - if (penguin) { - penguin->Tick(); - } - } - } - - void CourseManager_DrawSeagulls(s32 cameraId) { - for (auto& seagull : gWorldInstance.Seagulls) { - if (seagull) { - // seagull->Draw(cameraId); - } - } - } - - void CourseManager_TickSeagulls(void) { - for (auto& seagull : gWorldInstance.Seagulls) { - if (seagull) { - //seagull->Tick(); - } - } - } - - void CourseManager_DrawPenguins(s32 cameraId) { - for (auto& penguin : gWorldInstance.Penguins) { - if (penguin) { - penguin->Draw(cameraId); - } - } - } - size_t GetCupCursorPosition() { return gWorldInstance.CurrentCup->CursorPosition; } diff --git a/src/port/Game.h b/src/port/Game.h index 76ae4ac2d..ba4e1d359 100644 --- a/src/port/Game.h +++ b/src/port/Game.h @@ -109,18 +109,6 @@ void CourseManager_ClearVehicles(void); void CourseManager_DrawVehicles(s32 playerId); -void CourseManager_DrawThwomps(s32 cameraId); - -void CourseManager_TickThwomps(); - -void CourseManager_DrawSeagulls(s32 cameraId); - -void CourseManager_TickSeagulls(); - -void CourseManager_DrawPenguins(s32 cameraId); - -void CourseManager_TickPenguins(); - void CourseManager_CrossingTrigger(); void CourseManager_VehiclesCollision(s32 playerId, Player* player); From 57afb90c3901b4c5dc586f1be3f6604c52c423d6 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 29 Dec 2024 23:58:52 -0700 Subject: [PATCH 7/7] Add todo --- src/engine/objects/Seagull.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/objects/Seagull.h b/src/engine/objects/Seagull.h index d575e3721..c6898dcc2 100644 --- a/src/engine/objects/Seagull.h +++ b/src/engine/objects/Seagull.h @@ -16,7 +16,7 @@ extern "C" { #include "camera.h" } - +//! @todo unk_0D5 needs to be a struct variable probably. What does it do? Behaviour? class OSeagull : public OObject { public: explicit OSeagull(Vec3f pos);