summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMegaMech <7255464+MegaMech@users.noreply.github.com>2024-12-04 11:18:57 -0700
committerMegaMech <7255464+MegaMech@users.noreply.github.com>2024-12-04 11:18:57 -0700
commitb0d7f98ff4a3ad3072b7119c63f5c1472b496d8a (patch)
treea3a086af5a318faf9aaf1f7f967686850b2eadce /src
parent635556027af81c252cbf4a5cf8ea4b0b2f2e1581 (diff)
Reimplement penguins
Diffstat (limited to 'src')
-rw-r--r--src/code_80057C60.c2
-rw-r--r--src/code_80057C60_var.c2
-rw-r--r--src/engine/World.cpp8
-rw-r--r--src/engine/World.h4
-rw-r--r--src/engine/courses/SherbetLand.cpp66
-rw-r--r--src/engine/courses/YoshiValley.cpp6
-rw-r--r--src/engine/vehicles/OPenguin.cpp383
-rw-r--r--src/engine/vehicles/OPenguin.h68
-rw-r--r--src/port/Game.cpp18
-rw-r--r--src/port/Game.h4
-rw-r--r--src/render_objects.c9
11 files changed, 556 insertions, 14 deletions
diff --git a/src/code_80057C60.c b/src/code_80057C60.c
index bc0000bd6..96cf3e171 100644
--- a/src/code_80057C60.c
+++ b/src/code_80057C60.c
@@ -703,6 +703,7 @@ void render_object_for_player(s32 cameraId) {
CourseManager_RenderCourseObjects(cameraId);
CourseManager_TrainSmokeDraw(cameraId);
CourseManager_DrawThwomps(cameraId);
+ CourseManager_DrawPenguins(cameraId);
// switch (gCurrentCourseId) {
// case COURSE_MARIO_RACEWAY:
@@ -1580,6 +1581,7 @@ void update_object(void) {
CourseManager_UpdateCourseObjects();
CourseManager_TrainSmokeTick();
+ CourseManager_TickPenguins();
// switch (gCurrentCourseId) {
// case COURSE_MARIO_RACEWAY:
diff --git a/src/code_80057C60_var.c b/src/code_80057C60_var.c
index b06899cd3..fda4d187c 100644
--- a/src/code_80057C60_var.c
+++ b/src/code_80057C60_var.c
@@ -17,7 +17,7 @@ f32 D_8018D00C;
s16 D_8018D010;
UNUSED s32 D_8018D014;
s16 D_8018D018;
-f32 xOrientation;
+f32 xOrientation; // For mirror/extra mode
s16 D_8018D020;
f32 D_8018D028[8];
s16 D_8018D048;
diff --git a/src/engine/World.cpp b/src/engine/World.cpp
index aae7f3568..b8371b2c8 100644
--- a/src/engine/World.cpp
+++ b/src/engine/World.cpp
@@ -47,6 +47,7 @@ static size_t tankerTrucks;
static size_t cars;
static size_t boats;
static size_t thwomps;
+static size_t penguins;
/**
* Note that you can only remove the tender if there are no carriages
@@ -104,6 +105,13 @@ void World::AddThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16
gNumActiveThwomps = thwomps;
}
+std::shared_ptr<OPenguin> World::AddPenguin(Vec3f pos, u16 direction, OPenguin::PenguinType type, OPenguin::Behaviour behaviour) {
+ auto penguin = std::make_shared<OPenguin>(penguins, pos, direction, type, behaviour);
+ Penguins.push_back(penguin);
+ penguins++;
+ return penguin;
+}
+
u32 World::GetCupIndex() {
return this->CupIndex;
}
diff --git a/src/engine/World.h b/src/engine/World.h
index a5d9770a5..c339801d9 100644
--- a/src/engine/World.h
+++ b/src/engine/World.h
@@ -10,6 +10,7 @@
#include "vehicles/Train.h"
#include "TrainCrossing.h"
#include "vehicles/OThwomp.h"
+#include "vehicles/OPenguin.h"
#include <memory>
#include "Actor.h"
@@ -145,6 +146,9 @@ public:
std::vector<std::unique_ptr<OThwomp>> Thwomps;
void AddThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize = 7);
+ std::vector<std::shared_ptr<OPenguin>> Penguins;
+ std::shared_ptr<OPenguin> AddPenguin(Vec3f pos, u16 direction, OPenguin::PenguinType type, OPenguin::Behaviour behaviour);
+
TrainCrossing* AddCrossing(Vec3f position, u32 waypointMin, u32 waypointMax, f32 approachRadius, f32 exitRadius);
std::vector<std::shared_ptr<TrainCrossing>> Crossings;
diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp
index 19bfa573e..d483d966c 100644
--- a/src/engine/courses/SherbetLand.cpp
+++ b/src/engine/courses/SherbetLand.cpp
@@ -150,23 +150,81 @@ void SherbetLand::MinimapSettings() {
}
void SherbetLand::InitCourseObjects() {
- for (size_t i = 0; i < NUM_PENGUINS; i++) {
- init_object(indexObjectList1[i], 0);
+ //! @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() {
if (gGamestate != CREDITS_SEQUENCE) {
func_800842C8();
}
- update_penguins();
}
void SherbetLand::RenderCourseObjects(s32 cameraId) {
if (gGamestate != CREDITS_SEQUENCE) {
func_80052E30(cameraId);
}
- render_object_train_penguins(cameraId);
}
void SherbetLand::SomeSounds() {
diff --git a/src/engine/courses/YoshiValley.cpp b/src/engine/courses/YoshiValley.cpp
index 3c0a195f4..474d3f3d2 100644
--- a/src/engine/courses/YoshiValley.cpp
+++ b/src/engine/courses/YoshiValley.cpp
@@ -141,6 +141,12 @@ 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);
}
diff --git a/src/engine/vehicles/OPenguin.cpp b/src/engine/vehicles/OPenguin.cpp
new file mode 100644
index 000000000..e8d97116a
--- /dev/null
+++ b/src/engine/vehicles/OPenguin.cpp
@@ -0,0 +1,383 @@
+#include <libultraship.h>
+#include <libultra/gbi.h>
+#include "engine/vehicles/OPenguin.h"
+#include <vector>
+
+#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"
+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;
+ _type = type;
+ _bhv = behaviour;
+
+ s32 objectIndex = indexObjectList1[i];
+ init_object(objectIndex, 0);
+
+ Object *object = &gObjectList[objectIndex];
+ object->origin_pos[0] = pos[0] * xOrientation;
+ object->origin_pos[1] = pos[1];
+ object->origin_pos[2] = pos[2];
+ object->unk_0C6 = direction;
+
+ switch(type) {
+ case PenguinType::CHICK:
+ object->surfaceHeight = 5.0f;
+ object->sizeScaling = 0.04f;
+ object->boundingBoxSize = 4;
+ break;
+ case PenguinType::ADULT:
+ object->surfaceHeight = -80.0f;
+ object->sizeScaling = 0.08f;
+ object->boundingBoxSize = 4;
+ break;
+ case PenguinType::CREDITS:
+ object->surfaceHeight = -80.0f;
+ object->sizeScaling = 0.08f;
+ object->sizeScaling = 0.15f;
+ break;
+ case PenguinType::EMPEROR:
+ object->sizeScaling = 0.2f;
+ object->boundingBoxSize = 0x000C;
+ break;
+ }
+
+}
+
+void OPenguin::Tick(void) {
+ s32 objectIndex;
+
+ objectIndex = indexObjectList1[_idx];
+ if (gObjectList[objectIndex].state != 0) {
+ if (_type == PenguinType::EMPEROR) {
+ OPenguin::EmperorPenguin(objectIndex);
+ } else {
+ OPenguin::OtherPenguin(objectIndex);
+ }
+
+ OPenguin::Behaviours(objectIndex, _idx);
+ }
+ if (func_80072320(objectIndex, 1) != 0) {
+ func_80089820(objectIndex, 1.75f, 1.5f, 0x1900A046U);
+ } else if (func_80072320(objectIndex, 8) != 0) {
+ func_80089820(objectIndex, 1.3f, 1.0f, 0x1900A046U);
+ } else {
+ func_80089820(objectIndex, 1.5f, 1.25f, 0x1900A046U);
+ }
+ if ((is_obj_flag_status_active(objectIndex, 0x02000000) != 0) &&
+ (func_80072354(objectIndex, 0x00000020) != 0)) {
+ func_800722A4(objectIndex, 0x00000060);
+ set_object_flag_status_false(objectIndex, 0x02000000);
+ }
+}
+
+void OPenguin::Draw(s32 cameraId) {
+ s32 objectIndex;
+ s32 temp_s1;
+ s32 drawDistance;
+ u16 var_s1;
+ u32 var_s3;
+
+ if (gPlayerCountSelection1 == 1) {
+ var_s3 = 0x0003D090;
+ } else if (gPlayerCountSelection1 == 2) {
+ var_s3 = 0x00027100;
+ } else {
+ var_s3 = 0x00015F90;
+ }
+
+ objectIndex = indexObjectList1[_idx];
+ if (gObjectList[objectIndex].state >= 2) {
+ if (gPlayerCountSelection1 == 1) {
+ var_s1 = 0x4000;
+ if (_idx == 0) {
+ drawDistance = 0x000005DC;
+ } else if (func_80072320(objectIndex, 8) != 0) {
+ drawDistance = 0x00000320;
+ } else {
+ drawDistance = 0x000003E8;
+ }
+ } else {
+ if (func_80072320(objectIndex, 8) != 0) {
+ drawDistance = 0x000001F4;
+ var_s1 = 0x4000;
+ } else {
+ drawDistance = 0x00000258;
+ var_s1 = 0x5555;
+ }
+ }
+ temp_s1 = func_8008A364(objectIndex, cameraId, var_s1, drawDistance);
+ if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) {
+ func_800557B4(objectIndex, (u32) temp_s1, var_s3);
+ }
+ }
+}
+
+void OPenguin::Behaviours(s32 objectIndex, s32 arg1) {
+ Object* object;
+
+ object = &gObjectList[objectIndex];
+ switch (_bhv) {
+ case 1: // emperor
+ func_80085080(objectIndex);
+ break;
+ case 2:
+ func_8008502C(objectIndex, arg1);
+ break;
+ case 3:
+ func_80084D2C(objectIndex, 0);
+ break;
+ case 4:
+ func_80084D2C(objectIndex, 1);
+ break;
+ case 5:
+ func_80084D2C(objectIndex, 2);
+ break;
+ case 6:
+ func_80084D2C(objectIndex, 3);
+ break;
+ }
+ if (func_80072320(objectIndex, 0x00000020) != 0) {
+ if (func_80072320(objectIndex, 0x00000040) != 0) {
+ func_800722CC(objectIndex, 0x00000040);
+ object->unk_084[6] = 0;
+ object->unk_084[7] = 0x0096;
+ }
+ if (object->unk_084[7] == 0) {
+ func_800722CC(objectIndex, 0x00000020);
+ } else {
+ object->unk_084[7]--;
+ object->orientation[0] = object->direction_angle[0];
+ object->orientation[1] += 0x2000;
+ object->orientation[2] = object->direction_angle[2];
+ }
+ } else {
+ object->orientation[0] = object->direction_angle[0];
+ object->orientation[1] = object->direction_angle[1];
+ object->orientation[2] = object->direction_angle[2];
+ }
+}
+
+void OPenguin::EmperorPenguin(s32 objectIndex) {
+ switch (gObjectList[objectIndex].state) {
+ case 0:
+ break;
+ case 1:
+ OPenguin::InitEmperorPenguin(objectIndex);
+ break;
+ case 2:
+ func_80072E54(objectIndex, 0, gObjectList[objectIndex].type, 1, 0, -1);
+ break;
+ }
+}
+
+void OPenguin::InitEmperorPenguin(s32 objectIndex) {
+ Object* object;
+
+ object = &gObjectList[objectIndex];
+ object->unk_0D8 = 0;
+ object->model = (Gfx*) d_course_sherbet_land_unk_data1;
+ object->vertex = (Vtx*) d_course_sherbet_land_unk_data11;
+ //object->sizeScaling = 0.2f;
+ //object->boundingBoxSize = 0x000C;
+ object->unk_09C = 1;
+ set_obj_direction_angle(objectIndex, 0U, 0U, 0U);
+ object->unk_0DD = 1;
+ func_80086EF0(objectIndex);
+ object->spline = D_800E672C[0];
+ set_object_flag_status_true(objectIndex, 0x04000800);
+ object->type = get_animation_length(d_course_sherbet_land_unk_data11, 0);
+ object_next_state(objectIndex);
+}
+
+void OPenguin::OtherPenguin(s32 objectIndex) {
+ Object* object;
+
+ object = &gObjectList[objectIndex];
+ switch (object->state) {
+ case 0:
+ break;
+ case 1:
+ OPenguin::InitOtherPenguin(objectIndex);
+ break;
+ case 2:
+ func_80072E54(objectIndex, 0, (s32) object->type, (s32) object->unk_09C, 0, -1);
+ if (func_80072354(objectIndex, 0x00000020) != 0) {
+ if (object->unk_084[6] == 0) {
+ object->unk_084[6] = random_int(0x005AU) + 0x5A;
+ func_800722A4(objectIndex, 0x00000080);
+ } else {
+ object->unk_084[6]--;
+ }
+ }
+ break;
+ case 3:
+ func_80072E54(objectIndex, 0, object->type, 1, 0, 0);
+ break;
+ case 4:
+ func_800722CC(objectIndex, 2);
+ object_next_state(objectIndex);
+ break;
+ }
+ if (func_80072320(objectIndex, 0x00000020) != 0) {
+ if (object->unk_084[6] == 0) {
+ func_800722A4(objectIndex, 0x00000080);
+ object->unk_084[6] = 0x0010;
+ } else {
+ object->unk_084[6]--;
+ }
+ }
+ if (func_80072320(objectIndex, 0x00000080) != 0) {
+ func_800722CC(objectIndex, 0x00000080);
+ if (func_80072320(objectIndex, 0x00000010) != 0) {
+ func_800C98B8(object->pos, object->velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x70, 0x49));
+ } else {
+ func_800C98B8(object->pos, object->velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x70, 0x17));
+ }
+ }
+}
+
+void OPenguin::InitOtherPenguin(s32 objectIndex) {
+ Object* object;
+
+ object = &gObjectList[objectIndex];
+ object->unk_0D8 = 0;
+ object->model = (Gfx*) d_course_sherbet_land_unk_data1;
+ object->vertex = (Vtx*) d_course_sherbet_land_unk_data11;
+ //object->boundingBoxSize = 4;
+ object->unk_09C = 2;
+ object->unk_04C = random_int(0x012CU);
+ set_object_flag_status_true(objectIndex, 0x04000220);
+
+ switch(_bhv) {
+ case Behaviour::CIRCLE:
+ object->unk_01C[1] = Diameter;
+ object->unk_0C4 = (_idx << 0xF) & 0xFFFF;
+ //object->unk_0DD = 2;
+ func_800722A4(objectIndex, 8);
+ break;
+ case Behaviour::SLIDE3:
+ case Behaviour::SLIDE4:
+ case Behaviour::SLIDE6:
+ case Behaviour::STRUT:
+
+ if (gIsMirrorMode) {
+ object->unk_0C6 = MirrorModeAngleOffset;
+ }
+
+ set_obj_direction_angle(objectIndex, 0U, object->unk_0C6 + 0x8000, 0U);
+ func_800722A4(objectIndex, 20);
+ break;
+ }
+
+ if ((_idx > 0) && (_idx < 9)) {
+ if ((_idx == 1) || (_idx == 2)) {
+ //object->unk_0C6 = 0x0150;
+ //object->unk_01C[1] = 100.0f;
+ } else if ((_idx == 3) || (_idx == 4)) {
+ //object->unk_0C6 = 0x0100;
+ //object->unk_01C[1] = 80.0f;
+ } else if ((_idx == 5) || (_idx == 6)) {
+ //object->unk_0C6 = 0xFF00;
+ //object->unk_01C[1] = 80.0f;
+ } else if ((_idx == 7) || (_idx == 8)) {
+ //object->unk_0C6 = 0x0150;
+ //object->unk_01C[1] = 80.0f;
+ }
+ //object->unk_0C4 = (_idx << 0xF) & 0xFFFF;
+ //object->surfaceHeight = -80.0f;
+ //object->sizeScaling = 0.08f;
+ //object->unk_0DD = 2;
+ //func_800722A4(objectIndex, 8);
+ } else if ((_idx > 8) && (_idx < 15)) {
+ switch (_idx) {
+ case 9:
+ if (gGamestate != CREDITS_SEQUENCE) {
+ } else {
+ //object->sizeScaling = 0.15f;
+ }
+ //object->unk_0C6 = 0x9000;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 -= 0x4000;
+ }
+ //object->unk_0DD = 3;
+ break;
+ case 10:
+ //object->unk_0C6 = 0x5000;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 += 0x8000;
+ }
+ //object->unk_0DD = 4;
+ break;
+ case 11:
+ //object->unk_0C6 = 0xC000;
+ //object->unk_0DD = 6;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 += 0x8000;
+ }
+ break;
+ case 12:
+ //object->unk_0C6 = 0x4000;
+ //object->unk_0DD = 6;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 += 0x8000;
+ }
+ break;
+ case 13:
+ // object->unk_0C6 = 0x8000;
+ //object->unk_0DD = 6;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 -= 0x4000;
+ }
+ break;
+ case 14:
+ //object->unk_0C6 = 0x9000;
+ //object->unk_0DD = 6;
+ if (gIsMirrorMode != 0) {
+ //object->unk_0C6 -= 0x4000;
+ }
+ break;
+ default:
+ break;
+ }
+ //set_obj_direction_angle(objectIndex, 0U, object->unk_0C6 + 0x8000, 0U);
+ //object->surfaceHeight = 5.0f;
+ //object->sizeScaling = 0.04f;
+ //func_800722A4(objectIndex, 0x00000014);
+ }
+ func_80086EF0(objectIndex);
+ object->unk_034 = 0.0f;
+ object->type = get_animation_length(d_course_sherbet_land_unk_data11, 0);
+ object_next_state(objectIndex);
+}
diff --git a/src/engine/vehicles/OPenguin.h b/src/engine/vehicles/OPenguin.h
new file mode 100644
index 000000000..007baf551
--- /dev/null
+++ b/src/engine/vehicles/OPenguin.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <libultraship.h>
+#include <vector>
+#include "engine/vehicles/OPenguin.h"
+
+extern "C" {
+#include "macros.h"
+#include "main.h"
+#include "vehicles.h"
+#include "waypoints.h"
+#include "common_structs.h"
+#include "objects.h"
+}
+
+//! @todo Make shadow size bigger if thwomp is scaled up
+//! @todo make adjustable properties for squishSize and boundingBoxSize
+
+ /**
+ * Thwomp GameObject
+ *
+ * The game automatically places the actor on the ground so you do not need to provide a Y coordinate value.
+ *
+ * @arg direction the rotational direction the thwomp is facing.
+ * @arg behaviour the behaviour of the thwomp, uses values 1-6.
+ * @arg primAlpha unknown
+ * @arg boundingBoxSize optional. The size of the bounding box for the thwomp. Default value is 12
+ */
+class OPenguin {
+public:
+ enum PenguinType : uint32_t {
+ CHICK,
+ ADULT,
+ CREDITS,
+ EMPEROR
+ };
+
+ enum Behaviour : uint16_t {
+ DISABLED,
+ STRUT, // Emperor penguin
+ CIRCLE, // Waddle in a circle
+ SLIDE3,
+ SLIDE4,
+ UNK, // unused
+ SLIDE6,
+ };
+
+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);
+
+ void Tick();
+ void Draw(s32 playerId);
+private:
+ void Behaviours(s32 objectIndex, s32 arg1);
+ void EmperorPenguin(s32 objectIndex);
+ void InitEmperorPenguin(s32 objectIndex);
+ void OtherPenguin(s32 objectIndex);
+ void InitOtherPenguin(s32 objectIndex);
+
+ s32 _idx;
+ PenguinType _type;
+ Behaviour _bhv;
+
+
+};
diff --git a/src/port/Game.cpp b/src/port/Game.cpp
index 8a8c0b7cb..445e1b805 100644
--- a/src/port/Game.cpp
+++ b/src/port/Game.cpp
@@ -295,8 +295,10 @@ extern "C" {
void CourseManager_ClearVehicles(void) {
gWorldInstance.ClearVehicles();
+ gWorldInstance.Crossings.clear();
gWorldInstance.BombKarts.clear();
gWorldInstance.Thwomps.clear();
+ gWorldInstance.Penguins.clear();
}
void CourseManager_CrossingTrigger() {
@@ -501,6 +503,22 @@ extern "C" {
}
}
+ void CourseManager_TickPenguins(void) {
+ for (auto& penguin : gWorldInstance.Penguins) {
+ if (penguin) {
+ penguin->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 d2762c08f..c35e933e2 100644
--- a/src/port/Game.h
+++ b/src/port/Game.h
@@ -98,6 +98,10 @@ void CourseManager_DrawThwomps(s32 cameraId);
void CourseManager_TickThwomps();
+void CourseManager_DrawPenguins(s32 cameraId);
+
+void CourseManager_TickPenguins();
+
void CourseManager_CrossingTrigger();
void CourseManager_VehiclesCollision(s32 playerId, Player* player);
diff --git a/src/render_objects.c b/src/render_objects.c
index 7a34c47b5..48dc1b536 100644
--- a/src/render_objects.c
+++ b/src/render_objects.c
@@ -3637,7 +3637,6 @@ void func_80052D70(s32 playerId) {
void func_80052E30(UNUSED s32 arg0) {
s32 var_s0;
- // Lights1 D_800E4620l = *(Lights1 *) LOAD_ASSET(D_800E4620);
D_800E4620.l[0].l.dir[0] = D_80165840[0];
D_800E4620.l[0].l.dir[1] = D_80165840[1];
D_800E4620.l[0].l.dir[2] = D_80165840[2];
@@ -3760,20 +3759,12 @@ void render_lakitu(s32 cameraId) {
void translate_thwomp_lights(UNUSED s32 arg0) {
func_800419F8();
- // Lights1 *D_800E4638l = (Lights1 *) LOAD_ASSET(D_800E4638);
D_800E4638.l[0].l.dir[0] = D_80165840[0];
D_800E4638.l[0].l.dir[1] = D_80165840[1];
D_800E4638.l[0].l.dir[2] = D_80165840[2];
}
void thwomp_lights(s32 objectIndex) {
-
- // Lights1 *D_800E4638l = (Lights1 *) LOAD_ASSET(D_800E4638);
- // Lights1 *D_800E4650l = (Lights1 *) LOAD_ASSET(D_800E4650);
- // Lights1 *D_800E4668l = (Lights1 *) LOAD_ASSET(D_800E4668);
- // Lights1 *D_800E4680l = (Lights1 *) LOAD_ASSET(D_800E4680);
- // Lights1 *D_800E4698l = (Lights1 *) LOAD_ASSET(D_800E4698);
-
// Why these don't just use `gSPSetLights1` calls...
switch (gObjectList[objectIndex].type) { // hmm very strange 80165C18
case 0: