diff options
| author | MegaMech <MegaMech@users.noreply.github.com> | 2025-05-14 18:30:32 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-14 18:30:32 -0600 |
| commit | 32632cacdb316d7f2d3b6ecdb634f0ef9aebadf0 (patch) | |
| tree | d374a84675fc0f49100c275aa34828bc9db538f8 /src/engine | |
| parent | 70f049cb6c326dede27e0ba7e88ac0d67b7651a4 (diff) | |
Impl new intro (#193)
* Update menus
* Update CMakeLists.txt
* Add Ship
* Impl hm ship actors
* Update HM course
* Impl new intro
* Finish intro scene
* Rename
* Start Editor Work
* raycast works
* Fix ScreenRayTrace in widescreen
* Basic Actor Picking
* wip
* Editor use vtx collision
* gizmo work
* otr works for object picking
* Impl objects for editor
* actor init
* Update
* Add all axis move (freemove)
* Docking Windows works here
* Setup imgui layout for editor
* Editor Snap to Ground works
* Basic Scene Explorer Works
* Editor get actor names
* Impl editor object names
* impl Editor Play and Pause buttons
* Editor translate works while paused
* Fix freecam lighting
* Added adjustable track properties to editor
* Editor matrix, icons, rotation, impl light
* Setup Track Properties 1
* Editor tooling wip
* Load modded o2rs
* Don't enable hud if editor is enabled
* Updates
* SceneManager nearly working
* Fix mario kart 64 intro logo sizing
* Fix Rotator
* Finish new matrix translation code
* Cleanup headers
* Cleanup
* Cleanup 2
* Cleanup 3
* Prevent divize by zero crash
* Add visible circle for translate in all axis
* Editor scaling/rot works properly now
* Scale All_Axis evenly
* Fixes to includes to work on Linux.
* Removed overfilled arguments in gfx_create_framebuffer()
* Added missing function definitions to Game.h
* Editor sun face the camera
* Add rotation model to gizmo
* Add new handles
* Failed attempt at transforming collision
* Impl water volume
* Import fast64 paths
* water surface
* Scene Setup 1
* Custom Track O2R almost working needs testing
* Custom Track Load path O2r
* Render custom track. Wip collision
* Add missing function
* Debug Spawning Custom O2R Track
* Import courses working now
* Fix memory leak
* Remove New Track Button
* Engine.cpp more consistent with sf64
* Fix Editor Enable Button
* Editor Accurate mouse click drag objects
* Editor selects closest object and cleanup
* Gizmo rot and scale collision working
* Remove constexpr from IRotator
* Impl properties for location/rot/scale
* Better Properties display, swap rot handles
* Fix content browser dock and editor now disabled by default
* Remove GameInfoWindow, Multiplayer Button, and FPS Slider
* Disable Editor when its disabled
* Add new logo to hm intro
* Fix pause menu item box cursor
* Remove minimap from Course::from_json and to_json
* Impl Import Minimap
* Fix custom minimap rendering
* minimap uses extension .png
* Refactor minimap
* Freecam only for player 1
* GrandPrix Balloons work in custom track
* Track Id is now std::string and outside of Props
* Moved editor assets to be included in ship.o2r
* Fixed GenerateO2R to package the correct folder and save to the correct filename
* Linux specific changes.
* Added "#include <stdio.h>" that required them
* Changed how the "ship.o2r" file is loaded to allow it to load the file from within appimages.
* Changed the Linuxdeploy version to avoid errors later when the Github Actions creates appimages(same fix applied to other ports.)
* Revert "Moved editor assets to be included in ship.o2r"
This reverts commit 05704c01f761baa67a83e357d9765f5c6b5e3fdb.
* Added back files(this time without LUS changes)
* Changed workflow file to use correct filename for assets file.
* Missed a few spots in the workflow file.
* Added .desktop file and made corrections to the main workflow.
* Added the rest of upstream CMakeLists.txt
* disabled USE_NETWORKING
* New InverseMatrix
* Renamed both .o2r files to be more accurate to its contents.
* Reverted CmakeList.txt
---------
Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Co-authored-by: sitton76 <58642183+sitton76@users.noreply.github.com>
Diffstat (limited to 'src/engine')
143 files changed, 6386 insertions, 1187 deletions
diff --git a/src/engine/Actor.cpp b/src/engine/Actor.cpp index be86d2a5f..f3254fed0 100644 --- a/src/engine/Actor.cpp +++ b/src/engine/Actor.cpp @@ -1,16 +1,41 @@ #include <libultraship.h> +#include "Matrix.h" #include "Actor.h" +extern "C" { +#include "math_util.h" +} + AActor::AActor() {} // Virtual functions to be overridden by derived classes void AActor::Tick() { } -void AActor::Draw(Camera *camera) { } +void AActor::Draw(Camera *camera) { + if (Model) { + Mat4 mtx; + + gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); + gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); + + ApplyMatrixTransformations(mtx, *(FVector*)Pos, *(IRotator*)Rot, Scale); + if (render_set_position(mtx, 0) != 0) { + gSPDisplayList(gDisplayListHead++, Model); + } + } +} void AActor::Collision(Player* player, AActor* actor) {} void AActor::VehicleCollision(s32 playerId, Player* player){} void AActor::Destroy() { // Set uuid to zero. memset(uuid, 0, sizeof(uuid)); } -bool AActor::IsMod() { return false; }
\ No newline at end of file +bool AActor::IsMod() { return false; } +void AActor::SetLocation(FVector pos) { + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; +} +FVector AActor::GetLocation() const { + return FVector(Pos[0], Pos[1], Pos[2]); +} diff --git a/src/engine/Actor.h b/src/engine/Actor.h index a74ed74e0..fb0a9f89e 100644 --- a/src/engine/Actor.h +++ b/src/engine/Actor.h @@ -1,6 +1,7 @@ #pragma once #include <libultraship.h> +#include "CoreMath.h" extern "C" { #include "macros.h" @@ -24,6 +25,10 @@ public: /* 0x24 */ Vec3f Velocity = {0, 0, 0}; /* 0x30 */ Collision Unk30; uint8_t uuid[16]; + const char* Name = ""; + FVector Scale = {1, 1, 1}; + + Gfx* Model = NULL; virtual ~AActor() = default; // Virtual destructor for proper cleanup in derived classes @@ -33,6 +38,8 @@ public: virtual void Draw(Camera*); virtual void Collision(Player* player, AActor* actor); virtual void VehicleCollision(s32 playerId, Player* player); + void SetLocation(FVector pos); + FVector GetLocation() const; virtual void Destroy(); virtual bool IsMod(); diff --git a/src/engine/AllActors.h b/src/engine/AllActors.h new file mode 100644 index 000000000..f2b228b57 --- /dev/null +++ b/src/engine/AllActors.h @@ -0,0 +1,39 @@ +#pragma once + +#include "actors/MarioSign.h" +#include "actors/WarioSign.h" +#include "actors/Cloud.h" +#include "actors/Finishline.h" +#include "actors/SpaghettiShip.h" +#include "actors/Starship.h" +#include "actors/Ship.h" +#include "actors/Tree.h" +#include "vehicles/Train.h" +#include "vehicles/Boat.h" +#include "vehicles/Bus.h" +#include "vehicles/Truck.h" +#include "vehicles/Car.h" +#include "vehicles/Truck.h" +#include "vehicles/TankerTruck.h" + +#include "objects/Bat.h" +#include "objects/BombKart.h" +#include "objects/Boos.h" +#include "objects/CheepCheep.h" +#include "objects/Crab.h" +#include "objects/ChainChomp.h" +#include "objects/Flagpole.h" +#include "objects/Hedgehog.h" +#include "objects/HotAirBalloon.h" +#include "objects/Lakitu.h" +#include "objects/Mole.h" +#include "objects/Penguin.h" +#include "objects/Seagull.h" +#include "objects/Thwomp.h" +#include "objects/Seagull.h" +#include "objects/TrashBin.h" +#include "objects/Trophy.h" +#include "objects/Snowman.h" +#include "objects/Podium.h" +#include "objects/GrandPrixBalloons.h" + diff --git a/src/engine/CoreMath.h b/src/engine/CoreMath.h index ea74dd9a4..2c232aab9 100644 --- a/src/engine/CoreMath.h +++ b/src/engine/CoreMath.h @@ -10,16 +10,55 @@ * */ - +/** + * + * Applies pos, rot, and scale + * + */ struct FVector { float x, y, z; #ifdef __cplusplus - FVector& operator=(const FVector& other) { - x = other.x; - y = other.y; - z = other.z; - return *this; + // Operator to add two FVector objects + FVector operator+(const FVector& other) const { + return FVector(x + other.x, y + other.y, z + other.z); + } + + // Operator to subtract two FVector objects + FVector operator-(const FVector& other) const { + return FVector(x - other.x, y - other.y, z - other.z); + } + + // Operator to multiply a FVector by a scalar (float) + FVector operator*(float scalar) const { + return FVector(x * scalar, y * scalar, z * scalar); + } + + float Dot(const FVector& other) const { + return x * other.x + y * other.y + z * other.z; + } + + + FVector Cross(const FVector& other) const { + return FVector( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x + ); + } + + float Magnitude() const { + return std::sqrt(x * x + y * y + z * z); + } + + FVector Normalize() const { + float len = std::sqrt(x * x + y * y + z * z); + if (len > 0.0001f) { + return FVector( + x / len, y / len, z / len + ); + } + return FVector(0, 0, 0); } FVector() : x(0), y(0), z(0) {} @@ -27,6 +66,16 @@ struct FVector { #endif // __cplusplus }; +struct FVector4 { + float x, y, z, w; + +#ifdef __cplusplus + + FVector4() : x(0), y(0), z(0), w(0) {} + FVector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} +#endif // __cplusplus +}; + /** * For providing X and Z when you do not need Y * Some actors set themselves on the surface automatically @@ -50,35 +99,95 @@ struct FVector2D { // Sets integer X Z coordinates typedef struct IVector2D { - int32_t X, Z; + int32_t X, Y; #ifdef __cplusplus - IVector2D() : X(0), Z(0) {} // Default constructor + IVector2D() : X(0), Y(0) {} // Default constructor - IVector2D(int32_t x, int32_t z) : X(x), Z(z) {} // Constructor to initialize with values + IVector2D(int32_t x, int32_t y) : X(x), Y(y) {} // Constructor to initialize with values IVector2D& operator=(const IVector2D& other) { X = other.X; - Z = other.Z; + Y = other.Y; return *this; } #endif // __cplusplus } IVector2D; -struct FRotation { +/** + * This struct immediately converts float pitch/yaw/roll in degrees to n64 int16_t binary angles 0-0xFFFF == 0-360 degrees + * ToDegrees() Receive an FRotator of float degrees back. + * Set() Set an n64 int16_t binary angles 0-0xFFFF + */ +struct IRotator { + uint16_t pitch, yaw, roll; + +#ifdef __cplusplus + IRotator& operator=(const IRotator& other) { + pitch = other.pitch; + yaw = other.yaw; + roll = other.roll; + return *this; + } + + [[nodiscard]] void Set(uint16_t p, uint16_t y, uint16_t r) { + pitch = p; + yaw = y; + roll = r; + } + + IRotator() : pitch(0), yaw(0), roll(0) {} + IRotator(float p, float y, float r) { + pitch = p * (UINT16_MAX / 360); + yaw = y * (UINT16_MAX / 360); + roll = r * (UINT16_MAX / 360); + } + + // Convert to radians as FVector + [[nodiscard]] FVector ToRadians() const { + float scale = 2.0f * M_PI / 65536.0f; + return FVector( + pitch * scale, + yaw * scale, + roll * scale + ); + } +#endif // __cplusplus +}; + +/** + * Use IRotator unless you want to do some math in degrees. + * Always use ToBinary() or Rotator when sending into matrices or apply translation functions + * Convert from IRotator to FRotator float degrees by doing FRotator(myIRotator); + */ +struct FRotator { float pitch, yaw, roll; #ifdef __cplusplus - FRotation& operator=(const FRotation& other) { + FRotator& operator=(const FRotator& other) { pitch = other.pitch; - yaw = other.yaw; - roll = other.roll; + yaw = other.yaw; + roll = other.roll; return *this; } - FRotation() : pitch(0), yaw(0), roll(0) {} - FRotation(float p, float y, float r) : pitch(p), yaw(y), roll(r) {} + // Convert to binary rotator 0 --> INT16_MAX + [[nodiscard]] IRotator ToBinary() const { + return IRotator( + static_cast<uint16_t>(pitch * (UINT16_MAX / 360)), + static_cast<uint16_t>(yaw * (UINT16_MAX / 360)), + static_cast<uint16_t>(roll * (UINT16_MAX / 360)) + ); + } + + FRotator() : pitch(0), yaw(0), roll(0) {} + FRotator(float p, float y, float r) : pitch(p), yaw(y), roll(r) {} + FRotator(IRotator rot) { + pitch = static_cast<float>(rot.pitch * (360 / UINT16_MAX)); + yaw = static_cast<float>(rot.yaw * (360 / UINT16_MAX)); + roll = static_cast<float>(rot.roll * (360 / UINT16_MAX)); + } #endif // __cplusplus }; @@ -118,4 +227,4 @@ struct IPathSpan { #endif // __cplusplus }; -#endif // CORE_MATH_H
\ No newline at end of file +#endif // CORE_MATH_H diff --git a/src/engine/Cup.cpp b/src/engine/Cup.cpp index 85d7fed44..ec9e6c913 100644 --- a/src/engine/Cup.cpp +++ b/src/engine/Cup.cpp @@ -1,7 +1,7 @@ #include "Cup.h" #include "courses/Course.h" -Cup::Cup(const char* id, const char* name, std::vector<Course*> courses) { +Cup::Cup(std::string id, const char* name, std::vector<Course*> courses) { Id = id; Name = name; Courses = courses; diff --git a/src/engine/Cup.h b/src/engine/Cup.h index 4266c0126..0b477824f 100644 --- a/src/engine/Cup.h +++ b/src/engine/Cup.h @@ -9,13 +9,13 @@ class Course; // <-- Forward declare class Cup { public: - const char* Id; + std::string Id; const char* Name; u8 *Thumbnail; size_t CursorPosition = 0; // Course index in cup std::vector<Course*> Courses; - explicit Cup(const char* id, const char* name, std::vector<Course*> courses); + explicit Cup(std::string id, const char* name, std::vector<Course*> courses); virtual void ShuffleCourses(); diff --git a/src/engine/GarbageCollector.cpp b/src/engine/GarbageCollector.cpp index 926620fe1..9832aa29d 100644 --- a/src/engine/GarbageCollector.cpp +++ b/src/engine/GarbageCollector.cpp @@ -4,6 +4,7 @@ void RunGarbageCollector() { //CleanActors(); CleanObjects(); + CleanStaticMeshActors(); } void CleanActors() { @@ -18,14 +19,27 @@ void CleanActors() { // } } +void CleanStaticMeshActors() { + for (auto actor = gWorldInstance.StaticMeshActors.begin(); actor != gWorldInstance.StaticMeshActors.end();) { + StaticMeshActor* act = *actor; // Get a mutable copy + if (act->bPendingDestroy) { + delete act; + actor = gWorldInstance.StaticMeshActors.erase(actor); // Remove from container + continue; + } else { + actor++; + } + } +} + void CleanObjects() { for (auto object = gWorldInstance.Objects.begin(); object != gWorldInstance.Objects.end();) { OObject* obj = *object; // Get a mutable copy - if (obj->PendingDestroy) { + if (obj->bPendingDestroy) { 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 index 337d90e4a..c96f1c36a 100644 --- a/src/engine/GarbageCollector.h +++ b/src/engine/GarbageCollector.h @@ -8,4 +8,5 @@ void RunGarbageCollector(); void CleanActors(); +void CleanStaticMeshActors(); void CleanObjects(); diff --git a/src/engine/HM_Intro.cpp b/src/engine/HM_Intro.cpp new file mode 100644 index 000000000..e27d5db0c --- /dev/null +++ b/src/engine/HM_Intro.cpp @@ -0,0 +1,183 @@ +#include <libultra/gbi.h> +#include <libultra/gu.h> +#include "HM_Intro.h" + +#include "port/Game.h" + +extern "C" { +#include "main.h" +#include "memory.h" +#include "math_util.h" +#include "courses/harbour/track.h" +#include "courses/harbour/powered.h" +#include "courses/harbour/ship2_model.h" +#include "courses/harbour/ship3_model.h" +#include "collision.h" +#include "menu_items.h" +#include "external.h" +#include "menus.h" +extern Gfx ship1_spag1_mesh[]; +} + +HarbourMastersIntro::HarbourMastersIntro() { +} + +void HarbourMastersIntro::HM_InitIntro() { + _camera.Pos.x = 0; + _camera.Pos.y = 0; + _camera.Pos.z = 0; + + // The camera setup was broken when this was first made. And then it was fixed. + // That's why this file has weird coordinates as the objects were positioned in-front of the camera view + // Instead of moving the camera to the right spot in the scene. + _camera.LookAt.x = 0; + _camera.LookAt.y = 0; + _camera.LookAt.z = -2500; + + _cameraSpeed = 0.0f; + _cameraMaxSpeed = 16.0f; + _cameraAcceleration = 1.0f; + + _pos = FVector(-1000, -205, -800); // -1000, -210, -800 + _rot = IRotator(-5, 100, 0); + _scale = {0.7f, 0.7f, 0.7f}; + + _ship2Pos = FVector(300, -210, -1960); + _ship2Rot = IRotator(0, 45, 0); + + _shipPos = FVector(20, -210, -1650); + _shipRot = IRotator(0, 45, 0); + + _posHM64 = FVector(0, -500, -1000); + _rotHM64 = IRotator(0, -90, -4); // -0x2100 + + _hPos = FVector(-2000, 100, -4900); + _hRot = IRotator(0, -45.0f, 0); + _hScale = {2.0f, 2.0f, 2.0f}; + + lusPos = FVector(0, -400, -614); // 12, 190, -1000 + lusRot = IRotator(0, 0, 0); + lusScale = FVector(1, 1, 1); + + ground_f3d_material_013_lights = gdSPDefLights1( + 0x7F, 0x30, 0x80, + 0x60, 20, 10, 0x49, 0x49, 0x49 + ); + + gEditor.AddObject("lus", &lusPos, &lusRot, &lusScale, nullptr, 1, Editor::GameObject::CollisionType::BOUNDING_BOX, 10, &DespawnValue, -1); +} + +void HarbourMastersIntro::HM_TickIntro() { + _water += 1; + if (_water > 255) { + _water = 0; + } + + HarbourMastersIntro::SpagBob(_pos, _rot, 2.5f, 0.18f, 1.5f, 0.05f, 1.7f, 0.06f); + HarbourMastersIntro::Bob(_shipPos, _shipRot, 1.2f, 0.06f, 1.6f, -0.04f, 1.1f, -0.04f); + HarbourMastersIntro::Bob(_ship2Pos, _ship2Rot, 1.2f, 0.06f, 1.6f, -0.04f, 1.1f, -0.04f); + + _pos.x += 9; + if (lusPos.y < -60) { + lusPos.y += 3; + } + //_camera.Pos.x -= 1; + + // SWITCH TO NEXT MENU LOGO_INTRO_MENU + if (_pos.x >= 1100) { + gMenuFadeType = 0; + gMenuSelection = LOGO_INTRO_MENU; + gFadeModeSelection = FADE_MODE_LOGO; + } + + find_and_set_tile_size((uintptr_t) ((void*)mat_water_water1), 0, _water); + find_and_set_tile_size((uintptr_t) ((void*)mat_water_water2), _water, 0);; +} + +void HarbourMastersIntro::Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) { + float time = (float)gGlobalTimer; + + pos.y = -210 + bobAmp * sin(time * bobSpeed); + + rot.pitch = (tiltAmp * sin(time * tiltSpeed)) * (UINT16_MAX / 360); + + rot.roll = (rollAmp * sin(time * rollSpeed)) * (UINT16_MAX / 360); +} + +void HarbourMastersIntro::SpagBob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) { + float time = (float)gGlobalTimer; + + pos.y = -205 + bobAmp * sin(time * bobSpeed); + + rot.pitch = (-5 + tiltAmp * sin(time * tiltSpeed)) * (UINT16_MAX / 360); + + rot.roll = (rollAmp * sin(time * rollSpeed)) * (UINT16_MAX / 360); +} + +void HarbourMastersIntro::HM_DrawIntro() { + HarbourMastersIntro::Setup(); + + gSPMatrix(gDisplayListHead++, &gGfxPool->mtxScreen, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPMatrix(gDisplayListHead++, &gGfxPool->mtxLookAt[0], G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); + gDPSetEnvColor(gDisplayListHead++, 0x00, 0x00, 0x00, 0x00); + + Mat4 mtx_spaghettiShip; + ApplyMatrixTransformations(mtx_spaghettiShip, _pos, _rot, _scale); + render_set_position(mtx_spaghettiShip, 0); + gSPDisplayList(gDisplayListHead++, ship1_spag1_mesh); + + Mat4 mtx_ship2; + ApplyMatrixTransformations(mtx_ship2, _ship2Pos, _ship2Rot, _scale); + render_set_position(mtx_ship2, 0); + gSPDisplayList(gDisplayListHead++, ship2_SoH_mesh); + + Mat4 mtx_ship3; + ApplyMatrixTransformations(mtx_ship3, _shipPos, _shipRot, _scale); + render_set_position(mtx_ship3, 0); + gSPDisplayList(gDisplayListHead++, ship3_2Ship_mesh); + + Mat4 mtx_geo; + ApplyMatrixTransformations(mtx_geo, _hPos, _hRot, _hScale); + render_set_position(mtx_geo, 0); + + gSPDisplayList(gDisplayListHead++, ground_map_mesh); + //gSPDisplayList(gDisplayListHead++, powered_Text_mesh); // Replaced by poweredbylus + gSPDisplayList(gDisplayListHead++, castle_map_002_mesh); + gSPDisplayList(gDisplayListHead++, road_map_001_mesh); + gSPDisplayList(gDisplayListHead++, water_water1_mesh); + + Mat4 lusMtx; + ApplyMatrixTransformations(lusMtx, lusPos, lusRot, lusScale); + render_set_position(lusMtx, 0); + gSPDisplayList(gDisplayListHead++, (Gfx*)"__OTR__hmintro/poweredbylus"); + + HarbourMastersIntro::Sync(); +} + +void HarbourMastersIntro::Setup() { + u16 perspNorm; + move_segment_table_to_dmem(); + gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP); + guPerspective(&gGfxPool->mtxScreen, &perspNorm, 45.0f, 1.3333334f, 100.0f, 12800.0f, 1.0f); + gSPPerspNormalize(gDisplayListHead++, perspNorm); + guLookAt(&gGfxPool->mtxLookAt[0], _camera.Pos.x, _camera.Pos.y, _camera.Pos.z, _camera.LookAt.x, _camera.LookAt.y, _camera.LookAt.z, 0.0f, 1.0f, 0.0f); + + gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); + gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); + gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER | G_CULL_BACK | G_LIGHTING); + gDPSetFillColor(gDisplayListHead++, 0x00010001); + gDPFillRectangle(gDisplayListHead++, 0, 0, 319, 239); + gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_CULL_BACK | G_LIGHTING); + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); + gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH); + gDPPipeSync(gDisplayListHead++); +} + +void HarbourMastersIntro::Sync() { + gDPPipeSync(gDisplayListHead++); + gDPSetTexturePersp(gDisplayListHead++, G_TP_NONE); + gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP); +} diff --git a/src/engine/HM_Intro.h b/src/engine/HM_Intro.h new file mode 100644 index 000000000..24fe08e35 --- /dev/null +++ b/src/engine/HM_Intro.h @@ -0,0 +1,78 @@ +#ifndef _HM_INTRO_H +#define _HM_INTRO_H + +#include <libultraship.h> +#include <libultra/gbi.h> +#include "CoreMath.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "common_structs.h" +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +class HarbourMastersIntro { +public: + HarbourMastersIntro(); + + void HM_InitIntro(); + void HM_TickIntro(); + void HM_DrawIntro(); +private: + void Setup(); + void Sync(); + void Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed); + void SpagBob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed); + void MoveCloserToCamera(float moveSpeed); + + struct HMCamera { + FVector Pos; + FVector LookAt; + }; + + HMCamera _camera; + + f32 _cameraSpeed; + f32 _cameraMaxSpeed; + f32 _cameraAcceleration; + + FVector _pos; + IRotator _rot; + FVector _scale; + + FVector _shipPos; + IRotator _shipRot; + + FVector _ship2Pos; + IRotator _ship2Rot; + + s32 _water = 0; + + FVector _posHM64; + IRotator _rotHM64; + + FVector _hPos; + IRotator _hRot; + FVector _hScale; + + FVector lusPos; + IRotator lusRot; + FVector lusScale; + int32_t DespawnValue = 0; +}; + +extern "C" { +#endif + +void HM_InitIntro(void); +void HM_TickIntro(void); +void HM_DrawIntro(void); + +#ifdef __cplusplus +} +#endif + +#endif // _HM_INTRO_H
\ No newline at end of file diff --git a/src/engine/Matrix.cpp b/src/engine/Matrix.cpp index 354389db9..1f2301258 100644 --- a/src/engine/Matrix.cpp +++ b/src/engine/Matrix.cpp @@ -4,6 +4,8 @@ extern "C" { #include "common_structs.h" +#include "math_util.h" +#include "math_util_2.h" } void AddMatrix(std::vector<Mtx>& stack, Mat4 mtx, s32 flags) { @@ -26,7 +28,7 @@ Mtx* GetMatrix(std::vector<Mtx>& stack) { } /** - * Use GetMatrix first + * Use GetMatrix() first */ void AddMatrixFixed(std::vector<Mtx>& stack, s32 flags) { // Load the matrix @@ -58,6 +60,76 @@ Mtx* SetTextMatrix(f32 arg1, f32 arg2, f32 arg3, f32 arg4) { return mtx; } +void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector scale) { + f32 sine1, cosine1; + f32 sine2, cosine2; + f32 sine3, cosine3; + + // Compute the sine and cosine of the orientation (Euler angles) + sine1 = sins(rot.pitch); + cosine1 = coss(rot.pitch); + sine2 = sins(rot.yaw); + cosine2 = coss(rot.yaw); + sine3 = sins(rot.roll); + cosine3 = coss(rot.roll); + + // Compute the rotation matrix + mtx[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3); + mtx[1][0] = (-cosine2 * sine3) + ((sine1 * sine2) * cosine3); + mtx[2][0] = cosine1 * sine2; + mtx[3][0] = pos.x; + + mtx[0][1] = cosine1 * sine3; + mtx[1][1] = cosine1 * cosine3; + mtx[2][1] = -sine1; + mtx[3][1] = pos.y; + + mtx[0][2] = (-sine2 * cosine3) + ((sine1 * cosine2) * sine3); + mtx[1][2] = (sine2 * sine3) + ((sine1 * cosine2) * cosine3); + mtx[2][2] = cosine1 * cosine2; + mtx[3][2] = pos.z; + + // Apply scaling + mtx[0][0] *= scale.x; + mtx[1][0] *= scale.x; + mtx[2][0] *= scale.x; + mtx[0][1] *= scale.y; + mtx[1][1] *= scale.y; + mtx[2][1] *= scale.y; + mtx[0][2] *= scale.z; + mtx[1][2] *= scale.z; + mtx[2][2] *= scale.z; + + // Set the last row and column for the homogeneous coordinate system + mtx[0][3] = 0.0f; + mtx[1][3] = 0.0f; + mtx[2][3] = 0.0f; + mtx[3][3] = 1.0f; +} + +void AddLocalRotation(Mat4 mat, IRotator rot) { + f32 sin_pitch = sins(rot.pitch); + f32 cos_pitch = coss(rot.pitch); + f32 sin_yaw = sins(rot.yaw); + f32 cos_yaw = coss(rot.yaw); + f32 sin_roll = sins(rot.roll); + f32 cos_roll = coss(rot.roll); + + // Modify only the rotation part (keep translation intact) + mat[0][0] = (cos_yaw * cos_roll) + (sin_pitch * sin_yaw * sin_roll); + mat[0][1] = (cos_pitch * sin_roll); + mat[0][2] = (-sin_yaw * cos_roll) + (sin_pitch * cos_yaw * sin_roll); + + mat[1][0] = (-cos_yaw * sin_roll) + (sin_pitch * sin_yaw * cos_roll); + mat[1][1] = (cos_pitch * cos_roll); + mat[1][2] = (sin_yaw * sin_roll) + (sin_pitch * cos_yaw * cos_roll); + + mat[2][0] = (cos_pitch * sin_yaw); + mat[2][1] = -sin_pitch; + mat[2][2] = (cos_pitch * cos_yaw); +} + + // API extern "C" { @@ -122,3 +194,4 @@ extern "C" { gWorldInstance.Mtx.Objects.clear(); } } + diff --git a/src/engine/Matrix.h b/src/engine/Matrix.h index f72af76c4..180ebfb16 100644 --- a/src/engine/Matrix.h +++ b/src/engine/Matrix.h @@ -4,9 +4,12 @@ #include <libultraship.h> #include "common_structs.h" +#include "CoreMath.h" #ifdef __cplusplus extern "C" { +void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector scale); +void AddLocalRotation(Mat4 mat, IRotator rot); #endif void ClearMatrixPools(void); void AddHudMatrix(Mat4 mtx, s32 flags); diff --git a/src/engine/Registry.cpp b/src/engine/Registry.cpp new file mode 100644 index 000000000..0ea05c9d5 --- /dev/null +++ b/src/engine/Registry.cpp @@ -0,0 +1,59 @@ +// #include <vector> +// #include <functional> +// #include <iostream> +// #include <map> + +// #include "Registry.h" +// #include "Course.h" +// #include "port/Game.h" + +// template <class T> Registry<T>::Registry() { +// } + +// template <class T> void Registry<T>::Add(std::string id, std::function<T*()> fn) { +// // need to handle duplicate registration +// ContentVault[id] = fn; +// } + +// template <class T> +// void Registry<T>::AddArgs(std::string id) { +// ArgsVault[id] = [](Args&&... args) -> T* { +// return new T(std::forward<Args>(args)...); +// }; +// } + +// template <class T> +// T* Registry<T>::Get(std::string id) { +// auto it = ContentVault.find(id); +// if (it != ContentVault.end()) { +// return it->second(); +// } +// return nullptr; +// } + +// // Available Registries +// Registry<Course> Courses; +// Registry<Cup> Cups; +// Registry<AActor> Actors; + +// void AddCourse(std::string id, Course* course) { +// Courses.Add(id, [course]() { return course; }); +// course->Id = id; +// } + +// void AddCup(std::string id, Cup* cup) { +// Cups.Add(id, [cup]() { return cup; }); +// //cup->Id = id; +// } + +// void AddActor(std::string id, AActor* actor) { +// Actors.Add(id, [actor]() { return actor; }); +// } + +// void AddStockContent() { +// AddActor("mk:banana", new AMarioSign({0, 0, 0})); +// } + +// template class Registry<Course>; +// template class Registry<Cup>; +// template class Registry<AActor>; diff --git a/src/engine/Registry.h b/src/engine/Registry.h new file mode 100644 index 000000000..f55818dc3 --- /dev/null +++ b/src/engine/Registry.h @@ -0,0 +1,33 @@ +// #pragma once + +// #include "Course.h" +// #include "Cup.h" +// #include <unordered_map> +// #include "AllActors.h" +// #include "Actor.h" +// #include "objects/Object.h" + +// class AActor; // <-- Forward delare + +// template <class T> class Registry { +// public: +// Registry(); +// void Add(std::string name, std::function<T*()>); + +// template <typename... Args> +// void AddArgs(std::string id); +// T* Get(std::string id); +// private: +// std::unordered_map<std::string, std::function<T*()>> ContentVault; +// std::map<std::string, std::function<T*(Args&&...)>> ArgsVault; +// }; + +// void AddCourse(std::string id, Course* course); +// void AddCup(std::string id, Cup* cup); +// void AddActor(std::string id, AActor* actor); + +// void AddStockContent(); + +// extern Registry<Course> Courses; +// extern Registry<Cup> Cups; +// extern Registry<AActor> Actors; diff --git a/src/engine/StaticMeshActor.cpp b/src/engine/StaticMeshActor.cpp new file mode 100644 index 000000000..2e5fa1119 --- /dev/null +++ b/src/engine/StaticMeshActor.cpp @@ -0,0 +1,29 @@ +#include "StaticMeshActor.h" +#include <libultra/gbi.h> +#include "Matrix.h" + +extern "C" { +#include "main.h" +#include "math_util.h" +#include "math_util_2.h" +} + +StaticMeshActor::StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) : Name(name), Pos(pos), Rot(rot), Scale(scale), Model(""), Collision(collision) { + +} + +void StaticMeshActor::Draw() { + Mat4 mtx; + gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); + gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); + if (!Model.empty()) { + ApplyMatrixTransformations(mtx, Pos, Rot, Scale); + if (render_set_position(mtx, 0) != 0) { + gSPDisplayList(gDisplayListHead++, (Gfx*)Model.c_str()); + } + } +} + +void StaticMeshActor::Destroy() { + bPendingDestroy = true; +} diff --git a/src/engine/StaticMeshActor.h b/src/engine/StaticMeshActor.h new file mode 100644 index 000000000..4007aa2c1 --- /dev/null +++ b/src/engine/StaticMeshActor.h @@ -0,0 +1,61 @@ +#pragma once + +#include <libultraship.h> +#include <libultra/gbi.h> +#include "CoreMath.h" +#include <nlohmann/json.hpp> + +// todo: Make this class AStaticMeshActor : public AActor +class StaticMeshActor { +public: + std::string Name; + FVector Pos; + IRotator Rot; + FVector Scale; + std::string Model; + int32_t* Collision; + bool bPendingDestroy = false; + StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision); + + nlohmann::json to_json() const { + nlohmann::json j; + + // Serialize each field of the class + j["Name"] = Name; + j["Position"] = {Pos.x, Pos.y, Pos.z}; // Assuming FVector has x, y, z fields + j["Rotation"] = {Rot.pitch, Rot.yaw, Rot.roll}; // Assuming IRotator has pitch, yaw, roll fields + j["Scale"] = {Scale.x, Scale.y, Scale.z}; // Assuming FVector has x, y, z fields + j["Model"] = Model; + + // If Collision is not null, serialize it + if (Collision != nullptr) { + j["Collision"] = *Collision; // Serialize the value that Collision points to + } else { + j["Collision"] = nullptr; // Handle the case where Collision is nullptr + } + + return j; + } + + void from_json(const nlohmann::json& j) { + Name = j.at("Name").get<std::string>(); + Pos = FVector(j.at("Position")[0].get<float>(), j.at("Position")[1].get<float>(), j.at("Position")[2].get<float>()); + Rot.Set(j.at("Rotation")[0].get<uint16_t>(), j.at("Rotation")[1].get<uint16_t>(), j.at("Rotation")[2].get<uint16_t>()); + Scale = FVector(j.at("Scale")[0].get<float>(), j.at("Scale")[1].get<float>(), j.at("Scale")[2].get<float>()); + + // Deserialize the Model string + Model = j.at("Model").get<std::string>(); + + // Check if Collision is present in the JSON and deserialize it + //if (j.contains("Collision") && !j["Collision"].is_null()) { + // If Collision is a valid value, allocate memory for it and assign the value + // Collision = new int32_t(j.at("Collision").get<int32_t>()); + //} else { + // If Collision is not present or is null, set it to nullptr + Collision = nullptr; + //} + } + + virtual void Draw(); + virtual void Destroy(); +}; diff --git a/src/engine/World.cpp b/src/engine/World.cpp index a63c22b10..8e20806ff 100644 --- a/src/engine/World.cpp +++ b/src/engine/World.cpp @@ -6,14 +6,19 @@ #include "TrainCrossing.h" #include <memory> #include "objects/Object.h" +#include "port/Game.h" + +#include "editor/GameObject.h" extern "C" { - #include "camera.h" - #include "objects.h" - #include "main.h" - #include "defines.h" - #include "audio/external.h" - #include "menus.h" +#include "camera.h" +#include "objects.h" +#include "main.h" +#include "defines.h" +#include "audio/external.h" +#include "menus.h" +#include "common_data.h" +#include "mario_raceway_data.h" } World::World() {} @@ -112,15 +117,34 @@ void World::PreviousCourse() { AActor* World::AddActor(AActor* actor) { Actors.push_back(actor); + + if (actor->Model != NULL) { + gEditor.AddObject(actor->Name, (FVector*) &actor->Pos, (IRotator*)&actor->Rot, &actor->Scale, + (Gfx*) LOAD_ASSET_RAW(actor->Model), 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, + 0.0f, (int32_t*) &actor->Type, 0); + } else { + gEditor.AddObject(actor->Name, (FVector*) &actor->Pos, (IRotator*)&actor->Rot, &actor->Scale, nullptr, 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, (int32_t*)&actor->Type, 0); + } return Actors.back(); } struct Actor* World::AddBaseActor() { Actors.push_back(new AActor()); + + AActor* actor = Actors.back(); + // Skip C++ vtable to access variables in C return reinterpret_cast<struct Actor*>(reinterpret_cast<char*>(Actors.back()) + sizeof(void*)); } +void World::AddEditorObject(Actor* actor, const char* name) { + if (actor->model != NULL) { + gEditor.AddObject(name, (FVector*) &actor->pos, (IRotator*)&actor->rot, nullptr, (Gfx*)LOAD_ASSET_RAW(actor->model), 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, (int32_t*)&actor->type, 0); + } else { + gEditor.AddObject(name, (FVector*) &actor->pos, (IRotator*)&actor->rot, nullptr, nullptr, 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, (int32_t*)&actor->type, 0); + } +} + /** * Converts a C struct Actor* to its C++ AActor class */ @@ -153,8 +177,44 @@ void World::TickActors() { } } +StaticMeshActor* World::AddStaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) { + StaticMeshActors.push_back(new StaticMeshActor(name, pos, rot, scale, model, collision)); + auto actor = StaticMeshActors.back(); + auto gameObj = gEditor.AddObject(actor->Name.c_str(), &actor->Pos, &actor->Rot, &actor->Scale, (Gfx*) LOAD_ASSET_RAW(actor->Model.c_str()), 1.0f, + Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) true); + return actor; +} + +void World::DrawStaticMeshActors() { + for (const auto& actor: StaticMeshActors) { + actor->Draw(); + } +} + +void World::DeleteStaticMeshActors() { + for (auto it = StaticMeshActors.begin(); it != StaticMeshActors.end();) { + if ((*it)->bPendingDestroy) { + delete *it; // Deallocate memory for the actor + it = StaticMeshActors.erase(it); // Remove the pointer from the vector + } else { + ++it; // Only increment the iterator if we didn't erase an element + } + } +} + OObject* World::AddObject(OObject* object) { Objects.push_back(object); + + if (object->_objectIndex != -1) { + Object* cObj = &gObjectList[object->_objectIndex]; + + if (cObj->model != NULL) { + gEditor.AddObject(object->Name, (FVector*) &cObj->origin_pos[0], (IRotator*)&cObj->orientation, nullptr, (Gfx*)LOAD_ASSET_RAW(cObj->model), 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, &object->_objectIndex, -1); + } else { + gEditor.AddObject(object->Name, (FVector*) &cObj->origin_pos[0], (IRotator*)&cObj->orientation, nullptr, nullptr, 1.0f, Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, &object->_objectIndex, -1); + } + } + return Objects.back(); } @@ -209,3 +269,15 @@ Object* World::GetObjectByIndex(size_t index) { //} return nullptr; // Or handle the error as needed } + +void World::ClearWorld(void) { + World::DeleteStaticMeshActors(); + CM_CleanWorld(); + + // for (size_t i = 0; i < ARRAY_COUNT(gCollisionMesh); i++) { + + // } + + // gCollisionMesh + // Paths +} diff --git a/src/engine/World.h b/src/engine/World.h index 9490293b7..bb8979090 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -18,20 +18,26 @@ #include <memory> #include <unordered_map> #include "Actor.h" +#include "StaticMeshActor.h" #include "particles/ParticleEmitter.h" +#include "editor/Editor.h" +#include "editor/GameObject.h" + extern "C" { #include "camera.h" #include "objects.h" }; -class OObject; class Cup; // <-- Forward declaration +class OObject; class Course; +class StaticMeshActor; class AVehicle; class OBombKart; class TrainCrossing; class OLakitu; +class GameObject; // <-- Editor class World { typedef struct { @@ -49,12 +55,17 @@ public: AActor* AddActor(AActor* actor); struct Actor* AddBaseActor(); + void AddEditorObject(Actor* actor, const char* name); AActor* GetActor(size_t index); void TickActors(); AActor* ConvertActorToAActor(Actor* actor); Actor* ConvertAActorToActor(AActor* actor); + void DrawStaticMeshActors(); + StaticMeshActor* AddStaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision); + void DeleteStaticMeshActors(); + OObject* AddObject(OObject* object); void TickObjects(); @@ -76,6 +87,7 @@ public: void SetCourseFromCup(); World* GetWorld(void); + void ClearWorld(void); // These are only for browsing through the course list @@ -85,7 +97,6 @@ public: Matrix Mtx; - // Holds all available courses Course* CurrentCourse; Cup* CurrentCup; @@ -93,6 +104,7 @@ public: std::vector<Cup*> Cups; size_t CupIndex = 1; + std::vector<StaticMeshActor*> StaticMeshActors; std::vector<AActor*> Actors; std::vector<OObject*> Objects; std::vector<ParticleEmitter*> Emitters; @@ -105,6 +117,7 @@ public: TrainCrossing* AddCrossing(Vec3f position, u32 waypointMin, u32 waypointMax, f32 approachRadius, f32 exitRadius); std::vector<std::shared_ptr<TrainCrossing>> Crossings; + // Holds all available courses std::vector<Course*> Courses; size_t CourseIndex = 0; // For browsing courses. private: diff --git a/src/engine/actors/ABanana.cpp b/src/engine/actors/Banana.cpp index d484ab983..6c7f837d1 100644 --- a/src/engine/actors/ABanana.cpp +++ b/src/engine/actors/Banana.cpp @@ -1,6 +1,6 @@ #include <libultraship.h> -#include "ABanana.h" +#include "Banana.h" #include "engine/Actor.h" extern "C" { @@ -11,6 +11,7 @@ void render_actor_banana(Camera*, float[4][4], struct BananaActor*); } ABanana::ABanana(uint16_t playerId, const float pos[3], const s16 rot[3], const float velocity[3]) { + Name = "Banana"; // Initialize the BananaActor's position, rotation, and velocity std::copy(pos, pos + 3, Pos); //std::copy(rot, rot + 3, this->a.rot); diff --git a/src/engine/actors/ABanana.h b/src/engine/actors/Banana.h index 0da9eb98f..d8c55e9cb 100644 --- a/src/engine/actors/ABanana.h +++ b/src/engine/actors/Banana.h @@ -10,7 +10,6 @@ public: // Constructor ABanana(uint16_t playerId, const float pos[3], const s16 rot[3], const float velocity[3]); - virtual ~ABanana() override = default; // Virtual functions to be overridden by derived classes diff --git a/src/engine/actors/BowserStatue.cpp b/src/engine/actors/BowserStatue.cpp index de448de5e..c680c4c25 100644 --- a/src/engine/actors/BowserStatue.cpp +++ b/src/engine/actors/BowserStatue.cpp @@ -13,6 +13,7 @@ Vtx gBowserStatueVtx[717]; Gfx gBowserStatueGfx[162]; ABowserStatue::ABowserStatue(FVector pos, ABowserStatue::Behaviour behaviour) { + Name = "Bowser Statue"; Pos = pos; ABowserStatue::Behaviour _behaviour = behaviour; } diff --git a/src/engine/actors/ACloud.cpp b/src/engine/actors/Cloud.cpp index d3eaad32d..cae55e342 100644 --- a/src/engine/actors/ACloud.cpp +++ b/src/engine/actors/Cloud.cpp @@ -1,6 +1,6 @@ #include <libultraship.h> -#include "ACloud.h" +#include "Cloud.h" #include "engine/Actor.h" #include "World.h" @@ -14,10 +14,11 @@ extern f32 gKartHopInitialVelocityTable[]; extern f32 gKartGravityTable[]; } -ACloud::ACloud(Vec3f pos) { - Pos[0] = pos[0]; - Pos[1] = pos[1]; - Pos[2] = pos[2]; +ACloud::ACloud(FVector pos) { + Name = "Cloud"; + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; Rot[0] = 0; Rot[1] = 0; Rot[2] = 0; diff --git a/src/engine/actors/ACloud.h b/src/engine/actors/Cloud.h index 3d266243c..4805c08b9 100644 --- a/src/engine/actors/ACloud.h +++ b/src/engine/actors/Cloud.h @@ -2,6 +2,7 @@ #include <libultraship.h> #include "engine/Actor.h" +#include "CoreMath.h" extern "C" { #include "macros.h" @@ -15,7 +16,7 @@ public: // Constructor - ACloud(Vec3f pos); + ACloud(FVector pos); virtual ~ACloud() override = default; diff --git a/src/engine/actors/AFinishline.cpp b/src/engine/actors/Finishline.cpp index 77dd37ede..0680e60bd 100644 --- a/src/engine/actors/AFinishline.cpp +++ b/src/engine/actors/Finishline.cpp @@ -2,7 +2,7 @@ #include <libultra/gbi.h> #include "CoreMath.h" -#include "AFinishline.h" +#include "Finishline.h" #include "engine/Actor.h" #include "World.h" #include "assets/common_data.h" @@ -18,6 +18,7 @@ extern f32 gKartGravityTable[]; } AFinishline::AFinishline(std::optional<FVector> pos) { + Name = "Finishline"; if (pos.has_value()) { // Set spawn point to the provided position diff --git a/src/engine/actors/AFinishline.h b/src/engine/actors/Finishline.h index 61b561a5e..61b561a5e 100644 --- a/src/engine/actors/AFinishline.h +++ b/src/engine/actors/Finishline.h diff --git a/src/engine/actors/MarioSign.cpp b/src/engine/actors/MarioSign.cpp new file mode 100644 index 000000000..f39e4f69b --- /dev/null +++ b/src/engine/actors/MarioSign.cpp @@ -0,0 +1,56 @@ +#include "MarioSign.h" + +#include <libultra/gbi.h> +#include <assets/mario_raceway_data.h> + +extern "C" { +#include "common_structs.h" +#include "math_util.h" +#include "main.h" +#include "actor_types.h" +} + +AMarioSign::AMarioSign(FVector pos) { + Type = ACTOR_MARIO_SIGN; + Name = "Mario Sign"; + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; + Flags |= 0x4000; +} + +void AMarioSign::Tick() { + if ((Flags & 0x800) == 0) { + if ((Flags & 0x400) != 0) { + Pos[1] += 4.0f; + if (Pos[1] > 800.0f) { + Flags |= 0x800; + Rot[1] += 1820; + } + } else { + Rot[1] += 182; + } + } +} + +void AMarioSign::Draw(Camera *camera) { + Mat4 sp40; + f32 unk; + + if (Flags & 0x800) { + return; + } + + unk = is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 16000000.0f); + if (CVarGetInteger("gNoCulling", 0) == 1) { + unk = MAX(unk, 0.0f); + } + if (!(unk < 0.0f)) { + gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); + gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); + mtxf_pos_rotation_xyz(sp40, Pos, Rot); + if (render_set_position(sp40, 0) != 0) { + gSPDisplayList(gDisplayListHead++, (Gfx*)d_course_mario_raceway_dl_sign); + } + } +} diff --git a/src/engine/actors/MarioSign.h b/src/engine/actors/MarioSign.h new file mode 100644 index 000000000..099894dc1 --- /dev/null +++ b/src/engine/actors/MarioSign.h @@ -0,0 +1,19 @@ +#pragma once + +#include <libultraship.h> +#include "engine/Actor.h" +#include "CoreMath.h" + +extern "C" { +#include "common_structs.h" +} + +class AMarioSign : public AActor { +public: + + virtual ~AMarioSign() = default; + explicit AMarioSign(FVector pos); + + virtual void Tick() override; + virtual void Draw(Camera*) override; +}; diff --git a/src/engine/actors/Ship.cpp b/src/engine/actors/Ship.cpp index 148b883eb..5af3553e2 100644 --- a/src/engine/actors/Ship.cpp +++ b/src/engine/actors/Ship.cpp @@ -1,6 +1,8 @@ #include "Ship.h" #include <libultra/gbi.h> +#include "CoreMath.h" +#include "Matrix.h" extern "C" { #include "common_structs.h" @@ -14,48 +16,41 @@ extern "C" { AShip::AShip(FVector pos, AShip::Skin skin) { Spawn = pos; Spawn.y += 10; - + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; + Scale = FVector(0.4, 0.4, 0.4); + switch(skin) { case GHOSTSHIP: + Name = "Ghostship"; _skin = ghostship_Plane_mesh; break; case SHIP2: + Name = "Ship_1"; _skin = ship2_SoH_mesh; break; case SHIP3: + Name = "Ship_2"; _skin = ship3_2Ship_mesh; break; } + Model = _skin; } void AShip::Tick() { - static float angle = 0.0f; // Keeps track of the ship's rotation around the circle - float radius = 150.0f; // The radius of the circular path - float speed = 0.01f; // Speed of rotation - - angle += speed; // Increment the angle to move in a circle - - // Update the position based on a circular path - Pos.x = Spawn.x + radius * cosf(angle); - Pos.z = Spawn.z + radius * sinf(angle); + // static float angle = 0.0f; // Keeps track of the ship's rotation around the circle + // float radius = 150.0f; // The radius of the circular path + // float speed = 0.01f; // Speed of rotation - // Rotate to face forward along the circle - Rot.yaw = -static_cast<int16_t>(angle * (32768.0f / M_PI / 2.0f)); -} - -void AShip::Draw(Camera *camera) { - Mat4 shipMtx; - Vec3f hullPos = {Pos.x, Pos.y, Pos.z}; - Vec3s hullRot = {Rot.pitch, Rot.yaw, Rot.roll}; + // angle += speed; // Increment the angle to move in a circle - gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); - gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); + // // Update the position based on a circular path + // Pos.x = Spawn.x + radius * cosf(angle); + // Pos.z = Spawn.z + radius * sinf(angle); - mtxf_pos_rotation_xyz(shipMtx, hullPos, hullRot); - mtxf_scale(shipMtx, 0.4); - if (render_set_position(shipMtx, 0) != 0) { - gSPDisplayList(gDisplayListHead++, _skin); - } + // // Rotate to face forward along the circle + // Rot.yaw = -static_cast<int16_t>(angle * (32768.0f / M_PI / 2.0f)); } bool AShip::IsMod() { return true; } diff --git a/src/engine/actors/Ship.h b/src/engine/actors/Ship.h index 59ceb68a8..fe5743922 100644 --- a/src/engine/actors/Ship.h +++ b/src/engine/actors/Ship.h @@ -23,12 +23,12 @@ public: virtual ~AShip() = default; virtual void Tick() override; - virtual void Draw(Camera*) override; virtual bool IsMod() override; FVector Spawn; - FVector Pos; - FRotation Rot = {0, 0, 0}; + //FVector Pos; + ///IRotator Rot = {0, 0, 0}; + //FVector Scale = {0.4, 0.4, 0.4}; private: Gfx* _skin; }; diff --git a/src/engine/actors/SpaghettiShip.cpp b/src/engine/actors/SpaghettiShip.cpp index d53b90f07..b09ada319 100644 --- a/src/engine/actors/SpaghettiShip.cpp +++ b/src/engine/actors/SpaghettiShip.cpp @@ -1,6 +1,7 @@ #include "SpaghettiShip.h" #include <libultra/gbi.h> +#include "Matrix.h" extern "C" { #include "common_structs.h" @@ -10,8 +11,13 @@ extern "C" { } ASpaghettiShip::ASpaghettiShip(FVector pos) { + Name = "Spaghetti Ship"; + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; Spawn = pos; Spawn.y += 10; + Scale = {0.4, 0.4, 0.4}; } void ASpaghettiShip::Tick() { @@ -22,12 +28,11 @@ void ASpaghettiShip::Tick() { angle += speed; // Increment the angle to move in a circle // Update the position based on a circular path - Pos.x = Spawn.x + radius * cosf(angle); - Pos.z = Spawn.z + radius * sinf(angle); + Pos[0] = Spawn.x + radius * cosf(angle); + Pos[2] = Spawn.z + radius * sinf(angle); // Rotate to face forward along the circle - Rot.yaw = -static_cast<int16_t>(angle * (32768.0f / M_PI / 2.0f)); - + Rot[1] = -static_cast<int16_t>(angle * (32768.0f / M_PI / 2.0f)); WheelRot.pitch += 500; } @@ -36,30 +41,27 @@ void ASpaghettiShip::Draw(Camera *camera) { Mat4 shipMtx; Mat4 objectMtx; Mat4 resultMtx; - Vec3f hullPos = {Pos.x, Pos.y, Pos.z}; - Vec3s hullRot = {Rot.pitch, Rot.yaw, Rot.roll}; + Vec3f hullPos = {Pos[0], Pos[1], Pos[2]}; + Vec3s hullRot = {Rot[0], Rot[1], Rot[2]}; Vec3s rot = {WheelRot.pitch, WheelRot.yaw, WheelRot.roll}; gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - // empty/null mtx as a base - mtxf_pos_rotation_xyz(shipMtx, hullPos, hullRot); - mtxf_scale(shipMtx, 0.4); + ApplyMatrixTransformations(shipMtx, *(FVector*)Pos, *(IRotator*)Rot, Scale); if (render_set_position(shipMtx, 0) != 0) {} // Render the ships hull - Vec3f hullPos2 = {0, 0, 0}; - mtxf_translate(objectMtx, hullPos2); + ApplyMatrixTransformations(objectMtx, {0, 0, 0}, {0, 0, 0}, {1, 1, 1}); mtxf_multiplication(resultMtx, shipMtx, objectMtx); if (render_set_position(resultMtx, 3) != 0) { - gSPDisplayList(gDisplayListHead++, ship1_Spaghetti_mesh); + gSPDisplayList(gDisplayListHead++, ship1_spag1_mesh); } // Front tyre - Vec3f pos = {0, 0, 110}; - mtxf_rotate_x(shipMtx, WheelRot.pitch); - mtxf_translate(objectMtx, pos); + ApplyMatrixTransformations(objectMtx, FVector(0, 0, 110), IRotator(0, 0, 0), FVector(1, 1, 1)); + mtxf_identity(shipMtx); + AddLocalRotation(shipMtx, WheelRot); mtxf_multiplication(resultMtx, shipMtx, objectMtx); if (render_set_position(resultMtx, 3) != 0) { gSPDisplayList(gDisplayListHead++, wheels_Spaghetti_002_mesh); @@ -67,9 +69,8 @@ void ASpaghettiShip::Draw(Camera *camera) { } // Back tyre - Vec3f pos2 = {0, 0, -165}; - mtxf_rotate_x(shipMtx, WheelRot.pitch); - mtxf_translate(objectMtx, pos2); + AddLocalRotation(shipMtx, WheelRot); + ApplyMatrixTransformations(objectMtx, FVector(0, 0, -165), {0, 0, 0}, {1, 1, 1}); mtxf_multiplication(resultMtx, shipMtx, objectMtx); if (render_set_position(resultMtx, 3) != 0) { gSPDisplayList(gDisplayListHead++, wheels_Spaghetti_002_mesh); diff --git a/src/engine/actors/SpaghettiShip.h b/src/engine/actors/SpaghettiShip.h index 1d0d656c5..70bd047d7 100644 --- a/src/engine/actors/SpaghettiShip.h +++ b/src/engine/actors/SpaghettiShip.h @@ -20,9 +20,5 @@ public: virtual bool IsMod() override; FVector Spawn; - FVector Pos; - FRotation Rot = {0, 0, 0}; - FRotation WheelRot = {0, 0, 0}; -private: - f32 scale; + IRotator WheelRot = {0, 0, 0}; }; diff --git a/src/engine/actors/Starship.cpp b/src/engine/actors/Starship.cpp index bc201b84a..e104d0eb6 100644 --- a/src/engine/actors/Starship.cpp +++ b/src/engine/actors/Starship.cpp @@ -1,6 +1,7 @@ #include "Starship.h" #include <libultra/gbi.h> +#include "Matrix.h" extern "C" { #include "common_structs.h" @@ -10,7 +11,11 @@ extern "C" { } AStarship::AStarship(FVector pos) { + Name = "Starship"; Spawn = pos; + SetLocation(pos); + Scale = FVector(1.5, 1.5, 1.5); + Model = starship_Cube_mesh; } void AStarship::Tick() { @@ -21,29 +26,17 @@ void AStarship::Tick() { angle += speed; // Move relative to the initial position - Pos.x = Spawn.x + radius * cosf(angle); - Pos.z = Spawn.z + radius * sinf(angle); + + FVector pos = GetLocation(); + pos.x = Spawn.x + radius * cosf(angle); + pos.z = Spawn.z + radius * sinf(angle); + SetLocation(pos); // Keep y from changing (or adjust it if necessary) - Pos.y = Spawn.y; + //Pos.y = Spawn.y; // Rotate to face forward along the circle - Rot.yaw = angle * (180.0f / M_PI) + 90.0f; -} - -void AStarship::Draw(Camera *camera) { - Mat4 shipMtx; - Vec3f hullPos = {Pos.x, Pos.y, Pos.z}; - Vec3s hullRot = {Rot.pitch, Rot.yaw, Rot.roll}; - - gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); - gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - - mtxf_pos_rotation_xyz(shipMtx, hullPos, hullRot); - mtxf_scale(shipMtx, 1.5); - if (render_set_position(shipMtx, 0) != 0) { - gSPDisplayList(gDisplayListHead++, starship_Cube_mesh); - } + Rot[1] = angle * (180.0f / M_PI) + 90.0f; } bool AStarship::IsMod() { return true; } diff --git a/src/engine/actors/Starship.h b/src/engine/actors/Starship.h index 390aed2ea..71b898358 100644 --- a/src/engine/actors/Starship.h +++ b/src/engine/actors/Starship.h @@ -16,10 +16,7 @@ public: virtual ~AStarship() = default; virtual void Tick() override; - virtual void Draw(Camera*) override; virtual bool IsMod() override; FVector Spawn; - FVector Pos; - FRotation Rot = {0, 0, 0}; }; diff --git a/src/engine/actors/ATree.cpp b/src/engine/actors/Tree.cpp index fa1c7f580..faffd0798 100644 --- a/src/engine/actors/ATree.cpp +++ b/src/engine/actors/Tree.cpp @@ -1,4 +1,4 @@ -#include "ATree.h" +#include "Tree.h" #include <libultra/gbi.h> @@ -10,6 +10,7 @@ extern "C" { } ATree::ATree(Vec3f pos, Gfx* displaylist, f32 drawDistance, f32 minDrawDistance, const char* tlut = nullptr) { + Name = "Tree"; Pos[0] = pos[0]; Pos[1] = pos[1]; Pos[2] = pos[2]; diff --git a/src/engine/actors/ATree.h b/src/engine/actors/Tree.h index eb51f6e7e..eb51f6e7e 100644 --- a/src/engine/actors/ATree.h +++ b/src/engine/actors/Tree.h diff --git a/src/engine/actors/AWarioSign.cpp b/src/engine/actors/WarioSign.cpp index 8e73a94f3..0e83e114f 100644 --- a/src/engine/actors/AWarioSign.cpp +++ b/src/engine/actors/WarioSign.cpp @@ -1,4 +1,4 @@ -#include "AWarioSign.h" +#include "WarioSign.h" #include <libultra/gbi.h> #include <assets/wario_stadium_data.h> @@ -7,12 +7,15 @@ extern "C" { #include "common_structs.h" #include "math_util.h" #include "main.h" +#include "actor_types.h" } -AWarioSign::AWarioSign(Vec3f pos) { - Pos[0] = pos[0]; - Pos[1] = pos[1]; - Pos[2] = pos[2]; +AWarioSign::AWarioSign(FVector pos) { + Type = ACTOR_WARIO_SIGN; + Name = "Wario Sign"; + Pos[0] = pos.x; + Pos[1] = pos.y; + Pos[2] = pos.z; } void AWarioSign::Tick() { @@ -27,7 +30,6 @@ void AWarioSign::Draw(Camera *camera) { if (CVarGetInteger("gNoCulling", 0) == 1) { unk = MAX(unk, 0.0f); } - if (!(unk < 0.0f)) { gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); diff --git a/src/engine/actors/AWarioSign.h b/src/engine/actors/WarioSign.h index 31d9b9434..634b2132e 100644 --- a/src/engine/actors/AWarioSign.h +++ b/src/engine/actors/WarioSign.h @@ -2,6 +2,7 @@ #include <libultraship.h> #include "engine/Actor.h" +#include "CoreMath.h" extern "C" { #include "common_structs.h" @@ -10,9 +11,8 @@ extern "C" { class AWarioSign : public AActor { public: - virtual ~AWarioSign() = default; - explicit AWarioSign(Vec3f pos); + explicit AWarioSign(FVector pos); virtual void Tick() override; virtual void Draw(Camera*) override; diff --git a/src/engine/courses/BansheeBoardwalk.cpp b/src/engine/courses/BansheeBoardwalk.cpp index 5ebaf2bc1..51049fb8d 100644 --- a/src/engine/courses/BansheeBoardwalk.cpp +++ b/src/engine/courses/BansheeBoardwalk.cpp @@ -5,7 +5,7 @@ #include "BansheeBoardwalk.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "engine/objects/CheepCheep.h" #include "engine/objects/TrashBin.h" @@ -35,6 +35,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "course_offsets.h" + #include "course.h" extern const char *banshee_boardwalk_dls[]; } @@ -69,17 +70,26 @@ BansheeBoardwalk::BansheeBoardwalk() { this->gfx = d_course_banshee_boardwalk_packed_dls; this->gfxSize = 3689; Props.textures = banshee_boardwalk_textures; - Props.MinimapTexture = gTextureCourseOutlineBansheeBoardwalk; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineBansheeBoardwalk; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 55; + Props.Minimap.PlayerY = 39; + Props.Minimap.PlayerScaleFactor = 0.016f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Id = "mk:banshee_boardwalk"; + + Props.SetText(Props.Name, "banshee boardwalk", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "ghost", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "747m", sizeof(Props.CourseLength)); - Props.Id = "mk:banshee_boardwalk"; - Props.Name = "banshee boardwalk"; - Props.DebugName = "ghost"; - Props.CourseLength = "747m"; Props.AIBehaviour = D_0D009058; Props.AIMaximumSeparation = 40.0f; Props.AIMinimumSeparation = 0.4f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -119,8 +129,6 @@ BansheeBoardwalk::BansheeBoardwalk() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 0, 0}; Props.Skybox.BottomRight = {0, 0, 0}; @@ -131,6 +139,8 @@ BansheeBoardwalk::BansheeBoardwalk() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; Props.Sequence = MusicSeq::MUSIC_SEQ_BANSHEE_BOARDWALK; + + Props.WaterLevel = -80.0f; } void BansheeBoardwalk::Load() { @@ -140,10 +150,9 @@ void BansheeBoardwalk::Load() { D_801625EC = 0; D_801625F4 = 0; D_801625F0 = 0; - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_banshee_boardwalk_track_sections)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_banshee_boardwalk_track_sections)); func_80295C6C(); find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07000878), 128, 0, 0, 0); - D_8015F8E4 = -80.0f; } void BansheeBoardwalk::LoadTextures() { @@ -163,19 +172,19 @@ void BansheeBoardwalk::BeginPlay() { } if (gIsMirrorMode) { - gWorldInstance.AddObject(new OTrashBin(FVector(1765.0f, 45.0f, 195.0f), FRotation(0, 180.0f, 0), 1.0f, bhv)); + gWorldInstance.AddObject(new OTrashBin(FVector(1765.0f, 45.0f, 195.0f), IRotator(0, 180, 0), 1.0f, bhv)); } else { - gWorldInstance.AddObject(new OTrashBin(FVector(-1765.0f, 45.0f, 70.0f), FRotation(0, 0, 0), 1.0f, bhv)); + gWorldInstance.AddObject(new OTrashBin(FVector(-1765.0f, 45.0f, 70.0f), IRotator(0, 0, 0), 1.0f, bhv)); } if ((gGamestate != CREDITS_SEQUENCE) && (gModeSelection != TIME_TRIALS)) { - gWorldInstance.AddObject(new OBat(FVector(0,0,0), FRotation(0, 0, 90.0f))); + gWorldInstance.AddObject(new OBat(FVector(0,0,0), IRotator(0, 0, 90))); gWorldInstance.AddObject(new OBoos(5, IPathSpan(180, 190), IPathSpan(200, 210), IPathSpan(280, 290))); gWorldInstance.AddObject(new OBoos(5, IPathSpan(490, 500), IPathSpan(510, 520), IPathSpan(620, 630))); } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][110], 110, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][190], 190, 1, 0.8333333f)); @@ -187,15 +196,6 @@ void BansheeBoardwalk::BeginPlay() { } } -// Likely sets minimap boundaries -void BansheeBoardwalk::MinimapSettings() { - D_80165880 = dma_textures((const char*)gTextureGhosts, 0x4CC2, 0xD980); - D_8018D2A0 = 0.016f; - D_8018D2C0[0] = 0x0106; - D_8018D2E0 = 55; - D_8018D2E8 = 39; -} - void BansheeBoardwalk::InitCourseObjects() { size_t objectId = 0; if (gGamestate != CREDITS_SEQUENCE) { @@ -253,12 +253,6 @@ void BansheeBoardwalk::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void BansheeBoardwalk::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 BansheeBoardwalk::Render(struct UnkStruct_800DC5EC* arg0) { Camera* camera = arg0->camera; Mat4 spCC; @@ -322,8 +316,6 @@ void BansheeBoardwalk::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_banshee_boardwalk_dl_B308)); } -void BansheeBoardwalk::Collision() {} - void BansheeBoardwalk::ScrollingTextures() { D_802B87BC++; diff --git a/src/engine/courses/BansheeBoardwalk.h b/src/engine/courses/BansheeBoardwalk.h index f1b98538d..cc5b72213 100644 --- a/src/engine/courses/BansheeBoardwalk.h +++ b/src/engine/courses/BansheeBoardwalk.h @@ -28,17 +28,14 @@ public: virtual void LoadTextures() override; virtual void BeginPlay() override; //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void ScrollingTextures() override; virtual void Waypoints(Player*, int8_t) override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; diff --git a/src/engine/courses/BigDonut.cpp b/src/engine/courses/BigDonut.cpp index 5bdf76a23..4e99828eb 100644 --- a/src/engine/courses/BigDonut.cpp +++ b/src/engine/courses/BigDonut.cpp @@ -43,16 +43,24 @@ BigDonut::BigDonut() { this->gfx = d_course_big_donut_packed_dls; this->gfxSize = 528; Props.textures = big_donut_textures; - Props.MinimapTexture = gTextureCourseOutlineBigDonut; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineBigDonut; + 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 = 32; + Props.Minimap.PlayerY = 31; + Props.Minimap.PlayerScaleFactor = 0.0257f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "big donut", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "doughnut", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength)); - Props.Name = "big donut"; - Props.DebugName = "doughnut"; - Props.CourseLength = ""; Props.AIBehaviour = D_0D008F18; Props.AIMaximumSeparation = -1.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 40; Props.PathSizes = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}; @@ -89,8 +97,6 @@ BigDonut::BigDonut() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 0, 0}; Props.Skybox.BottomRight = {0, 0, 0}; @@ -101,6 +107,8 @@ BigDonut::BigDonut() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; Props.Sequence = MusicSeq::MUSIC_SEQ_BATTLE_ARENAS; + + Props.WaterLevel = 100.0f; } void BigDonut::Load() { @@ -117,17 +125,13 @@ void BigDonut::Load() { // d_course_big_donut_packed_dl_230 generate_collision_mesh_with_default_section_id((Gfx*) segmented_gfx_to_virtual((void*)0x07000230), 6); func_80295C6C(); - D_8015F8E4 = 100.0f; -} - -void BigDonut::LoadTextures() { } void BigDonut::BeginPlay() { spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_big_donut_item_box_spawns)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = {0, 0, 0}; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][20], 20, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][40], 40, 0, 1.0f)); @@ -139,31 +143,10 @@ void BigDonut::BeginPlay() { } } -// Likely sets minimap boundaries -void BigDonut::MinimapSettings() { - D_8018D2A0 = 0.0257f; - D_8018D2E0 = 32; - D_8018D2E8 = 31; -} - -void BigDonut::InitCourseObjects() {} - -void BigDonut::SomeSounds() {} - -void BigDonut::WhatDoesThisDo(Player* player, int8_t playerId) {} - -void BigDonut::WhatDoesThisDoAI(Player* player, int8_t playerId) {} - -// Positions the finishline on the minimap -void BigDonut::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 BigDonut::Render(struct UnkStruct_800DC5EC* arg0) { gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); @@ -185,8 +168,6 @@ void BigDonut::Render(struct UnkStruct_800DC5EC* arg0) { void BigDonut::RenderCredits() {} -void BigDonut::Collision() {} - void BigDonut::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = 0; } diff --git a/src/engine/courses/BigDonut.h b/src/engine/courses/BigDonut.h index bc076ecf2..bc10105e1 100644 --- a/src/engine/courses/BigDonut.h +++ b/src/engine/courses/BigDonut.h @@ -17,26 +17,14 @@ extern "C" { class BigDonut : public Course { public: - virtual ~BigDonut() = default; // Virtual destructor for proper cleanup in derived classes + virtual ~BigDonut() = default; - // Constructor explicit BigDonut(); -// virtual void Load(const char* courseVtx, -// course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; - virtual void LoadTextures() override; virtual void BeginPlay() override; - //virtual void InitClouds() override; - virtual void MinimapSettings() override; - virtual void InitCourseObjects() override; - virtual void SomeSounds() override; - virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; - virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void Destroy() override; }; diff --git a/src/engine/courses/BlockFort.cpp b/src/engine/courses/BlockFort.cpp index 136ffeef5..cf246220e 100644 --- a/src/engine/courses/BlockFort.cpp +++ b/src/engine/courses/BlockFort.cpp @@ -45,17 +45,24 @@ BlockFort::BlockFort() { this->gfx = d_course_block_fort_packed_dls; this->gfxSize = 699; Props.textures = block_fort_textures; - Props.MinimapTexture = gTextureCourseOutlineBlockFort; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineBlockFort; + 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 = 32; + Props.Minimap.PlayerY = 32; + Props.Minimap.PlayerScaleFactor = 0.0335f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "block fort", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "block", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength)); - - Props.Name = "block fort"; - Props.DebugName = "block"; - Props.CourseLength = ""; Props.AIBehaviour = D_0D008F18; Props.AIMaximumSeparation = -1.0f; Props.AIMinimumSeparation = 0.1f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -95,8 +102,6 @@ BlockFort::BlockFort() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {128, 184, 248}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -114,17 +119,14 @@ void BlockFort::Load() { generate_collision_mesh_with_default_section_id((Gfx*) segmented_gfx_to_virtual((void*)0x070015C0), 1); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; -} - -void BlockFort::LoadTextures() { + Props.WaterLevel = gCourseMinY - 10.0f; } void BlockFort::BeginPlay() { spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_block_fort_item_box_spawns)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][20], 20, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][40], 40, 0, 1.0f)); @@ -136,29 +138,8 @@ void BlockFort::BeginPlay() { } } -// Likely sets minimap boundaries -void BlockFort::MinimapSettings() { - D_8018D2A0 = 0.0335f; - D_8018D2E0 = 32; - D_8018D2E8 = 32; -} - -void BlockFort::InitCourseObjects() {} - -void BlockFort::SomeSounds() {} - -void BlockFort::WhatDoesThisDo(Player* player, int8_t playerId) {} - -void BlockFort::WhatDoesThisDoAI(Player* player, int8_t playerId) {} - -// Positions the finishline on the minimap -void BlockFort::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 BlockFort::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -166,12 +147,6 @@ void BlockFort::Render(struct UnkStruct_800DC5EC* arg0) { gSPDisplayList(gDisplayListHead++, (segmented_gfx_to_virtual((void*)0x070015C0))); } -void BlockFort::RenderCredits() {} - -void BlockFort::Collision() {} - void BlockFort::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = 0; } - -void BlockFort::Destroy() { } diff --git a/src/engine/courses/BlockFort.h b/src/engine/courses/BlockFort.h index c985b9546..f0e4c6aa6 100644 --- a/src/engine/courses/BlockFort.h +++ b/src/engine/courses/BlockFort.h @@ -25,18 +25,7 @@ public: // virtual void Load(const char* courseVtx, // course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; - virtual void LoadTextures() override; virtual void BeginPlay() override; - //virtual void InitClouds() override; - virtual void MinimapSettings() override; - virtual void InitCourseObjects() override; - virtual void SomeSounds() override; - virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; - virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; - virtual void RenderCredits() override; - virtual void Collision() override; virtual void Waypoints(Player*, int8_t) override; - virtual void Destroy() override; }; diff --git a/src/engine/courses/BowsersCastle.cpp b/src/engine/courses/BowsersCastle.cpp index cac1dde92..22b6cbe78 100644 --- a/src/engine/courses/BowsersCastle.cpp +++ b/src/engine/courses/BowsersCastle.cpp @@ -5,7 +5,7 @@ #include "BowsersCastle.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "engine/objects/Thwomp.h" #include "bowsers_castle_data.h" @@ -31,6 +31,7 @@ extern "C" { #include "collision.h" #include "code_8003DC40.h" #include "memory.h" + #include "course.h" extern const char *bowsers_castle_dls[]; } @@ -71,17 +72,26 @@ BowsersCastle::BowsersCastle() { this->gfx = d_course_bowsers_castle_packed_dls; this->gfxSize = 4900; Props.textures = bowsers_castle_textures; - Props.MinimapTexture = gTextureCourseOutlineBowsersCastle; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineBowsersCastle; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 265; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 12; + Props.Minimap.PlayerY = 48; + Props.Minimap.PlayerScaleFactor = 0.0174f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Id = "mk:bowsers_castle"; + + Props.SetText(Props.Name, "bowser's castle", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "castle", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "777m", sizeof(Props.CourseLength)); - Props.Id = "mk:bowsers_castle"; - Props.Name = "bowser's castle"; - Props.DebugName = "castle"; - Props.CourseLength = "777m"; Props.AIBehaviour = D_0D008FB8; Props.AIMaximumSeparation = 35.0f; Props.AIMinimumSeparation = 0.2f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -121,8 +131,6 @@ BowsersCastle::BowsersCastle() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {48, 8, 120}; Props.Skybox.BottomRight = {0, 0, 0}; @@ -133,21 +141,40 @@ BowsersCastle::BowsersCastle() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; Props.Sequence = MusicSeq::MUSIC_SEQ_BOWSERS_CASTLE; + + Props.WaterLevel = -50.0f; + WaterVolumes.push_back({20.0f, 1549.0f, 1859.0f, -1402.0f, -1102.0f}); } void BowsersCastle::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_bowsers_castle_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_bowsers_castle_addr)); func_80295C6C(); find_vtx_and_set_colours(segmented_gfx_to_virtual(reinterpret_cast<void*>(0x07001350)), 0x32, 0, 0, 0); - D_8015F8E4 = -50.0f; } void BowsersCastle::LoadTextures() { dma_textures(gTextureShrub, 0x000003FFU, 0x00000800U); } +// Required for the 2 thwomps that go far +void BowsersCastle::SpawnStockThwomp() { + s32 objectId = indexObjectList1[0]; + init_object(objectId, 0); + gObjectList[objectId].origin_pos[0] = 0x04b0 * xOrientation; + gObjectList[objectId].origin_pos[2] = 0xf5ba; + gObjectList[objectId].unk_0D5 = 3; + gObjectList[objectId].primAlpha = 0; + + objectId = indexObjectList1[1]; + init_object(objectId, 0); + gObjectList[objectId].origin_pos[0] = 0x04b0 * xOrientation; + gObjectList[objectId].origin_pos[2] = 0xf592; + gObjectList[objectId].unk_0D5 = 3; + gObjectList[objectId].primAlpha = 1; +} + void BowsersCastle::BeginPlay() { 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)); @@ -159,6 +186,7 @@ void BowsersCastle::BeginPlay() { 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)); + BowsersCastle::SpawnStockThwomp(); 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)); @@ -170,6 +198,7 @@ void BowsersCastle::BeginPlay() { 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)); + BowsersCastle::SpawnStockThwomp(); 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)); @@ -182,6 +211,7 @@ void BowsersCastle::BeginPlay() { 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)); + BowsersCastle::SpawnStockThwomp(); 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)); @@ -194,7 +224,7 @@ void BowsersCastle::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][150], 150, 1, 0.8333333f)); @@ -206,14 +236,6 @@ void BowsersCastle::BeginPlay() { } } -// Likely sets minimap boundaries -void BowsersCastle::MinimapSettings() { - D_8018D2C0[0] = 265; - D_8018D2A0 = 0.0174f; - D_8018D2E0 = 12; - D_8018D2E8 = 48; -} - void BowsersCastle::InitCourseObjects() { size_t objectId; size_t i; @@ -283,12 +305,6 @@ void BowsersCastle::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void BowsersCastle::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 BowsersCastle::Render(struct UnkStruct_800DC5EC* arg0) { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); @@ -320,8 +336,6 @@ void BowsersCastle::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_bowsers_castle_dl_9148)); } -void BowsersCastle::Collision() {} - void BowsersCastle::SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003E6EC(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } diff --git a/src/engine/courses/BowsersCastle.h b/src/engine/courses/BowsersCastle.h index 767bbdb8c..b52af2a26 100644 --- a/src/engine/courses/BowsersCastle.h +++ b/src/engine/courses/BowsersCastle.h @@ -26,19 +26,17 @@ public: // course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; virtual void LoadTextures() override; + void SpawnStockThwomp(); virtual void BeginPlay() override; //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; virtual void Waypoints(Player*, int8_t) override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection); diff --git a/src/engine/courses/ChocoMountain.cpp b/src/engine/courses/ChocoMountain.cpp index 632f31981..be5dcb0b1 100644 --- a/src/engine/courses/ChocoMountain.cpp +++ b/src/engine/courses/ChocoMountain.cpp @@ -7,7 +7,7 @@ #include "World.h" #include "engine/objects/BombKart.h" #include "choco_mountain_data.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" extern "C" { #include "main.h" @@ -31,6 +31,7 @@ extern "C" { #include "code_8003DC40.h" #include "memory.h" #include "course_offsets.h" + #include "course.h" extern const char *choco_mountain_dls[]; } @@ -63,17 +64,25 @@ ChocoMountain::ChocoMountain() { this->gfx = d_course_choco_mountain_packed_dls; this->gfxSize = 2910; Props.textures = choco_mountain_textures; - Props.MinimapTexture = gTextureCourseOutlineChocoMountain; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineChocoMountain; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 265; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 19; + Props.Minimap.PlayerY = 37; + Props.Minimap.PlayerScaleFactor = 0.022f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = -16.0; + + Id = "mk:choco_mountain"; + Props.SetText(Props.Name, "choco mountain", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "mountain", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "687m", sizeof(Props.CourseLength)); - Props.Id = "mk:choco_mountain"; - Props.Name = "choco mountain"; - Props.DebugName = "mountain"; - Props.CourseLength = "687m"; Props.AIBehaviour = D_0D008F80; Props.AIMaximumSeparation = 35.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -113,8 +122,6 @@ ChocoMountain::ChocoMountain() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {255, 255, 255}; Props.Skybox.BottomRight = {255, 255, 255}; @@ -125,6 +132,8 @@ ChocoMountain::ChocoMountain() { Props.Skybox.FloorBottomLeft = {255, 255, 255}; Props.Skybox.FloorTopLeft = {255, 255, 255}; Props.Sequence = MusicSeq::MUSIC_SEQ_CHOCO_MOUNTAIN; + + Props.WaterLevel = -80.0f; } void ChocoMountain::Load() { @@ -154,10 +163,9 @@ void ChocoMountain::Load() { nullify_displaylist((uintptr_t) segmented_gfx_to_virtual(reinterpret_cast<void*>(0x070003C8))); } - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_choco_mountain_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_choco_mountain_addr)); func_802B5CAC(0x238E, 0x31C7, D_8015F590); func_80295C6C(); - D_8015F8E4 = -80.0f; } void ChocoMountain::LoadTextures() { @@ -168,7 +176,7 @@ void ChocoMountain::BeginPlay() { spawn_falling_rocks((struct ActorSpawnData*)LOAD_ASSET_RAW((const char*)d_course_choco_mountain_falling_rock_spawns)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][140], 140, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][165], 165, 1, 0.8333333f)); @@ -180,14 +188,6 @@ void ChocoMountain::BeginPlay() { } } -// Likely sets minimap boundaries -void ChocoMountain::MinimapSettings() { - D_8018D2A0 = 0.022f; - D_8018D2C0[0] = 265; - D_8018D2E0 = 19; - D_8018D2E8 = 37; -} - void ChocoMountain::InitCourseObjects() { if (gGamestate != CREDITS_SEQUENCE) { if (gModeSelection == GRAND_PRIX) { @@ -235,12 +235,6 @@ void ChocoMountain::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void ChocoMountain::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 ChocoMountain::Render(struct UnkStruct_800DC5EC* arg0) { gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -292,8 +286,6 @@ void ChocoMountain::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_choco_mountain_dl_71B8)); } -void ChocoMountain::Collision() {} - void ChocoMountain::SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003E37C(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } diff --git a/src/engine/courses/ChocoMountain.h b/src/engine/courses/ChocoMountain.h index 45926ed61..b592ba9df 100644 --- a/src/engine/courses/ChocoMountain.h +++ b/src/engine/courses/ChocoMountain.h @@ -27,15 +27,12 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; virtual void Destroy() override; }; 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; diff --git a/src/engine/courses/Course.h b/src/engine/courses/Course.h index 889012a12..0a0eff823 100644 --- a/src/engine/courses/Course.h +++ b/src/engine/courses/Course.h @@ -6,6 +6,7 @@ #ifdef __cplusplus #include "engine/objects/Lakitu.h" +#include "port/resource/type/TrackSections.h" extern "C" { #endif @@ -34,20 +35,44 @@ typedef struct SkyboxColours { RGB8 FloorTopLeft; } SkyboxColours; +// Extends infinitely in the Y direction +// If a player is overtop of a water volume then it should use its height +// Recommend using the new water surface type. This is here to support the stock tracks. +// Albeit, there's no reason you cannot use this so long as you input a square. +// How to use: WaterVolumes.push_back({0, -100, 100, -100, 100}); +struct WaterVolume { + float Height; // Y coordinate of the Water level + float MinX; + float MaxX; + float MinZ; + float MaxZ; +}; + +typedef struct MinimapProps { + const char* Texture; + int16_t Width; + int16_t Height; + IVector2D Pos[2]; // Minimap position for players 1 and 2. 3/4 player mode is hard-coded to the center. + int32_t PlayerX; // The offset to place the player markers + int32_t PlayerY; + float PlayerScaleFactor; // Scale factor of the player markers + float FinishlineX; // The offset to place the finishline texture on the minimap + float FinishlineY; + RGB8 Colour; // Colour of the visible pixels (the track path) +} MinimapProps; + typedef struct Properties { - const char* Id; - const char* Name; - const char* DebugName; - const char* CourseLength; + char Name[128]; + char DebugName[128]; + char CourseLength[128]; + int32_t LakituTowType; + MinimapProps Minimap; const char* AIBehaviour; - const char* MinimapTexture; - s32 LakituTowType; - IVector2D MinimapDimensions; float AIMaximumSeparation; float AIMinimumSeparation; float NearPersp; float FarPersp; - int16_t *SomePtr; + int16_t* AIDistance; uint32_t AISteeringSensitivity; _struct_gCoursePathSizes_0x10 PathSizes; Vec4f D_0D009418; @@ -56,13 +81,160 @@ typedef struct Properties { Vec4f D_0D009808; TrackWaypoint* PathTable[4]; TrackWaypoint* PathTable2[4]; + uint8_t* CloudTexture; CloudData *Clouds; CloudData *CloudList; - int32_t MinimapFinishlineX; - int32_t MinimapFinishlineY; SkyboxColours Skybox; const course_texture *textures; enum MusicSeq Sequence; + float WaterLevel; // Used for effects, and Lakitu pick up height. Not necessarily the visual water model height. + +#ifdef __cplusplus + nlohmann::json to_json() const { + nlohmann::json j; + // j["Id"] = Id ? Id : ""; + j["Name"] = Name ? Name : ""; + j["DebugName"] = DebugName ? DebugName : ""; + j["CourseLength"] = CourseLength ? CourseLength : ""; + j["AIBehaviour"] = AIBehaviour ? AIBehaviour : ""; + j["LakituTowType"] = LakituTowType; + j["AIMaximumSeparation"] = AIMaximumSeparation; + j["AIMinimumSeparation"] = AIMinimumSeparation; + j["NearPersp"] = NearPersp; + j["FarPersp"] = FarPersp; + + // AIDistance as a JSON array + j["AIDistance"] = std::vector<int16_t>(AIDistance, AIDistance + 32); // gAIDistances array size of 32 + + j["AISteeringSensitivity"] = AISteeringSensitivity; + + // PathSizes - Assuming _struct_gCoursePathSizes_0x10 can be serialized similarly + // j["PathSizes"] = PathSizes; // Implement your serialization logic here + + j["D_0D009418"] = { D_0D009418[0], D_0D009418[1], D_0D009418[2], D_0D009418[3] }; + j["D_0D009568"] = { D_0D009568[0], D_0D009568[1], D_0D009568[2], D_0D009568[3] }; + j["D_0D0096B8"] = { D_0D0096B8[0], D_0D0096B8[1], D_0D0096B8[2], D_0D0096B8[3] }; + j["D_0D009808"] = { D_0D009808[0], D_0D009808[1], D_0D009808[2], D_0D009808[3] }; + + // Serialize arrays PathTable and PathTable2 (convert pointers into a JSON array if possible) + //j["PathTable"] = {{}}; + //j["PathTable2"] = {{}}; + // Populate PathTable and PathTable2 + + //j["Clouds"] = Clouds ? nlohmann::json{{"x", Clouds->x, "y", Clouds->y, "z", Clouds->z}} : nullptr; + //j["CloudList"] = CloudList ? nlohmann::json{{"x", CloudList->x, "y", CloudList->y, "z", CloudList->z}} : nullptr; + + j["MinimapPosition"] = {Minimap.Pos[0].X, Minimap.Pos[0].Y}; + j["MinimapPosition2P"] = {Minimap.Pos[1].X, Minimap.Pos[1].Y}; + j["MinimapPlayerX"] = Minimap.PlayerX; + j["MinimapPlayerY"] = Minimap.PlayerY; + j["MinimapPlayerScaleFactor"] = Minimap.PlayerScaleFactor; + j["MinimapFinishlineX"] = Minimap.FinishlineX; + j["MinimapFinishlineY"] = Minimap.FinishlineY; + j["MinimapColour"] = {static_cast<int>(Minimap.Colour.r), static_cast<int>(Minimap.Colour.g), static_cast<int>(Minimap.Colour.b)}; + // SkyboxColors - assuming SkyboxColors can be serialized similarly + // j["Skybox"] = Skybox; // Implement your serialization logic here + j["Sequence"] = static_cast<int>(Sequence); + + j["WaterLevel"] = static_cast<float>(WaterLevel); + + return j; + } + + // Function to load struct from JSON + void from_json(const nlohmann::json& j) { + //Id = j.at("Id").get<std::string>().c_str(); +// Name = j.at("Name").get<std::string>().c_str(); + strncpy(Name, j.at("Name").get<std::string>().c_str(), sizeof(Name) - 1); + Name[sizeof(Name) - 1] = '\0'; // Ensure null termination + +// DebugName = j.at("DebugName").get<std::string>().c_str(); + strncpy(DebugName, j.at("DebugName").get<std::string>().c_str(), sizeof(DebugName) - 1); + DebugName[sizeof(DebugName) - 1] = '\0'; // Ensure null termination + + // CourseLength = j.at("CourseLength").get<std::string>().c_str(); + strncpy(CourseLength, j.at("CourseLength").get<std::string>().c_str(), sizeof(CourseLength) - 1); + CourseLength[sizeof(CourseLength) - 1] = '\0'; // Ensure null termination + + AIBehaviour = j.at("AIBehaviour").get<std::string>().c_str(); + LakituTowType = j.at("LakituTowType").get<int>(); + + AIMaximumSeparation = j.at("AIMaximumSeparation").get<float>(); + AIMinimumSeparation = j.at("AIMinimumSeparation").get<float>(); + NearPersp = j.at("NearPersp").get<float>(); + FarPersp = j.at("FarPersp").get<float>(); + + const auto temp = j.at("AIDistance").get<std::vector<int16_t>>(); + + // Ensure the vector has 32 entries + if (temp.size() == 32) { + // Copy the data into the existing AIDistances array + std::copy(temp.begin(), temp.end(), AIDistance); + } else { + printf("Course::from_json() AIDistance array not size of 32\n"); + } + + AISteeringSensitivity = j.at("AISteeringSensitivity").get<uint32_t>(); + + // Deserialize PathSizes and other custom structs if needed + + D_0D009418[0] = j.at("D_0D009418")[0].get<float>(); + D_0D009418[1] = j.at("D_0D009418")[1].get<float>(); + D_0D009418[2] = j.at("D_0D009418")[2].get<float>(); + D_0D009418[3] = j.at("D_0D009418")[3].get<float>(); + + D_0D009568[0] = j.at("D_0D009568")[0].get<float>(); + D_0D009568[1] = j.at("D_0D009568")[1].get<float>(); + D_0D009568[2] = j.at("D_0D009568")[2].get<float>(); + D_0D009568[3] = j.at("D_0D009568")[3].get<float>(); + + D_0D0096B8[0] = j.at("D_0D0096B8")[0].get<float>(); + D_0D0096B8[1] = j.at("D_0D0096B8")[1].get<float>(); + D_0D0096B8[2] = j.at("D_0D0096B8")[2].get<float>(); + D_0D0096B8[3] = j.at("D_0D0096B8")[3].get<float>(); + + D_0D009808[0] = j.at("D_0D009808")[0].get<float>(); + D_0D009808[1] = j.at("D_0D009808")[1].get<float>(); + D_0D009808[2] = j.at("D_0D009808")[2].get<float>(); + D_0D009808[3] = j.at("D_0D009808")[3].get<float>(); + + // Deserialize arrays PathTable and PathTable2 similarly + + //Clouds = nullptr; // Deserialize if data is present + //CloudList = nullptr; // Deserialize if data is present + Minimap.Pos[0].X = j.at("MinimapPosition")[0].get<int32_t>(); + Minimap.Pos[0].Y = j.at("MinimapPosition")[1].get<int32_t>(); + Minimap.Pos[1].X = j.at("MinimapPosition2P")[0].get<int32_t>(); + Minimap.Pos[1].Y = j.at("MinimapPosition2P")[1].get<int32_t>(); + Minimap.PlayerX = j.at("MinimapPlayerX").get<int32_t>(); + Minimap.PlayerY = j.at("MinimapPlayerY").get<int32_t>(); + Minimap.PlayerScaleFactor = j.at("MinimapPlayerScaleFactor").get<float>(); + Minimap.FinishlineX = j.at("MinimapFinishlineX").get<float>(); + Minimap.FinishlineY = j.at("MinimapFinishlineY").get<float>(); + Minimap.Colour.r = j.at("MinimapColour")[0].get<uint8_t>(); + Minimap.Colour.g = j.at("MinimapColour")[1].get<uint8_t>(); + Minimap.Colour.b = j.at("MinimapColour")[2].get<uint8_t>(); + //textures = nullptr; // Deserialize textures if present + Sequence = static_cast<MusicSeq>(j.at("Sequence").get<int>()); + WaterLevel = j.at("WaterLevel").get<float>(); + } + void SetText(char* name, const char* title, size_t bufferSize) { + // Copy the title into the name buffer, ensuring it's null-terminated and within bounds + std::strncpy(name, title, bufferSize - 1); + name[bufferSize - 1] = '\0'; // Ensure the string is null-terminated + } + + const char* GetName() { + return Name; + } + + void New() { + SetText(Name, "", sizeof(Name)); + SetText(DebugName, "", sizeof(DebugName)); + SetText(CourseLength, "", sizeof(CourseLength)); + } +#endif + } Properties; #ifdef __cplusplus @@ -72,32 +244,41 @@ class World; // <-- Forward declare class Course { public: + std::string Id; Properties Props; + // This allows multiple water levels in a map. + // Ex. DK Jungle where there's a waterfall and you can drive above and below it. + std::vector<WaterVolume> WaterVolumes; + const char* vtx = nullptr; const char* gfx = nullptr; size_t gfxSize = 0; const course_texture* textures = nullptr; bool bSpawnFinishline = true; std::optional<FVector> FinishlineSpawnPoint; + std::string TrackSectionsPtr; + bool bIsMod = false; virtual ~Course() = default; explicit Course(); - virtual void Load(); // Decompress and load stock courses. Must be overridden for custom courses - virtual void Load(Vtx* vtx, Gfx *gfx); // Load custom course + virtual void LoadO2R(std::string trackPath); // Load custom track from o2r + virtual void Load(); // Decompress and load stock courses or from o2r but TrackSectionsPtr must be set. + virtual void Load(Vtx* vtx, Gfx *gfx); // Load custom track from code. Load must be overridden and then call to this base class method impl. virtual void LoadTextures(); + virtual void ParseCourseSections(TrackSectionsO2R* sections, size_t size); /** * @brief BeginPlay This function is called once at the start of gameplay. * Actor spawning should go here. */ virtual void BeginPlay(); + virtual void TestPath(); virtual void InitClouds(); virtual void UpdateClouds(s32, Camera*); virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7); - virtual void MinimapSettings(); virtual void InitCourseObjects(); virtual void UpdateCourseObjects(); virtual void RenderCourseObjects(s32 cameraId); @@ -105,12 +286,11 @@ public: virtual void CreditsSpawnActors(); virtual void WhatDoesThisDo(Player*, int8_t); virtual void WhatDoesThisDoAI(Player*, int8_t); - virtual void MinimapFinishlinePosition(); virtual void SetStaffGhost(); virtual void Render(struct UnkStruct_800DC5EC*); virtual void RenderCredits(); virtual void Waypoints(Player* player, int8_t playerId); - virtual void Collision(); + virtual f32 GetWaterLevel(FVector pos, Collision* collision); virtual void ScrollingTextures(); virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection); virtual void Destroy(); diff --git a/src/engine/courses/DKJungle.cpp b/src/engine/courses/DKJungle.cpp index bb9c951bc..bbb602584 100644 --- a/src/engine/courses/DKJungle.cpp +++ b/src/engine/courses/DKJungle.cpp @@ -5,7 +5,7 @@ #include "DKJungle.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "assets/dks_jungle_parkway_data.h" @@ -14,6 +14,7 @@ extern "C" { #include "main.h" + #include "common_structs.h" #include "camera.h" #include "course_offsets.h" #include "code_800029B0.h" @@ -34,6 +35,7 @@ extern "C" { #include "code_8003DC40.h" #include "memory.h" #include "sounds.h" + #include "course.h" extern const char *d_course_dks_jungle_parkway_unknown_dl_list[]; extern s16 currentScreenSection; } @@ -71,16 +73,24 @@ DKJungle::DKJungle() { this->gfx = d_course_dks_jungle_parkway_packed_dls; this->gfxSize = 4997; Props.textures = dks_jungle_parkway_textures; - Props.MinimapTexture = gTextureCourseOutlineDksJungleParkway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineDksJungleParkway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 255; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 29; + Props.Minimap.PlayerY = 47; + Props.Minimap.PlayerScaleFactor = 0.0155f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "d.k.'s jungle parkway", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "jungle", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "893m", sizeof(Props.CourseLength)); - Props.Name = "d.k.'s jungle parkway"; - Props.DebugName = "jungle"; - Props.CourseLength = "893m"; Props.AIBehaviour = D_0D0093C0; Props.AIMaximumSeparation = 40.0f; Props.AIMinimumSeparation = 0.1f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 9.0f; @@ -120,8 +130,6 @@ DKJungle::DKJungle() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {255, 174, 0}; Props.Skybox.BottomRight = {255, 229, 124}; @@ -132,18 +140,50 @@ DKJungle::DKJungle() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {22, 145, 22}; Props.Sequence = MusicSeq::MUSIC_SEQ_DK_JUNGLE; + + Props.WaterLevel = -475.0f; } void DKJungle::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_dks_jungle_parkway_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_dks_jungle_parkway_addr)); func_80295C6C(); - D_8015F8E4 = -475.0f; // d_course_dks_jungle_parkway_packed_dl_3FA8 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07003FA8), 120, 255, 255, 255); } +f32 DKJungle::GetWaterLevel(FVector pos, Collision* collision) { + int32_t temp_v1 = get_track_section_id(collision->meshIndexZX) & 0xFF; + + if (temp_v1 == 0xFF) { + if ((get_surface_type(collision->meshIndexZX) & 0xFF) == CAVE) { + return -475.0f; + } + if (pos.x > -478.0f) { + return -33.9f; + } + if (pos.x < -838.0f) { + return -475.0f; + } + if (pos.z > -436.0f) { + return -475.0f; + } + if (pos.z < -993.0f) { + return -33.9f; + } + if (pos.z < pos.x) { + return -475.0f; + } + + return -33.9f; + } + if (temp_v1 >= 0x14) { + return -475.0f; + } + return -33.9f; +} + void DKJungle::LoadTextures() { dma_textures(gTextureDksJungleParkwayKiwanoFruit1, 0x0000032FU, 0x00000400U); dma_textures(gTextureDksJungleParkwayKiwanoFruit2, 0x00000369U, 0x00000400U); @@ -164,7 +204,7 @@ void DKJungle::BeginPlay() { gWorldInstance.AddActor(new ABoat((0.6666666f)/4, 0)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 1, 0.8333333f)); @@ -177,14 +217,6 @@ void DKJungle::BeginPlay() { } } -// Likely sets minimap boundaries -void DKJungle::MinimapSettings() { - D_8018D2A0 = 0.0155f; - D_8018D2C0[0] = 255; - D_8018D2E0 = 29; - D_8018D2E8 = 47; -} - void DKJungle::InitCourseObjects() { for (size_t i = 0; i < NUM_TORCHES; i++) { init_smoke_particles(i); @@ -253,15 +285,9 @@ void DKJungle::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void DKJungle::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 DKJungle::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); - func_802B5D64(&D_800DC610[1], D_802B87D4, D_802B87D0, 1); + set_track_light_direction(D_800DC610, D_802B87D4, 0, 1); + set_track_light_direction(&D_800DC610[1], D_802B87D4, D_802B87D0, 1); gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_LIGHTING); @@ -286,8 +312,6 @@ void DKJungle::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_dks_jungle_parkway_dl_13C30)); } -void DKJungle::Collision() {} - void DKJungle::SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003F138(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } diff --git a/src/engine/courses/DKJungle.h b/src/engine/courses/DKJungle.h index 71cc1e582..84767a94a 100644 --- a/src/engine/courses/DKJungle.h +++ b/src/engine/courses/DKJungle.h @@ -26,19 +26,17 @@ public: // course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; virtual void LoadTextures() override; + virtual f32 GetWaterLevel(FVector pos, Collision* collision) override; virtual void BeginPlay() override; //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void ScrollingTextures() override; diff --git a/src/engine/courses/DoubleDeck.cpp b/src/engine/courses/DoubleDeck.cpp index fea83005d..ecadf9d48 100644 --- a/src/engine/courses/DoubleDeck.cpp +++ b/src/engine/courses/DoubleDeck.cpp @@ -43,16 +43,25 @@ DoubleDeck::DoubleDeck() { this->gfx = d_course_double_deck_packed_dls; this->gfxSize = 699; Props.textures = double_deck_textures; - Props.MinimapTexture = gTextureCourseOutlineDoubleDeck; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineDoubleDeck; + 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 = 32; + Props.Minimap.PlayerY = 32; + Props.Minimap.PlayerScaleFactor = 0.0285f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "double deck", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "deck", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength)); + - Props.Name = "double deck"; - Props.DebugName = "deck"; - Props.CourseLength = ""; Props.AIBehaviour = D_0D008F18; Props.AIMaximumSeparation = -1.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -92,8 +101,6 @@ DoubleDeck::DoubleDeck() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {113, 70, 255}; Props.Skybox.BottomRight = {255, 184, 99}; @@ -111,7 +118,7 @@ void DoubleDeck::Load() { generate_collision_mesh_with_default_section_id((Gfx*) segmented_gfx_to_virtual((void*)0x07000738), 1); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void DoubleDeck::LoadTextures() { @@ -121,7 +128,7 @@ void DoubleDeck::BeginPlay() { spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_double_deck_item_box_spawns)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][20], 20, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][40], 40, 0, 1.0f)); @@ -133,13 +140,6 @@ void DoubleDeck::BeginPlay() { } } -// Likely sets minimap boundaries -void DoubleDeck::MinimapSettings() { - D_8018D2A0 = 0.0285f; - D_8018D2E0 = 32; - D_8018D2E8 = 32; -} - void DoubleDeck::InitCourseObjects() {} void DoubleDeck::SomeSounds() {} @@ -148,14 +148,8 @@ void DoubleDeck::WhatDoesThisDo(Player* player, int8_t playerId) {} void DoubleDeck::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void DoubleDeck::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 DoubleDeck::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -167,8 +161,6 @@ void DoubleDeck::Render(struct UnkStruct_800DC5EC* arg0) { void DoubleDeck::RenderCredits() {} -void DoubleDeck::Collision() {} - void DoubleDeck::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = 0; } diff --git a/src/engine/courses/DoubleDeck.h b/src/engine/courses/DoubleDeck.h index d821187c8..2ebb5d9c3 100644 --- a/src/engine/courses/DoubleDeck.h +++ b/src/engine/courses/DoubleDeck.h @@ -27,16 +27,12 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void Destroy() override; }; diff --git a/src/engine/courses/FrappeSnowland.cpp b/src/engine/courses/FrappeSnowland.cpp index 7383946d1..16b9b7380 100644 --- a/src/engine/courses/FrappeSnowland.cpp +++ b/src/engine/courses/FrappeSnowland.cpp @@ -6,7 +6,7 @@ #include "FrappeSnowland.h" #include "World.h" #include "CoreMath.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "engine/objects/Snowman.h" #include "assets/frappe_snowland_data.h" @@ -34,6 +34,7 @@ extern "C" { #include "memory.h" #include "update_objects.h" #include "course_offsets.h" + #include "course.h" extern const char *d_course_frappe_snowland_dl_list[]; extern s8 gPlayerCount; } @@ -51,16 +52,25 @@ FrappeSnowland::FrappeSnowland() { this->gfx = d_course_frappe_snowland_packed_dls; this->gfxSize = 4140; Props.textures = frappe_snowland_textures; - Props.MinimapTexture = gTextureCourseOutlineFrappeSnowland; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineFrappeSnowland; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 36; + Props.Minimap.PlayerY = 40; + Props.Minimap.PlayerScaleFactor = 0.016f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + Props.Minimap.Colour = {72, 100, 255}; + + Props.SetText(Props.Name, "frappe snowland", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "snow", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "734m", sizeof(Props.CourseLength)); - Props.Name = "frappe snowland"; - Props.DebugName = "snow"; - Props.CourseLength = "734m"; Props.AIBehaviour = D_0D0090F8; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 9.0f; @@ -100,8 +110,6 @@ FrappeSnowland::FrappeSnowland() { Props.Clouds = NULL; // not used for frappe Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {28, 11, 90}; Props.Skybox.BottomRight = {0, 99, 164}; @@ -112,14 +120,15 @@ FrappeSnowland::FrappeSnowland() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 99, 164}; Props.Sequence = MusicSeq::MUSIC_SEQ_FRAPPE_SNOWLAND; + + Props.WaterLevel = -50.0f; } void FrappeSnowland::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_frappe_snowland_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_frappe_snowland_addr)); func_80295C6C(); - D_8015F8E4 = -50.0f; } void FrappeSnowland::LoadTextures() { @@ -130,7 +139,7 @@ void FrappeSnowland::LoadTextures() { void FrappeSnowland::BeginPlay() { spawn_foliage((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_frappe_snowland_tree_spawns)); spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_frappe_snowland_item_box_spawns)); - + if (gGamestate != CREDITS_SEQUENCE) { gWorldInstance.AddObject(new OSnowman(FVector(697, 0, -1684))); gWorldInstance.AddObject(new OSnowman(FVector(82, 0, -2245))); @@ -154,7 +163,7 @@ void FrappeSnowland::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 1, 0.8333333f)); @@ -186,17 +195,6 @@ void FrappeSnowland::UpdateClouds(s32 sp1C, Camera* camera) { func_80078170(sp1C, camera); } -// Likely sets minimap boundaries -void FrappeSnowland::MinimapSettings() { - D_8018D2C0[0] = 262; - D_8018D2A0 = 0.016f; - D_8018D2E0 = 36; - D_8018D2E8 = 40; - D_8018D300 = 72; - D_8018D308 = 100; - D_8018D310 = 255; -} - void FrappeSnowland::InitCourseObjects() { size_t objectId; size_t i; @@ -209,22 +207,6 @@ void FrappeSnowland::UpdateCourseObjects() { update_snowflakes(); } -void FrappeSnowland::RenderCourseObjects(s32 cameraId) { -} - -void FrappeSnowland::SomeSounds() { -} - -void FrappeSnowland::WhatDoesThisDo(Player* player, int8_t playerId) {} - -void FrappeSnowland::WhatDoesThisDoAI(Player* player, int8_t playerId) {} - -// Positions the finishline on the minimap -void FrappeSnowland::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 FrappeSnowland::Render(struct UnkStruct_800DC5EC* arg0) { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); @@ -246,8 +228,6 @@ void FrappeSnowland::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_frappe_snowland_dl_76A0)); } -void FrappeSnowland::Collision() {} - void FrappeSnowland::Waypoints(Player* player, int8_t playerId) { s16 waypoint = gNearestWaypointByPlayerId[playerId]; @@ -260,7 +240,3 @@ void FrappeSnowland::Waypoints(Player* player, int8_t playerId) { } } } - -void FrappeSnowland::ScrollingTextures() {} - -void FrappeSnowland::Destroy() {} diff --git a/src/engine/courses/FrappeSnowland.h b/src/engine/courses/FrappeSnowland.h index 8ecbdbf46..8f01559a9 100644 --- a/src/engine/courses/FrappeSnowland.h +++ b/src/engine/courses/FrappeSnowland.h @@ -17,30 +17,18 @@ extern "C" { class FrappeSnowland : public Course { public: - virtual ~FrappeSnowland() = default; // Virtual destructor for proper cleanup in derived classes + virtual ~FrappeSnowland() = default; - // Constructor explicit FrappeSnowland(); -// virtual void Load(const char* courseVtx, -// course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; virtual void InitClouds() override; virtual void UpdateClouds(s32 sp1C, Camera* camera) override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; - virtual void RenderCourseObjects(s32 cameraId) override; - virtual void SomeSounds() override; - virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; - virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; - virtual void ScrollingTextures() override; virtual void Waypoints(Player* player, int8_t playerId) override; - virtual void Destroy() override; }; diff --git a/src/engine/courses/Harbour.cpp b/src/engine/courses/Harbour.cpp index a33f9f3b6..bd037754c 100644 --- a/src/engine/courses/Harbour.cpp +++ b/src/engine/courses/Harbour.cpp @@ -6,7 +6,7 @@ #include "Harbour.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/actors/BowserStatue.h" #include "engine/actors/Ship.h" #include "engine/actors/SpaghettiShip.h" @@ -16,8 +16,8 @@ #include "assets/mario_raceway_data.h" #include "assets/bowsers_castle_data.h" #include "assets/bowsers_castle_displaylists.h" -#include "engine/actors/ATree.h" -#include "engine/actors/ACloud.h" +#include "engine/actors/Tree.h" +#include "engine/actors/Cloud.h" #include "engine/vehicles/Train.h" #include "engine/objects/Trophy.h" #include "engine/objects/CheepCheep.h" @@ -28,6 +28,7 @@ #include "engine/objects/HotAirBalloon.h" #include "engine/objects/Crab.h" #include "engine/objects/Boos.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -50,12 +51,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "courses/harbour/track.h" - typedef struct { - Gfx* addr; - u8 surfaceType; - u8 sectionId; - u16 flags; - } TrackSections; + #include "course.h" } TrackWaypoint harbour_path[] = { @@ -518,27 +514,28 @@ TrackWaypoint harbour_path[] = { {13,-121,0,0}, {15,-121,-14,0}, {-32768, -32768, -32768, 0} - - - - }; Harbour::Harbour() { this->gfxSize = 100; this->textures = NULL; - Props.MinimapTexture = gTextureCourseOutlineMarioRaceway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); - - Props.Id = "mk:harbour"; - Props.Name = "Harbour"; - Props.DebugName = "harbour"; - Props.CourseLength = "99m"; + Props.Minimap.Texture = gTextureCourseOutlineMarioRaceway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 260; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 6; + Props.Minimap.PlayerY = 28; + Props.Minimap.PlayerScaleFactor = 0.022f; + + Id = "mk:harbour"; + Props.SetText(Props.Name, "Harbour", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "harbour", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "99m", sizeof(Props.CourseLength)); Props.AIBehaviour = D_0D008F28; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCB34; Props.AISteeringSensitivity = 48; Props.NearPersp = 9.0f; @@ -576,10 +573,11 @@ Harbour::Harbour() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust5); Props.Clouds = gKalimariDesertClouds; Props.CloudList = gLuigiRacewayClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; Props.Skybox.TopRight = {120, 140, 188}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -601,6 +599,12 @@ TrackSections harbour_surfaces[] = { void Harbour::Load() { Course::Load(road_map_001_mesh_vtx_0, NULL); + // The light gets overridden in hm_intro, reset to normal + ground_f3d_material_013_lights = gdSPDefLights1( + 0x7F, 0x7F, 0x7F, + 0xFF, 0xFF, 0xFF, 0x49, 0x49, 0x49 + ); + generate_collision_mesh_with_default_section_id(ground_map_mesh, 8); generate_collision_mesh_with_default_section_id(road_map_001_mesh, 1); generate_collision_mesh_with_defaults(castle_map_002_mesh); @@ -608,9 +612,9 @@ void Harbour::Load() { generate_collision_mesh_with_defaults(bush_map_004_mesh); generate_collision_mesh_with_defaults(statue_map_005_mesh); - parse_course_displaylists((TrackSectionsI*)harbour_surfaces); + parse_course_displaylists((TrackSections*)harbour_surfaces); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void Harbour::LoadTextures() { @@ -726,7 +730,7 @@ void Harbour::BeginPlay() { // 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, OTrashBin::Behaviour::MUNCHING)); + //gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), IRotator(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING)); //gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9)); //gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400)); @@ -750,34 +754,11 @@ void Harbour::BeginPlay() { // add_actor_to_empty_slot(itemPos, rot, vel, ACTOR_ITEM_BOX); // } // } - gWorldInstance.AddActor(new AShip(FVector(-1694, -111, 1451), AShip::Skin::GHOSTSHIP)); - gWorldInstance.AddActor(new AShip(FVector(2811, -83, 966), AShip::Skin::SHIP2)); - gWorldInstance.AddActor(new AShip(FVector(1526, -36, -2228), AShip::Skin::SHIP3)); - - - gWorldInstance.AddActor(new ASpaghettiShip(FVector(582, -70, -650))); - //gWorldInstance.AddActor(new ASpaghettiShip(FVector(2811, -83, 966 ))); - gWorldInstance.AddActor(new AStarship(FVector(1019, 160, 1987))); - + //gWorldInstance.AddActor(new AShip(FVector(-1694, -111, 1451), AShip::Skin::GHOSTSHIP)); + //gWorldInstance.AddActor(new AShip(FVector(2811, -83, 966), AShip::Skin::SHIP2)); + //gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(16, -136, -34))); } -// Likely sets minimap boundaries -void Harbour::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust5, 0x443, 0x1000)); - D_8018D2A0 = 0.022f; - D_8018D2E0 = 6; - D_8018D2E8 = 28; - D_8018D2C0[0] = 260; - D_8018D2D8[0] = 170; - D_80165718 = 0; - D_80165720 = 5; - D_80165728 = -240; -} - -void Harbour::InitCourseObjects() {} - -void Harbour::SomeSounds() {} - void Harbour::WhatDoesThisDo(Player* player, int8_t playerId) { if (((s16) gNearestWaypointByPlayerId[playerId] >= 0x19B) && ((s16) gNearestWaypointByPlayerId[playerId] < 0x1B9)) { @@ -808,16 +789,10 @@ void Harbour::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void Harbour::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 Harbour::Render(struct UnkStruct_800DC5EC* arg0) { gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); @@ -836,13 +811,6 @@ void Harbour::Render(struct UnkStruct_800DC5EC* arg0) { gSPDisplayList(gDisplayListHead++, moon_moon_mesh); } -void Harbour::RenderCredits() { -} - -void Harbour::Collision() {} - -void Harbour::Destroy() { } - bool Harbour::IsMod() { return true; }
\ No newline at end of file diff --git a/src/engine/courses/Harbour.h b/src/engine/courses/Harbour.h index dadb78f5a..834154f84 100644 --- a/src/engine/courses/Harbour.h +++ b/src/engine/courses/Harbour.h @@ -27,15 +27,8 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; - virtual void InitCourseObjects() override; - virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; - virtual void RenderCredits() override; - virtual void Collision() override; - virtual void Destroy() override; virtual bool IsMod() override; }; diff --git a/src/engine/courses/KalimariDesert.cpp b/src/engine/courses/KalimariDesert.cpp index 133a38e08..8f4c3e893 100644 --- a/src/engine/courses/KalimariDesert.cpp +++ b/src/engine/courses/KalimariDesert.cpp @@ -5,7 +5,7 @@ #include "KalimariDesert.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "kalimari_desert_data.h" #include "engine/vehicles/Utils.h" @@ -32,6 +32,7 @@ extern "C" { #include "actors.h" #include "collision.h" #include "memory.h" + #include "course.h" extern const char *kalimari_desert_dls[]; } @@ -56,16 +57,24 @@ KalimariDesert::KalimariDesert() { this->gfx = d_course_kalimari_desert_packed_dls; this->gfxSize = 5328; Props.textures = kalimari_desert_textures; - Props.MinimapTexture = gTextureCourseOutlineKalimariDesert; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineKalimariDesert; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 263; + Props.Minimap.Pos[0].Y = 165; + Props.Minimap.PlayerX = 55; + Props.Minimap.PlayerY = 27; + Props.Minimap.PlayerScaleFactor = 0.015f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 4.0; + + Props.SetText(Props.Name, "kalimari desert", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "desert", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "753m", sizeof(Props.CourseLength)); - Props.Name = "kalimari desert"; - Props.DebugName = "desert"; - Props.CourseLength = "753m"; Props.AIBehaviour = D_0D009260; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 10.0f; @@ -103,10 +112,9 @@ KalimariDesert::KalimariDesert() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust5); Props.Clouds = gKalimariDesertClouds; Props.CloudList = gKalimariDesertClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {195, 231, 255}; Props.Skybox.BottomRight = {255, 192, 0}; @@ -122,9 +130,9 @@ KalimariDesert::KalimariDesert() { void KalimariDesert::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_kalimari_desert_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_kalimari_desert_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void KalimariDesert::LoadTextures() { @@ -202,7 +210,7 @@ void KalimariDesert::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][138], 138, 1, 0.8333333f)); @@ -215,16 +223,6 @@ void KalimariDesert::BeginPlay() { } } -// Likely sets minimap boundaries -void KalimariDesert::MinimapSettings() { - D_8018D2C0[0] = 263; - D_8018D2D8[0] = 165; - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust5, 0x443, 0x1000)); - D_8018D2A0 = 0.015f; - D_8018D2E0 = 55; - D_8018D2E8 = 27; -} - void KalimariDesert::InitCourseObjects() { size_t i; if (gGamestate != CREDITS_SEQUENCE) { @@ -248,14 +246,8 @@ void KalimariDesert::WhatDoesThisDo(Player* player, int8_t playerId) {} void KalimariDesert::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void KalimariDesert::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 KalimariDesert::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + set_track_light_direction(D_800DC610, D_802B87D4, 0, 1); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -291,6 +283,4 @@ void KalimariDesert::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_kalimari_desert_dl_22E00)); } -void KalimariDesert::Collision() {} - void KalimariDesert::Destroy() { } diff --git a/src/engine/courses/KalimariDesert.h b/src/engine/courses/KalimariDesert.h index 0a07fcbb3..fe8b21f23 100644 --- a/src/engine/courses/KalimariDesert.h +++ b/src/engine/courses/KalimariDesert.h @@ -29,15 +29,12 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Destroy() override; private: diff --git a/src/engine/courses/KoopaTroopaBeach.cpp b/src/engine/courses/KoopaTroopaBeach.cpp index 3fd22598a..fff1b7b55 100644 --- a/src/engine/courses/KoopaTroopaBeach.cpp +++ b/src/engine/courses/KoopaTroopaBeach.cpp @@ -6,7 +6,7 @@ #include "KoopaTroopaBeach.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "engine/objects/Crab.h" #include "assets/koopa_troopa_beach_data.h" @@ -32,6 +32,7 @@ extern "C" { #include "collision.h" #include "code_8003DC40.h" #include "memory.h" + #include "course.h" extern const char *koopa_troopa_beach_dls[]; extern s8 gPlayerCount; } @@ -61,17 +62,25 @@ KoopaTroopaBeach::KoopaTroopaBeach() { this->gfx = d_course_koopa_troopa_beach_packed_dls; this->gfxSize = 5720; Props.textures = koopa_troopa_beach_textures; - Props.MinimapTexture = gTextureCourseOutlineKoopaTroopaBeach; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineKoopaTroopaBeach; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 268; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 40; + Props.Minimap.PlayerY = 21; + Props.Minimap.PlayerScaleFactor = 0.014f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Id = "mk:koopa_beach"; + Props.SetText(Props.Name, "koopa troopa beach", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "beach", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "691m", sizeof(Props.CourseLength)); - Props.Id = "mk:koopa_beach"; - Props.Name = "koopa troopa beach"; - Props.DebugName = "beach"; - Props.CourseLength = "691m"; Props.AIBehaviour = D_0D009158; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 1.0f; @@ -109,10 +118,9 @@ KoopaTroopaBeach::KoopaTroopaBeach() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust3); Props.Clouds = gKoopaTroopaBeachClouds; Props.CloudList = gKoopaTroopaBeachClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {48, 152, 120}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -123,12 +131,16 @@ KoopaTroopaBeach::KoopaTroopaBeach() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {48, 152, 120}; Props.Sequence = MusicSeq::MUSIC_SEQ_KOOPA_TROOPA_BEACH; + + Props.WaterLevel = 0.0f; + gWaterVelocity = -0.1f; + WaterVolumes.push_back({0.8f, 67.0f, 239.0f, 2233.0f, 2405.0f}); } void KoopaTroopaBeach::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_koopa_troopa_beach_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_koopa_troopa_beach_addr)); func_80295C6C(); find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x0700ADE0), -0x6A, 255, 255, 255); find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x0700A540), -0x6A, 255, 255, 255); @@ -172,7 +184,7 @@ void KoopaTroopaBeach::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][60], 60, 1, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][120], 120, 1, 0.8333333f)); @@ -184,15 +196,6 @@ void KoopaTroopaBeach::BeginPlay() { } } -// Likely sets minimap boundaries -void KoopaTroopaBeach::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust3, 0x3C8U, 0x1000)); - D_8018D2A0 = 0.014f; - D_8018D2C0[0] = 268; - D_8018D2E0 = 40; - D_8018D2E8 = 21; -} - void KoopaTroopaBeach::InitCourseObjects() { } @@ -228,12 +231,6 @@ void KoopaTroopaBeach::WhatDoesThisDo(Player* player, int8_t playerId) {} void KoopaTroopaBeach::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void KoopaTroopaBeach::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 KoopaTroopaBeach::Render(struct UnkStruct_800DC5EC* arg0) { gDPPipeSync(gDisplayListHead++); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); @@ -264,21 +261,20 @@ void KoopaTroopaBeach::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_koopa_troopa_beach_dl_18D68)); } -void KoopaTroopaBeach::Collision() {} - void KoopaTroopaBeach::SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003E37C(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } void KoopaTroopaBeach::ScrollingTextures() { // clang-format off - if (D_8015F8E8 < 0.0f) { - if (D_8015F8E4 < -20.0f) { D_8015F8E8 *= -1.0f; } + // This flips the velocity from 0.1f to -0.1f + if (gWaterVelocity < 0.0f) { + if (Props.WaterLevel < -20.0f) { gWaterVelocity *= -1.0f; } } else { - if (D_8015F8E4 > 0.0f) { D_8015F8E8 *= -1.0f; } + if (Props.WaterLevel > 0.0f) { gWaterVelocity *= -1.0f; } } // clang-format on - D_8015F8E4 += D_8015F8E8; + Props.WaterLevel += gWaterVelocity; D_802B87BC += 9; if (D_802B87BC > 255) { @@ -330,7 +326,7 @@ void KoopaTroopaBeach::DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pat break; } vector[0] = 0.0f; - vector[1] = D_8015F8E4; + vector[1] = Props.WaterLevel; vector[2] = 0.0f; mtxf_translate(matrix, vector); render_set_position(matrix, 0); diff --git a/src/engine/courses/KoopaTroopaBeach.h b/src/engine/courses/KoopaTroopaBeach.h index 490dfe8ab..7ebd8bac8 100644 --- a/src/engine/courses/KoopaTroopaBeach.h +++ b/src/engine/courses/KoopaTroopaBeach.h @@ -30,17 +30,14 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player *player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; virtual void ScrollingTextures() override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; diff --git a/src/engine/courses/LuigiRaceway.cpp b/src/engine/courses/LuigiRaceway.cpp index 555af3212..e4ee857a3 100644 --- a/src/engine/courses/LuigiRaceway.cpp +++ b/src/engine/courses/LuigiRaceway.cpp @@ -8,7 +8,8 @@ #include "engine/objects/BombKart.h" #include "assets/luigi_raceway_data.h" #include "engine/objects/HotAirBalloon.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -34,6 +35,7 @@ extern "C" { #include "courses/staff_ghost_data.h" #include "framebuffer_effects.h" #include "skybox_and_splitscreen.h" +#include "course.h" extern const char* luigi_raceway_dls[]; extern s16 currentScreenSection; } @@ -87,17 +89,25 @@ LuigiRaceway::LuigiRaceway() { this->gfx = d_course_luigi_raceway_packed_dls; this->gfxSize = 6377; Props.textures = luigi_raceway_textures; - Props.MinimapTexture = gTextureCourseOutlineLuigiRaceway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineLuigiRaceway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 271; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 45; + Props.Minimap.PlayerY = 60; + Props.Minimap.PlayerScaleFactor = 0.0155f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Id = "mk:luigi_raceway"; + Props.SetText(Props.Name, "luigi raceway", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "l circuit", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "717m", sizeof(Props.CourseLength)); - Props.Id = "mk:luigi_raceway"; - Props.Name = "luigi raceway"; - Props.DebugName = "l circuit"; - Props.CourseLength = "717m"; Props.AIBehaviour = D_0D0091E8; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.7f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 48; Props.NearPersp = 9.0f; @@ -135,10 +145,9 @@ LuigiRaceway::LuigiRaceway() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*)LOAD_ASSET_RAW(gTextureExhaust2); Props.Clouds = gLuigiRacewayClouds; Props.CloudList = gLuigiRacewayClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = { 128, 184, 248 }; Props.Skybox.BottomRight = { 216, 232, 248 }; @@ -154,9 +163,9 @@ LuigiRaceway::LuigiRaceway() { void LuigiRaceway::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*) LOAD_ASSET_RAW(d_course_luigi_raceway_addr)); + parse_course_displaylists((TrackSections*) LOAD_ASSET_RAW(d_course_luigi_raceway_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void LuigiRaceway::LoadTextures() { @@ -172,10 +181,11 @@ void LuigiRaceway::BeginPlay() { 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))); + gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(-140, -44, -215))); } if (gModeSelection == VERSUS) { - Vec3f pos = { 0, 0, 0 }; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 1, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][200], 200, 3, 0.8333333f)); @@ -187,38 +197,15 @@ void LuigiRaceway::BeginPlay() { } } -// Likely sets minimap boundaries -void LuigiRaceway::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t(*)[1024]>(dma_textures(gTextureExhaust2, 0x4F4U, 0xC00)); - D_8018D2A0 = 0.0155f; - D_8018D2C0[0] = 271; - D_8018D2E0 = 45; - D_8018D2E8 = 60; - D_80165718 = -140; - D_80165720 = -44; - D_80165728 = -215; -} - void LuigiRaceway::InitCourseObjects() { size_t i; if (gGamestate != CREDITS_SEQUENCE) { if (gModeSelection == GRAND_PRIX) { func_80070714(); } - - for (i = 0; i < D_80165738; i++) { - find_unused_obj_index(&gObjectParticle3[i]); - init_object(gObjectParticle3[i], 0); - } } } -void LuigiRaceway::UpdateCourseObjects() { -} - -void LuigiRaceway::RenderCourseObjects(s32 cameraId) { -} - void LuigiRaceway::SomeSounds() { vec3f_set(D_8015F748, 85.0f, 21.0f, -219.0f); func_800C9D80(D_8015F748, D_802B91C8, 0x5103700B); @@ -252,13 +239,6 @@ void LuigiRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void LuigiRaceway::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 LuigiRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 11200) { @@ -444,13 +424,7 @@ void LuigiRaceway::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*) (d_course_luigi_raceway_dl_FD40)); } -void LuigiRaceway::Collision() { -} - void LuigiRaceway::SomeCollisionThing(Player* player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003E9EC(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - -void LuigiRaceway::Destroy() { -} diff --git a/src/engine/courses/LuigiRaceway.h b/src/engine/courses/LuigiRaceway.h index c5e089d81..48a7d8c08 100644 --- a/src/engine/courses/LuigiRaceway.h +++ b/src/engine/courses/LuigiRaceway.h @@ -29,19 +29,13 @@ class LuigiRaceway : public Course { virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; - virtual void UpdateCourseObjects() override; - virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void SetStaffGhost() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player* player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; - virtual void Destroy() override; }; diff --git a/src/engine/courses/MarioRaceway.cpp b/src/engine/courses/MarioRaceway.cpp index e3b9bba21..50af0d890 100644 --- a/src/engine/courses/MarioRaceway.cpp +++ b/src/engine/courses/MarioRaceway.cpp @@ -5,9 +5,10 @@ #include "MarioRaceway.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/Object.h" #include "engine/objects/BombKart.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -31,6 +32,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "courses/staff_ghost_data.h" + #include "course.h" extern const char *mario_raceway_dls[]; } @@ -72,19 +74,28 @@ MarioRaceway::MarioRaceway() { this->vtx = d_course_mario_raceway_vertex; this->gfx = d_course_mario_raceway_packed_dls; this->gfxSize = 3367; - Props.textures = mario_raceway_textures; - Props.MinimapTexture = gTextureCourseOutlineMarioRaceway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); - Props.Id = "mk:mario_raceway"; - Props.Name = "Mario Raceway"; - Props.DebugName = "m circuit"; - Props.CourseLength = "567m"; + Props.textures = mario_raceway_textures; + Props.Minimap.Texture = gTextureCourseOutlineMarioRaceway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 260; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 6; + Props.Minimap.PlayerY = 28; + Props.Minimap.PlayerScaleFactor = 0.022f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = -2.0; + + Id = "mk:mario_raceway"; + Props.SetText(Props.Name, "mario raceway", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "m circuit", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "567m", sizeof(Props.CourseLength)); Props.AIBehaviour = D_0D008F28; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCB34; + Props.AIDistance = gMarioRacewayAIDistances; Props.AISteeringSensitivity = 48; Props.NearPersp = 9.0f; @@ -122,10 +133,9 @@ MarioRaceway::MarioRaceway() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (uint8_t*) LOAD_ASSET_RAW(gTextureExhaust5); Props.Clouds = gKalimariDesertClouds; Props.CloudList = gLuigiRacewayClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 184, 248}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -156,9 +166,9 @@ void MarioRaceway::Load() { } } - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_mario_raceway_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_mario_raceway_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void MarioRaceway::LoadTextures() { @@ -191,7 +201,7 @@ void MarioRaceway::BeginPlay() { add_actor_to_empty_slot(position, rotation, velocity, ACTOR_MARIO_SIGN); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][40], 40, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][265], 265, 3, 0.8333333f)); @@ -200,19 +210,10 @@ void MarioRaceway::BeginPlay() { gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][0], 0, 0, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][0], 0, 0, 0.8333333f)); } -} -// Likely sets minimap boundaries -void MarioRaceway::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust5, 0x443, 0x1000)); - D_8018D2A0 = 0.022f; - D_8018D2E0 = 6; - D_8018D2E8 = 28; - D_8018D2C0[0] = 260; - D_8018D2D8[0] = 170; - D_80165718 = 0; - D_80165720 = 5; - D_80165728 = -240; + if (gGamestate != CREDITS_SEQUENCE) { + gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(0, 5, -240))); + } } void MarioRaceway::InitCourseObjects() { @@ -220,10 +221,6 @@ void MarioRaceway::InitCourseObjects() { if (gModeSelection == GRAND_PRIX) { func_80070714(); } - for (size_t i = 0; i < D_80165738; i++) { - find_unused_obj_index(&gObjectParticle3[i]); - init_object(gObjectParticle3[i], 0); - } } } @@ -262,12 +259,6 @@ void MarioRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void MarioRaceway::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 MarioRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 9000) { @@ -390,8 +381,6 @@ void MarioRaceway::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_mario_raceway_dl_9348)); } -void MarioRaceway::Collision() {} - void MarioRaceway::CreditsSpawnActors() { dma_textures(gTextureTrees1, 0x35B, 0x800); spawn_foliage((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_mario_raceway_tree_spawns)); diff --git a/src/engine/courses/MarioRaceway.h b/src/engine/courses/MarioRaceway.h index a91226dbe..e237f1538 100644 --- a/src/engine/courses/MarioRaceway.h +++ b/src/engine/courses/MarioRaceway.h @@ -27,16 +27,13 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void SetStaffGhost() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void CreditsSpawnActors() override; virtual void Destroy() override; }; diff --git a/src/engine/courses/MooMooFarm.cpp b/src/engine/courses/MooMooFarm.cpp index cf83a920d..304ad2210 100644 --- a/src/engine/courses/MooMooFarm.cpp +++ b/src/engine/courses/MooMooFarm.cpp @@ -5,7 +5,7 @@ #include "MooMooFarm.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "assets/moo_moo_farm_data.h" #include "engine/objects/MoleGroup.h" @@ -32,6 +32,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "code_80086E70.h" + #include "course.h" extern const char *moo_moo_farm_dls[]; extern s16 currentScreenSection; extern s8 gPlayerCount; @@ -74,16 +75,24 @@ MooMooFarm::MooMooFarm() { this->gfx = d_course_moo_moo_farm_packed_dls; this->gfxSize = 3304; Props.textures = moo_moo_farm_textures; - Props.MinimapTexture = gTextureCourseOutlineMooMooFarm; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineMooMooFarm; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 271; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 18; + Props.Minimap.PlayerY = 36; + Props.Minimap.PlayerScaleFactor = 0.0155f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "moo moo farm", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "farm", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "527m", sizeof(Props.CourseLength)); - Props.Name = "moo moo farm"; - Props.DebugName = "farm"; - Props.CourseLength = "527m"; Props.AIBehaviour = D_0D009210; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 48; Props.NearPersp = 9.0f; @@ -121,10 +130,9 @@ MooMooFarm::MooMooFarm() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust0); Props.Clouds = gYoshiValleyMooMooFarmClouds; Props.CloudList = gYoshiValleyMooMooFarmClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 18, 255}; Props.Skybox.BottomRight = {197, 211, 255}; @@ -140,9 +148,9 @@ MooMooFarm::MooMooFarm() { void MooMooFarm::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_moo_moo_farm_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_moo_moo_farm_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void MooMooFarm::LoadTextures() { @@ -311,7 +319,7 @@ void MooMooFarm::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][140], 140, 3, 0.8333333f)); @@ -323,15 +331,6 @@ void MooMooFarm::BeginPlay() { } } -// Likely sets minimap boundaries -void MooMooFarm::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust0, 0x479, 0xC00)); - D_8018D2A0 = 0.0155f; - D_8018D2C0[0] = 271; - D_8018D2E0 = 18; - D_8018D2E8 = 36; -} - void MooMooFarm::WhatDoesThisDo(Player* player, int8_t playerId) { if (((s16) gNearestWaypointByPlayerId[playerId] >= 0x145) && ((s16) gNearestWaypointByPlayerId[playerId] < 0x18B)) { @@ -362,17 +361,11 @@ void MooMooFarm::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void MooMooFarm::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 MooMooFarm::Render(struct UnkStruct_800DC5EC* arg0) { s16 temp_s0 = arg0->pathCounter; s16 temp_s1 = arg0->playerDirection; - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -445,8 +438,6 @@ void MooMooFarm::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_moo_moo_farm_dl_14088)); } -void MooMooFarm::Collision() {} - void MooMooFarm::CreditsSpawnActors() { dma_textures(gTextureTrees4Left, 0x3E8, 0x800); dma_textures(gTextureTrees4Right, 0x3E8, 0x800); diff --git a/src/engine/courses/MooMooFarm.h b/src/engine/courses/MooMooFarm.h index 8b8b1b811..3c18e5024 100644 --- a/src/engine/courses/MooMooFarm.h +++ b/src/engine/courses/MooMooFarm.h @@ -30,13 +30,10 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void CreditsSpawnActors() override; virtual void Destroy() override; }; diff --git a/src/engine/courses/PodiumCeremony.cpp b/src/engine/courses/PodiumCeremony.cpp index 637dbc5d3..a4c01f588 100644 --- a/src/engine/courses/PodiumCeremony.cpp +++ b/src/engine/courses/PodiumCeremony.cpp @@ -12,6 +12,7 @@ #include "engine/objects/Podium.h" #include "engine/objects/CheepCheep.h" #include "engine/particles/StarEmitter.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -35,6 +36,7 @@ extern "C" { #include "memory.h" #include "courses/staff_ghost_data.h" #include "podium_ceremony_actors.h" + #include "course.h" extern const char *royal_raceway_dls[]; } @@ -90,15 +92,23 @@ PodiumCeremony::PodiumCeremony() { this->gfx = d_course_royal_raceway_packed_dls; this->gfxSize = 5670; Props.textures = podium_ceremony_textures; - Props.MinimapDimensions = IVector2D(0, 0); + Props.Minimap.Width = 0; + Props.Minimap.Height = 0; + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 37; + Props.Minimap.PlayerY = 50; + Props.Minimap.PlayerScaleFactor = 0.014f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "royal raceway", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "p circuit", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "1025m", sizeof(Props.CourseLength)); - Props.Name = "royal raceway"; - Props.DebugName = "p circuit"; - Props.CourseLength = "1025m"; Props.AIBehaviour = D_0D009188; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.4f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.PathSizes = {500, 500, 500, 500, 1, 0, 0, 0, 0, 0, 0}; @@ -133,10 +143,9 @@ PodiumCeremony::PodiumCeremony() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust4); Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {238, 144, 255}; Props.Skybox.BottomRight = {255, 224, 240}; @@ -147,14 +156,15 @@ PodiumCeremony::PodiumCeremony() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 224, 240}; Props.Sequence = MusicSeq::MUSIC_SEQ_UNKNOWN; + + Props.WaterLevel = -60.0f; } void PodiumCeremony::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_royal_raceway_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_royal_raceway_addr)); func_80295C6C(); - D_8015F8E4 = -60.0f; } void PodiumCeremony::LoadTextures() { @@ -189,7 +199,7 @@ void PodiumCeremony::BeginPlay() { OTrophy* trophy = reinterpret_cast<OTrophy*>(gWorldInstance.AddObject(new OTrophy(pos, type, OTrophy::Behaviour::PODIUM_CEREMONY))); - Vec3f kart = {0, 0, 0}; + FVector kart = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][3], 3, 5, 1.25f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][40], 40, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][60], 60, 0, 1.0f)); @@ -197,18 +207,10 @@ void PodiumCeremony::BeginPlay() { gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][100], 100, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][120], 120, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[3][140], 140, 0, 1.0f)); -} -// Likely sets minimap boundaries -void PodiumCeremony::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust4, 0x3F8, 0x1000)); - D_8018D2C0[0] = 262; - D_8018D2A0 = 0.014f; - D_8018D2E0 = 37; - D_8018D2E8 = 50; - D_80165718 = -64; - D_80165720 = 5; - D_80165728 = -330; + if (gGamestate != CREDITS_SEQUENCE) { + gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(-64, 5, -330))); + } } void PodiumCeremony::InitCourseObjects() { @@ -217,10 +219,6 @@ void PodiumCeremony::InitCourseObjects() { if (gModeSelection == GRAND_PRIX) { func_80070714(); } - for (i = 0; i < D_80165738; i++) { - find_unused_obj_index(&gObjectParticle3[i]); - init_object(gObjectParticle3[i], 0); - } } } @@ -257,12 +255,6 @@ void PodiumCeremony::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void PodiumCeremony::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 PodiumCeremony::Render(struct UnkStruct_800DC5EC* arg0) { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); @@ -296,6 +288,4 @@ void PodiumCeremony::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_royal_raceway_dl_D8E8)); } -void PodiumCeremony::Collision() {} - void PodiumCeremony::Destroy() { } diff --git a/src/engine/courses/PodiumCeremony.h b/src/engine/courses/PodiumCeremony.h index 140d95889..6026d7f9f 100644 --- a/src/engine/courses/PodiumCeremony.h +++ b/src/engine/courses/PodiumCeremony.h @@ -29,14 +29,11 @@ public: virtual void LoadTextures() override; virtual void BeginPlay() override; //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Destroy() override; }; diff --git a/src/engine/courses/RainbowRoad.cpp b/src/engine/courses/RainbowRoad.cpp index 11ca643b8..7c60d3af3 100644 --- a/src/engine/courses/RainbowRoad.cpp +++ b/src/engine/courses/RainbowRoad.cpp @@ -5,7 +5,7 @@ #include "RainbowRoad.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/ChainChomp.h" #include "engine/objects/BombKart.h" #include "assets/rainbow_road_data.h" @@ -30,6 +30,7 @@ extern "C" { #include "actors.h" #include "collision.h" #include "memory.h" + #include "course.h" extern const char *rainbow_road_dls[]; } @@ -48,16 +49,24 @@ RainbowRoad::RainbowRoad() { this->gfx = d_course_rainbow_road_packed_dls; this->gfxSize = 5670; Props.textures = rainbow_road_textures; - Props.MinimapTexture = gTextureCourseOutlineRainbowRoad; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineRainbowRoad; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 261; + Props.Minimap.Pos[0].Y = 166; + Props.Minimap.PlayerX = 39; + Props.Minimap.PlayerY = 55; + Props.Minimap.PlayerScaleFactor = 0.0103f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "rainbow road", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "rainbow", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "2000m", sizeof(Props.CourseLength)); - Props.Name = "rainbow road"; - Props.DebugName = "rainbow"; - Props.CourseLength = "2000m"; Props.AIBehaviour = D_0D0092C8; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.4f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 38; Props.NearPersp = 2.0f; @@ -97,8 +106,6 @@ RainbowRoad::RainbowRoad() { Props.Clouds = gToadsTurnpikeRainbowRoadStars; Props.CloudList = gToadsTurnpikeRainbowRoadStars; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 0, 0}; Props.Skybox.BottomRight = {0, 0, 0}; @@ -109,15 +116,16 @@ RainbowRoad::RainbowRoad() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; Props.Sequence = MusicSeq::MUSIC_SEQ_RAINBOW_ROAD; + + Props.WaterLevel = 0.0f; } void RainbowRoad::Load() { Course::Load(); D_800DC5C8 = 1; - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_rainbow_road_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_rainbow_road_addr)); func_80295C6C(); - D_8015F8E4 = 0.0f; // d_course_rainbow_road_packed_dl_2068 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07002068), -0x6A, 255, 255, 255); // d_course_rainbow_road_packed_dl_1E18 @@ -147,7 +155,7 @@ void RainbowRoad::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 1, 0.8333333f)); @@ -167,15 +175,6 @@ void RainbowRoad::UpdateClouds(s32 sp1C, Camera* camera) { update_stars(sp1C, camera, this->Props.CloudList); } -// Likely sets minimap boundaries -void RainbowRoad::MinimapSettings() { - D_8018D2A0 = 0.0103f; - D_8018D2C0[0] = 261; - D_8018D2D8[0] = 166; - D_8018D2E0 = 39; - D_8018D2E8 = 55; -} - void RainbowRoad::InitCourseObjects() { if (gGamestate != CREDITS_SEQUENCE) { size_t i; @@ -206,12 +205,6 @@ void RainbowRoad::WhatDoesThisDo(Player* player, int8_t playerId) {} void RainbowRoad::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void RainbowRoad::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 RainbowRoad::Render(struct UnkStruct_800DC5EC* arg0) { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); @@ -224,8 +217,6 @@ void RainbowRoad::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_rainbow_road_dl_16220)); } -void RainbowRoad::Collision() {} - void RainbowRoad::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = gCopyNearestWaypointByPlayerId[playerId]; } diff --git a/src/engine/courses/RainbowRoad.h b/src/engine/courses/RainbowRoad.h index e5262f170..282655ace 100644 --- a/src/engine/courses/RainbowRoad.h +++ b/src/engine/courses/RainbowRoad.h @@ -29,17 +29,14 @@ public: virtual void BeginPlay() override; virtual void InitClouds() override; virtual void UpdateClouds(s32, Camera*) override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; virtual void CreditsSpawnActors() override; diff --git a/src/engine/courses/RoyalRaceway.cpp b/src/engine/courses/RoyalRaceway.cpp index 7ff7579ff..849087c3f 100644 --- a/src/engine/courses/RoyalRaceway.cpp +++ b/src/engine/courses/RoyalRaceway.cpp @@ -5,9 +5,10 @@ #include "RoyalRaceway.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "assets/royal_raceway_data.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -30,6 +31,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "courses/staff_ghost_data.h" + #include "course.h" extern const char *royal_raceway_dls[]; } @@ -85,16 +87,24 @@ RoyalRaceway::RoyalRaceway() { this->gfx = d_course_royal_raceway_packed_dls; this->gfxSize = 5670; Props.textures = royal_raceway_textures; - Props.MinimapTexture = gTextureCourseOutlineRoyalRaceway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineRoyalRaceway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 37; + Props.Minimap.PlayerY = 50; + Props.Minimap.PlayerScaleFactor = 0.014f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "royal raceway", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "p circuit", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "1025m", sizeof(Props.CourseLength)); - Props.Name = "royal raceway"; - Props.DebugName = "p circuit"; - Props.CourseLength = "1025m"; Props.AIBehaviour = D_0D009188; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.4f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 9.0f; @@ -132,10 +142,9 @@ RoyalRaceway::RoyalRaceway() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust4); Props.Clouds = gRoyalRacewayClouds; Props.CloudList = gRoyalRacewayClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {238, 144, 255}; Props.Skybox.BottomRight = {255, 224, 240}; @@ -146,14 +155,15 @@ RoyalRaceway::RoyalRaceway() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 224, 240}; Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; + + Props.WaterLevel = -60.0f; } void RoyalRaceway::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_royal_raceway_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_royal_raceway_addr)); func_80295C6C(); - D_8015F8E4 = -60.0f; } void RoyalRaceway::LoadTextures() { @@ -176,7 +186,7 @@ void RoyalRaceway::BeginPlay() { spawn_piranha_plants((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_piranha_plant_spawn)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 3, 0.8333333f)); @@ -186,18 +196,9 @@ void RoyalRaceway::BeginPlay() { gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][0], 0, 0, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][0], 0, 0, 0.8333333f)); } -} - -// Likely sets minimap boundaries -void RoyalRaceway::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust4, 0x3F8, 0x1000)); - D_8018D2C0[0] = 262; - D_8018D2A0 = 0.014f; - D_8018D2E0 = 37; - D_8018D2E8 = 50; - D_80165718 = -64; - D_80165720 = 5; - D_80165728 = -330; + if (gGamestate != CREDITS_SEQUENCE) { + gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(-64, 5, -330))); + } } void RoyalRaceway::InitCourseObjects() { @@ -206,16 +207,9 @@ void RoyalRaceway::InitCourseObjects() { if (gModeSelection == GRAND_PRIX) { func_80070714(); } - for (i = 0; i < D_80165738; i++) { - find_unused_obj_index(&gObjectParticle3[i]); - init_object(gObjectParticle3[i], 0); - } } } -void RoyalRaceway::SomeSounds() { -} - void RoyalRaceway::WhatDoesThisDo(Player* player, int8_t playerId) { if (((s16) gNearestWaypointByPlayerId[playerId] >= 0x180) && ((s16) gNearestWaypointByPlayerId[playerId] < 0x1E1)) { @@ -246,12 +240,6 @@ void RoyalRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void RoyalRaceway::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 RoyalRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 16000) { @@ -298,8 +286,6 @@ void RoyalRaceway::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_royal_raceway_dl_D8E8)); } -void RoyalRaceway::Collision() {} - void RoyalRaceway::Waypoints(Player* player, int8_t playerId) { s16 waypoint = gNearestWaypointByPlayerId[playerId]; if ((waypoint >= 0x258) && (waypoint < 0x2A4)) { @@ -322,5 +308,3 @@ void RoyalRaceway::ScrollingTextures() { // d_course_royal_raceway_packed_dl_A648 find_and_set_tile_size((uintptr_t) segmented_gfx_to_virtual((void*)0x0700A648), 0, D_802B87BC); } - -void RoyalRaceway::Destroy() { } diff --git a/src/engine/courses/RoyalRaceway.h b/src/engine/courses/RoyalRaceway.h index 2a3095bc8..7fe973edd 100644 --- a/src/engine/courses/RoyalRaceway.h +++ b/src/engine/courses/RoyalRaceway.h @@ -27,17 +27,12 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; - virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void SetStaffGhost() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void ScrollingTextures() override; virtual void Waypoints(Player* player, int8_t playerId) override; - virtual void Destroy() override; }; diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp index a452d2c03..7eb7e958c 100644 --- a/src/engine/courses/SherbetLand.cpp +++ b/src/engine/courses/SherbetLand.cpp @@ -5,7 +5,7 @@ #include "SherbetLand.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "assets/sherbet_land_data.h" #include "engine/objects/Penguin.h" @@ -30,6 +30,7 @@ extern "C" { #include "actors.h" #include "collision.h" #include "memory.h" + #include "course.h" extern const char *sherbet_land_dls[]; extern const char *sherbet_land_dls_2[]; } @@ -48,19 +49,27 @@ SherbetLand::SherbetLand() { this->gfx = d_course_sherbet_land_packed_dls; this->gfxSize = 1803; Props.textures = sherbet_land_textures; - Props.MinimapTexture = gTextureCourseOutlineSherbetLand; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); - - Props.Name = "sherbet land"; - Props.DebugName = "sherbet"; - Props.CourseLength = "756m"; + Props.Minimap.Texture = gTextureCourseOutlineSherbetLand; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 52; + Props.Minimap.PlayerY = 33; + Props.Minimap.PlayerScaleFactor = 0.015f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + Props.Minimap.Colour = {72, 100, 255}; + + Props.SetText(Props.Name, "sherbet land", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "sherbet", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "756m", sizeof(Props.CourseLength)); Props.LakituTowType = (s32)OLakitu::LakituTowType::ICE; Props.AIBehaviour = D_0D009280; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 9.0f; @@ -98,10 +107,9 @@ SherbetLand::SherbetLand() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust1); Props.Clouds = gSherbetLandClouds; Props.CloudList = gSherbetLandClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {128, 184, 248}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -112,21 +120,26 @@ SherbetLand::SherbetLand() { Props.Skybox.FloorBottomLeft = {128, 184, 248}; Props.Skybox.FloorTopLeft = {216, 232, 248}; Props.Sequence = MusicSeq::MUSIC_SEQ_FRAPPE_SNOWLAND; + + Props.WaterLevel = -18.0f; } void SherbetLand::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_sherbet_land_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_sherbet_land_addr)); func_80295C6C(); - D_8015F8E4 = -18.0f; // d_course_sherbet_land_packed_dl_1EB8 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07001EB8), -0x4C, 255, 255, 255); // d_course_sherbet_land_packed_dl_2308 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07002308), -0x6A, 255, 255, 255); } -void SherbetLand::LoadTextures() { +f32 SherbetLand::GetWaterLevel(FVector pos, Collision* collision) { + if ((get_surface_type(collision->meshIndexZX) & 0xFF) == SNOW) { + return (f32) (gCourseMinY - 0xA); + } + return Props.WaterLevel; } void SherbetLand::BeginPlay() { @@ -134,65 +147,65 @@ void SherbetLand::BeginPlay() { // Multiplayer does not spawn the big penguin // if (gPlayerCountSelection1 == 1) { - Vec3f pos = {-383.0f, 2.0f, -690.0f}; + FVector pos = {-383.0f, 2.0f, -690.0f}; gWorldInstance.AddObject(new OPenguin(pos, 0, OPenguin::PenguinType::EMPEROR, OPenguin::Behaviour::STRUT)); // } - Vec3f pos2 = {-2960.0f, -80.0f, 1521.0f}; + FVector pos2 = { -2960.0f, -80.0f, 1521.0f }; auto penguin = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos2, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); auto penguin2 = reinterpret_cast<OPenguin*>(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}; + FVector pos3 = { -2490.0f, -80.0f, 1612.0f }; auto penguin3 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos3, 0x100, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); auto penguin4 = reinterpret_cast<OPenguin*>(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}; + FVector pos4 = { -2098.0f, -80.0f, 1624.0f }; auto penguin5 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos4, 0xFF00, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); auto penguin6 = reinterpret_cast<OPenguin*>(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}; + FVector pos5 = { -2080.0f, -80.0f, 1171.0f }; auto penguin7 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos5, 0x150, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE))); auto penguin8 = reinterpret_cast<OPenguin*>(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}; + FVector pos6 = { 380.0, 0.0f, -535.0f }; auto penguin9 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos6, 0x9000, OPenguin::PenguinType::CREDITS, OPenguin::Behaviour::SLIDE3))); penguin9->MirrorModeAngleOffset = -0x4000; } else { - Vec3f pos6 = {146.0f, 0.0f, -380.0f}; + FVector pos6 = { 146.0f, 0.0f, -380.0f }; auto penguin9 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos6, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE3))); penguin9->MirrorModeAngleOffset = -0x4000; } - Vec3f pos7 = {380.0f, 0.0f, -766.0f}; + FVector pos7 = { 380.0f, 0.0f, -766.0f }; auto penguin10 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos7, 0x5000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE4))); penguin10->MirrorModeAngleOffset = 0x8000; - Vec3f pos8 = {-2300.0f, 0.0f, -210.0f}; + FVector pos8 = { -2300.0f, 0.0f, -210.0f }; auto penguin11 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos8, 0xC000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); penguin11->MirrorModeAngleOffset = 0x8000; - Vec3f pos9 = {-2500.0f, 0.0f, -250.0f}; + FVector pos9 = { -2500.0f, 0.0f, -250.0f }; auto penguin12 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos9, 0x4000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); penguin12->MirrorModeAngleOffset = 0x8000; - Vec3f pos10 = {-535.0f, 0.0f, 875.0f}; + FVector pos10 = { -535.0f, 0.0f, 875.0f }; auto penguin13 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos10, 0x8000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); penguin13->MirrorModeAngleOffset = -0x4000; - Vec3f pos11 = {-250.0f, 0.0f, 953.0f}; + FVector pos11 = { -250.0f, 0.0f, 953.0f }; auto penguin14 = reinterpret_cast<OPenguin*>(gWorldInstance.AddObject(new OPenguin(pos11, 0x9000, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6))); penguin14->MirrorModeAngleOffset = -0x4000; if (gGamestate != CREDITS_SEQUENCE) { if (gModeSelection == VERSUS) { - Vec3f kart = {0, 0, 0}; + FVector kart = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[0][100], 100, 1, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(kart, &D_80164550[0][150], 150, 3, 0.8333333f)); @@ -204,21 +217,6 @@ void SherbetLand::BeginPlay() { } } -// Likely sets minimap boundaries -void SherbetLand::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust1, 0x485, 0xC00)); - D_8018D2A0 = 0.015f; - D_8018D2C0[0] = 262; - D_8018D2E0 = 52; - D_8018D2E8 = 33; - D_8018D300 = 72; - D_8018D308 = 100; - D_8018D310 = 255; -} - -void SherbetLand::InitCourseObjects() { -} - void SherbetLand::UpdateCourseObjects() { if (gGamestate != CREDITS_SEQUENCE) { func_800842C8(); @@ -231,19 +229,6 @@ void SherbetLand::RenderCourseObjects(s32 cameraId) { } } -void SherbetLand::SomeSounds() { -} - -void SherbetLand::WhatDoesThisDo(Player* player, int8_t playerId) {} - -void SherbetLand::WhatDoesThisDoAI(Player* player, int8_t playerId) {} - -// Positions the finishline on the minimap -void SherbetLand::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 SherbetLand::Render(struct UnkStruct_800DC5EC* arg0) { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -257,8 +242,6 @@ void SherbetLand::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_sherbet_land_dl_9AE8)); } -void SherbetLand::Collision() {} - void SherbetLand::DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) { Mat4 matrix; @@ -275,7 +258,7 @@ void SherbetLand::DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCoun render_course_segments(sherbet_land_dls_2, screen); gDPSetAlphaCompare(gDisplayListHead++, G_AC_NONE); - if ((func_80290C20(screen->camera) == 1) && (func_802AAB4C(screen->player) < screen->player->pos[1])) { + if ((func_80290C20(screen->camera) == 1) && (get_water_level(screen->player) < screen->player->pos[1])) { gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER); gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); @@ -291,5 +274,3 @@ void SherbetLand::CreditsSpawnActors() { // d_course_sherbet_land_packed_dl_2308 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*)0x07002308), -0x6A, 0xFF, 0xFF, 0xFF); } - -void SherbetLand::Destroy() { } diff --git a/src/engine/courses/SherbetLand.h b/src/engine/courses/SherbetLand.h index 13e41e592..eb62e2807 100644 --- a/src/engine/courses/SherbetLand.h +++ b/src/engine/courses/SherbetLand.h @@ -25,20 +25,12 @@ public: // virtual void Load(const char* courseVtx, // course_texture* textures, const char* displaylists, size_t dlSize); virtual void Load() override; - virtual void LoadTextures() override; + virtual f32 GetWaterLevel(FVector pos, Collision* collision) override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; - virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; - virtual void SomeSounds() override; - virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; - virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; virtual void CreditsSpawnActors() override; - virtual void Destroy() override; }; diff --git a/src/engine/courses/Skyscraper.cpp b/src/engine/courses/Skyscraper.cpp index abf622ae2..4c165a787 100644 --- a/src/engine/courses/Skyscraper.cpp +++ b/src/engine/courses/Skyscraper.cpp @@ -64,16 +64,24 @@ Skyscraper::Skyscraper() { this->gfx = d_course_skyscraper_packed_dls; this->gfxSize = 548; Props.textures = skyscraper_textures; - Props.MinimapTexture = gTextureCourseOutlineSkyscraper; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineSkyscraper; + 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 = 32; + Props.Minimap.PlayerY = 32; + Props.Minimap.PlayerScaleFactor = 0.0445f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "skyscraper", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "skyscraper", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength)); - Props.Name = "skyscraper"; - Props.DebugName = "skyscraper"; - Props.CourseLength = ""; Props.AIBehaviour = D_0D008F18; Props.AIMaximumSeparation = -1.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 2.0f; @@ -113,8 +121,6 @@ Skyscraper::Skyscraper() { Props.Clouds = NULL; // no clouds Props.CloudList = NULL; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {0, 0, 0}; Props.Skybox.BottomRight = {0, 0, 0}; @@ -125,6 +131,8 @@ Skyscraper::Skyscraper() { Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; Props.Sequence = MusicSeq::MUSIC_SEQ_BATTLE_ARENAS; + + Props.WaterLevel = -480.0f; } void Skyscraper::Load() { @@ -135,8 +143,6 @@ void Skyscraper::Load() { // d_course_skyscraper_packed_dl_258 generate_collision_mesh_with_default_section_id((Gfx*) segmented_gfx_to_virtual((void*)0x07000258), 1); func_80295C6C(); - - D_8015F8E4 = -480.0f; } void Skyscraper::LoadTextures() { @@ -146,7 +152,7 @@ void Skyscraper::BeginPlay() { spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_skyscraper_item_box_spawns)); if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][20], 20, 0, 1.0f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][40], 40, 0, 1.0f)); @@ -158,13 +164,6 @@ void Skyscraper::BeginPlay() { } } -// Likely sets minimap boundaries -void Skyscraper::MinimapSettings() { - D_8018D2A0 = 0.0445f; - D_8018D2E0 = 32; - D_8018D2E8 = 32; -} - void Skyscraper::InitCourseObjects() {} void Skyscraper::SomeSounds() {} @@ -173,14 +172,8 @@ void Skyscraper::WhatDoesThisDo(Player* player, int8_t playerId) {} void Skyscraper::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void Skyscraper::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 Skyscraper::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -204,8 +197,6 @@ void Skyscraper::Render(struct UnkStruct_800DC5EC* arg0) { void Skyscraper::RenderCredits() {} -void Skyscraper::Collision() {} - void Skyscraper::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = 0; } diff --git a/src/engine/courses/Skyscraper.h b/src/engine/courses/Skyscraper.h index b9b998f73..ed6592121 100644 --- a/src/engine/courses/Skyscraper.h +++ b/src/engine/courses/Skyscraper.h @@ -28,15 +28,12 @@ public: virtual void LoadTextures() override; virtual void BeginPlay() override; //virtual void InitClouds() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void Destroy() override; }; diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index 3217f8f4a..eebaee17a 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -6,7 +6,7 @@ #include "TestCourse.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/actors/BowserStatue.h" #include "engine/actors/Ship.h" #include "engine/actors/SpaghettiShip.h" @@ -16,8 +16,8 @@ #include "assets/mario_raceway_data.h" #include "assets/bowsers_castle_data.h" #include "assets/bowsers_castle_displaylists.h" -#include "engine/actors/ATree.h" -#include "engine/actors/ACloud.h" +#include "engine/actors/Tree.h" +#include "engine/actors/Cloud.h" #include "engine/vehicles/Train.h" #include "engine/objects/Trophy.h" #include "engine/objects/CheepCheep.h" @@ -28,6 +28,7 @@ #include "engine/objects/HotAirBalloon.h" #include "engine/objects/Crab.h" #include "engine/objects/Boos.h" +#include "engine/objects/GrandPrixBalloons.h" extern "C" { #include "main.h" @@ -49,12 +50,7 @@ extern "C" { #include "actors.h" #include "collision.h" #include "memory.h" - typedef struct { - Gfx* addr; - u8 surfaceType; - u8 sectionId; - u16 flags; - } TrackSections; + #include "course.h" extern Gfx test_course_dls[]; extern Vtx mario_Plane_001_mesh_vtx_1[]; extern Gfx mario_Plane_001_mesh[]; @@ -65,18 +61,27 @@ extern "C" { TestCourse::TestCourse() { this->gfxSize = 100; this->textures = NULL; - Props.MinimapTexture = gTextureCourseOutlineMarioRaceway; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); - - Props.Id = "mk:test_course"; - Props.Name = "Test Course"; - Props.DebugName = "test track"; - Props.CourseLength = "100m"; + Props.Minimap.Texture = gTextureCourseOutlineMarioRaceway; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 260; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 6; + Props.Minimap.PlayerY = 28; + Props.Minimap.PlayerScaleFactor = 0.022f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + Props.Minimap.Colour = {255, 255, 255}; + + Id = "mk:test_course"; + + Props.SetText(Props.Name, "Test Course", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "test track", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "100m", sizeof(Props.CourseLength)); Props.AIBehaviour = D_0D008F28; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.3f; - Props.SomePtr = D_800DCB34; Props.AISteeringSensitivity = 48; Props.NearPersp = 9.0f; @@ -114,10 +119,9 @@ TestCourse::TestCourse() { Props.PathTable2[2] = NULL; Props.PathTable2[3] = NULL; + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust5); Props.Clouds = gKalimariDesertClouds; Props.CloudList = gLuigiRacewayClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {120, 140, 188}; Props.Skybox.BottomRight = {216, 232, 248}; @@ -135,9 +139,9 @@ void TestCourse::Load() { generate_collision_mesh_with_defaults(mario_Plane_001_mesh); - parse_course_displaylists((TrackSectionsI*)test_course_addr); + parse_course_displaylists((TrackSections*)test_course_addr); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void TestCourse::LoadTextures() { @@ -267,7 +271,7 @@ void TestCourse::BeginPlay() { // 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, OTrashBin::Behaviour::MUNCHING)); + //gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), IRotator(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING)); //gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9)); //gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400)); @@ -285,32 +289,16 @@ void TestCourse::BeginPlay() { //gWorldInstance.AddTrain(ATrain::TenderStatus::HAS_TENDER, 5, 2.5f, 0); //gWorldInstance.AddTrain(ATrain::TenderStatus::HAS_TENDER, 5, 2.5f, 8); - Vec3f pos2 = {0, 0, 0}; + FVector pos2 = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos2, &D_80164550[0][25], 25, 4, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos2, &D_80164550[0][45], 45, 4, 0.8333333f)); gWorldInstance.AddActor(new AShip(FVector(0, 0, 0), AShip::Skin::SHIP3)); + gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(0, 0, 0))); } -// Likely sets minimap boundaries -void TestCourse::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust5, 0x443, 0x1000)); - D_8018D2A0 = 0.022f; - D_8018D2E0 = 6; - D_8018D2E8 = 28; - D_8018D2C0[0] = 260; - D_8018D2D8[0] = 170; - D_80165718 = 0; - D_80165720 = 5; - D_80165728 = -240; -} - -void TestCourse::InitCourseObjects() {} - -void TestCourse::SomeSounds() {} - void TestCourse::WhatDoesThisDo(Player* player, int8_t playerId) { if (((s16) gNearestWaypointByPlayerId[playerId] >= 0x19B) && ((s16) gNearestWaypointByPlayerId[playerId] < 0x1B9)) { @@ -341,16 +329,10 @@ void TestCourse::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void TestCourse::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 TestCourse::Render(struct UnkStruct_800DC5EC* arg0) { gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); @@ -362,13 +344,6 @@ void TestCourse::Render(struct UnkStruct_800DC5EC* arg0) { gSPDisplayList(gDisplayListHead++, mario_Plane_001_mesh); } -void TestCourse::RenderCredits() { -} - -void TestCourse::Collision() {} - -void TestCourse::Destroy() { } - bool TestCourse::IsMod() { return true; }
\ No newline at end of file diff --git a/src/engine/courses/TestCourse.h b/src/engine/courses/TestCourse.h index 3421304e2..d44e0a266 100644 --- a/src/engine/courses/TestCourse.h +++ b/src/engine/courses/TestCourse.h @@ -27,15 +27,8 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; - virtual void InitCourseObjects() override; - virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; - virtual void RenderCredits() override; - virtual void Collision() override; - virtual void Destroy() override; virtual bool IsMod() override; }; diff --git a/src/engine/courses/ToadsTurnpike.cpp b/src/engine/courses/ToadsTurnpike.cpp index a9507acad..867fedf25 100644 --- a/src/engine/courses/ToadsTurnpike.cpp +++ b/src/engine/courses/ToadsTurnpike.cpp @@ -7,7 +7,7 @@ #include "World.h" #include "engine/objects/BombKart.h" #include "assets/toads_turnpike_data.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/vehicles/Bus.h" #include "engine/vehicles/Car.h" #include "engine/vehicles/Truck.h" @@ -36,6 +36,7 @@ extern "C" { #include "collision.h" #include "memory.h" #include "code_80086E70.h" + #include "course.h" extern const char *d_course_toads_turnpike_dl_list[]; extern s16 currentScreenSection; extern s8 gPlayerCount; @@ -69,16 +70,24 @@ ToadsTurnpike::ToadsTurnpike() { this->gfx = d_course_toads_turnpike_packed_dls; this->gfxSize = 3427; Props.textures = toads_turnpike_textures; - Props.MinimapTexture = gTextureCourseOutlineToadsTurnpike; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineToadsTurnpike; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 252; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 57; + Props.Minimap.PlayerY = 44; + Props.Minimap.PlayerScaleFactor = 0.013f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "toad's turnpike", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "highway", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "1036m", sizeof(Props.CourseLength)); - Props.Name = "toad's turnpike"; - Props.DebugName = "highway"; - Props.CourseLength = "1036m"; Props.AIBehaviour = D_0D009238; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.5f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 40; Props.NearPersp = 9.0f; @@ -126,9 +135,6 @@ ToadsTurnpike::ToadsTurnpike() { this->FinishlineSpawnPoint = finish; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; - Props.Skybox.TopRight = {0, 2, 94}; Props.Skybox.BottomRight = {209, 65, 23}; Props.Skybox.BottomLeft = {209, 65, 23}; @@ -148,9 +154,9 @@ void ToadsTurnpike::Load() { D_801625F0 = 4; D_802B87B0 = 993; D_802B87B4 = 1000; - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_toads_turnpike_addr)); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_toads_turnpike_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void ToadsTurnpike::LoadTextures() { @@ -195,7 +201,7 @@ void ToadsTurnpike::BeginPlay() { } if (gModeSelection == VERSUS) { - Vec3f pos = {0, 0, 0}; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 1, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][150], 150, 3, 0.8333333f)); @@ -215,14 +221,6 @@ void ToadsTurnpike::UpdateClouds(s32 sp1C, Camera* camera) { update_stars(sp1C, camera, this->Props.CloudList); } -// Likely sets minimap boundaries -void ToadsTurnpike::MinimapSettings() { - D_8018D2A0 = 0.013f; - D_8018D2C0[0] = 252; - D_8018D2E0 = 57; - D_8018D2E8 = 44; -} - void ToadsTurnpike::SomeSounds() {} void ToadsTurnpike::WhatDoesThisDo(Player* player, int8_t playerId) { @@ -253,14 +251,8 @@ void ToadsTurnpike::WhatDoesThisDoAI(Player* player, int8_t playerId) { } } -// Positions the finishline on the minimap -void ToadsTurnpike::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 ToadsTurnpike::Render(struct UnkStruct_800DC5EC* arg0) { - func_802B5D64(D_800DC610, D_802B87D4, 0, 1); + 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); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -289,6 +281,4 @@ void ToadsTurnpike::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_toads_turnpike_dl_23930)); } -void ToadsTurnpike::Collision() {} - void ToadsTurnpike::Destroy() { } diff --git a/src/engine/courses/ToadsTurnpike.h b/src/engine/courses/ToadsTurnpike.h index a73e3829f..de145849d 100644 --- a/src/engine/courses/ToadsTurnpike.h +++ b/src/engine/courses/ToadsTurnpike.h @@ -29,14 +29,11 @@ public: virtual void BeginPlay() override; virtual void InitClouds() override; virtual void UpdateClouds(s32, Camera*) override; - virtual void MinimapSettings() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void Destroy() override; private: size_t _numTrucks = 7; diff --git a/src/engine/courses/WarioStadium.cpp b/src/engine/courses/WarioStadium.cpp index d60d754c0..b703323f4 100644 --- a/src/engine/courses/WarioStadium.cpp +++ b/src/engine/courses/WarioStadium.cpp @@ -7,8 +7,8 @@ #include "World.h" #include "engine/objects/BombKart.h" #include "assets/wario_stadium_data.h" -#include "engine/actors/AWarioSign.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/WarioSign.h" +#include "engine/actors/Finishline.h" extern "C" { #include "main.h" @@ -32,6 +32,7 @@ extern "C" { #include "code_8003DC40.h" #include "memory.h" #include "skybox_and_splitscreen.h" +#include "course.h" extern const char* wario_stadium_dls[]; extern s16 currentScreenSection; } @@ -65,16 +66,24 @@ WarioStadium::WarioStadium() { this->gfx = d_course_wario_stadium_packed_dls; this->gfxSize = 5272; Props.textures = wario_stadium_textures; - Props.MinimapTexture = gTextureCourseOutlineWarioStadium; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineWarioStadium; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.Pos[0].X = 262; + Props.Minimap.Pos[0].Y = 170; + Props.Minimap.PlayerX = 53; + Props.Minimap.PlayerY = 35; + Props.Minimap.PlayerScaleFactor = 0.0155f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "wario stadium", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "stadium", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "1591m", sizeof(Props.CourseLength)); - Props.Name = "wario stadium"; - Props.DebugName = "stadium"; - Props.CourseLength = "1591m"; Props.AIBehaviour = D_0D009310; Props.AIMaximumSeparation = 50.0f; Props.AIMinimumSeparation = 0.6f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 10.0f; @@ -122,9 +131,6 @@ WarioStadium::WarioStadium() { this->FinishlineSpawnPoint = finish; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; - Props.Skybox.TopRight = { 20, 30, 56 }; Props.Skybox.BottomRight = { 40, 60, 110 }; Props.Skybox.BottomLeft = { 40, 60, 110 }; @@ -139,9 +145,9 @@ WarioStadium::WarioStadium() { void WarioStadium::Load() { Course::Load(); - parse_course_displaylists((TrackSectionsI*) LOAD_ASSET_RAW(d_course_wario_stadium_addr)); + parse_course_displaylists((TrackSections*) LOAD_ASSET_RAW(d_course_wario_stadium_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; // d_course_wario_stadium_packed_dl_C50 find_vtx_and_set_colours(segmented_gfx_to_virtual((void*) 0x07000C50), 100, 255, 255, 255); // d_course_wario_stadium_packed_dl_BD8 @@ -166,20 +172,20 @@ void WarioStadium::LoadTextures() { void WarioStadium::BeginPlay() { spawn_all_item_boxes((struct ActorSpawnData*) LOAD_ASSET_RAW(d_course_wario_stadium_item_box_spawns)); - Vec3f pos = { -131.0f, 83.0f, 286.0f }; - pos[0] *= gCourseDirection; + FVector pos = { -131.0f, 83.0f, 286.0f }; + pos.x *= gCourseDirection; gWorldInstance.AddActor(new AWarioSign(pos)); - Vec3f pos2 = { -2353.0f, 72.0f, -1608.0f }; - pos2[0] *= gCourseDirection; + FVector pos2 = { -2353.0f, 72.0f, -1608.0f }; + pos2.x *= gCourseDirection; gWorldInstance.AddActor(new AWarioSign(pos2)); - Vec3f pos3 = { -2622.0f, 79.0f, 739.0f }; - pos3[0] *= gCourseDirection; + FVector pos3 = { -2622.0f, 79.0f, 739.0f }; + pos3.x *= gCourseDirection; gWorldInstance.AddActor(new AWarioSign(pos3)); if (gModeSelection == VERSUS) { - Vec3f pos = { 0, 0, 0 }; + FVector pos = { 0, 0, 0 }; gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][50], 50, 3, 0.8333333f)); gWorldInstance.AddObject(new OBombKart(pos, &D_80164550[0][100], 100, 1, 0.8333333f)); @@ -199,14 +205,6 @@ void WarioStadium::UpdateClouds(s32 sp1C, Camera* camera) { update_stars(sp1C, camera, this->Props.CloudList); } -// Likely sets minimap boundaries -void WarioStadium::MinimapSettings() { - D_8018D2A0 = 0.0155f; - D_8018D2C0[0] = 0x0106; - D_8018D2E0 = 53; - D_8018D2E8 = 35; -} - void WarioStadium::InitCourseObjects() { } @@ -227,13 +225,6 @@ void WarioStadium::WhatDoesThisDo(Player* player, int8_t playerId) { void WarioStadium::WhatDoesThisDoAI(Player* player, int8_t playerId) { } -// Positions the finishline on the minimap -void WarioStadium::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 WarioStadium::Jumbotron() { gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); gDPTileSync(gDisplayListHead++); @@ -365,9 +356,6 @@ void WarioStadium::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*) (d_course_wario_stadium_dl_CA78)); } -void WarioStadium::Collision() { -} - void WarioStadium::SomeCollisionThing(Player* player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) { func_8003EE2C(player, arg1, arg2, arg3, arg4, arg5, arg6, arg7); diff --git a/src/engine/courses/WarioStadium.h b/src/engine/courses/WarioStadium.h index 72f796cc7..91f613c1b 100644 --- a/src/engine/courses/WarioStadium.h +++ b/src/engine/courses/WarioStadium.h @@ -31,15 +31,12 @@ class WarioStadium : public Course { virtual void BeginPlay() override; virtual void InitClouds() override; virtual void UpdateClouds(s32, Camera*) override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void SomeCollisionThing(Player* player, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32* arg4, f32* arg5, f32* arg6, f32* arg7) override; virtual void DrawWater(struct UnkStruct_800DC5EC* screen, uint16_t pathCounter, uint16_t cameraRot, diff --git a/src/engine/courses/YoshiValley.cpp b/src/engine/courses/YoshiValley.cpp index 98d887b03..5fbcbea69 100644 --- a/src/engine/courses/YoshiValley.cpp +++ b/src/engine/courses/YoshiValley.cpp @@ -6,7 +6,7 @@ #include "YoshiValley.h" #include "World.h" -#include "engine/actors/AFinishline.h" +#include "engine/actors/Finishline.h" #include "engine/objects/BombKart.h" #include "engine/objects/Hedgehog.h" #include "engine/objects/Flagpole.h" @@ -33,6 +33,7 @@ extern "C" { #include "actors.h" #include "collision.h" #include "memory.h" + #include "course.h" extern const char *d_course_yoshi_valley_dl_list[]; } @@ -60,16 +61,22 @@ YoshiValley::YoshiValley() { this->gfxSize = 4140; Props.textures = yoshi_valley_textures; - Props.MinimapTexture = gTextureCourseOutlineYoshiValley; - Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture)); + Props.Minimap.Texture = gTextureCourseOutlineYoshiValley; + Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture); + Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture); + Props.Minimap.PlayerX = 61; + Props.Minimap.PlayerY = 38; + Props.Minimap.PlayerScaleFactor = 0.018f; + Props.Minimap.FinishlineX = 0; + Props.Minimap.FinishlineY = 0; + + Props.SetText(Props.Name, "yoshi valley", sizeof(Props.Name)); + Props.SetText(Props.DebugName, "maze", sizeof(Props.DebugName)); + Props.SetText(Props.CourseLength, "772m", sizeof(Props.CourseLength)); - Props.Name = "yoshi valley"; - Props.DebugName = "maze"; - Props.CourseLength = "772m"; Props.AIBehaviour = D_0D0090B8; Props.AIMaximumSeparation = 35.0f; Props.AIMinimumSeparation = 0.0f; - Props.SomePtr = D_800DCAF4; Props.AISteeringSensitivity = 53; Props.NearPersp = 9.0f; @@ -107,10 +114,9 @@ YoshiValley::YoshiValley() { Props.PathTable2[2] = (TrackWaypoint*)LOAD_ASSET_RAW(d_course_yoshi_valley_track_waypoints_3); Props.PathTable2[3] = (TrackWaypoint*)LOAD_ASSET_RAW(d_course_yoshi_valley_track_waypoints_4); + Props.CloudTexture = (u8*) LOAD_ASSET_RAW(gTextureExhaust0); Props.Clouds = gYoshiValleyMooMooFarmClouds; Props.CloudList = gYoshiValleyMooMooFarmClouds; - Props.MinimapFinishlineX = 0; - Props.MinimapFinishlineY = 0; Props.Skybox.TopRight = {113, 70, 255}; Props.Skybox.BottomRight = {255, 184, 99}; @@ -127,10 +133,10 @@ void YoshiValley::Load() { Course::Load(); Lights1 lights4 = gdSPDefLights1(100, 100, 100, 255, 254, 254, 0, 0, 120); - func_802B5D64(&lights4, -0x38F0, 0x1C70, 1); - parse_course_displaylists((TrackSectionsI*)LOAD_ASSET_RAW(d_course_yoshi_valley_addr)); + set_track_light_direction(&lights4, -0x38F0, 0x1C70, 1); + parse_course_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_yoshi_valley_addr)); func_80295C6C(); - D_8015F8E4 = gCourseMinY - 10.0f; + Props.WaterLevel = gCourseMinY - 10.0f; } void YoshiValley::LoadTextures() { @@ -177,31 +183,23 @@ void YoshiValley::BeginPlay() { // the original data has values here. // Note that the Y height is calculated automatically to place the kart on the surface - Vec3f pos = {-1533, 0, -682}; + FVector pos = { -1533, 0, -682 }; gWorldInstance.AddObject(new OBombKart(pos, NULL, 0, 0, 0.8333333f)); - Vec3f pos2 = {-1565, 0, -619}; + FVector pos2 = { -1565, 0, -619 }; gWorldInstance.AddObject(new OBombKart(pos2, NULL, 10, 0, 0.8333333f)); - Vec3f pos3 = {-1529, 0, -579}; + FVector pos3 = { -1529, 0, -579 }; gWorldInstance.AddObject(new OBombKart(pos3, NULL, 20, 0, 0.8333333f)); - Vec3f pos4 = {-1588, 0, -534}; + FVector pos4 = { -1588, 0, -534 }; gWorldInstance.AddObject(new OBombKart(pos4, NULL, 30, 0, 0.8333333f)); - Vec3f pos5 = {-1598, 0, -207}; + FVector pos5 = { -1598, 0, -207 }; gWorldInstance.AddObject(new OBombKart(pos5, NULL, 40, 0, 0.8333333f)); - Vec3f pos6 = {-1646, 0, -147}; + FVector pos6 = { -1646, 0, -147 }; gWorldInstance.AddObject(new OBombKart(pos6, NULL, 50, 0, 0.8333333f)); - Vec3f pos7 = {-2532, 0, -445}; + FVector pos7 = { -2532, 0, -445 }; gWorldInstance.AddObject(new OBombKart(pos7, NULL, 60, 0, 0.8333333f)); } } -// Likely sets minimap boundaries -void YoshiValley::MinimapSettings() { - D_8018D220 = reinterpret_cast<uint8_t (*)[1024]>(dma_textures(gTextureExhaust0, 0x479, 0xC00)); - D_8018D2A0 = 0.018f; - D_8018D2E0 = 61; - D_8018D2E8 = 38; -} - void YoshiValley::InitCourseObjects() { } @@ -218,12 +216,6 @@ void YoshiValley::WhatDoesThisDo(Player* player, int8_t playerId) {} void YoshiValley::WhatDoesThisDoAI(Player* player, int8_t playerId) {} -// Positions the finishline on the minimap -void YoshiValley::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 YoshiValley::Render(struct UnkStruct_800DC5EC* arg0) { gDPPipeSync(gDisplayListHead++); gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEI, G_CC_MODULATEI); @@ -237,8 +229,6 @@ void YoshiValley::RenderCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*)(d_course_yoshi_valley_dl_18020)); } -void YoshiValley::Collision() {} - void YoshiValley::Waypoints(Player* player, int8_t playerId) { player->nearestWaypointId = gCopyNearestWaypointByPlayerId[playerId]; } diff --git a/src/engine/courses/YoshiValley.h b/src/engine/courses/YoshiValley.h index a986cd902..b4ec8d442 100644 --- a/src/engine/courses/YoshiValley.h +++ b/src/engine/courses/YoshiValley.h @@ -27,17 +27,14 @@ public: virtual void Load() override; virtual void LoadTextures() override; virtual void BeginPlay() override; - virtual void MinimapSettings() override; virtual void InitCourseObjects() override; virtual void UpdateCourseObjects() override; virtual void RenderCourseObjects(s32 cameraId) override; virtual void SomeSounds() override; virtual void WhatDoesThisDo(Player* player, int8_t playerId) override; virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; - virtual void MinimapFinishlinePosition() override; virtual void Render(struct UnkStruct_800DC5EC*) override; virtual void RenderCredits() override; - virtual void Collision() override; virtual void ScrollingTextures() override; virtual void Waypoints(Player* player, int8_t playerId) override; virtual void CreditsSpawnActors() override; diff --git a/src/engine/editor/Collision.cpp b/src/engine/editor/Collision.cpp new file mode 100644 index 000000000..bf62d6273 --- /dev/null +++ b/src/engine/editor/Collision.cpp @@ -0,0 +1,188 @@ +#include "Collision.h" + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "Matrix.h" + +extern "C" { +#include "main.h" +#include "other_textures.h" +} + +namespace Editor { + void GenerateCollisionMesh(GameObject* object, Gfx* model, float scale) { + int8_t opcode; + uintptr_t lo; + uintptr_t hi; + + Gfx* ptr = model; + Vtx* vtx = NULL; + size_t i = 0; + bool run = true; + while (run) { + i++; + lo = ptr->words.w0; + hi = ptr->words.w1; + + opcode = (EDITOR_GFX_GET_OPCODE(lo) >> 24); + switch(opcode) { + case G_DL: + GenerateCollisionMesh(object, (Gfx*)hi, scale); + break; + case G_DL_OTR_HASH: + ptr++; + GenerateCollisionMesh(object, (Gfx*)ResourceGetDataByCrc(((uint64_t)(ptr->words.w0 << 32)) + ptr->words.w1), scale); + break; + case G_DL_OTR_FILEPATH: + // printf("otr filepath: %s\n", (const char*)hi); + GenerateCollisionMesh(object, (Gfx*)ResourceGetDataByName((const char*)hi), scale); + break; + case G_VTX: + vtx = (Vtx*)ptr->words.w1; + break; + case G_VTX_OTR_HASH: { + ptr++; + vtx = (Vtx*)ResourceGetDataByCrc(((uint64_t)(ptr->words.w0 << 32)) + ptr->words.w1); + break; + } + case G_VTX_OTR_FILEPATH: { + const char* filePath = (const char*)hi; + ptr++; + size_t vtxDataOff = ptr->words.w1 & 0xFFFF; + vtx = ( (Vtx*)ResourceGetDataByName(filePath) ) + vtxDataOff; + break; + } + case G_TRI1: { + if (vtx == NULL) { + ptr++; + continue; + } + uint32_t v1 = ((hi & 0x00FF0000) >> 16) / 2; + uint32_t v2 = ((hi & 0x0000FF00) >> 8) / 2; + uint32_t v3 = (hi & 0x000000FF) / 2; + + FVector p1 = FVector(vtx[v1].v.ob[0], vtx[v1].v.ob[1], vtx[v1].v.ob[2]); + FVector p2 = FVector(vtx[v2].v.ob[0], vtx[v2].v.ob[1], vtx[v2].v.ob[2]); + FVector p3 = FVector(vtx[v3].v.ob[0], vtx[v3].v.ob[1], vtx[v3].v.ob[2]); + + object->Triangles.push_back({p1, p2, p3}); + break; + } + case G_TRI1_OTR: { + if (vtx == NULL) { + ptr++; + continue; + } + + // The shift values here are different than the above. No idea why. But it has to be this way. + uint32_t v1 = (lo & 0x0000FFFF); + uint32_t v2 = (hi >> 16); + uint32_t v3 = (hi & 0x0000FFFF); + + FVector p1 = FVector(vtx[v1].v.ob[0], vtx[v1].v.ob[1], vtx[v1].v.ob[2]); + FVector p2 = FVector(vtx[v2].v.ob[0], vtx[v2].v.ob[1], vtx[v2].v.ob[2]); + FVector p3 = FVector(vtx[v3].v.ob[0], vtx[v3].v.ob[1], vtx[v3].v.ob[2]); + + object->Triangles.push_back({p1, p2, p3}); + + break; + } + case G_TRI2: { + if (vtx == NULL) { + ptr++; + continue; + } + uint32_t v1 = ((lo & 0x00FF0000) >> 16) / 2; + uint32_t v2 = ((lo & 0x0000FF00) >> 8) / 2; + uint32_t v3 = (lo & 0x000000FF) / 2; + + // This is actually triangle 2; vert 1,2,3. + uint32_t v4 = ((hi & 0x00FF0000) >> 16) / 2; + uint32_t v5 = ((hi & 0x0000FF00) >> 8) / 2; + uint32_t v6 = (hi & 0x000000FF) / 2; + + FVector p1 = FVector(vtx[v1].v.ob[0], vtx[v1].v.ob[1], vtx[v1].v.ob[2]); + FVector p2 = FVector(vtx[v2].v.ob[0], vtx[v2].v.ob[1], vtx[v2].v.ob[2]); + FVector p3 = FVector(vtx[v3].v.ob[0], vtx[v3].v.ob[1], vtx[v3].v.ob[2]); + + FVector p4 = FVector(vtx[v4].v.ob[0], vtx[v4].v.ob[1], vtx[v4].v.ob[2]); + FVector p5 = FVector(vtx[v5].v.ob[0], vtx[v5].v.ob[1], vtx[v5].v.ob[2]); + FVector p6 = FVector(vtx[v6].v.ob[0], vtx[v6].v.ob[1], vtx[v6].v.ob[2]); + + object->Triangles.push_back({p1, p2, p3}); + object->Triangles.push_back({p4, p5, p6}); + break; + } + case G_QUAD: { + if (vtx == NULL) { + ptr++; + continue; + } + uint32_t v1 = ((hi & 0x00FF0000) >> 16) / 2; + uint32_t v2 = ((hi & 0x0000FF00) >> 8) / 2; + uint32_t v3 = (hi & 0x000000FF) / 2; + uint32_t v4 = ((hi & 0xFF000000) >> 24) / 2; + + FVector p1 = FVector(vtx[v1].v.ob[0], vtx[v1].v.ob[1], vtx[v1].v.ob[2]); + FVector p2 = FVector(vtx[v2].v.ob[0], vtx[v2].v.ob[1], vtx[v2].v.ob[2]); + FVector p3 = FVector(vtx[v3].v.ob[0], vtx[v3].v.ob[1], vtx[v3].v.ob[2]); + FVector p4 = FVector(vtx[v4].v.ob[0], vtx[v4].v.ob[1], vtx[v4].v.ob[2]); + + object->Triangles.push_back({p1, p2, p3}); + object->Triangles.push_back({p1, p3, p4}); + break; + } + case G_ENDDL: + run = false; + break; + } + + ptr++; + } + } + + std::unordered_map<GameObject*, std::vector<Vtx>> gDebugObjVtxCache; + + // Render a collision model + void DebugCollision(GameObject* obj, FVector pos, IRotator rot, FVector scale, const std::vector<Triangle>& triangles) { + if (obj == NULL || triangles.empty()) { + return; + } + + gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); + + auto& vtxBuffer = gDebugObjVtxCache[obj]; + if (vtxBuffer.empty()) { + for (const auto& tri : triangles) { + vtxBuffer.push_back({(s16)tri.v0.x, (s16)tri.v0.y, (s16)tri.v0.z, 0, {0, 0}, {255, 255, 255, 255}}); + vtxBuffer.push_back({(s16)tri.v1.x, (s16)tri.v1.y, (s16)tri.v1.z, 0, {0, 0}, {255, 255, 255, 255}}); + vtxBuffer.push_back({(s16)tri.v2.x, (s16)tri.v2.y, (s16)tri.v2.z, 0, {0, 0}, {255, 255, 255, 255}}); + } + } + + // Setup matrix and render state + Mat4 mtx; + ApplyMatrixTransformations(mtx, pos, rot, scale); + Editor_AddMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPSetGeometryMode(gDisplayListHead++, G_FOG); + gDPPipeSync(gDisplayListHead++); + gDPSetCombineMode(gDisplayListHead++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gSPTexture(gDisplayListHead++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); + gDPSetRenderMode(gDisplayListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2); + uint32_t hash = (uint32_t)((uintptr_t)obj ^ ((uintptr_t)obj >> 16)); + u8 r = (hash >> 16) & 0xFF; + u8 g = (hash >> 8) & 0xFF; + u8 b = hash & 0xFF; + + gDPSetPrimColor(gDisplayListHead++, 0, 0, r, g, b, 255); + + // Render triangles in batches of 3 + for (size_t i = 0; i + 2 < vtxBuffer.size(); i += 3) { + gSPVertex(gDisplayListHead++, (uintptr_t)&vtxBuffer[i], 3, 0); + gSP1Triangle(gDisplayListHead++, 0, 1, 2, 0); + } + + gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK | G_ZBUFFER); + } +} diff --git a/src/engine/editor/Collision.h b/src/engine/editor/Collision.h new file mode 100644 index 000000000..ee8fef4af --- /dev/null +++ b/src/engine/editor/Collision.h @@ -0,0 +1,23 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "GameObject.h" + +#include "EditorMath.h" + +/** + * @file Editor Collision + * + * Most actors use cylinder collision. + * Proper vtx intersection tests are necessary for object picking + * + * Therefore, generate a full collision mesh for actors + */ + +#define EDITOR_GFX_GET_OPCODE(var) ((uint32_t) ((var) & 0xFF000000)) + +namespace Editor { + void GenerateCollisionMesh(GameObject* object, Gfx* model, float scale); + void DebugCollision(GameObject* obj, FVector pos, IRotator rot, FVector scale, const std::vector<Triangle>& triangles); +}
\ No newline at end of file diff --git a/src/engine/editor/Editor.cpp b/src/engine/editor/Editor.cpp new file mode 100644 index 000000000..446da7487 --- /dev/null +++ b/src/engine/editor/Editor.cpp @@ -0,0 +1,166 @@ +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "../CoreMath.h" +#include <libultra/types.h> +#include "../World.h" + +#include "Editor.h" +#include "Collision.h" +#include "Light.h" + +#include "port/Engine.h" +#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h> +#include <window/Window.h> + +#include "engine/actors/Ship.h" +#include "port/Game.h" + +extern "C" { +#include "common_structs.h" +#include "main.h" +#include "defines.h" +#include "actors.h" +#include "camera.h" +} + +namespace Editor { + int gfx_create_framebuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height, + uint8_t resize); + + Editor::Editor() { + } + + void Editor::Load() { + printf("Editor: Loading Editor...\n"); + eObjectPicker.Load(); + for (auto& object : eGameObjects) { + GenerateCollisionMesh(object, object->Model, 1.0f); + object->Load(); + } + printf("Editor: Loading Complete!\n"); + } + + void Editor::Tick() { + + if (CVarGetInteger("gEditorEnabled", 0) == true) { + bEditorEnabled = true; + } else { + bEditorEnabled = false; + return; + } + + auto wnd = GameEngine::Instance->context->GetWindow(); + + static bool wasMouseDown = false; + static bool isDragging = false; + static Ship::Coords mouseStartPos; + + Ship::Coords mousePos = wnd->GetMousePos(); + bool isMouseDown = wnd->GetMouseState(Ship::LUS_MOUSE_BTN_LEFT); + + eGameObjects.erase( + std::remove_if(eGameObjects.begin(), eGameObjects.end(), + [](const auto& object) { return (*object->DespawnFlag) == object->DespawnValue; }), + eGameObjects.end()); + + if (isMouseDown && !wasMouseDown) { + // Mouse just pressed (Pressed state) + mouseStartPos = mousePos; + isDragging = false; + } + + if (isMouseDown) { + // Mouse is being held (Held state) + int dx = mousePos.x - mouseStartPos.x; + int dy = mousePos.y - mouseStartPos.y; + int dragThreshold = 5; // Adjust as needed + + if ((dx * dx + dy * dy) > (dragThreshold * dragThreshold)) { + // Squared distance check to avoid unnecessary sqrt() + isDragging = true; + eObjectPicker.DragHandle(); // Call drag logic + } + } + + if (!isMouseDown && wasMouseDown) { + // Mouse just released (Released state) + eObjectPicker.eGizmo.SelectedHandle = Gizmo::GizmoHandle::None; + eObjectPicker.eGizmo.ManipulationStart = true; + if (!isDragging) { + eObjectPicker.SelectObject(eGameObjects); + } + + } + + wasMouseDown = isMouseDown; // Update previous state + + eObjectPicker.Tick(); + + for (auto& object : eGameObjects) { + object->Tick(); + } + } + + void Editor::Draw() { + if (!bEditorEnabled) { + return; + } + eObjectPicker.Draw(); + for (auto& object : eGameObjects) { + object->Draw(); + } + } + + GameObject* Editor::AddObject(const char* name, FVector* pos, IRotator* rot, FVector* scale, Gfx* model, float collScale, GameObject::CollisionType collision, float boundingBoxSize, int32_t* despawnFlag, int32_t despawnValue) { + //printf("After AddObj: Pos(%f, %f, %f), Name: %s, Model: %s\n", + // pos->x, pos->y, pos->z, name, model); + if (model != nullptr) { + eGameObjects.push_back(new GameObject(name, pos, rot, scale, model, {}, collision, boundingBoxSize, despawnFlag, despawnValue)); + GenerateCollisionMesh(eGameObjects.back(), model, collScale); + } else { // to bounding box or sphere collision + eGameObjects.push_back(new GameObject(name, pos, rot, scale, model, {}, GameObject::CollisionType::BOUNDING_BOX, + 10.0f, despawnFlag, despawnValue)); + } + return eGameObjects.back(); + } + + void Editor::AddLight(const char* name, FVector* pos, s8* rot) { + eGameObjects.push_back(new LightObject(name, pos, rot)); + } + + void Editor::ClearObjects() { + for (auto& obj : eGameObjects) { + delete obj; + } + eGameObjects.clear(); + } + + void Editor::DeleteObject() { + GameObject* obj = eObjectPicker.eGizmo._selected; + + if (obj) { + *obj->DespawnFlag = obj->DespawnValue; + obj = nullptr; + eObjectPicker._selected = nullptr; + } + } + + void Editor::ClearMatrixPool() { + EditorMatrix.clear(); + } + + void Editor::SelectObjectFromSceneExplorer(GameObject* object) { + eObjectPicker._selected = object; + eObjectPicker.eGizmo.Enabled = true; + eObjectPicker.eGizmo.SetGizmoNoCursor(object); + } + + void Editor::SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY) { + eObjectPicker.eGizmo.dimensions.MinX = minX + -1000; + eObjectPicker.eGizmo.dimensions.MaxX = maxX + 1000; + eObjectPicker.eGizmo.dimensions.MinY = minY + -100; + eObjectPicker.eGizmo.dimensions.MaxY = maxY + 500; + eObjectPicker.eGizmo.dimensions.MinZ = minZ + -1000; + eObjectPicker.eGizmo.dimensions.MaxZ = maxZ + 1000; + } +} diff --git a/src/engine/editor/Editor.h b/src/engine/editor/Editor.h new file mode 100644 index 000000000..759c59355 --- /dev/null +++ b/src/engine/editor/Editor.h @@ -0,0 +1,47 @@ +#ifndef __EDITOR_H__ +#define __EDITOR_H__ + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "GameObject.h" + +#ifdef __cplusplus + +#include "ObjectPicker.h" +namespace Editor { + class ObjectPicker; + + class Editor { +public: + Editor(); + + ObjectPicker eObjectPicker; + std::vector<GameObject*> eGameObjects; + + void Tick(); + void Draw(); + void Load(); + GameObject* AddObject(const char* name, FVector* pos, IRotator* rot, FVector* scale, Gfx* model, float collScale, GameObject::CollisionType collision, float boundingBoxSize, int32_t* despawnFlag, int32_t despawnValue); + void AddLight(const char* name, FVector* pos, s8* rot); + void ClearObjects(); + void RemoveObject(); + void SelectObjectFromSceneExplorer(GameObject* object); + void SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY); + void ClearMatrixPool(); + void DeleteObject(); + bool bEditorEnabled = false; + +private: + bool _draw = false; + Vec3f _ray; + + s32 Inverse(MtxF* src, MtxF* dest); + void Copy(MtxF* src, MtxF* dest); + void Clear(MtxF* mf); +}; +} +#endif + +void SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY); + +#endif // __EDITOR_H__ diff --git a/src/engine/editor/EditorMath.cpp b/src/engine/editor/EditorMath.cpp new file mode 100644 index 000000000..533c0c2b5 --- /dev/null +++ b/src/engine/editor/EditorMath.cpp @@ -0,0 +1,427 @@ +#include "EditorMath.h" + +#include <libultraship/libultraship.h> +#include "port/Game.h" +#include "port/Engine.h" +#include <libultra/types.h> +#include "GameObject.h" + +#include <vector> +#include <limits> +#include <cmath> + +extern "C" { +#include "common_structs.h" +#include "main.h" +#include "defines.h" +#include "actors.h" +#include "math_util.h" +#include "math_util_2.h" +#include "camera.h" +} + +std::vector<Mtx> EditorMatrix; + +bool IsInGameScreen() { + auto wnd = GameEngine::Instance->context->GetWindow(); + Ship::Coords mouse = wnd->GetMousePos(); + + // Define viewport boundaries + int left = gfx_current_game_window_viewport.x; + int right = left + OTRGetGameRenderWidth(); + int top = gfx_current_game_window_viewport.y; + int bottom = top + OTRGetGameRenderHeight(); + + // Check if the mouse is within the game render area + return (mouse.x >= left && mouse.x < right) && (mouse.y >= top && mouse.y < bottom); +} + +FVector ScreenRayTrace() { + auto wnd = GameEngine::Instance->context->GetWindow(); + Camera* camera = &cameras[0]; + + Ship::Coords mouse = wnd->GetMousePos(); + mouse.x -= gfx_current_game_window_viewport.x; + mouse.y -= gfx_current_game_window_viewport.y; + // Get screen dimensions + uint32_t width = OTRGetGameViewportWidth(); + uint32_t height = OTRGetGameViewportHeight(); + + // Convert mouse to NDS screen coordinates + float x = (2.0f * mouse.x) / width - 1.0f; // Normalized X: -1 to 1 + float y = 1.0f - (2.0f * mouse.y) / height; // Normalized Y: -1 to 1 + float z = 1.0f; // z is typically 1.0 for the near plane + + FVector4 rayClip = {x, y, z, 1.0f}; + + Mat4 perspMtx; + u16 perspNorm; + guPerspectiveF(perspMtx, &perspNorm, gCameraZoom[0], OTRGetAspectRatio(), CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f); + + Mat4 inversePerspMtx; + if (InverseMatrix((float*)&perspMtx, (float*)&inversePerspMtx) != 2) { + FVector4 rayEye = MultiplyMatrixVector(inversePerspMtx, (float*)&rayClip.x); + + Mat4 lookAtMtx; + guLookAtF(lookAtMtx, camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0], camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]); + Mat4 inverseViewMtx; + if (InverseMatrix((float*)&lookAtMtx, (float*)&inverseViewMtx[0][0]) != 2) { + rayEye.w = 0; + FVector4 invRayWor = MultiplyMatrixVector(inverseViewMtx, (float*)&rayEye.x); + + FVector direction; + direction = FVector(invRayWor.x, invRayWor.y, invRayWor.z); + + return direction; + } + } + return FVector(0, 0, 0); +} + +bool QueryCollisionRayActor(Vec3f rayOrigin, Vec3f rayDir, Vec3f actorMin, Vec3f actorMax, float* t) { + float tmin = -FLT_MAX, tmax = FLT_MAX; + + for (int i = 0; i < 3; i++) { + if (fabs(rayDir[i]) > 1e-6f) { // Avoid division by zero + float t1 = (actorMin[i] - rayOrigin[i]) / rayDir[i]; + float t2 = (actorMax[i] - rayOrigin[i]) / rayDir[i]; + + if (t1 > t2) { float temp = t1; t1 = t2; t2 = temp; } + + tmin = fmax(tmin, t1); + tmax = fmin(tmax, t2); + + if (tmax < tmin) return false; // No intersection + } else if (rayOrigin[i] < actorMin[i] || rayOrigin[i] > actorMax[i]) { + return false; // Ray is outside the slab + } + } + + *t = tmin; // Distance to first intersection + return true; +} + +FVector4 MultiplyMatrixVector(float matrix[4][4], float vector[4]) { + FVector4 result; + float* resultPtr = &result.x; + for (int i = 0; i < 4; i++) { + resultPtr[i] = 0; + for (int j = 0; j < 4; j++) { + resultPtr[i] += matrix[j][i] * vector[j]; // Swap [i][j] → [j][i] for column order + } + } + return result; +} + +// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix +static bool InverseMatrix(const float m[16], float invOut[16]) { + float inv[16], det; + int i; + + inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + + inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - + m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + + inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; + + inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - + m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; + + inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - + m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + + inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + + inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - + m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; + + inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; + + inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; + + inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - + m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; + + inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; + + inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - + m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; + + inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - + m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; + + inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; + + inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - + m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; + + inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - + m[8] * m[2] * m[5]; + + det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + + if (det == 0) { + return false; + } + + det = 1.0 / det; + + for (i = 0; i < 16; i++) { + invOut[i] = inv[i] * det; + } + + return true; +} + +FVector TransformVecByMatrix(const FVector& vec, const float mtx[4][4]) { + FVector result; + result.x = vec.x * mtx[0][0] + vec.y * mtx[1][0] + vec.z * mtx[2][0] + mtx[3][0]; + result.y = vec.x * mtx[0][1] + vec.y * mtx[1][1] + vec.z * mtx[2][1] + mtx[3][1]; + result.z = vec.x * mtx[0][2] + vec.y * mtx[1][2] + vec.z * mtx[2][2] + mtx[3][2]; + return result; +} + +FVector TransformVecDirection(const FVector& dir, const float mtx[4][4]) { + FVector result; + result.x = dir.x * mtx[0][0] + dir.y * mtx[1][0] + dir.z * mtx[2][0]; + result.y = dir.x * mtx[0][1] + dir.y * mtx[1][1] + dir.z * mtx[2][1]; + result.z = dir.x * mtx[0][2] + dir.y * mtx[1][2] + dir.z * mtx[2][2]; + return result; +} + +Ray RayToLocalSpace(MtxF mtx, const Ray& ray) { + MtxF inverse; + + if (InverseMatrix((float*)&mtx, (float*)&inverse) != 2) { + FVector localRayOrigin = TransformVecByMatrix(ray.Origin, (float(*)[4])&inverse); + FVector localRayDir = TransformVecDirection(ray.Direction, (float(*)[4])&inverse); + return Ray{localRayOrigin, localRayDir.Normalize()}; + } + return Ray{}; // Fail. Return empty ray +} + +bool IntersectRayTriangle(const Ray& ray, const Triangle& tri, float& t) { + constexpr float EPSILON = 1e-6f; + + // Adjust the triangle vertices by the object's position + FVector v0 = tri.v0; + FVector v1 = tri.v1; + FVector v2 = tri.v2; + + FVector edge1 = v1 - v0; + FVector edge2 = v2 - v0; + FVector h = ray.Direction.Cross(edge2); + float a = edge1.Dot(h); + + if (std::abs(a) < EPSILON) + return false; // Ray is parallel to triangle + + float f = 1.0f / a; + FVector s = ray.Origin - v0; + float u = f * s.Dot(h); + + if (u < 0.0f || u > 1.0f) + return false; + + FVector q = s.Cross(edge1); + float v = f * ray.Direction.Dot(q); + + if (v < 0.0f || u + v > 1.0f) + return false; + + t = f * edge2.Dot(q); + return t > EPSILON; +} + +bool IntersectRayTriangleAndTransform(const Ray& ray, FVector pos, const Triangle& tri, float& t) { + constexpr float EPSILON = 1e-6f; + + // Adjust the triangle vertices by the object's position + FVector v0 = tri.v0 + pos; + FVector v1 = tri.v1 + pos; + FVector v2 = tri.v2 + pos; + + FVector edge1 = v1 - v0; + FVector edge2 = v2 - v0; + FVector h = ray.Direction.Cross(edge2); + float a = edge1.Dot(h); + + if (std::abs(a) < EPSILON) + return false; // Ray is parallel to triangle + + float f = 1.0f / a; + FVector s = ray.Origin - v0; + float u = f * s.Dot(h); + + if (u < 0.0f || u > 1.0f) + return false; + + FVector q = s.Cross(edge1); + float v = f * ray.Direction.Dot(q); + + if (v < 0.0f || u + v > 1.0f) + return false; + + t = f * edge2.Dot(q); + return t > EPSILON; +} + +std::optional<FVector> QueryHandleIntersection(MtxF mtx, Ray ray, const Triangle& tri) { + float t; + Ray localRay = RayToLocalSpace(mtx, ray); + if (IntersectRayTriangle(localRay, tri, t)) { + FVector localClickPosition = localRay.Origin + localRay.Direction * t; + FVector worldClickPosition = TransformVecByMatrix(localClickPosition, (float(*)[4])&mtx); + + return worldClickPosition; // Stop checking objects if we selected a Gizmo handle + } + return std::nullopt; +} + +bool IntersectRaySphere(const Ray& ray, const FVector& sphereCenter, float radius, float& t) { + const float EPSILON = 1e-6f; + + // Vector from ray origin to sphere center + FVector oc = ray.Origin - sphereCenter; + + // Quadratic equation coefficients + float a = ray.Direction.Dot(ray.Direction); + float b = 2.0f * oc.Dot(ray.Direction); + float c = oc.Dot(oc) - (radius * radius); + + // Compute discriminant + float discriminant = (b * b) - (4 * a * c); + + // No intersection if discriminant is negative + if (discriminant < 0) { + return false; + } + + // Compute nearest intersection point + float sqrtD = sqrtf(discriminant); + float t0 = (-b - sqrtD) / (2.0f * a); + float t1 = (-b + sqrtD) / (2.0f * a); + + // Select the closest valid intersection + if (t0 > EPSILON) { + t = t0; + return true; + } else if (t1 > EPSILON) { + t = t1; + return true; + } + + return false; // Sphere is behind the ray origin +} + +// bool FindClosestObject(const Ray& ray, const std::vector<GameObject*>& objects, GameObject* outObject, float& outDistance) { +// float closestDist = std::numeric_limits<float>::max(); +// bool found = false; + +// for (const auto& obj : objects) { +// for (const auto& tri : obj.Triangles) { +// float t; +// if (IntersectRayTriangle(ray, tri, *obj.Pos, t) && t < closestDist) { +// closestDist = t; +// outObject = obj; +// found = true; +// } +// } +// } + +// if (found) { +// outDistance = closestDist; +// return true; +// } + +// return false; +// } + +// Transform a matrix to a matrix identity +void Editor_MatrixIdentity(Mat4 mtx) { + register s32 i; + register s32 k; + + for (i = 0; i < 4; i++) { + for (k = 0; k < 4; k++) { + mtx[i][k] = (i == k) ? 1.0f : 0.0f; + } + } +} + +void Editor_AddMatrix(Mat4 mtx, int32_t flags) { + EditorMatrix.emplace_back(); + guMtxF2L(mtx, &EditorMatrix.back()); + gSPMatrix(gDisplayListHead++, &EditorMatrix.back(), flags); +} + +float CalculateAngle(const FVector& start, const FVector& end) { + float dot = start.Dot(end); + + float magStart = start.Magnitude(); + float magEnd = end.Magnitude(); + + float cosAngle = dot / (magStart * magEnd); + cosAngle = std::min(1.0f, std::max(-1.0f, cosAngle)); + + return acos(cosAngle); +} + +void SetDirectionFromRotator(IRotator rot, s8 direction[3]) { + float yaw = (rot.yaw) * (M_PI / 32768.0f); // Convert from n64 binary angles 0-0xFFFF 0-360 degrees to radians + float pitch = rot.pitch * (M_PI / 32768.0f); + + // Compute unit direction vector + float x = cosf(yaw) * cosf(pitch); + float y = -sinf(pitch); + float z = -sinf(yaw) * cosf(pitch); + + // Scale into -127 to 127 range (not 128 to avoid overflow) + direction[0] = static_cast<s8>(x * 127.0f); + direction[1] = static_cast<s8>(y * 127.0f); + direction[2] = static_cast<s8>(z * 127.0f); + + //printf("Light dir %d %d %d (from rot 0x%X 0x%X 0x%X)\n", direction[0], direction[1], direction[2], rotator[0], rotator[1], rotator[2]); +} + +void SetRotatorFromDirection(FVector direction, IRotator* rot) { + // Compute pitch (inverse of -sinf(pitch)) + float pitch = -asinf(direction.y); + + // Compute yaw (inverse of cosf(yaw) * cosf(pitch)) + float yaw = atan2f(-direction.z, direction.x); + + // Convert back to N64 angles (0-0xFFFF range) + rot->pitch = (s16)(pitch * (32768.0f / M_PI)); + rot->yaw = (s16)(yaw * (32768.0f / M_PI)); + rot->roll = 0; // Assume no roll, since it's undefined from direction alone +} + +FVector GetPositionAheadOfCamera(f32 dist) { + FVector pos = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]); + + f32 pitch = (cameras[0].rot[2] / 65535.0f) * 360.0f; + f32 yaw = (cameras[0].rot[1] / 65535.0f) * 360.0f; + + // Convert degrees to radians + pitch = pitch * M_PI / 180.0f; + yaw = yaw * M_PI / 180.0f; + + // Compute forward vector + FVector forward( + -sinf(yaw), // X + -sinf(pitch), // Y + cosf(yaw) // Z (vertical component) + ); + + // Move 1000 units forward from the camera position + return pos + (forward * dist); +} diff --git a/src/engine/editor/EditorMath.h b/src/engine/editor/EditorMath.h new file mode 100644 index 000000000..abc694976 --- /dev/null +++ b/src/engine/editor/EditorMath.h @@ -0,0 +1,58 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include <libultra/types.h> +#include "../CoreMath.h" +#include <vector> +#include "GameObject.h" + +extern "C" { +#include "common_structs.h" +} + +extern std::vector<Mtx> EditorMatrix; + +struct Ray { + FVector Origin; + FVector Direction; +}; + +struct Triangle { + FVector v0, v1, v2; +}; + +/** + * Projects 2D cursor into the game world + * + * @return FVector ray direction + * + * ray.x = camera->pos[0] + direction.x * length; + * ray.y = camera->pos[1] + direction.y * length; + * ray.z = camera->pos[2] + direction.z * length; + */ +bool IsInGameScreen(); +FVector ScreenRayTrace(); +bool QueryCollisionRayActor(Vec3f rayOrigin, Vec3f rayDir, Vec3f actorMin, Vec3f actorMax, float* t); +FVector4 MultiplyMatrixVector(float matrix[4][4], float vector[4]); +static bool InverseMatrix(const float m[16], float invOut[16]); +void Copy(MtxF* src, MtxF* dest); +void Clear(MtxF* mf); + +FVector TransformVecByMatrix(const FVector& vec, const float mtx[4][4]); +FVector TransformVecDirection(const FVector& dir, const float mtx[4][4]); +Ray RayToLocalSpace(MtxF mtx, const Ray& ray); +bool IntersectRayTriangle(const Ray& ray, const Triangle& tri, float& t); // Uses local space not global space. +bool IntersectRayTriangleAndTransform(const Ray& ray, FVector pos, const Triangle& tri, float& t); // Uses global space because no access to mtx +bool IntersectRaySphere(const Ray& ray, const FVector& sphereCenter, float radius, float& t); +/** + * optional used here so we can check for successful query and return the click position + */ +std::optional<FVector> QueryHandleIntersection(MtxF mtx, Ray ray, const Triangle& tri); + +void Editor_MatrixIdentity(Mat4 mtx); +void Editor_AddMatrix(Mat4 mtx, int32_t flags); +float CalculateAngle(const FVector& start, const FVector& end); +void SetDirectionFromRotator(IRotator rot, s8 direction[3]); +void SetRotatorFromDirection(FVector direction, IRotator* rot); +FVector GetPositionAheadOfCamera(f32 dist); diff --git a/src/engine/editor/GameObject.cpp b/src/engine/editor/GameObject.cpp new file mode 100644 index 000000000..6f52c8ac8 --- /dev/null +++ b/src/engine/editor/GameObject.cpp @@ -0,0 +1,30 @@ +#include <libultraship/libultraship.h> +#include "GameObject.h" + +namespace Editor { + + GameObject::GameObject(const char* name, FVector* pos, IRotator* rot, FVector* scale, Gfx* model, std::vector<Triangle> triangles, CollisionType collision, float boundingBoxSize, int32_t* despawnFlag, int32_t despawnValue) { + Name = name; + Pos = pos; + Rot = rot; + Scale = scale; + Model = model; + Triangles = triangles; + Collision = collision; + BoundingBoxSize = boundingBoxSize; + DespawnFlag = despawnFlag; + DespawnValue = despawnValue; + } + + GameObject::GameObject(FVector* pos, Vec3s* rot) { + //Pos = pos; + //Rot = rot; + } + + GameObject::GameObject() {}; + + void GameObject::Draw(){}; + + void GameObject::Tick(){}; + +} // namespace Editor diff --git a/src/engine/editor/GameObject.h b/src/engine/editor/GameObject.h new file mode 100644 index 000000000..ca08d8ba9 --- /dev/null +++ b/src/engine/editor/GameObject.h @@ -0,0 +1,44 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include <libultra/types.h> +#include "../CoreMath.h" +#include "EditorMath.h" +#include <vector> + +extern "C" { +#include "common_structs.h" +} + +struct Triangle; + +namespace Editor { + class GameObject { +public: + enum class CollisionType { + VTX_INTERSECT, + BOUNDING_BOX, + BOUNDING_SPHERE + }; + + GameObject(const char* name, FVector* pos, IRotator* rot, FVector* scale, Gfx* model, std::vector<Triangle> triangles, CollisionType collision, float boundingBoxSize, int32_t* despawnFlag, int32_t despawnValue); + GameObject(FVector* pos, Vec3s* rot); + GameObject(); + virtual void Tick(); + virtual void Draw(); + virtual void Load() {}; + + const char* Name; + FVector* Pos; + IRotator* Rot; + FVector* Scale; + Gfx* Model; + std::vector<Triangle> Triangles; + CollisionType Collision; + float BoundingBoxSize; + int32_t* DespawnFlag; + int32_t DespawnValue; + + }; +} diff --git a/src/engine/editor/Gizmo.cpp b/src/engine/editor/Gizmo.cpp new file mode 100644 index 000000000..4987242f0 --- /dev/null +++ b/src/engine/editor/Gizmo.cpp @@ -0,0 +1,348 @@ +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "../CoreMath.h" +#include <libultra/types.h> +#include "../World.h" + +#include "EditorMath.h" +#include "Gizmo.h" +#include "Collision.h" +#include "port/Engine.h" +#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h> +#include <window/Window.h> + + +#include "engine/actors/Ship.h" +#include "port/Game.h" +#include "Handles.h" + +extern "C" { +#include "common_structs.h" +#include "main.h" +#include "actors.h" +#include "camera.h" +#include "src/racing/collision.h" +#include "math_util.h" +} + +namespace Editor { + +void Gizmo::Load() { + /* Translate handle collision */ + RedCollision.Pos = &Pos; + RedCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_red"; + + GreenCollision.Pos = &Pos; + GreenCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_green"; + + BlueCollision.Pos = &Pos; + BlueCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_blue"; + + /* Rotate handle collision */ + RedRotateCollision.Pos = &Pos; + RedRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_red"; + + GreenRotateCollision.Pos = &Pos; + GreenRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_green"; + + BlueRotateCollision.Pos = &Pos; + BlueRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_blue"; + + /* Scale handle collision */ + RedScaleCollision.Pos = &Pos; + RedScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_red"; + + GreenScaleCollision.Pos = &Pos; + GreenScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_green"; + + BlueScaleCollision.Pos = &Pos; + BlueScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_blue"; + + GenerateCollisionMesh(&RedCollision, (Gfx*)LOAD_ASSET_RAW(RedCollision.Model), 1.0f); + GenerateCollisionMesh(&GreenCollision, (Gfx*)LOAD_ASSET_RAW(GreenCollision.Model), 1.0f); + GenerateCollisionMesh(&BlueCollision, (Gfx*)LOAD_ASSET_RAW(BlueCollision.Model), 1.0f); + + GenerateCollisionMesh(&RedRotateCollision, (Gfx*)LOAD_ASSET_RAW(RedRotateCollision.Model), 1.0f); + GenerateCollisionMesh(&GreenRotateCollision, (Gfx*)LOAD_ASSET_RAW(GreenRotateCollision.Model), 1.0f); + GenerateCollisionMesh(&BlueRotateCollision, (Gfx*)LOAD_ASSET_RAW(BlueRotateCollision.Model), 1.0f); + + GenerateCollisionMesh(&RedScaleCollision, (Gfx*)LOAD_ASSET_RAW(RedScaleCollision.Model), 1.0f); + GenerateCollisionMesh(&GreenScaleCollision, (Gfx*)LOAD_ASSET_RAW(GreenScaleCollision.Model), 1.0f); + GenerateCollisionMesh(&BlueScaleCollision, (Gfx*)LOAD_ASSET_RAW(BlueScaleCollision.Model), 1.0f); +} + +void Gizmo::Tick() { + if (Enabled) { + TranslationMode mode = static_cast<TranslationMode>(CVarGetInteger("eGizmoMode", 0)); + switch(mode) { + case TranslationMode::Move: + Gizmo::Translate(); + break; + case TranslationMode::Rotate: + Gizmo::Rotate(); + break; + case TranslationMode::Scale: + Gizmo::Scale(); + break; + } + } +} + +// Makes the gizmo visible +void Gizmo::SetGizmo(GameObject* object, Ray ray) { + _selected = object; + _ray = ray.Direction; + Pos = FVector( + object->Pos->x, + object->Pos->y, + object->Pos->z + ); +} + +void Gizmo::SetGizmoNoCursor(GameObject* object) { + _selected = object; + Pos = FVector( + object->Pos->x, + object->Pos->y, + object->Pos->z + ); +} + +void Gizmo::Translate() { + static float length = 180.0f; // Default value + + // Prevent nullptr exceptions + if (_selected == NULL || _selected->Pos == NULL) { + return; + } + + if (Enabled) { + length = sqrt( + pow(_selected->Pos->x - cameras[0].pos[0], 2) + + pow(_selected->Pos->y - cameras[0].pos[1], 2) + + pow(_selected->Pos->z - cameras[0].pos[2], 2) + ); + + switch(SelectedHandle) { + case GizmoHandle::All_Axis: + _selected->Pos->x = (cameras[0].pos[0] + _ray.x * PickDistance) + _cursorOffset.x; + _selected->Pos->y = (cameras[0].pos[1] + _ray.y * PickDistance) + _cursorOffset.y; + _selected->Pos->z = (cameras[0].pos[2] + _ray.z * PickDistance) + _cursorOffset.z; + if (CVarGetInteger("gEditorSnapToGround", 0) == true) { + _selected->Pos->y = SnapToSurface(_selected->Pos); + } + break; + case GizmoHandle::X_Axis: + _selected->Pos->x = (cameras[0].pos[0] + _ray.x * length) + _cursorOffset.x; + if (CVarGetInteger("gEditorSnapToGround", 0) == true) { + _selected->Pos->y = SnapToSurface(_selected->Pos); + } + break; + case GizmoHandle::Y_Axis: + _selected->Pos->y = (cameras[0].pos[1] + _ray.y * length) + _cursorOffset.y; + break; + case GizmoHandle::Z_Axis: + _selected->Pos->z = (cameras[0].pos[2] + _ray.z * length) + _cursorOffset.z; + if (CVarGetInteger("gEditorSnapToGround", 0) == true) { + _selected->Pos->y = SnapToSurface(_selected->Pos); + } + break; + } + + if (CVarGetInteger("gEditorBoundary", 0) == true) { + _selected->Pos->x = MAX(_selected->Pos->x, dimensions.MinX); + _selected->Pos->x = MIN(_selected->Pos->x, dimensions.MaxX); + + _selected->Pos->y = MAX(_selected->Pos->y, dimensions.MinY); + _selected->Pos->y = MIN(_selected->Pos->y, dimensions.MaxY); + + _selected->Pos->z = MAX(_selected->Pos->z, dimensions.MinZ); + _selected->Pos->z = MIN(_selected->Pos->z, dimensions.MaxZ); + } + + Pos = FVector( + _selected->Pos->x, + _selected->Pos->y, + _selected->Pos->z + ); + } +} + +f32 Gizmo::SnapToSurface(FVector* pos) { + float y; + y = spawn_actor_on_surface(pos->x, 2000.0f, pos->z); + + if (y == 3000.0f || y == -3000.0f) { + y = pos->y; + } + + return y; +} + +void Gizmo::Rotate() { + FVector cam = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]); + + if (_selected == nullptr || _selected->Rot == nullptr) { + return; + } + + // Store initial scale at the beginning of the drag + if (ManipulationStart) { + ManipulationStart = false; + InitialRotation = *_selected->Rot; // Store initial rotation + } + + // Initial click position + FVector clickPos = *_selected->Pos - _cursorOffset; + + // Calculate difference + FVector diff = (cam + _ray * PickDistance) - clickPos; + + // Set rotation sensitivity + diff = diff * 100.0f; + switch (SelectedHandle) { + case GizmoHandle::X_Axis: + _selected->Rot->pitch = (uint16_t)InitialRotation.pitch + diff.x; + break; + case GizmoHandle::Y_Axis: + _selected->Rot->yaw = (uint16_t)InitialRotation.yaw + diff.y; + break; + case GizmoHandle::Z_Axis: + _selected->Rot->roll = (uint16_t)InitialRotation.roll + diff.z; + break; + } +} + +void Gizmo::Scale() { + FVector cam = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]); + if (_selected == nullptr || _selected->Scale == nullptr) { + return; + } + + // Store initial scale at the beginning of the drag + if (ManipulationStart) { + ManipulationStart = false; + InitialScale = *_selected->Scale; + } + + // Initial click position + FVector clickPos = *_selected->Pos - _cursorOffset; + + // Calculate difference + FVector diff = (cam + _ray * PickDistance) - clickPos; + + // Lower scaling sensitivity + diff = diff * 0.01f; + + switch (SelectedHandle) { + case GizmoHandle::X_Axis: + _selected->Scale->x = InitialScale.x + -diff.x; + break; + case GizmoHandle::Y_Axis: + _selected->Scale->y = InitialScale.y + diff.y; + break; + case GizmoHandle::Z_Axis: + _selected->Scale->z = InitialScale.z + -diff.z; + break; + case GizmoHandle::All_Axis: + float uniformScale = (diff.x - diff.y - diff.z) / 3.0f; + uniformScale *= 1.8; // Increased sensitivity + _selected->Scale->x = uniformScale; + _selected->Scale->y = uniformScale; + _selected->Scale->z = uniformScale; + break; + } +} + +void Gizmo::Draw() { + if (Enabled) { + DrawHandles(); + //DebugCollision(&RedCollision, Pos, {0, 0, 0}, {0.05f, 0.05f, 0.05f}, RedCollision.Triangles); + //DebugCollision(&BlueCollision, Pos, {90, 0, 0}, {0.05f, 0.05f, 0.05f}, BlueCollision.Triangles); + //DebugCollision(&GreenCollision, Pos, {0, 90, 0}, {0.05f, 0.05f, 0.05f}, GreenCollision.Triangles); + //DebugCollision(&RedRotateCollision, Pos, {0, 0, 0}, {0.15f, 0.15f, 0.15f}, RedRotateCollision.Triangles); + //DebugCollision((uintptr_t)_selected, Pos, BlueRotateCollision.Triangles); + //DebugCollision((uintptr_t)_selected, Pos, GreenRotateCollision.Triangles); + } +} + +void Gizmo::DrawHandles() { + Mat4 mainMtx; + Editor_MatrixIdentity((float(*)[4])&Mtx_RedX); + Editor_MatrixIdentity((float(*)[4])&Mtx_GreenY); + Editor_MatrixIdentity((float(*)[4])&Mtx_BlueZ); + + const char* blueHandle; + const char* greenHandle; + const char* redHandle; + const char* center = nullptr; + IRotator blueRot; + IRotator greenRot; + IRotator redRot; + FVector scale = {0.05f, 0.05f, 0.05f}; + + switch(static_cast<TranslationMode>(CVarGetInteger("eGizmoMode", 0))) { + case TranslationMode::Move: + center = "__OTR__editor/gizmo/center_handle"; + blueHandle = "__OTR__editor/gizmo/translate_handle_blue"; + greenHandle = "__OTR__editor/gizmo/translate_handle_green"; + redHandle = "__OTR__editor/gizmo/translate_handle_red"; + _gizmoOffset = 8.0f; + greenRot = {0, 90, 0}; + blueRot = {90, 0, 0}; + scale = {0.3, 0.3, 0.3}; + break; + case TranslationMode::Rotate: + center = nullptr; // No All_Axis drag button for Rotation + blueHandle = "__OTR__editor/gizmo/rot_handle_blue"; + greenHandle = "__OTR__editor/gizmo/rot_handle_green"; + redHandle = "__OTR__editor/gizmo/rot_handle_red"; + _gizmoOffset = 0.0f; + scale = {0.15f, 0.15f, 0.15f}; + break; + case TranslationMode::Scale: + center = "__OTR__editor/gizmo/center_handle"; + blueHandle = "__OTR__editor/gizmo/scale_handle_blue"; + greenHandle = "__OTR__editor/gizmo/scale_handle_green"; + redHandle = "__OTR__editor/gizmo/scale_handle_red"; + _gizmoOffset = 8.0f; + greenRot = {0, 90, 0}; + blueRot = {90, 0, 0}; + scale = {0.05f, 0.05f, 0.05f}; + break; + } + + ApplyMatrixTransformations(mainMtx, Pos, Rot, {1, 1, 1}); + Editor_AddMatrix(mainMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + if (center) { + Mat4 CenterMtx; + Editor_MatrixIdentity(CenterMtx); + + // Calculate camera-to-object distance + FVector cameraDir = FVector(Pos.x - cameras[0].pos[0], Pos.y - cameras[0].pos[1], Pos.z - cameras[0].pos[2]); + cameraDir = cameraDir.Normalize(); + + IRotator centerRot; + SetRotatorFromDirection(cameraDir, ¢erRot); + centerRot.pitch += 0x4000; // Align mesh to face camera since it was not exported facing the correct direction + centerRot.yaw += 0x4000; + + ApplyMatrixTransformations(CenterMtx, Pos, centerRot, FVector(0.06f, 0.06f, 0.06f)); + Editor_AddMatrix(CenterMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)center); + } + + ApplyMatrixTransformations((float(*)[4])&Mtx_RedX, FVector(Pos.x, Pos.y, Pos.z - _gizmoOffset), Rot, scale); + Editor_AddMatrix((float(*)[4])&Mtx_RedX, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)redHandle); + + ApplyMatrixTransformations((float(*)[4])&Mtx_GreenY, FVector(Pos.x - _gizmoOffset, Pos.y, Pos.z), greenRot, scale); + Editor_AddMatrix((float(*)[4])&Mtx_GreenY, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)greenHandle); + + ApplyMatrixTransformations((float(*)[4])&Mtx_BlueZ, FVector(Pos.x, Pos.y + _gizmoOffset, Pos.z), blueRot, scale); + Editor_AddMatrix((float(*)[4])&Mtx_BlueZ, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)blueHandle); +} +} diff --git a/src/engine/editor/Gizmo.h b/src/engine/editor/Gizmo.h new file mode 100644 index 000000000..47ef99549 --- /dev/null +++ b/src/engine/editor/Gizmo.h @@ -0,0 +1,85 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "Collision.h" +#include "GameObject.h" + +namespace Editor { + +class Gizmo { +public: + + enum class GizmoHandle { + None, + All_Axis, + X_Axis, + Y_Axis, + Z_Axis + }; + + enum class TranslationMode { + Move, + Rotate, + Scale + }; + + void Tick(); + void Draw(); + void Load(); + + void SetGizmo(GameObject* object, Ray ray); + void SetGizmoNoCursor(GameObject* object); // Used for scene explorer selection + void Translate(); + void Rotate(); + void Scale(); + void DrawHandles(); + f32 SnapToSurface(FVector* pos); + + struct TrackDimensions { + s16 MinX = -10000; + s16 MaxX = 10000; + s16 MinY = -3000; + s16 MaxY = 3000; + s16 MinZ = -10000; + s16 MaxZ = 10000; + }; + TrackDimensions dimensions; + + bool Enabled; + bool ManipulationStart = true; + FVector InitialScale = {1, 1, 1}; + IRotator InitialRotation = {0, 0, 0}; + GizmoHandle SelectedHandle; + + GameObject RedCollision; + GameObject GreenCollision; + GameObject BlueCollision; + + GameObject RedRotateCollision; + GameObject GreenRotateCollision; + GameObject BlueRotateCollision; + + GameObject RedScaleCollision; + GameObject GreenScaleCollision; + GameObject BlueScaleCollision; + + MtxF Mtx_RedX; + MtxF Mtx_GreenY; + MtxF Mtx_BlueZ; + + FVector Pos; // Global scene view + IRotator Rot = {0, 0, 0}; + float AllAxisRadius = 3.0f; // Free move selection radius + float PickDistance; + FVector _cursorOffset; + float _gizmoOffset = 8.0f; + + float HandleSize = 2.0f; + + FVector _ray; + GameObject* _selected = nullptr; + private: + bool _draw = false; +}; +} diff --git a/src/engine/editor/Handles.cpp b/src/engine/editor/Handles.cpp new file mode 100644 index 000000000..9074a2b45 --- /dev/null +++ b/src/engine/editor/Handles.cpp @@ -0,0 +1,23 @@ +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> + +#include "Handles.h" + +namespace Editor { + Handles::Handles() { + Pos = &pos; + Rot = &rot; + } + + void Handles::Load() { + + } + + void Handles::Tick() { + + } + + void Handles::Draw() { + + } +}
\ No newline at end of file diff --git a/src/engine/editor/Handles.h b/src/engine/editor/Handles.h new file mode 100644 index 000000000..1faa4b59e --- /dev/null +++ b/src/engine/editor/Handles.h @@ -0,0 +1,19 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "GameObject.h" + +namespace Editor { + class Handles : public GameObject { + + Handles(); + + virtual void Tick() override; + virtual void Draw() override; + virtual void Load() override; + + FVector pos; + IRotator rot; + }; +} diff --git a/src/engine/editor/Light.cpp b/src/engine/editor/Light.cpp new file mode 100644 index 000000000..594383bd3 --- /dev/null +++ b/src/engine/editor/Light.cpp @@ -0,0 +1,84 @@ +#include <iostream> +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "../CoreMath.h" +#include <libultra/types.h> +#include "../World.h" + +#include "Light.h" +#include "port/Engine.h" +#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h> +#include <window/Window.h> + +#include "engine/actors/Ship.h" +#include "port/Game.h" +#include "Gizmo.h" + +#include "EditorMath.h" + +extern "C" { +#include "common_structs.h" +#include "main.h" +#include "defines.h" +#include "actors.h" +#include "camera.h" +#include "math_util.h" +#include "math_util_2.h" +} + +namespace Editor { + +size_t LightObject::NumLights = 0; + + LightObject::LightObject(const char* name, FVector* pos, s8* direction) : GameObject(nullptr, nullptr) { + Name = name; + Pos = &LightPos; + Rot = &LightRot; + Scale = &LightScale; + + DespawnFlag = &_despawnFlag; + DespawnValue = -1; + + Direction = direction; + + Collision = CollisionType::BOUNDING_BOX; + BoundingBoxSize = 4.0f; + + NumLights += 1; + } + + void LightObject::Load() { + } + + void LightObject::Tick() { + SetDirectionFromRotator(*Rot, Direction); + } + void LightObject::Draw() { + Mat4 mtx_sun; + Editor_MatrixIdentity(mtx_sun); + gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); + gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); + + + // Calculate camera-to-object distance + FVector cameraDir = FVector(LightPos.x - cameras[0].pos[0], LightPos.y - cameras[0].pos[1], LightPos.z - cameras[0].pos[2]); + cameraDir = cameraDir.Normalize(); + + IRotator centerRot; + SetRotatorFromDirection(cameraDir, ¢erRot); + + // Account for object not facing the correct direction when exported + centerRot.yaw += 0x4000; + ApplyMatrixTransformations(mtx_sun, LightPos, centerRot, LightScale); + Editor_AddMatrix(mtx_sun, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, sun_LightModel_mesh); + + // Draw Arrow + Mat4 mtx_arrow; + IRotator rot = LightRot; + rot.yaw += 0x4000; + ApplyMatrixTransformations(mtx_arrow, LightPos, rot, LightScale); + Editor_AddMatrix(mtx_arrow, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)"__OTR__editor/light/sun_arrow"); + } +} diff --git a/src/engine/editor/Light.h b/src/engine/editor/Light.h new file mode 100644 index 000000000..972942663 --- /dev/null +++ b/src/engine/editor/Light.h @@ -0,0 +1,2143 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "Collision.h" +#include "Gizmo.h" +#include "GameObject.h" + +namespace Editor { + +class LightObject : public GameObject { +public: + LightObject(const char* name, FVector* pos, s8* direction); + + virtual void Draw() override; + virtual void Tick() override; + virtual void Load() override; + + static size_t NumLights; + FVector LightPos = FVector(0, 100, 0); + IRotator LightRot = IRotator(0, 0, 0); + FVector LightScale = FVector(0.1, 0.1, 0.1); + s8* Direction; + s32 _despawnFlag = 0; + +u8 sun_sun_rgba32[16384] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xed, 0x8e, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xe4, 0x85, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfb, 0x9d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xdb, 0x7d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xac, 0x01, 0xff, + 0xe5, 0x87, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xae, 0x01, 0xff, + 0xd1, 0x72, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xba, 0x00, 0xff, + 0xff, 0xaa, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xc4, 0x01, 0xff, 0xfe, 0xba, 0x00, 0xff, + 0xc6, 0x67, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xc9, 0x00, 0xff, + 0xff, 0xc8, 0x01, 0xff, 0xda, 0x7c, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xd9, 0x00, 0xff, + 0xff, 0xd1, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xd8, 0x00, 0xff, + 0xff, 0xd8, 0x01, 0xff, 0xfe, 0xa2, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xe5, 0x00, 0xff, + 0xff, 0xde, 0x00, 0xff, 0xff, 0xb8, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xe9, 0x01, 0xff, 0xff, 0xcc, 0x01, 0xff, + 0xcd, 0x6f, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xf9, 0x00, 0xff, 0xff, 0xf3, 0x00, 0xff, + 0xff, 0xec, 0x00, 0xff, 0xff, 0xae, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf5, 0x00, 0xff, + 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf2, 0x00, 0xff, + 0xf8, 0x99, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xfa, 0x01, 0xff, 0xff, 0xa5, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xca, 0x00, 0xff, 0xc1, 0x63, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xfd, 0x01, 0xff, 0xf6, 0x98, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xef, 0x91, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf6, 0x01, 0xff, 0xef, 0x91, 0x00, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf9, 0x01, 0xff, 0xeb, 0x8c, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xfe, 0xa0, 0x01, 0xff, + 0xef, 0x91, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfd, 0x9e, 0x00, 0xff, + 0xff, 0xa4, 0x00, 0xff, 0xcf, 0x70, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xc6, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xf3, 0x01, 0xff, 0xdc, 0x7e, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xc2, 0x01, 0xff, + 0xff, 0xb3, 0x00, 0xff, 0xff, 0xa4, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xb3, 0x01, 0xff, 0xff, 0xb9, 0x01, 0xff, + 0xe2, 0x84, 0x01, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xf7, 0x01, 0xff, + 0xe1, 0x82, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xec, 0x00, 0xff, 0xcd, 0x6e, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xe4, 0x00, 0xff, + 0xff, 0xd7, 0x01, 0xff, 0xff, 0xc9, 0x01, 0xff, + 0xff, 0xb9, 0x00, 0xff, 0xcf, 0x70, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xc0, 0x00, 0xff, 0xff, 0xc7, 0x00, 0xff, + 0xff, 0xcf, 0x01, 0xff, 0xf8, 0x99, 0x01, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xbe, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xe5, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf8, 0x00, 0xff, 0xff, 0xeb, 0x00, 0xff, + 0xff, 0xde, 0x00, 0xff, 0xff, 0xcf, 0x00, 0xff, + 0xe1, 0x82, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xd5, 0x00, 0xff, + 0xfe, 0xdc, 0x00, 0xff, 0xff, 0xe7, 0x01, 0xff, + 0xff, 0xb2, 0x00, 0xff, 0xd0, 0x72, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xf7, 0x00, 0xff, 0xea, 0x8b, 0x00, 0xff, + 0xfc, 0x9e, 0x00, 0xff, 0xff, 0xb0, 0x01, 0xff, + 0xff, 0xb1, 0x00, 0xff, 0xff, 0xa2, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xdc, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xf4, 0x00, 0xff, + 0xff, 0xe7, 0x01, 0xff, 0xf6, 0x98, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xe1, 0x00, 0xff, + 0xff, 0xea, 0x00, 0xff, 0xff, 0xf3, 0x01, 0xff, + 0xfe, 0xfc, 0x00, 0xff, 0xfe, 0xcb, 0x00, 0xff, + 0xe2, 0x84, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xa2, 0x00, 0xff, 0xfe, 0xb5, 0x00, 0xff, + 0xff, 0xc9, 0x01, 0xff, 0xff, 0xda, 0x01, 0xff, + 0xff, 0xe1, 0x01, 0xff, 0xff, 0xe6, 0x01, 0xff, + 0xff, 0xe7, 0x01, 0xff, 0xff, 0xe2, 0x01, 0xff, + 0xff, 0xda, 0x01, 0xff, 0xfe, 0xcb, 0x00, 0xff, + 0xff, 0xbd, 0x00, 0xff, 0xff, 0xaa, 0x01, 0xff, + 0xf1, 0x93, 0x00, 0xff, 0xda, 0x7c, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xfd, 0x00, 0xff, + 0xff, 0xb0, 0x00, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xff, 0xf5, 0x01, 0xff, 0xff, 0xfe, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xe3, 0x00, 0xff, 0xff, 0xa0, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xb7, 0x00, 0xff, + 0xff, 0xd4, 0x00, 0xff, 0xff, 0xdc, 0x01, 0xff, + 0xff, 0xe2, 0x01, 0xff, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xee, 0x00, 0xff, 0xfe, 0xf3, 0x00, 0xff, + 0xfe, 0xf7, 0x00, 0xff, 0xff, 0xfd, 0x00, 0xff, + 0xfe, 0xfc, 0x00, 0xff, 0xfe, 0xf9, 0x00, 0xff, + 0xff, 0xf5, 0x01, 0xff, 0xff, 0xf0, 0x01, 0xff, + 0xff, 0xe9, 0x00, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xff, 0xdc, 0x00, 0xff, 0xff, 0xd4, 0x00, 0xff, + 0xff, 0xb9, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xcb, 0x01, 0xff, + 0xce, 0x6f, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xca, 0x00, 0xff, 0xd5, 0x76, 0x01, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xfa, 0x9b, 0x01, 0xff, + 0xfe, 0xd2, 0x00, 0xff, 0xfe, 0xe2, 0x00, 0xff, + 0xff, 0xf0, 0x00, 0xff, 0xfe, 0xf5, 0x00, 0xff, + 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xfe, 0x01, 0xff, + 0xff, 0xf7, 0x00, 0xff, 0xfe, 0xf0, 0x00, 0xff, + 0xff, 0xe4, 0x01, 0xff, 0xff, 0xd4, 0x01, 0xff, + 0xff, 0xa7, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xe2, 0x01, 0xff, 0xe0, 0x82, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xd4, 0x75, 0x00, 0xff, + 0xff, 0xbb, 0x00, 0xff, 0xfe, 0xd7, 0x00, 0xff, + 0xff, 0xe8, 0x01, 0xff, 0xff, 0xf7, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf8, 0x00, 0xff, 0xff, 0xeb, 0x00, 0xff, + 0xff, 0xda, 0x00, 0xff, 0xff, 0xc1, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfb, 0x9d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xf6, 0x98, 0x01, 0xff, 0xff, 0xcb, 0x01, 0xff, + 0xff, 0xdc, 0x01, 0xff, 0xff, 0xed, 0x01, 0xff, + 0xff, 0xfb, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xf1, 0x01, 0xff, 0xff, 0xdf, 0x00, 0xff, + 0xff, 0xcc, 0x00, 0xff, 0xf6, 0x97, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xc6, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xca, 0x00, 0xff, 0xfe, 0xe3, 0x00, 0xff, + 0xfe, 0xf3, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xf5, 0x00, 0xff, + 0xff, 0xe3, 0x00, 0xff, 0xff, 0xca, 0x01, 0xff, + 0xd1, 0x73, 0x01, 0xff, 0xcf, 0x71, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xbc, 0x01, 0xff, + 0xff, 0xdb, 0x00, 0xff, 0xff, 0xf4, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xf3, 0x01, 0xff, 0xff, 0xd9, 0x01, 0xff, + 0xff, 0xb6, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xfd, 0x9f, 0x00, 0xff, 0xff, 0xd3, 0x00, 0xff, + 0xff, 0xec, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xe7, 0x00, 0xff, + 0xff, 0xd1, 0x01, 0xff, 0xf1, 0x92, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xc9, 0x01, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xfe, 0xf8, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf5, 0x01, 0xff, + 0xff, 0xe0, 0x01, 0xff, 0xff, 0xc8, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcf, 0x71, 0x00, 0xff, 0xc7, 0x68, 0x01, 0xff, + 0xbd, 0x5e, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0xff, 0xaa, 0x00, 0xff, + 0xff, 0xd8, 0x01, 0xff, 0xff, 0xef, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xed, 0x00, 0xff, 0xff, 0xd7, 0x01, 0xff, + 0xff, 0xa9, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xf6, 0x00, 0xff, + 0xff, 0xe7, 0x01, 0xff, 0xff, 0xd7, 0x01, 0xff, + 0xff, 0xc7, 0x01, 0xff, 0xff, 0xb8, 0x01, 0xff, + 0xff, 0xa7, 0x00, 0xff, 0xf6, 0x98, 0x00, 0xff, + 0xe7, 0x89, 0x01, 0xff, 0xd9, 0x7b, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x99, 0x00, 0xff, 0xff, 0xa6, 0x00, 0xff, + 0xff, 0xac, 0x00, 0xff, 0xff, 0xa4, 0x00, 0xff, + 0xfa, 0x9b, 0x01, 0xff, 0xf0, 0x91, 0x00, 0xff, + 0xe4, 0x85, 0x00, 0xff, 0xd9, 0x7a, 0x01, 0xff, + 0xcb, 0x6c, 0x00, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xca, 0x6b, 0x01, 0xff, 0xff, 0xc5, 0x00, 0xff, + 0xff, 0xe4, 0x01, 0xff, 0xfe, 0xfa, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xfb, 0x01, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xff, 0xc5, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, + 0xff, 0xe7, 0x00, 0xff, 0xff, 0xd7, 0x00, 0xff, + 0xff, 0xc5, 0x00, 0xff, 0xff, 0xb4, 0x00, 0xff, + 0xf4, 0x95, 0x00, 0xff, 0xd0, 0x71, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xaf, 0x00, 0xff, + 0xff, 0xbc, 0x01, 0xff, 0xff, 0xca, 0x01, 0xff, + 0xff, 0xd9, 0x00, 0xff, 0xff, 0xe9, 0x01, 0xff, + 0xff, 0xec, 0x00, 0xff, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xe2, 0x01, 0xff, 0xff, 0xdc, 0x00, 0xff, + 0xff, 0xd5, 0x00, 0xff, 0xff, 0xcd, 0x01, 0xff, + 0xdf, 0x80, 0x00, 0xff, 0xfe, 0xcb, 0x00, 0xff, + 0xff, 0xe9, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xcc, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xfa, 0x00, 0xff, + 0xff, 0xe0, 0x00, 0xff, 0xff, 0xb8, 0x00, 0xff, + 0xec, 0x8e, 0x01, 0xff, 0xc4, 0x65, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xc4, 0x00, 0xff, 0xff, 0xd1, 0x00, 0xff, + 0xff, 0xdf, 0x01, 0xff, 0xfe, 0xed, 0x00, 0xff, + 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xf4, 0x96, 0x01, 0xff, 0xff, 0xd1, 0x00, 0xff, + 0xff, 0xee, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xec, 0x01, 0xff, + 0xff, 0xd0, 0x00, 0xff, 0xec, 0x8d, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xe4, 0x01, 0xff, 0xfe, 0xb5, 0x00, 0xff, + 0xe2, 0x83, 0x01, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xfe, 0xe4, 0x00, 0xff, 0xff, 0xf2, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xa8, 0x00, 0xff, 0xff, 0xd6, 0x00, 0xff, + 0xff, 0xf3, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xef, 0x00, 0xff, + 0xff, 0xd5, 0x01, 0xff, 0xff, 0xa0, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xe3, 0x00, 0xff, 0xff, 0xaf, 0x00, 0xff, + 0xd8, 0x79, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0xf7, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xb5, 0x00, 0xff, 0xff, 0xdb, 0x01, 0xff, + 0xff, 0xf6, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf4, 0x01, 0xff, + 0xff, 0xd9, 0x00, 0xff, 0xfe, 0xb1, 0x00, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xa6, 0x00, 0xff, + 0xc9, 0x6a, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xc3, 0x00, 0xff, 0xff, 0xe0, 0x01, 0xff, + 0xff, 0xf9, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf7, 0x00, 0xff, + 0xff, 0xde, 0x01, 0xff, 0xfe, 0xc2, 0x00, 0xff, + 0xd0, 0x72, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xe5, 0x87, 0x01, 0xff, + 0xff, 0xc9, 0x01, 0xff, 0xfe, 0xe2, 0x00, 0xff, + 0xff, 0xfb, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xfa, 0x00, 0xff, + 0xff, 0xe2, 0x01, 0xff, 0xff, 0xc9, 0x01, 0xff, + 0xe1, 0x83, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xfe, 0xff, 0x00, 0xff, 0xf4, 0x95, 0x01, 0xff, + 0xff, 0xcd, 0x01, 0xff, 0xff, 0xe5, 0x00, 0xff, + 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xfd, 0x01, 0xff, + 0xff, 0xe4, 0x00, 0xff, 0xff, 0xcc, 0x00, 0xff, + 0xf2, 0x93, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbb, 0x5d, 0x00, 0xff, 0xf1, 0x92, 0x01, 0xff, + 0xff, 0xca, 0x00, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xfb, 0x00, 0xff, + 0xff, 0xe3, 0x00, 0xff, 0xff, 0xcb, 0x00, 0xff, + 0xf2, 0x93, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xdd, 0x7f, 0x00, 0xff, + 0xff, 0xc4, 0x00, 0xff, 0xff, 0xdd, 0x00, 0xff, + 0xff, 0xf6, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xf7, 0x00, 0xff, + 0xff, 0xde, 0x01, 0xff, 0xfe, 0xc4, 0x00, 0xff, + 0xe1, 0x82, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xca, 0x6b, 0x01, 0xff, + 0xff, 0xbb, 0x00, 0xff, 0xff, 0xd7, 0x00, 0xff, + 0xff, 0xf1, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf2, 0x01, 0xff, + 0xff, 0xd9, 0x01, 0xff, 0xff, 0xbc, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0xbf, 0x60, 0x00, 0xff, + 0xfc, 0x9e, 0x00, 0xff, 0xff, 0xdb, 0x00, 0xff, + 0xfe, 0xa8, 0x00, 0xff, 0xfe, 0xcf, 0x00, 0xff, + 0xff, 0xea, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xed, 0x01, 0xff, + 0xff, 0xd1, 0x00, 0xff, 0xff, 0xac, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xfe, 0x01, 0xff, + 0xff, 0xf0, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xcd, 0x6f, 0x00, 0xff, + 0xff, 0xa5, 0x01, 0xff, 0xff, 0xd9, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xf2, 0x94, 0x00, 0xff, 0xff, 0xc9, 0x01, 0xff, + 0xff, 0xe3, 0x00, 0xff, 0xff, 0xfb, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xfc, 0x01, 0xff, 0xff, 0xe6, 0x01, 0xff, + 0xff, 0xc9, 0x00, 0xff, 0xf9, 0x9b, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xf9, 0x01, 0xff, + 0xff, 0xea, 0x01, 0xff, 0xff, 0xdd, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xd6, 0x77, 0x01, 0xff, + 0xff, 0xa9, 0x00, 0xff, 0xff, 0xd7, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xdc, 0x7e, 0x00, 0xff, 0xfe, 0xc1, 0x00, 0xff, + 0xff, 0xdd, 0x01, 0xff, 0xfe, 0xf4, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf6, 0x01, 0xff, 0xff, 0xdf, 0x01, 0xff, + 0xff, 0xc2, 0x00, 0xff, 0xe4, 0x86, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xf3, 0x00, 0xff, + 0xff, 0xe3, 0x00, 0xff, 0xff, 0xd5, 0x01, 0xff, + 0xff, 0xc7, 0x01, 0xff, 0xff, 0xb9, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5e, 0x01, 0xff, 0xde, 0x80, 0x00, 0xff, + 0xff, 0xaa, 0x01, 0xff, 0xff, 0xd3, 0x00, 0xff, + 0xff, 0xed, 0x01, 0xff, 0xff, 0xfd, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xba, 0x00, 0xff, + 0xfe, 0xd5, 0x00, 0xff, 0xff, 0xee, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xee, 0x00, 0xff, 0xff, 0xd7, 0x01, 0xff, + 0xff, 0xba, 0x01, 0xff, 0xcd, 0x6e, 0x01, 0xff, + 0xff, 0xba, 0x01, 0xff, 0xff, 0xc4, 0x01, 0xff, + 0xff, 0xcc, 0x00, 0xff, 0xff, 0xd3, 0x01, 0xff, + 0xff, 0xd9, 0x00, 0xff, 0xfe, 0xde, 0x00, 0xff, + 0xff, 0xdc, 0x00, 0xff, 0xfe, 0xcc, 0x00, 0xff, + 0xff, 0xbe, 0x01, 0xff, 0xff, 0xaf, 0x00, 0xff, + 0xff, 0xa3, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xc2, 0x64, 0x01, 0xff, 0xe6, 0x87, 0x00, 0xff, + 0xff, 0xa7, 0x01, 0xff, 0xff, 0xb7, 0x00, 0xff, + 0xff, 0xc8, 0x00, 0xff, 0xff, 0xd8, 0x00, 0xff, + 0xff, 0xea, 0x01, 0xff, 0xff, 0xf9, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xb1, 0x01, 0xff, + 0xff, 0xce, 0x00, 0xff, 0xff, 0xe6, 0x00, 0xff, + 0xff, 0xf9, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf9, 0x00, 0xff, + 0xff, 0xe6, 0x01, 0xff, 0xff, 0xcf, 0x01, 0xff, + 0xff, 0xb1, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xc6, 0x67, 0x01, 0xff, 0xd2, 0x73, 0x00, 0xff, + 0xdf, 0x80, 0x00, 0xff, 0xe9, 0x8b, 0x00, 0xff, + 0xf3, 0x95, 0x00, 0xff, 0xfb, 0x9d, 0x00, 0xff, + 0xf6, 0x98, 0x00, 0xff, 0xea, 0x8b, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xc9, 0x6a, 0x00, 0xff, 0xd8, 0x79, 0x01, 0xff, + 0xe6, 0x88, 0x01, 0xff, 0xf5, 0x97, 0x00, 0xff, + 0xfe, 0xa6, 0x00, 0xff, 0xff, 0xb7, 0x01, 0xff, + 0xff, 0xc7, 0x01, 0xff, 0xff, 0xd6, 0x00, 0xff, + 0xff, 0xe6, 0x00, 0xff, 0xff, 0xf4, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xf0, 0x91, 0x00, 0xff, + 0xff, 0xbf, 0x01, 0xff, 0xfe, 0xd4, 0x00, 0xff, + 0xff, 0xe9, 0x00, 0xff, 0xff, 0xfb, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xf9, 0x00, 0xff, 0xff, 0xeb, 0x00, 0xff, + 0xff, 0xd6, 0x00, 0xff, 0xff, 0xc1, 0x01, 0xff, + 0xf1, 0x92, 0x00, 0xff, 0xbc, 0x5e, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xc0, 0x62, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xae, 0x01, 0xff, 0xfe, 0xc3, 0x00, 0xff, + 0xfe, 0xd9, 0x00, 0xff, 0xfe, 0xef, 0x00, 0xff, + 0xff, 0xfd, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xf8, 0x00, 0xff, + 0xfe, 0xee, 0x00, 0xff, 0xff, 0xdd, 0x01, 0xff, + 0xfe, 0xc7, 0x00, 0xff, 0xff, 0xae, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xd1, 0x73, 0x00, 0xff, 0xff, 0xb2, 0x00, 0xff, + 0xff, 0xc8, 0x01, 0xff, 0xff, 0xe2, 0x01, 0xff, + 0xfe, 0xf1, 0x00, 0xff, 0xff, 0xfe, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xf9, 0x01, 0xff, 0xff, 0xee, 0x00, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xce, 0x00, 0xff, + 0xff, 0xb5, 0x01, 0xff, 0xdf, 0x80, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xf3, 0x94, 0x01, 0xff, + 0xff, 0xb6, 0x00, 0xff, 0xff, 0xd1, 0x01, 0xff, + 0xfe, 0xe4, 0x00, 0xff, 0xff, 0xf0, 0x01, 0xff, + 0xff, 0xfa, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf6, 0x00, 0xff, + 0xff, 0xed, 0x00, 0xff, 0xfe, 0xe3, 0x00, 0xff, + 0xff, 0xd2, 0x01, 0xff, 0xff, 0xba, 0x01, 0xff, + 0xf9, 0x9a, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5e, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0xff, 0xa4, 0x00, 0xff, 0xff, 0xbf, 0x01, 0xff, + 0xfe, 0xd0, 0x00, 0xff, 0xff, 0xdf, 0x01, 0xff, + 0xff, 0xec, 0x01, 0xff, 0xff, 0xf5, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xfe, 0x00, 0xff, + 0xfe, 0xf3, 0x00, 0xff, 0xff, 0xeb, 0x01, 0xff, + 0xff, 0xde, 0x00, 0xff, 0xff, 0xcf, 0x00, 0xff, + 0xff, 0xbf, 0x01, 0xff, 0xff, 0xa6, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xff, 0xa3, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xcd, 0x6f, 0x01, 0xff, 0xff, 0xa4, 0x00, 0xff, + 0xff, 0xb7, 0x01, 0xff, 0xff, 0xc9, 0x01, 0xff, + 0xff, 0xd7, 0x01, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xff, 0xf1, 0x01, 0xff, 0xff, 0xf7, 0x00, 0xff, + 0xff, 0xfb, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfb, 0x00, 0xff, + 0xff, 0xf7, 0x01, 0xff, 0xff, 0xf0, 0x01, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xd3, 0x01, 0xff, + 0xff, 0xc4, 0x00, 0xff, 0xff, 0xb3, 0x00, 0xff, + 0xfe, 0xa2, 0x00, 0xff, 0xcd, 0x6e, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5c, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xd7, 0x78, 0x01, 0xff, + 0xfe, 0xe3, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xf3, 0x95, 0x01, 0xff, 0xff, 0xae, 0x00, 0xff, + 0xfe, 0xbf, 0x00, 0xff, 0xff, 0xcd, 0x01, 0xff, + 0xff, 0xdb, 0x01, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0xff, 0xe9, 0x01, 0xff, 0xff, 0xee, 0x01, 0xff, + 0xff, 0xf1, 0x00, 0xff, 0xff, 0xf5, 0x00, 0xff, + 0xfe, 0xf8, 0x00, 0xff, 0xff, 0xfb, 0x00, 0xff, + 0xff, 0xfc, 0x01, 0xff, 0xff, 0xf9, 0x01, 0xff, + 0xff, 0xf5, 0x01, 0xff, 0xff, 0xf1, 0x00, 0xff, + 0xff, 0xec, 0x01, 0xff, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xda, 0x00, 0xff, + 0xff, 0xcb, 0x01, 0xff, 0xff, 0xbc, 0x00, 0xff, + 0xff, 0xac, 0x01, 0xff, 0xed, 0x8e, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xf6, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xff, 0xbe, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xd6, 0x77, 0x01, 0xff, + 0xff, 0xa4, 0x00, 0xff, 0xfe, 0xb4, 0x00, 0xff, + 0xff, 0xc1, 0x00, 0xff, 0xff, 0xc8, 0x00, 0xff, + 0xff, 0xcf, 0x01, 0xff, 0xff, 0xd5, 0x01, 0xff, + 0xff, 0xda, 0x01, 0xff, 0xff, 0xdf, 0x01, 0xff, + 0xff, 0xe3, 0x01, 0xff, 0xff, 0xe6, 0x00, 0xff, + 0xff, 0xe6, 0x01, 0xff, 0xff, 0xe1, 0x00, 0xff, + 0xff, 0xdd, 0x01, 0xff, 0xff, 0xd7, 0x01, 0xff, + 0xff, 0xd2, 0x01, 0xff, 0xff, 0xcd, 0x01, 0xff, + 0xff, 0xc7, 0x01, 0xff, 0xfe, 0xc1, 0x00, 0xff, + 0xfe, 0xb3, 0x00, 0xff, 0xff, 0xa4, 0x00, 0xff, + 0xc9, 0x6b, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xfe, 0x9f, 0x00, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xf6, 0x01, 0xff, + 0xff, 0xec, 0x01, 0xff, 0xff, 0xe3, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0xff, 0xa5, 0x00, 0xff, 0xff, 0xf4, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xe3, 0x85, 0x00, 0xff, + 0xfe, 0xa1, 0x00, 0xff, 0xff, 0xaa, 0x00, 0xff, + 0xff, 0xb0, 0x00, 0xff, 0xff, 0xb7, 0x00, 0xff, + 0xff, 0xbd, 0x00, 0xff, 0xff, 0xc3, 0x01, 0xff, + 0xff, 0xc7, 0x00, 0xff, 0xff, 0xcb, 0x00, 0xff, + 0xff, 0xcb, 0x01, 0xff, 0xff, 0xc6, 0x01, 0xff, + 0xff, 0xc1, 0x01, 0xff, 0xff, 0xbb, 0x00, 0xff, + 0xfe, 0xb5, 0x00, 0xff, 0xff, 0xb0, 0x01, 0xff, + 0xff, 0xaa, 0x01, 0xff, 0xff, 0xa2, 0x01, 0xff, + 0xe2, 0x84, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0xd3, 0x74, 0x00, 0xff, 0xff, 0xbd, 0x01, 0xff, + 0xff, 0xf3, 0x00, 0xff, 0xff, 0xe9, 0x01, 0xff, + 0xff, 0xde, 0x00, 0xff, 0xff, 0xd5, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xe7, 0x89, 0x00, 0xff, + 0xff, 0xdb, 0x01, 0xff, 0xff, 0xe8, 0x01, 0xff, + 0xff, 0xf4, 0x00, 0xff, 0xff, 0xfe, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xd1, 0x72, 0x00, 0xff, 0xe4, 0x86, 0x00, 0xff, + 0xf4, 0x96, 0x00, 0xff, 0xff, 0xa4, 0x00, 0xff, + 0xff, 0xac, 0x00, 0xff, 0xff, 0xb2, 0x01, 0xff, + 0xff, 0xb1, 0x00, 0xff, 0xfe, 0xab, 0x00, 0xff, + 0xff, 0xa4, 0x00, 0xff, 0xf0, 0x91, 0x00, 0xff, + 0xdd, 0x7e, 0x00, 0xff, 0xc9, 0x6a, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xff, 0xa4, 0x01, 0xff, 0xff, 0xdb, 0x00, 0xff, + 0xff, 0xd1, 0x00, 0xff, 0xff, 0xc8, 0x01, 0xff, + 0xff, 0xbf, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x00, 0xff, + 0xcf, 0x70, 0x01, 0xff, 0xff, 0xc2, 0x01, 0xff, + 0xff, 0xd0, 0x00, 0xff, 0xff, 0xdd, 0x01, 0xff, + 0xff, 0xe9, 0x00, 0xff, 0xff, 0xf3, 0x01, 0xff, + 0xff, 0xfc, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xff, 0xab, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xc6, 0x67, 0x00, 0xff, 0xd6, 0x78, 0x01, 0xff, + 0xd5, 0x77, 0x01, 0xff, 0xc2, 0x64, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xff, 0xc6, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbc, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xe7, 0x89, 0x01, 0xff, + 0xfe, 0xc1, 0x00, 0xff, 0xff, 0xb9, 0x00, 0xff, + 0xff, 0xb0, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x00, 0xff, + 0xff, 0xa9, 0x01, 0xff, 0xff, 0xb7, 0x00, 0xff, + 0xff, 0xc6, 0x01, 0xff, 0xff, 0xd2, 0x00, 0xff, + 0xff, 0xdf, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x00, 0xff, 0xff, 0xb3, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xe5, 0x87, 0x01, 0xff, + 0xff, 0xf5, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xcd, 0x6f, 0x00, 0xff, 0xff, 0xa9, 0x01, 0xff, + 0xff, 0xa1, 0x00, 0xff, 0xf9, 0x9a, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5c, 0x00, 0xff, 0xef, 0x91, 0x00, 0xff, + 0xfe, 0xa0, 0x00, 0xff, 0xff, 0xae, 0x00, 0xff, + 0xff, 0xbd, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xff, 0xbc, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xbb, 0x5c, 0x00, 0xff, + 0xff, 0xc6, 0x01, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5c, 0x00, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xf0, 0x91, 0x01, 0xff, 0xea, 0x8b, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xda, 0x7b, 0x00, 0xff, 0xe9, 0x8b, 0x01, 0xff, + 0xf7, 0x98, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbc, 0x5d, 0x01, 0xff, 0xff, 0xc3, 0x01, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xed, 0x8e, 0x00, 0xff, 0xff, 0xef, 0x01, 0xff, + 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfa, 0x00, 0xff, + 0xff, 0xf5, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x00, 0xff, 0xda, 0x7c, 0x01, 0xff, + 0xd6, 0x77, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x67, 0x00, 0xff, + 0xd4, 0x76, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xff, 0xc8, 0x00, 0xff, + 0xff, 0xf2, 0x01, 0xff, 0xff, 0xf6, 0x00, 0xff, + 0xff, 0xfa, 0x01, 0xff, 0xff, 0xfc, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5c, 0x00, 0xff, 0xff, 0xc5, 0x01, 0xff, + 0xff, 0xee, 0x01, 0xff, 0xff, 0xea, 0x00, 0xff, + 0xff, 0xe7, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xc6, 0x67, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xc0, 0x61, 0x01, 0xff, 0xff, 0xcd, 0x00, 0xff, + 0xff, 0xe2, 0x00, 0xff, 0xff, 0xe7, 0x00, 0xff, + 0xff, 0xeb, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xbb, 0x5d, 0x00, 0xff, 0xf3, 0x94, 0x00, 0xff, + 0xff, 0xdd, 0x01, 0xff, 0xff, 0xda, 0x00, 0xff, + 0xff, 0xd8, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xcc, 0x6e, 0x01, 0xff, 0xff, 0xca, 0x00, 0xff, + 0xff, 0xd1, 0x00, 0xff, 0xff, 0xd7, 0x00, 0xff, + 0xff, 0xdb, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbc, 0x5d, 0x00, 0xff, 0xbf, 0x60, 0x00, 0xff, + 0xff, 0xc1, 0x00, 0xff, 0xff, 0xc8, 0x00, 0xff, + 0xfe, 0xc6, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xd6, 0x77, 0x00, 0xff, 0xff, 0xb9, 0x00, 0xff, + 0xff, 0xc1, 0x00, 0xff, 0xff, 0xc8, 0x01, 0xff, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbb, 0x5c, 0x00, 0xff, 0xbc, 0x5d, 0x01, 0xff, + 0xf4, 0x96, 0x00, 0xff, 0xff, 0xb6, 0x00, 0xff, + 0xff, 0xb6, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xdf, 0x81, 0x00, 0xff, 0xff, 0xaa, 0x00, 0xff, + 0xff, 0xb2, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xc9, 0x6b, 0x01, 0xff, 0xff, 0xa5, 0x01, 0xff, + 0xff, 0xa6, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0xe8, 0x89, 0x00, 0xff, 0xf9, 0x9b, 0x00, 0xff, + 0xff, 0xa4, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5c, 0x00, 0xff, 0xf1, 0x92, 0x00, 0xff, + 0xf3, 0x94, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xe2, 0x83, 0x00, 0xff, 0xec, 0x8e, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0xbc, 0x5d, 0x01, 0xff, 0xd1, 0x73, 0x00, 0xff, + 0xe2, 0x84, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xd6, 0x77, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x5d, 0x01, 0xff, + 0xd3, 0x74, 0x01, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xbb, 0x5c, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc3, 0x64, 0x00, 0xff, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x5d, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbb, 0x5d, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + +}; + +Vtx sun_LightModel_mesh_vtx_cull[8] = { + {{ {-100, -100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {-100, -100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {-100, 100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {-100, 100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {100, -100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {100, -100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {100, 100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, + {{ {100, 100, 0}, 0, {0, 0}, {0, 0, 0, 0} }}, +}; + +Vtx sun_LightModel_mesh_vtx_0[4] = { + {{ {-100, -100, 0}, 0, {-16, 2032}, {0, 0, 127, 255} }}, + {{ {100, -100, 0}, 0, {2032, 2032}, {0, 0, 127, 255} }}, + {{ {100, 100, 0}, 0, {2032, -16}, {0, 0, 127, 255} }}, + {{ {-100, 100, 0}, 0, {-16, -16}, {0, 0, 127, 255} }}, +}; + +Gfx sun_LightModel_mesh_tri_0[3] = { + gsSPVertex(sun_LightModel_mesh_vtx_0 + 0, 4, 0), + gsSP2Triangles(0, 1, 2, 0, 0, 2, 3, 0), + gsSPEndDisplayList(), +}; + +Gfx mat_sun_sun[13] = { + gsSPSetGeometryMode(G_FOG), + gsSPClearGeometryMode(G_CULL_BACK | G_CLIPPING), + gsDPPipeSync(), + gsDPSetCombineLERP(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2), + gsSPTexture(65535, 65535, 0, 0, 1), + gsDPSetPrimColor(0, 0, 255, 255, 255, 128), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_32b_LOAD_BLOCK, 1, sun_sun_rgba32), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_32b_LOAD_BLOCK, 0, 0, 7, 0, G_TX_WRAP | G_TX_NOMIRROR, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 0, 0), + gsDPLoadBlock(7, 0, 0, 4095, 64), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_32b, 16, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 6, 0, G_TX_WRAP | G_TX_NOMIRROR, 6, 0), + gsDPSetTileSize(0, 0, 0, 252, 252), + gsSPEndDisplayList(), +}; + +Gfx mat_revert_sun_sun[4] = { + gsSPClearGeometryMode(G_FOG), + gsSPSetGeometryMode(G_CULL_BACK | G_CLIPPING), + gsDPPipeSync(), + gsSPEndDisplayList(), +}; + +Gfx sun_LightModel_mesh[13] = { + gsSPClearGeometryMode(G_LIGHTING), + gsSPVertex(sun_LightModel_mesh_vtx_cull + 0, 8, 0), + gsSPSetGeometryMode(G_LIGHTING), + gsSPCullDisplayList(0, 7), + gsSPDisplayList(mat_sun_sun), + gsSPDisplayList(sun_LightModel_mesh_tri_0), + gsSPDisplayList(mat_revert_sun_sun), + gsDPPipeSync(), + gsSPSetGeometryMode(G_LIGHTING), + gsSPClearGeometryMode(G_TEXTURE_GEN), + gsDPSetCombineLERP(0, 0, 0, SHADE, 0, 0, 0, ENVIRONMENT, 0, 0, 0, SHADE, 0, 0, 0, ENVIRONMENT), + gsSPTexture(65535, 65535, 0, 0, 0), + gsSPEndDisplayList(), +}; + + +}; +} diff --git a/src/engine/editor/ObjectPicker.cpp b/src/engine/editor/ObjectPicker.cpp new file mode 100644 index 000000000..9cfeed5f8 --- /dev/null +++ b/src/engine/editor/ObjectPicker.cpp @@ -0,0 +1,207 @@ +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "../CoreMath.h" +#include <libultra/types.h> +#include "../World.h" + +#include "ObjectPicker.h" +#include "port/Engine.h" +#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h> +#include <window/Window.h> + +#include "engine/actors/Ship.h" +#include "port/Game.h" +#include "Gizmo.h" + +#include "EditorMath.h" + +extern "C" { +#include "common_structs.h" +#include "main.h" +#include "defines.h" +#include "actors.h" +#include "camera.h" +} + +namespace Editor { + +void ObjectPicker::Load() { + eGizmo.Load(); +} + +void ObjectPicker::Tick() { +} + +void ObjectPicker::SelectObject(std::vector<GameObject*> objects) { + Ray ray; + ray.Origin = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]); + + // This allows selection of objects in the scene explorer. + // Otherwise this would still run when selecting buttons in editor windows. + if (IsInGameScreen()) { + ray.Direction = ScreenRayTrace(); + + ObjectPicker::FindObject(ray, objects); + + if (_selected != nullptr) { + eGizmo.SetGizmo(_selected, ray); + eGizmo.Enabled = true; + } else { + //eGizmo.Disable(); + eGizmo.Enabled = false; + eGizmo._selected = nullptr; + } + } +} + +void ObjectPicker::DragHandle() { + Ray ray; + ray.Origin = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]); + ray.Direction = ScreenRayTrace(); + + // Skip if a drag is already in progress + if (eGizmo.SelectedHandle != Gizmo::GizmoHandle::None) { + eGizmo._ray = ray.Direction; + eGizmo.Tick(); + return; + } + + // Is the gizmo being dragged? + if (!eGizmo.Enabled) { return; } + float closestDistance = FLT_MAX; + std::optional<FVector> closestClickPos; + Gizmo::GizmoHandle closestHandle = Gizmo::GizmoHandle::None; + + // All axis grab. Not used in rotate mode rotate + if (static_cast<Gizmo::TranslationMode>(CVarGetInteger("eGizmoMode", 0)) != Gizmo::TranslationMode::Rotate) { + float t; + if (IntersectRaySphere(ray, eGizmo.Pos, eGizmo.AllAxisRadius, t)) { + if (t < closestDistance) { + closestDistance = t; + closestClickPos = ray.Origin + ray.Direction * t; + closestHandle = Gizmo::GizmoHandle::All_Axis; + } + } + } + + // Arrow handles + auto tryHandle = [&](Gizmo::GizmoHandle handle, MtxF mtx, const std::vector<Triangle>& tris) { + for (const auto& tri : tris) { + if (auto clickPos = QueryHandleIntersection(mtx, ray, tri)) { + float dist = (*clickPos - ray.Origin).Magnitude(); + if (dist < closestDistance) { + closestDistance = dist; + closestClickPos = *clickPos; + closestHandle = handle; + } + } + } + }; + + switch(static_cast<Gizmo::TranslationMode>(CVarGetInteger("eGizmoMode", 0))) { + case Gizmo::TranslationMode::Move: + tryHandle(Gizmo::GizmoHandle::Z_Axis, eGizmo.Mtx_RedX, eGizmo.RedCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::X_Axis, eGizmo.Mtx_GreenY, eGizmo.GreenCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::Y_Axis, eGizmo.Mtx_BlueZ, eGizmo.BlueCollision.Triangles); + break; + case Gizmo::TranslationMode::Rotate: + tryHandle(Gizmo::GizmoHandle::X_Axis, eGizmo.Mtx_RedX, eGizmo.RedRotateCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::Z_Axis, eGizmo.Mtx_GreenY, eGizmo.GreenRotateCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::Y_Axis, eGizmo.Mtx_BlueZ, eGizmo.BlueRotateCollision.Triangles); + break; + case Gizmo::TranslationMode::Scale: + tryHandle(Gizmo::GizmoHandle::Z_Axis, eGizmo.Mtx_RedX, eGizmo.RedScaleCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::X_Axis, eGizmo.Mtx_GreenY, eGizmo.GreenScaleCollision.Triangles); + tryHandle(Gizmo::GizmoHandle::Y_Axis, eGizmo.Mtx_BlueZ, eGizmo.BlueScaleCollision.Triangles); + break; + + } + + if (closestHandle != Gizmo::GizmoHandle::None && closestClickPos.has_value()) { + eGizmo.SelectedHandle = closestHandle; + eGizmo._ray = ray.Direction; + eGizmo._cursorOffset = eGizmo.Pos - *closestClickPos; + eGizmo.PickDistance = closestDistance; + } +} + +void ObjectPicker::Draw() { + if (_selected != NULL) { + eGizmo.Draw(); + } + + if (Debug) { + Mat4 CursorMtx; + IRotator rot = IRotator(0,0,0); + FVector scale = FVector(0.1, 0.1, 0.1); + FVector ray = ScreenRayTrace(); + + float x = (cameras[0].pos[0] + ray.x * 800); + float y = (cameras[0].pos[1] + ray.y * 800); + float z = (cameras[0].pos[2] + ray.z * 800); + + ApplyMatrixTransformations((float(*)[4])&CursorMtx, FVector(x, y, z), rot, scale); + Editor_AddMatrix((float(*)[4])&CursorMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, (Gfx*)"__OTR__tracks/sphere"); + } +} + +void ObjectPicker::FindObject(Ray ray, std::vector<GameObject*> objects) { + bool found = false; + GameObject* closestObject = nullptr; + float closestDistance = FLT_MAX; + + for (auto& object : objects) { + float boundingBox = object->BoundingBoxSize; + if (boundingBox == 0.0f) { + boundingBox = 2.0f; + } + + switch(object->Collision) { + case GameObject::CollisionType::VTX_INTERSECT: + for (const auto& tri : object->Triangles) { + float t; + if (IntersectRayTriangleAndTransform(ray, *object->Pos, tri, t)) { + if (t < closestDistance) { + closestDistance = t; + closestObject = object; + printf("SELECTED OBJECT\n"); + } + } + } + break; + case GameObject::CollisionType::BOUNDING_BOX: { + float max = 2.0f; + float min = -2.0f; + Vec3f boxMin = { object->Pos->x + boundingBox * min, + object->Pos->y + boundingBox * min, + object->Pos->z + boundingBox * min }; + + Vec3f boxMax = { object->Pos->x + boundingBox * max, + object->Pos->y + boundingBox * max, + object->Pos->z + boundingBox * max }; + float t; + if (QueryCollisionRayActor(&ray.Origin.x, &ray.Direction.x, boxMin, boxMax, &t)) { + if (t < closestDistance) { + closestDistance = t; + closestObject = object; + printf("FOUND BOUNDING BOX OBJECT\n"); + } + break; + } + break; + } + case GameObject::CollisionType::BOUNDING_SPHERE: + printf("Editor::ObjectPicker.cpp Bounding sphere collision type not yet supported\n"); + break; + } + } + if (closestObject != nullptr) { + _selected = closestObject; + // printf("FOUND COLLISION %d\n", type); + } else { + // printf("NO COLLISION\n"); + _selected = nullptr; + } +} +} diff --git a/src/engine/editor/ObjectPicker.h b/src/engine/editor/ObjectPicker.h new file mode 100644 index 000000000..e96bddcbc --- /dev/null +++ b/src/engine/editor/ObjectPicker.h @@ -0,0 +1,28 @@ +#pragma once + +#include <libultraship/libultraship.h> +#include <libultra/gbi.h> +#include "Collision.h" +#include "Gizmo.h" +#include "GameObject.h" + +namespace Editor { + class ObjectPicker { + public: + void SelectObject(std::vector<GameObject*> objects); + void DragHandle(); + void Draw(); + void FindObject(Ray ray, std::vector<GameObject*> objects); + void Load(); + void Tick(); + Gizmo eGizmo; + GameObject* _selected; + private: + bool _draw = false; + GameObject* _lastSelected; + s32 Inverse(MtxF* src, MtxF* dest); + void Copy(MtxF* src, MtxF* dest); + void Clear(MtxF* mf); + bool Debug = false; + }; +} diff --git a/src/engine/editor/SceneManager.cpp b/src/engine/editor/SceneManager.cpp new file mode 100644 index 000000000..a2de6656c --- /dev/null +++ b/src/engine/editor/SceneManager.cpp @@ -0,0 +1,156 @@ +#include "SceneManager.h" +#include "port/Game.h" +#include "CoreMath.h" +#include "World.h" +#include "GameObject.h" + +#include <iostream> +#include <fstream> +#include <nlohmann/json.hpp> +#include "port/Engine.h" +#include <libultraship/src/resource/type/Json.h> +#include "port/resource/type/Minimap.h" +#include <libultraship/src/resource/File.h> +#include "port/resource/type/ResourceType.h" + +namespace Editor { + + std::shared_ptr<Ship::Archive> CurrentArchive; + std::string SceneFile = ""; + + void SaveLevel() { + auto props = gWorldInstance.CurrentCourse->Props; + + if ((CurrentArchive) && (!SceneFile.empty())) { + nlohmann::json data; + + data["Props"] = props.to_json(); + + nlohmann::json staticMesh; + + for (const auto& mesh : gWorldInstance.StaticMeshActors) { + staticMesh.push_back(mesh->to_json()); + } + data["StaticMeshActors"] = staticMesh; + + // nlohmann::json actors; + + // for (const auto& actor : gWorldInstance.Actors) { + // actors.push_back(actor->to_json()); + // } + // data["Actors"] = actors; + + // nlohmann::json objects; + + // for (const auto& object : gWorldInstance.Objects) { + // objects.push_back(object->to_json()); + // } + // data["Objects"] = objects; + + try { + auto dat = data.dump(); + std::vector<uint8_t> stringify; + stringify.assign(dat.begin(), dat.end()); + + bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, stringify); + if (wrote) { + printf("Successfully wrote scene file!\n Wrote: %s\n", SceneFile.c_str()); + } else { + printf("Failed to write scene file!\n"); + } + } catch (const nlohmann::json::exception& e) { + printf("SceneManager::SaveLevel():\n JSON error during dump: %s\n", e.what()); + } + } else { + printf("Could not save scene file, SceneFile or CurrentArchive not set\n"); + } + } + + void LoadLevel(std::shared_ptr<Ship::Archive> archive, Course* course, std::string sceneFile) { + SceneFile = sceneFile; + + if (archive) { + auto initData = std::make_shared<Ship::ResourceInitData>(); + initData->Parent = archive; + initData->Format = RESOURCE_FORMAT_BINARY; + initData->ByteOrder = Ship::Endianness::Little; + initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json); + initData->ResourceVersion = 0; + + nlohmann::json data = std::static_pointer_cast<Ship::Json>( + GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data; + + if (data.is_null() || data.empty()) { + return; + } + + // Load the Props (deserialize it) + if (data.contains("Props")) { + auto& propsJson = data["Props"]; + try { + course->Props.from_json(propsJson); + } catch(const std::exception& e) { + std::cerr << "SceneManager::LoadLevel() Error parsing track properties: " << e.what() << std::endl; + std::cerr << " Is your scene.json file out of date?" << std::endl; + } + } else { + std::cerr << "Props data not found in the JSON file!" << std::endl; + } + + // Load the Actors (deserialize them) + if (data.contains("StaticMeshActors")) { + auto& actorsJson = data["StaticMeshActors"]; + gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any + + for (const auto& actorJson : actorsJson) { + Load_AddStaticMeshActor(actorJson); + } + } else { + std::cerr << "Actors data not found in the JSON file!" << std::endl; + } + } + } + + void Load_AddStaticMeshActor(const nlohmann::json& actorJson) { + gWorldInstance.StaticMeshActors.push_back(new StaticMeshActor("", FVector(0, 0, 0), IRotator(0, 0, 0), FVector(1, 1, 1), "", nullptr)); + auto actor = gWorldInstance.StaticMeshActors.back(); + actor->from_json(actorJson); + + printf("After from_json: Pos(%f, %f, %f), Name: %s, Model: %s\n", + actor->Pos.x, actor->Pos.y, actor->Pos.z, actor->Name.c_str(), actor->Model.c_str()); + gEditor.AddObject(actor->Name.c_str(), &actor->Pos, &actor->Rot, &actor->Scale, (Gfx*) nullptr, 1.0f, + GameObject::CollisionType::BOUNDING_BOX, 20.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) 1); + } + + void SetSceneFile(std::shared_ptr<Ship::Archive> archive, std::string sceneFile) { + CurrentArchive = archive; + SceneFile = sceneFile; + } + + void LoadMinimap(std::shared_ptr<Ship::Archive> archive, Course* course, std::string filePath) { + printf("LOADING MINIMAP %s\n", filePath.c_str()); + if (archive) { + auto initData = std::make_shared<Ship::ResourceInitData>(); + initData->Parent = archive; + initData->Format = RESOURCE_FORMAT_BINARY; + initData->ByteOrder = Ship::Endianness::Little; + initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap); + initData->ResourceVersion = 0; + + std::shared_ptr<MK64::Minimap> ptr = std::static_pointer_cast<MK64::Minimap>( + GameEngine::Instance->context->GetResourceManager()->LoadResource(filePath, true, initData)); + + if (ptr) { + printf("LOADED MINIMAP!\n"); + MK64::MinimapTexture texture = ptr->Texture; + course->Props.Minimap.Texture = (const char*)texture.Data; + course->Props.Minimap.Width = texture.Width; + course->Props.Minimap.Height = texture.Height; + } else { // Fallback + course->Props.Minimap.Texture = gTextureCourseOutlineMarioRaceway; + course->Props.Minimap.Width = ResourceGetTexWidthByName(course->Props.Minimap.Texture); + course->Props.Minimap.Height = ResourceGetTexHeightByName(course->Props.Minimap.Texture); + } + } + } +} diff --git a/src/engine/editor/SceneManager.h b/src/engine/editor/SceneManager.h new file mode 100644 index 000000000..58699107e --- /dev/null +++ b/src/engine/editor/SceneManager.h @@ -0,0 +1,13 @@ +#include <libultraship/libultraship.h> +#include "engine/courses/Course.h" + +namespace Editor { + void SaveLevel(); + void LoadLevel(std::shared_ptr<Ship::Archive> archive, Course* course, std::string sceneFile); + void Load_AddStaticMeshActor(const nlohmann::json& actorJson); + void SetSceneFile(std::shared_ptr<Ship::Archive> archive, std::string sceneFile); + void LoadMinimap(std::shared_ptr<Ship::Archive> archive, Course* course, std::string filePath); + + extern std::shared_ptr<Ship::Archive> CurrentArchive; // This is used to retrieve and write the scene data file + extern std::string SceneFile; +} diff --git a/src/engine/objects/Bat.cpp b/src/engine/objects/Bat.cpp index b90f7c857..764476064 100644 --- a/src/engine/objects/Bat.cpp +++ b/src/engine/objects/Bat.cpp @@ -18,8 +18,8 @@ const char* sBoardwalkTexList[] = { gTextureBat1, gTextureBat2, gTextureBat3, gT size_t OBat::_count = 0; -OBat::OBat(const FVector& pos, const FRotation& rot) { - +OBat::OBat(const FVector& pos, const IRotator& rot) { + Name = "Bat"; find_unused_obj_index(&_objectIndex); init_texture_object(_objectIndex, (uint8_t*)d_course_banshee_boardwalk_bat_tlut, sBoardwalkTexList, 0x20U, diff --git a/src/engine/objects/Bat.h b/src/engine/objects/Bat.h index f9e0df074..d6b7e8774 100644 --- a/src/engine/objects/Bat.h +++ b/src/engine/objects/Bat.h @@ -21,14 +21,14 @@ extern "C" { /** * OBat * - * FRotation does not appear to do anything. + * IRotator does not appear to do anything. * Could not find where origin_pos was at. * So pos does not work either * */ class OBat : public OObject { public: - explicit OBat(const FVector& pos, const FRotation& rot); + explicit OBat(const FVector& pos, const IRotator& rot); ~OBat() { _count--; @@ -51,10 +51,8 @@ public: void func_8007D794(s32 objectIndex); void func_8007DA4C(s32 objectIndex); - private: FVector _pos; static size_t _count; size_t _idx; - s32 _objectIndex; }; diff --git a/src/engine/objects/BombKart.cpp b/src/engine/objects/BombKart.cpp index fc27103ed..53b4a4262 100644 --- a/src/engine/objects/BombKart.cpp +++ b/src/engine/objects/BombKart.cpp @@ -29,7 +29,8 @@ extern s8 gPlayerCount; size_t OBombKart::_count = 0; -OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C) { +OBombKart::OBombKart(FVector pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C) { + Name = "Bomb Kart"; _idx = _count; Vec3f _pos = {0, 0, 0}; @@ -41,10 +42,10 @@ OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, // Set height to the default value of 2000.0f unless Pos[1] is higher. // This allows placing these on very high surfaces. - f32 height = (pos[1] > 2000.0f) ? pos[1] : 2000.0f; - _pos[0] = pos[0]; - _pos[1] = spawn_actor_on_surface(pos[0], height, pos[2]); - _pos[2] = pos[2]; + f32 height = (pos.y > 2000.0f) ? pos.y : 2000.0f; + _pos[0] = pos.x; + _pos[1] = spawn_actor_on_surface(pos.x, height, pos.z); + _pos[2] = pos.z; } WaypointIndex = waypointIndex; @@ -72,7 +73,7 @@ OBombKart::OBombKart(Vec3f pos, TrackWaypoint* waypoint, uint16_t waypointIndex, WheelPos[3][2] = _pos[2]; check_bounding_collision(&_Collision, 2.0f, _pos[0], _pos[1], _pos[2]); - find_unused_obj_index(&ObjectIndex); + find_unused_obj_index(&_objectIndex); _count++; } @@ -329,7 +330,7 @@ void OBombKart::Tick() { void OBombKart::Draw(s32 cameraId) { if (gModeSelection == BATTLE) { for (size_t playerId = 0; playerId < NUM_BOMB_KARTS_BATTLE; playerId++) { - Object* object = &gObjectList[ObjectIndex]; + Object* object = &gObjectList[_objectIndex]; if (object->state != 0) { s32 primAlpha = object->primAlpha; Player* player = &gPlayerOne[playerId]; @@ -337,9 +338,9 @@ void OBombKart::Draw(s32 cameraId) { object->pos[1] = player->pos[1] - 2.0; object->pos[2] = player->pos[2]; object->surfaceHeight = player->unk_074; - func_800563DC(ObjectIndex, cameraId, primAlpha); - func_8005669C(ObjectIndex, cameraId, primAlpha); - func_800568A0(ObjectIndex, cameraId); + func_800563DC(_objectIndex, cameraId, primAlpha); + func_8005669C(_objectIndex, cameraId, primAlpha); + func_800568A0(_objectIndex, cameraId); } } return; @@ -358,27 +359,27 @@ void OBombKart::Draw(s32 cameraId) { } Camera* camera = &camera1[cameraId]; if (cameraId == PLAYER_ONE) { - if (is_obj_flag_status_active(ObjectIndex, 0x00200000) != 0) { + if (is_obj_flag_status_active(_objectIndex, 0x00200000) != 0) { Unk_4A = 0; } else if (gGamestate != ENDING) { Unk_4A = 1; } - clear_object_flag(ObjectIndex, 0x00200000); + clear_object_flag(_objectIndex, 0x00200000); } // huh??? s32 state = State; if (State != States::DISABLED) { - gObjectList[ObjectIndex].pos[0] = Pos[0]; - gObjectList[ObjectIndex].pos[1] = Pos[1]; - gObjectList[ObjectIndex].pos[2] = Pos[2]; - s32 temp_s4 = func_8008A364(ObjectIndex, cameraId, 0x31C4U, 0x000001F4); - if (is_obj_flag_status_active(ObjectIndex, VISIBLE) != 0) { - set_object_flag(ObjectIndex, 0x00200000); + gObjectList[_objectIndex].pos[0] = Pos[0]; + gObjectList[_objectIndex].pos[1] = Pos[1]; + gObjectList[_objectIndex].pos[2] = Pos[2]; + s32 temp_s4 = func_8008A364(_objectIndex, cameraId, 0x31C4U, 0x000001F4); + if (is_obj_flag_status_active(_objectIndex, VISIBLE) != 0) { + set_object_flag(_objectIndex, 0x00200000); D_80183E80[0] = 0; D_80183E80[1] = func_800418AC(Pos[0], Pos[2], camera->pos); D_80183E80[2] = 0x8000; - func_800563DC(ObjectIndex, cameraId, 0x000000FF); + func_800563DC(_objectIndex, cameraId, 0x000000FF); OBombKart::SomeRender(camera->pos); if (((u32) temp_s4 < 0x4E21U) && (state != BOMB_STATE_EXPLODED)) { OBombKart::LoadMtx(); diff --git a/src/engine/objects/BombKart.h b/src/engine/objects/BombKart.h index 3663ee664..29069a00f 100644 --- a/src/engine/objects/BombKart.h +++ b/src/engine/objects/BombKart.h @@ -47,11 +47,10 @@ public: u16 Unk_4A = 0; s16 Unk_4C = 1; f32 CenterY; // Center of the circle - s32 ObjectIndex = 0; // Index into gObjectList Collision _Collision; // 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); + explicit OBombKart(FVector pos, TrackWaypoint* waypoint, uint16_t waypointIndex, uint16_t state, f32 unk_3C); ~OBombKart() { _count--; diff --git a/src/engine/objects/Boos.cpp b/src/engine/objects/Boos.cpp index f06abc8f7..5bdbd41cf 100644 --- a/src/engine/objects/Boos.cpp +++ b/src/engine/objects/Boos.cpp @@ -23,6 +23,7 @@ extern "C" { size_t OBoos::_count = 0; OBoos::OBoos(size_t numBoos, const IPathSpan& leftBoundary, const IPathSpan& active, const IPathSpan& rightBoundary) { + Name = "Boos"; // Max five boos allowed due to limited splines // D_800E5D9C if (numBoos > 10) { diff --git a/src/engine/objects/ChainChomp.cpp b/src/engine/objects/ChainChomp.cpp index 1008aab52..695df1e8a 100644 --- a/src/engine/objects/ChainChomp.cpp +++ b/src/engine/objects/ChainChomp.cpp @@ -17,9 +17,10 @@ extern "C" { size_t OChainChomp::_count = 0; OChainChomp::OChainChomp() { + Name = "Chain Chomp"; _idx = _count; init_object(indexObjectList2[_count], 0); - + _objectIndex = indexObjectList2[_count]; _count++; } diff --git a/src/engine/objects/CheepCheep.cpp b/src/engine/objects/CheepCheep.cpp index 10cdf6602..5b4157c61 100644 --- a/src/engine/objects/CheepCheep.cpp +++ b/src/engine/objects/CheepCheep.cpp @@ -18,6 +18,7 @@ extern Lights1 D_800E45C0[]; } OCheepCheep::OCheepCheep(const FVector& pos, CheepType type, IPathSpan span) { + Name = "Cheep Cheep"; _type = type; _spawnPos = pos; _span = span; diff --git a/src/engine/objects/Crab.cpp b/src/engine/objects/Crab.cpp index c722a9037..82d2b9330 100644 --- a/src/engine/objects/Crab.cpp +++ b/src/engine/objects/Crab.cpp @@ -28,6 +28,7 @@ extern "C" { size_t OCrab::_count = 0; OCrab::OCrab(const FVector2D& start, const FVector2D& end) { + Name = "Crab"; _idx = _count; _start = start; _end = end; diff --git a/src/engine/objects/Crab.h b/src/engine/objects/Crab.h index 2d1ef5e93..4cadd3b87 100644 --- a/src/engine/objects/Crab.h +++ b/src/engine/objects/Crab.h @@ -46,5 +46,4 @@ private: FVector2D _end; static size_t _count; s32 _idx; - s32 _objectIndex; }; diff --git a/src/engine/objects/Flagpole.cpp b/src/engine/objects/Flagpole.cpp index 7b5e5af20..acd74ba2b 100644 --- a/src/engine/objects/Flagpole.cpp +++ b/src/engine/objects/Flagpole.cpp @@ -16,6 +16,7 @@ extern "C" { size_t OFlagpole::_count = 0; OFlagpole::OFlagpole(const FVector& pos, s16 direction) { + Name = "Flagpole"; _idx = _count; _pos = pos; _direction = direction; diff --git a/src/engine/objects/Flagpole.h b/src/engine/objects/Flagpole.h index 034db865e..5824fcf18 100644 --- a/src/engine/objects/Flagpole.h +++ b/src/engine/objects/Flagpole.h @@ -42,5 +42,4 @@ private: s16 _direction; static size_t _count; size_t _idx; - s32 _objectIndex; }; diff --git a/src/engine/objects/GrandPrixBalloons.cpp b/src/engine/objects/GrandPrixBalloons.cpp new file mode 100644 index 000000000..819bde1c6 --- /dev/null +++ b/src/engine/objects/GrandPrixBalloons.cpp @@ -0,0 +1,231 @@ +#include "GrandPrixBalloons.h" + +#include "port/Game.h" +#include "assets/other_textures.h" +#include "assets/common_data.h" + +extern "C" { +#include "update_objects.h" +#include "render_objects.h" +#include "code_80057C60.h" +#include "code_80086E70.h" +#include "math_util.h" +#include "math_util_2.h" +#include "menus.h" +} + +size_t OGrandPrixBalloons::_count = 0; + +OGrandPrixBalloons::OGrandPrixBalloons(const FVector& pos) { + Pos = pos; + + _active = 1; + if (gPlayerCount == 1) { + _numBalloons = 0x64; + _numBalloons2 = 0x3C; + _numBalloons3 = 0x1E; + } else { + _numBalloons = 0x32; + _numBalloons2 = 0x1E; + _numBalloons3 = 0xA; + } + + for (size_t i = 0; i < _numBalloons; i++) { + find_unused_obj_index(&gObjectParticle3[i]); + init_object(gObjectParticle3[i], 0); + } +} + +void OGrandPrixBalloons::Tick() { + s32 someIndex; + s32 objectIndex; + s32 someCount; + Object* object; + + if (!_active) { + return; + } + someCount = 0; + for (someIndex = 0; someIndex < _numBalloons; someIndex++) { + objectIndex = gObjectParticle3[someIndex]; + if (objectIndex != DELETED_OBJECT_ID) { + object = &gObjectList[objectIndex]; + if (object->state != 0) { + OGrandPrixBalloons::func_80074E28(objectIndex); + OGrandPrixBalloons::func_80074D94(objectIndex); + if (object->state == 0) { + delete_object_wrapper(&gObjectParticle3[someIndex]); + this->Destroy(); + } + someCount += 1; + } + } + } + if (someCount == 0) { + _active = 0; + } +} + +void OGrandPrixBalloons::Draw(s32 cameraId) { + s32 var_s1; + s32 objectIndex; + if (!_active) { + return; + } + + gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007E98); + gDPLoadTLUT_pal256(gDisplayListHead++, gTLUTOnomatopoeia); + func_8004B614(0, 0, 0, 0, 0, 0, 0); + gDPSetAlphaCompare(gDisplayListHead++, G_AC_THRESHOLD); + gDPSetRenderMode(gDisplayListHead++, + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); + D_80183E80[0] = 0; + D_80183E80[1] = 0x8000; + rsp_load_texture((uint8_t*)gTextureBalloon1, 64, 32); + for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) { + objectIndex = gObjectParticle3[var_s1]; + if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) { + OGrandPrixBalloons::func_80053D74(objectIndex, cameraId, 0); + } + } + rsp_load_texture((uint8_t*)gTextureBalloon2, 64, 32); + for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) { + objectIndex = gObjectParticle3[var_s1]; + if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) { + OGrandPrixBalloons::func_80053D74(objectIndex, cameraId, 4); + } + } +} + +void OGrandPrixBalloons::func_80053D74(s32 objectIndex, UNUSED s32 arg1, s32 vertexIndex) { + Object* object; + + Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); + + if (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX) { + object = &gObjectList[objectIndex]; + D_80183E80[2] = (s16) (object->unk_084[6] + 0x8000); + rsp_set_matrix_transformation(object->pos, (u16*) D_80183E80, object->sizeScaling); + set_color_render((s32) object->unk_084[0], (s32) object->unk_084[1], (s32) object->unk_084[2], + (s32) object->unk_084[3], (s32) object->unk_084[4], (s32) object->unk_084[5], + (s32) object->primAlpha); + gSPVertex(gDisplayListHead++, (uintptr_t)&vtx[vertexIndex], 4, 0); + gSPDisplayList(gDisplayListHead++, (Gfx*)common_rectangle_display); + } +} + +void OGrandPrixBalloons::func_80074924(s32 objectIndex) { + s32 sp2C = 0; + s32 sp28; + s32 sp24; + s32 sp20 = 0; + s32 temp_a0; + Object* object; + + object = &gObjectList[objectIndex]; + object->sizeScaling = 0.15f; + + if (GetCourse() == GetMarioRaceway()) { + sp2C = random_int(0x00C8U); + sp28 = random_int(_numBalloons3); + sp24 = random_int(0x0096U); + sp20 = random_int(0x2000U); + object->origin_pos[0] = (f32) ((((f64) Pos.x + 100.0) - (f64) sp2C) * (f64) xOrientation); + object->origin_pos[1] = (f32) (Pos.y + sp28); + object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); + } else if (GetCourse() == GetRoyalRaceway()) { + sp2C = random_int(0x0168U); + sp28 = random_int(_numBalloons3); + sp24 = random_int(0x00B4U); + sp20 = random_int(0x2000U); + object->origin_pos[0] = (f32) ((((f64) Pos.x + 180.0) - (f64) sp2C) * (f64) xOrientation); + object->origin_pos[1] = (f32) (Pos.y + sp28); + object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); + } else if (GetCourse() == GetLuigiRaceway()) { + sp2C = random_int(0x012CU); + sp28 = random_int(_numBalloons3); + sp24 = random_int(0x0096U); + sp20 = random_int(0x2000U); + object->origin_pos[0] = (f32) ((((f64) Pos.x + 150.0) - (f64) sp2C) * (f64) xOrientation); + object->origin_pos[1] = (f32) (Pos.y + sp28); + object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); + } else { // any track + sp2C = random_int(0x00C8U); + sp28 = random_int(_numBalloons3); + sp24 = random_int(0x0096U); + sp20 = random_int(0x2000U); + object->origin_pos[0] = (f32) ((((f64) Pos.x + 100.0) - (f64) sp2C) * (f64) xOrientation); + object->origin_pos[1] = (f32) (Pos.y + sp28); + object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); + } + + set_obj_origin_offset(objectIndex, 0, 0, 0); + if (gPlayerCount == 1) { + object->velocity[1] = (f32) (((f64) (f32) (sp2C % 4) * 0.25) + 0.8); + } else { + object->velocity[1] = (f32) (((f64) (f32) (sp2C % 3) * 0.2) + 0.4); + } + temp_a0 = sp2C % 8; + object->unk_084[0] = D_800E6F30[temp_a0][0]; + object->unk_084[1] = D_800E6F30[temp_a0][1]; + object->unk_084[2] = D_800E6F30[temp_a0][2]; + object->unk_084[3] = D_800E6F48[temp_a0][0]; + object->unk_084[4] = D_800E6F48[temp_a0][1]; + object->unk_084[5] = D_800E6F48[temp_a0][2]; + object->unk_084[6] = sp20 - 0x1000; + if (sp2C & 1) { + object->unk_084[7] = (sp20 / 32) + 0x100; + } else { + object->unk_084[7] = -0x100 - (sp20 / 32); + } + object->primAlpha = 0x00E6; + object_next_state(objectIndex); +} + +void OGrandPrixBalloons::func_80074D94(s32 objectIndex) { + if (gObjectList[objectIndex].unk_0AE == 1) { + if ((_numBalloons2 <= gObjectList[objectIndex].offset[1]) && + (s16_step_down_towards(&gObjectList[objectIndex].primAlpha, 0, 8) != 0)) { + func_80086F60(objectIndex); + } + object_add_velocity_offset_y(objectIndex); + } + object_calculate_new_pos_offset(objectIndex); +} + +void OGrandPrixBalloons::func_80074E28(s32 objectIndex) { + switch (gObjectList[objectIndex].state) { + case 1: + OGrandPrixBalloons::func_80074924(objectIndex); + break; + case 2: + if (set_and_run_timer_object(objectIndex, 1) != false) { + func_80086E70(objectIndex); + break; + } + case 0: + break; + case 3: + OGrandPrixBalloons::func_80041480(&gObjectList[objectIndex].unk_084[6], -0x1000, 0x1000, &gObjectList[objectIndex].unk_084[7]); + if (gObjectList[objectIndex].unk_0AE == 0) { + func_80072428(objectIndex); + } + break; + } +} + +void OGrandPrixBalloons::func_80041480(s16* arg0, s16 arg1, s16 arg2, s16* arg3) { + *arg0 += *arg3; + if (*arg3 >= 0) { + if (*arg0 >= arg2) { + *arg0 = arg2; + *arg3 = -*arg3; + } + } else if (arg1 >= *arg0) { + *arg0 = arg1; + *arg3 = -*arg3; + } +}
\ No newline at end of file diff --git a/src/engine/objects/GrandPrixBalloons.h b/src/engine/objects/GrandPrixBalloons.h new file mode 100644 index 000000000..93ec04479 --- /dev/null +++ b/src/engine/objects/GrandPrixBalloons.h @@ -0,0 +1,55 @@ +#pragma once + +#include <libultraship.h> +#include <vector> + +#include "engine/World.h" +#include "engine/objects/Object.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" +} + + + +/** + * Grand Prix Balloons OObject + */ +class OGrandPrixBalloons : public OObject { +public: + + explicit OGrandPrixBalloons(const FVector& pos); + + ~OGrandPrixBalloons() { + _count--; + } + + static size_t GetCount() { + return _count; + } + + virtual void Tick() override; + virtual void Draw(s32 cameraId) override; + void func_80053D74(s32 objectIndex, UNUSED s32 arg1, s32 vertexIndex); + + void func_80074924(s32 objectIndex); + void func_80074D94(s32 objectIndex); + void func_80074E28(s32 objectIndex); + void func_80041480(s16* arg0, s16 arg1, s16 arg2, s16* arg3); // Some weird math function + +private: + static size_t _count; + s32 _idx; + FVector Pos; + bool _active; + size_t _numBalloons; + size_t _numBalloons2; + size_t _numBalloons3; +}; diff --git a/src/engine/objects/Hedgehog.cpp b/src/engine/objects/Hedgehog.cpp index 133a1f38d..ebc5b30bb 100644 --- a/src/engine/objects/Hedgehog.cpp +++ b/src/engine/objects/Hedgehog.cpp @@ -15,10 +15,12 @@ extern "C" { size_t OHedgehog::_count = 0; OHedgehog::OHedgehog(const FVector& pos, const FVector2D& patrolPoint, s16 unk) { + Name = "Hedgehog"; _idx = _count; _pos = pos; s32 objectId = indexObjectList2[_idx]; + _objectIndex = objectId; 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; diff --git a/src/engine/objects/HotAirBalloon.cpp b/src/engine/objects/HotAirBalloon.cpp index 917fd7354..4e337d98e 100644 --- a/src/engine/objects/HotAirBalloon.cpp +++ b/src/engine/objects/HotAirBalloon.cpp @@ -15,6 +15,7 @@ extern "C" { } OHotAirBalloon::OHotAirBalloon(const FVector& pos) { + Name = "Hot Air Balloon"; _pos = pos; D_80165898 = 0; diff --git a/src/engine/objects/HotAirBalloon.h b/src/engine/objects/HotAirBalloon.h index 5dad406db..301e111c4 100644 --- a/src/engine/objects/HotAirBalloon.h +++ b/src/engine/objects/HotAirBalloon.h @@ -31,5 +31,4 @@ public: private: FVector _pos; bool *_visible; - s32 _objectIndex; }; diff --git a/src/engine/objects/Lakitu.cpp b/src/engine/objects/Lakitu.cpp index 93a87f5e1..12ca2d7db 100644 --- a/src/engine/objects/Lakitu.cpp +++ b/src/engine/objects/Lakitu.cpp @@ -37,6 +37,7 @@ extern s8 gPlayerCount; } OLakitu::OLakitu(s32 playerId, LakituType type) { + Name = "Lakitu"; _playerId = playerId; init_object(gIndexLakituList[playerId], (s32)type); diff --git a/src/engine/objects/Mole.cpp b/src/engine/objects/Mole.cpp index fdf5e7b08..06bd5f56c 100644 --- a/src/engine/objects/Mole.cpp +++ b/src/engine/objects/Mole.cpp @@ -25,6 +25,7 @@ extern "C" { size_t OMole::_count = 0; OMole::OMole(FVector pos, OMoleGroup* group) { + Name = "Mole"; _idx = _count; _group = group; diff --git a/src/engine/objects/Mole.h b/src/engine/objects/Mole.h index 7707b5383..1457c72cc 100644 --- a/src/engine/objects/Mole.h +++ b/src/engine/objects/Mole.h @@ -40,7 +40,6 @@ public: void func_80081790(s32 objectIndex); void func_8008153C(s32 objectIndex); - s32 _objectIndex; s32 _moleIndex; private: static size_t _count; diff --git a/src/engine/objects/Object.cpp b/src/engine/objects/Object.cpp index d532dd566..4e4fd6766 100644 --- a/src/engine/objects/Object.cpp +++ b/src/engine/objects/Object.cpp @@ -18,6 +18,6 @@ void OObject::Tick60fps() {} void OObject::Draw(s32 cameraId) { } void OObject::Expire() { } void OObject::Destroy() { - PendingDestroy = true; + bPendingDestroy = true; } void OObject::Reset() { } diff --git a/src/engine/objects/Object.h b/src/engine/objects/Object.h index b78b27240..9dd44397b 100644 --- a/src/engine/objects/Object.h +++ b/src/engine/objects/Object.h @@ -11,7 +11,9 @@ class OObject { public: uint8_t uuid[16]; Object o; - bool PendingDestroy = false; + const char* Name = ""; + bool bPendingDestroy = false; + s32 _objectIndex = -1; virtual ~OObject() = default; diff --git a/src/engine/objects/Penguin.cpp b/src/engine/objects/Penguin.cpp index 1eeb00ff4..d283101b3 100644 --- a/src/engine/objects/Penguin.cpp +++ b/src/engine/objects/Penguin.cpp @@ -34,7 +34,8 @@ extern s8 gPlayerCount; } -OPenguin::OPenguin(Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour) { +OPenguin::OPenguin(FVector pos, u16 direction, PenguinType type, Behaviour behaviour) { + Name = "Penguin"; _type = type; _bhv = behaviour; @@ -43,9 +44,9 @@ OPenguin::OPenguin(Vec3f pos, u16 direction, PenguinType type, Behaviour behavio 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->origin_pos[0] = pos.x * xOrientation; + object->origin_pos[1] = pos.y; + object->origin_pos[2] = pos.z; object->unk_0C6 = direction; switch(type) { diff --git a/src/engine/objects/Penguin.h b/src/engine/objects/Penguin.h index 72ba16285..91d5687b9 100644 --- a/src/engine/objects/Penguin.h +++ b/src/engine/objects/Penguin.h @@ -38,7 +38,7 @@ public: f32 Diameter = 0.0f; // Waddle in a circle around the spawn point at this diameter. uint16_t MirrorModeAngleOffset; - explicit OPenguin(Vec3f pos, u16 direction, PenguinType type, Behaviour behaviour); + explicit OPenguin(FVector pos, u16 direction, PenguinType type, Behaviour behaviour); virtual void Tick() override; virtual void Draw(s32 cameraId) override; @@ -55,7 +55,6 @@ private: void InitOtherPenguin(s32 objectIndex); static bool _toggle; - s32 _objectIndex; PenguinType _type; Behaviour _bhv; }; diff --git a/src/engine/objects/Podium.cpp b/src/engine/objects/Podium.cpp index d8f1e2ff2..ec396ca53 100644 --- a/src/engine/objects/Podium.cpp +++ b/src/engine/objects/Podium.cpp @@ -26,7 +26,7 @@ extern Vec3s D_800E634C[]; // }; OPodium::OPodium(const FVector& pos) { - + Name = "Podium"; _pos = pos; find_unused_obj_index(&_podium1Index); diff --git a/src/engine/objects/Seagull.cpp b/src/engine/objects/Seagull.cpp index 11043238f..17c35c07d 100644 --- a/src/engine/objects/Seagull.cpp +++ b/src/engine/objects/Seagull.cpp @@ -32,6 +32,7 @@ SplineData* D_800E633C[] = { &D_800E6034, &D_800E60F0, &D_800E61B4, &D_800E6280 size_t OSeagull::_count = 0; OSeagull::OSeagull(FVector pos) { + Name = "Seagull"; _idx = _count; _pos.x = pos.x; _pos.y = pos.y; diff --git a/src/engine/objects/Seagull.h b/src/engine/objects/Seagull.h index a0e5cd233..42474159e 100644 --- a/src/engine/objects/Seagull.h +++ b/src/engine/objects/Seagull.h @@ -38,7 +38,6 @@ public: void func_8008241C(s32 objectIndex, s32 arg1); void func_80082714(s32 objectIndex, s32 arg1); private: - s32 _objectIndex; FVector _pos; static size_t _count; s32 _idx; diff --git a/src/engine/objects/Snowman.cpp b/src/engine/objects/Snowman.cpp index 2052a8adb..12beb9e47 100644 --- a/src/engine/objects/Snowman.cpp +++ b/src/engine/objects/Snowman.cpp @@ -17,11 +17,13 @@ static const char* sSnowmanHeadList[] = { d_course_frappe_snowland_snowman_head size_t OSnowman::_count = 0; OSnowman::OSnowman(const FVector& pos) { + Name = "Snowman"; _idx = _count; _pos = pos; find_unused_obj_index(&_headIndex); init_object(_headIndex, 0); + _objectIndex = _headIndex; gObjectList[_headIndex].origin_pos[0] = pos.x * xOrientation; gObjectList[_headIndex].origin_pos[1] = pos.y + 5.0 + 3.0; gObjectList[_headIndex].origin_pos[2] = pos.z; diff --git a/src/engine/objects/Snowman.h b/src/engine/objects/Snowman.h index ffa927769..f33ee3b53 100644 --- a/src/engine/objects/Snowman.h +++ b/src/engine/objects/Snowman.h @@ -50,7 +50,6 @@ private: FVector _pos; static size_t _count; size_t _idx; - s32 _objectIndex; s32 _headIndex; s32 _bodyIndex; }; diff --git a/src/engine/objects/Thwomp.cpp b/src/engine/objects/Thwomp.cpp index 6a04f07bb..d3f99a8d9 100644 --- a/src/engine/objects/Thwomp.cpp +++ b/src/engine/objects/Thwomp.cpp @@ -47,6 +47,7 @@ s16 D_800E597C[] = { 0x0000, 0x0000, 0x4000, 0x8000, 0x8000, 0xc000 }; size_t OThwomp::_count = 0; OThwomp::OThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) { + Name = "Thwomp"; _idx = _count; _faceDirection = direction; _boundingBoxSize = boundingBoxSize; diff --git a/src/engine/objects/Thwomp.h b/src/engine/objects/Thwomp.h index 75aeaf1a0..22c674bb5 100644 --- a/src/engine/objects/Thwomp.h +++ b/src/engine/objects/Thwomp.h @@ -113,7 +113,6 @@ public: private: static size_t _count; s32 _idx; - s32 _objectIndex; s16 _faceDirection; //! @todo Write this better. This effects the squish size and the bounding box size. // We should probably return to the programmer the pointer to the actor so they can do thwomp->squishSize = value. diff --git a/src/engine/objects/TrashBin.cpp b/src/engine/objects/TrashBin.cpp index 6aa556470..c94d0352f 100644 --- a/src/engine/objects/TrashBin.cpp +++ b/src/engine/objects/TrashBin.cpp @@ -20,7 +20,8 @@ extern "C" { #define DEGREES_FLOAT_TO_SHORT(Degrees) ((s16)((Degrees) * (0x8000 / 180.0f))) -OTrashBin::OTrashBin(const FVector& pos, const FRotation& rotation, f32 scale, OTrashBin::Behaviour bhv) { +OTrashBin::OTrashBin(const FVector& pos, const IRotator& rotation, f32 scale, OTrashBin::Behaviour bhv) { + Name = "Trashbin"; _pos = pos; _rot = rotation; _scale = scale; diff --git a/src/engine/objects/TrashBin.h b/src/engine/objects/TrashBin.h index 2ebe13e87..3e878e1c0 100644 --- a/src/engine/objects/TrashBin.h +++ b/src/engine/objects/TrashBin.h @@ -24,7 +24,7 @@ public: STATIC, // The lid stays shut MUNCHING // The lid opens/closes in a scary munching manner }; - explicit OTrashBin(const FVector& pos, const FRotation& rotation, f32 scale, OTrashBin::Behaviour bhv); + explicit OTrashBin(const FVector& pos, const IRotator& rotation, f32 scale, OTrashBin::Behaviour bhv); virtual void Tick() override; virtual void Draw(s32 cameraId) override; @@ -38,9 +38,8 @@ private: Behaviour _bhv; FVector _pos; - FRotation _rot; + IRotator _rot; float _scale; size_t _idx; - s32 _objectIndex; bool _drawBin = false; }; diff --git a/src/engine/objects/Trophy.cpp b/src/engine/objects/Trophy.cpp index 54bd70d3e..9f90b6be1 100644 --- a/src/engine/objects/Trophy.cpp +++ b/src/engine/objects/Trophy.cpp @@ -21,6 +21,7 @@ extern "C" { } OTrophy::OTrophy(const FVector& pos, TrophyType trophy, Behaviour bhv) { + Name = "Trophy"; _trophy = trophy; _spawnPos = pos; _spawnPos.y += 16.0f; // Adjust the height so the trophy sits on the surface when positioned to 0,0,0 diff --git a/src/engine/objects/Trophy.h b/src/engine/objects/Trophy.h index c2bb937ab..89f130997 100644 --- a/src/engine/objects/Trophy.h +++ b/src/engine/objects/Trophy.h @@ -48,7 +48,6 @@ public: private: StarEmitter* _emitter; - s32 _objectIndex; TrophyType _trophy; FVector _spawnPos; Behaviour _bhv; diff --git a/src/engine/vehicles/Boat.cpp b/src/engine/vehicles/Boat.cpp index 460331f97..073974581 100644 --- a/src/engine/vehicles/Boat.cpp +++ b/src/engine/vehicles/Boat.cpp @@ -17,6 +17,7 @@ extern s8 gPlayerCount; size_t ABoat::_count = 0; ABoat::ABoat(f32 speed, u32 waypoint) { + Name = "Paddle Steam Boat"; Path2D* temp_a2; u16 waypointOffset; Index = _count; diff --git a/src/engine/vehicles/Bus.cpp b/src/engine/vehicles/Bus.cpp index 43b6e7406..c58cd0a6c 100644 --- a/src/engine/vehicles/Bus.cpp +++ b/src/engine/vehicles/Bus.cpp @@ -19,6 +19,7 @@ extern s8 gPlayerCount; size_t ABus::_count = 0; ABus::ABus(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { + Name = "Bus"; TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; diff --git a/src/engine/vehicles/Car.cpp b/src/engine/vehicles/Car.cpp index a5dd49007..89409df50 100644 --- a/src/engine/vehicles/Car.cpp +++ b/src/engine/vehicles/Car.cpp @@ -19,6 +19,7 @@ extern s8 gPlayerCount; size_t ACar::_count = 0; ACar::ACar(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { + Name = "Car"; TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; diff --git a/src/engine/vehicles/TankerTruck.cpp b/src/engine/vehicles/TankerTruck.cpp index a6b94429f..02cd9553b 100644 --- a/src/engine/vehicles/TankerTruck.cpp +++ b/src/engine/vehicles/TankerTruck.cpp @@ -19,6 +19,7 @@ extern s8 gPlayerCount; size_t ATankerTruck::_count = 0; ATankerTruck::ATankerTruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { + Name = "Tanker Truck"; TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; diff --git a/src/engine/vehicles/Train.cpp b/src/engine/vehicles/Train.cpp index 14d9c9763..a3952742d 100644 --- a/src/engine/vehicles/Train.cpp +++ b/src/engine/vehicles/Train.cpp @@ -25,6 +25,7 @@ extern "C" { size_t ATrain::_count = 0; ATrain::ATrain(ATrain::TenderStatus tender, size_t numCarriages, f32 speed, uint32_t waypoint) { + Name = "Train"; u16 waypointOffset; TrainCarStuff* ptr1; Path2D* pos; diff --git a/src/engine/vehicles/Truck.cpp b/src/engine/vehicles/Truck.cpp index 68ef87353..585293489 100644 --- a/src/engine/vehicles/Truck.cpp +++ b/src/engine/vehicles/Truck.cpp @@ -19,6 +19,7 @@ extern s8 gPlayerCount; size_t ATruck::_count = 0; ATruck::ATruck(f32 speedA, f32 speedB, TrackWaypoint* path, uint32_t waypoint) { + Name = "Truck"; TrackWaypoint* temp_v0; u16 waypointOffset; s32 numWaypoints = gWaypointCountByPathIndex[0]; |
