1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-28 01:04:50 +01:00
Files
OpenRCT2/src/openrct2/ride/Station.cpp
Łukasz Pękalski 065da23b3b Close #12437, refactor: RIDE_MODE_* to strong enums (#12833)
* partial refactor: RIDE_MODE_* to strong enums

* Close #12437, refactor: RIDE_MODE_* to strong enums

* chore: code formatting

* refactor: RideMode, change enum names to CamelCase

and resolve casting order.

* chore: refactor due to code formatting

* Close #12437, refactor: RIDE_MODE_* to strong enums

Resolved comments

* chore: Formatting correction.

* Use EnumsToFlags constexpr

* refactor: resolved comments

added newline at the end of file

* refactor: Change case stack to default in Switch

Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-09-28 14:09:59 +01:00

447 lines
14 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2020 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "Station.h"
#include "../Game.h"
#include "../scenario/Scenario.h"
#include "../world/Location.hpp"
#include "../world/Sprite.h"
#include "Track.h"
static void ride_update_station_blocksection(Ride* ride, StationIndex stationIndex);
static void ride_update_station_dodgems(Ride* ride, StationIndex stationIndex);
static void ride_update_station_normal(Ride* ride, StationIndex stationIndex);
static void ride_update_station_race(Ride* ride, StationIndex stationIndex);
static void ride_race_init_vehicle_speeds(Ride* ride);
static void ride_invalidate_station_start(Ride* ride, StationIndex stationIndex, bool greenLight);
/**
*
* rct2: 0x006ABFFB
*/
void ride_update_station(Ride* ride, StationIndex stationIndex)
{
if (ride->stations[stationIndex].Start.isNull())
return;
switch (ride->mode)
{
case RideMode::Race:
ride_update_station_race(ride, stationIndex);
break;
case RideMode::Dodgems:
ride_update_station_dodgems(ride, stationIndex);
break;
case RideMode::ContinuousCircuitBlockSectioned:
case RideMode::PoweredLaunchBlockSectioned:
ride_update_station_blocksection(ride, stationIndex);
break;
default:
ride_update_station_normal(ride, stationIndex);
break;
}
}
/**
*
* rct2: 0x006AC0A1
*/
static void ride_update_station_blocksection(Ride* ride, StationIndex stationIndex)
{
TileElement* tileElement = ride_get_station_start_track_element(ride, stationIndex);
if ((ride->status == RIDE_STATUS_CLOSED && ride->num_riders == 0)
|| (tileElement != nullptr && tileElement->AsTrack()->BlockBrakeClosed()))
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
if ((ride->stations[stationIndex].Depart & STATION_DEPART_FLAG)
|| (tileElement != nullptr && tileElement->AsTrack()->HasGreenLight()))
ride_invalidate_station_start(ride, stationIndex, false);
}
else
{
if (!(ride->stations[stationIndex].Depart & STATION_DEPART_FLAG))
{
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, true);
}
else if (tileElement != nullptr && tileElement->AsTrack()->HasGreenLight())
{
ride_invalidate_station_start(ride, stationIndex, true);
}
}
}
/**
*
* rct2: 0x006AC12B
*/
static void ride_update_station_dodgems(Ride* ride, StationIndex stationIndex)
{
// Change of station depart flag should really call invalidate_station_start
// but since dodgems do not have station lights there is no point.
if (ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)))
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
return;
}
if (ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
{
int32_t dx = ride->time_limit * 32;
int32_t dh = (dx >> 8) & 0xFF;
for (size_t i = 0; i < ride->num_vehicles; i++)
{
Vehicle* vehicle = GetEntity<Vehicle>(ride->vehicles[i]);
if (vehicle == nullptr)
continue;
if (vehicle->var_CE < dh)
continue;
// End match
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
return;
}
// Continue match
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
}
else
{
// Check if all vehicles are ready to go
for (size_t i = 0; i < ride->num_vehicles; i++)
{
Vehicle* vehicle = GetEntity<Vehicle>(ride->vehicles[i]);
if (vehicle == nullptr)
continue;
if (vehicle->status != Vehicle::Status::WaitingToDepart)
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
return;
}
}
// Begin the match
ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
/**
*
* rct2: 0x006AC02C
*/
static void ride_update_station_normal(Ride* ride, StationIndex stationIndex)
{
int32_t time = ride->stations[stationIndex].Depart & STATION_DEPART_MASK;
if ((ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))
|| (ride->status == RIDE_STATUS_CLOSED && ride->num_riders == 0))
{
if (time != 0 && time != 127 && !(gCurrentTicks & 7))
time--;
ride->stations[stationIndex].Depart = time;
ride_invalidate_station_start(ride, stationIndex, false);
}
else
{
if (time == 0)
{
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, true);
}
else
{
if (time != 127 && !(gCurrentTicks & 31))
time--;
ride->stations[stationIndex].Depart = time;
ride_invalidate_station_start(ride, stationIndex, false);
}
}
}
/**
*
* rct2: 0x006AC1DF
*/
static void ride_update_station_race(Ride* ride, StationIndex stationIndex)
{
if (ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)))
{
if (ride->stations[stationIndex].Depart & STATION_DEPART_FLAG)
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, false);
}
return;
}
if (ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
{
int32_t numLaps = ride->num_laps;
for (size_t i = 0; i < ride->num_vehicles; i++)
{
Vehicle* vehicle = GetEntity<Vehicle>(ride->vehicles[i]);
if (vehicle == nullptr)
continue;
if (vehicle->status != Vehicle::Status::WaitingToDepart && vehicle->num_laps >= numLaps)
{
// Found a winner
if (vehicle->num_peeps != 0)
{
auto* peep = GetEntity<Guest>(vehicle->peep[0]);
if (peep != nullptr)
{
ride->race_winner = peep->sprite_index;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
// Race is over
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
if (ride->stations[stationIndex].Depart & STATION_DEPART_FLAG)
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, false);
}
return;
}
}
// Continue racing
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
}
else
{
// Check if all vehicles are ready to go
for (size_t i = 0; i < ride->num_vehicles; i++)
{
Vehicle* vehicle = GetEntity<Vehicle>(ride->vehicles[i]);
if (vehicle == nullptr)
continue;
if (vehicle->status != Vehicle::Status::WaitingToDepart && vehicle->status != Vehicle::Status::Departing)
{
if (ride->stations[stationIndex].Depart & STATION_DEPART_FLAG)
{
ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, false);
}
return;
}
}
// Begin the race
ride_race_init_vehicle_speeds(ride);
ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
if (!(ride->stations[stationIndex].Depart & STATION_DEPART_FLAG))
{
ride->stations[stationIndex].Depart |= STATION_DEPART_FLAG;
ride_invalidate_station_start(ride, stationIndex, true);
}
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
/**
*
* rct2: 0x006AC988
* set the speed of the go kart type vehicle at the start to a random value or alter if peep name is an easter egg
* @param ride (esi)
*/
static void ride_race_init_vehicle_speeds(Ride* ride)
{
for (size_t i = 0; i < ride->num_vehicles; i++)
{
Vehicle* vehicle = GetEntity<Vehicle>(ride->vehicles[i]);
if (vehicle == nullptr)
continue;
vehicle->ClearUpdateFlag(VEHICLE_UPDATE_FLAG_6);
rct_ride_entry* rideEntry = vehicle->GetRideEntry();
vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->vehicle_type].powered_max_speed;
if (vehicle->num_peeps != 0)
{
auto peep = GetEntity<Peep>(vehicle->peep[0]);
// Easter egg names should only work on guests
Guest* guest = peep->AsGuest();
if (guest != nullptr)
{
switch (guest->GetEasterEggNameId())
{
case EASTEREGG_PEEP_NAME_MICHAEL_SCHUMACHER:
vehicle->speed += 35;
break;
case EASTEREGG_PEEP_NAME_JACQUES_VILLENEUVE:
vehicle->speed += 25;
break;
case EASTEREGG_PEEP_NAME_DAMON_HILL:
vehicle->speed += 55;
break;
case EASTEREGG_PEEP_NAME_CHRIS_SAWYER:
vehicle->speed += 14;
break;
case EASTEREGG_PEEP_NAME_MR_BEAN:
vehicle->speed = 9;
break;
}
}
}
}
}
/**
*
* rct2: 0x006AC2C7
*/
static void ride_invalidate_station_start(Ride* ride, StationIndex stationIndex, bool greenLight)
{
auto startPos = ride->stations[stationIndex].Start;
TileElement* tileElement = ride_get_station_start_track_element(ride, stationIndex);
// If no station track found return
if (tileElement == nullptr)
return;
tileElement->AsTrack()->SetHasGreenLight(greenLight);
// Invalidate map tile
map_invalidate_tile_zoom1({ startPos, tileElement->GetBaseZ(), tileElement->GetClearanceZ() });
}
TileElement* ride_get_station_start_track_element(Ride* ride, StationIndex stationIndex)
{
auto stationStart = ride->stations[stationIndex].GetStart();
// Find the station track element
TileElement* tileElement = map_get_first_element_at(stationStart);
if (tileElement == nullptr)
return nullptr;
do
{
if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK && stationStart.z == tileElement->GetBaseZ())
return tileElement;
} while (!(tileElement++)->IsLastForTile());
return nullptr;
}
TileElement* ride_get_station_exit_element(const CoordsXYZ& elementPos)
{
// Find the station track element
TileElement* tileElement = map_get_first_element_at(elementPos);
if (tileElement == nullptr)
return nullptr;
do
{
if (tileElement == nullptr)
break;
if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE && elementPos.z == tileElement->GetBaseZ())
return tileElement;
} while (!(tileElement++)->IsLastForTile());
return nullptr;
}
StationIndex ride_get_first_valid_station_exit(Ride* ride)
{
for (StationIndex i = 0; i < MAX_STATIONS; i++)
{
if (!ride->stations[i].Exit.isNull())
{
return i;
}
}
return STATION_INDEX_NULL;
}
StationIndex ride_get_first_valid_station_start(const Ride* ride)
{
for (StationIndex i = 0; i < MAX_STATIONS; i++)
{
if (!ride->stations[i].Start.isNull())
{
return i;
}
}
return STATION_INDEX_NULL;
}
StationIndex ride_get_first_empty_station_start(const Ride* ride)
{
for (StationIndex i = 0; i < MAX_STATIONS; i++)
{
if (ride->stations[i].Start.isNull())
{
return i;
}
}
return STATION_INDEX_NULL;
}
TileCoordsXYZD ride_get_entrance_location(const Ride* ride, const StationIndex stationIndex)
{
return ride->stations[stationIndex].Entrance;
}
TileCoordsXYZD ride_get_exit_location(const Ride* ride, const StationIndex stationIndex)
{
return ride->stations[stationIndex].Exit;
}
void ride_clear_entrance_location(Ride* ride, const StationIndex stationIndex)
{
ride->stations[stationIndex].Entrance.setNull();
}
void ride_clear_exit_location(Ride* ride, const StationIndex stationIndex)
{
ride->stations[stationIndex].Exit.setNull();
}
void ride_set_entrance_location(Ride* ride, const StationIndex stationIndex, const TileCoordsXYZD& location)
{
ride->stations[stationIndex].Entrance = location;
}
void ride_set_exit_location(Ride* ride, const StationIndex stationIndex, const TileCoordsXYZD& location)
{
ride->stations[stationIndex].Exit = location;
}
int32_t RideStation::GetBaseZ() const
{
return Height * COORDS_Z_STEP;
}
void RideStation::SetBaseZ(int32_t newZ)
{
Height = newZ / COORDS_Z_STEP;
}
CoordsXYZ RideStation::GetStart() const
{
return { Start, GetBaseZ() };
}