summaryrefslogtreecommitdiff
path: root/src/engine/vehicles/Train.cpp
diff options
context:
space:
mode:
authorMegaMech <MegaMech@users.noreply.github.com>2024-10-15 13:09:43 -0600
committerGitHub <noreply@github.com>2024-10-15 13:09:43 -0600
commita0862b6a159373f2e1554e489ecb5bb08d89654e (patch)
treeb5c33fc7f65b438ee74898dd9ed7ba25b0fa108a /src/engine/vehicles/Train.cpp
parent58d56fcba848e8545052c1d85ef27d0b02841538 (diff)
[modding] Implement Vehicles & Fix Animations (#109)
* Train works * Fix minimap * Fix highway * Fix * Refactor train and boat * Update * Implement Trucks * Fix tanker * Finish implementing vehicles * Fix animations * Fix spawn players * Fix spawn players * Fix loading custom data --------- Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Diffstat (limited to 'src/engine/vehicles/Train.cpp')
-rw-r--r--src/engine/vehicles/Train.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/engine/vehicles/Train.cpp b/src/engine/vehicles/Train.cpp
new file mode 100644
index 000000000..85391ec53
--- /dev/null
+++ b/src/engine/vehicles/Train.cpp
@@ -0,0 +1,294 @@
+
+#include <libultraship.h>
+#include <libultra/gbi.h>
+#include "Train.h"
+#include <vector>
+
+extern "C" {
+#include "macros.h"
+#include "main.h"
+#include "defines.h"
+#include "code_80005FD0.h"
+#include "vehicles.h"
+#include "actors.h"
+#include "math_util.h"
+#include "sounds.h"
+#include "update_objects.h"
+#include "waypoints.h"
+#include "code_80057C60.h"
+#include "math_util_2.h"
+#include "render_objects.h"
+#include "assets/common_data.h"
+ // #include "common_structs.h"
+}
+
+ATrain::ATrain(size_t idx, size_t numCarriages, f32 speed, uint32_t waypoint) {
+ u16 waypointOffset;
+ TrainCarStuff* ptr1;
+ Path2D* pos;
+
+ Index = idx;
+ Speed = speed;
+
+ // Set to the default value
+ std::fill(SmokeParticles, SmokeParticles + 128, NULL_OBJECT_ID);
+
+ for (size_t i = 0; i < numCarriages; i++) {
+ PassengerCars.push_back(TrainCarStuff());
+ }
+
+ // outputs 160 or 392 depending on the train.
+ // Wraps the value around to always output a valid waypoint.
+ waypointOffset = waypoint;
+
+ // 120.0f is about the maximum usable value
+ for (size_t i = 0; i < PassengerCars.size(); i++) {
+ waypointOffset += 4;
+ ptr1 = &PassengerCars[i];
+ pos = &gVehicle2DWaypoint[waypointOffset];
+ set_vehicle_pos_waypoint(ptr1, pos, waypointOffset);
+ }
+ // Smaller offset for the tender
+ waypointOffset += 3;
+ pos = &gVehicle2DWaypoint[waypointOffset];
+ set_vehicle_pos_waypoint(&this->Tender, pos, waypointOffset);
+ waypointOffset += 4;
+ pos = &gVehicle2DWaypoint[waypointOffset];
+ set_vehicle_pos_waypoint(&Locomotive, pos, waypointOffset);
+
+ // Only use locomotive unless overwritten below.
+ NumCars = LOCOMOTIVE_ONLY;
+
+ // Spawn all rolling stock in single player mode.
+ switch (gScreenModeSelection) {
+ case SCREEN_MODE_1P: // single player
+ Tender.isActive = 1;
+
+ // clang-format off
+ // Same line required for matching...
+ for (size_t i = 0; i < numCarriages; i++) { PassengerCars[i].isActive = 1; }
+ // clang-format on
+
+ NumCars = NUM_TENDERS + numCarriages;
+ break;
+
+ // Spawn locomotive, tender, and one passenger car in versus 2/3 player mode.
+ case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: // multiplayer fall-through
+ case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
+ if (gModeSelection != GRAND_PRIX) {
+ Tender.isActive = 1;
+ PassengerCars[4].isActive = 1;
+ NumCars = NUM_TENDERS + NUM_2P_PASSENGER_CARS;
+ }
+ break;
+ }
+
+ AnotherSmokeTimer = 0;
+}
+
+void ATrain::Spawn() {
+ TrainCarStuff* tempLocomotive;
+ TrainCarStuff* tempTender;
+ TrainCarStuff* tempPassengerCar;
+ Vec3s trainCarRot;
+ s16 trainCarYRot;
+ f32 origXPos;
+ f32 origZPos;
+
+ tempLocomotive = &Locomotive;
+ origXPos = tempLocomotive->position[0];
+ origZPos = tempLocomotive->position[2];
+ trainCarYRot = update_vehicle_following_waypoint(
+ tempLocomotive->position, (s16*) &tempLocomotive->waypointIndex, Speed);
+ tempLocomotive->velocity[0] = tempLocomotive->position[0] - origXPos;
+ tempLocomotive->velocity[2] = tempLocomotive->position[2] - origZPos;
+ vec3s_set(trainCarRot, 0, trainCarYRot, 0);
+ tempLocomotive->actorIndex = add_actor_to_empty_slot(tempLocomotive->position, trainCarRot,
+ tempLocomotive->velocity, ACTOR_TRAIN_ENGINE);
+
+ tempTender = &Tender;
+ if (tempTender->isActive == 1) {
+ origXPos = tempTender->position[0];
+ origZPos = tempTender->position[2];
+ trainCarYRot = update_vehicle_following_waypoint(
+ tempTender->position, (s16*) &tempTender->waypointIndex, Speed);
+ tempTender->velocity[0] = tempTender->position[0] - origXPos;
+ tempTender->velocity[2] = tempTender->position[2] - origZPos;
+ vec3s_set(trainCarRot, 0, trainCarYRot, 0);
+ tempTender->actorIndex = add_actor_to_empty_slot(tempTender->position, trainCarRot,
+ tempTender->velocity, ACTOR_TRAIN_TENDER);
+ }
+
+ for (size_t i = 0; i < PassengerCars.size(); i++) {
+ tempPassengerCar = &PassengerCars[i];
+ if (tempPassengerCar->isActive == 1) {
+ origXPos = tempPassengerCar->position[0];
+ origZPos = tempPassengerCar->position[2];
+ trainCarYRot = update_vehicle_following_waypoint(tempPassengerCar->position,
+ (s16*) &tempPassengerCar->waypointIndex,
+ Speed);
+ tempPassengerCar->velocity[0] = tempPassengerCar->position[0] - origXPos;
+ tempPassengerCar->velocity[2] = tempPassengerCar->position[2] - origZPos;
+ vec3s_set(trainCarRot, 0, trainCarYRot, 0);
+ tempPassengerCar->actorIndex =
+ add_actor_to_empty_slot(tempPassengerCar->position, trainCarRot, tempPassengerCar->velocity,
+ ACTOR_TRAIN_PASSENGER_CAR);
+ }
+ }
+}
+
+void ATrain::BeginPlay() {
+}
+
+void ATrain::SyncComponents(TrainCarStuff* trainCar, s16 orientationY) {
+ struct TrainCar* trainCarActor;
+
+ //! @todo: Change actorIndex to ptr to TrainCar actor
+ trainCarActor = (struct TrainCar*) &gActorList[trainCar->actorIndex];
+ trainCarActor->pos[0] = trainCar->position[0];
+ trainCarActor->pos[1] = trainCar->position[1];
+ trainCarActor->pos[2] = trainCar->position[2];
+ if (gIsMirrorMode != 0) {
+ trainCarActor->rot[1] = -orientationY;
+ } else {
+ trainCarActor->rot[1] = orientationY;
+ }
+ trainCarActor->velocity[0] = trainCar->velocity[0];
+ trainCarActor->velocity[2] = trainCar->velocity[2];
+}
+
+void ATrain::Tick() {
+ f32 temp_f20;
+ TrainCarStuff* car;
+ u16 oldWaypointIndex;
+ s16 orientationYUpdate;
+ f32 temp_f22;
+ s32 j;
+ Vec3f smokePos;
+
+ AnotherSmokeTimer += 1;
+
+ oldWaypointIndex = (u16) Locomotive.waypointIndex;
+
+ temp_f20 = Locomotive.position[0];
+ temp_f22 = Locomotive.position[2];
+
+ orientationYUpdate = update_vehicle_following_waypoint(
+ Locomotive.position, (s16*) &Locomotive.waypointIndex, Speed);
+
+ Locomotive.velocity[0] = Locomotive.position[0] - temp_f20;
+ Locomotive.velocity[2] = Locomotive.position[2] - temp_f22;
+
+ sync_train_components(&Locomotive, orientationYUpdate);
+
+ if ((oldWaypointIndex != Locomotive.waypointIndex) &&
+ ((Locomotive.waypointIndex == 0x00BE) ||
+ (Locomotive.waypointIndex == 0x0140))) { // play crossing bell sound
+ func_800C98B8(Locomotive.position, Locomotive.velocity,
+ SOUND_ARG_LOAD(0x19, 0x01, 0x80, 0x0E));
+ } else if (random_int(100) == 0) { // play train whistle sound
+ func_800C98B8(Locomotive.position, Locomotive.velocity,
+ SOUND_ARG_LOAD(0x19, 0x01, 0x80, 0x0D));
+ }
+
+ SomeFlags = set_vehicle_render_distance_flags(
+ Locomotive.position, TRAIN_SMOKE_RENDER_DISTANCE, SomeFlags);
+ // Renders locomotive smoke on all screens if any player is within range.
+ if ((((s16) AnotherSmokeTimer % 5) == 0) && (SomeFlags != 0)) {
+ smokePos[0] = Locomotive.position[0];
+ smokePos[1] = (f32) ((f64) Locomotive.position[1] + 65.0);
+ smokePos[2] = (f32) ((f64) Locomotive.position[2] + 25.0);
+ adjust_position_by_angle(smokePos, Locomotive.position, orientationYUpdate);
+ //spawn_train_smoke(Index, smokePos, 1.1f);
+ printf("\nSMOKE HERE: %d\n\n", Index);
+ AddSmoke(Index, smokePos, 1.1f);
+ }
+
+ car = &Tender;
+
+ if (car->isActive == 1) {
+ temp_f20 = car->position[0];
+ temp_f22 = car->position[2];
+ orientationYUpdate =
+ update_vehicle_following_waypoint(car->position, (s16*) &car->waypointIndex, Speed);
+ car->velocity[0] = car->position[0] - temp_f20;
+ car->velocity[2] = car->position[2] - temp_f22;
+ sync_train_components(car, orientationYUpdate);
+ }
+
+ for (j = 0; j < PassengerCars.size(); j++) {
+ car = &PassengerCars[j];
+ if (car->isActive == 1) {
+ temp_f20 = car->position[0];
+ temp_f22 = car->position[2];
+
+ orientationYUpdate =
+ update_vehicle_following_waypoint(car->position, (s16*) &car->waypointIndex, Speed);
+ car->velocity[0] = car->position[0] - temp_f20;
+ car->velocity[2] = car->position[2] - temp_f22;
+ sync_train_components(car, orientationYUpdate);
+ }
+ }
+}
+
+void ATrain::Collision(s32 playerId, Player* player) {
+ TrainCarStuff* trainCar;
+ f32 playerPosX;
+ f32 playerPosZ;
+ f32 x_dist;
+ f32 z_dist;
+ s32 trainIndex;
+
+ if (D_801631E0[playerId] != 1) {
+ if (!(player->effects & 0x01000000)) {
+ playerPosX = player->pos[0];
+ playerPosZ = player->pos[2];
+ trainCar = &Locomotive;
+ x_dist = playerPosX - trainCar->position[0];
+ z_dist = playerPosZ - trainCar->position[2];
+ if ((x_dist > -100.0) && (x_dist < 100.0)) {
+ if ((z_dist > -100.0) && (z_dist < 100.0)) {
+ if (func_80006018(trainCar->position[0], trainCar->position[2], trainCar->velocity[0],
+ trainCar->velocity[2], 60.0f, 20.0f, playerPosX, playerPosZ) == 1) {
+ player->soundEffects |= REVERSE_SOUND_EFFECT;
+ }
+ trainCar = &Tender;
+ if (trainCar->isActive == 1) {
+ if (func_80006018(trainCar->position[0], trainCar->position[2], trainCar->velocity[0],
+ trainCar->velocity[2], 30.0f, 20.0f, playerPosX, playerPosZ) == 1) {
+ player->soundEffects |= REVERSE_SOUND_EFFECT;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < PassengerCars.size(); i++) {
+ trainCar = &PassengerCars[i];
+ x_dist = playerPosX - trainCar->position[0];
+ z_dist = playerPosZ - trainCar->position[2];
+ if (trainCar->isActive == 1) {
+ if ((x_dist > -100.0) && (x_dist < 100.0)) {
+ if ((z_dist > -100.0) && (z_dist < 100.0)) {
+ if (func_80006018(trainCar->position[0], trainCar->position[2], trainCar->velocity[0],
+ trainCar->velocity[2], 30.0f, 20.0f, playerPosX, playerPosZ) == 1) {
+ player->soundEffects |= REVERSE_SOUND_EFFECT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void ATrain::Draw(s32 playerId) {
+}
+
+s32 ATrain::AddSmoke(s32 trainIndex, Vec3f pos, f32 velocity) {
+ s32 objectIndex = add_unused_obj_index(SmokeParticles, &NextParticlePtr, gObjectParticle2_SIZE);
+ if (objectIndex != NULL_OBJECT_ID) {
+ init_train_smoke(objectIndex, pos, velocity);
+ }
+ return objectIndex;
+}