From 9c4b35206a2c697acc7345e91587c52a09240eb9 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sat, 28 Dec 2024 20:30:18 -0700 Subject: [PATCH] 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);