summaryrefslogtreecommitdiff
path: root/src/engine/courses/Course.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/courses/Course.cpp')
-rw-r--r--src/engine/courses/Course.cpp178
1 files changed, 162 insertions, 16 deletions
diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp
index 3e5c0b2ab..bbc9455fe 100644
--- a/src/engine/courses/Course.cpp
+++ b/src/engine/courses/Course.cpp
@@ -3,6 +3,9 @@
#include "Course.h"
#include "MarioRaceway.h"
#include "ChocoMountain.h"
+#include "port/Game.h"
+#include "port/resource/type/TrackWaypoint.h"
+#include "port/resource/type/TrackSections.h"
extern "C" {
#include "main.h"
@@ -18,20 +21,36 @@ extern "C" {
#include "staff_ghosts.h"
#include "code_800029B0.h"
#include "render_courses.h"
+#include "collision.h"
+#include "actors.h"
extern StaffGhost* d_mario_raceway_staff_ghost;
}
Course::Course() {
// Props.Name = "Course Name";
// Props.DebugName = "CName";
- // Props.CourseLength = "567m";
+ Props.SetText(Props.CourseLength, "100m", sizeof(Props.CourseLength));
// Props.Cup = FLOWER_CUP;
// Props.CupIndex = 3;
+ Id = "";
+ Props.Minimap.Texture = gTextureCourseOutlineMarioRaceway;
+ Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture);
+ Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture);
+ Props.Minimap.Pos[0].X = 257;
+ Props.Minimap.Pos[0].Y = 170;
+ Props.Minimap.PlayerX = 0;
+ Props.Minimap.PlayerY = 0;
+ Props.Minimap.PlayerScaleFactor = 0.22f;
+ Props.Minimap.FinishlineX = 0;
+ Props.Minimap.FinishlineY = 0;
+ Props.Minimap.Colour = {255, 255, 255};
+ Props.WaterLevel = -10.0f;
+
Props.LakituTowType = (s32) OLakitu::LakituTowType::NORMAL;
Props.AIBehaviour = D_0D008F28;
Props.AIMaximumSeparation = 50.0f;
Props.AIMinimumSeparation = 0.3f;
- Props.SomePtr = D_800DCB34;
+ Props.AIDistance = gMarioRacewayAIDistances;
Props.AISteeringSensitivity = 48;
Props.NearPersp = 3.0f;
@@ -71,11 +90,10 @@ Course::Course() {
Props.Clouds = NULL;
Props.CloudList = NULL;
- Props.MinimapFinishlineX = 0;
- Props.MinimapFinishlineY = 0;
Props.Sequence = MusicSeq::MUSIC_SEQ_UNKNOWN;
}
+// Load custom track from code
void Course::Load(Vtx* vtx, Gfx* gfx) {
gSegmentTable[4] = reinterpret_cast<uintptr_t>(&vtx[0]);
gSegmentTable[7] = reinterpret_cast<uintptr_t>(&gfx[0]);
@@ -83,8 +101,60 @@ void Course::Load(Vtx* vtx, Gfx* gfx) {
Course::Init();
}
+void Course::LoadO2R(std::string trackPath) {
+ if (!trackPath.empty()) {
+ TrackSectionsPtr = (trackPath + "/data_track_sections");
+
+ std::string path_file = (trackPath + "/data_paths").c_str();
+
+ auto res = std::dynamic_pointer_cast<MK64::Paths>(ResourceLoad(path_file.c_str()));
+
+ if (res != nullptr) {
+ auto& paths = res->PathList;
+
+ size_t i = 0;
+ for (auto& path : paths) {
+ if (i == 0) {
+ Props.PathTable[0] = (TrackWaypoint*)path.data();
+ Props.PathTable[1] = NULL;
+ Props.PathTable[2] = NULL;
+ Props.PathTable[3] = NULL;
+ Props.PathTable2[0] = (TrackWaypoint*)path.data();
+ Props.PathTable2[1] = NULL;
+ Props.PathTable2[2] = NULL;
+ Props.PathTable2[3] = NULL;
+ }
+
+ i += 1;
+ }
+ }
+
+ } else {
+ printf("Course.cpp: LoadO2R: trackPath str is empty\n");
+ }
+}
+
+// Load stock track
void Course::Load() {
+ // Load from O2R
+ if (!TrackSectionsPtr.empty()) {
+ bIsMod = true;
+ //auto res = std::dynamic_pointer_cast<MK64::TrackSectionsO2RClass>(ResourceLoad(TrackSectionsPtr.c_str()));
+
+ TrackSectionsO2R* sections = (TrackSectionsO2R*) LOAD_ASSET_RAW(TrackSectionsPtr.c_str());
+ size_t size = ResourceGetSizeByName(TrackSectionsPtr.c_str());
+
+ if (sections != nullptr) {
+ Course::Init();
+ ParseCourseSections(sections, size);
+ func_80295C6C();
+ Props.WaterLevel = gCourseMinY - 10.0f;
+ }
+ return;
+ }
+
+ // Stock
size_t vtxSize = (ResourceGetSizeByName(this->vtx) / sizeof(CourseVtx)) * sizeof(Vtx);
size_t texSegSize;
@@ -129,6 +199,53 @@ void Course::Load() {
Course::Init();
}
+// C++ version of parse_course_displaylists()
+void Course::ParseCourseSections(TrackSectionsO2R* sections, size_t size) {
+ for (size_t i = 0; i < (size / sizeof(TrackSectionsO2R)); i++) {
+ if (sections[i].flags & 0x8000) {
+ D_8015F59C = 1;
+ } else {
+ D_8015F59C = 0;
+ }
+ if (sections[i].flags & 0x2000) {
+ D_8015F5A0 = 1;
+ } else {
+ D_8015F5A0 = 0;
+ }
+ if (sections[i].flags & 0x4000) {
+ D_8015F5A4 = 1;
+ } else {
+ D_8015F5A4 = 0;
+ }
+ printf("LOADING DL %s\n", sections[i].addr.c_str());
+ generate_collision_mesh((Gfx*)LOAD_ASSET_RAW(sections[i].addr.c_str()), sections[i].surfaceType, sections[i].sectionId);
+ }
+}
+
+void Course::TestPath() {
+ // DEBUG ONLY TO VISUALIZE PATH
+ return;
+ s16 x;
+ s16 y;
+ s16 z;
+ Vec3s rot = {0, 0, 0};
+ Vec3f vel = {0, 0, 0};
+
+ for (size_t i = 0; i < gWaypointCountByPathIndex[0]; i++) {
+ x = D_80164550[0][i].posX;
+ y = D_80164550[0][i].posY;
+ z = D_80164550[0][i].posZ;
+
+ if (((x & 0xFFFF) == 0x8000) && ((y & 0xFFFF) == 0x8000) && ((z & 0xFFFF) == 0x8000)) {
+ break;
+ }
+
+ f32 height = spawn_actor_on_surface(x, 2000.0f, z);
+ Vec3f itemPos = {x, height, z};
+ add_actor_to_empty_slot(itemPos, rot, vel, ACTOR_ITEM_BOX);
+ }
+}
+
void Course::Init() {
gNumActors = 0;
gCourseMinX = 0;
@@ -153,6 +270,7 @@ void Course::LoadTextures() {
}
void Course::BeginPlay() {
+ TestPath();
}
void Course::InitClouds() {
@@ -181,9 +299,6 @@ void Course::SomeCollisionThing(Player* player, Vec3f arg1, Vec3f arg2, Vec3f ar
func_8003E048(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
-void Course::MinimapSettings() {
-}
-
void Course::InitCourseObjects() {
}
@@ -206,13 +321,6 @@ void Course::WhatDoesThisDo(Player* player, int8_t playerId) {
void Course::WhatDoesThisDoAI(Player* player, int8_t playerId) {
}
-// Positions the finishline on the minimap
-void Course::MinimapFinishlinePosition() {
- //! todo: Place hard-coded values here.
- draw_hud_2d_texture_8x8(this->Props.MinimapFinishlineX, this->Props.MinimapFinishlineY,
- (u8*) common_texture_minimap_finish_line);
-}
-
void Course::SetStaffGhost() {
D_80162DD6 = 1;
D_80162DF4 = 1;
@@ -226,11 +334,49 @@ void Course::Waypoints(Player* player, int8_t playerId) {
}
void Course::Render(struct UnkStruct_800DC5EC* arg0) {
+ if (!TrackSectionsPtr.empty()) {
+ gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
+ gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
+ // set_track_light_direction(D_800DC610, D_802B87D4, 0, 1);
+ gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
+ gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
+
+ if (func_80290C20(arg0->camera) == 1) {
+ gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
+ gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
+ // d_course_big_donut_packed_dl_DE8
+ }
+
+ TrackSectionsO2R* sections = (TrackSectionsO2R*)LOAD_ASSET_RAW(TrackSectionsPtr.c_str());
+ size_t size = ResourceGetSizeByName(TrackSectionsPtr.c_str());
+ for (size_t i = 0; i < (size / sizeof(TrackSectionsO2R)); i++) {
+ gSPDisplayList(gDisplayListHead++, (Gfx*)LOAD_ASSET_RAW(sections[i].addr.c_str()));
+ }
+ }
}
+
void Course::RenderCredits() {
}
-void Course::Collision() {
+
+f32 Course::GetWaterLevel(FVector pos, Collision* collision) {
+ float highestWater = -FLT_MAX;
+ bool found = false;
+
+ for (const auto& volume : gWorldInstance.CurrentCourse->WaterVolumes) {
+ if (pos.x >= volume.MinX && pos.x <= volume.MaxX &&
+ pos.z >= volume.MinZ && pos.z <= volume.MaxZ) {
+ // Choose the highest water volume the player is over
+ if (!found || volume.Height > highestWater) {
+ highestWater = volume.Height;
+ found = true;
+ }
+ }
+ }
+
+ // If player is not over-top of a water volume then return the courses default water level
+ return found ? highestWater : gWorldInstance.CurrentCourse->Props.WaterLevel;
}
+
void Course::ScrollingTextures() {
}
void Course::DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot,
@@ -241,7 +387,7 @@ void Course::Destroy() {
}
bool Course::IsMod() {
- return false;
+ return bIsMod;
}
Course* currentCourse = nullptr;