Implement RideSetVehicleAction

Move all callees to the new action.
Required rework on how the ride type change worked.
This commit is contained in:
duncanspumpkin 2019-02-21 15:56:23 +00:00
parent cf1a4c9d66
commit c1546a92b7
7 changed files with 302 additions and 219 deletions

View File

@ -611,7 +611,7 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c
format_string(log_msg, 256, STR_LOG_DEMOLISH_RIDE, args);
network_append_server_log(log_msg);
}
else if (command == GAME_COMMAND_SET_RIDE_VEHICLES || command == GAME_COMMAND_SET_RIDE_SETTING)
else if (command == GAME_COMMAND_SET_RIDE_SETTING)
{
// Get ride name
int ride_index = *edx & 0xFF;
@ -626,12 +626,6 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c
switch (command)
{
case GAME_COMMAND_SET_RIDE_APPEARANCE:
format_string(log_msg, 256, STR_LOG_RIDE_APPEARANCE, args);
break;
case GAME_COMMAND_SET_RIDE_VEHICLES:
format_string(log_msg, 256, STR_LOG_RIDE_VEHICLES, args);
break;
case GAME_COMMAND_SET_RIDE_SETTING:
format_string(log_msg, 256, STR_LOG_RIDE_SETTINGS, args);
break;
@ -1297,7 +1291,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = {
game_command_create_ride,
game_command_demolish_ride,
game_command_set_ride_status,
game_command_set_ride_vehicles,
nullptr,
game_command_set_ride_name,
game_command_set_ride_setting,
game_command_place_ride_entrance_or_exit,

View File

@ -27,8 +27,8 @@ enum GAME_COMMAND
GAME_COMMAND_CREATE_RIDE, // GA
GAME_COMMAND_DEMOLISH_RIDE, // GA
GAME_COMMAND_SET_RIDE_STATUS, // GA
GAME_COMMAND_SET_RIDE_VEHICLES,
GAME_COMMAND_SET_RIDE_NAME, // GA
GAME_COMMAND_SET_RIDE_VEHICLES, // GA
GAME_COMMAND_SET_RIDE_NAME, // GA
GAME_COMMAND_SET_RIDE_SETTING,
GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT,
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,

View File

@ -39,6 +39,9 @@ enum class GA_ERROR : uint16_t
NO_CLEARANCE,
ITEM_ALREADY_PLACED,
NOT_CLOSED,
BROKEN,
NO_FREE_ELEMENTS,
UNKNOWN = UINT16_MAX,

View File

@ -42,6 +42,7 @@
#include "TrackPlaceAction.hpp"
#include "TrackRemoveAction.hpp"
#include "WallRemoveAction.hpp"
#include "RideSetVehiclesAction.hpp"
namespace GameActions
{
@ -65,6 +66,7 @@ namespace GameActions
Register<RideSetPriceAction>();
Register<RideSetStatusAction>();
Register<RideSetAppearanceAction>();
Register<RideSetVehicleAction>();
Register<SetParkEntranceFeeAction>();
Register<SignSetNameAction>();
Register<SignSetStyleAction>();

View File

@ -0,0 +1,276 @@
/*****************************************************************************
* Copyright (c) 2014-2018 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.
*****************************************************************************/
#pragma once
#include "../Cheats.h"
#include "../Context.h"
#include "../core/MemoryStream.h"
#include "../drawing/Drawing.h"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../management/Research.h"
#include "../ride/Ride.h"
#include "../ui/UiContext.h"
#include "../ui/WindowManager.h"
#include "../world/Park.h"
#include "GameAction.h"
enum class RideSetVehicleType : uint8_t
{
NumTrains,
NumCarsPerTrain,
RideEntry
};
DEFINE_GAME_ACTION(RideSetVehicleAction, GAME_COMMAND_SET_RIDE_VEHICLES, GameActionResult)
{
private:
NetworkRideId_t _rideIndex{ -1 };
uint8_t _type;
uint8_t _value;
uint8_t _colour;
constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL,
STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL,
STR_RIDE_SET_VEHICLE_TYPE_FAIL };
public:
RideSetVehicleAction()
{
}
RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour = 0)
: _rideIndex(rideIndex)
, _type(static_cast<uint8_t>(type))
, _value(value)
, _colour(colour)
{
}
uint16_t GetActionFlags() const override
{
return GameAction::GetActionFlags();
}
void Serialise(DataSerialiser & stream) override
{
GameAction::Serialise(stream);
stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour);
}
GameActionResult::Ptr Query() const override
{
if (_type > sizeof(SetVehicleTypeErrorTitle))
{
log_warning("Invalid type. type = %d", _type);
}
auto errTitle = SetVehicleTypeErrorTitle[_type];
if (_rideIndex >= MAX_RIDES || _rideIndex == RIDE_ID_NULL)
{
log_warning("Invalid game command for ride %u", uint32_t(_rideIndex));
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
Ride* ride = get_ride(_rideIndex);
if (ride == nullptr || ride->type == RIDE_TYPE_NULL)
{
log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex));
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
{
return std::make_unique<GameActionResult>(GA_ERROR::BROKEN, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING);
}
if (ride->status != RIDE_STATUS_CLOSED)
{
return std::make_unique<GameActionResult>(GA_ERROR::NOT_CLOSED, errTitle, STR_MUST_BE_CLOSED_FIRST);
}
switch (static_cast<RideSetVehicleType>(_type))
{
case RideSetVehicleType::NumTrains:
case RideSetVehicleType::NumCarsPerTrain:
break;
case RideSetVehicleType::RideEntry:
{
if (!ride_is_vehicle_type_valid(ride))
{
log_error("Invalid vehicle type. type = %d", _value);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
auto rideEntry = get_ride_entry(_value);
if (rideEntry == nullptr)
{
log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
// Validate preset
vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list;
if (_colour >= presetList->count)
{
log_error("Unknown vehicle colour preset. colour = %d", _colour);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
break;
}
default:
log_error("Unknown vehicle command. type = %d", _type);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
return std::make_unique<GameActionResult>();
}
GameActionResult::Ptr Execute() const override
{
auto errTitle = SetVehicleTypeErrorTitle[_type];
Ride* ride = get_ride(_rideIndex);
if (ride == nullptr || ride->type == RIDE_TYPE_NULL)
{
log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex));
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
switch (static_cast<RideSetVehicleType>(_type))
{
case RideSetVehicleType::NumTrains:
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
ride->proposed_num_vehicles = _value;
break;
case RideSetVehicleType::NumCarsPerTrain:
{
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
invalidate_test_results(ride);
auto rideEntry = get_ride_entry(ride->subtype);
if (rideEntry == nullptr)
{
log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
auto clampValue = _value;
if (!gCheatsDisableTrainLengthLimit)
{
clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train);
}
ride->proposed_num_cars_per_train = clampValue;
break;
}
case RideSetVehicleType::RideEntry:
{
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
invalidate_test_results(ride);
ride->subtype = _value;
auto rideEntry = get_ride_entry(ride->subtype);
if (rideEntry == nullptr)
{
log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
ride_set_vehicle_colours_to_random_preset(ride, _colour);
if (!gCheatsDisableTrainLengthLimit)
{
ride->proposed_num_cars_per_train = std::clamp(
ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train);
}
break;
}
default:
log_error("Unknown vehicle command. type = %d", _type);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, errTitle);
}
ride->num_circuits = 1;
ride_update_max_vehicles(ride);
auto res = std::make_unique<GameActionResult>();
if (ride->overall_view.xy != RCT_XY8_UNDEFINED)
{
res->Position.x = ride->overall_view.x * 32 + 16;
res->Position.y = ride->overall_view.y * 32 + 16;
res->Position.z = tile_element_height(res->Position.x, res->Position.y);
}
auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE);
intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex);
context_broadcast_intent(&intent);
gfx_invalidate_screen();
return res;
}
private:
bool ride_is_vehicle_type_valid(Ride * ride) const
{
bool selectionShouldBeExpanded;
int32_t rideTypeIterator, rideTypeIteratorMax;
if (gCheatsShowVehiclesFromOtherTrackTypes
&& !(
ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE
|| ride->type == RIDE_TYPE_MINI_GOLF))
{
selectionShouldBeExpanded = true;
rideTypeIterator = 0;
rideTypeIteratorMax = RIDE_TYPE_COUNT - 1;
}
else
{
selectionShouldBeExpanded = false;
rideTypeIterator = ride->type;
rideTypeIteratorMax = ride->type;
}
for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++)
{
if (selectionShouldBeExpanded)
{
if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE))
continue;
if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF)
continue;
}
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator);
for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL;
currentRideEntryIndex++)
{
uint8_t rideEntryIndex = *currentRideEntryIndex;
if (rideEntryIndex == _value)
{
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
return false;
}
return true;
}
}
}
return false;
}
};

View File

@ -16,6 +16,7 @@
#include "../Input.h"
#include "../OpenRCT2.h"
#include "../actions/TrackRemoveAction.hpp"
#include "../actions/RideSetVehiclesAction.hpp"
#include "../audio/AudioMixer.h"
#include "../audio/audio.h"
#include "../common.h"
@ -7365,219 +7366,21 @@ void ride_update_max_vehicles(Ride* ride)
void ride_set_ride_entry(Ride* ride, int32_t rideEntry)
{
gGameCommandErrorTitle = STR_RIDE_SET_VEHICLE_TYPE_FAIL;
game_do_command(
0, GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_RIDE_ENTRY << 8), 0, (rideEntry << 8) | ride->id,
GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
auto colour = ride_get_unused_preset_vehicle_colour(rideEntry);
auto rideSetVehicleAction = RideSetVehicleAction(ride->id, RideSetVehicleType::RideEntry, rideEntry, colour);
GameActions::Execute(&rideSetVehicleAction);
}
void ride_set_num_vehicles(Ride* ride, int32_t numVehicles)
{
gGameCommandErrorTitle = STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL;
game_do_command(
0, GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_TRAINS << 8), 0, (numVehicles << 8) | ride->id,
GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
auto rideSetVehicleAction = RideSetVehicleAction(ride->id, RideSetVehicleType::NumTrains, numVehicles);
GameActions::Execute(&rideSetVehicleAction);
}
void ride_set_num_cars_per_vehicle(Ride* ride, int32_t numCarsPerVehicle)
{
gGameCommandErrorTitle = STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL;
game_do_command(
0, GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_CARS_PER_TRAIN << 8), 0,
(numCarsPerVehicle << 8) | ride->id, GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
}
static bool ride_is_vehicle_type_valid(Ride* ride, uint8_t inputRideEntryIndex)
{
bool selectionShouldBeExpanded;
int32_t rideTypeIterator, rideTypeIteratorMax;
if (gCheatsShowVehiclesFromOtherTrackTypes
&& !(ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE
|| ride->type == RIDE_TYPE_MINI_GOLF))
{
selectionShouldBeExpanded = true;
rideTypeIterator = 0;
rideTypeIteratorMax = RIDE_TYPE_COUNT - 1;
}
else
{
selectionShouldBeExpanded = false;
rideTypeIterator = ride->type;
rideTypeIteratorMax = ride->type;
}
for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++)
{
if (selectionShouldBeExpanded)
{
if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE))
continue;
if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF)
continue;
}
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator);
for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL;
currentRideEntryIndex++)
{
uint8_t rideEntryIndex = *currentRideEntryIndex;
if (rideEntryIndex == inputRideEntryIndex)
{
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
return false;
}
return true;
}
}
}
return false;
}
static money32 ride_set_vehicles(ride_id_t rideIndex, uint8_t setting, uint8_t value, uint32_t flags, uint8_t ex)
{
rct_ride_entry* rideEntry;
Ride* ride = get_ride(rideIndex);
if (ride == nullptr || ride->type == RIDE_TYPE_NULL)
{
log_warning("Invalid game command for ride #%u", rideIndex);
return MONEY32_UNDEFINED;
}
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
{
gGameCommandErrorText = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING;
return MONEY32_UNDEFINED;
}
if (ride->status != RIDE_STATUS_CLOSED)
{
gGameCommandErrorText = STR_MUST_BE_CLOSED_FIRST;
return MONEY32_UNDEFINED;
}
switch (setting)
{
case RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_TRAINS:
if (!(flags & GAME_COMMAND_FLAG_APPLY))
{
return 0;
}
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
ride->proposed_num_vehicles = value;
break;
case RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_CARS_PER_TRAIN:
if (!(flags & GAME_COMMAND_FLAG_APPLY))
{
return 0;
}
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
invalidate_test_results(ride);
rideEntry = get_ride_entry(ride->subtype);
if (!gCheatsDisableTrainLengthLimit)
{
value = std::clamp(value, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train);
}
ride->proposed_num_cars_per_train = value;
break;
case RIDE_SET_VEHICLES_COMMAND_TYPE_RIDE_ENTRY:
{
if (!ride_is_vehicle_type_valid(ride, value))
{
log_error("Invalid vehicle type.");
return MONEY32_UNDEFINED;
}
if (!(flags & GAME_COMMAND_FLAG_APPLY))
{
return 0;
}
ride_clear_for_construction(ride);
ride_remove_peeps(ride);
ride->vehicle_change_timeout = 100;
invalidate_test_results(ride);
ride->subtype = value;
rideEntry = get_ride_entry(ride->subtype);
uint8_t preset = ex;
if (!(flags & GAME_COMMAND_FLAG_NETWORKED))
{
preset = ride_get_unused_preset_vehicle_colour(ride->subtype);
}
// Validate preset
vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list;
if (preset >= presetList->count)
{
log_error("Unknown vehicle colour preset.");
return MONEY32_UNDEFINED;
}
ride_set_vehicle_colours_to_random_preset(ride, preset);
if (!gCheatsDisableTrainLengthLimit)
{
ride->proposed_num_cars_per_train = std::clamp(
ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train);
}
break;
}
default:
log_error("Unknown vehicle command.");
return MONEY32_UNDEFINED;
}
ride->num_circuits = 1;
ride_update_max_vehicles(ride);
if (ride->overall_view.xy != RCT_XY8_UNDEFINED)
{
LocationXYZ16 coord;
coord.x = ride->overall_view.x * 32 + 16;
coord.y = ride->overall_view.y * 32 + 16;
coord.z = tile_element_height(coord.x, coord.y);
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
}
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE);
intent.putExtra(INTENT_EXTRA_RIDE_ID, rideIndex);
windowManager->BroadcastIntent(intent);
gfx_invalidate_screen();
return 0;
}
/**
*
* rct2: 0x006B52D4
*/
void game_command_set_ride_vehicles(
int32_t* eax, int32_t* ebx, [[maybe_unused]] int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi, [[maybe_unused]] int32_t* ebp)
{
ride_id_t rideIndex = *edx & 0xFF;
uint8_t setting = (*ebx >> 8) & 0xFF;
uint8_t value = (*edx >> 8) & 0xFF;
uint32_t flags = *ebx;
uint8_t ex = *eax & 0xFF;
*ebx = ride_set_vehicles(rideIndex, setting, value, flags, ex);
auto rideSetVehicleAction = RideSetVehicleAction(ride->id, RideSetVehicleType::NumCarsPerTrain, numCarsPerVehicle);
GameActions::Execute(&rideSetVehicleAction);
}
/**

View File

@ -13,6 +13,7 @@
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../actions/LargeSceneryRemoveAction.hpp"
#include "../actions/RideSetVehiclesAction.hpp"
#include "../actions/SmallSceneryRemoveAction.hpp"
#include "../actions/TrackPlaceAction.hpp"
#include "../actions/TrackRemoveAction.hpp"
@ -1960,13 +1961,17 @@ static money32 place_track_design(int16_t x, int16_t y, int16_t z, uint8_t flags
if (entryIndex != 0xFF)
{
game_do_command(0, flags | (2 << 8), 0, ride->id | (entryIndex << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
auto colour = ride_get_unused_preset_vehicle_colour(entryIndex);
auto rideSetVehicleAction = RideSetVehicleAction(ride->id, RideSetVehicleType::RideEntry, entryIndex, colour);
GameActions::ExecuteNested(&rideSetVehicleAction);
}
game_do_command(0, flags | (td6->ride_mode << 8), 0, ride->id | (0 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0);
game_do_command(0, flags | (0 << 8), 0, ride->id | (td6->number_of_trains << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
game_do_command(
0, flags | (1 << 8), 0, ride->id | (td6->number_of_cars_per_train << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0);
auto rideSetVehicleAction2 = RideSetVehicleAction(ride->id, RideSetVehicleType::NumTrains, td6->number_of_trains);
GameActions::ExecuteNested(&rideSetVehicleAction2);
auto rideSetVehicleAction3 = RideSetVehicleAction(
ride->id, RideSetVehicleType::NumCarsPerTrain, td6->number_of_cars_per_train);
GameActions::ExecuteNested(&rideSetVehicleAction3);
game_do_command(0, flags | (td6->depart_flags << 8), 0, ride->id | (1 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0);
game_do_command(0, flags | (td6->min_waiting_time << 8), 0, ride->id | (2 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0);
game_do_command(0, flags | (td6->max_waiting_time << 8), 0, ride->id | (3 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0);