Add PeepPickupAction

Move Guest and Staff pickup to the new game action. Rework the game
action so that only one game action is required for the two game
commands. Remove the final game command with a callback.
This commit is contained in:
duncanspumpkin 2019-06-09 16:54:12 +01:00
parent 65c0b0591d
commit b896f07687
13 changed files with 270 additions and 210 deletions

View File

@ -14,6 +14,7 @@
#include <openrct2/Game.h>
#include <openrct2/Input.h>
#include <openrct2/actions/GuestSetFlagsAction.hpp>
#include <openrct2/actions/PeepPickupAction.hpp>
#include <openrct2/config/Config.h>
#include <openrct2/localisation/Localisation.h>
#include <openrct2/management/Marketing.h>
@ -692,14 +693,25 @@ void window_guest_overview_mouse_up(rct_window* w, rct_widgetindex widgetIndex)
window_guest_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_PICKUP:
{
if (!peep_can_be_picked_up(peep))
{
return;
}
w->picked_peep_old_x = peep->x;
game_command_callback = game_command_callback_pickup_guest;
game_do_command(w->number, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_PICKUP_GUEST, 0, 0);
break;
PeepPickupAction pickupAction{ PeepPickupType::Pickup, w->number, {}, network_get_current_player_id() };
pickupAction.SetCallback([peepnum = w->number](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
return;
rct_window* wind = window_find_by_number(WC_PEEP, peepnum);
if (wind)
{
tool_set(wind, WC_PEEP__WIDX_PICKUP, TOOL_PICKER);
}
});
GameActions::Execute(&pickupAction);
}
break;
case WIDX_RENAME:
window_text_input_open(
w, widgetIndex, STR_GUEST_RENAME_TITLE, STR_GUEST_RENAME_PROMPT, peep->name_string_idx, peep->id, 32);
@ -1275,8 +1287,16 @@ void window_guest_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex,
if (dest_x == LOCATION_NULL)
return;
game_command_callback = game_command_callback_pickup_guest;
game_do_command(w->number, GAME_COMMAND_FLAG_APPLY, 2, tileElement->base_height, GAME_COMMAND_PICKUP_GUEST, dest_x, dest_y);
PeepPickupAction pickupAction{
PeepPickupType::Place, w->number, { dest_x, dest_y, tileElement->base_height }, network_get_current_player_id()
};
pickupAction.SetCallback([](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
return;
tool_cancel();
gPickupPeepImage = UINT32_MAX;
});
GameActions::Execute(&pickupAction);
}
/**
@ -1288,7 +1308,10 @@ void window_guest_overview_tool_abort(rct_window* w, rct_widgetindex widgetIndex
if (widgetIndex != WIDX_PICKUP)
return;
game_do_command(w->number, GAME_COMMAND_FLAG_APPLY, 1, 0, GAME_COMMAND_PICKUP_GUEST, w->picked_peep_old_x, 0);
PeepPickupAction pickupAction{
PeepPickupType::Cancel, w->number, { w->picked_peep_old_x, 0, 0 }, network_get_current_player_id()
};
GameActions::Execute(&pickupAction);
}
/**

View File

@ -16,6 +16,7 @@
#include <openrct2/Context.h>
#include <openrct2/Game.h>
#include <openrct2/Input.h>
#include <openrct2/actions/PeepPickupAction.hpp>
#include <openrct2/actions/StaffSetCostumeAction.hpp>
#include <openrct2/actions/StaffSetOrdersAction.hpp>
#include <openrct2/actions/StaffSetPatrolAreaAction.hpp>
@ -462,13 +463,19 @@ void window_staff_overview_mouseup(rct_window* w, rct_widgetindex widgetIndex)
break;
case WIDX_PICKUP:
{
// this is called in callback when hiring staff, setting nestlevel to 0 so that command is sent separately
int32_t oldNestLevel = gGameCommandNestLevel;
gGameCommandNestLevel = 0;
game_command_callback = game_command_callback_pickup_staff;
w->picked_peep_old_x = peep->x;
game_do_command(w->number, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_PICKUP_STAFF, 0, 0);
gGameCommandNestLevel = oldNestLevel;
PeepPickupAction pickupAction{ PeepPickupType::Pickup, w->number, {}, network_get_current_player_id() };
pickupAction.SetCallback([peepnum = w->number](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
return;
rct_window* wind = window_find_by_number(WC_PEEP, peepnum);
if (wind)
{
tool_set(wind, WC_STAFF__WIDX_PICKUP, TOOL_PICKER);
}
});
GameActions::Execute(&pickupAction);
}
break;
case WIDX_FIRE:
@ -1198,9 +1205,16 @@ void window_staff_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex,
if (dest_x == LOCATION_NULL)
return;
game_command_callback = game_command_callback_pickup_staff;
game_do_command(
w->number, GAME_COMMAND_FLAG_APPLY, 2, tileElement->base_height, GAME_COMMAND_PICKUP_STAFF, dest_x, dest_y);
PeepPickupAction pickupAction{
PeepPickupType::Place, w->number, { dest_x, dest_y, tileElement->base_height }, network_get_current_player_id()
};
pickupAction.SetCallback([](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
return;
tool_cancel();
gPickupPeepImage = UINT32_MAX;
});
GameActions::Execute(&pickupAction);
}
else if (widgetIndex == WIDX_PATROL)
{
@ -1285,7 +1299,10 @@ void window_staff_overview_tool_abort(rct_window* w, rct_widgetindex widgetIndex
{
if (widgetIndex == WIDX_PICKUP)
{
game_do_command(w->number, GAME_COMMAND_FLAG_APPLY, 1, 0, GAME_COMMAND_PICKUP_STAFF, w->picked_peep_old_x, 0);
PeepPickupAction pickupAction{
PeepPickupType::Cancel, w->number, { w->picked_peep_old_x, 0, 0 }, network_get_current_player_id()
};
GameActions::Execute(&pickupAction);
}
else if (widgetIndex == WIDX_PATROL)
{

View File

@ -96,8 +96,8 @@ static GAME_COMMAND_CALLBACK_POINTER * const game_command_callback_table[] = {
nullptr,
nullptr,
nullptr,
game_command_callback_pickup_guest,
game_command_callback_pickup_staff
nullptr,
nullptr
};
// clang-format on
int32_t game_command_playerid = -1;
@ -1222,8 +1222,8 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = {
nullptr,
nullptr,
nullptr,
game_command_pickup_guest,
game_command_pickup_staff,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,

View File

@ -85,19 +85,19 @@ enum GAME_COMMAND
GAME_COMMAND_MODIFY_GROUPS, // GA
GAME_COMMAND_KICK_PLAYER, // GA
GAME_COMMAND_CHEAT, // GA
GAME_COMMAND_PICKUP_GUEST,
GAME_COMMAND_PICKUP_STAFF,
GAME_COMMAND_BALLOON_PRESS, // GA
GAME_COMMAND_MODIFY_TILE, // GA
GAME_COMMAND_EDIT_SCENARIO_OPTIONS, // GA
GAME_COMMAND_PLACE_PEEP_SPAWN, // GA, TODO: refactor to separate array for just game actions
GAME_COMMAND_SET_CLIMATE, // GA
GAME_COMMAND_SET_COLOUR_SCHEME, // GA
GAME_COMMAND_SET_STAFF_COSTUME, // GA
GAME_COMMAND_PLACE_FOOTPATH_SCENERY, // GA
GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, // GA
GAME_COMMAND_GUEST_SET_FLAGS, // GA
GAME_COMMAND_SET_DATE, // GA
GAME_COMMAND_PICKUP_GUEST, // GA
GAME_COMMAND_PICKUP_STAFF, // GA
GAME_COMMAND_BALLOON_PRESS, // GA
GAME_COMMAND_MODIFY_TILE, // GA
GAME_COMMAND_EDIT_SCENARIO_OPTIONS, // GA
GAME_COMMAND_PLACE_PEEP_SPAWN, // GA, TODO: refactor to separate array for just game actions
GAME_COMMAND_SET_CLIMATE, // GA
GAME_COMMAND_SET_COLOUR_SCHEME, // GA
GAME_COMMAND_SET_STAFF_COSTUME, // GA
GAME_COMMAND_PLACE_FOOTPATH_SCENERY, // GA
GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, // GA
GAME_COMMAND_GUEST_SET_FLAGS, // GA
GAME_COMMAND_SET_DATE, // GA
GAME_COMMAND_COUNT,
};

View File

@ -43,6 +43,7 @@
#include "ParkSetParameterAction.hpp"
#include "ParkSetResearchFundingAction.hpp"
#include "PauseToggleAction.hpp"
#include "PeepPickupAction.hpp"
#include "PlaceParkEntranceAction.hpp"
#include "PlacePeepSpawnAction.hpp"
#include "PlayerKickAction.hpp"
@ -110,6 +111,7 @@ namespace GameActions
Register<ParkSetNameAction>();
Register<ParkSetParameterAction>();
Register<ParkSetResearchFundingAction>();
Register<PeepPickupAction>();
Register<PlaceParkEntranceAction>();
Register<PlacePeepSpawnAction>();
Register<PlayerKickAction>();

View File

@ -0,0 +1,189 @@
/*****************************************************************************
* Copyright (c) 2014-2019 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 "../Input.h"
#include "../network/network.h"
#include "../world/Sprite.h"
#include "GameAction.h"
enum class PeepPickupType : uint8_t
{
Pickup,
Cancel,
Place,
Count
};
DEFINE_GAME_ACTION(PeepPickupAction, GAME_COMMAND_PICKUP_GUEST, GameActionResult)
{
private:
uint8_t _type = static_cast<uint8_t>(PeepPickupType::Count);
uint32_t _spriteId = SPRITE_INDEX_NULL;
CoordsXYZ _loc;
NetworkPlayerId_t _owner = { -1 };
public:
PeepPickupAction() = default;
PeepPickupAction(PeepPickupType type, uint32_t spriteId, CoordsXYZ loc, NetworkPlayerId_t owner)
: _type(static_cast<uint8_t>(type))
, _spriteId(spriteId)
, _loc(loc)
, _owner(owner)
{
}
uint16_t GetActionFlags() const override
{
return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED;
}
void Serialise(DataSerialiser & stream) override
{
GameAction::Serialise(stream);
stream << DS_TAG(_type) << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_owner);
}
GameActionResult::Ptr Query() const override
{
if (_spriteId >= MAX_SPRITES || _spriteId == SPRITE_INDEX_NULL)
{
log_error("Failed to pick up peep for sprite %d", _spriteId);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE);
}
Peep* const peep = GET_PEEP(_spriteId);
if (!peep || peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP)
{
log_error("Failed to pick up peep for sprite %d", _spriteId);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE);
}
auto res = MakeResult();
switch (static_cast<PeepPickupType>(_type))
{
case PeepPickupType::Pickup:
{
res->Position = { peep->x, peep->y, peep->z };
if (!peep_can_be_picked_up(peep))
{
return MakeResult(GA_ERROR::DISALLOWED, STR_ERR_CANT_PLACE_PERSON_HERE);
}
Peep* existing = network_get_pickup_peep(_owner);
if (existing)
{
// already picking up a peep
PeepPickupAction existingPickupAction{
PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner
};
auto result = GameActions::QueryNested(&existingPickupAction);
if (existing == peep)
{
return result;
}
}
}
break;
case PeepPickupType::Cancel:
res->Position = { peep->x, peep->y, peep->z };
break;
case PeepPickupType::Place:
res->Position = _loc;
if (network_get_pickup_peep(_owner) != peep)
{
return MakeResult(GA_ERROR::UNKNOWN, STR_ERR_CANT_PLACE_PERSON_HERE);
}
if (!peep->Place({ _loc.x / 32, _loc.y / 32, _loc.z }, false))
{
return MakeResult(GA_ERROR::UNKNOWN, STR_ERR_CANT_PLACE_PERSON_HERE, gGameCommandErrorText);
}
break;
default:
log_error("Invalid pickup type: %u", _type);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE);
break;
}
return res;
}
GameActionResult::Ptr Execute() const override
{
Peep* const peep = GET_PEEP(_spriteId);
if (!peep || peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP)
{
log_error("Failed to pick up peep for sprite %d", _spriteId);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE);
}
auto res = MakeResult();
switch (static_cast<PeepPickupType>(_type))
{
case PeepPickupType::Pickup:
{
res->Position = { peep->x, peep->y, peep->z };
Peep* existing = network_get_pickup_peep(_owner);
if (existing)
{
// already picking up a peep
PeepPickupAction existingPickupAction{
PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner
};
auto result = GameActions::ExecuteNested(&existingPickupAction);
if (existing == peep)
{
return result;
}
if (_owner == network_get_current_player_id())
{
// prevent tool_cancel()
input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false);
}
}
network_set_pickup_peep(_owner, peep);
network_set_pickup_peep_old_x(_owner, peep->x);
peep->Pickup();
}
break;
case PeepPickupType::Cancel:
{
res->Position = { peep->x, peep->y, peep->z };
Peep* const pickedUpPeep = network_get_pickup_peep(_owner);
if (pickedUpPeep)
{
pickedUpPeep->PickupAbort(_loc.x);
}
network_set_pickup_peep(_owner, nullptr);
}
break;
case PeepPickupType::Place:
res->Position = _loc;
if (!peep->Place({ _loc.x / 32, _loc.y / 32, _loc.z }, true))
{
return MakeResult(GA_ERROR::UNKNOWN, STR_ERR_CANT_PLACE_PERSON_HERE, gGameCommandErrorText);
}
break;
default:
log_error("Invalid pickup type: %u", _type);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE);
break;
}
return res;
}
};

View File

@ -677,11 +677,6 @@ void window_align_tabs(rct_window* w, rct_widgetindex start_tab_id, rct_widgetin
void window_staff_list_init_vars();
void game_command_callback_pickup_guest(
int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp);
void game_command_callback_pickup_staff(
int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp);
void window_event_close_call(rct_window* w);
void window_event_mouse_up_call(rct_window* w, rct_widgetindex widgetIndex);
void window_event_resize_call(rct_window* w);

View File

@ -16,6 +16,7 @@
#include "../PlatformEnvironment.h"
#include "../actions/LoadOrQuitAction.hpp"
#include "../actions/NetworkModifyGroupAction.hpp"
#include "../actions/PeepPickupAction.hpp"
#include "../core/Guard.hpp"
#include "../platform/platform.h"
#include "../ui/UiContext.h"
@ -2246,11 +2247,11 @@ void Network::ServerClientDisconnected(std::unique_ptr<NetworkConnection>& conne
Peep* pickup_peep = network_get_pickup_peep(connection_player->Id);
if (pickup_peep)
{
game_command_playerid = connection_player->Id;
game_do_command(
pickup_peep->sprite_index, GAME_COMMAND_FLAG_APPLY, 1, 0,
pickup_peep->type == PEEP_TYPE_GUEST ? GAME_COMMAND_PICKUP_GUEST : GAME_COMMAND_PICKUP_STAFF,
network_get_pickup_peep_old_x(connection_player->Id), 0);
PeepPickupAction pickupAction{ PeepPickupType::Cancel,
pickup_peep->sprite_index,
{ network_get_pickup_peep_old_x(connection_player->Id), 0, 0 },
network_get_current_player_id() };
auto res = GameActions::Execute(&pickupAction);
}
gNetwork.Server_Send_EVENT_PLAYER_DISCONNECTED(
(char*)connection_player->Name.c_str(), connection->GetLastDisconnectReason());

View File

@ -853,99 +853,6 @@ bool Peep::Place(TileCoordsXYZ location, bool apply)
return true;
}
bool peep_pickup_command(uint32_t peepnum, int32_t x, int32_t y, int32_t z, int32_t action, bool apply)
{
if (peepnum >= MAX_SPRITES)
{
log_error("Failed to pick up peep for sprite %d", peepnum);
return false;
}
Peep* const peep = GET_PEEP(peepnum);
if (!peep || peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP)
{
return false;
}
switch (action)
{
case 0: // pickup
{
if (!peep_can_be_picked_up(peep))
{
return false;
}
Peep* existing = network_get_pickup_peep(game_command_playerid);
if (existing)
{
// already picking up a peep
bool result = peep_pickup_command(
existing->sprite_index, network_get_pickup_peep_old_x(game_command_playerid), 0, 0, 1, apply);
if (existing == peep)
{
return result;
}
if (game_command_playerid == network_get_current_player_id())
{
// prevent tool_cancel()
input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false);
}
}
if (apply)
{
network_set_pickup_peep(game_command_playerid, peep);
network_set_pickup_peep_old_x(game_command_playerid, peep->x);
peep->Pickup();
}
}
break;
case 1: // cancel
if (apply)
{
// TODO: Verify if this is really needed or that we can use `peep` instead
Peep* const pickedUpPeep = network_get_pickup_peep(game_command_playerid);
if (pickedUpPeep)
{
pickedUpPeep->PickupAbort(x);
}
network_set_pickup_peep(game_command_playerid, nullptr);
}
break;
case 2: // place
if (network_get_pickup_peep(game_command_playerid) != peep)
{
return false;
}
if (!peep->Place({ x / 32, y / 32, z }, apply))
{
return false;
}
break;
}
return true;
}
void game_command_pickup_guest(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
int32_t peepnum = *eax;
int32_t x = *edi;
int32_t y = *ebp;
int32_t z = *edx;
int32_t action = *ecx;
if (peep_pickup_command(peepnum, x, y, z, action, *ebx & GAME_COMMAND_FLAG_APPLY))
{
*ebx = 0;
}
else
{
*ebx = MONEY32_UNDEFINED;
}
}
/**
*
* rct2: 0x0069A535

View File

@ -953,7 +953,6 @@ int32_t get_peep_face_sprite_small(Peep* peep);
int32_t get_peep_face_sprite_large(Peep* peep);
int32_t peep_check_easteregg_name(int32_t index, Peep* peep);
int32_t peep_get_easteregg_name_id(Peep* peep);
bool peep_pickup_command(uint32_t peepnum, int32_t x, int32_t y, int32_t z, int32_t action, bool apply);
void game_command_pickup_guest(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void peep_sprite_remove(Peep* peep);

View File

@ -1089,24 +1089,6 @@ int32_t staff_path_finding(Staff* peep)
}
}
void game_command_pickup_staff(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
int32_t peepnum = *eax;
int32_t x = *edi;
int32_t y = *ebp;
int32_t z = *edx;
int32_t action = *ecx;
if (peep_pickup_command(peepnum, x, y, z, action, *ebx & GAME_COMMAND_FLAG_APPLY))
{
*ebx = 0;
}
else
{
*ebx = MONEY32_UNDEFINED;
}
}
colour_t staff_get_colour(uint8_t staffType)
{
switch (staffType)

View File

@ -71,9 +71,6 @@ extern colour_t gStaffHandymanColour;
extern colour_t gStaffMechanicColour;
extern colour_t gStaffSecurityColour;
void game_command_pickup_staff(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void staff_reset_modes();
void staff_set_name(uint16_t spriteIndex, const char* name);
bool staff_hire_new_member(STAFF_TYPE staffType, ENTERTAINER_COSTUME entertainerType);

View File

@ -29,58 +29,6 @@
bool gDisableErrorWindowSound = false;
void game_command_callback_pickup_guest(
int32_t eax, int32_t ebx, int32_t ecx, [[maybe_unused]] int32_t edx, [[maybe_unused]] int32_t esi,
[[maybe_unused]] int32_t edi, [[maybe_unused]] int32_t ebp)
{
switch (ecx)
{
case 0:
{
int32_t peepnum = eax;
rct_window* w = window_find_by_number(WC_PEEP, peepnum);
if (w)
{
tool_set(w, WC_PEEP__WIDX_PICKUP, TOOL_PICKER);
}
}
break;
case 2:
if (ebx == 0)
{
tool_cancel();
gPickupPeepImage = UINT32_MAX;
}
break;
}
}
void game_command_callback_pickup_staff(
int32_t eax, int32_t ebx, int32_t ecx, [[maybe_unused]] int32_t edx, [[maybe_unused]] int32_t esi,
[[maybe_unused]] int32_t edi, [[maybe_unused]] int32_t ebp)
{
switch (ecx)
{
case 0:
{
int32_t peepnum = eax;
rct_window* w = window_find_by_number(WC_PEEP, peepnum);
if (w)
{
tool_set(w, WC_STAFF__WIDX_PICKUP, TOOL_PICKER);
}
}
break;
case 2:
if (ebx == 0)
{
tool_cancel();
gPickupPeepImage = UINT32_MAX;
}
break;
}
}
uint64_t _enabledRidePieces;
uint8_t _rideConstructionState2;