Fix single player pre-designed rides not working.

Move ride_create_command into GameActionCompat
Refactor GameActions to return the GA_FLAGS instead of using the const value.
Refactor passing params to GameActions over constructor.
This commit is contained in:
ZehMatt 2017-09-04 21:37:58 +02:00 committed by Michał Janiszewski
parent 89c020d3fe
commit ce54b41aba
8 changed files with 160 additions and 115 deletions

View File

@ -137,7 +137,7 @@ namespace GameActions
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
// As a client we have to wait or send it first.
if (!(actionFlags & GA_FLAGS::CLIENT_ONLY) && !(flags & GAME_COMMAND_FLAG_GHOST) && !(flags & GAME_COMMAND_FLAG_NETWORKED))
if (!(actionFlags & GA_FLAGS::CLIENT_ONLY) && !(flags & GAME_COMMAND_FLAG_NETWORKED))
{
log_info("[%s] GameAction::Execute\n", "cl");
@ -150,7 +150,7 @@ namespace GameActions
{
// If player is the server it would execute right away as where clients execute the commands
// at the beginning of the frame, so we have to put them into the queue.
if (!(actionFlags & GA_FLAGS::CLIENT_ONLY) && !(flags & GAME_COMMAND_FLAG_GHOST) && !(flags & GAME_COMMAND_FLAG_NETWORKED))
if (!(actionFlags & GA_FLAGS::CLIENT_ONLY) && !(flags & GAME_COMMAND_FLAG_NETWORKED))
{
log_info("[%s] GameAction::Execute\n", "sv-cl");
network_enqueue_game_action(action);

View File

@ -93,7 +93,6 @@ public:
private:
uint32 const _type;
uint16 const _actionFlags;
uint32 _playerId = 0; // Callee
uint32 _flags = 0; // GAME_COMMAND_FLAGS
@ -101,9 +100,8 @@ private:
Callback_t _callback;
public:
GameAction(uint32 type, uint16 actionFlags)
: _type(type),
_actionFlags(actionFlags)
GameAction(uint32 type)
: _type(type)
{
}
@ -122,9 +120,16 @@ public:
/**
* Gets the GA_FLAGS flags that are enabled for this game action.
*/
uint16 GetActionFlags() const
virtual uint16 GetActionFlags() const
{
return _actionFlags;
// Make sure we execute some things only on the client.
if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) != 0 ||
(GetFlags() & GAME_COMMAND_FLAG_5) != 0)
{
return GA_FLAGS::CLIENT_ONLY;
}
return 0;
}
/**
@ -193,14 +198,16 @@ public:
#pragma GCC diagnostic pop
#endif
template<uint32 TType, uint16 TActionFlags, typename TResultType>
template<uint32 TType, typename TResultType>
struct GameActionBase : GameAction
{
public:
typedef TResultType Result;
static constexpr uint32 TYPE = TType;
GameActionBase()
: GameAction(TYPE, TActionFlags)
: GameAction(TYPE)
{
}

View File

@ -14,6 +14,7 @@
*****************************************************************************/
#pragma endregion
#include "GameAction.h"
#include "PlaceParkEntranceAction.hpp"
#include "SetParkEntranceFeeAction.hpp"
#include "RideCreateAction.hpp"
@ -24,11 +25,7 @@ extern "C"
#pragma region PlaceParkEntranceAction
money32 place_park_entrance(sint16 x, sint16 y, sint16 z, uint8 direction)
{
auto gameAction = PlaceParkEntranceAction();
gameAction.x = x;
gameAction.y = y;
gameAction.z = z;
gameAction.direction = direction;
auto gameAction = PlaceParkEntranceAction(x, y, z, direction);
auto result = GameActions::Execute(&gameAction);
if (result->Error == GA_ERROR::OK)
{
@ -63,11 +60,7 @@ extern "C"
{
park_entrance_remove_ghost();
auto gameAction = PlaceParkEntranceAction();
gameAction.x = x;
gameAction.y = y;
gameAction.z = z;
gameAction.direction = direction;
auto gameAction = PlaceParkEntranceAction(x, y, z, direction);
gameAction.SetFlags(GAME_COMMAND_FLAG_GHOST);
auto result = GameActions::Execute(&gameAction);
@ -106,13 +99,11 @@ extern "C"
*/
void ride_construct_new(ride_list_item listItem)
{
auto gameAction = RideCreateAction();
gameAction.rideType = listItem.type;
gameAction.rideSubType = listItem.entry_index;
sint32 rideEntryIndex = ride_get_entry_index(listItem.type, listItem.entry_index);
sint32 colour1 = ride_get_random_colour_preset_index(listItem.type);
sint32 colour2 = ride_get_unused_preset_vehicle_colour(listItem.type, rideEntryIndex);
sint32 rideEntryIndex = ride_get_entry_index(gameAction.rideType, gameAction.rideSubType);
gameAction.colourPreset1 = ride_get_random_colour_preset_index(gameAction.rideType);
gameAction.colourPreset2 = ride_get_unused_preset_vehicle_colour(gameAction.rideType, rideEntryIndex);
auto gameAction = RideCreateAction(listItem.type, listItem.entry_index, colour1, colour2);
gameAction.SetCallback([](const GameAction *ga, const RideCreateGameActionResult * result)
{
@ -125,6 +116,24 @@ extern "C"
GameActions::Execute(&gameAction);
}
money32 ride_create_command(sint32 type, sint32 subType, sint32 flags, uint8 *outRideIndex, uint8 *outRideColour)
{
sint32 rideEntryIndex = ride_get_entry_index(type, subType);
sint32 colour1 = ride_get_random_colour_preset_index(type);
sint32 colour2 = ride_get_unused_preset_vehicle_colour(type, rideEntryIndex);
auto gameAction = RideCreateAction(type, subType, colour1, colour2);
gameAction.SetFlags(flags);
auto r = GameActions::Execute(&gameAction);
const RideCreateGameActionResult *res = static_cast<RideCreateGameActionResult*>(r.get());
*outRideIndex = res->rideIndex;
*outRideColour = colour1;
return res->Cost;
}
/**
*
* rct2: 0x006B3F0F
@ -140,10 +149,7 @@ extern "C"
void ride_set_status(sint32 rideIndex, sint32 status)
{
auto gameAction = RideSetStatusAction();
gameAction.RideIndex = rideIndex;
gameAction.Status = status;
auto gameAction = RideSetStatusAction(rideIndex, status);
GameActions::Execute(&gameAction);
}

View File

@ -38,19 +38,34 @@ struct PlaceParkEntranceGameActionResult : public GameActionResult
}
};
struct PlaceParkEntranceAction : public GameActionBase<GAME_COMMAND_PLACE_PARK_ENTRANCE, GA_FLAGS::EDITOR_ONLY, PlaceParkEntranceGameActionResult>
struct PlaceParkEntranceAction : public GameActionBase<GAME_COMMAND_PLACE_PARK_ENTRANCE, PlaceParkEntranceGameActionResult>
{
private:
sint16 _x;
sint16 _y;
sint16 _z;
uint8 _direction;
public:
sint16 x;
sint16 y;
sint16 z;
uint8 direction;
PlaceParkEntranceAction() {}
PlaceParkEntranceAction(sint16 x, sint16 y, sint16 z, sint16 direction) :
_x(x),
_y(y),
_z(z),
_direction(direction)
{
}
uint16 GetActionFlags() const override
{
return GameActionBase::GetActionFlags() | GA_FLAGS::EDITOR_ONLY;
}
void Serialise(DataSerialiser& stream) override
{
GameAction::Serialise(stream);
stream << x << y << z << direction;
stream << _x << _y << _z << _direction;
}
GameActionResult::Ptr Query() const override
@ -62,16 +77,16 @@ public:
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
gCommandPosition.x = x;
gCommandPosition.y = y;
gCommandPosition.z = z * 16;
gCommandPosition.x = _x;
gCommandPosition.y = _y;
gCommandPosition.z = _z * 16;
if (!map_check_free_elements_and_reorganise(3))
{
return std::make_unique<PlaceParkEntranceGameActionResult>(GA_ERROR::NO_FREE_ELEMENTS, STR_NONE);
}
if (x <= 32 || y <= 32 || x >= (gMapSizeUnits - 32) || y >= (gMapSizeUnits - 32))
if (_x <= 32 || _y <= 32 || _x >= (gMapSizeUnits - 32) || _y >= (gMapSizeUnits - 32))
{
return std::make_unique<PlaceParkEntranceGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_TOO_CLOSE_TO_EDGE_OF_MAP);
}
@ -91,20 +106,20 @@ public:
return std::make_unique<PlaceParkEntranceGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_ERR_TOO_MANY_PARK_ENTRANCES);
}
sint8 zLow = z * 2;
sint8 zLow = _z * 2;
sint8 zHigh = zLow + 12;
rct_xy16 entranceLoc = { x, y };
rct_xy16 entranceLoc = { _x, _y };
for (uint8 index = 0; index < 3; index++)
{
if (index == 1)
{
entranceLoc.x += TileDirectionDelta[(direction - 1) & 0x3].x;
entranceLoc.y += TileDirectionDelta[(direction - 1) & 0x3].y;
entranceLoc.x += TileDirectionDelta[(_direction - 1) & 0x3].x;
entranceLoc.y += TileDirectionDelta[(_direction - 1) & 0x3].y;
}
else if (index == 2)
{
entranceLoc.x += TileDirectionDelta[(direction + 1) & 0x3].x * 2;
entranceLoc.y += TileDirectionDelta[(direction + 1) & 0x3].y * 2;
entranceLoc.x += TileDirectionDelta[(_direction + 1) & 0x3].x * 2;
entranceLoc.y += TileDirectionDelta[(_direction + 1) & 0x3].y * 2;
}
if (!gCheatsDisableClearanceChecks)
@ -132,9 +147,9 @@ public:
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
gCommandPosition.x = x;
gCommandPosition.y = y;
gCommandPosition.z = z * 16;
gCommandPosition.x = _x;
gCommandPosition.y = _y;
gCommandPosition.z = _z * 16;
sint8 entranceNum = -1;
for (uint8 i = 0; i < MAX_PARK_ENTRANCES; ++i)
@ -148,25 +163,25 @@ public:
Guard::Assert(entranceNum != -1);
gParkEntrances[entranceNum].x = x;
gParkEntrances[entranceNum].y = y;
gParkEntrances[entranceNum].z = z * 16;
gParkEntrances[entranceNum].direction = direction;
gParkEntrances[entranceNum].x = _x;
gParkEntrances[entranceNum].y = _y;
gParkEntrances[entranceNum].z = _z * 16;
gParkEntrances[entranceNum].direction = _direction;
sint8 zLow = z * 2;
sint8 zLow = _z * 2;
sint8 zHigh = zLow + 12;
rct_xy16 entranceLoc = { x, y };
rct_xy16 entranceLoc = { _x, _y };
for (uint8 index = 0; index < 3; index++)
{
if (index == 1)
{
entranceLoc.x += TileDirectionDelta[(direction - 1) & 0x3].x;
entranceLoc.y += TileDirectionDelta[(direction - 1) & 0x3].y;
entranceLoc.x += TileDirectionDelta[(_direction - 1) & 0x3].x;
entranceLoc.y += TileDirectionDelta[(_direction - 1) & 0x3].y;
}
else if (index == 2)
{
entranceLoc.x += TileDirectionDelta[(direction + 1) & 0x3].x * 2;
entranceLoc.y += TileDirectionDelta[(direction + 1) & 0x3].y * 2;
entranceLoc.x += TileDirectionDelta[(_direction + 1) & 0x3].x * 2;
entranceLoc.y += TileDirectionDelta[(_direction + 1) & 0x3].y * 2;
}
if (!(flags & GAME_COMMAND_FLAG_GHOST))
@ -185,7 +200,7 @@ public:
}
newElement->type = MAP_ELEMENT_TYPE_ENTRANCE;
newElement->type |= direction;
newElement->type |= _direction;
newElement->properties.entrance.index = index;
newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE;
newElement->properties.entrance.path_type = gFootpathSelectedId;

View File

@ -41,37 +41,52 @@ struct RideCreateGameActionResult : public GameActionResult
sint32 rideIndex;
};
struct RideCreateAction : public GameActionBase<GAME_COMMAND_CREATE_RIDE, GA_FLAGS::ALLOW_WHILE_PAUSED, RideCreateGameActionResult>
struct RideCreateAction : public GameActionBase<GAME_COMMAND_CREATE_RIDE, RideCreateGameActionResult>
{
private:
sint32 _rideType;
sint32 _subType;
uint8 _colour1;
uint8 _colour2;
public:
sint32 rideType;
sint32 rideSubType;
uint8 colourPreset1;
uint8 colourPreset2;
RideCreateAction() {}
RideCreateAction(sint32 rideType, sint32 subType, sint32 colour1, sint32 colour2) :
_rideType(rideType),
_subType(subType),
_colour1(colour1),
_colour2(colour2)
{
}
uint16 GetActionFlags() const override
{
return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED;;
}
void Serialise(DataSerialiser& stream) override
{
GameAction::Serialise(stream);
stream << rideType << rideSubType << colourPreset1 << colourPreset2;
stream << _rideType << _subType << _colour1 << _colour2;
}
GameActionResult::Ptr Query() const override
{
if (rideType >= RIDE_TYPE_COUNT)
if (_rideType >= RIDE_TYPE_COUNT)
{
return std::make_unique<RideCreateGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE);
}
sint32 rideEntryIndex = ride_get_entry_index(rideType, rideSubType);
sint32 rideEntryIndex = ride_get_entry_index(_rideType, _subType);
if (rideEntryIndex >= 128)
{
return std::make_unique<RideCreateGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE);
}
const track_colour_preset_list *colourPresets = &RideColourPresets[rideType];
if (colourPreset1 >= colourPresets->count)
const track_colour_preset_list *colourPresets = &RideColourPresets[_rideType];
if (_colour1 >= colourPresets->count)
{
// FIXME: Add new error string.
return std::make_unique<RideCreateGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE);
@ -79,7 +94,7 @@ public:
rct_ride_entry *rideEntry = get_ride_entry(rideEntryIndex);
vehicle_colour_preset_list *presetList = rideEntry->vehicle_preset_list;
if (colourPreset2 >= presetList->count)
if (_colour2 >= presetList->count)
{
// FIXME: Add new error string.
return std::make_unique<RideCreateGameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_RIDE_TYPE);
@ -93,7 +108,7 @@ public:
rct_ride_entry * rideEntry;
auto res = std::make_unique<RideCreateGameActionResult>();
sint32 rideEntryIndex = ride_get_entry_index(rideType, rideSubType);
sint32 rideEntryIndex = ride_get_entry_index(_rideType, _subType);
sint32 rideIndex = ride_get_empty_slot();
res->rideIndex = rideIndex;
@ -108,9 +123,9 @@ public:
return std::move(res);
}
ride->type = rideType;
ride->type = _rideType;
ride->subtype = rideEntryIndex;
ride_set_colour_preset(ride, colourPreset1);
ride_set_colour_preset(ride, _colour1);
ride->overall_view.xy = RCT_XY8_UNDEFINED;
// Ride name
@ -279,7 +294,7 @@ public:
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, colourPreset2);
ride_set_vehicle_colours_to_random_preset(ride, _colour2);
window_invalidate_by_class(WC_RIDE_LIST);
res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION;
@ -287,4 +302,4 @@ public:
return std::move(res);
}
};
};

View File

@ -28,25 +28,37 @@ extern "C"
#include "../ride/ride.h"
}
struct RideSetStatusAction : public GameActionBase<GAME_COMMAND_SET_RIDE_STATUS, GA_FLAGS::ALLOW_WHILE_PAUSED, GameActionResult>
struct RideSetStatusAction : public GameActionBase<GAME_COMMAND_SET_RIDE_STATUS, GameActionResult>
{
private:
uint8 _rideIndex;
uint8 _status;
public:
uint8 RideIndex;
uint8 Status;
RideSetStatusAction() {}
RideSetStatusAction(uint8 rideIndex, uint8 status) :
_rideIndex(rideIndex),
_status(status)
{
}
uint16 GetActionFlags() const override
{
return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED;
}
void Serialise(DataSerialiser& stream) override
{
GameAction::Serialise(stream);
stream << RideIndex;
stream << Status;
stream << _rideIndex << _status;
}
GameActionResult::Ptr Query() const override
{
if (RideIndex >= MAX_RIDES)
if (_rideIndex >= MAX_RIDES)
{
log_warning("Invalid game command for ride %u", RideIndex);
log_warning("Invalid game command for ride %u", _rideIndex);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS);
}
return std::make_unique<GameActionResult>();
@ -57,11 +69,11 @@ public:
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS;
rct_ride *ride = get_ride(RideIndex);
rct_ride *ride = get_ride(_rideIndex);
if (ride->type == RIDE_TYPE_NULL)
{
log_warning("Invalid game command for ride %u", RideIndex);
log_warning("Invalid game command for ride %u", _rideIndex);
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS);
}
@ -72,15 +84,15 @@ public:
res->Position.z = map_element_height(res->Position.x, res->Position.y);
}
switch (Status) {
switch (_status) {
case RIDE_STATUS_CLOSED:
if (ride->status == Status)
if (ride->status == _status)
{
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN))
{
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED;
ride_clear_for_construction(RideIndex);
ride_remove_peeps(RideIndex);
ride_clear_for_construction(_rideIndex);
ride_remove_peeps(_rideIndex);
}
}
@ -88,47 +100,47 @@ public:
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->race_winner = SPRITE_INDEX_NULL;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
window_invalidate_by_number(WC_RIDE, RideIndex);
window_invalidate_by_number(WC_RIDE, _rideIndex);
break;
case RIDE_STATUS_TESTING:
case RIDE_STATUS_OPEN:
{
if (ride->status == Status)
if (ride->status == _status)
{
return res;
}
// Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening
// otherwise vehicles get added to the ride incorrectly (such as to a ghost station)
rct_window *constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, RideIndex);
rct_window *constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex);
if (constructionWindow != nullptr)
{
window_close(constructionWindow);
}
if (Status == RIDE_STATUS_TESTING)
if (_status == RIDE_STATUS_TESTING)
{
if (!ride_is_valid_for_test(RideIndex, Status == RIDE_STATUS_OPEN, 1))
if (!ride_is_valid_for_test(_rideIndex, _status == RIDE_STATUS_OPEN, 1))
{
//*ebx = MONEY32_UNDEFINED;
return res;
}
}
else if (!ride_is_valid_for_open(RideIndex, Status == RIDE_STATUS_OPEN, 1))
else if (!ride_is_valid_for_open(_rideIndex, _status == RIDE_STATUS_OPEN, 1))
{
//*ebx = MONEY32_UNDEFINED;
return res;
}
ride->race_winner = SPRITE_INDEX_NULL;
ride->status = Status;
ride_get_measurement(RideIndex, nullptr);
ride->status = _status;
ride_get_measurement(_rideIndex, nullptr);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
window_invalidate_by_number(WC_RIDE, RideIndex);
window_invalidate_by_number(WC_RIDE, _rideIndex);
break;
}
default:
Guard::Assert(false, "Invalid status passed: %u", Status);
Guard::Assert(false, "Invalid status passed: %u", _status);
break;
}
return res;

View File

@ -27,11 +27,16 @@ extern "C"
#include "../world/park.h"
}
struct SetParkEntranceFeeAction : public GameActionBase<GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GA_FLAGS::ALLOW_WHILE_PAUSED, GameActionResult>
struct SetParkEntranceFeeAction : public GameActionBase<GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GameActionResult>
{
public:
money16 Fee;
uint16 GetActionFlags() const override
{
return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED;
}
void Serialise(DataSerialiser& stream) override
{
GameAction::Serialise(stream);

View File

@ -5839,21 +5839,6 @@ bool shop_item_has_common_price(sint32 shopItem)
}
}
money32 ride_create_command(sint32 type, sint32 subType, sint32 flags, uint8 *outRideIndex, uint8 *outRideColour)
{
sint32 eax = 0;
sint32 ebx = flags;
sint32 ecx = 0;
sint32 edx = type | (subType << 8);
sint32 esi = 0;
sint32 edi = 0;
sint32 ebp = 0;
money32 cost = game_do_command_p(GAME_COMMAND_CREATE_RIDE, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp);
*outRideIndex = edi & 0xFF;
*outRideColour = eax;
return cost;
}
void ride_set_name_to_default(Ride * ride, rct_ride_entry * rideEntry)
{
if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) {