mirror of
https://github.com/HarbourMasters/SpaghettiKart
synced 2026-08-22 07:04:47 -04:00
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:
@@ -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
|
||||
################################################################################
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+6
-9
@@ -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
@@ -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
@@ -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++;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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(); };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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" {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void RegisterGameActors();
|
||||
+26
-53
@@ -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
@@ -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
@@ -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};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
class StaticMeshActor {
|
||||
public:
|
||||
std::string Name;
|
||||
std::string ResourceName;
|
||||
FVector Pos;
|
||||
IRotator Rot;
|
||||
FVector Scale;
|
||||
|
||||
+10
-38
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 0–65535
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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};
|
||||
};
|
||||
|
||||
@@ -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 0–65535
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 0–65535
|
||||
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 (0–7)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}}},
|
||||
};
|
||||
};
|
||||
@@ -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];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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*);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
namespace Editor {
|
||||
Handles::Handles() {
|
||||
Pos = &pos;
|
||||
Rot = &rot;
|
||||
}
|
||||
|
||||
void Handles::Load() {
|
||||
|
||||
@@ -13,7 +13,5 @@ namespace Editor {
|
||||
virtual void Draw() override;
|
||||
virtual void Load() override;
|
||||
|
||||
FVector pos;
|
||||
IRotator rot;
|
||||
};
|
||||
}
|
||||
|
||||
+16
-13
@@ -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, ¢erRot);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user