diff --git a/src/openrct2/actions/GameAction.cpp b/src/openrct2/actions/GameAction.cpp index 2ec2a0e036..0f2773c892 100644 --- a/src/openrct2/actions/GameAction.cpp +++ b/src/openrct2/actions/GameAction.cpp @@ -190,10 +190,10 @@ namespace GameActions } // Call callback for asynchronous events - const std::function& cb = action->GetCallback(); + const GameActionCallback_t& cb = action->GetCallback(); if (cb) { - cb(); + cb(action, result); } if (result.Error != GA_ERROR::OK && !(flags & GAME_COMMAND_FLAG_GHOST)) diff --git a/src/openrct2/actions/GameAction.h b/src/openrct2/actions/GameAction.h index dc4b71fa41..dcaa5861db 100644 --- a/src/openrct2/actions/GameAction.h +++ b/src/openrct2/actions/GameAction.h @@ -23,11 +23,10 @@ extern "C" { #include "IGameAction.h" typedef IGameAction *(*GameActionFactory)(); -using GameActionCallback = std::function; template struct GameAction : public IGameAction -{ +{ public: constexpr static uint32 Type = _TYPE; constexpr static uint16 ActionFlags = _ACTFLAGS; @@ -36,7 +35,7 @@ private: uint32 _playerId; // Callee uint32 _flags; // GAME_COMMAND_FLAGS uint32 _networkId; - std::function _callback; + GameActionCallback_t _callback; public: GameAction() : _playerId(0), _flags(0), _networkId(0) @@ -79,12 +78,12 @@ public: return Type; } - virtual void SetCallback(const std::function& cb) + virtual void SetCallback(const GameActionCallback_t& cb) { _callback = cb; } - virtual const std::function& GetCallback() const + virtual const GameActionCallback_t& GetCallback() const { return _callback; } diff --git a/src/openrct2/actions/GameActionCompat.cpp b/src/openrct2/actions/GameActionCompat.cpp index 57552988a1..df26e64cb3 100644 --- a/src/openrct2/actions/GameActionCompat.cpp +++ b/src/openrct2/actions/GameActionCompat.cpp @@ -1,5 +1,6 @@ #include "PlaceParkEntranceAction.hpp" #include "SetParkEntranceFeeAction.hpp" +#include "RideCreateAction.hpp" extern "C" { @@ -70,10 +71,6 @@ extern "C" { auto gameAction = SetParkEntranceFeeAction(); gameAction.Fee = (money16)value; - gameAction.SetCallback([]() - { - log_info("GameAction Callback executed"); - }); GameActions::Execute(&gameAction); } @@ -84,4 +81,39 @@ extern "C" GameActions::Execute(&gameAction); } #pragma endregion + +#pragma region RideCreateAction + /** + * + * rct2: 0x006B4800 + */ + void ride_construct_new(ride_list_item listItem) + { + auto gameAction = RideCreateAction(); + gameAction.rideType = listItem.type; + gameAction.rideSubType = listItem.entry_index; + gameAction.SetCallback([](const IGameAction *ga, GameActionResult& res) + { + if (res.Error != GA_ERROR::OK) + return; + + ride_construct(static_cast(res).RideIndex()); + }); + + GameActions::Execute(&gameAction); + } + + /** + * + * rct2: 0x006B3F0F + */ + void game_command_create_ride(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp) + { + ride_list_item tmp; + tmp.ride_type_and_entry = (uint16)*edx; + ride_construct_new(tmp); + } + +#pragma endregion + } diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index f1b196f3de..d7da40516e 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -1,6 +1,7 @@ #include "GameAction.h" #include "PlaceParkEntranceAction.hpp" #include "SetParkEntranceFeeAction.hpp" +#include "RideCreateAction.hpp" namespace GameActions { @@ -8,6 +9,7 @@ void Register() { Register(); Register(); + Register(); } } \ No newline at end of file diff --git a/src/openrct2/actions/IGameAction.h b/src/openrct2/actions/IGameAction.h index 16137ae8e6..377d01bc25 100644 --- a/src/openrct2/actions/IGameAction.h +++ b/src/openrct2/actions/IGameAction.h @@ -69,12 +69,14 @@ struct GameActionResult rct_xyz32 Position = { 0 }; money32 Cost = 0; uint16 ExpenditureType = 0; - void * Tag = nullptr; + uint64 Results[4]; GameActionResult(); GameActionResult(GA_ERROR error, rct_string_id message); }; +typedef std::function GameActionCallback_t; + /** * Represents an action that changes the state of the game. Can be serialised and * deserialised into a stream. @@ -101,8 +103,8 @@ public: virtual void SetPlayer(uint32 playerId) abstract; virtual uint32 GetPlayer() const abstract; - virtual void SetCallback(const std::function& cb) abstract; - virtual const std::function& GetCallback() const abstract; + virtual void SetCallback(const GameActionCallback_t& cb) abstract; + virtual const GameActionCallback_t& GetCallback() const abstract; virtual void SetNetworkId(uint32_t id) abstract; virtual uint32 GetNetworkId() const abstract; diff --git a/src/openrct2/actions/RideCreateAction.hpp b/src/openrct2/actions/RideCreateAction.hpp new file mode 100644 index 0000000000..a212d183d5 --- /dev/null +++ b/src/openrct2/actions/RideCreateAction.hpp @@ -0,0 +1,288 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* OpenRCT2 is the work of many authors, a full list can be found in contributors.md +* For more information, visit https://github.com/OpenRCT2/OpenRCT2 +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* A full copy of the GNU General Public License can be found in licence.txt +*****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../core/MemoryStream.h" +#include "../localisation/string_ids.h" +#include "GameAction.h" + +extern "C" +{ +#include "../localisation/date.h" +#include "../cheats.h" +#include "../interface/window.h" +#include "../world/park.h" +#include "../rct1.h" +#include "../ride/ride_data.h" +#include "../ride/ride.h" +} + +struct RideCreateGameActionResult : public GameActionResult { + RideCreateGameActionResult() {} + RideCreateGameActionResult(GA_ERROR error, rct_string_id message) : GameActionResult(error, message) {} + + sint32& RideIndex() + { + return reinterpret_cast(Results[0]); + } + + uint32& RideColor() + { + return reinterpret_cast(Results[1]); + } +}; + +struct RideCreateAction : public GameAction +{ +public: + sint32 rideType; + sint32 rideSubType; + + void Serialise(DataSerialiser& stream) override + { + stream << rideType << rideSubType; + } + + GameActionResult Query() const override + { + if (rideType >= RIDE_TYPE_COUNT) + { + return RideCreateGameActionResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE); + } + + return GameActionResult(); + } + + GameActionResult Execute() const override + { + RideCreateGameActionResult res; + + rct_ride *ride; + rct_ride_entry *rideEntry; + sint32 rideIndex, rideEntryIndex; + sint32 subType = rideSubType; + + if (subType == RIDE_ENTRY_INDEX_NULL) + { + uint8 *availableRideEntries = get_ride_entry_indices_for_ride_type(rideType); + for (uint8 *rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++) { + rideEntry = get_ride_entry(*rei); + + // Can happen in select-by-track-type mode + if (!ride_entry_is_invented(*rei)) + { + continue; + } + + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) { + subType = *rei; + break; + } + } + if (subType == RIDE_ENTRY_INDEX_NULL) + { + subType = availableRideEntries[0]; + if (subType == RIDE_ENTRY_INDEX_NULL) { + return RideCreateGameActionResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE); + } + } + } + + rideEntryIndex = subType; + rideIndex = ride_get_empty_slot(); + + if (subType >= 128) + { + return RideCreateGameActionResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE); + } + + if (rideIndex == -1) + { + return RideCreateGameActionResult(GA_ERROR::DISALLOWED, STR_TOO_MANY_RIDES); + } + + res.RideIndex() = rideIndex; + res.RideColor() = ride_get_random_colour_preset_index(rideType) | (ride_get_unused_preset_vehicle_colour(rideType, subType) << 8); + + ride = get_ride(rideIndex); + rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == (rct_ride_entry *)-1) + { + log_warning("Invalid request for ride %u", rideIndex); + return RideCreateGameActionResult(GA_ERROR::UNKNOWN, STR_UNKNOWN_OBJECT_TYPE); + } + + ride->type = rideType; + ride->subtype = rideEntryIndex; + ride_set_colour_preset(ride, res.RideColor() & 0xFF); + ride->overall_view = 0xFFFF; + + // Ride name + if (rideEntryIndex == RIDE_ENTRY_INDEX_NULL) + { + ride_set_name_to_track_default(ride, rideEntry); + } + else + { + ride_set_name_to_default(ride, rideEntry); + } + + for (size_t i = 0; i < RCT12_MAX_STATIONS_PER_RIDE; i++) { + ride->station_starts[i] = 0xFFFF; + ride->entrances[i] = 0xFFFF; + ride->exits[i] = 0xFFFF; + ride->train_at_station[i] = 255; + ride->queue_time[i] = 0; + } + + for (size_t i = 0; i < MAX_VEHICLES_PER_RIDE; i++) { + ride->vehicles[i] = SPRITE_INDEX_NULL; + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags = 0; + ride->vehicle_change_timeout = 0; + ride->num_stations = 0; + ride->num_vehicles = 1; + ride->proposed_num_vehicles = 32; + ride->max_trains = 32; + ride->num_cars_per_train = 1; + ride->proposed_num_cars_per_train = 12; + ride->min_waiting_time = 10; + ride->max_waiting_time = 60; + ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT) { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + ride->music = RideData4[ride->type].default_music; + + const rct_ride_properties rideProperties = RideProperties[ride->type]; + ride->operation_option = (rideProperties.min_value * 3 + rideProperties.max_value) / 4; + + ride->lift_hill_speed = RideLiftData[ride->type].minimum_speed; + + ride->measurement_index = 255; + ride->excitement = (ride_rating)-1; + ride->cur_num_customers = 0; + ride->num_customers_timeout = 0; + ride->chairlift_bullwheel_rotation = 0; + + ride->price = 0; + ride->price_secondary = 0; + if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) { + ride->price = RideData4[ride->type].price; + ride->price_secondary = RideData4[ride->type].price_secondary; + + if (rideEntry->shop_item == SHOP_ITEM_NONE) { + if (!(gParkFlags & PARK_FLAGS_PARK_FREE_ENTRY) && !gCheatsUnlockAllPrices) { + ride->price = 0; + } + } + else { + ride->price = DefaultShopItemPrice[rideEntry->shop_item]; + } + if (rideEntry->shop_item_secondary != SHOP_ITEM_NONE) { + ride->price_secondary = DefaultShopItemPrice[rideEntry->shop_item_secondary]; + } + + if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) { + ride->price = 0; + } + + if (ride->type == RIDE_TYPE_TOILETS) { + if (shop_item_has_common_price(SHOP_ITEM_ADMISSION)) { + money32 price = ride_get_common_price(ride); + if (price != MONEY32_UNDEFINED) { + ride->price = (money16)price; + } + } + } + + if (rideEntry->shop_item != SHOP_ITEM_NONE) { + if (shop_item_has_common_price(rideEntry->shop_item)) { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item); + if (price != MONEY32_UNDEFINED) { + ride->price = (money16)price; + } + } + } + + if (rideEntry->shop_item_secondary != SHOP_ITEM_NONE) { + if (shop_item_has_common_price(rideEntry->shop_item_secondary)) { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item_secondary); + if (price != MONEY32_UNDEFINED) { + ride->price_secondary = (money16)price; + } + } + } + + // Set the on-ride photo price, whether the ride has one or not (except shops). + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(SHOP_ITEM_PHOTO)) { + money32 price = shop_item_get_common_price(ride, SHOP_ITEM_PHOTO); + if (price != MONEY32_UNDEFINED) { + ride->price_secondary = (money16)price; + } + } + } + + memset(ride->num_customers, 0, sizeof(ride->num_customers)); + ride->value = 0xFFFF; + ride->satisfaction = 255; + ride->satisfaction_time_out = 0; + ride->satisfaction_next = 0; + ride->popularity = 255; + ride->popularity_time_out = 0; + ride->popularity_next = 0; + ride->window_invalidate_flags = 0; + ride->total_customers = 0; + ride->total_profit = 0; + ride->num_riders = 0; + ride->slide_in_use = 0; + ride->maze_tiles = 0; + ride->build_date = gDateMonthsElapsed; + ride->music_tune_id = 255; + + ride->breakdown_reason = 255; + ride->upkeep_cost = (money16)-1; + ride->reliability = 0x64FF; + ride->unreliability_factor = 1; + ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; + ride->last_inspection = 0; + ride->downtime = 0; + memset(ride->downtime_history, 0, sizeof(ride->downtime_history)); + ride->no_primary_items_sold = 0; + ride->no_secondary_items_sold = 0; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + ride->income_per_hour = MONEY32_UNDEFINED; + ride->profit = MONEY32_UNDEFINED; + ride->connected_message_throttle = 0; + ride->entrance_style = RIDE_ENTRANCE_STYLE_PLAIN; + ride->num_block_brakes = 0; + ride->guests_favourite = 0; + + ride->num_circuits = 1; + ride->mode = ride_get_default_mode(ride); + ride->min_max_cars_per_train = (rideEntry->min_cars_in_train << 4) | rideEntry->max_cars_in_train; + ride_set_vehicle_colours_to_random_preset(ride, 0xFF & (res.RideColor() >> 8)); + window_invalidate_by_class(WC_RIDE_LIST); + + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + gCommandPosition.x = (uint16)0x8000; + return res; + } +}; + diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 518211215f..a9d9cb0de0 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -82,7 +82,7 @@ uint32 gCurrentTicks; GAME_COMMAND_CALLBACK_POINTER* game_command_callback = 0; GAME_COMMAND_CALLBACK_POINTER* game_command_callback_table[] = { 0, - game_command_callback_ride_construct_new, + 0, game_command_callback_ride_construct_placed_front, game_command_callback_ride_construct_placed_back, game_command_callback_ride_remove_track_piece, diff --git a/src/openrct2/network/network.h b/src/openrct2/network/network.h index 566fe9038c..0a5e8a5614 100644 --- a/src/openrct2/network/network.h +++ b/src/openrct2/network/network.h @@ -76,7 +76,7 @@ typedef struct IGameAction IGameAction; #include "NetworkServerAdvertiser.h" #include "NetworkUser.h" #include "TcpSocket.h" - +#include "../actions/IGameAction.h" enum { NETWORK_TICK_FLAG_CHECKSUMS = 1 << 0, @@ -169,7 +169,7 @@ public: std::vector> group_list; NetworkKey _key; std::vector _challenge; - std::map> _gameActionCallbacks; + std::map _gameActionCallbacks; NetworkUserManager _userManager; std::string ServerName; diff --git a/src/openrct2/ride/ride.c b/src/openrct2/ride/ride.c index 700e57bf17..86323cc8a2 100644 --- a/src/openrct2/ride/ride.c +++ b/src/openrct2/ride/ride.c @@ -205,6 +205,7 @@ static void ride_call_closest_mechanic(sint32 rideIndex); static void ride_call_mechanic(sint32 rideIndex, rct_peep *mechanic, sint32 forInspection); static void ride_chairlift_update(Ride *ride); static void ride_entrance_exit_connected(Ride* ride, sint32 ride_idx); +static void ride_set_name_to_vehicle_default(rct_ride * ride, rct_ride_entry * rideEntry); static sint32 ride_get_new_breakdown_problem(Ride *ride); static void ride_inspection_update(Ride *ride); static void ride_mechanic_status_update(sint32 rideIndex, sint32 mechanicStatus); @@ -213,10 +214,7 @@ static void ride_shop_connected(Ride* ride, sint32 ride_idx); static void ride_spiral_slide_update(Ride *ride); static void ride_update(sint32 rideIndex); static void ride_update_vehicle_colours(sint32 rideIndex); -static void ride_set_vehicle_colours_to_random_preset(Ride *ride, uint8 preset_index); void loc_6DDF9C(Ride *ride, rct_map_element *mapElement); -static void ride_set_name_to_track_default(Ride * ride, rct_ride_entry * rideEntry); -static void ride_set_name_to_vehicle_default(Ride * ride, rct_ride_entry * rideEntry); Ride *get_ride(sint32 index) @@ -1016,33 +1014,6 @@ static rct_window *ride_create_or_find_construction_window(sint32 rideIndex) return w; } -static sint32 ride_create_ride(ride_list_item listItem) -{ - sint32 eax, ebx, ecx, edx, esi, edi, ebp; - edx = listItem.ride_type_and_entry; - eax = 0; - ecx = 0; - ebx = GAME_COMMAND_FLAG_APPLY; - edi = 0; - esi = GAME_COMMAND_CREATE_RIDE; - ebp = 0; - - gGameCommandErrorTitle = STR_CANT_CREATE_NEW_RIDE_ATTRACTION; - - game_do_command_p(esi, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx == MONEY32_UNDEFINED ? -1 : edi; -} - -/** - * - * rct2: 0x006B4800 - */ -void ride_construct_new(ride_list_item listItem) -{ - game_command_callback = game_command_callback_ride_construct_new; - ride_create_ride(listItem); -} - /** * * rct2: 0x006B4857 @@ -3134,7 +3105,7 @@ static bool ride_does_vehicle_colour_exist(uint8 ride_sub_type, vehicle_colour * return true; } -static sint32 ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_sub_type) +sint32 ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_sub_type) { if (ride_sub_type >= 128) { @@ -3167,7 +3138,7 @@ static sint32 ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_ * * rct2: 0x006DE52C */ -static void ride_set_vehicle_colours_to_random_preset(Ride *ride, uint8 preset_index) +void ride_set_vehicle_colours_to_random_preset(Ride *ride, uint8 preset_index) { rct_ride_entry *rideEntry = get_ride_entry(ride->subtype); vehicle_colour_preset_list *presetList = rideEntry->vehicle_preset_list; @@ -5814,7 +5785,7 @@ static void ride_stop_peeps_queuing(sint32 rideIndex) } } -static sint32 ride_get_empty_slot() +sint32 ride_get_empty_slot() { for (sint32 i = 0; i < MAX_RIDES; i++) { Ride *ride = get_ride(i); @@ -5825,7 +5796,7 @@ static sint32 ride_get_empty_slot() return -1; } -static sint32 ride_get_default_mode(Ride *ride) +sint32 ride_get_default_mode(Ride *ride) { const rct_ride_entry *rideEntry = get_ride_entry(ride->subtype); const uint8 *availableModes = RideAvailableModes; @@ -5876,7 +5847,7 @@ static bool ride_name_exists(char *name) * * Based on rct2: 0x006B4776 */ -static sint32 ride_get_random_colour_preset_index(uint8 ride_type) +sint32 ride_get_random_colour_preset_index(uint8 ride_type) { if (ride_type >= 128) { @@ -5901,7 +5872,7 @@ static sint32 ride_get_random_colour_preset_index(uint8 ride_type) * * Based on rct2: 0x006B4776 */ -static void ride_set_colour_preset(Ride *ride, uint8 index) +void ride_set_colour_preset(Ride *ride, uint8 index) { const track_colour_preset_list * colourPresets = &RideColourPresets[ride->type]; track_colour colours = { COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK }; @@ -5916,7 +5887,7 @@ static void ride_set_colour_preset(Ride *ride, uint8 index) ride->colour_scheme_type = 0; } -static money32 ride_get_common_price(Ride *forRide) +money32 ride_get_common_price(Ride *forRide) { Ride *ride; sint32 i; @@ -5930,7 +5901,7 @@ static money32 ride_get_common_price(Ride *forRide) return MONEY32_UNDEFINED; } -static money32 shop_item_get_common_price(Ride *forRide, sint32 shopItem) +money32 shop_item_get_common_price(Ride *forRide, sint32 shopItem) { rct_ride_entry *rideEntry; Ride *ride; @@ -5989,243 +5960,6 @@ money32 ride_create_command(sint32 type, sint32 subType, sint32 flags, uint8 *ou return cost; } -/** - * - * rct2: 0x006B3F0F - */ -static money32 ride_create(sint32 type, sint32 subType, sint32 flags, sint32 *outRideIndex, sint32 *outRideColour) -{ - Ride *ride; - rct_ride_entry *rideEntry; - sint32 rideIndex, rideEntryIndex; - - if (type >= RIDE_TYPE_COUNT) - { - log_warning("Invalid request for ride type %u", type); - return MONEY32_UNDEFINED; - } - - if (subType == RIDE_ENTRY_INDEX_NULL) { - uint8 *availableRideEntries = get_ride_entry_indices_for_ride_type(type); - for (uint8 *rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++) { - rideEntry = get_ride_entry(*rei); - - // Can happen in select-by-track-type mode - if (!ride_entry_is_invented(*rei) && !gCheatsIgnoreResearchStatus) - { - continue; - } - - if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) { - subType = *rei; - goto foundRideEntry; - } - } - subType = availableRideEntries[0]; - if (subType == RIDE_ENTRY_INDEX_NULL) { - return MONEY32_UNDEFINED; - } - } - -foundRideEntry: - rideEntryIndex = subType; - rideIndex = ride_get_empty_slot(); - if (subType >= 128) - { - log_warning("Invalid request for ride entry %u", subType); - return MONEY32_UNDEFINED; - } - if (rideIndex == -1) { - gGameCommandErrorText = STR_TOO_MANY_RIDES; - return MONEY32_UNDEFINED; - } - *outRideIndex = rideIndex; - - // Ride/vehicle colour is calculated before applying to ensure - // correct colour is passed over the network. - if (!(flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_NETWORKED)) { - *outRideColour = - ride_get_random_colour_preset_index(type) | - (ride_get_unused_preset_vehicle_colour(type, subType) << 8); - } - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) { - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; - gCommandPosition.x = 0x8000; - return 0; - } - - ride = get_ride(rideIndex); - rideEntry = get_ride_entry(rideEntryIndex); - if (rideEntry == (rct_ride_entry *)-1) - { - log_warning("Invalid request for ride %u", rideIndex); - return MONEY32_UNDEFINED; - } - ride->type = type; - ride->subtype = rideEntryIndex; - ride_set_colour_preset(ride, *outRideColour & 0xFF); - ride->overall_view.xy = RCT_XY8_UNDEFINED; - - // Ride name - if (rideEntryIndex == RIDE_ENTRY_INDEX_NULL) - { - ride_set_name_to_track_default(ride, rideEntry); - } - else - { - ride_set_name_to_default(ride, rideEntry); - } - - for (size_t i = 0; i < MAX_STATIONS; i++) { - ride->station_starts[i].xy = RCT_XY8_UNDEFINED; - ride->entrances[i].xy = RCT_XY8_UNDEFINED; - ride->exits[i].xy = RCT_XY8_UNDEFINED; - ride->train_at_station[i] = 255; - ride->queue_time[i] = 0; - } - - for (size_t i = 0; i < MAX_VEHICLES_PER_RIDE; i++) { - ride->vehicles[i] = SPRITE_INDEX_NULL; - } - - ride->status = RIDE_STATUS_CLOSED; - ride->lifecycle_flags = 0; - ride->vehicle_change_timeout = 0; - ride->num_stations = 0; - ride->num_vehicles = 1; - ride->proposed_num_vehicles = 32; - ride->max_trains = 32; - ride->num_cars_per_train = 1; - ride->proposed_num_cars_per_train = 12; - ride->min_waiting_time = 10; - ride->max_waiting_time = 60; - ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | WAIT_FOR_LOAD_FULL; - if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT) { - ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; - } - ride->music = RideData4[ride->type].default_music; - - const rct_ride_properties rideProperties = RideProperties[ride->type]; - ride->operation_option = (rideProperties.min_value * 3 + rideProperties.max_value) / 4; - - ride->lift_hill_speed = RideLiftData[ride->type].minimum_speed; - - ride->measurement_index = 255; - ride->excitement = (ride_rating)-1; - ride->cur_num_customers = 0; - ride->num_customers_timeout = 0; - ride->chairlift_bullwheel_rotation = 0; - - ride->price = 0; - ride->price_secondary = 0; - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) { - ride->price = RideData4[ride->type].price; - ride->price_secondary = RideData4[ride->type].price_secondary; - - if (rideEntry->shop_item == SHOP_ITEM_NONE) { - if (!(gParkFlags & PARK_FLAGS_PARK_FREE_ENTRY) && !gCheatsUnlockAllPrices) { - ride->price = 0; - } - } else { - ride->price = DefaultShopItemPrice[rideEntry->shop_item]; - } - if (rideEntry->shop_item_secondary != SHOP_ITEM_NONE) { - ride->price_secondary = DefaultShopItemPrice[rideEntry->shop_item_secondary]; - } - - if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) { - ride->price = 0; - } - - if (ride->type == RIDE_TYPE_TOILETS) { - if (shop_item_has_common_price(SHOP_ITEM_ADMISSION)) { - money32 price = ride_get_common_price(ride); - if (price != MONEY32_UNDEFINED) { - ride->price = (money16)price; - } - } - } - - if (rideEntry->shop_item != SHOP_ITEM_NONE) { - if (shop_item_has_common_price(rideEntry->shop_item)) { - money32 price = shop_item_get_common_price(ride, rideEntry->shop_item); - if (price != MONEY32_UNDEFINED) { - ride->price = (money16)price; - } - } - } - - if (rideEntry->shop_item_secondary != SHOP_ITEM_NONE) { - if (shop_item_has_common_price(rideEntry->shop_item_secondary)) { - money32 price = shop_item_get_common_price(ride, rideEntry->shop_item_secondary); - if (price != MONEY32_UNDEFINED) { - ride->price_secondary = (money16)price; - } - } - } - - // Set the on-ride photo price, whether the ride has one or not (except shops). - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(SHOP_ITEM_PHOTO)) { - money32 price = shop_item_get_common_price(ride, SHOP_ITEM_PHOTO); - if (price != MONEY32_UNDEFINED) { - ride->price_secondary = (money16)price; - } - } - } - - memset(ride->num_customers, 0, sizeof(ride->num_customers)); - ride->value = 0xFFFF; - ride->satisfaction = 255; - ride->satisfaction_time_out = 0; - ride->satisfaction_next = 0; - ride->popularity = 255; - ride->popularity_time_out = 0; - ride->popularity_next = 0; - ride->window_invalidate_flags = 0; - ride->total_customers = 0; - ride->total_profit = 0; - ride->num_riders = 0; - ride->slide_in_use = 0; - ride->maze_tiles = 0; - ride->build_date = gDateMonthsElapsed; - ride->music_tune_id = 255; - - ride->breakdown_reason = 255; - ride->upkeep_cost = (money16)-1; - ride->reliability = RIDE_INITIAL_RELIABILITY; - ride->unreliability_factor = 1; - ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; - ride->last_inspection = 0; - ride->downtime = 0; - memset(ride->downtime_history, 0, sizeof(ride->downtime_history)); - ride->no_primary_items_sold = 0; - ride->no_secondary_items_sold = 0; - ride->last_crash_type = RIDE_CRASH_TYPE_NONE; - ride->income_per_hour = MONEY32_UNDEFINED; - ride->profit = MONEY32_UNDEFINED; - ride->connected_message_throttle = 0; - ride->entrance_style = RIDE_ENTRANCE_STYLE_PLAIN; - ride->num_block_brakes = 0; - ride->guests_favourite = 0; - - ride->num_circuits = 1; - ride->mode = ride_get_default_mode(ride); - ride->min_max_cars_per_train = (rideEntry->min_cars_in_train << 4) | rideEntry->max_cars_in_train; - ride_set_vehicle_colours_to_random_preset(ride, 0xFF & (*outRideColour >> 8)); - window_invalidate_by_class(WC_RIDE_LIST); - - // Log ride creation - if (network_get_mode() == NETWORK_MODE_SERVER) { - int ebp = 1; - game_log_multiplayer_command(GAME_COMMAND_CREATE_RIDE, 0, 0, 0, &rideIndex, 0, &ebp); - } - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; - gCommandPosition.x = 0x8000; - return 0; -} - void ride_set_name_to_default(Ride * ride, rct_ride_entry * rideEntry) { if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) { @@ -6235,7 +5969,7 @@ void ride_set_name_to_default(Ride * ride, rct_ride_entry * rideEntry) } } -static void ride_set_name_to_track_default(Ride *ride, rct_ride_entry * rideEntry) +void ride_set_name_to_track_default(Ride *ride, rct_ride_entry * rideEntry) { char rideNameBuffer[256]; ride_name_args name_args; @@ -6312,22 +6046,6 @@ rct_ride_name get_ride_naming(uint8 rideType, rct_ride_entry * rideEntry) } } -/** - * - * rct2: 0x006B3F0F - */ -void game_command_create_ride(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp) -{ - *ebx = ride_create(*edx & 0xFF, (*edx >> 8) & 0xFF, *ebx, edi, eax); -} - -void game_command_callback_ride_construct_new(sint32 eax, sint32 ebx, sint32 ecx, sint32 edx, sint32 esi, sint32 edi, sint32 ebp) -{ - sint32 rideIndex = edi; - if (rideIndex != -1) - ride_construct(rideIndex); -} - /** * * Network client callback when placing ride pieces diff --git a/src/openrct2/ride/ride.h b/src/openrct2/ride/ride.h index 470f940dd8..108e3990e2 100644 --- a/src/openrct2/ride/ride.h +++ b/src/openrct2/ride/ride.h @@ -1021,6 +1021,8 @@ extern sint32 gRideRemoveTrackPieceCallbackType; extern uint8 gLastEntranceStyle; +sint32 ride_get_empty_slot(); +sint32 ride_get_default_mode(Ride *ride); sint32 ride_get_count(); sint32 ride_get_total_queue_length(Ride *ride); sint32 ride_get_max_queue_time(Ride *ride); @@ -1050,6 +1052,8 @@ sint32 ride_get_total_time(Ride *ride); sint32 ride_can_have_multiple_circuits(Ride *ride); track_colour ride_get_track_colour(Ride *ride, sint32 colourScheme); vehicle_colour ride_get_vehicle_colour(Ride *ride, sint32 vehicleIndex); +sint32 ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_sub_type); +void ride_set_vehicle_colours_to_random_preset(Ride *ride, uint8 preset_index); rct_ride_entry *get_ride_entry_by_ride(Ride *ride); uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType); void reset_type_to_ride_entry_index_map(); @@ -1073,6 +1077,10 @@ void ride_set_name(sint32 rideIndex, const char *name); void game_command_set_ride_name(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); void game_command_set_ride_setting(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); sint32 ride_get_refund_price(sint32 ride_id); +sint32 ride_get_random_colour_preset_index(uint8 ride_type); +void ride_set_colour_preset(Ride *ride, uint8 index); +money32 ride_get_common_price(Ride *forRide); +money32 shop_item_get_common_price(Ride *forRide, sint32 shopItem); bool shop_item_is_photo(sint32 shopItem); bool shop_item_has_common_price(sint32 shopItem); rct_ride_name get_ride_naming(uint8 rideType, rct_ride_entry * rideEntry);