Implement SpawnParams struct (#536)

* Impl SpawnParams

* Added json submodule

* Update json

* Update

* Works

* Remove comment

* Works refactor

* Snowman and thwomp working

* Impl hot air balloon

* More progress

* All OObjects are done

* cleanup

* Refactor 2Dpath to normal path

* Update nlohmann json & fix compile

* Rest of actors

* MORE CHANGES

* Finish actors

* Done PR, some fix to collision viewer

* Impl falling rocks

* Add const

* wip editor refactor

* Property work

* continue

* Overridable editor properties

* Actor saving/loading works now

* Fix light alignment

* Clarification

* Impl penguin

* params impl signs

* properties impl falling rock

* More property impls

* impl air balloon

* Add spawnParams to OObject Translate

* Snowman translate better

* impl hedgehog properly

* properties impl trophy

* thwomp progress

* Finish impl properties

* Fix compile

* Fix cursor collisions

* Move registered actors

* Rename pathPoint XYZ to xyz

* Fix editor pause bug

* Clean up

* Review comments

* Remove SpawnParams struct from actor classes

* Rename

* Player Label First Iteration

* Work now

* Working 3d text

* Fix boo bug

* Finish AText actor

* Fix spawnparams compile

* Register AText

* Finish Text Actor

* Fix thwomp interpolation

* Fix compile

* Fix crab and hedgehog

* Fix loading flagpole

* Fix Hot Air Balloon

* Turn zbuffer on for AText

* Update

---------

Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
This commit is contained in:
MegaMech
2025-11-09 19:07:44 -07:00
committed by GitHub
parent 760fa3bf52
commit de9c5d5101
177 changed files with 6967 additions and 2105 deletions
+2
View File
@@ -70,6 +70,7 @@ set(CMAKE_OSX_ARCHITECTURES=arm64;x86_64)
# Set the C++ standard and enable the MSVC parallel build option
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use")
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Spaghettify)
set(PROJECT_TEAM "MegaMech")
@@ -309,6 +310,7 @@ else()
add_executable(${PROJECT_NAME} ${ALL_FILES})
endif()
################################################################################
# MSVC runtime library
################################################################################
+2 -2
View File
@@ -62,9 +62,9 @@ enum ActorType {
ACTOR_MARIO_SIGN,
ACTOR_UNKNOWN_0x18,
ACTOR_PALM_TREE,
ACTOR_UNKNOWN_0x1A,
ACTOR_TREE_LUIGI_RACEWAY,
ACTOR_UNKNOWN_0x1B,
ACTOR_TREE_BOWSERS_CASTLE,
ACTOR_TREE_PEACH_CASTLE,
ACTOR_TREE_FRAPPE_SNOWLAND,
ACTOR_CACTUS1_KALAMARI_DESERT,
ACTOR_CACTUS2_KALAMARI_DESERT,
+9
View File
@@ -112,6 +112,15 @@
#define FOUR_PLAYERS_SELECTED 4
#define SELECTED_PLAYER_DEFINES_TOTAL 5
// Camera index into cameras array
enum CameraId {
CAMERA_ONE = 0,
CAMERA_TWO,
CAMERA_THREE,
CAMERA_FOUR,
CAMERA_FREECAM
};
enum PlayerId {
PLAYER_NONE = -1,
PLAYER_ONE = 0,
+3 -3
View File
@@ -12,9 +12,9 @@ enum {
};
typedef struct {
/* 0x00 */ s16 posX;
/* 0x02 */ s16 posY;
/* 0x04 */ s16 posZ;
/* 0x00 */ s16 x;
/* 0x02 */ s16 y;
/* 0x04 */ s16 z;
/* 0x06 */ u16 trackSectionId;
} TrackPathPoint; // size = 0x08
+9 -9
View File
@@ -30,9 +30,9 @@ void func_802B3B44(struct ShellActor* shell) {
Vec3f origPos;
currentWaypoint = shell->pathIndex;
temp_f2 = gCurrentTrackPath[currentWaypoint].posX;
temp_f12 = gCurrentTrackPath[currentWaypoint].posY;
temp_f28 = gCurrentTrackPath[currentWaypoint].posZ;
temp_f2 = gCurrentTrackPath[currentWaypoint].x;
temp_f12 = gCurrentTrackPath[currentWaypoint].y;
temp_f28 = gCurrentTrackPath[currentWaypoint].z;
nextWaypoint = currentWaypoint + 1;
if (nextWaypoint >= gSelectedPathCount) {
@@ -44,9 +44,9 @@ void func_802B3B44(struct ShellActor* shell) {
temp_f24 = temp_f28 - shell->pos[2];
temp_f0 = (temp_f20 * temp_f20) + (temp_f22 * temp_f22) + (temp_f24 * temp_f24);
if (temp_f0 > 400.0f) {
temp_f18_3 = gCurrentTrackPath[nextWaypoint].posX;
temp_f16_3 = gCurrentTrackPath[nextWaypoint].posY;
temp_f26 = gCurrentTrackPath[nextWaypoint].posZ;
temp_f18_3 = gCurrentTrackPath[nextWaypoint].x;
temp_f16_3 = gCurrentTrackPath[nextWaypoint].y;
temp_f26 = gCurrentTrackPath[nextWaypoint].z;
temp_f12_0 = temp_f18_3 - shell->pos[0];
temp_f12_1 = temp_f16_3 - shell->pos[1];
@@ -97,9 +97,9 @@ void func_802B3B44(struct ShellActor* shell) {
shell->pos[2] = temp_f28;
shell->pathIndex = nextWaypoint;
} else {
temp_f18_3 = gCurrentTrackPath[nextWaypoint].posX;
temp_f16_3 = gCurrentTrackPath[nextWaypoint].posY;
temp_f26 = gCurrentTrackPath[nextWaypoint].posZ;
temp_f18_3 = gCurrentTrackPath[nextWaypoint].x;
temp_f16_3 = gCurrentTrackPath[nextWaypoint].y;
temp_f26 = gCurrentTrackPath[nextWaypoint].z;
shell->pos[0] = (temp_f2 + temp_f18_3) * 0.5f;
shell->pos[1] = ((temp_f12 + temp_f16_3) * 0.5f) + shell->boundingBoxSize;
+3 -3
View File
@@ -31,9 +31,9 @@ void update_actor_kiwano_fruit(struct KiwanoFruit* fruit) {
fruit->velocity[0] = 80.0f;
case 1:
nearestWaypoint = gNearestPathPointByPlayerId[(u16) (player - gPlayerOne)];
temp_f2 = player->pos[0] - gCurrentTrackPath[nearestWaypoint].posX;
temp_f16 = player->pos[1] - gCurrentTrackPath[nearestWaypoint].posY;
temp_f14 = player->pos[2] - gCurrentTrackPath[nearestWaypoint].posZ;
temp_f2 = player->pos[0] - gCurrentTrackPath[nearestWaypoint].x;
temp_f16 = player->pos[1] - gCurrentTrackPath[nearestWaypoint].y;
temp_f14 = player->pos[2] - gCurrentTrackPath[nearestWaypoint].z;
temp_f12 = fruit->velocity[0] / sqrtf((temp_f2 * temp_f2) + (temp_f16 * temp_f16) + (temp_f14 * temp_f14));
temp_f2 *= temp_f12;
temp_f16 *= temp_f12;
+13 -1
View File
@@ -4,6 +4,18 @@
#include <assets/mario_raceway_data.h>
#include <assets/royal_raceway_data.h>
const char* sPiranhaPlantTextures[] = {
gTexturePiranhaPlant1,
gTexturePiranhaPlant2,
gTexturePiranhaPlant3,
gTexturePiranhaPlant4,
gTexturePiranhaPlant5,
gTexturePiranhaPlant6,
gTexturePiranhaPlant7,
gTexturePiranhaPlant8,
gTexturePiranhaPlant9
};
/**
* @brief Renders the piranha plant actor.
* Actor used in Mario Raceway and Royal Raceway.
@@ -115,7 +127,7 @@ void render_actor_piranha_plant(Camera* arg0, Mat4 arg1, struct PiranhaPlant* ar
if (animationFrame > 8) {
animationFrame = 8;
}
addr = D_802BA058 + (animationFrame << 0xB);
addr = LOAD_ASSET(sPiranhaPlantTextures[animationFrame]);
gDPLoadTextureBlock(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(addr), G_IM_FMT_CI, G_IM_SIZ_8b, 32, 64, 0,
G_TX_MIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
+4 -14
View File
@@ -162,8 +162,7 @@ void render_actor_tree_moo_moo_farm(Camera* camera, Mat4 arg1, struct Actor* arg
}
}
// have all the properties of the tree
void func_80299864(Camera* camera, Mat4 arg1, struct Actor* arg2) {
void render_actor_tree_luigi_raceway(Camera* camera, Mat4 arg1, struct Actor* arg2) {
f32 temp_f0;
s16 temp_v0 = arg2->flags;
@@ -195,27 +194,18 @@ void func_80299864(Camera* camera, Mat4 arg1, struct Actor* arg2) {
// Based on the TLUT being loaded above, this ought to be be another
// tree related DL, presumably one found in a course other than Moo Moo farm
// 0x0600FC70
//! @warning Possible bug:
// Previous incorrectly set to:
// d_course_moo_moo_farm_mole_tlut
// Unless both courses use this actor and use the same addr for the texture.
// Just in-case changed the code into a switch to prevent future crashes.
// This comment can be removed when this is confirmed to work.
if (IsLuigiRaceway()) {
gSPDisplayList(gDisplayListHead++, d_course_luigi_raceway_dl_FC70);
}
gSPDisplayList(gDisplayListHead++, d_course_luigi_raceway_dl_FC70);
}
}
/**
* @brief Renders the tree actor in Bowser's Castle.
* @brief Renders Peach's Castle trees in Royal Raceway.
*
* @param camera
* @param arg1
* @param arg2
*/
void render_actor_tree_bowser_castle(Camera* camera, Mat4 arg1, struct Actor* arg2) {
void render_actor_tree_peach_castle(Camera* camera, Mat4 arg1, struct Actor* arg2) {
f32 temp_f0;
s16 temp_v0 = arg2->flags;
+5 -6
View File
@@ -377,10 +377,10 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3,
if (IsToadsTurnpike()) {
var_f14 = sp5C[0];
} else {
var_f14 = sp5C[0] + temp_s2->posX;
var_f14 = sp5C[0] + temp_s2->x;
}
temp_f16 = D_80165230[7] + sp5C[2];
temp_f18 = sp5C[1] + (temp_s2->posY + D_80164A30);
temp_f18 = sp5C[1] + (temp_s2->y + D_80164A30);
arg2[0] += (var_f14 - camera->lookAt[0]) * 1;
arg2[1] += (temp_f18 - camera->lookAt[1]) * 1;
arg2[2] += (temp_f16 - camera->lookAt[2]) * 1;
@@ -388,10 +388,10 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3,
if (IsToadsTurnpike()) {
var_f14 = sp68[0];
} else {
var_f14 = sp68[0] + temp_s2->posX;
var_f14 = sp68[0] + temp_s2->x;
}
temp_f16 = D_80165230[7] + sp68[2];
temp_f18 = sp68[1] + (temp_s2->posY + D_80164A30 + 6.0f);
temp_f18 = sp68[1] + (temp_s2->y + D_80164A30 + 6.0f);
move_f32_towards(&D_80164A30, 0, 0.02f);
posX = camera->pos[0];
*arg3 = ((var_f14 - posX) * 1) + posX;
@@ -1113,8 +1113,7 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) {
func_8001E8E8(camera, player, index);
break;
}
freecam(camera, player, index); // Runs func_8001E45C when freecam is disabled
//func_8001E45C(camera, player, index);
func_8001E45C(camera, player, index);
break;
case 8: // Transition start
func_8001E0C4(camera, player, index);
+49 -2
View File
@@ -61,7 +61,7 @@ struct UnkStruct_800DC5EC* D_800DC5F0 = &D_8015F480[1];
struct UnkStruct_800DC5EC* D_800DC5F4 = &D_8015F480[2];
struct UnkStruct_800DC5EC* D_800DC5F8 = &D_8015F480[3];
u16 gIsGamePaused = false; // true if the game is paused and false if the game is not paused
bool gIsEditorPaused = false;
bool gIsEditorPaused = true;
u8* pAppNmiBuffer = (u8*) &osAppNmiBuffer;
s32 gIsMirrorMode = 0;
@@ -188,6 +188,7 @@ void setup_race(void) {
int i;
LUSLOG_DEBUG("Setup Race!", 0);
LUSLOG_DEBUG("Game Speed: %d", gTickLogic);
gPlayerCountSelection1 = gPlayerCount;
if (gGamestate != RACING) {
@@ -230,7 +231,7 @@ void setup_race(void) {
D_80152308 = 0;
D_802BA038 = -1;
D_802BA048 = 0;
func_802A74BC();
set_screen();
func_802A4D18();
func_80091FA4();
init_actors_and_load_textures();
@@ -266,6 +267,52 @@ void setup_race(void) {
}
}
void setup_editor(void) {
LUSLOG_DEBUG("Setup Editor!", 0);
LUSLOG_DEBUG("Game Speed: %d", gTickLogic);
gPlayerCountSelection1 = 1;
if (gGamestate != RACING) {
gIsMirrorMode = 0;
}
gActiveScreenMode = gScreenModeSelection;
if (gCurrentCourseId != gCurrentlyLoadedCourseId) {
D_80150120 = 0;
gCurrentlyLoadedCourseId = gCurrentCourseId;
gNextFreeMemoryAddress = gFreeMemoryResetAnchor;
load_course(gCurrentCourseId);
course_init();
gFreeMemoryCourseAnchor = gNextFreeMemoryAddress;
} else {
gNextFreeMemoryAddress = gFreeMemoryCourseAnchor;
}
if (gIsMirrorMode) {
gCourseDirection = -1.0f;
} else {
gCourseDirection = 1.0f;
}
// Cow related
D_8015F702 = 0;
D_8015F700 = 200;
func_80005310();
func_8003D080();
init_hud();
gRaceState = RACE_INIT;
gNumSpawnedShells = 0;
D_800DC5B8 = 0;
D_80152308 = 0;
D_802BA038 = -1;
D_802BA048 = 0;
set_editor_screen();
func_802A4D18();
func_80091FA4();
init_actors_and_load_textures();
}
void func_80002DAC(void) {
CM_SomeSounds();
+1
View File
@@ -30,6 +30,7 @@ struct UnkStruct_800DC5EC {
void func_800029B0(void);
void setup_race(void);
void setup_editor(void);
void func_80002DAC(void);
void clear_nmi_buffer(void);
void credits_spawn_actors(void);
+256 -227
View File
File diff suppressed because it is too large Load Diff
+6 -9
View File
@@ -44,11 +44,6 @@ typedef struct {
u16 unk6;
} UnkStruct_46D0;
typedef struct {
s16 x;
s16 z;
} Path2D;
enum CpuItemStrategyEnum {
CPU_STRATEGY_WAIT_NEXT_ITEM = 0,
@@ -181,7 +176,7 @@ f32 func_80010FA0(f32, f32, f32, s32, s32);
s32 func_80011014(TrackPathPoint*, TrackPathPoint*, s32, s32);
s32 process_path_data(TrackPathPoint*, TrackPathPoint*);
s32 generate_2d_path(Path2D*, TrackPathPoint*, s32);
s32 generate_2d_path(TrackPathPoint*, TrackPathPoint*, s32);
void copy_courses_cpu_behaviour(void);
void reset_cpu_behaviour_none(s32);
void reset_cpu_behaviour(s32);
@@ -194,7 +189,7 @@ void generate_train_path(void);
void generate_ferry_path(void);
void spawn_vehicle_on_road(Vec3f position, Vec3s rotation, Vec3f velocity, s32 waypointIndex,
s32 someMultiplierTheSequel, f32 speed);
void set_vehicle_pos_path_point(TrainCarStuff*, Path2D*, u16);
void set_vehicle_pos_path_point(TrainCarStuff*, TrackPathPoint*, u16);
void init_vehicles_trains(size_t, size_t, f32);
void sync_train_components(TrainCarStuff*, s16);
void update_vehicle_trains(void);
@@ -375,8 +370,10 @@ extern s16 D_801634EC;
extern s32 D_801634F0;
extern s32 D_801634F4;
extern TrackPositionFactorInstruction gPlayerTrackPositionFactorInstruction[];
extern Path2D* gVehicle2DPathPoint;
extern s32 gVehicle2DPathLength;
extern TrackPathPoint* gVehicle2DPathPoint;
extern s32 gVehicle2DPathSize;
extern TrackPathPoint* gVehiclePath;
extern size_t gVehiclePathSize;
extern u16 isCrossingTriggeredByIndex[];
extern u16 sCrossingActiveTimer[];
extern s32 D_80163DD8[];
+18 -6
View File
@@ -543,12 +543,18 @@ void render_object(u32 arg0) {
}
void render_object_p1(void) {
size_t playerIdx = PLAYER_ONE;
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_ONE),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_ONE),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
if (CVarGetInteger("gFreecam", 0) == true) {
playerIdx = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
// if (gGamestate == ENDING) {
// //func_80055F48(PLAYER_ONE);
@@ -639,10 +645,16 @@ void render_player_snow_effect(u32 arg0) {
}
void render_player_snow_effect_one(void) {
size_t playerIdx = PLAYER_ONE;
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_ONE),
if (CVarGetInteger("gFreecam", 0) == true) {
playerIdx = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_ONE),
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
if (gGamestate != ENDING) {
render_snowing_effect(PLAYER_ONE);
+15 -15
View File
@@ -1711,15 +1711,15 @@ void func_80090178(Player* player, s8 playerId, Vec3f arg2, Vec3f arg3) {
if (IsYoshiValley()) {
test = player->nearestPathPointId;
temp_v1 = &gTrackPaths[gCopyPathIndexByPlayerId[playerId]][test];
arg2[0] = temp_v1->posX;
arg2[1] = temp_v1->posY;
arg2[2] = temp_v1->posZ;
arg2[0] = temp_v1->x;
arg2[1] = temp_v1->y;
arg2[2] = temp_v1->z;
temp_v1 = &gTrackPaths[gCopyPathIndexByPlayerId[playerId]]
[(player->nearestPathPointId + 5) %
(gPathCountByPathIndex[gCopyPathIndexByPlayerId[playerId]] + 1)];
arg3[0] = temp_v1->posX;
arg3[1] = temp_v1->posY;
arg3[2] = temp_v1->posZ;
arg3[0] = temp_v1->x;
arg3[1] = temp_v1->y;
arg3[2] = temp_v1->z;
} else if (IsBlockFort()) {
arg2[0] = spF8[playerId];
arg2[1] = 0.0f;
@@ -1751,13 +1751,13 @@ void func_80090178(Player* player, s8 playerId, Vec3f arg2, Vec3f arg3) {
} else {
test = player->nearestPathPointId;
temp_v1 = &gTrackPaths[0][test];
arg2[0] = temp_v1->posX;
arg2[1] = temp_v1->posY;
arg2[2] = temp_v1->posZ;
arg2[0] = temp_v1->x;
arg2[1] = temp_v1->y;
arg2[2] = temp_v1->z;
temp_v1 = &gTrackPaths[0][(player->nearestPathPointId + 5) % (gPathCountByPathIndex[0] + 1)];
arg3[0] = temp_v1->posX;
arg3[1] = temp_v1->posY;
arg3[2] = temp_v1->posZ;
arg3[0] = temp_v1->x;
arg3[1] = temp_v1->y;
arg3[2] = temp_v1->z;
}
}
@@ -1925,9 +1925,9 @@ void func_80090970(Player* player, s8 playerId, s8 arg2) {
}
if (player->unk_0C8 == 0x00FC) {
waypoint = gTrackPaths[0];
player->pos[0] = waypoint->posX;
player->pos[1] = waypoint->posY;
player->pos[2] = waypoint->posZ;
player->pos[0] = waypoint->x;
player->pos[1] = waypoint->y;
player->pos[2] = waypoint->z;
}
move_f32_towards(&player->pos[1], (player->unk_074 + player->boundingBoxSize) - 2.0f, 0.04f);
player->unk_0C8++;
+2 -1
View File
@@ -71,6 +71,7 @@ void func_80280038(void) {
render_set_position(matrix, 0);
render_course(D_800DC5EC);
render_course_actors(D_800DC5EC);
CM_DrawActors(D_800DC5EC->camera);
CM_DrawStaticMeshActors();
render_object(PLAYER_ONE + SCREEN_MODE_1P);
render_player_snow_effect(PLAYER_ONE + SCREEN_MODE_1P);
@@ -138,7 +139,7 @@ void load_credits(void) {
D_800DC5B4 = 1;
creditsRenderMode = 1;
func_802A4D18();
func_802A74BC();
set_screen();
camera->unk_B4 = 60.0f;
gCameraZoom[0] = 60.0f;
D_800DC5EC->screenWidth = SCREEN_WIDTH;
+1 -1
View File
@@ -104,7 +104,7 @@ void setup_podium_ceremony(void) {
gGotoMenu = 0xFFFF;
D_80287554 = 0;
func_802A4D18();
func_802A74BC();
set_screen();
camera->unk_B4 = 60.0f;
gCameraZoom[0] = 60.0f;
D_800DC5EC->screenWidth = SCREEN_WIDTH;
+63 -4
View File
@@ -1,13 +1,35 @@
#include <libultraship.h>
#include "Matrix.h"
#include "Actor.h"
#include "engine/World.h"
// Editor
#include "engine/editor/Collision.h"
extern "C" {
#include "math_util.h"
}
AActor::AActor() {}
AActor::AActor(SpawnParams params) {
ResourceName = "mk:actor"; // This needs to be overridden in derived classes
SpawnPos = params.Location.value_or(FVector{0.0f, 0.0f, 0.0f});
SpawnRot = params.Rotation.value_or(IRotator{0, 0, 0});
SpawnScale = params.Scale.value_or(FVector(0, 0, 0));
Speed = params.Speed.value_or(0.0f);
}
void AActor::BeginPlay() {
// This makes actors clickable in the editor
if (CVarGetInteger("gEditorEnabled", false) == true) {
if ((nullptr != Model) && (Model[0] != '\0')) {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(Model), 1.0f);
}
}
}
}
// Virtual functions to be overridden by derived classes
void AActor::Tick() { }
@@ -20,15 +42,14 @@ void AActor::Draw(Camera *camera) {
ApplyMatrixTransformations(mtx, *(FVector*)Pos, *(IRotator*)Rot, Scale);
if (render_set_position(mtx, 0) != 0) {
gSPDisplayList(gDisplayListHead++, Model);
gSPDisplayList(gDisplayListHead++, (Gfx*)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));
bPendingDestroy = true;
}
bool AActor::IsMod() { return false; }
void AActor::SetLocation(FVector pos) {
@@ -39,3 +60,41 @@ void AActor::SetLocation(FVector pos) {
FVector AActor::GetLocation() const {
return FVector(Pos[0], Pos[1], Pos[2]);
}
IRotator AActor::GetRotation() const {
IRotator rot;
rot.Set(Rot[0], Rot[1], Rot[2]);
return rot;
}
FVector AActor::GetScale() const {
return Scale;
}
void AActor::SetSpawnParams(SpawnParams& params) {
params.Name = ResourceName;
params.Location = SpawnPos;
params.Rotation = SpawnRot;
params.Scale = SpawnScale;
params.Speed = Speed;
}
void AActor::Translate(FVector pos) {
SpawnPos = pos;
Pos[0] = pos.x;
Pos[1] = pos.y;
Pos[2] = pos.z;
}
void AActor::Rotate(IRotator rot) {
SpawnRot = rot;
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
}
void AActor::SetScale(FVector scale) {
SpawnScale = scale;
Scale = scale;
}
+32 -7
View File
@@ -1,7 +1,8 @@
#pragma once
#include <libultraship.h>
#include "CoreMath.h"
#include "engine/SpawnParams.h"
#include "engine/editor/EditorMath.h"
extern "C" {
#include "macros.h"
@@ -9,10 +10,8 @@ extern "C" {
#include "camera.h"
#include "common_structs.h"
class AActor {
public:
/* 0x00 */ s16 Type = 0;
/* 0x02 */ s16 Flags;
/* 0x04 */ s16 Unk_04;
@@ -24,25 +23,51 @@ public:
/* 0x18 */ Vec3f Pos;
/* 0x24 */ Vec3f Velocity = {0, 0, 0};
/* 0x30 */ Collision Unk30;
/* 0x */ const char* Model = "";
uint8_t uuid[16];
const char* Name = "";
FVector Scale = {1, 1, 1};
const char* ResourceName = "";
FVector SpawnPos = {0.0f, 0.0f, 0.0f};
IRotator SpawnRot = {0, 0, 0};
FVector SpawnScale = {1.0f, 1.0f, 1.0f};
Gfx* Model = NULL;
FVector Scale = {1, 1, 1};
float Speed = 0.0f;
std::vector<Triangle> Triangles;
bool bPendingDestroy = false;
virtual ~AActor() = default; // Virtual destructor for proper cleanup in derived classes
explicit AActor();
explicit AActor(SpawnParams params);
/**
* Make sure you call this in derived classes!
* Usage:
* MyActor::SetSpawnParams(SetSpawnParams& params) {
* AActor::SetSpawnParams(params); // Calls default implementation
* }
*/
virtual void SetSpawnParams(SpawnParams& params);
virtual void BeginPlay();
virtual void Tick();
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();
/** Editor functions **/
FVector GetLocation() const;
IRotator GetRotation() const;
FVector GetScale() const;
void Translate(FVector pos);
void Rotate(IRotator rot);
void SetScale(FVector scale);
virtual void DrawEditorProperties() { DrawDefaultEditorProperties(); };
};
}
}
+3
View File
@@ -1,5 +1,7 @@
#pragma once
#include "actors/Banana.h"
#include "actors/FallingRock.h"
#include "actors/MarioSign.h"
#include "actors/WarioSign.h"
#include "actors/Cloud.h"
@@ -8,6 +10,7 @@
#include "actors/Starship.h"
#include "actors/Ship.h"
#include "actors/Tree.h"
#include "actors/Text.h"
#include "vehicles/Train.h"
#include "vehicles/Boat.h"
#include "vehicles/Bus.h"
+20 -3
View File
@@ -1,6 +1,10 @@
#ifndef CORE_MATH_H
#define CORE_MATH_H
#ifdef __cplusplus
#include <nlohmann/json.hpp>
#endif
#include <libultraship.h>
/**
@@ -10,6 +14,14 @@
*
*/
struct RGBA8 {
uint8_t r, g, b, a;
#ifdef __cplusplus
NLOHMANN_DEFINE_TYPE_INTRUSIVE(RGBA8, r, g, b, a)
#endif
};
/**
*
* Applies pos, rot, and scale
@@ -63,6 +75,7 @@ struct FVector {
FVector() : x(0), y(0), z(0) {}
FVector(float x, float y, float z) : x(x), y(y), z(z) {}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(FVector, x, y, z)
#endif // __cplusplus
};
@@ -94,6 +107,7 @@ struct FVector2D {
FVector2D() : x(0), z(0) {}
FVector2D(float x, float z) : x(x), z(z) {}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(FVector2D, x, z)
#endif // __cplusplus
};
@@ -118,12 +132,14 @@ typedef struct IVector2D {
/**
* 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
* Set() to update an IRotator using n64 int16_t binary angles 0-0xFFFF (ex. IRotator.Set(0, 0x4000, 0) for Y 90 degrees)
*/
struct IRotator {
uint16_t pitch, yaw, roll;
#ifdef __cplusplus
NLOHMANN_DEFINE_TYPE_INTRUSIVE(IRotator, pitch, yaw, roll)
IRotator& operator=(const IRotator& other) {
pitch = other.pitch;
yaw = other.yaw;
@@ -158,7 +174,7 @@ struct IRotator {
/**
* Use IRotator unless you want to do some math in degrees.
* Always use ToBinary() or Rotator when sending into matrices or apply translation functions
* Always use ToBinary() or IRotator when sending into matrices or apply translation functions
* Convert from IRotator to FRotator float degrees by doing FRotator(myIRotator);
*/
struct FRotator {
@@ -196,9 +212,10 @@ struct FRotator {
* Usage: IPathSpan(point1, point2) --> IPathSpan(40, 65)
*/
struct IPathSpan {
int Start, End;
int32_t Start, End;
#ifdef __cplusplus
NLOHMANN_DEFINE_TYPE_INTRUSIVE(IPathSpan, Start, End)
// Default Constructor
IPathSpan() : Start(0), End(0) {}
+19 -10
View File
@@ -2,21 +2,30 @@
#include "World.h"
void RunGarbageCollector() {
//CleanActors();
CleanActors();
CleanObjects();
CleanStaticMeshActors();
}
void CleanActors() {
// for (auto actor = gWorldInstance.Actors.begin(); actor != gWorldInstance.Actors.end();) {
// OObject* act = *actor; // Get a mutable copy
// if (act->PendingDestroy) {
// delete act;
// actor = gWorldInstance.Objects.erase(actor); // Remove from container
// continue;
// }
// actor++;
// }
for (auto actor = gWorldInstance.Actors.begin(); actor != gWorldInstance.Actors.end();) {
AActor* act = *actor; // Get a mutable copy
if (act->bPendingDestroy) {
if (act->IsMod()) { // C++ actor
delete act;
actor = gWorldInstance.Actors.erase(actor); // Remove from container
} else { // Old C actor
act->Flags = 0;
act->Type = 0;
act->Name = "";
act->ResourceName = "";
actor++; // Manually advance the iterator since no deletion happens here
}
gNumActors -= 1;
continue;
}
actor++;
}
}
void CleanStaticMeshActors() {
-2
View File
@@ -65,8 +65,6 @@ void HarbourMastersIntro::HM_InitIntro() {
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() {
+50 -1
View File
@@ -119,6 +119,56 @@ void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector sca
mtx[3][3] = 1.0f;
}
/*
* Spherical billboarding
* Rotates the object to face the camera
* Rotates on all three axis
*/
void ApplySphericalBillBoard(Mat4 mat, FVector pos, FVector scale, s32 cameraIndex) {
Mtx* lookAt = GetLookAtMatrix(cameraIndex);
Mat4 lookAtF;
guMtxL2F((float(*)[4])&lookAtF, lookAt);
// Camera Right
mat[0][0] = lookAtF[0][0];
mat[1][0] = lookAtF[0][1];
mat[2][0] = lookAtF[0][2];
mat[3][0] = 0;
// Camera Up
mat[0][1] = lookAtF[1][0];
mat[1][1] = lookAtF[1][1];
mat[2][1] = lookAtF[1][2];
mat[3][1] = 0;
// Camera Forward
mat[0][2] = lookAtF[2][0];
mat[1][2] = lookAtF[2][1];
mat[2][2] = lookAtF[2][2];
mat[3][2] = 0;
mat[0][3] = 0;
mat[1][3] = 0;
mat[2][3] = 0;
mat[3][3] = 1;
// Set position
mat[3][0] = pos.x;
mat[3][1] = pos.y;
mat[3][2] = pos.z;
// Apply scaling
mat[0][0] *= scale.x;
mat[1][0] *= scale.x;
mat[2][0] *= scale.x;
mat[0][1] *= scale.y;
mat[1][1] *= scale.y;
mat[2][1] *= scale.y;
mat[0][2] *= scale.z;
mat[1][2] *= scale.z;
mat[2][2] *= scale.z;
}
void AddLocalRotation(Mat4 mat, IRotator rot) {
f32 sin_pitch = sins(rot.pitch);
f32 cos_pitch = coss(rot.pitch);
@@ -141,7 +191,6 @@ void AddLocalRotation(Mat4 mat, IRotator rot) {
mat[2][2] = (cos_pitch * cos_yaw);
}
// API
extern "C" {
+1
View File
@@ -9,6 +9,7 @@
#ifdef __cplusplus
extern "C" {
void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector scale);
void ApplySphericalBillBoard(Mat4 mat, FVector pos, FVector scale, s32 cameraIndex);
void AddLocalRotation(Mat4 mat, IRotator rot);
#endif
void ClearMatrixPools(void);
+372
View File
@@ -0,0 +1,372 @@
#include "SpawnParams.h"
#include "engine/CoreMath.h"
#include "Registry.h"
#include "engine/World.h"
#include "AllActors.h"
extern "C" {
#include "common_structs.h"
#include "actors.h"
#include "actor_types.h"
}
void RegisterGameActors() {
RegisterActor("mk:item_box",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
spawn_item_box(pos);
}
);
RegisterActor("mk:fake_item_box",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
spawn_fake_item_box(pos);
}
);
RegisterActor("mk:thwomp",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OThwomp(params));
}
);
RegisterActor("mk:snowman",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OSnowman(params));
}
);
RegisterActor("mk:hot_air_balloon",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OHotAirBalloon(params));
}
);
RegisterActor("mk:hedgehog",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OHedgehog(params));
}
);
RegisterActor("mk:grand_prix_balloons",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OGrandPrixBalloons(params));
}
);
RegisterActor("mk:flagpole",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OFlagpole(params));
}
);
RegisterActor("mk:crab",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OCrab(params));
}
);
RegisterActor("mk:cheep_cheep",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OCheepCheep(params));
}
);
RegisterActor("mk:bomb_kart",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OBombKart(params));
}
);
RegisterActor("mk:bat",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OBat(params));
}
);
RegisterActor("mk:boos",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OBoos(params));
}
);
RegisterActor("mk:trophy",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OTrophy(params));
}
);
RegisterActor("mk:trash_bin",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OTrashBin(params));
}
);
RegisterActor("mk:seagull",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OSeagull(params));
}
);
RegisterActor("mk:chain_chomp",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OChainChomp());
}
);
RegisterActor("mk:podium",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OPodium(params));
}
);
RegisterActor("mk:penguin",
[](const SpawnParams& params) {
gWorldInstance.AddObject(new OPenguin(params));
}
);
RegisterActor("mk:banana",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ABanana(params));
}
);
RegisterActor("mk:mario_sign",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AMarioSign(params));
}
);
RegisterActor("mk:wario_sign",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AWarioSign(params));
}
);
RegisterActor("mk:falling_rock",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AFallingRock(params));
}
);
RegisterActor("mk:yoshi_egg",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_YOSHI_EGG);
}
);
RegisterActor("mk:piranha_plant",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_PIRANHA_PLANT);
}
);
RegisterActor("mk:tree_mario_raceway",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_MARIO_RACEWAY);
}
);
RegisterActor("mk:tree_yoshi_valley",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_YOSHI_VALLEY);
}
);
RegisterActor("mk:tree_royal_raceway",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_ROYAL_RACEWAY);
}
);
RegisterActor("mk:tree_moo_moo_farm",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_MOO_MOO_FARM);
}
);
RegisterActor("mk:palm_tree",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_PALM_TREE);
}
);
RegisterActor("mk:unknown_0x1a",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_LUIGI_RACEWAY);
}
);
RegisterActor("mk:unknown_0x1b",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_UNKNOWN_0x1B);
}
);
RegisterActor("mk:tree_peach_castle",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_PEACH_CASTLE);
}
);
RegisterActor("mk:tree_frappe_snowland",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_TREE_FRAPPE_SNOWLAND);
}
);
RegisterActor("mk:cactus1_kalamari_desert",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_CACTUS1_KALAMARI_DESERT);
}
);
RegisterActor("mk:cactus2_kalamari_desert",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_CACTUS2_KALAMARI_DESERT);
}
);
RegisterActor("mk:cactus3_kalamari_desert",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_CACTUS3_KALAMARI_DESERT);
}
);
RegisterActor("mk:bush_bowsers_castle",
[](const SpawnParams& params) {
FVector loc = params.Location.value_or(FVector{0, 0, 0});
Vec3f pos = { loc.x, loc.y, loc.z };
Vec3s rot = {0, 0, 0};
Vec3f vel = {0, 0, 0};
add_actor_to_empty_slot(pos, rot, vel, ACTOR_BUSH_BOWSERS_CASTLE);
}
);
RegisterActor("mk:train",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ATrain(params));
}
);
RegisterActor("mk:paddle_boat",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ABoat(params));
}
);
RegisterActor("mk:car",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ACar(params));
}
);
RegisterActor("mk:truck",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ATankerTruck(params));
}
);
RegisterActor("mk:tanker_truck",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ATankerTruck(params));
}
);
RegisterActor("mk:bus",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ATankerTruck(params));
}
);
RegisterActor("hm:spaghetti_ship",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ASpaghettiShip(params));
}
);
RegisterActor("hm:ship",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AShip(params));
}
);
RegisterActor("hm:starship",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AStarship(params));
}
);
RegisterActor("hm:cloud",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new ACloud(params));
}
);
RegisterActor("hm:text",
[](const SpawnParams& params) {
gWorldInstance.AddActor(new AText(params));
}
);
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void RegisterGameActors();
+26 -53
View File
@@ -1,59 +1,32 @@
// #include <vector>
// #include <functional>
// #include <iostream>
// #include <map>
#include <functional>
#include <unordered_map>
#include <string>
// #include "Registry.h"
// #include "Course.h"
// #include "port/Game.h"
#include "Registry.h"
#include "engine/CoreMath.h"
// template <class T> Registry<T>::Registry() {
// }
extern "C" {
#include "actors.h"
#include "actor_types.h"
}
// template <class T> void Registry<T>::Add(std::string id, std::function<T*()> fn) {
// // need to handle duplicate registration
// ContentVault[id] = fn;
// }
std::unordered_map<std::string, ActorRegistryEntry> gActorRegistry;
// template <class T>
// void Registry<T>::AddArgs(std::string id) {
// ArgsVault[id] = [](Args&&... args) -> T* {
// return new T(std::forward<Args>(args)...);
// };
// }
void RegisterActor(const std::string& name,
std::function<void(const SpawnParams&)> spawnFunc)
{
gActorRegistry[name] = { spawnFunc };
}
// template <class T>
// T* Registry<T>::Get(std::string id) {
// auto it = ContentVault.find(id);
// if (it != ContentVault.end()) {
// return it->second();
// }
// return nullptr;
// }
void Registry_SpawnActor(SpawnParams& params) {
auto it = gActorRegistry.find(params.Name);
if (it != gActorRegistry.end() && it->second.spawnFunc) {
printf("[Registry] Spawned %s\n", params.Name.c_str());
it->second.spawnFunc(params);
}
}
// // 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>;
// @arg name Must be a resource name such as mk:car
bool Registry_Find(const std::string& name) {
return gActorRegistry.find(name) != gActorRegistry.end();
}
+10 -29
View File
@@ -1,33 +1,14 @@
// #pragma once
#pragma once
// #include "Course.h"
// #include "Cup.h"
// #include <unordered_map>
// #include "AllActors.h"
// #include "Actor.h"
// #include "objects/Object.h"
#include <libultraship.h>
#include "SpawnParams.h"
// class AActor; // <-- Forward delare
struct ActorRegistryEntry {
std::function<void(const SpawnParams&)> spawnFunc;
};
// 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;
// };
extern std::unordered_map<std::string, ActorRegistryEntry> gActorRegistry;
// 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;
void Registry_SpawnActor(SpawnParams& params);
void RegisterActor(const std::string& name,
std::function<void(const SpawnParams&)> spawnFunc);
+30 -3
View File
@@ -1,6 +1,8 @@
#include "Rulesets.h"
#include "objects/Thwomp.h"
#include "objects/Trophy.h"
#include "objects/BombKart.h"
#include "actors/Text.h"
extern "C" {
#include "code_800029B0.h"
@@ -29,7 +31,7 @@ void Rulesets::PostInit() {
for (auto object : gWorldInstance.Objects) {
if (OThwomp* thwomp = dynamic_cast<OThwomp*>(object)) {
gObjectList[thwomp->_objectIndex].unk_0D5 = OThwomp::States::JAILED; // Sets all the thwomp behaviour flags to marty
thwomp->State = OThwomp::States::JAILED;
thwomp->Behaviour = OThwomp::States::JAILED;
}
}
}
@@ -37,12 +39,37 @@ void Rulesets::PostInit() {
if (CVarGetInteger("gAllBombKartsChase", false) == true) {
for (auto object : gWorldInstance.Objects) {
if (OBombKart* kart = dynamic_cast<OBombKart*>(object)) {
kart->State = OBombKart::States::CHASE;
kart->Behaviour = OBombKart::States::CHASE;
}
}
}
if (CVarGetInteger("gGoFish", false) == true) {
gWorldInstance.AddObject(new OTrophy(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH));
OTrophy::Spawn(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH);
}
if (CVarGetInteger("gPlayerNames", false) == true) {
std::string playerNames[NUM_PLAYERS] = {
"Player 1", "Player 2", "Player 3",
"Player 4", "Player 5", "Player 6",
"Player 7", "Player 8"
};
for (size_t i = 0; i < NUM_PLAYERS; i++) {
// text, pos, scale, mode, playerIndex
AText* text = AText::Spawn(playerNames[i], FVector(0, 0, 0), FVector(0.15f, 0.15f, 0.15f), AText::TextMode::FOLLOW_PLAYER, i);
text->ScaleX = 1.0f;
text->Scale.x = 0.15f;
text->Scale.y = 0.15f;
text->Scale.z = 0.15f;
text->Animate = false; // Cycle between colours similar to grand prix title text
// White
for (size_t j = 0; j < 4; j++) {
text->TextColour[j] = {255, 255, 255, 255};
}
}
}
}
+132
View File
@@ -0,0 +1,132 @@
#pragma once
#include <vector>
#include <optional>
#include <string>
#include <nlohmann/json.hpp>
#include "CoreMath.h"
extern "C" {
#include "common_structs.h"
}
// Helper function to handle std::optional deserialization
template <typename T>
void get_optional_to(const nlohmann::json& j, const char* key, std::optional<T>& opt_val) {
if (j.contains(key) && !j.at(key).is_null()) {
opt_val = j.at(key).get<T>();
}
}
// Helper function to handle std::optional serialization
template <typename T>
void set_optional_from(nlohmann::json& j, const char* key, const std::optional<T>& opt_val) {
if (opt_val.has_value()) {
j[key] = opt_val.value();
}
}
// Used to save and load all game actors to the scene file
struct SpawnParams {
std::string Name; // Must use format mk:actor_name for stock game, mymodname:myactorname for mods
std::optional<int16_t> Type; // OObject type (ex. Emperor penguin, sliding penguin) or literal actor type for AActors
std::optional<int16_t> Behaviour;
std::optional<std::string> Skin;
std::optional<FVector> Location;
std::optional<IRotator> Rotation; // int16_t
std::optional<FVector> Scale;
std::optional<FVector> Velocity; // Used by some AActors
std::optional<FVector2D> PatrolStart; // OCrab
std::optional<FVector2D> PatrolEnd; // OCrab & Hedgehog
std::optional<IPathSpan> PathSpan; // Cheep Cheep
// Thwomps
std::optional<int16_t> PrimAlpha; // Thwomp
std::optional<uint16_t> BoundingBoxSize;
// Boos
std::optional<uint32_t> Count; // vehicles
std::optional<IPathSpan> LeftExitSpan; // Disable boo
std::optional<IPathSpan> TriggerSpan; // Activate boos
std::optional<IPathSpan> RightExitSpan; // Disable boo
// Vehicles
std::optional<uint32_t> PathIndex; // 0-3 Place vehicle this path
std::optional<uint32_t> PathPoint; // Path point index
std::optional<bool> Bool; // train tender
std::optional<bool> Bool2;
std::optional<float> Speed; // Train
std::optional<float> SpeedB; // cars, trucks, buses, etc.
std::optional<FVector> FVec2;
std::optional<RGBA8> Colour;
std::optional<RGBA8> Colour2;
std::optional<RGBA8> Colour3;
std::optional<RGBA8> Colour4;
void from_json(const nlohmann::json& j) {
j.at("Name").get_to(Name);
get_optional_to(j, "Type", Type);
get_optional_to(j, "Behaviour", Behaviour);
get_optional_to(j, "Skin", Skin);
get_optional_to(j, "Location", Location);
get_optional_to(j, "Rotation", Rotation);
get_optional_to(j, "Scale", Scale);
get_optional_to(j, "Velocity", Velocity);
get_optional_to(j, "PatrolStart", PatrolStart);
get_optional_to(j, "PatrolEnd", PatrolEnd);
get_optional_to(j, "PathSpan", PathSpan);
get_optional_to(j, "PrimAlpha", PrimAlpha);
get_optional_to(j, "BoundingBoxSize", BoundingBoxSize);
get_optional_to(j, "Count", Count);
get_optional_to(j, "LeftExitSpan", LeftExitSpan);
get_optional_to(j, "TriggerSpan", TriggerSpan);
get_optional_to(j, "RightExitSpan", RightExitSpan);
get_optional_to(j, "PathIndex", PathIndex);
get_optional_to(j, "PathPoint", PathPoint);
get_optional_to(j, "Bool", Bool);
get_optional_to(j, "Bool2", Bool2);
get_optional_to(j, "Speed", Speed);
get_optional_to(j, "SpeedB", SpeedB);
get_optional_to(j, "FVec2", FVec2);
get_optional_to(j, "Colour", Colour);
get_optional_to(j, "Colour2", Colour2);
get_optional_to(j, "Colour3", Colour3);
get_optional_to(j, "Colour4", Colour4);
}
nlohmann::json to_json() const {
nlohmann::json j;
j["Name"] = Name;
set_optional_from(j, "Type", Type);
set_optional_from(j, "Behaviour", Behaviour);
set_optional_from(j, "Skin", Skin);
set_optional_from(j, "Location", Location);
set_optional_from(j, "Rotation", Rotation);
set_optional_from(j, "Scale", Scale);
set_optional_from(j, "Velocity", Velocity);
set_optional_from(j, "PatrolStart", PatrolStart);
set_optional_from(j, "PatrolEnd", PatrolEnd);
set_optional_from(j, "PathSpan", PathSpan);
set_optional_from(j, "PrimAlpha", PrimAlpha);
set_optional_from(j, "BoundingBoxSize", BoundingBoxSize);
set_optional_from(j, "Count", Count);
set_optional_from(j, "LeftExitSpan", LeftExitSpan);
set_optional_from(j, "TriggerSpan", TriggerSpan);
set_optional_from(j, "RightExitSpan", RightExitSpan);
set_optional_from(j, "PathIndex", PathIndex);
set_optional_from(j, "PathPoint", PathPoint);
set_optional_from(j, "Bool", Bool);
set_optional_from(j, "Bool2", Bool2);
set_optional_from(j, "Speed", Speed);
set_optional_from(j, "SpeedB", SpeedB);
set_optional_from(j, "FVec2", FVec2);
set_optional_from(j, "Colour", Colour);
set_optional_from(j, "Colour2", Colour2);
set_optional_from(j, "Colour3", Colour3);
set_optional_from(j, "Colour4", Colour4);
return j;
}
};
+2
View File
@@ -9,6 +9,8 @@ extern "C" {
}
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) {
Name = "StaticMesh";
ResourceName = "hm:static_mesh";
}
+1
View File
@@ -9,6 +9,7 @@
class StaticMeshActor {
public:
std::string Name;
std::string ResourceName;
FVector Pos;
IRotator Rot;
FVector Scale;
+10 -38
View File
@@ -126,14 +126,7 @@ 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);
}
actor->BeginPlay();
return Actors.back();
}
@@ -146,12 +139,9 @@ struct Actor* World::AddBaseActor() {
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);
}
void World::ActorBeginPlay(Actor* actor) {
AActor* act = ConvertActorToAActor(actor);
act->BeginPlay();
}
/**
@@ -189,8 +179,6 @@ 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;
}
@@ -200,29 +188,14 @@ void World::DrawStaticMeshActors() {
}
}
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);
}
}
// This is an example of how to get the C object.
// However, nothing is being done with it, so it's been commented out.
// if (object->_objectIndex != -1) {
// Object* cObj = &gObjectList[object->_objectIndex];
// }
return Objects.back();
}
@@ -267,7 +240,7 @@ void World::DrawParticles(s32 cameraId) {
// Sets OObjects or AActors static member variables back to default values
void World::Reset() {
for (const auto& object : Objects) {
object->Reset();
object->Reset(); // Used for OPenguin
}
}
@@ -280,7 +253,6 @@ Object* World::GetObjectByIndex(size_t index) {
}
void World::ClearWorld(void) {
World::DeleteStaticMeshActors();
CM_CleanWorld();
// for (size_t i = 0; i < ARRAY_COUNT(gCollisionMesh); i++) {
+3 -13
View File
@@ -5,16 +5,8 @@
#include "engine/courses/Course.h"
#include "objects/Object.h"
#include "Cup.h"
#include "vehicles/Train.h"
#include "vehicles/Car.h"
#include "objects/BombKart.h"
#include "PlayerBombKart.h"
#include "vehicles/Train.h"
#include "TrainCrossing.h"
#include "objects/Thwomp.h"
#include "objects/Penguin.h"
#include "objects/Seagull.h"
#include "objects/Lakitu.h"
#include <memory>
#include <unordered_map>
#include "Actor.h"
@@ -33,7 +25,6 @@ class Cup; // <-- Forward declaration
class OObject;
class Course;
class StaticMeshActor;
class AVehicle;
class OBombKart;
class TrainCrossing;
class OLakitu;
@@ -43,8 +34,8 @@ class World {
typedef struct Matrix {
Mtx Screen2D; // Orthogonal projection for UI, skybox, and such
Mtx Ortho;
std::array<Mtx,4> Persp;
std::array<Mtx,4> LookAt;
std::array<Mtx,5> Persp;
std::array<Mtx,5> LookAt;
std::array<Mtx, 8 * 4> Karts; // Eight players * four screens
std::array<Mtx, 8 * 4> Shadows; // Eight players * four screens
std::deque<Mtx> Hud;
@@ -63,7 +54,7 @@ public:
AActor* AddActor(AActor* actor);
struct Actor* AddBaseActor();
void AddEditorObject(Actor* actor, const char* name);
void ActorBeginPlay(Actor* actor);
AActor* GetActor(size_t index);
void TickActors();
@@ -72,7 +63,6 @@ public:
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);
+9 -6
View File
@@ -10,19 +10,22 @@ void update_actor_banana(struct BananaActor*);
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]) {
ABanana::ABanana(const SpawnParams& params) : AActor(params) {
Name = "Banana";
// Initialize the BananaActor's position, rotation, and velocity
std::copy(pos, pos + 3, Pos);
//std::copy(rot, rot + 3, this->a.rot);
std::copy(velocity, velocity + 3, Velocity);
ResourceName = "mk:banana";
FVector pos = params.Location.value_or(FVector(0, 0, 0));
Pos[0] = pos.x; Pos[1] = pos.y; Pos[2] = pos.z;
FVector vel = params.Velocity.value_or(FVector(0, 0, 0));
Velocity[0] = vel.x; Velocity[1] = vel.y; Velocity[2] = vel.z;
Type = 6; // ACTOR_BANANA
Flags = -0x8000;
Unk_04 = 20;
State = HELD_BANANA;
PlayerId = playerId;
PlayerId = 0; // Don't remember why this is here
//this->a.unk_08 = 0.0f;
Flags |= 0x4000 | 0x1000;
+1 -1
View File
@@ -9,7 +9,7 @@ public:
uint16_t PlayerId;
// Constructor
ABanana(uint16_t playerId, const float pos[3], const s16 rot[3], const float velocity[3]);
ABanana(const SpawnParams& params);
virtual ~ABanana() override = default;
// Virtual functions to be overridden by derived classes
+1
View File
@@ -14,6 +14,7 @@ Gfx gBowserStatueGfx[162];
ABowserStatue::ABowserStatue(FVector pos, ABowserStatue::Behaviour behaviour) {
Name = "Bowser Statue";
ResourceName = "mk:bowser_statue";
Pos = pos;
ABowserStatue::Behaviour _behaviour = behaviour;
}
+2
View File
@@ -13,6 +13,8 @@ extern "C" {
extern Vtx gBowserStatueVtx[717];
extern Gfx gBowserStatueGfx[162];
// The data for this actor is generated and cut out from the actual track geography
// That generator is currently commented out. So this actor is not usable atm.
class ABowserStatue : public AActor {
public:
enum Behaviour {
+82 -13
View File
@@ -2,7 +2,8 @@
#include "Cloud.h"
#include "engine/Actor.h"
#include "World.h"
#include "engine/World.h"
#include "port/Game.h"
extern "C" {
#include "macros.h"
@@ -10,24 +11,48 @@ extern "C" {
#include "math_util.h"
#include "actor_types.h"
#include "actors.h"
#include "other_textures.h"
extern f32 gKartHopInitialVelocityTable[];
extern f32 gKartGravityTable[];
}
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;
ACloud::ACloud(const SpawnParams& params) : AActor(params) {
Name = "Cloud";
ResourceName = "hm:cloud";
FVector pos = params.Location.value_or(FVector(0, 0, 0));
Pos[0] = pos.x;
Pos[1] = pos.y;
Pos[2] = pos.z;
Rot[0] = 0;
Rot[1] = 0;
Rot[2] = 0;
TimerLength = params.Type.value_or(500); // How long the effect lasts
Hop = params.Speed.value_or(3.0f); // How long the effect lasts
Gravity = params.SpeedB.value_or(200.0f); // How long the effect lasts
// Flags = -0x8000 | 0x4000;
BoundingBoxSize = 2.0f;
}
void ACloud::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
params.Name = ResourceName;
params.Type = TimerLength;
params.Speed = Hop;
params.SpeedB = Gravity;
}
extern Gfx cloud_mesh[];
void ACloud::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)cloud_mesh, 1.0f);
}
}
void ACloud::Tick() {
Rot[1] += 0x200;
@@ -35,7 +60,7 @@ void ACloud::Tick() {
Timer++; // Increment timer
}
if (Timer > 500) { // Time has expired, reset the actor and player
if (Timer > TimerLength) { // Time has expired, reset the actor and player
PickedUp = false;
if (_player) {
gKartHopInitialVelocityTable[_player->characterId] = OldHop; // reset back to normal
@@ -46,8 +71,6 @@ void ACloud::Tick() {
}
}
extern Gfx cloud_mesh[];
void ACloud::Draw(Camera* camera) {
Mat4 mtx;
@@ -71,7 +94,9 @@ void ACloud::Collision(Player* player, AActor* actor) {
OldHop = gKartHopInitialVelocityTable[player->characterId];
OldGravity = gKartGravityTable[player->characterId];
// Hop height
gKartHopInitialVelocityTable[player->characterId] = Hop;
// How strong gravity is
gKartGravityTable[player->characterId] = Gravity;
}
}
@@ -133,9 +158,53 @@ Gfx mat_cloud_cutout[] = {
Gfx cloud_mesh[] = {
// gsSPClearGeometryMode(G_LIGHTING),
// gsSPVertex(cloud_mesh_vtx_cull + 0, 8, 0),
gsSPSetGeometryMode(G_LIGHTING),
//gsSPSetGeometryMode(G_LIGHTING),
// gsSPCullDisplayList(0, 7),
gsSPDisplayList(mat_cloud_cutout),
gsSPDisplayList(cloud_mesh_tri_0),
gsSPEndDisplayList(),
};
void ACloud::DrawEditorProperties() {
ImGui::Text("Location");
ImGui::SameLine();
FVector location = FVector(Pos[0], Pos[1], Pos[2]);
if (ImGui::DragFloat3("##Location", (float*)&location)) {
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPos")) {
FVector location = FVector(0, 0, 0);
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::Text("Effect Timer");
ImGui::SameLine();
int32_t type = static_cast<int32_t>(TimerLength);
if (ImGui::InputInt("##Type", &type)) {
TimerLength = static_cast<uint32_t>(type);
}
ImGui::Text("Hop");
ImGui::SameLine();
if (ImGui::DragFloat("##Speed", &Hop, 0.01f)) {
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetSpeed")) {
Hop = 0.0f;
}
ImGui::Text("Gravity");
ImGui::Text("Higher value = stronger gravity");
if (ImGui::DragFloat("##SpeedB", &Gravity, 1.0f)) {
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetSpeedB")) {
Gravity = 0.0f;
}
}
+20 -8
View File
@@ -3,6 +3,7 @@
#include <libultraship.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/World.h"
extern "C" {
#include "macros.h"
@@ -13,27 +14,38 @@ extern "C" {
class ACloud : public AActor {
public:
// Constructor
ACloud(FVector pos);
ACloud(const SpawnParams& params);
virtual ~ACloud() override = default;
// Virtual functions to be overridden by derived classes
// This is simply a helper function to keep Spawning code clean
static inline ACloud* Spawn(FVector pos, uint16_t time, f32 hop, f32 gravity) {
SpawnParams params = {
.Name = "hm:cloud",
.Type = time, // How long the effect is active
.Location = pos,
.Speed = hop, // How high you hop
.SpeedB = gravity, // How much gravity is effected
};
return static_cast<ACloud*>(gWorldInstance.AddActor(new ACloud(params)));
}
virtual void Tick() override;
virtual void Draw(Camera*) override;
virtual void BeginPlay() override;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual void DrawEditorProperties() override;
virtual void Collision(Player* player, AActor* actor) override;
virtual bool IsMod() override;
bool PickedUp = false;
uint32_t TimerLength = 500;
uint32_t Timer = 0;
Player* _player = NULL;
f32 Hop = 3.0f;
f32 Gravity = 200.0f;
f32 OldHop = 0;
f32 OldGravity = 0;
+231
View File
@@ -0,0 +1,231 @@
#include "FallingRock.h"
#include <libultra/gbi.h>
#include "CoreMath.h"
#include <assets/choco_mountain_data.h>
#include "port/interpolation/FrameInterpolation.h"
#include "port/Game.h"
extern "C" {
#include "common_structs.h"
#include "math_util.h"
#include "main.h"
#include "actor_types.h"
#include "code_800029B0.h"
#include "collision.h"
#include "code_800029B0.h"
#include "external.h"
}
size_t AFallingRock::_count = 0;
AFallingRock::AFallingRock(SpawnParams params) : AActor(params) {
Type = ACTOR_FALLING_ROCK;
Name = "Falling Rock";
ResourceName = "mk:falling_rock";
FVector pos = params.Location.value_or(FVector(0, 0, 0));
TimerLength = params.Behaviour.value_or(80);
Pos[0] = pos.x * gCourseDirection;
Pos[1] = pos.y + 10.0f;
Pos[2] = pos.z;
State = _count;
func_802AAAAC(&Unk30);
Flags = -0x8000;
Flags |= 0x4000;
BoundingBoxSize = 10.0f;
Model = d_course_choco_mountain_dl_falling_rock;
_count += 1;
}
void AFallingRock::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
params.Behaviour = TimerLength;
}
void AFallingRock::Reset() {
RespawnTimer = TimerLength;
FVector pos = SpawnPos;
Pos[0] = (f32) pos.x * gCourseDirection;
Pos[1] = (f32) pos.y + 10.0f;
Pos[2] = (f32) pos.z;
vec3f_set(Velocity, 0, 0, 0);
vec3s_set(Rot, 0, 0, 0);
}
bool AFallingRock::IsMod() {
return true;
}
/**
* @brief Updates the falling rock actor.
* Actor used in Choco Mountain.
*
* @param rock
*/
void AFallingRock::Tick() {
Vec3f unkVec;
f32 pad0;
f32 pad1;
if (RespawnTimer != 0) {
RespawnTimer -= 1;
return;
}
if (Pos[1] < CM_GetWaterLevel(Pos, NULL)) {
AFallingRock::Reset();
}
Rot[0] += (s16) ((Velocity[2] * 5461.0f) / 20.0f);
Rot[2] += (s16) ((Velocity[0] * 5461.0f) / 20.0f);
Velocity[1] -= 0.1;
if (Velocity[1] < (-2.0f)) {
Velocity[1] = -2.0f;
}
Pos[0] += Velocity[0];
Pos[1] += Velocity[1];
Pos[2] += Velocity[2];
pad1 = Velocity[1];
check_bounding_collision(&Unk30, 10.0f, Pos[0], Pos[1], Pos[2]);
pad0 = Unk30.surfaceDistance[2];
if (pad0 < 0.0f) {
unkVec[0] = -Unk30.orientationVector[0];
unkVec[1] = -Unk30.orientationVector[1];
unkVec[2] = -Unk30.orientationVector[2];
Pos[0] += unkVec[0] * Unk30.surfaceDistance[2];
Pos[1] += unkVec[1] * Unk30.surfaceDistance[2];
Pos[2] += unkVec[2] * Unk30.surfaceDistance[2];
adjust_pos_orthogonally(unkVec, pad0, Velocity, 2.0f);
Velocity[1] = -1.2f * pad1;
func_800C98B8(Pos, Velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x0F));
}
pad0 = Unk30.surfaceDistance[0];
if (pad0 < 0.0f) {
unkVec[1] = -Unk30.unk48[1];
if (unkVec[1] == 0.0f) {
Velocity[1] *= -1.2f;
return;
} else {
unkVec[0] = -Unk30.unk48[0];
unkVec[2] = -Unk30.unk48[2];
Pos[0] += unkVec[0] * Unk30.surfaceDistance[0];
Pos[1] += unkVec[1] * Unk30.surfaceDistance[0];
Pos[2] += unkVec[2] * Unk30.surfaceDistance[0];
adjust_pos_orthogonally(unkVec, pad0, Velocity, 2.0f);
Velocity[1] = -1.2f * pad1;
func_800C98B8(Pos, Velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x0F));
}
}
pad0 = Unk30.surfaceDistance[1];
if (pad0 < 0.0f) {
unkVec[1] = -Unk30.unk54[1];
if (unkVec[1] == 0.0f) {
Velocity[1] *= -1.2f;
} else {
unkVec[0] = -Unk30.unk54[0];
unkVec[2] = -Unk30.unk54[2];
Pos[0] += unkVec[0] * Unk30.surfaceDistance[1];
Pos[1] += unkVec[1] * Unk30.surfaceDistance[1];
Pos[2] += unkVec[2] * Unk30.surfaceDistance[1];
pad1 = Velocity[1];
adjust_pos_orthogonally(unkVec, pad0, Velocity, 2.0f);
Velocity[1] = -1.2f * pad1;
func_800C98B8(Pos, Velocity, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x0F));
}
}
}
/**
* @brief Renders the falling rock actor.
* Actor used in Choco Mountain.
*
* @param camera
* @param rock
*/
void AFallingRock::Draw(Camera* camera) {
Vec3s sp98;
Vec3f sp8C;
Mat4 mtx;
f32 height;
UNUSED s32 pad[4];
if (RespawnTimer != 0) {
return;
}
height = is_within_render_distance(camera->pos, Pos, camera->rot[1], 400.0f, gCameraZoom[camera - camera1],
4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
height = CLAMP(height, 0.0f, 250000.0f);
}
if (height < 0.0f) {
return;
}
if (height < 250000.0f) {
if (Unk30.unk34 == 1) {
sp8C[0] = Pos[0];
sp8C[2] = Pos[2];
height = calculate_surface_height(sp8C[0], Pos[1], sp8C[2], Unk30.meshIndexZX);
sp98[0] = 0;
sp98[1] = 0;
sp98[2] = 0;
sp8C[1] = height + 2.0f;
FrameInterpolation_RecordOpenChild("rock_shadow", (uintptr_t) this);
mtxf_pos_rotation_xyz(mtx, sp8C, sp98);
if (render_set_position(mtx, 0) == 0) {
FrameInterpolation_RecordCloseChild();
return;
}
gSPDisplayList(gDisplayListHead++, (Gfx*)d_course_choco_mountain_dl_6F88);
FrameInterpolation_RecordCloseChild();
}
}
// @port: Tag the transform.
FrameInterpolation_RecordOpenChild("rock", (uintptr_t) this);
mtxf_pos_rotation_xyz(mtx, Pos, Rot);
if (render_set_position(mtx, 0) == 0) {
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
return;
}
gSPDisplayList(gDisplayListHead++, (Gfx*)d_course_choco_mountain_dl_falling_rock);
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}
void AFallingRock::DrawEditorProperties() {
ImGui::Text("Location");
ImGui::SameLine();
FVector location = SpawnPos;
if (ImGui::DragFloat3("##Location", (float*)&location)) {
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPos")) {
FVector location = FVector(0, 0, 0);
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::Text("Respawn Timer");
ImGui::SameLine();
int32_t behaviour = static_cast<int32_t>(TimerLength);
if (ImGui::InputInt("##Behaviour", &behaviour)) {
TimerLength = static_cast<uint32_t>(behaviour);
}
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include <libultraship.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/SpawnParams.h"
#include "engine/CoreMath.h"
#include "engine/World.h"
class World;
extern World gWorldInstance;
extern "C" {
#include "common_structs.h"
}
// Falls from the sky bouncing off of geography until it goes through water.
// Then after a brief period of time, respawns.
class AFallingRock : public AActor {
public:
explicit AFallingRock(SpawnParams params);
~AFallingRock() {
_count -= 1;
};
// This is simply a helper function to keep Spawning code clean
// @arg respawnTimer default game used 60, 120, 180 as the timer. Time until respawn after reaching the bottom?
static inline AFallingRock* Spawn(FVector pos, int16_t respawnTimer) {
SpawnParams params = {
.Name = "mk:falling_rock",
.Behaviour = respawnTimer,
.Location = pos,
};
return static_cast<AFallingRock*>(gWorldInstance.AddActor(new AFallingRock(params)));
}
int16_t TimerLength = 80;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual bool IsMod() override;
virtual void Tick() override;
virtual void Draw(Camera*) override;
virtual void DrawEditorProperties() override;
void Reset();
private:
uint32_t RespawnTimer = 0;
static size_t _count;
};
+22 -11
View File
@@ -21,30 +21,41 @@ extern f32 gKartGravityTable[];
size_t AFinishline::_count = 0;
AFinishline::AFinishline(std::optional<FVector> pos) {
AFinishline::AFinishline(const SpawnParams& params) : AActor(params) {
Name = "Finishline";
ResourceName = "mk:finishline";
if (pos.has_value()) {
if (params.Location.has_value()) {
FVector pos = params.Location.value_or(FVector(0, 0, 0));
// Set spawn point to the provided position
Pos[0] = D_8015F8D0[0] = pos.value().x;
Pos[1] = D_8015F8D0[1] = pos.value().y - 15;
Pos[2] = D_8015F8D0[2] = pos.value().z;
Pos[0] = D_8015F8D0[0] = pos.x;
Pos[1] = D_8015F8D0[1] = pos.y - 15;
Pos[2] = D_8015F8D0[2] = pos.z;
} else {
// Set spawn point to the tracks first path point.
Pos[0] = D_8015F8D0[0] = gCurrentTrackPath->posX;
Pos[1] = D_8015F8D0[1] = (f32) (gCurrentTrackPath->posY - 15);
Pos[2] = D_8015F8D0[2] = gCurrentTrackPath->posZ;
Pos[0] = D_8015F8D0[0] = gCurrentTrackPath->x;
Pos[1] = D_8015F8D0[1] = (f32) (gCurrentTrackPath->y - 15);
Pos[2] = D_8015F8D0[2] = gCurrentTrackPath->z;
}
Rot[0] = 0;
Rot[1] = 0;
Rot[2] = 0;
IRotator rot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
Flags = -0x8000 | 0x4000;
BoundingBoxSize = 0.0f;
}
void AFinishline::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(D_0D001B90), 1.0f);
}
}
void AFinishline::Tick() {
}
+20 -1
View File
@@ -3,6 +3,7 @@
#include <libultraship.h>
#include "CoreMath.h"
#include "engine/Actor.h"
#include "engine/World.h"
extern "C" {
#include "macros.h"
@@ -17,13 +18,31 @@ public:
* Default behaviour places the finishline at the first waypoint.
* @arg pos, optional. Sets a custom position
*/
AFinishline(std::optional<FVector> pos);
AFinishline(const SpawnParams& params);
virtual ~AFinishline() override = default;
// This is simply a helper function to keep Spawning code clean
static inline AFinishline* Spawn(FVector pos, IRotator rot) {
SpawnParams params = {
.Name = "mk:finishline",
.Location = pos,
.Rotation = rot,
};
return static_cast<AFinishline*>(gWorldInstance.AddActor(new AFinishline(params)));
}
static inline AFinishline* Spawn() {
SpawnParams params = {
.Name = "mk:finishline",
};
return static_cast<AFinishline*>(gWorldInstance.AddActor(new AFinishline(params)));
}
// Virtual functions to be overridden by derived classes
virtual void Tick() override;
virtual void Draw(Camera*) override;
virtual void BeginPlay() override;
virtual void Collision(Player* player, AActor* actor) override;
virtual bool IsMod() override;
+32 -4
View File
@@ -2,33 +2,60 @@
#include <libultra/gbi.h>
#include <assets/mario_raceway_data.h>
#include "CoreMath.h"
extern "C" {
#include "common_structs.h"
#include "math_util.h"
#include "main.h"
#include "actor_types.h"
#include "code_800029B0.h"
#include "collision.h"
}
AMarioSign::AMarioSign(FVector pos) {
AMarioSign::AMarioSign(const SpawnParams& params) : AActor(params) {
Type = ACTOR_MARIO_SIGN;
Name = "Mario Sign";
Pos[0] = pos.x;
ResourceName = "mk:mario_sign";
Model = d_course_mario_raceway_dl_sign;
Speed = params.Speed.value_or(182);
FVector pos = params.Location.value_or(FVector(0, 0, 0));
Pos[0] = pos.x * gCourseDirection;
Pos[1] = pos.y;
Pos[2] = pos.z;
IRotator rot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
Scale = params.Scale.value_or(FVector(1.0f, 1.0f, 1.0f));
func_802AAAAC(&Unk30);
Flags = -0x8000;
Flags |= 0x4000;
}
bool AMarioSign::IsMod() {
return true;
}
void AMarioSign::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
}
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;
Rot[1] += Speed * 10; // Originally 1820
}
} else {
Rot[1] += 182;
Rot[1] += Speed; // Originally 182
}
}
}
@@ -49,6 +76,7 @@ void AMarioSign::Draw(Camera *camera) {
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);
}
+20 -1
View File
@@ -3,6 +3,10 @@
#include <libultraship.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/World.h"
class World;
extern World gWorldInstance;
extern "C" {
#include "common_structs.h"
@@ -12,8 +16,23 @@ class AMarioSign : public AActor {
public:
virtual ~AMarioSign() = default;
explicit AMarioSign(FVector pos);
explicit AMarioSign(const SpawnParams& params);
// This is simply a helper function to keep Spawning code clean
static inline AMarioSign* Spawn(FVector pos, IRotator rot, FVector velocity, FVector scale) {
SpawnParams params = {
.Name = "mk:mario_sign",
.Location = pos,
.Rotation = rot,
.Scale = scale,
.Velocity = velocity,
.Speed = 182,
};
return static_cast<AMarioSign*>(gWorldInstance.AddActor(new AMarioSign(params)));
}
virtual bool IsMod() override;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual void Tick() override;
virtual void Draw(Camera*) override;
};
+116 -9
View File
@@ -2,6 +2,7 @@
#include <libultra/gbi.h>
#include "CoreMath.h"
#include "port/Game.h"
#include "Matrix.h"
extern "C" {
@@ -13,29 +14,48 @@ extern "C" {
#include "courses/harbour/ship3_model.h"
}
AShip::AShip(FVector pos, AShip::Skin skin) {
Spawn = pos;
Spawn.y += 10;
AShip::AShip(const SpawnParams& params) : AActor(params) {
ResourceName = "hm:ship";
FVector pos = params.Location.value_or(FVector(0, 0, 0));
//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:
SpawnSkin = static_cast<AShip::Skin>(params.Type.value_or(0));
switch(SpawnSkin) {
case Skin::GHOSTSHIP:
Name = "Ghostship";
_skin = ghostship_Plane_mesh;
break;
case SHIP2:
case Skin::SHIP2:
Name = "Ship_1";
_skin = ship2_SoH_mesh;
break;
case SHIP3:
case Skin::SHIP3:
Name = "Ship_2";
_skin = ship3_2Ship_mesh;
break;
}
Model = _skin;
Model = (const char*)_skin;
}
void AShip::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
params.Name = ResourceName;
params.Type = static_cast<int16_t>(SpawnSkin);
params.Location = SpawnPos;
params.Rotation = SpawnRot;
params.Scale = SpawnScale;
params.Speed = Speed;
}
void AShip::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)_skin, Scale.y);
}
}
void AShip::Tick() {
@@ -54,3 +74,90 @@ void AShip::Tick() {
}
bool AShip::IsMod() { return true; }
void AShip::DrawEditorProperties() {
ImGui::Text("Ship Type");
ImGui::SameLine();
int32_t type = static_cast<int32_t>(SpawnSkin);
const char* items[] = { "Ghostship", "Ship 2", "Ship 3" };
if (ImGui::Combo("##Type", &type, items, IM_ARRAYSIZE(items))) {
SpawnSkin = static_cast<AShip::Skin>(type);
switch(SpawnSkin) {
case Skin::GHOSTSHIP:
Name = "Ghostship";
_skin = ghostship_Plane_mesh;
break;
case Skin::SHIP2:
Name = "Ship_1";
_skin = ship2_SoH_mesh;
break;
case Skin::SHIP3:
Name = "Ship_2";
_skin = ship3_2Ship_mesh;
break;
}
Model = (const char*)_skin;
}
ImGui::Text("Location");
ImGui::SameLine();
FVector location = FVector(Pos[0], Pos[1], Pos[2]);
if (ImGui::DragFloat3("##Location", (float*)&location)) {
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPos")) {
FVector location = FVector(0, 0, 0);
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::Text("Rotation");
ImGui::SameLine();
IRotator objRot = GetRotation();
// Convert to temporary int values (to prevent writing 32bit values to 16bit variables)
int rot[3] = {
objRot.pitch,
objRot.yaw,
objRot.roll
};
if (ImGui::DragInt3("##Rotation", rot, 5.0f)) {
for (size_t i = 0; i < 3; i++) {
// Wrap around 065535
rot[i] = (rot[i] % 65536 + 65536) % 65536;
}
IRotator newRot;
newRot.Set(
static_cast<uint16_t>(rot[0]),
static_cast<uint16_t>(rot[1]),
static_cast<uint16_t>(rot[2])
);
Rotate(newRot);
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetRot")) {
IRotator rot = IRotator(0, 0, 0);
Rotate(rot);
}
FVector scale = GetScale();
ImGui::Text("Scale ");
ImGui::SameLine();
ImGui::DragFloat3("##Scale", (float*)&scale, 0.1f);
SetScale(scale);
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetScale")) {
FVector scale = FVector(0.4f, 0.4f, 0.4f);
SetScale(scale);
}
}
+21 -8
View File
@@ -2,8 +2,9 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/Actor.h"
#include "engine/World.h"
extern "C" {
#include "common_structs.h"
@@ -19,16 +20,28 @@ public:
SHIP3,
};
explicit AShip(FVector pos, AShip::Skin);
explicit AShip(const SpawnParams& params);
virtual ~AShip() = default;
virtual void Tick() override;
virtual bool IsMod() override;
// This is simply a helper function to keep Spawning code clean
static inline AShip* Spawn(FVector pos, IRotator rot, FVector scale, int16_t skin) {
SpawnParams params = {
.Name = "hm:ship",
.Type = skin, // which ship model to use
.Location = pos,
.Rotation = rot,
.Scale = scale,
};
return static_cast<AShip*>(gWorldInstance.AddActor(new AShip(params)));
}
FVector Spawn;
//FVector Pos;
///IRotator Rot = {0, 0, 0};
//FVector Scale = {0.4, 0.4, 0.4};
AShip::Skin SpawnSkin = Skin::GHOSTSHIP;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual void Tick() override;
virtual void BeginPlay() override;
virtual bool IsMod() override;
virtual void DrawEditorProperties() override;
private:
Gfx* _skin;
};
+15 -6
View File
@@ -10,14 +10,22 @@ extern "C" {
#include "courses/harbour/ship_model.h"
}
ASpaghettiShip::ASpaghettiShip(FVector pos) {
ASpaghettiShip::ASpaghettiShip(const SpawnParams& params) : AActor(params) {
Name = "Spaghetti Ship";
ResourceName = "hm:spaghetti_ship";
BoundingBoxSize = 3.0f;
FVector pos = params.Location.value_or(FVector(0, 0, 0));
Pos[0] = pos.x;
Pos[1] = pos.y;
Pos[2] = pos.z;
Spawn = pos;
Spawn.y += 10;
Scale = {0.4, 0.4, 0.4};
Scale = params.Scale.value_or(FVector(0.4f, 0.4f, 0.4f));
IRotator rot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
}
void ASpaghettiShip::Tick() {
@@ -28,8 +36,9 @@ void ASpaghettiShip::Tick() {
angle += speed; // Increment the angle to move in a circle
// Update the position based on a circular path
Pos[0] = Spawn.x + radius * cosf(angle);
Pos[2] = Spawn.z + radius * sinf(angle);
FVector spawn = SpawnPos;
Pos[0] = spawn.x + radius * cosf(angle);
Pos[2] = spawn.z + radius * sinf(angle);
// Rotate to face forward along the circle
Rot[1] = -static_cast<int16_t>(angle * (32768.0f / M_PI / 2.0f));
+14 -3
View File
@@ -2,8 +2,9 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/Actor.h"
#include "engine/World.h"
extern "C" {
#include "common_structs.h"
@@ -12,13 +13,23 @@ extern "C" {
class ASpaghettiShip : public AActor {
public:
explicit ASpaghettiShip(FVector pos);
explicit ASpaghettiShip(const SpawnParams& params);
virtual ~ASpaghettiShip() = default;
// This is simply a helper function to keep Spawning code clean
static inline ASpaghettiShip* Spawn(FVector pos, IRotator rot, FVector scale) {
SpawnParams params = {
.Name = "hm:spaghetti_ship",
.Location = pos,
.Rotation = rot,
.Scale = scale,
};
return static_cast<ASpaghettiShip*>(gWorldInstance.AddActor(new ASpaghettiShip(params)));
}
virtual void Tick() override;
virtual void Draw(Camera*) override;
virtual bool IsMod() override;
FVector Spawn;
IRotator WheelRot = {0, 0, 0};
};
+113 -9
View File
@@ -2,6 +2,7 @@
#include <libultra/gbi.h>
#include "Matrix.h"
#include "port/Game.h"
extern "C" {
#include "common_structs.h"
@@ -10,26 +11,44 @@ extern "C" {
#include "courses/harbour/starship_model.h"
}
AStarship::AStarship(FVector pos) {
AStarship::AStarship(const SpawnParams& params) : AActor(params) {
Name = "Starship";
Spawn = pos;
ResourceName = "hm:starship";
FVector pos = params.Location.value_or(FVector(0, 0, 0));
SetLocation(pos);
Scale = FVector(1.5, 1.5, 1.5);
Model = starship_Cube_mesh;
IRotator rot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
Scale = params.Scale.value_or(FVector(0, 0, 0));
Speed = params.Speed.value_or(0.01f);
SpeedB = params.SpeedB.value_or(150.0f);
Model = (const char*)starship_Cube_mesh;
}
void AStarship::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
params.SpeedB = SpeedB;
}
void AStarship::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)Model, 1.0f);
}
}
void AStarship::Tick() {
static float angle = 0.0f;
float radius = 150.0f;
float speed = 0.01f;
angle += speed;
angle += Speed;
// Move relative to the initial position
FVector pos = GetLocation();
pos.x = Spawn.x + radius * cosf(angle);
pos.z = Spawn.z + radius * sinf(angle);
FVector spawn = SpawnPos;
pos.x = spawn.x + SpeedB * cosf(angle);
pos.z = spawn.z + SpeedB * sinf(angle);
SetLocation(pos);
// Keep y from changing (or adjust it if necessary)
@@ -40,3 +59,88 @@ void AStarship::Tick() {
}
bool AStarship::IsMod() { return true; }
void AStarship::DrawEditorProperties() {
ImGui::Text("Location");
ImGui::SameLine();
FVector location = FVector(Pos[0], Pos[1], Pos[2]);
if (ImGui::DragFloat3("##Location", (float*)&location)) {
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetPos")) {
FVector location = FVector(0, 0, 0);
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
ImGui::Text("Rotation");
ImGui::SameLine();
IRotator objRot = GetRotation();
// Convert to temporary int values (to prevent writing 32bit values to 16bit variables)
int rot[3] = {
objRot.pitch,
objRot.yaw,
objRot.roll
};
if (ImGui::DragInt3("##Rotation", rot, 5.0f)) {
for (size_t i = 0; i < 3; i++) {
// Wrap around 065535
rot[i] = (rot[i] % 65536 + 65536) % 65536;
}
IRotator newRot;
newRot.Set(
static_cast<uint16_t>(rot[0]),
static_cast<uint16_t>(rot[1]),
static_cast<uint16_t>(rot[2])
);
Rotate(newRot);
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetRot")) {
IRotator rot = IRotator(0, 0, 0);
Rotate(rot);
}
FVector scale = GetScale();
ImGui::Text("Scale ");
ImGui::SameLine();
ImGui::DragFloat3("##Scale", (float*)&scale, 0.1f);
SetScale(scale);
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetScale")) {
FVector scale = FVector(0.4f, 0.4f, 0.4f);
SetScale(scale);
}
ImGui::Text("Speed");
ImGui::SameLine();
float speed = Speed;
if (ImGui::DragFloat("##Speed", &speed, 0.01f)) {
Speed = speed;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetSpeed")) {
Speed = 0.0f;
}
ImGui::Text("Radius");
ImGui::SameLine();
float speed2 = SpeedB;
if (ImGui::DragFloat("##SpeedB", &speed2, 5.0f)) {
SpeedB = speed2;
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UNDO "##ResetSpeedB")) {
SpeedB = 0.0f;
}
}
+21 -4
View File
@@ -2,8 +2,9 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/Actor.h"
#include "engine/World.h"
extern "C" {
#include "common_structs.h"
@@ -12,11 +13,27 @@ extern "C" {
class AStarship : public AActor {
public:
explicit AStarship(FVector pos);
explicit AStarship(const SpawnParams& params);
virtual ~AStarship() = default;
// This is simply a helper function to keep Spawning code clean
static inline AStarship* Spawn(FVector pos, IRotator rot, FVector scale, f32 speed, f32 radius) {
SpawnParams params = {
.Name = "hm:starship",
.Location = pos,
.Rotation = rot,
.Scale = scale,
.Speed = speed,
.SpeedB = radius,
};
return static_cast<AStarship*>(gWorldInstance.AddActor(new AStarship(params)));
}
float SpeedB;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual void Tick() override;
virtual bool IsMod() override;
FVector Spawn;
virtual void BeginPlay() override;
virtual void DrawEditorProperties() override;
};
+588
View File
@@ -0,0 +1,588 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include <vector>
#include "Text.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/Matrix.h"
#include "engine/editor/EditorMath.h"
extern "C" {
#include "defines.h"
#include "main.h"
#include "menu_items.h"
#include "assets/data_segment2.h"
#include "render_player.h"
#include "math_util.h"
#include "assets/texture_data_2.h"
#include "render_objects.h"
#include "common_structs.h"
#include "code_80005FD0.h"
}
AText::AText(const SpawnParams& params) : AActor(params) {
Name = "Text";
ResourceName = "hm:text";
SpawnPos = params.Location.value_or(FVector(0.0f, 100.0f, 0.0f));
Pos[0] = SpawnPos.x;
Pos[1] = SpawnPos.y;
Pos[2] = SpawnPos.z;
SpawnRot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = SpawnRot.pitch;
Rot[1] = SpawnRot.yaw;
Rot[2] = SpawnRot.roll;
SpawnScale = params.Scale.value_or(FVector(1.0f, 1.0f, 1.0f));
Scale = SpawnScale;
ScaleX = params.FVec2.value_or(FVector{1.0f, 0.0f, 0.0f}).x;
Mode = static_cast<TextMode>(params.Type.value_or(0)); // STATIONARY
Animate = params.Bool.value_or(false);
FaceCamera = params.Bool2.value_or(true);
WidthOffset = params.Speed.value_or(0.0f);
HeightOffset = params.SpeedB.value_or(8.0f);
FVector options = params.Velocity.value_or(FVector{1.0f, 14000.0f, 0.0f});
LetterSpacing = options.x;
Far = options.y;
Close = options.z;
TextColour[0] = params.Colour.value_or(RGBA8{255, 255, 255, 255});
TextColour[1] = params.Colour2.value_or(RGBA8{255, 255, 255, 255});
TextColour[2] = params.Colour3.value_or(RGBA8{255, 255, 255, 255});
TextColour[3] = params.Colour4.value_or(RGBA8{255, 255, 255, 255});
PlayerIndex = static_cast<uint32_t>(params.Behaviour.value_or(0));
if (PlayerIndex < 0 || PlayerIndex >= NUM_PLAYERS) {
PlayerIndex = 0;
}
Text = ValidateString(params.Skin.value_or("Harbour Masters"));
AText::Print3D((char*)Text.c_str(), 0, CENTER_TEXT_MODE_2);
}
/**
* Filters out bad characters (allows a-z, A-Z, 0-9, space)
* Returns "Blank Text" for blank input
* Returns "Invalid" if no valid input found
* Limits str to 20 characters
*
* The font does support some symbols and other language characters
* But these need to be checked thoroughly before white-listing.
*/
std::string AText::ValidateString(const std::string_view& s) {
if (s.empty()) { return "Blank Text"; }
Text.clear();
for (char c : s) {
if (std::isalpha(static_cast<unsigned char>(c)) ||
std::isdigit(static_cast<unsigned char>(c)) ||
c == ' ')
{
Text += c;
if (Text.size() >= 20) {
break;
};
}
}
// No valid characters found
if (Text.empty()) {
return "Invalid";
}
return Text;
}
/*
* Most changes during runtime require a refresh because the text is generated statically
* with the intention of this code being somewhat performant
*/
void AText::Refresh() {
AText::TextureList.clear();
AText::Print3D((char*)Text.c_str(), 0, CENTER_TEXT_MODE_2);
}
bool AText::IsMod() { return true; }
void AText::SetSpawnParams(SpawnParams& params) {
AActor::SetSpawnParams(params);
params.Name = ResourceName;
params.Type = static_cast<int16_t>(Mode);
params.Behaviour = PlayerIndex;
params.Skin = Text;
params.Colour = TextColour[0];
params.Colour2 = TextColour[1];
params.Colour3 = TextColour[2];
params.Colour4 = TextColour[3];
params.Speed = WidthOffset;
params.SpeedB = HeightOffset;
params.Velocity = {LetterSpacing, Far, Close};
params.FVec2 = {ScaleX, 0.0f, 0.0f};
params.Bool = Animate;
params.Bool2 = FaceCamera;
}
void AText::Tick() {
switch(Mode) {
case STATIONARY:
break; // Do nothing
case FOLLOW_PLAYER:
AText::FollowPlayer();
break;
}
}
void AText::FollowPlayer() {
Pos[0] = gPlayers[PlayerIndex].pos[0] + WidthOffset;
Pos[1] = gPlayers[PlayerIndex].pos[1] + HeightOffset;
Pos[2] = gPlayers[PlayerIndex].pos[2];
// Animate text if player is in first place
// if (gGPCurrentRaceRankByPlayerId[PlayerIndex] == 0) {
// Animate = true;
// } else {
// Animate = false;
// }
}
void AText::Draw(Camera* camera) {
switch(Mode) {
case STATIONARY:
break; // Do nothing
case FOLLOW_PLAYER:
if (PlayerIndex == camera->playerId) {
return; // Do not draw the local players own name
}
if ((gPlayers[PlayerIndex].effects & BOO_EFFECT) == BOO_EFFECT) {
FadeState = FADE_OUT;
AText::DrawText3D(camera);
return; // Skip expensive calculations below
}
break;
}
f32 distance = is_within_render_distance(camera->pos, (float*)&Pos[0], camera->rot[1], Close,
gCameraZoom[camera - camera1], Far);
if (distance == -1.0f) {
Dist = DistanceProps::TOO_FAR;
} else if (distance < Close) {
Dist = DistanceProps::TOO_CLOSE;
} else {
Dist = DistanceProps::ACTIVE;
}
if (Dist != PrevState) {
PrevState = Dist;
if ((distance == -1.0f) || (distance < Close)) {
FadeState = FADE_OUT;
} else {
FadeState = FADE_IN;
}
}
AText::DrawText3D(camera);
}
/**
* These have been refactored for efficiency purposes.
* The new method uses 1 matrix to display the whole string
* And then setting vertex data is done during the setup/constructor phase,
* instead of during rendering
* This requires a refresh if the data ever changes
*
* This method is more efficient because the original version does all this work
* during the render phase. Now it's done during the actor spawn phase with the exception
* if any changes are made at runtime.
*/
void AText::Print3D(char* text, s32 tracking, s32 mode) {
char* temp_string = text;
s32 stringWidth = 0;
s32 glyphIndex;
s32 sp60;
s32 column = 0;
s32 row = 0;
if (text == NULL) {
// @port if invalid text is loaded it will skip rendering it.
return;
}
while (*temp_string != '\0') {
glyphIndex = char_to_glyph_index(temp_string);
if (glyphIndex >= 0) {
stringWidth += ((gGlyphDisplayWidth[glyphIndex] + tracking) * ScaleX);
} else if ((glyphIndex != -2) && (glyphIndex == -1)) {
stringWidth += ((tracking + 7) * ScaleX);
} else {
return;
}
if (glyphIndex >= 0x30) {
temp_string += 2;
} else {
temp_string += 1;
}
}
switch (mode) {
case LEFT_TEXT:
//! FAKE:
do {
} while (0);
case RIGHT_TEXT:
column -= stringWidth;
break;
case CENTER_TEXT_MODE_1:
case CENTER_TEXT_MODE_2:
column -= stringWidth / 2;
break;
default:
break;
}
if (mode < 3) {
sp60 = 1;
} else {
sp60 = 2;
}
while (*text != '\0') {
glyphIndex = char_to_glyph_index(text);
if (glyphIndex >= 0) {
AText::PrintLetter3D(gGlyphTextureLUT[glyphIndex],
column, row, sp60);
column = column + (s32) ((gGlyphDisplayWidth[glyphIndex] + tracking) * ScaleX);
} else if ((glyphIndex != -2) && (glyphIndex == -1)) {
column = column + (s32) ((tracking + 7) * ScaleX);
} else {
return;
}
if (glyphIndex >= 0x30) {
text += 2;
} else {
text += 1;
}
}
SetupVtx(); // position each letter
}
void AText::PrintLetter3D(MenuTexture* glyphTexture, f32 column, f32 row, s32 mode) {
s32 var_v0;
u8* temp_v0_2;
f32 thing0;
f32 thing1;
MenuTexture* texture;
texture = glyphTexture;
while (texture->textureData != NULL) {
if (texture->textureData != 0) {
f32 col = texture->dX + column;
TextureList.emplace_back(CharacterList{
(const char*) texture->textureData,
col,
texture->dY + row,
texture->width,
texture->height,
mode,
});
}
texture++;
}
}
void AText::SetupVtx() {
for (CharacterList& character : TextureList) {
Vtx* vtxPtr;
switch (character.width) {
default:
vtxPtr = (Vtx*)&AText::myVtx[4];
break;
case 16:
vtxPtr = (Vtx*)&AText::myVtx[4];
break;
case 26:
vtxPtr = (Vtx*)&AText::myVtx[0];
break;
case 30:
vtxPtr = (Vtx*)&AText::myVtx[8];
break;
}
// printf("col %f width %d span %d\n", character.column, character.width, character.span);
// memcpy the vtx data into the unique vtx data for this letter
Vtx* vtxSrc = (Vtx*)vtxPtr;
memcpy(&character.vtx, vtxSrc, sizeof(Vtx) * 4);
for (size_t i = 0; i < 4; i++) {
// Set the location for this letter (beside the previous letter) center the text over the anchor point
float span = (character.column * LetterSpacing);
character.vtx[i].v.ob[0] += (s16)span;
// Set the colour for this letter
character.vtx[i].v.cn[0] = TextColour[i].r;
character.vtx[i].v.cn[1] = TextColour[i].g;
character.vtx[i].v.cn[2] = TextColour[i].b;
character.vtx[i].v.cn[3] = TextColour[i].a;
}
}
}
void AText::DrawText3D(Camera* camera) { // Based on func_80095BD0
Mat4 mtx;
if (FaceCamera) {
ApplySphericalBillBoard(mtx, *(FVector*)Pos, Scale, camera->cameraId);
} else {
ApplyMatrixTransformations(mtx, *(FVector*)Pos, *(IRotator*)Rot, Scale);
}
AddObjectMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
FrameInterpolation_RecordOpenChild("actor_text", TAG_LETTER(this));
gSPDisplayList(gDisplayListHead++, (Gfx*)D_020077A8);
switch (1) {
case 1:
gSPDisplayList(gDisplayListHead++, (Gfx*)D_020077F8);
break;
case 2:
gSPDisplayList(gDisplayListHead++, (Gfx*)D_02007818);
break;
}
for (CharacterList& tex : TextureList) {
//printf("tex texture %p width %d height %d mode %d col %f\n", tex.Texture, tex.width, tex.height, tex.mode, tex.column);
gDPLoadTextureTile_4b(gDisplayListHead++, (Gfx*)tex.Texture, G_IM_FMT_I, tex.width, 0, 0, 0, tex.width, tex.height + 2, 0,
G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
// gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER);
if (Animate) {
AnimateColour(tex.vtx);
}
switch(FadeState) {
case FADE_IN:
AText::FadeIn(tex.vtx);
break;
case FADE_OUT:
AText::FadeOut(tex.vtx);
break;
}
gSPVertex(gDisplayListHead++, (uintptr_t)tex.vtx, 4, 0);
gSP2Triangles(gDisplayListHead++, 0, 2, 1, 0, 0, 3, 2, 0);
// gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER);
}
gSPDisplayList(gDisplayListHead++, (Gfx*)D_020077D8);
FrameInterpolation_RecordCloseChild();
}
void AText::AnimateColour(Vtx* vtx) {
u8 r = (sin(gGlobalTimer * 0.1f) * 0.5f + 0.5f) * 200;
u8 g = (sin(gGlobalTimer * 0.1f + 2.0f) * 0.5f + 0.5f) * 200;
u8 b = (sin(gGlobalTimer * 0.1f + 4.0f) * 0.5f + 0.5f) * 200;
for (size_t i = 0; i < 4; i++) {
vtx[i].v.cn[0] = r;
vtx[i].v.cn[1] = g;
vtx[i].v.cn[2] = b;
}
}
#define fadeSpeed 16
void AText::FadeIn(Vtx* vtx) {
uint8_t alpha = vtx[0].v.cn[3];
if (alpha + fadeSpeed > 255) {
alpha = 255;
FadeState = NO_FADE;
} else {
alpha += fadeSpeed;
}
// Apply alpha to all 4 vertices
for (size_t i = 0; i < 4; i++) {
vtx[i].v.cn[3] = alpha;
}
}
void AText::FadeOut(Vtx* vtx) {
uint8_t alpha = vtx[0].v.cn[3];
if (alpha < fadeSpeed) {
alpha = 0;
FadeState = NO_FADE;
} else {
alpha -= fadeSpeed;
}
// Apply alpha to all 4 vertices
for (size_t i = 0; i < 4; i++) {
vtx[i].v.cn[3] = alpha;
}
}
#undef fadeSpeed
void AText::DrawEditorProperties() {
bool updated = false;
ImGui::Text("Text");
ImGui::SameLine();
char text[21] = "";
strncpy(text, Text.c_str(), sizeof(text));
ImGui::InputText("Enter text", text, IM_ARRAYSIZE(text));
Text = std::string(text);
ImGui::Text("Mode");
ImGui::SameLine();
int32_t mode = static_cast<int32_t>(Mode);
const char* items[] = { "STATIONARY", "FOLLOW PLAYER" };
if (ImGui::Combo("##Type", &mode, items, IM_ARRAYSIZE(items))) {
Mode = static_cast<TextMode>(mode);
updated = true;
}
ImGui::DragFloat("Far Render Dist", &Far);
ImGui::DragFloat("Close Render Dist", &Close);
ImGui::Checkbox("Face Camera", &FaceCamera);
if (!FaceCamera) {
ImGui::Text("Rotation");
ImGui::SameLine();
IRotator objRot = GetRotation();
// Convert to temporary int values (to prevent writing 32bit values to 16bit variables)
int rot[3] = {
objRot.pitch,
objRot.yaw,
objRot.roll
};
if (ImGui::DragInt3("##Rotation", rot, 5.0f)) {
for (size_t i = 0; i < 3; i++) {
// Wrap around 065535
rot[i] = (rot[i] % 65536 + 65536) % 65536;
}
IRotator newRot;
newRot.Set(
static_cast<uint16_t>(rot[0]),
static_cast<uint16_t>(rot[1]),
static_cast<uint16_t>(rot[2])
);
Rotate(newRot);
}
}
switch(mode) {
case STATIONARY: {
ImGui::Text("Location");
ImGui::SameLine();
FVector location = GetLocation();
if (ImGui::DragFloat3("##Location", (float*)&location)) {
Translate(location);
gEditor.eObjectPicker.eGizmo.Pos = location;
}
break;
}
case FOLLOW_PLAYER:
// Allow setting PlayerIndex
int32_t playerIdx = PlayerIndex + 1;
// Draw the input box (ImGui input limited between 1 and 8)
ImGui::SetNextItemWidth(100);
if (ImGui::InputInt("Follow Player", &playerIdx)) {
// Clamp display value to [1, 8]
if (playerIdx < 1) playerIdx = 1;
if (playerIdx > 8) playerIdx = 8;
// Update the internal value (07)
PlayerIndex = playerIdx - 1;
}
ImGui::DragFloat("Width Offset", &WidthOffset);
ImGui::DragFloat("Height Offset", &HeightOffset);
break;
}
DrawColourEditor(&updated);
ImGui::Text("Transform Settings");
ImGui::Separator();
ImGui::SetNextItemWidth(100);
ImGui::DragFloat("Scale X", &ScaleX, 0.1f, -5.0f, 5.0f, "%.2f");
ImGui::SetNextItemWidth(100);
if (ImGui::DragFloat("Letter Spacing", &LetterSpacing, 0.1f, 0.0f, 5.0f, "%.2f")) {
updated = true;
}
if (updated) {
Refresh();
}
}
void AText::DrawColourEditor(bool* updated) {
ImGui::Checkbox("Use single colour", &SingleColour);
if (SingleColour)
{
// Convert 8bit colours to float
ImVec4 colour(
TextColour[0].r / 255.0f,
TextColour[0].g / 255.0f,
TextColour[0].b / 255.0f,
TextColour[0].a / 255.0f
);
// Single color input
ImGui::ColorEdit4("Colour", (float*)&colour);
// Apply same color to all vertices
for (int i = 0; i < 4; i++) {
TextColour[i].r = FloatToU8(colour.x);
TextColour[i].g = FloatToU8(colour.y);
TextColour[i].b = FloatToU8(colour.z);
TextColour[i].a = FloatToU8(colour.w);
}
*updated = true;
} else {
// Separate color pickers for each vertex
for (int i = 0; i < 4; i++)
{
ImVec4 colour2(
TextColour[i].r / 255.0f,
TextColour[i].g / 255.0f,
TextColour[i].b / 255.0f,
TextColour[i].a / 255.0f
);
char label[32];
snprintf(label, sizeof(label), "Vtx %d Colour", i);
if (ImGui::ColorEdit4(label, (float*)&colour2)) {
TextColour[i].r = FloatToU8(colour2.x);
TextColour[i].g = FloatToU8(colour2.y);
TextColour[i].b = FloatToU8(colour2.z);
TextColour[i].a = FloatToU8(colour2.w);
*updated = true;
}
}
}
}
+149
View File
@@ -0,0 +1,149 @@
#pragma once
#include <libultraship.h>
#include "engine/Actor.h"
#include "src/textures.h"
#include "engine/CoreMath.h"
#include "port/Game.h"
class AText : public AActor {
public:
enum TextMode : int16_t {
STATIONARY,
FOLLOW_PLAYER
};
enum FadeMode : int16_t {
NO_FADE,
FADE_IN,
FADE_OUT
};
enum DistanceProps : int16_t {
TOO_CLOSE,
ACTIVE,
TOO_FAR
};
DistanceProps Dist = ACTIVE;
DistanceProps PrevState = ACTIVE;
FadeMode FadeState = NO_FADE;
struct CharacterList {
const char* Texture;
f32 column;
f32 row;
u32 width;
u32 height;
s32 mode;
Vtx vtx[4];
};
std::vector<CharacterList> TextureList;
std::string Text; // The text to be displayed
TextMode Mode;
uint32_t PlayerIndex;
float WidthOffset = 0.0f;
float HeightOffset = 8.0f; // Place text above player
f32 ScaleX = 1.0f;
f32 LetterSpacing = 1.0f;
f32 Far = 14000.0f;
f32 Close = 350.0f;
bool FaceCamera = true;
bool Animate = false;
bool SingleColour = true; // Only used for imGUI to show more colour options
// 1 colour for each of the 4 vtx
// This allows setting each vtx colour individually
RGBA8 TextColour[4];
// Constructor
AText(const SpawnParams& params);
virtual ~AText() override = default;
/**
* This is simply a helper function to keep Spawning code clean
* Main parameters usage:
*
* PlayerIndex is only used if textMode is FOLLOW_PLAYER
*
* Other available options:
*
* TextColour<RGBA8> - Colour of the text (1 colour for each vertex)
* ScaleX<float> - Font scale Y
* LetterSpacing<float> - Space between letters
* HeightOffset<float> - Height above player when in FOLLOW_PLAYER mode
* WidthOffset<float> - Left/right offset of the text when in FOLLOW_PLAYER mode
* Far<float> - Skip rendering if camera is too far away
* Close<float> - Skip rendering if too close to the camera
* Animate<bool> - Cycle colours similar to the grand prix title text
*
* Other options usage:
*
* AText* text = AText::Spawn("Hello World", FVector(0, 0, 0), etc.);
* text->Animate = true;
* text->Far = 14000.0f;
* text->ScaleX = 0.1f; // Recommend in the range of 0-2.0f. Default 1.0f
* text->LetterSpacing = 1.0f; // Default 1.0f
*
* For one single colour, set all vertices to the same colour.
* text->TextColour[0] = {255, 0, 0, 255}; // Red
* text->TextColour[1] = {0, 255, 0, 255}; // Green
* text->TextColour[2] = {0, 0, 255, 255}; // Blue
* text->TextColour[3] = {255, 255, 0, 255}; // Yellow
*
* The above will result in a gradient between red, green, blue, and yellow
* For transparency {0, 0, 0, 100} <-- alpha value of 100 will render semi-transparent black text.
*
*/
static inline AText* Spawn(std::string text, FVector pos, FVector scale, AText::TextMode textMode, int16_t playerIndex) {
SpawnParams params = {
.Name = "hm:text",
.Type = static_cast<int16_t>(textMode),
.Behaviour = static_cast<int16_t>(playerIndex),
.Skin = text,
.Location = pos,
.Scale = scale,
};
return static_cast<AText*>(gWorldInstance.AddActor(new AText(params)));
}
// Virtual functions to be overridden by derived classes
virtual void Tick() override;
virtual void Draw(Camera* camera) override;
virtual void SetSpawnParams(SpawnParams& params) override;
virtual bool IsMod() override;
virtual void DrawEditorProperties() override;
void DrawColourEditor(bool* updated);
void FollowPlayer();
std::string ValidateString(const std::string_view& text);
void Refresh();
void Print3D(char* text, s32 tracking, s32 mode);
void PrintLetter3D(MenuTexture* glyphTexture, f32 column, f32 row, s32 mode);
void SetupVtx();
void DrawText3D(Camera* camera); // Based on func_80095BD0
void AnimateColour(Vtx* vtx); // Animate the vtx colours
void FadeIn(Vtx* vtx);
void FadeOut(Vtx* vtx);
inline uint8_t FloatToU8(float v) {
return (uint8_t)(v * 255.0f);
}
Vtx myVtx[12] = { // D_02007BB8
{{{ 0, 16, 0}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{26, 16, 0}, 0, {1600, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{26, 0, 0}, 0, {1600, 960}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 0, 0, 0}, 0, { 0, 960}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 0, 16, 0}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{16, 16, 0}, 0, {960, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{16, 0, 0}, 0, {960, 960}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 0, 0, 0}, 0, { 0, 960}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 0, 32, 0}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{30, 32, 0}, 0, {1856, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{30, 0, 0}, 0, {1856, 1984}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 0, 0, 0}, 0, { 0, 1984}, {0xff, 0xff, 0xff, 0xff}}},
};
};
+1
View File
@@ -11,6 +11,7 @@ extern "C" {
ATree::ATree(Vec3f pos, Gfx* displaylist, f32 drawDistance, f32 minDrawDistance, const char* tlut = nullptr) {
Name = "Tree";
ResourceName = "mk:tree";
Pos[0] = pos[0];
Pos[1] = pos[1];
Pos[2] = pos[2];
+25 -3
View File
@@ -8,18 +8,40 @@ extern "C" {
#include "math_util.h"
#include "main.h"
#include "actor_types.h"
#include "code_800029B0.h"
#include "collision.h"
}
AWarioSign::AWarioSign(FVector pos) {
AWarioSign::AWarioSign(const SpawnParams& params) : AActor(params) {
Type = ACTOR_WARIO_SIGN;
Name = "Wario Sign";
Pos[0] = pos.x;
ResourceName = "mk:wario_sign";
Model = d_course_wario_stadium_dl_sign;
Speed = params.Speed.value_or(182);
FVector pos = params.Location.value_or(FVector(0, 0, 0));
Pos[0] = pos.x * gCourseDirection;
Pos[1] = pos.y;
Pos[2] = pos.z;
IRotator rot = params.Rotation.value_or(IRotator(0, 0, 0));
Rot[0] = rot.pitch;
Rot[1] = rot.yaw;
Rot[2] = rot.roll;
Scale = params.Scale.value_or(FVector(1.0f, 1.0f, 1.0f));
func_802AAAAC(&Unk30);
Flags = -0x8000;
}
bool AWarioSign::IsMod() {
return true;
}
void AWarioSign::Tick() {
Rot[1] += 0xB6;
Rot[1] += Speed;
}
void AWarioSign::Draw(Camera *camera) {
+16 -1
View File
@@ -3,6 +3,7 @@
#include <libultraship.h>
#include "engine/Actor.h"
#include "CoreMath.h"
#include "engine/World.h"
extern "C" {
#include "common_structs.h"
@@ -12,8 +13,22 @@ class AWarioSign : public AActor {
public:
virtual ~AWarioSign() = default;
explicit AWarioSign(FVector pos);
explicit AWarioSign(const SpawnParams& params);
// This is simply a helper function to keep Spawning code clean
static inline AWarioSign* Spawn(FVector pos, IRotator rot, FVector velocity, FVector scale) {
SpawnParams params = {
.Name = "mk:wario_sign",
.Location = pos,
.Rotation = rot,
.Scale = scale,
.Velocity = velocity,
.Speed = 182,
};
return static_cast<AWarioSign*>(gWorldInstance.AddActor(new AWarioSign(params)));
}
virtual bool IsMod() override;
virtual void Tick() override;
virtual void Draw(Camera*) override;
};
+14 -16
View File
@@ -164,8 +164,8 @@ void BansheeBoardwalk::LoadTextures() {
void BansheeBoardwalk::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_banshee_boardwalk_item_box_spawns));
gWorldInstance.AddObject(new OCheepCheep(FVector(xOrientation * -1650.0, -200.0f, -1650.0f),
OCheepCheep::CheepType::RACE, IPathSpan(160, 170)));
OCheepCheep::Spawn(FVector(xOrientation * -1650.0, -200.0f, -1650.0f),
OCheepCheep::Behaviour::RACE, IPathSpan(160, 170));
OTrashBin::Behaviour bhv;
if (gModeSelection == TIME_TRIALS) {
@@ -175,27 +175,25 @@ void BansheeBoardwalk::BeginPlay() {
}
if (gIsMirrorMode) {
gWorldInstance.AddObject(new OTrashBin(FVector(1765.0f, 45.0f, 195.0f), IRotator(0, 180, 0), 1.0f, bhv));
OTrashBin::Spawn(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), IRotator(0, 0, 0), 1.0f, bhv));
OTrashBin::Spawn(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), 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)));
OBat::Spawn(FVector(0,0,0), IRotator(0, 0, 90));
OBoos::Spawn(5, IPathSpan(180, 190), IPathSpan(200, 210), IPathSpan(280, 290));
OBoos::Spawn(5, IPathSpan(490, 500), IPathSpan(510, 520), IPathSpan(620, 630));
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][110], 110, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][190], 190, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][475], 475, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][610], 610, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 110, 3, 0.8333333f);
OBombKart::Spawn(0, 190, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 475, 1, 0.8333333f);
OBombKart::Spawn(0, 610, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+7 -9
View File
@@ -132,15 +132,13 @@ void BigDonut::BeginPlay() {
spawn_all_item_boxes((ActorSpawnData*) LOAD_ASSET_RAW(d_course_big_donut_item_box_spawns));
if (gModeSelection == VERSUS) {
FVector pos = {0, 0, 0};
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][20], 20, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][40], 40, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][60], 60, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][80], 80, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][120], 120, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 0, 1.0f));
OBombKart::Spawn(0, 20, 0, 1.0f);
OBombKart::Spawn(0, 40, 0, 1.0f);
OBombKart::Spawn(0, 60, 0, 1.0f);
OBombKart::Spawn(0, 80, 0, 1.0f);
OBombKart::Spawn(0, 100, 0, 1.0f);
OBombKart::Spawn(0, 120, 0, 1.0);
OBombKart::Spawn(0, 140, 0, 1.0f);
}
}
+7 -9
View File
@@ -127,15 +127,13 @@ void BlockFort::BeginPlay() {
spawn_all_item_boxes((ActorSpawnData*) LOAD_ASSET_RAW(d_course_block_fort_item_box_spawns));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][20], 20, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][40], 40, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][60], 60, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][80], 80, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][120], 120, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 0, 1.0f));
OBombKart::Spawn(0, 20, 0, 1.0f);
OBombKart::Spawn(0, 40, 0, 1.0f);
OBombKart::Spawn(0, 60, 0, 1.0f);
OBombKart::Spawn(0, 80, 0, 1.0f);
OBombKart::Spawn(0, 100, 0, 1.0f);
OBombKart::Spawn(0, 120, 0, 1.0f);
OBombKart::Spawn(0, 140, 0, 1.0f);
}
}
+40 -41
View File
@@ -4,7 +4,8 @@
#include <memory>
#include "BowsersCastle.h"
#include "World.h"
#include "engine/World.h"
#include "engine/courses/Course.h"
#include "engine/actors/Finishline.h"
#include "engine/objects/BombKart.h"
#include "engine/objects/Thwomp.h"
@@ -169,54 +170,52 @@ void BowsersCastle::BeginPlay() {
switch (gCCSelection) {
case CC_100:
case CC_EXTRA:
gWorldInstance.AddObject(new OThwomp(0x0320, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0));
gWorldInstance.AddObject(new OThwomp(0x044c, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 1));
gWorldInstance.AddObject(new OThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 1));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5bf, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf597, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 1));
gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0));
gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 0));
gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1));
OThwomp::Spawn(0x0320, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0);
OThwomp::Spawn(0x044c, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 1);
OThwomp::Spawn(0x02bc, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0);
OThwomp::Spawn(0x04b0, 0xf8f8, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 1);
OThwomp::Spawn(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0);
OThwomp::Spawn(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1);
OThwomp::Spawn(0x091a, 0xf5bf, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0);
OThwomp::Spawn(0x091a, 0xf597, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 1);
OThwomp::Spawn(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0);
OThwomp::Spawn(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 0);
OThwomp::Spawn(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1);
break;
case CC_50:
gWorldInstance.AddObject(new OThwomp(0x3B6, 0xF92A, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0));
gWorldInstance.AddObject(new OThwomp(0x0352, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5b0, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0));
gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0));
gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE , 0));
gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1));
OThwomp::Spawn(0x3B6, 0xF92A, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0);
OThwomp::Spawn(0x0352, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0);
OThwomp::Spawn(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0);
OThwomp::Spawn(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1);
OThwomp::Spawn(0x091a, 0xf5b0, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0);
OThwomp::Spawn(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0);
OThwomp::Spawn(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE , 0);
OThwomp::Spawn(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1);
break;
case CC_150:
gWorldInstance.AddObject(new OThwomp(0x0320, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0));
gWorldInstance.AddObject(new OThwomp(0x044c, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 1));
gWorldInstance.AddObject(new OThwomp(0x02bc, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf8f8, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 1));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0));
gWorldInstance.AddObject(new OThwomp(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5c9, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf5ab, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 1));
gWorldInstance.AddObject(new OThwomp(0x091a, 0xf58d, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 2));
gWorldInstance.AddObject(new OThwomp(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0));
gWorldInstance.AddObject(new OThwomp(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 0));
gWorldInstance.AddObject(new OThwomp(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1));
OThwomp::Spawn(0x0320, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 0);
OThwomp::Spawn(0x044c, 0xf92a, 0xC000, 1.0f, OThwomp::States::STATIONARY, 1);
OThwomp::Spawn(0x02bc, 0xf95c, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 0);
OThwomp::Spawn(0x04b0, 0xf8f8, 0xC000, 1.0f, OThwomp::States::MOVE_AND_ROTATE, 1);
OThwomp::Spawn(0x04b0, 0xf5ba, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 0);
OThwomp::Spawn(0x04b0, 0xf592, 0xC000, 1.0f, OThwomp::States::MOVE_FAR, 1);
OThwomp::Spawn(0x091a, 0xf5c9, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 0);
OThwomp::Spawn(0x091a, 0xf5ab, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 1);
OThwomp::Spawn(0x091a, 0xf58d, 0xC000, 1.0f, OThwomp::States::STATIONARY_FAST, 2);
OThwomp::Spawn(0x0596, 0xf92f, 0xC000, 1.5f, OThwomp::States::JAILED, 0);
OThwomp::Spawn(0x082a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 0);
OThwomp::Spawn(0x073a, 0xf9f2, 0x4000, 1.0f, OThwomp::States::SLIDE, 1);
break;
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][260], 260, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][435], 435, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 150, 1, 0.8333333f);
OBombKart::Spawn(0, 200, 3, 0.8333333f);
OBombKart::Spawn(0, 260, 1, 0.8333333f);
OBombKart::Spawn(0, 435, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+11 -10
View File
@@ -8,6 +8,7 @@
#include "engine/objects/BombKart.h"
#include "choco_mountain_data.h"
#include "engine/actors/Finishline.h"
#include "engine/actors/FallingRock.h"
extern "C" {
#include "main.h"
@@ -177,18 +178,18 @@ void ChocoMountain::LoadTextures() {
void ChocoMountain::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_choco_mountain_item_box_spawns));
spawn_falling_rocks((struct ActorSpawnData*)LOAD_ASSET_RAW((const char*)d_course_choco_mountain_falling_rock_spawns));
AFallingRock::Spawn(FVector(2019, 156, 164), 60);
AFallingRock::Spawn(FVector(2018, 155, 379), 120);
AFallingRock::Spawn(FVector(1996, 146, 505), 180);
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][165], 165, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][330], 330, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][550], 550, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][595], 595, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 140, 3, 0.8333333f);
OBombKart::Spawn(0, 165, 1, 0.8333333f);
OBombKart::Spawn(0, 330, 3, 0.8333333f);
OBombKart::Spawn(0, 550, 1, 0.8333333f);
OBombKart::Spawn(0, 595, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+36 -14
View File
@@ -6,6 +6,8 @@
#include "port/Game.h"
#include "port/resource/type/TrackPathPointData.h"
#include "port/resource/type/TrackSections.h"
#include "engine/editor/SceneManager.h"
#include "Registry.h"
extern "C" {
#include "main.h"
@@ -24,6 +26,7 @@ extern "C" {
#include "collision.h"
#include "actors.h"
#include "math_util.h"
#include "code_80005FD0.h"
extern StaffGhost* d_mario_raceway_staff_ghost;
}
@@ -99,6 +102,7 @@ Course::Course() {
Props.PathTable2[1] = NULL;
Props.PathTable2[2] = NULL;
Props.PathTable2[3] = NULL;
Props.PathTable2[4] = NULL;
Props.Clouds = NULL;
Props.CloudList = NULL;
@@ -115,6 +119,7 @@ void Course::Load(Vtx* vtx, Gfx* gfx) {
void Course::LoadO2R(std::string trackPath) {
if (!trackPath.empty()) {
SceneFilePtr = (trackPath + "/scene.json");
TrackSectionsPtr = (trackPath + "/data_track_sections");
std::string path_file = (trackPath + "/data_paths").c_str();
@@ -125,22 +130,19 @@ void Course::LoadO2R(std::string trackPath) {
auto& paths = res->PathList;
size_t i = 0;
u16* ptr = &Props.PathSizes.unk0;
for (auto& path : paths) {
if (i == 0) {
Props.PathSizes.unk0 = path.size();
Props.PathTable[0] = (TrackPathPoint*) path.data();
Props.PathTable[1] = NULL;
Props.PathTable[2] = NULL;
Props.PathTable[3] = NULL;
Props.PathTable2[0] = (TrackPathPoint*) path.data();
Props.PathTable2[1] = NULL;
Props.PathTable2[2] = NULL;
Props.PathTable2[3] = NULL;
if (i >= ARRAY_COUNT(Props.PathTable2)) {
printf("[Course.cpp] The game can only import 5 paths. Found more than 5. Skipping the rest\n");
break; // Only 5 paths allowed. 4 track, 1 vehicle
}
ptr[i] = path.size();
Props.PathTable2[i] = (TrackPathPoint*) path.data();
i += 1;
}
}
gVehiclePathSize = Props.PathSizes.unk0; // This is likely incorrect.
} else {
printf("Course.cpp: LoadO2R: trackPath str is empty\n");
@@ -149,6 +151,10 @@ void Course::LoadO2R(std::string trackPath) {
// Load stock and o2r tracks
void Course::Load() {
// Re-load scenefile in-case changes were made in the editor
if (!SceneFilePtr.empty()) {
Editor::LoadLevel(this, SceneFilePtr);
}
// Load from O2R
if (!TrackSectionsPtr.empty()) {
@@ -219,6 +225,7 @@ void Course::Load() {
// C++ version of parse_course_displaylists()
void Course::ParseCourseSections(TrackSectionsO2R* sections, size_t size) {
printf("\n[Track] Generating Collision Meshes...\n");
for (size_t i = 0; i < (size / sizeof(TrackSectionsO2R)); i++) {
if (sections[i].flags & 0x8000) {
D_8015F59C = 1; // single-sided wall
@@ -235,10 +242,11 @@ void Course::ParseCourseSections(TrackSectionsO2R* sections, size_t size) {
} else {
D_8015F5A4 = 0;
}
printf("LOADING DL %s\n", sections[i].addr.c_str());
printf(" %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);
}
printf("[Track] Collision Mesh Generation Complete!\n\n");
}
void Course::TestPath() {
@@ -251,9 +259,9 @@ void Course::TestPath() {
Vec3f vel = { 0, 0, 0 };
for (size_t i = 0; i < gPathCountByPathIndex[0]; i++) {
x = gTrackPaths[0][i].posX;
y = gTrackPaths[0][i].posY;
z = gTrackPaths[0][i].posZ;
x = gTrackPaths[0][i].x;
y = gTrackPaths[0][i].y;
z = gTrackPaths[0][i].z;
if (((x & 0xFFFF) == 0x8000) && ((y & 0xFFFF) == 0x8000) && ((z & 0xFFFF) == 0x8000)) {
break;
@@ -289,7 +297,21 @@ void Course::LoadTextures() {
}
void Course::BeginPlay() {
printf("[Track] BeginPlay\n");
TestPath();
this->SpawnActors();
}
// Spawns actors from SpawnParams set by the scene file in SceneManager.cpp
void Course::SpawnActors() {
for (const auto& actor : SpawnList) {
auto it = gActorRegistry.find(actor.Name);
if (it != gActorRegistry.end() && it->second.spawnFunc) {
it->second.spawnFunc(actor);
} else {
printf("Actor not found %s\n", actor.Name.c_str());
}
}
}
void Course::InitClouds() {
+14 -3
View File
@@ -1,10 +1,13 @@
#ifndef ENGINE_COURSE_H
#define ENGINE_COURSE_H
#include <libultraship.h>
#include <libultraship/libultraship.h>
#include "CoreMath.h"
#ifdef __cplusplus
#include "engine/SpawnParams.h"
#include <optional>
#include <nlohmann/json.hpp>
#include "engine/objects/Lakitu.h"
#include "port/resource/type/TrackSections.h"
extern "C" {
@@ -81,8 +84,8 @@ typedef struct Properties {
Vec4f NormalTargetSpeed;
Vec4f D_0D0096B8;
Vec4f OffTrackTargetSpeed;
TrackPathPoint* PathTable[4];
TrackPathPoint* PathTable2[4];
TrackPathPoint* PathTable[4]; // Only used for podium ceremony
TrackPathPoint* PathTable2[5]; // The fifth entry is for vehicles
uint8_t* CloudTexture;
CloudData *Clouds;
CloudData *CloudList;
@@ -286,6 +289,7 @@ typedef struct Properties {
#ifdef __cplusplus
class World; // <-- Forward declare
class Course {
@@ -304,8 +308,14 @@ public:
const course_texture* textures = nullptr;
bool bSpawnFinishline = true;
std::optional<FVector> FinishlineSpawnPoint;
// O2R Loading
std::shared_ptr<Ship::Archive> RootArchive;
std::string SceneFilePtr;
std::string TrackSectionsPtr;
bool bIsMod = false;
std::vector<SpawnParams> SpawnList;
virtual ~Course() = default;
@@ -322,6 +332,7 @@ public:
* Actor spawning should go here.
*/
virtual void BeginPlay();
void SpawnActors();
virtual void TestPath();
virtual void InitClouds();
virtual void UpdateClouds(s32, Camera*);
+8 -10
View File
@@ -205,18 +205,16 @@ void DKJungle::BeginPlay() {
// The original game only ran vehicle logic every second frame.
// Thus the speed gets divided by two to set speed to match properly
gWorldInstance.AddActor(new ABoat((0.6666666f)/4, 0));
ABoat::Spawn((0.6666666f)/4, 0, 0, ABoat::SpawnMode::POINT);
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][190], 190, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 190, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
}
+7 -9
View File
@@ -129,15 +129,13 @@ void DoubleDeck::BeginPlay() {
spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_double_deck_item_box_spawns));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][20], 20, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][40], 40, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][60], 60, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][80], 80, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][120], 120, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 0, 1.0f));
OBombKart::Spawn(0, 20, 0, 1.0f);
OBombKart::Spawn(0, 40, 0, 1.0f);
OBombKart::Spawn(0, 60, 0, 1.0f);
OBombKart::Spawn(0, 80, 0, 1.0f);
OBombKart::Spawn(0, 100, 0, 1.0f);
OBombKart::Spawn(0, 120, 0, 1.0f);
OBombKart::Spawn(0, 140, 0, 1.0f);
}
}
+26 -28
View File
@@ -145,37 +145,35 @@ void FrappeSnowland::BeginPlay() {
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)));
gWorldInstance.AddObject(new OSnowman(FVector(27, 5, -2067)));
gWorldInstance.AddObject(new OSnowman(FVector(-656, 0, -1735)));
gWorldInstance.AddObject(new OSnowman(FVector(-1497, 0, -83)));
gWorldInstance.AddObject(new OSnowman(FVector(-1643, 0, -25)));
gWorldInstance.AddObject(new OSnowman(FVector(-1547, 0, -20)));
gWorldInstance.AddObject(new OSnowman(FVector(-1445, 0, -10)));
gWorldInstance.AddObject(new OSnowman(FVector(-1502, 0, 61)));
gWorldInstance.AddObject(new OSnowman(FVector(-1429, 0, 79)));
gWorldInstance.AddObject(new OSnowman(FVector(-1586, 0, 71)));
gWorldInstance.AddObject(new OSnowman(FVector(-1471, 0, 157)));
gWorldInstance.AddObject(new OSnowman(FVector(-1539, 0, 175)));
gWorldInstance.AddObject(new OSnowman(FVector(-1484, 0, 303)));
gWorldInstance.AddObject(new OSnowman(FVector(-1442, 0, 358)));
gWorldInstance.AddObject(new OSnowman(FVector(-1510, 0, 426)));
gWorldInstance.AddObject(new OSnowman(FVector(-665, 0, 830)));
gWorldInstance.AddObject(new OSnowman(FVector(-701, 3, 853)));
gWorldInstance.AddObject(new OSnowman(FVector(-602, 0, 929)));
OSnowman::Spawn(FVector(697, 0, -1684));
OSnowman::Spawn(FVector(82, 0, -2245));
OSnowman::Spawn(FVector(27, 5, -2067));
OSnowman::Spawn(FVector(-656, 0, -1735));
OSnowman::Spawn(FVector(-1497, 0, -83));
OSnowman::Spawn(FVector(-1643, 0, -25));
OSnowman::Spawn(FVector(-1547, 0, -20));
OSnowman::Spawn(FVector(-1445, 0, -10));
OSnowman::Spawn(FVector(-1502, 0, 61));
OSnowman::Spawn(FVector(-1429, 0, 79));
OSnowman::Spawn(FVector(-1586, 0, 71));
OSnowman::Spawn(FVector(-1471, 0, 157));
OSnowman::Spawn(FVector(-1539, 0, 175));
OSnowman::Spawn(FVector(-1484, 0, 303));
OSnowman::Spawn(FVector(-1442, 0, 358));
OSnowman::Spawn(FVector(-1510, 0, 426));
OSnowman::Spawn(FVector(-665, 0, 830));
OSnowman::Spawn(FVector(-701, 3, 853));
OSnowman::Spawn(FVector(-602, 0, 929));
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][290], 290, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][350], 350, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 290, 1, 0.8333333f);
OBombKart::Spawn(0, 350, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
-81
View File
@@ -620,75 +620,8 @@ void Harbour::Load() {
void Harbour::LoadTextures() {
dma_textures(gTextureTrees1, 0x0000035BU, 0x00000800U); // 0x03009000
D_802BA058 = dma_textures(gTexturePiranhaPlant1, 0x000003E8U, 0x00000800U); // 0x03009800
dma_textures(gTexturePiranhaPlant2, 0x000003E8U, 0x00000800U); // 0x0300A000
dma_textures(gTexturePiranhaPlant3, 0x000003E8U, 0x00000800U); // 0x0300A800
dma_textures(gTexturePiranhaPlant4, 0x000003E8U, 0x00000800U); // 0x0300B000
dma_textures(gTexturePiranhaPlant5, 0x000003E8U, 0x00000800U); // 0x0300B800
dma_textures(gTexturePiranhaPlant6, 0x000003E8U, 0x00000800U); // 0x0300C000
dma_textures(gTexturePiranhaPlant7, 0x000003E8U, 0x00000800U); // 0x0300C800
dma_textures(gTexturePiranhaPlant8, 0x000003E8U, 0x00000800U); // 0x0300D000
dma_textures(gTexturePiranhaPlant9, 0x000003E8U, 0x00000800U); // 0x0300D800
}
Path2D harbour_path2D[] = {
{ 0, 0},
{ 0, -100},
{ 0, -200},
{ 0, -300},
{ 0, -400},
{ 0, -500},
{ 0, -600},
{ 0, -700},
{ 0, -800},
{ 0, -900},
{ 0, -1000},
{ 0, -1096}, // Main point 1
{ 100, -1090},
{ 200, -1085},
{ 300, -1080},
{ 400, -1075},
{ 500, -1072}, // Curve begins to smooth here
{ 600, -1068},
{ 700, -1065},
{ 800, -1063},
{ 900, -1061},
{ 984, -1060}, // Main point 2
{ 990, -900},
{ 995, -800},
{ 997, -700},
{ 998, -600},
{ 999, -500},
{ 999, -400},
{ 999, -300},
{ 999, -200},
{ 999, -100},
{ 999, 0},
{ 999, 100},
{ 999, 200},
{ 999, 300},
{ 999, 400},
{ 999, 500},
{ 999, 600},
{ 999, 700},
{ 999, 800},
{ 999, 900},
{ 999, 940}, // Main point 3
{ 900, 945},
{ 800, 945},
{ 700, 947},
{ 600, 948},
{ 500, 949},
{ 400, 949},
{ 300, 949},
{ 200, 950},
{ 100, 950},
{ 0, 950}, // Main point 4
// End of path
{ -32768, -32768 } // Terminator
};
void Harbour::BeginPlay() {
struct ActorSpawnData itemboxes[] = {
{ 200, 1500, 200 , 0},
@@ -742,22 +675,8 @@ void Harbour::BeginPlay() {
// gWorldInstance.AddObject(new OBoos(10, IPathSpan(0, 5), IPathSpan(18, 23), IPathSpan(25, 50)));
// gVehicle2DPathPoint = harbour_path2D;
//gVehicle2DPathLength = 53;
// D_80162EB0 = spawn_actor_on_surface(harbour_path2D[0].x, 2000.0f, harbour_path2D[0].z);
// DEBUG ONLY TO VISUALIZE PATH
// for (size_t i = 0; i < ARRAY_COUNT(harbour_path); i++) {
// if (i % 10 == 1) {
// f32 height = spawn_actor_on_surface(harbour_path[i].posX, 2000.0f, harbour_path[i].posZ);
// Vec3f itemPos = {harbour_path[i].posX, height, harbour_path[i].posZ};
// 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.AddObject(new OGrandPrixBalloons(FVector(16, -136, -34)));
}
void Harbour::WhatDoesThisDo(Player* player, int8_t playerId) {
+12 -12
View File
@@ -4,7 +4,7 @@
#include <memory>
#include "KalimariDesert.h"
#include "World.h"
#include "engine/World.h"
#include "engine/actors/Finishline.h"
#include "engine/objects/BombKart.h"
#include "kalimari_desert_data.h"
@@ -198,7 +198,9 @@ void KalimariDesert::BeginPlay() {
// Spawn two trains
for (size_t i = 0; i < _numTrains; ++i) {
uint32_t waypoint = CalculateWaypointDistribution(i, _numTrains, gVehicle2DPathLength, centerWaypoint);
// outputs 160 for train 1 and 392 for train 2.
// If using more trains, it wraps the value to always output a valid waypoint.
uint32_t waypoint = CalculateWaypointDistribution(i, _numTrains, gVehiclePathSize, centerWaypoint);
if (CVarGetInteger("gMultiplayerNoFeatureCuts", 0) == false) {
// Multiplayer modes have no tender and no carriages
@@ -214,19 +216,17 @@ void KalimariDesert::BeginPlay() {
}
}
gWorldInstance.AddActor(new ATrain(_tender, _numCarriages, 2.5f, waypoint));
ATrain::Spawn(_tender, _numCarriages, 2.5f, 0, waypoint, ATrain::SpawnMode::POINT);
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][138], 138, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][280], 280, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][404], 404, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][510], 510, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 138, 1, 0.8333333f);
OBombKart::Spawn(0, 280, 3, 0.8333333f);
OBombKart::Spawn(0, 404, 1, 0.8333333f);
OBombKart::Spawn(0, 510, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
}
+21 -22
View File
@@ -9,6 +9,7 @@
#include "engine/actors/Finishline.h"
#include "engine/objects/BombKart.h"
#include "engine/objects/Crab.h"
#include "engine/objects/Seagull.h"
#include "assets/koopa_troopa_beach_data.h"
extern "C" {
@@ -164,42 +165,40 @@ void KoopaTroopaBeach::BeginPlay() {
spawn_palm_trees((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_koopa_troopa_beach_tree_spawn));
if (gGamestate != CREDITS_SEQUENCE) {
gWorldInstance.AddObject(new OCrab(FVector2D(-1809, 625), FVector2D(-1666, 594)));
gWorldInstance.AddObject(new OCrab(FVector2D(-1852, 757), FVector2D(-1620, 740)));
gWorldInstance.AddObject(new OCrab(FVector2D(-1478, 1842), FVector2D(-1453, 1833)));
gWorldInstance.AddObject(new OCrab(FVector2D(-1418, 1967), FVector2D(-1455, 1962)));
gWorldInstance.AddObject(new OCrab(FVector2D(-1472, 2112), FVector2D(-1417, 2100)));
gWorldInstance.AddObject(new OCrab(FVector2D(-1389, 2152), FVector2D(-1335, 2136)));
gWorldInstance.AddObject(new OCrab(FVector2D(218, 693), FVector2D(69, 696)));
gWorldInstance.AddObject(new OCrab(FVector2D(235, 528), FVector2D(24, 501)));
gWorldInstance.AddObject(new OCrab(FVector2D(268, 406), FVector2D(101, 394)));
gWorldInstance.AddObject(new OCrab(FVector2D(223, 318), FVector2D(86, 308)));
OCrab::Spawn(FVector2D(-1809, 625), FVector2D(-1666, 594));
OCrab::Spawn(FVector2D(-1852, 757), FVector2D(-1620, 740));
OCrab::Spawn(FVector2D(-1478, 1842), FVector2D(-1453, 1833));
OCrab::Spawn(FVector2D(-1418, 1967), FVector2D(-1455, 1962));
OCrab::Spawn(FVector2D(-1472, 2112), FVector2D(-1417, 2100));
OCrab::Spawn(FVector2D(-1389, 2152), FVector2D(-1335, 2136));
OCrab::Spawn(FVector2D(218, 693), FVector2D(69, 696));
OCrab::Spawn(FVector2D(235, 528), FVector2D(24, 501));
OCrab::Spawn(FVector2D(268, 406), FVector2D(101, 394));
OCrab::Spawn(FVector2D(223, 318), FVector2D(86, 308));
}
if (gGamestate == CREDITS_SEQUENCE) {
for (size_t i = 0; i < NUM_SEAGULLS; i++) {
gWorldInstance.AddObject(new OSeagull(FVector(-360.0f, 60.0f, -1300.0f)));
OSeagull::Spawn(FVector(-360.0f, 60.0f, -1300.0f));
}
} else { // Normal gameplay
for (size_t i = 0; i < 4; i++) {
gWorldInstance.AddObject(new OSeagull(FVector(-985.0f, 15.0f, 1200.0f)));
OSeagull::Spawn(FVector(-985.0f, 15.0f, 1200.0f));
}
for (size_t i = 0; i < 6; i++) {
gWorldInstance.AddObject(new OSeagull(FVector(328.0f, 20.0f, 2541.0f)));
OSeagull::Spawn(FVector(328.0f, 20.0f, 2541.0f));
}
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][60], 60, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][120], 120, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][280], 280, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][435], 435, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 60, 1, 0.8333333f);
OBombKart::Spawn(0, 120, 1, 0.8333333f);
OBombKart::Spawn(0, 200, 3, 0.8333333f);
OBombKart::Spawn(0, 280, 1, 0.8333333f);
OBombKart::Spawn(0, 435, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+10 -12
View File
@@ -182,22 +182,20 @@ void LuigiRaceway::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*) LOAD_ASSET_RAW(d_course_luigi_raceway_item_box_spawns));
if (gGamestate == CREDITS_SEQUENCE) {
gWorldInstance.AddObject(new OHotAirBalloon(FVector(-1250.0f, 0.0f, 1110.0f)));
OHotAirBalloon::Spawn(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)));
OHotAirBalloon::Spawn(FVector(-176.0, 0.0f, -2323.0f));
OGrandPrixBalloons::Spawn(FVector(-140, -44, -215));
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][305], 305, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][440], 440, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][515], 515, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 1, 0.8333333f);
OBombKart::Spawn(0, 200, 3, 0.8333333f);
OBombKart::Spawn(0, 305, 1, 0.8333333f);
OBombKart::Spawn(0, 440, 3, 0.8333333f);
OBombKart::Spawn(0, 515, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+12 -24
View File
@@ -6,6 +6,7 @@
#include "MarioRaceway.h"
#include "World.h"
#include "engine/actors/Finishline.h"
#include "engine/actors/MarioSign.h"
#include "engine/objects/Object.h"
#include "engine/objects/BombKart.h"
#include "engine/objects/GrandPrixBalloons.h"
@@ -177,15 +178,6 @@ void MarioRaceway::Load() {
void MarioRaceway::LoadTextures() {
dma_textures(gTextureTrees1, 0x0000035BU, 0x00000800U); // 0x03009000
D_802BA058 = dma_textures(gTexturePiranhaPlant1, 0x000003E8U, 0x00000800U); // 0x03009800
dma_textures(gTexturePiranhaPlant2, 0x000003E8U, 0x00000800U); // 0x0300A000
dma_textures(gTexturePiranhaPlant3, 0x000003E8U, 0x00000800U); // 0x0300A800
dma_textures(gTexturePiranhaPlant4, 0x000003E8U, 0x00000800U); // 0x0300B000
dma_textures(gTexturePiranhaPlant5, 0x000003E8U, 0x00000800U); // 0x0300B800
dma_textures(gTexturePiranhaPlant6, 0x000003E8U, 0x00000800U); // 0x0300C000
dma_textures(gTexturePiranhaPlant7, 0x000003E8U, 0x00000800U); // 0x0300C800
dma_textures(gTexturePiranhaPlant8, 0x000003E8U, 0x00000800U); // 0x0300D000
dma_textures(gTexturePiranhaPlant9, 0x000003E8U, 0x00000800U); // 0x0300D800
}
void MarioRaceway::BeginPlay() {
@@ -197,26 +189,22 @@ void MarioRaceway::BeginPlay() {
spawn_foliage((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_mario_raceway_tree_spawns));
spawn_piranha_plants((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_mario_raceway_piranha_plant_spawns));
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_mario_raceway_item_box_spawns));
vec3f_set(position, 150.0f, 40.0f, -1300.0f);
position[0] *= gCourseDirection;
add_actor_to_empty_slot(position, rotation, velocity, ACTOR_MARIO_SIGN);
vec3f_set(position, 2520.0f, 0.0f, 1240.0f);
position[0] *= gCourseDirection;
add_actor_to_empty_slot(position, rotation, velocity, ACTOR_MARIO_SIGN);
AMarioSign::Spawn(FVector(150.0f, 40.0f, -1300.0f), IRotator(0, 0, 0), FVector(0, 0, 0), FVector(1.0f, 1.0f, 1.0f));
AMarioSign::Spawn(FVector(2520.0f, 0.0f, 1240.0f), IRotator(0, 0, 0), FVector(0, 0, 0), FVector(1.0f, 1.0f, 1.0f));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][40], 40, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][265], 265, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][285], 285, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][420], 420, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 40, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 3, 0.8333333f);
OBombKart::Spawn(0, 265, 3, 0.8333333f);
OBombKart::Spawn(0, 285, 1, 0.8333333f);
OBombKart::Spawn(0, 420, 1, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
if (gGamestate != CREDITS_SEQUENCE) {
gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(0, 5, -240)));
OGrandPrixBalloons::Spawn(FVector(0, 5, -240));
}
}
+7 -9
View File
@@ -323,15 +323,13 @@ void MooMooFarm::BeginPlay() {
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][225], 225, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][316], 316, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][434], 434, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 140, 3, 0.8333333f);
OBombKart::Spawn(0, 225, 3, 0.8333333f);
OBombKart::Spawn(0, 316, 3, 0.8333333f);
OBombKart::Spawn(0, 434, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+16 -17
View File
@@ -138,10 +138,10 @@ PodiumCeremony::PodiumCeremony() {
Props.PathTable[2] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path_3);
Props.PathTable[3] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path_4);
Props.PathTable2[0] = NULL;
Props.PathTable2[1] = NULL;
Props.PathTable2[2] = NULL;
Props.PathTable2[3] = NULL;
Props.PathTable2[0] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path);
Props.PathTable2[1] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path_2);
Props.PathTable2[2] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path_3);
Props.PathTable2[3] = (TrackPathPoint*)LOAD_ASSET_RAW(podium_ceremony_path_4);
Props.CloudTexture = (u8*) gTextureExhaust4;
Props.Clouds = NULL; // no clouds
@@ -175,9 +175,9 @@ void PodiumCeremony::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_item_box_spawns));
spawn_piranha_plants((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_piranha_plant_spawn));
gWorldInstance.AddObject(new OCheepCheep(FVector((f32)-3202, (f32)19, (f32)-478), OCheepCheep::CheepType::PODIUM_CEREMONY, IPathSpan(0, 0)));
gWorldInstance.AddObject(new OPodium(FVector((f32)-3202, (f32)19, (f32)-478)));
OCheepCheep::Spawn(FVector((f32)-3202, (f32)19, (f32)-478), OCheepCheep::Behaviour::PODIUM_CEREMONY, IPathSpan(0, 0));
OPodium::Spawn(FVector((f32)-3202, (f32)19, (f32)-478));
FVector pos = {0, 90.0f, 0};
OTrophy::TrophyType type = OTrophy::TrophyType::BRONZE;
@@ -197,19 +197,18 @@ void PodiumCeremony::BeginPlay() {
break;
}
OTrophy* trophy = reinterpret_cast<OTrophy*>(gWorldInstance.AddObject(new OTrophy(pos, type, OTrophy::Behaviour::PODIUM_CEREMONY)));
OTrophy::Spawn(pos, type, OTrophy::Behaviour::PODIUM_CEREMONY);
FVector kart = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][3], 3, OBombKart::States::PODIUM_CEREMONY, 1.25f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][40], 40, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][60], 60, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][80], 80, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][100], 100, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][120], 120, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[3][140], 140, 0, 1.0f));
OBombKart::Spawn(3, 3, OBombKart::States::PODIUM_CEREMONY, 1.25f);
OBombKart::Spawn(3, 40, 0, 1.0f);
OBombKart::Spawn(3, 60, 0, 1.0f);
OBombKart::Spawn(3, 80, 0, 1.0f);
OBombKart::Spawn(3, 100, 0, 1.0f);
OBombKart::Spawn(3, 120, 0, 1.0f);
OBombKart::Spawn(3, 140, 0, 1.0f);
if (gGamestate != CREDITS_SEQUENCE) {
gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(-64, 5, -330)));
OGrandPrixBalloons::Spawn(FVector(-64, 5, -330));
}
}
+7 -9
View File
@@ -156,15 +156,13 @@ void RainbowRoad::BeginPlay() {
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 200, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+8 -19
View File
@@ -173,15 +173,6 @@ void RoyalRaceway::Load() {
void RoyalRaceway::LoadTextures() {
dma_textures(gTextureTrees3, 0x000003E8U, 0x00000800U); // 0x03009000
dma_textures(gTextureTrees7, 0x000003E8U, 0x00000800U); // 0x03009800
D_802BA058 = dma_textures(gTexturePiranhaPlant1, 0x000003E8U, 0x00000800U); // 0x0300A000
dma_textures(gTexturePiranhaPlant2, 0x000003E8U, 0x00000800U); // 0x0300A800
dma_textures(gTexturePiranhaPlant3, 0x000003E8U, 0x00000800U); // 0x0300B000
dma_textures(gTexturePiranhaPlant4, 0x000003E8U, 0x00000800U); // 0x0300B800
dma_textures(gTexturePiranhaPlant5, 0x000003E8U, 0x00000800U); // 0x0300C000
dma_textures(gTexturePiranhaPlant6, 0x000003E8U, 0x00000800U); // 0x0300C800
dma_textures(gTexturePiranhaPlant7, 0x000003E8U, 0x00000800U); // 0x0300D000
dma_textures(gTexturePiranhaPlant8, 0x000003E8U, 0x00000800U); // 0x0300D800
dma_textures(gTexturePiranhaPlant9, 0x000003E8U, 0x00000800U); // 0x0300E000
}
void RoyalRaceway::BeginPlay() {
@@ -190,18 +181,16 @@ void RoyalRaceway::BeginPlay() {
spawn_piranha_plants((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_royal_raceway_piranha_plant_spawn));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][296], 296, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][400], 400, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][746], 746, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 3, 0.8333333f);
OBombKart::Spawn(0, 296, 3, 0.8333333f);
OBombKart::Spawn(0, 400, 1, 0.8333333f);
OBombKart::Spawn(0, 746, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
if (gGamestate != CREDITS_SEQUENCE) {
gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(-64, 5, -330)));
OGrandPrixBalloons::Spawn(FVector(-64, 5, -330));
}
}
+24 -54
View File
@@ -152,74 +152,44 @@ f32 SherbetLand::GetWaterLevel(FVector pos, Collision* collision) {
void SherbetLand::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_sherbet_land_item_box_spawns));
// Multiplayer does not spawn the big penguin
// Multiplayer does not spawn the big penguin... It does now!
// if (gPlayerCountSelection1 == 1) {
FVector pos = {-383.0f, 2.0f, -690.0f};
gWorldInstance.AddObject(new OPenguin(pos, 0, OPenguin::PenguinType::EMPEROR, OPenguin::Behaviour::STRUT));
OPenguin::Spawn(FVector(-383.0f, 2.0f, -690.0f), 0, 0, 0.0f, OPenguin::PenguinType::EMPEROR, OPenguin::Behaviour::STRUT);
// }
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;
OPenguin::Spawn(FVector(-2960.0f, -80.0f, 1521.0f), 0x150, 0, 100.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
OPenguin::Spawn(FVector(-2960.0f, -80.0f, 1521.0f), 0x150, 0, 100.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
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;
OPenguin::Spawn(FVector(-2490.0f, -80.0f, 1612.0f), 0x100, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
OPenguin::Spawn(FVector(-2490.0f, -80.0f, 1612.0f), 0x100, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
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;
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;
OPenguin::Spawn(FVector(-2098.0f, -80.0f, 1624.0f), 0xFF00, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
OPenguin::Spawn(FVector(-2098.0f, -80.0f, 1624.0f), 0xFF00, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
OPenguin::Spawn(FVector(-2080.0f, -80.0f, 1171.0f), 0x150, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
OPenguin::Spawn(FVector(-2080.0f, -80.0f, 1171.0f), 0x150, 0, 80.0f, OPenguin::PenguinType::ADULT, OPenguin::Behaviour::CIRCLE);
if (gGamestate == CREDITS_SEQUENCE) {
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;
OPenguin::Spawn(FVector(380.0f, 0.0f, -535.0f), 0x9000, -0x4000, 0.0f, OPenguin::PenguinType::CREDITS, OPenguin::Behaviour::SLIDE3);
} else {
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;
OPenguin::Spawn(FVector(146.0f, 0.0f, -380.0f), 0x9000, -0x4000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE3);
}
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;
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;
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;
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;
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;
OPenguin::Spawn(FVector(380.0f, 0.0f, -766.0f), 0x5000, 0x8000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE4);
OPenguin::Spawn(FVector(-2300.0f, 0.0f, -210.0f), 0xC000, 0x8000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6);
OPenguin::Spawn(FVector(-2500.0f, 0.0f, -250.0f), 0x4000, 0x8000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6);
OPenguin::Spawn(FVector(-535.0f, 0.0f, 875.0f), 0x8000, -0x4000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6);
OPenguin::Spawn(FVector(-250.0f, 0.0f, 953.0f), 0x9000, -0x4000, 0.0f, OPenguin::PenguinType::CHICK, OPenguin::Behaviour::SLIDE6);
if (gGamestate != CREDITS_SEQUENCE) {
if (gModeSelection == VERSUS) {
FVector kart = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][200], 200, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(kart, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 200, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
}
+7 -9
View File
@@ -153,15 +153,13 @@ void Skyscraper::BeginPlay() {
spawn_all_item_boxes((ActorSpawnData*)LOAD_ASSET_RAW(d_course_skyscraper_item_box_spawns));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][20], 20, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][40], 40, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][60], 60, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][80], 80, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][120], 120, 0, 1.0f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][140], 140, 0, 1.0f));
OBombKart::Spawn(0, 20, 0, 1.0f);
OBombKart::Spawn(0, 40, 0, 1.0f);
OBombKart::Spawn(0, 60, 0, 1.0f);
OBombKart::Spawn(0, 80, 0, 1.0f);
OBombKart::Spawn(0, 100, 0, 1.0f);
OBombKart::Spawn(0, 120, 0, 1.0f);
OBombKart::Spawn(0, 140, 0, 1.0f);
}
}
+6 -77
View File
@@ -29,6 +29,7 @@
#include "engine/objects/Crab.h"
#include "engine/objects/Boos.h"
#include "engine/objects/GrandPrixBalloons.h"
#include "engine/objects/Thwomp.h"
extern "C" {
#include "main.h"
@@ -147,75 +148,8 @@ void TestCourse::Load() {
void TestCourse::LoadTextures() {
dma_textures(gTextureTrees1, 0x0000035BU, 0x00000800U); // 0x03009000
D_802BA058 = dma_textures(gTexturePiranhaPlant1, 0x000003E8U, 0x00000800U); // 0x03009800
dma_textures(gTexturePiranhaPlant2, 0x000003E8U, 0x00000800U); // 0x0300A000
dma_textures(gTexturePiranhaPlant3, 0x000003E8U, 0x00000800U); // 0x0300A800
dma_textures(gTexturePiranhaPlant4, 0x000003E8U, 0x00000800U); // 0x0300B000
dma_textures(gTexturePiranhaPlant5, 0x000003E8U, 0x00000800U); // 0x0300B800
dma_textures(gTexturePiranhaPlant6, 0x000003E8U, 0x00000800U); // 0x0300C000
dma_textures(gTexturePiranhaPlant7, 0x000003E8U, 0x00000800U); // 0x0300C800
dma_textures(gTexturePiranhaPlant8, 0x000003E8U, 0x00000800U); // 0x0300D000
dma_textures(gTexturePiranhaPlant9, 0x000003E8U, 0x00000800U); // 0x0300D800
}
Path2D test_course_path2D[] = {
{ 0, 0},
{ 0, -100},
{ 0, -200},
{ 0, -300},
{ 0, -400},
{ 0, -500},
{ 0, -600},
{ 0, -700},
{ 0, -800},
{ 0, -900},
{ 0, -1000},
{ 0, -1096}, // Main point 1
{ 100, -1090},
{ 200, -1085},
{ 300, -1080},
{ 400, -1075},
{ 500, -1072}, // Curve begins to smooth here
{ 600, -1068},
{ 700, -1065},
{ 800, -1063},
{ 900, -1061},
{ 984, -1060}, // Main point 2
{ 990, -900},
{ 995, -800},
{ 997, -700},
{ 998, -600},
{ 999, -500},
{ 999, -400},
{ 999, -300},
{ 999, -200},
{ 999, -100},
{ 999, 0},
{ 999, 100},
{ 999, 200},
{ 999, 300},
{ 999, 400},
{ 999, 500},
{ 999, 600},
{ 999, 700},
{ 999, 800},
{ 999, 900},
{ 999, 940}, // Main point 3
{ 900, 945},
{ 800, 945},
{ 700, 947},
{ 600, 948},
{ 500, 949},
{ 400, 949},
{ 300, 949},
{ 200, 950},
{ 100, 950},
{ 0, 950}, // Main point 4
// End of path
{ -32768, -32768 } // Terminator
};
void TestCourse::BeginPlay() {
struct ActorSpawnData itemboxes[] = {
{ 200, 1500, 200 , 0},
@@ -270,7 +204,7 @@ void TestCourse::BeginPlay() {
// gWorldInstance.AddActor(new OSeagull(2, pos));
// gWorldInstance.AddActor(new OSeagull(3, pos));
// gWorldInstance.AddObject(new OCheepCheep(FVector(0, 40, 0), OCheepCheep::CheepType::RACE, IPathSpan(0, 10)));
gWorldInstance.AddObject(new OTrophy(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH));
OTrophy::Spawn(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), IRotator(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING));
@@ -282,22 +216,17 @@ void TestCourse::BeginPlay() {
// gWorldInstance.AddActor(new ABowserStatue(FVector(-200, 0, 0), ABowserStatue::Behaviour::CRUSH));
// gWorldInstance.AddObject(new OBoos(10, IPathSpan(0, 5), IPathSpan(18, 23), IPathSpan(25, 50)));
gVehicle2DPathPoint = test_course_path2D;
gVehicle2DPathLength = 53;
D_80162EB0 = spawn_actor_on_surface(test_course_path2D[0].x, 2000.0f, test_course_path2D[0].z);
//OThwomp::Spawn(0, 0, 0, 1.0f, 0, 1, 7);
//gWorldInstance.AddTrain(ATrain::TenderStatus::HAS_TENDER, 5, 2.5f, 0);
//gWorldInstance.AddTrain(ATrain::TenderStatus::HAS_TENDER, 5, 2.5f, 8);
FVector pos2 = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos2, &gTrackPaths[0][25], 25, 4, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos2, &gTrackPaths[0][45], 45, 4, 0.8333333f));
OBombKart::Spawn(0, 25, 4, 0.8333333f);
OBombKart::Spawn(0, 45, 4, 0.8333333f);
// gWorldInstance.AddActor(new AShip(FVector(0, 0, 0), AShip::Skin::SHIP3));
// gWorldInstance.AddObject(new OGrandPrixBalloons(FVector(0, 0, 0)));
// OGrandPrixBalloons::Spawn(FVector(0, 0, 0));
}
void TestCourse::WhatDoesThisDo(Player* player, int8_t playerId) {
+16 -17
View File
@@ -170,7 +170,7 @@ void ToadsTurnpike::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*)LOAD_ASSET_RAW(d_course_toads_turnpike_item_box_spawns));
if (gGamestate != CREDITS_SEQUENCE) {
uint32_t waypoint;
uint32_t pathPoint;
f32 a = ((gCCSelection * 90.0) / 216.0f) + 4.583333333333333;
f32 b = ((gCCSelection * 90.0) / 216.0f) + 2.9166666666666665;
a /= 2; // Normally vehicle logic is only ran every 2 frames. This slows the vehicles down to match.
@@ -190,34 +190,33 @@ void ToadsTurnpike::BeginPlay() {
}
for (size_t i = 0; i < _numTrucks; i++) {
waypoint = CalculateWaypointDistribution(i, _numTrucks, gPathCountByPathIndex[0], 0);
gWorldInstance.AddActor(new ATruck(a, b, &gTrackPaths[0][0], waypoint));
pathPoint = CalculateWaypointDistribution(i, _numTrucks, gPathCountByPathIndex[0], 0);
ATruck::Spawn(a, b, 0, pathPoint, ATruck::SpawnMode::POINT);
}
for (size_t i = 0; i < _numBuses; i++) {
waypoint = CalculateWaypointDistribution(i, _numBuses, gPathCountByPathIndex[0], 75);
gWorldInstance.AddActor(new ABus(a, b, &gTrackPaths[0][0], waypoint));
pathPoint = CalculateWaypointDistribution(i, _numBuses, gPathCountByPathIndex[0], 75);
ABus::Spawn(a, b, 0, pathPoint, ABus::SpawnMode::POINT);
}
for (size_t i = 0; i < _numTankerTrucks; i++) {
waypoint = CalculateWaypointDistribution(i, _numTankerTrucks, gPathCountByPathIndex[0], 50);
gWorldInstance.AddActor(new ATankerTruck(a, b, &gTrackPaths[0][0], waypoint));
pathPoint = CalculateWaypointDistribution(i, _numTankerTrucks, gPathCountByPathIndex[0], 50);
ATankerTruck::Spawn(a, b, 0, pathPoint, ATankerTruck::SpawnMode::POINT);
}
for (size_t i = 0; i < _numCars; i++) {
waypoint = CalculateWaypointDistribution(i, _numCars, gPathCountByPathIndex[0], 25);
gWorldInstance.AddActor(new ACar(a, b, &gTrackPaths[0][0], waypoint));
pathPoint = CalculateWaypointDistribution(i, _numCars, gPathCountByPathIndex[0], 25);
ACar::Spawn(a, b, 0, pathPoint, ACar::SpawnMode::POINT);
}
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 200, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
}
+10 -20
View File
@@ -176,28 +176,18 @@ void WarioStadium::LoadTextures() {
void WarioStadium::BeginPlay() {
spawn_all_item_boxes((struct ActorSpawnData*) LOAD_ASSET_RAW(d_course_wario_stadium_item_box_spawns));
FVector pos = { -131.0f, 83.0f, 286.0f };
pos.x *= gCourseDirection;
gWorldInstance.AddActor(new AWarioSign(pos));
FVector pos2 = { -2353.0f, 72.0f, -1608.0f };
pos2.x *= gCourseDirection;
gWorldInstance.AddActor(new AWarioSign(pos2));
FVector pos3 = { -2622.0f, 79.0f, 739.0f };
pos3.x *= gCourseDirection;
gWorldInstance.AddActor(new AWarioSign(pos3));
AWarioSign::Spawn(FVector(-131.0f, 83.0f, 286.0f), IRotator(0, 0, 0), FVector(0, 0, 0), FVector(1.0f, 1.0f, 1.0f));
AWarioSign::Spawn(FVector(-2353.0f, 72.0f, -1608.0f), IRotator(0, 0, 0), FVector(0, 0, 0), FVector(1.0f, 1.0f, 1.0f));
AWarioSign::Spawn(FVector(-2622.0f, 79.0f, 739.0f), IRotator(0, 0, 0), FVector(0, 0, 0), FVector(1.0f, 1.0f, 1.0f));
if (gModeSelection == VERSUS) {
FVector pos = { 0, 0, 0 };
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][50], 50, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][100], 100, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][150], 150, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][200], 200, 1, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][250], 250, 3, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
gWorldInstance.AddObject(new OBombKart(pos, &gTrackPaths[0][0], 0, 0, 0.8333333f));
OBombKart::Spawn(0, 50, 3, 0.8333333f);
OBombKart::Spawn(0, 100, 1, 0.8333333f);
OBombKart::Spawn(0, 150, 3, 0.8333333f);
OBombKart::Spawn(0, 200, 1, 0.8333333f);
OBombKart::Spawn(0, 250, 3, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
OBombKart::Spawn(0, 0, 0, 0.8333333f);
}
}
+26 -33
View File
@@ -160,26 +160,26 @@ void YoshiValley::BeginPlay() {
if (gGamestate != CREDITS_SEQUENCE) {
//! @bug Skip spawning in credits due to animation crash for now
gWorldInstance.AddObject(new OFlagpole(FVector(-902, 70, -1406), 0x3800));
gWorldInstance.AddObject(new OFlagpole(FVector(-948, 70, -1533), 0x3800));
gWorldInstance.AddObject(new OFlagpole(FVector(-2170, 0, 723), 0x400));
gWorldInstance.AddObject(new OFlagpole(FVector(-2193, 0, 761), 0x400));
OFlagpole::Spawn(FVector(-902, 70, -1406), 0x3800);
OFlagpole::Spawn(FVector(-948, 70, -1533), 0x3800);
OFlagpole::Spawn(FVector(-2170, 0, 723), 0x400);
OFlagpole::Spawn(FVector(-2193, 0, 761), 0x400);
gWorldInstance.AddObject(new OHedgehog(FVector(-1683, -80, -88), FVector2D(-1650, -114), 9));
gWorldInstance.AddObject(new OHedgehog(FVector(-1636, -93, -147), FVector2D(-1661, -151), 9));
gWorldInstance.AddObject(new OHedgehog(FVector(-1628, -86, -108), FVector2D(-1666, -58), 9));
gWorldInstance.AddObject(new OHedgehog(FVector(-1676, -69, -30), FVector2D(-1651, -26), 9));
gWorldInstance.AddObject(new OHedgehog(FVector(-1227, -27, -989), FVector2D(-1194, -999), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1261, -41, -880), FVector2D(-1213, -864), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1342, -60, -830), FVector2D(-1249, -927), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1429, -78, -849), FVector2D(-1347, -866), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1492, -94, -774), FVector2D(-1427, -891), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1453, -87, -784), FVector2D(-1509, -809), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1488, 89, -852), FVector2D(-1464, -822), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-1301, 47, -904), FVector2D(-1537, -854), 26));
gWorldInstance.AddObject(new OHedgehog(FVector(-2587, 56, -259), FVector2D(-2624, -241), 28));
gWorldInstance.AddObject(new OHedgehog(FVector(-2493, 94, -454), FVector2D(-2505, -397), 28));
gWorldInstance.AddObject(new OHedgehog(FVector(-2477, 3, -57), FVector2D(-2539, -66), 28));
OHedgehog::Spawn(FVector(-1683, -80, -88), FVector2D(-1650, -114), 9);
OHedgehog::Spawn(FVector(-1636, -93, -147), FVector2D(-1661, -151), 9);
OHedgehog::Spawn(FVector(-1628, -86, -108), FVector2D(-1666, -58), 9);
OHedgehog::Spawn(FVector(-1676, -69, -30), FVector2D(-1651, -26), 9);
OHedgehog::Spawn(FVector(-1227, -27, -989), FVector2D(-1194, -999), 26);
OHedgehog::Spawn(FVector(-1261, -41, -880), FVector2D(-1213, -864), 26);
OHedgehog::Spawn(FVector(-1342, -60, -830), FVector2D(-1249, -927), 26);
OHedgehog::Spawn(FVector(-1429, -78, -849), FVector2D(-1347, -866), 26);
OHedgehog::Spawn(FVector(-1492, -94, -774), FVector2D(-1427, -891), 26);
OHedgehog::Spawn(FVector(-1453, -87, -784), FVector2D(-1509, -809), 26);
OHedgehog::Spawn(FVector(-1488, 89, -852), FVector2D(-1464, -822), 26);
OHedgehog::Spawn(FVector(-1301, 47, -904), FVector2D(-1537, -854), 26);
OHedgehog::Spawn(FVector(-2587, 56, -259), FVector2D(-2624, -241), 28);
OHedgehog::Spawn(FVector(-2493, 94, -454), FVector2D(-2505, -397), 28);
OHedgehog::Spawn(FVector(-2477, 3, -57), FVector2D(-2539, -66), 28);
}
if (gModeSelection == VERSUS) {
@@ -187,20 +187,13 @@ void YoshiValley::BeginPlay() {
// the original data has values here.
// Note that the Y height is calculated automatically to place the kart on the surface
FVector pos = { -1533, 0, -682 };
gWorldInstance.AddObject(new OBombKart(pos, NULL, 0, 0, 0.8333333f));
FVector pos2 = { -1565, 0, -619 };
gWorldInstance.AddObject(new OBombKart(pos2, NULL, 10, 0, 0.8333333f));
FVector pos3 = { -1529, 0, -579 };
gWorldInstance.AddObject(new OBombKart(pos3, NULL, 20, 0, 0.8333333f));
FVector pos4 = { -1588, 0, -534 };
gWorldInstance.AddObject(new OBombKart(pos4, NULL, 30, 0, 0.8333333f));
FVector pos5 = { -1598, 0, -207 };
gWorldInstance.AddObject(new OBombKart(pos5, NULL, 40, 0, 0.8333333f));
FVector pos6 = { -1646, 0, -147 };
gWorldInstance.AddObject(new OBombKart(pos6, NULL, 50, 0, 0.8333333f));
FVector pos7 = { -2532, 0, -445 };
gWorldInstance.AddObject(new OBombKart(pos7, NULL, 60, 0, 0.8333333f));
OBombKart::Spawn(FVector(-1533, 0, -682), 0, 0.8333333f);
OBombKart::Spawn(FVector(-1565, 0, -619), 0, 0.8333333f);
OBombKart::Spawn(FVector(-1529, 0, -579), 0, 0.8333333f);
OBombKart::Spawn(FVector(-1588, 0, -534), 0, 0.8333333f);
OBombKart::Spawn(FVector(-1598, 0, -207), 0, 0.8333333f);
OBombKart::Spawn(FVector(-1646, 0, -147), 0, 0.8333333f);
OBombKart::Spawn(FVector(-2532, 0, -445), 0, 0.8333333f);
}
}
+33 -10
View File
@@ -4,13 +4,17 @@
#include <libultra/gbi.h>
#include "Matrix.h"
#include "engine/Actor.h"
#include "engine/objects/Object.h"
#include "engine/editor/GameObject.h"
extern "C" {
#include "main.h"
#include "other_textures.h"
}
namespace Editor {
void GenerateCollisionMesh(GameObject* object, Gfx* model, float scale) {
void GenerateCollisionMesh(std::variant<AActor*, OObject*, GameObject*> object, Gfx* model, float scale) {
int8_t opcode;
uintptr_t lo;
uintptr_t hi;
@@ -19,6 +23,12 @@ namespace Editor {
Vtx* vtx = NULL;
size_t i = 0;
bool run = true;
//! @attention Objects will not be clickable if editor is enabled mid-race.
if (CVarGetInteger("gEditorEnabled", false) == true) {
return;
}
while (run) {
i++;
lo = ptr->words.w0;
@@ -64,8 +74,11 @@ namespace Editor {
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});
std::visit([p1, p2, p3](auto* obj) {
if (obj) {
obj->Triangles.push_back({p1, p2, p3});
}
}, object);
break;
}
case G_TRI1_OTR: {
@@ -82,9 +95,11 @@ namespace Editor {
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});
std::visit([p1, p2, p3](auto* obj) {
if (obj) {
obj->Triangles.push_back({p1, p2, p3});
}
}, object);
break;
}
case G_TRI2: {
@@ -109,8 +124,12 @@ namespace Editor {
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});
std::visit([p1, p2, p3, p4, p5, p6](auto* obj) {
if (obj) {
obj->Triangles.push_back({p1, p2, p3});
obj->Triangles.push_back({p4, p5, p6});
}
}, object);
break;
}
case G_QUAD: {
@@ -128,8 +147,12 @@ namespace Editor {
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});
std::visit([p1, p2, p3, p4](auto* obj) {
if (obj) {
obj->Triangles.push_back({p1, p2, p3});
obj->Triangles.push_back({p1, p3, p4});
}
}, object);
break;
}
case G_ENDDL:
+4 -2
View File
@@ -3,6 +3,8 @@
#include <libultraship/libultraship.h>
#include <libultra/gbi.h>
#include "GameObject.h"
#include "engine/Actor.h"
#include "engine/objects/Object.h"
#include "EditorMath.h"
@@ -18,6 +20,6 @@
#define EDITOR_GFX_GET_OPCODE(var) ((uint32_t) ((var) & 0xFF000000))
namespace Editor {
void GenerateCollisionMesh(GameObject* object, Gfx* model, float scale);
void GenerateCollisionMesh(std::variant<AActor*, OObject*, GameObject*> object, Gfx* model, float scale);
void DebugCollision(GameObject* obj, FVector pos, IRotator rot, FVector scale, const std::vector<Triangle>& triangles);
}
}
+51 -29
View File
@@ -24,9 +24,6 @@ extern "C" {
}
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() {
}
@@ -39,21 +36,35 @@ namespace Editor {
printf("Editor: Loading Editor...\n");
eObjectPicker.Load();
for (auto& object : eGameObjects) {
GenerateCollisionMesh(object, object->Model, 1.0f);
GenerateCollisionMesh(object, (Gfx*)object->Model, 1.0f);
object->Load();
}
printf("Editor: Loading Complete!\n");
}
void Editor::Tick() {
void Editor::GenerateCollision() {
// for (auto& actor : gWorldInstance.Actors) {
// GenerateCollisionMesh(actor, (Gfx*)actor->Model, 1.0f);
// }
}
void Editor::Tick() {
if (CVarGetInteger("gEditorEnabled", 0) == true) {
bEditorEnabled = true;
} else {
bEditorEnabled = false;
gIsEditorPaused = false; // Prevents game being paused with the editor closed.
return;
}
// Set camera
if (CVarGetInteger("gFreecam", 0) == true) {
eCamera = &cameras[CAMERA_FREECAM];
} else {
eCamera = &cameras[0];
}
auto wnd = GameEngine::Instance->context->GetWindow();
static bool wasMouseDown = false;
@@ -63,16 +74,16 @@ namespace Editor {
Ship::Coords mousePos = wnd->GetMousePos();
bool isMouseDown = wnd->GetMouseState(Ship::LUS_MOUSE_BTN_LEFT);
auto it = std::remove_if(eGameObjects.begin(), eGameObjects.end(),
[](auto& object) {
if (*object->DespawnFlag == object->DespawnValue) {
delete object; // Free the pointed-to memory
return true; // Remove the pointer from the vector
}
return false;
});
//auto it = std::remove_if(eGameObjects.begin(), eGameObjects.end(),
// [](auto& object) {
// if (*object->DespawnFlag == object->DespawnValue) {
// delete object; // Free the pointed-to memory
// return true; // Remove the pointer from the vector
// }
// return false;
// });
eGameObjects.erase(it, eGameObjects.end());
//eGameObjects.erase(it, eGameObjects.end());
if (isMouseDown && !wasMouseDown) {
// Mouse just pressed (Pressed state)
@@ -80,7 +91,7 @@ namespace Editor {
isDragging = false;
}
if (isMouseDown) {
if (isMouseDown) {
// Mouse is being held (Held state)
int dx = mousePos.x - mouseStartPos.x;
int dy = mousePos.y - mouseStartPos.y;
@@ -122,15 +133,16 @@ namespace Editor {
}
}
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) {
GameObject* Editor::AddObject(FVector pos, IRotator rot, FVector scale, const char* model, float collScale, GameObject::CollisionType collision, float boundingBoxSize) {
//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);
if (nullptr != model && model[0] != '\0') {
eGameObjects.push_back(new GameObject(pos, rot, scale, model, {}, collision, boundingBoxSize));
GenerateCollisionMesh(eGameObjects.back(), (Gfx*)LOAD_ASSET_RAW(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));
eGameObjects.push_back(new GameObject(pos, rot, scale, model, {}, GameObject::CollisionType::BOUNDING_BOX,
10.0f));
}
return eGameObjects.back();
}
@@ -140,27 +152,37 @@ namespace Editor {
}
void Editor::ClearObjects() {
ResetGizmo();
for (auto& obj : eGameObjects) {
delete obj;
}
eGameObjects.clear();
}
void Editor::DeleteObject() {
Gizmo* gizmo = &eObjectPicker.eGizmo;
// Reset the gizmo
void Editor::ResetGizmo() {
eObjectPicker.eGizmo._selected = static_cast<GameObject*>(nullptr);
eObjectPicker._selected = static_cast<GameObject*>(nullptr);
eObjectPicker.eGizmo.Pos = FVector(0, 0, 0);
eObjectPicker.eGizmo.Enabled = false;
}
if (gizmo->_selected && gizmo->_selected->DespawnFlag) {
*gizmo->_selected->DespawnFlag = gizmo->_selected->DespawnValue;
gizmo->_selected = nullptr;
eObjectPicker._selected = nullptr;
}
void Editor::DeleteObject() {
std::visit([this](auto* obj) {
if (nullptr != obj) {
gEditor.ResetGizmo(); // Unselect the object to prevent crashes
obj->Destroy();
}
}, eObjectPicker.eGizmo._selected);
}
void Editor::ClearMatrixPool() {
EditorMatrix.clear();
}
void Editor::SelectObjectFromSceneExplorer(GameObject* object) {
void Editor::SelectObjectFromSceneExplorer(std::variant<AActor*, OObject*, GameObject*> object) {
eObjectPicker._selected = object;
eObjectPicker.eGizmo.Enabled = true;
eObjectPicker.eGizmo.SetGizmoNoCursor(object);
+9 -2
View File
@@ -5,7 +5,11 @@
#include <libultra/gbi.h>
#include "GameObject.h"
#ifdef __cplusplus
extern "C" {
#include "camera.h"
}
#include "ObjectPicker.h"
namespace Editor {
@@ -22,16 +26,19 @@ public:
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 GenerateCollision();
GameObject* AddObject(FVector pos, IRotator rot, FVector scale, const char* model, float collScale, GameObject::CollisionType collision, float boundingBoxSize);
void AddLight(const char* name, FVector* pos, s8* rot);
void ClearObjects();
void ResetGizmo();
void RemoveObject();
void SelectObjectFromSceneExplorer(GameObject* object);
void SelectObjectFromSceneExplorer(std::variant<AActor*, OObject*, GameObject*> object);
void SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY);
void ClearMatrixPool();
void DeleteObject();
bool bEditorEnabled = false;
Camera* eCamera = &cameras[0];
private:
bool _draw = false;
Vec3f _ray;
+9 -7
View File
@@ -42,12 +42,13 @@ bool IsInGameScreen() {
FVector ScreenRayTrace() {
auto wnd = GameEngine::Instance->context->GetWindow();
Camera* camera = &cameras[0];
Camera* camera = gEditor.eCamera;
Ship::Coords mouse = wnd->GetMousePos();
auto gfx_current_game_window_viewport = GetInterpreter()->mGameWindowViewport;
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();
@@ -285,7 +286,6 @@ std::optional<FVector> QueryHandleIntersection(MtxF mtx, Ray ray, const Triangle
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;
@@ -381,8 +381,9 @@ float CalculateAngle(const FVector& start, const FVector& end) {
}
void SetDirectionFromRotator(IRotator rot, s8 direction[3]) {
rot.yaw += 0xC000; //! @warning dumb hack to align the light properly
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);
float pitch = rot.pitch * (M_PI / 32768.0f);
// Compute unit direction vector
float x = cosf(yaw) * cosf(pitch);
@@ -411,10 +412,11 @@ void SetRotatorFromDirection(FVector direction, IRotator* rot) {
}
FVector GetPositionAheadOfCamera(f32 dist) {
FVector pos = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]);
Camera* camera = gEditor.eCamera;
FVector pos = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
f32 pitch = (cameras[0].rot[2] / 65535.0f) * 360.0f;
f32 yaw = (cameras[0].rot[1] / 65535.0f) * 360.0f;
f32 pitch = (camera->rot[2] / 65535.0f) * 360.0f;
f32 yaw = (camera->rot[1] / 65535.0f) * 360.0f;
// Convert degrees to radians
pitch = pitch * M_PI / 180.0f;
@@ -422,7 +424,7 @@ FVector GetPositionAheadOfCamera(f32 dist) {
// Compute forward vector
FVector forward(
-sinf(yaw), // X
sinf(yaw), // X
-sinf(pitch), // Y
cosf(yaw) // Z (vertical component)
);
+20 -9
View File
@@ -3,8 +3,7 @@
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;
GameObject::GameObject(FVector pos, IRotator rot, FVector scale, const char* model, std::vector<Triangle> triangles, CollisionType collision, float boundingBoxSize) {
Pos = pos;
Rot = rot;
Scale = scale;
@@ -12,13 +11,6 @@ namespace Editor {
Triangles = triangles;
Collision = collision;
BoundingBoxSize = boundingBoxSize;
DespawnFlag = despawnFlag;
DespawnValue = despawnValue;
}
GameObject::GameObject(FVector* pos, Vec3s* rot) {
//Pos = pos;
//Rot = rot;
}
GameObject::GameObject() {};
@@ -27,4 +19,23 @@ namespace Editor {
void GameObject::Tick(){};
FVector GameObject::GetLocation() const {
return Pos;
};
IRotator GameObject::GetRotation() const {
return Rot;
}
FVector GameObject::GetScale() const {
return Scale;
}
void GameObject::Translate(FVector pos) {
Pos = pos;
};
void GameObject::Rotate(IRotator rot) {
Rot = rot;
};
void GameObject::SetScale(FVector scale) {
Scale = scale;
};
} // namespace Editor
+21 -9
View File
@@ -6,6 +6,9 @@
#include "../CoreMath.h"
#include "EditorMath.h"
#include <vector>
#include "engine/SpawnParams.h"
#include "src/port/ui/DefaultProperties.h"
extern "C" {
#include "common_structs.h"
@@ -22,23 +25,32 @@ public:
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(FVector pos, IRotator rot, FVector scale, const char* model, std::vector<Triangle> triangles, CollisionType collision, float boundingBoxSize);
GameObject();
virtual void Tick();
virtual void Draw();
virtual void Load() {};
FVector GetLocation() const;
IRotator GetRotation() const;
FVector GetScale() const;
void Translate(FVector pos);
void Rotate(IRotator rot);
void SetScale(FVector scale);
void Destroy() {};
const char* Name;
FVector* Pos;
IRotator* Rot;
FVector* Scale;
Gfx* Model;
const char* ResourceName;
FVector SpawnPos = {0.0f, 0.0f, 0.0f};
IRotator SpawnRot = {0, 0, 0};
FVector SpawnScale = {1.0f, 1.0f, 1.0f};
float Speed;
FVector Pos;
IRotator Rot;
FVector Scale;
const char* Model = "";
std::vector<Triangle> Triangles;
CollisionType Collision;
float BoundingBoxSize;
int32_t* DespawnFlag;
int32_t DespawnValue;
virtual void DrawEditorProperties() { DrawDefaultEditorProperties(); };
};
}
+213 -130
View File
@@ -10,6 +10,10 @@
#include "port/Engine.h"
#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h>
#include <window/Window.h>
#include "engine/Matrix.h"
#include "engine/Actor.h"
#include "engine/objects/Object.h"
#include "engine/editor/GameObject.h"
#include "engine/actors/Ship.h"
@@ -29,34 +33,34 @@ namespace Editor {
void Gizmo::Load() {
/* Translate handle collision */
RedCollision.Pos = &Pos;
RedCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_red";
RedCollision.Pos = Pos;
RedCollision.Model = "__OTR__editor/gizmo/translate_handle_red";
GreenCollision.Pos = &Pos;
GreenCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_green";
GreenCollision.Pos = Pos;
GreenCollision.Model = "__OTR__editor/gizmo/translate_handle_green";
BlueCollision.Pos = &Pos;
BlueCollision.Model = (Gfx*)"__OTR__editor/gizmo/translate_handle_blue";
BlueCollision.Pos = Pos;
BlueCollision.Model = "__OTR__editor/gizmo/translate_handle_blue";
/* Rotate handle collision */
RedRotateCollision.Pos = &Pos;
RedRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_red";
RedRotateCollision.Pos = Pos;
RedRotateCollision.Model = "__OTR__editor/gizmo/rot_handle_red";
GreenRotateCollision.Pos = &Pos;
GreenRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_green";
GreenRotateCollision.Pos = Pos;
GreenRotateCollision.Model = "__OTR__editor/gizmo/rot_handle_green";
BlueRotateCollision.Pos = &Pos;
BlueRotateCollision.Model = (Gfx*)"__OTR__editor/gizmo/rot_handle_blue";
BlueRotateCollision.Pos = Pos;
BlueRotateCollision.Model = "__OTR__editor/gizmo/rot_handle_blue";
/* Scale handle collision */
RedScaleCollision.Pos = &Pos;
RedScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_red";
RedScaleCollision.Pos = Pos;
RedScaleCollision.Model = "__OTR__editor/gizmo/scale_handle_red";
GreenScaleCollision.Pos = &Pos;
GreenScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_green";
GreenScaleCollision.Pos = Pos;
GreenScaleCollision.Model = "__OTR__editor/gizmo/scale_handle_green";
BlueScaleCollision.Pos = &Pos;
BlueScaleCollision.Model = (Gfx*)"__OTR__editor/gizmo/scale_handle_blue";
BlueScaleCollision.Pos = Pos;
BlueScaleCollision.Model = "__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);
@@ -89,178 +93,256 @@ void Gizmo::Tick() {
}
// Makes the gizmo visible
void Gizmo::SetGizmo(GameObject* object, Ray ray) {
_selected = object;
void Gizmo::SetGizmo(const std::variant<AActor*, OObject*, GameObject*>& object, Ray ray) {
_ray = ray.Direction;
Pos = FVector(
object->Pos->x,
object->Pos->y,
object->Pos->z
);
std::visit([this](auto* obj) {
_selected = obj;
this->Pos = obj->GetLocation();
}, object);
}
void Gizmo::SetGizmoNoCursor(GameObject* object) {
_selected = object;
Pos = FVector(
object->Pos->x,
object->Pos->y,
object->Pos->z
);
void Gizmo::SetGizmoNoCursor(const std::variant<AActor*, OObject*, GameObject*>& object) {
std::visit([this](auto* obj) {
_selected = obj;
Pos = obj->GetLocation();
}, object);
}
void Gizmo::Translate() {
static float length = 180.0f; // Default value
// Prevent nullptr exceptions
if (_selected == NULL || _selected->Pos == NULL) {
return;
}
std::visit([this](auto* obj) {
Camera* camera = gEditor.eCamera;
float x, y, z = 0;
if (nullptr == obj) {
return;
}
const FVector location = obj->GetLocation();
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)
pow(location.x - camera->pos[0], 2) +
pow(location.y - camera->pos[1], 2) +
pow(location.z - camera->pos[2], 2)
);
switch(SelectedHandle) {
switch(this->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);
y = SnapToSurface(location);
} else {
y = ((camera->pos[1] + _ray.y * PickDistance) + _cursorOffset.y);
}
obj->Translate(
FVector(
((camera->pos[0] + _ray.x * PickDistance) + _cursorOffset.x),
y,
((camera->pos[2] + _ray.z * PickDistance) + _cursorOffset.z)
)
);
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);
y = SnapToSurface(location);
} else {
y = location.y; // Preserve Y
}
obj->Translate(
FVector(
((camera->pos[0] + _ray.x * length) + _cursorOffset.x),
y,
location.z // Preserve Z
)
);
break;
case GizmoHandle::Y_Axis:
_selected->Pos->y = (cameras[0].pos[1] + _ray.y * length) + _cursorOffset.y;
obj->Translate(
FVector(
location.x, // Preserve X
((camera->pos[1] + _ray.y * length) + _cursorOffset.y),
location.z // Preserve Z
)
);
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);
y = SnapToSurface(location);
} else {
y = location.y; // Preserve Y
}
obj->Translate(
FVector(
location.x, // Preserve X
y,
((camera->pos[2] + _ray.z * length) + _cursorOffset.z)
)
);
break;
}
FVector newLoc = obj->GetLocation();
x = newLoc.x;
y = newLoc.y;
z = newLoc.z;
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);
#define EDITOR_CLAMP(value, min, max) ((value) < (min) ? min : (value) > (max) ? max : value)
x = EDITOR_CLAMP(newLoc.x, dimensions.MinX, dimensions.MaxX);
y = EDITOR_CLAMP(newLoc.y, dimensions.MinY, dimensions.MaxY);
z = EDITOR_CLAMP(newLoc.z, dimensions.MinZ, dimensions.MaxZ);
obj->Translate(FVector(x, y, z));
#undef EDITOR_CLAMP
}
Pos = FVector(
_selected->Pos->x,
_selected->Pos->y,
_selected->Pos->z
);
}
// Update the gizmo position
Pos = FVector(x, y, z);
// Pass the _selected object into this lambda function
}, _selected);
}
f32 Gizmo::SnapToSurface(FVector* pos) {
f32 Gizmo::SnapToSurface(const FVector pos) {
float y;
y = spawn_actor_on_surface(pos->x, 2000.0f, pos->z);
y = spawn_actor_on_surface(pos.x, 2000.0f, pos.z);
if (y == 3000.0f || y == -3000.0f) {
y = pos->y;
y = pos.y;
}
return y;
}
void Gizmo::Rotate() {
FVector cam = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]);
std::visit([this](auto* obj) {
Camera* camera = gEditor.eCamera;
FVector cam = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
IRotator rot;
if (_selected == nullptr || _selected->Rot == nullptr) {
return;
}
if (nullptr == obj) {
return;
}
// Store initial scale at the beginning of the drag
if (ManipulationStart) {
ManipulationStart = false;
InitialRotation = *_selected->Rot; // Store initial rotation
}
// Store initial scale at the beginning of the drag
if (ManipulationStart) {
ManipulationStart = false;
InitialRotation = obj->GetRotation(); // Store initial rotation
}
// Initial click position
FVector clickPos = *_selected->Pos - _cursorOffset;
// Initial click position
FVector clickPos = obj->GetLocation() - _cursorOffset;
// Calculate difference
FVector diff = (cam + _ray * PickDistance) - clickPos;
// 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;
// Set rotation sensitivity
diff = diff * 100.0f;
switch (SelectedHandle) {
case GizmoHandle::X_Axis:
rot.Set(
(uint16_t)(InitialRotation.pitch + diff.x),
InitialRotation.yaw,
InitialRotation.roll
);
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;
}
case GizmoHandle::Y_Axis:
rot.Set(
InitialRotation.pitch,
(uint16_t)(InitialRotation.yaw + diff.y),
InitialRotation.roll
);
break;
case GizmoHandle::Z_Axis:
rot.Set(
InitialRotation.pitch,
InitialRotation.yaw,
(uint16_t)(InitialRotation.roll + diff.z)
);
break;
}
obj->Rotate(rot);
// Pass the _selected object into this lambda function
}, _selected);
}
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;
}
std::visit([this](auto* obj) {
Camera* camera = gEditor.eCamera;
FVector cam = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
if (nullptr == obj) {
return;
}
// Store initial scale at the beginning of the drag
if (ManipulationStart) {
ManipulationStart = false;
InitialScale = *_selected->Scale;
}
// Store initial scale at the beginning of the drag
if (ManipulationStart) {
ManipulationStart = false;
InitialScale = obj->GetScale();
}
// Initial click position
FVector clickPos = *_selected->Pos - _cursorOffset;
FVector scale = obj->GetScale();
// Calculate difference
FVector diff = (cam + _ray * PickDistance) - clickPos;
// Initial click position
FVector clickPos = obj->GetLocation() - _cursorOffset;
// Lower scaling sensitivity
diff = diff * 0.01f;
// Calculate difference
FVector diff = (cam + _ray * PickDistance) - clickPos;
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;
}
// Lower scaling sensitivity
diff = diff * 0.01f;
switch (SelectedHandle) {
case GizmoHandle::X_Axis:
obj->SetScale(
FVector(
(InitialScale.x + -diff.x),
scale.y,
scale.z
)
);
break;
case GizmoHandle::Y_Axis:
obj->SetScale(
FVector(
scale.x,
(InitialScale.y + diff.y),
scale.z
)
);
break;
case GizmoHandle::Z_Axis:
obj->SetScale(
FVector(
scale.x,
scale.y,
(InitialScale.z + -diff.z)
)
);
break;
case GizmoHandle::All_Axis:
float uniformScale = (diff.x - diff.y - diff.z) / 3.0f;
uniformScale *= 1.8; // Increased sensitivity
obj->SetScale(
FVector(
uniformScale,
uniformScale,
uniformScale
)
);
break;
}
// Pass the _selected object into this lambda function
}, _selected);
}
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(&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);
}
@@ -316,11 +398,12 @@ void Gizmo::DrawHandles() {
Editor_AddMatrix(mainMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (center) {
Camera* camera = gEditor.eCamera;
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]);
FVector cameraDir = FVector(Pos.x - camera->pos[0], Pos.y - camera->pos[1], Pos.z - camera->pos[2]);
cameraDir = cameraDir.Normalize();
IRotator centerRot;
+7 -4
View File
@@ -4,6 +4,9 @@
#include <libultra/gbi.h>
#include "Collision.h"
#include "GameObject.h"
#include "engine/Actor.h"
#include "engine/objects/Object.h"
#include <variant>
namespace Editor {
@@ -28,13 +31,13 @@ public:
void Draw();
void Load();
void SetGizmo(GameObject* object, Ray ray);
void SetGizmoNoCursor(GameObject* object); // Used for scene explorer selection
void SetGizmo(const std::variant<AActor*, OObject*, GameObject*>& object, Ray ray);
void SetGizmoNoCursor(const std::variant<AActor*, OObject*, GameObject*>& object); // Used for scene explorer selection
void Translate();
void Rotate();
void Scale();
void DrawHandles();
f32 SnapToSurface(FVector* pos);
f32 SnapToSurface(FVector pos);
struct TrackDimensions {
s16 MinX = -10000;
@@ -78,7 +81,7 @@ public:
float HandleSize = 2.0f;
FVector _ray;
GameObject* _selected = nullptr;
std::variant<AActor*, OObject*, GameObject*> _selected;
private:
bool _draw = false;
};
-2
View File
@@ -5,8 +5,6 @@
namespace Editor {
Handles::Handles() {
Pos = &pos;
Rot = &rot;
}
void Handles::Load() {
-2
View File
@@ -13,7 +13,5 @@ namespace Editor {
virtual void Draw() override;
virtual void Load() override;
FVector pos;
IRotator rot;
};
}
+16 -13
View File
@@ -4,6 +4,7 @@
#include "../CoreMath.h"
#include <libultra/types.h>
#include "../World.h"
#include "engine/Matrix.h"
#include "Light.h"
#include "port/Engine.h"
@@ -30,14 +31,16 @@ namespace Editor {
size_t LightObject::NumLights = 0;
LightObject::LightObject(const char* name, FVector* pos, s8* direction) : GameObject(nullptr, nullptr) {
LightObject::LightObject(const char* name, FVector* pos, s8* direction) {
Name = name;
Pos = &LightPos;
Rot = &LightRot;
Scale = &LightScale;
ResourceName = "editor:light";
DespawnFlag = &_despawnFlag;
DespawnValue = -1;
Pos = FVector(0, 100, 0);
Rot = IRotator(0, 0, 0);
Scale = FVector(0.1, 0.1, 0.1);
SpawnPos = Pos;
SpawnRot = Rot;
Direction = direction;
@@ -51,9 +54,10 @@ size_t LightObject::NumLights = 0;
}
void LightObject::Tick() {
SetDirectionFromRotator(*Rot, Direction);
SetDirectionFromRotator(Rot, Direction);
}
void LightObject::Draw() {
Camera* camera = gEditor.eCamera;
Mat4 mtx_sun;
Editor_MatrixIdentity(mtx_sun);
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
@@ -61,23 +65,22 @@ size_t LightObject::NumLights = 0;
// 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]);
FVector cameraDir = FVector(Pos.x - camera->pos[0], Pos.y - camera->pos[1], Pos.z - camera->pos[2]);
cameraDir = cameraDir.Normalize();
IRotator centerRot;
SetRotatorFromDirection(cameraDir, &centerRot);
// Account for object not facing the correct direction when exported
// The sun was exported facing the wrong direction.
// Thus, force the sun texture to face the camera.
centerRot.yaw += 0x4000;
ApplyMatrixTransformations(mtx_sun, LightPos, centerRot, LightScale);
ApplyMatrixTransformations(mtx_sun, Pos, centerRot, Scale);
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);
ApplyMatrixTransformations(mtx_arrow, Pos, Rot, Scale);
Editor_AddMatrix(mtx_arrow, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, (Gfx*)"__OTR__editor/light/sun_arrow");
}
-5
View File
@@ -3,7 +3,6 @@
#include <libultraship/libultraship.h>
#include <libultra/gbi.h>
#include "Collision.h"
#include "Gizmo.h"
#include "GameObject.h"
namespace Editor {
@@ -17,11 +16,7 @@ public:
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,
+133 -45
View File
@@ -2,7 +2,9 @@
#include <libultra/gbi.h>
#include "../CoreMath.h"
#include <libultra/types.h>
#include "../World.h"
#include "engine/World.h"
#include "engine/Actor.h"
#include "engine/objects/Object.h"
#include "ObjectPicker.h"
#include "port/Engine.h"
@@ -33,8 +35,9 @@ void ObjectPicker::Tick() {
}
void ObjectPicker::SelectObject(std::vector<GameObject*> objects) {
Camera* camera = gEditor.eCamera;
Ray ray;
ray.Origin = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]);
ray.Origin = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
// This allows selection of objects in the scene explorer.
// Otherwise this would still run when selecting buttons in editor windows.
@@ -43,22 +46,23 @@ void ObjectPicker::SelectObject(std::vector<GameObject*> objects) {
ObjectPicker::FindObject(ray, objects);
if (_selected != nullptr) {
eGizmo.SetGizmo(_selected, ray);
eGizmo.Enabled = true;
} else {
//eGizmo.Disable();
eGizmo.Enabled = false;
eGizmo._selected = nullptr;
}
std::visit([this, ray](auto* obj) {
if (obj) {
eGizmo.SetGizmo(_selected, ray);
eGizmo.Enabled = true;
} else {
eGizmo.Enabled = false;
_selected = static_cast<GameObject*>(nullptr);
}
}, _selected);
}
}
void ObjectPicker::DragHandle() {
Camera* camera = gEditor.eCamera;
Ray ray;
ray.Origin = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]);
ray.Origin = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
ray.Direction = ScreenRayTrace();
// Skip if a drag is already in progress
if (eGizmo.SelectedHandle != Gizmo::GizmoHandle::None) {
eGizmo._ray = ray.Direction;
@@ -116,7 +120,6 @@ void ObjectPicker::DragHandle() {
break;
}
if (closestHandle != Gizmo::GizmoHandle::None && closestClickPos.has_value()) {
eGizmo.SelectedHandle = closestHandle;
eGizmo._ray = ray.Direction;
@@ -126,32 +129,68 @@ void ObjectPicker::DragHandle() {
}
void ObjectPicker::Draw() {
if (_selected != NULL) {
eGizmo.Draw();
}
std::visit([](auto* obj) {
if (obj) {
gEditor.eObjectPicker.eGizmo.Draw();
}
}, _selected);
if (Debug) {
Camera* camera = gEditor.eCamera;
Mat4 CursorMtx;
IRotator rot = IRotator(0,0,0);
FVector scale = FVector(0.1, 0.1, 0.1);
FVector scale = FVector(1, 1, 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);
float x = (camera->pos[0] + ray.x * 800);
float y = (camera->pos[1] + ray.y * 800);
float z = (camera->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");
gSPDisplayList(gDisplayListHead++, (Gfx*)"__OTR__gizmo/gizmo_center_button");
}
}
void ObjectPicker::FindObject(Ray ray, std::vector<GameObject*> objects) {
bool found = false;
GameObject* closestObject = nullptr;
float closestDistance = FLT_MAX;
float distance = FLT_MAX;
std::variant<AActor*, OObject*, GameObject*> object;
for (auto& object : objects) {
_selected = static_cast<GameObject*>(nullptr);
auto [hitActor, hitActorDist] = ObjectPicker::CheckAActorRay(ray);
if (hitActor) {
object = hitActor;
distance = hitActorDist;
}
// OObjects
auto [hitObject, hitObjectDist] = ObjectPicker::CheckOObjectRay(ray);
if (hitObject && (hitObjectDist < distance)) {
object = hitObject;
distance = hitObjectDist;
}
// Editor objects
auto [hitEditorObject, hitEditorObjectDist] = ObjectPicker::CheckEditorObjectRay(ray);
if (hitEditorObject && (hitEditorObjectDist < distance)) {
object = hitEditorObject;
distance = hitEditorObjectDist;
}
// Set _selected from object variant
_selected = object;
std::visit([this](auto* obj) {
if (obj) {
}
}, object);
}
std::pair<GameObject*, float> ObjectPicker::CheckEditorObjectRay(Ray ray) {
GameObject* hitObject = nullptr;
float hitDistance = FLT_MAX;
for (auto& object : gEditor.eGameObjects) {
float boundingBox = object->BoundingBoxSize;
if (boundingBox == 0.0f) {
boundingBox = 2.0f;
@@ -161,11 +200,10 @@ void ObjectPicker::FindObject(Ray ray, std::vector<GameObject*> objects) {
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");
if (IntersectRayTriangleAndTransform(ray, object->Pos, tri, t)) {
if (t < hitDistance) {
hitDistance = t;
hitObject = object;
}
}
}
@@ -173,18 +211,18 @@ void ObjectPicker::FindObject(Ray ray, std::vector<GameObject*> objects) {
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 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 };
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;
if (t < hitDistance) {
hitDistance = t;
hitObject = object;
printf("FOUND BOUNDING BOX OBJECT\n");
}
break;
@@ -196,12 +234,62 @@ void ObjectPicker::FindObject(Ray ray, std::vector<GameObject*> objects) {
break;
}
}
if (closestObject != nullptr) {
_selected = closestObject;
// printf("FOUND COLLISION %d\n", type);
} else {
// printf("NO COLLISION\n");
_selected = nullptr;
return std::pair(hitObject, hitDistance);
}
std::pair<OObject*, float> ObjectPicker::CheckOObjectRay(Ray ray) {
OObject* hitObject = nullptr;
float hitDistance = FLT_MAX;
return std::pair(hitObject, hitDistance);
}
std::pair<AActor*, float> ObjectPicker::CheckAActorRay(Ray ray) {
AActor* hitActor = nullptr;
float hitDistance = FLT_MAX;
for (auto actor : gWorldInstance.Actors) {
if ((actor->bPendingDestroy) && (!actor->IsMod())) {
continue;
}
float boundingBox = actor->BoundingBoxSize;
if (boundingBox == 0.0f) {
boundingBox = 2.0f;
}
if (actor->Triangles.size()) {
for (const auto& tri : actor->Triangles) {
float t;
if (IntersectRayTriangleAndTransform(ray, FVector(actor->Pos[0], actor->Pos[1], actor->Pos[2]), tri, t)) {
if (t < hitDistance) {
hitDistance = t;
hitActor = static_cast<AActor*>(actor);
}
}
}
} else {
float max = 1.2f;
float min = -1.2f;
Vec3f boxMin = { actor->Pos[0] + boundingBox * min,
actor->Pos[1] + boundingBox * min,
actor->Pos[2] + boundingBox * min };
Vec3f boxMax = { actor->Pos[0] + boundingBox * max,
actor->Pos[1] + boundingBox * max,
actor->Pos[2] + boundingBox * max };
float t;
if (QueryCollisionRayActor(&ray.Origin.x, &ray.Direction.x, boxMin, boxMax, &t)) {
if (t < hitDistance) {
hitDistance = t;
hitActor = static_cast<AActor*>(actor);
}
}
}
}
return std::pair(hitActor, hitDistance);
}
}
+6 -1
View File
@@ -5,6 +5,7 @@
#include "Collision.h"
#include "Gizmo.h"
#include "GameObject.h"
#include "engine/Matrix.h"
namespace Editor {
class ObjectPicker {
@@ -16,13 +17,17 @@ namespace Editor {
void Load();
void Tick();
Gizmo eGizmo;
GameObject* _selected;
std::variant<AActor*, OObject*, GameObject*> _selected;
private:
bool _draw = false;
GameObject* _lastSelected;
s32 Inverse(MtxF* src, MtxF* dest);
void Copy(MtxF* src, MtxF* dest);
void Clear(MtxF* mf);
// actor, distance from camera
std::pair<AActor*, float> CheckAActorRay(Ray ray);
std::pair<OObject*, float> CheckOObjectRay(Ray ray);
std::pair<GameObject*, float> CheckEditorObjectRay(Ray ray);
bool Debug = false;
};
}
+116 -26
View File
@@ -1,11 +1,12 @@
#include "SceneManager.h"
#include "port/Game.h"
#include "CoreMath.h"
#include "engine/CoreMath.h"
#include "World.h"
#include "GameObject.h"
#include <iostream>
#include <fstream>
#include <optional> // Must be before json.hpp
#include <nlohmann/json.hpp>
#include "port/Engine.h"
#include <libultraship/src/resource/type/Json.h>
@@ -13,6 +14,19 @@
#include <libultraship/src/resource/File.h>
#include "port/resource/type/ResourceType.h"
#include "engine/vehicles/Train.h"
#include "engine/objects/Object.h"
#include "engine/objects/Thwomp.h"
#include "engine/objects/Snowman.h"
#include <iostream>
extern "C" {
#include "common_structs.h"
#include "actors.h"
#include "actor_types.h"
}
namespace Editor {
std::shared_ptr<Ship::Archive> CurrentArchive;
@@ -33,45 +47,42 @@ namespace Editor {
}
data["StaticMeshActors"] = staticMesh;
// nlohmann::json actors;
nlohmann::json actors;
// for (const auto& actor : gWorldInstance.Actors) {
// actors.push_back(actor->to_json());
// }
// data["Actors"] = actors;
SaveActors(actors);
// nlohmann::json objects;
// for (const auto& object : gWorldInstance.Objects) {
// objects.push_back(object->to_json());
// }
// data["Objects"] = objects;
data["Actors"] = actors;
try {
auto dat = data.dump();
auto dat = data.dump(2);
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());
// Tell the cache this needs to be reloaded
auto resource = GameEngine::Instance->context->GetResourceManager()->GetCachedResource(SceneFile);
if (resource) {
resource->Dirty();
}
} else {
printf("Failed to write scene file!\n");
printf("[SceneManager::SaveLevel] Failed to write scene file!\n");
}
} catch (const nlohmann::json::exception& e) {
printf("SceneManager::SaveLevel():\n JSON error during dump: %s\n", e.what());
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 && (course != nullptr)) {
/** Do not use gWorldInstance.CurrentCourse during loading! The current track is not guaranteed! **/
void LoadLevel(Course* course, std::string sceneFile) {
SceneFile = sceneFile;
if ((nullptr != course) && (nullptr != course->RootArchive)) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = archive;
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
@@ -97,6 +108,20 @@ namespace Editor {
std::cerr << "Props data not found in the JSON file!" << std::endl;
}
/** Populate Track SpawnParams for spawning actors **/
if (data.contains("Actors")) {
auto & actorsJson = data["Actors"];
course->SpawnList.clear();
for (const auto& actor : actorsJson) {
SpawnParams params;
params.from_json(actor); //<SpawnParams>();
if (!params.Name.empty()) {
course->SpawnList.push_back(params);
}
}
SPDLOG_INFO("[SceneManager] Loaded Scene File!");
}
// Load the Actors (deserialize them)
if (data.contains("StaticMeshActors")) {
auto& actorsJson = data["StaticMeshActors"];
@@ -106,7 +131,7 @@ namespace Editor {
Load_AddStaticMeshActor(actorJson);
}
} else {
std::cerr << "Actors data not found in the JSON file!" << std::endl;
SPDLOG_INFO("[SceneManager::LoadLevel] [scene.json] This track contains no StaticMeshActors!");
}
}
}
@@ -118,8 +143,6 @@ namespace Editor {
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) {
@@ -127,11 +150,11 @@ namespace Editor {
SceneFile = sceneFile;
}
void LoadMinimap(std::shared_ptr<Ship::Archive> archive, Course* course, std::string filePath) {
void LoadMinimap(Course* course, std::string filePath) {
printf("LOADING MINIMAP %s\n", filePath.c_str());
if (archive) {
if ((nullptr != course) && (nullptr != course->RootArchive)) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = archive;
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap);
@@ -153,4 +176,71 @@ namespace Editor {
}
}
}
void SaveActors(nlohmann::json& actorList) {
for (const auto& actor : gWorldInstance.Actors) {
SpawnParams params{};
bool alreadyProcessed = false;
// Only some actors are supported for saving.
// Bananas and stuff don't make sense to be saved.
switch(actor->Type) {
case ACTOR_ITEM_BOX:
case ACTOR_FAKE_ITEM_BOX:
case ACTOR_TREE_MARIO_RACEWAY:
case ACTOR_TREE_YOSHI_VALLEY:
case ACTOR_TREE_ROYAL_RACEWAY:
case ACTOR_TREE_MOO_MOO_FARM:
case ACTOR_PALM_TREE:
case ACTOR_TREE_LUIGI_RACEWAY: // A plant?
case ACTOR_UNKNOWN_0x1B:
case ACTOR_TREE_PEACH_CASTLE:
case ACTOR_TREE_FRAPPE_SNOWLAND:
case ACTOR_CACTUS1_KALAMARI_DESERT:
case ACTOR_CACTUS2_KALAMARI_DESERT:
case ACTOR_CACTUS3_KALAMARI_DESERT:
case ACTOR_BUSH_BOWSERS_CASTLE:
params.Name = get_actor_resource_location_name(actor->Type);
params.Location = FVector(actor->Pos[0], actor->Pos[1], actor->Pos[2]);
if (!params.Name.empty()) {
actorList.push_back(params.to_json());
}
alreadyProcessed = true;
break;
case ACTOR_PIRANHA_PLANT:
params.Name = get_actor_resource_location_name(actor->Type);
params.Location = FVector(actor->Pos[0], actor->Pos[1], actor->Pos[2]);
// params.Type = // Need this to use royal raceway version
actorList.push_back(params.to_json());
alreadyProcessed = true;
break;
case ACTOR_YOSHI_EGG:
params.Name = get_actor_resource_location_name(actor->Type);
params.Location = FVector(actor->Velocity[0], actor->Pos[1], actor->Velocity[2]); // Velocity is pathCenter
if (!params.Name.empty()) {
actorList.push_back(params.to_json());
}
alreadyProcessed = true;
break;
}
if (!alreadyProcessed) {
actor->SetSpawnParams(params);
if (!params.Name.empty()) {
actorList.push_back(params.to_json());
}
}
}
for (const auto& object : gWorldInstance.Objects) {
SpawnParams params;
object->SetSpawnParams(params);
// Unimplemented objects should not be added to the SpawnList
// The name field is required. If not set, then its not implemented yet.
if (!params.Name.empty()) {
actorList.push_back(params.to_json());
}
}
}
}
+15 -7
View File
@@ -1,13 +1,21 @@
#pragma once
#include <libultraship/libultraship.h>
#include "CoreMath.h"
#include "engine/courses/Course.h"
#include <optional>
#include <nlohmann/json.hpp>
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);
void SaveLevel();
void LoadLevel(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(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;
void SaveActors(nlohmann::json& actorList);
void SpawnActors(std::vector<std::pair<std::string, SpawnParams>> spawnList);
extern std::shared_ptr<Ship::Archive> CurrentArchive; // This is used to retrieve and write the scene data file
extern std::string SceneFile;
}

Some files were not shown because too many files have changed in this diff Show More