OpenRCT2/src/openrct2-ui/windows/LandRights.cpp

419 lines
15 KiB
C++
Raw Normal View History

2015-05-15 17:28:27 +02:00
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
2015-05-15 17:28:27 +02:00
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
2015-05-15 17:28:27 +02:00
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
2015-05-15 17:28:27 +02:00
*****************************************************************************/
#include <algorithm>
2018-06-22 23:21:44 +02:00
#include <openrct2-ui/interface/LandTool.h>
#include <openrct2-ui/interface/Viewport.h>
#include <openrct2-ui/interface/Widget.h>
2017-08-06 21:20:05 +02:00
#include <openrct2-ui/windows/Window.h>
2018-06-22 23:21:44 +02:00
#include <openrct2/Context.h>
2017-11-30 18:17:06 +01:00
#include <openrct2/Game.h>
#include <openrct2/GameState.h>
2017-12-12 14:52:57 +01:00
#include <openrct2/Input.h>
Split actions hpp files into separate h and cpp files (#13548) * Split up SmallSceneryPlace/Remove Added undo function for Remove Scenery * Refactor: Balloon and Banner actions hpp=>h/cpp * Refactor: rename all action *.hpp files to *.cpp This is preparation for separation in later commits. Note that without the complete set of commits in this branch, the code will not build. * Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp * VSCode: add src subdirectories to includePath * Refactor Guest actions hpp=>h/cpp * Refactor Land actions hpp=>h/cpp * Refactor LargeScenery actions hpp=>h/cpp * Refactor Load, Maze, Network actions hpp=>h/cpp * Refactor Park actions hpp=>h/cpp * Refactor/style: move private function declarations in actions *.h Previous action .h files included private function declarations with private member variables, before public function declarations. This commit re-orders the header files to the following order: - public member variables - private member variables - public functions - private functions * Refactor Pause action hpp=>h/cpp * Refactor Peep, Place, Player actions hpp=>h/cpp * Refactor Ride actions hpp=>h/cpp * Refactor Scenario, Set*, Sign* actions hpp=>h/cpp * Refactor SmallScenerySetColourAction hpp=>h/cpp * Refactor Staff actions hpp=>h/cpp * Refactor Surface, Tile, Track* actions hpp=>h/cpp * Refactor Wall and Water actions hpp=>h/cpp * Fix various includes and other compile errors Update includes for tests. Move static function declarations to .h files Add explicit includes to various files that were previously implicit (the required header was a nested include in an action hpp file, and the action .h file does not include that header) Move RideSetStatus string enum to the cpp file to avoid unused imports * Xcode: modify project file for actions refactor * Cleanup whitespace and end-of-file newlines Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-12-10 07:39:10 +01:00
#include <openrct2/actions/LandBuyRightsAction.h>
#include <openrct2/core/String.hpp>
2018-03-19 23:28:40 +01:00
#include <openrct2/drawing/Drawing.h>
2021-12-12 00:06:06 +01:00
#include <openrct2/localisation/Formatter.h>
2018-06-22 23:21:44 +02:00
#include <openrct2/localisation/Localisation.h>
2018-03-19 23:28:40 +01:00
#include <openrct2/world/Park.h>
2015-05-15 17:28:27 +02:00
namespace OpenRCT2::Ui::Windows
{
static constexpr StringId WINDOW_TITLE = STR_LAND_RIGHTS;
static constexpr int32_t WH = 94;
static constexpr int32_t WW = 98;
// clang-format off
enum WindowLandRightsWidgetIdx {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PREVIEW,
WIDX_DECREMENT,
WIDX_INCREMENT,
WIDX_BUY_LAND_RIGHTS,
WIDX_BUY_CONSTRUCTION_RIGHTS
2015-05-15 17:28:27 +02:00
};
2022-12-24 16:50:29 +01:00
static Widget window_land_rights_widgets[] = {
2020-05-09 16:44:21 +02:00
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({27, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , ImageId(SPR_LAND_TOOL_SIZE_0) ), // preview box
MakeRemapWidget({28, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_RIGHTS_TIP), // decrement size
MakeRemapWidget({54, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_RIGHTS_TIP ), // increment size
MakeRemapWidget({22, 53}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary, SPR_BUY_LAND_RIGHTS, STR_BUY_LAND_RIGHTS_TIP ), // land rights
MakeRemapWidget({52, 53}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary, SPR_BUY_CONSTRUCTION_RIGHTS, STR_BUY_CONSTRUCTION_RIGHTS_TIP ), // construction rights
kWidgetsEnd,
2015-05-15 17:28:27 +02:00
};
// clang-format on
2015-05-15 17:28:27 +02:00
constexpr uint8_t LAND_RIGHTS_MODE_BUY_CONSTRUCTION_RIGHTS = 0;
constexpr uint8_t LAND_RIGHTS_MODE_BUY_LAND = 1;
2017-06-26 20:01:35 +02:00
class LandRightsWindow final : public Window
{
public:
void OnOpen() override
{
widgets = window_land_rights_widgets;
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
_landRightsMode = LAND_RIGHTS_MODE_BUY_LAND;
pressed_widgets = (1uLL << WIDX_BUY_LAND_RIGHTS);
gLandToolSize = 1;
ShowGridlines();
ToolSet(*this, WIDX_BUY_LAND_RIGHTS, Tool::UpArrow);
InputSetFlag(INPUT_FLAG_6, true);
ShowLandRights();
2017-06-26 20:59:52 +02:00
if (gLandRemainingConstructionSales == 0)
{
ShowConstructionRights();
}
}
void OnClose() override
{
HideGridlines();
if (gLandRemainingConstructionSales == 0)
{
HideConstructionRights();
}
// If the tool wasn't changed, turn tool off
if (LandRightsToolIsActive())
ToolCancel();
}
2017-08-06 05:22:00 +02:00
void OnMouseUp(WidgetIndex widgetIndex) override
{
switch (widgetIndex)
{
case WIDX_CLOSE:
Close();
break;
case WIDX_PREVIEW:
InputSize();
break;
case WIDX_BUY_LAND_RIGHTS:
if (_landRightsMode != LAND_RIGHTS_MODE_BUY_LAND)
{
ToolSet(*this, WIDX_BUY_LAND_RIGHTS, Tool::UpArrow);
_landRightsMode = LAND_RIGHTS_MODE_BUY_LAND;
ShowLandRights();
Invalidate();
}
break;
case WIDX_BUY_CONSTRUCTION_RIGHTS:
if (_landRightsMode != LAND_RIGHTS_MODE_BUY_CONSTRUCTION_RIGHTS)
{
ToolSet(*this, WIDX_BUY_CONSTRUCTION_RIGHTS, Tool::UpArrow);
_landRightsMode = LAND_RIGHTS_MODE_BUY_CONSTRUCTION_RIGHTS;
ShowConstructionRights();
Invalidate();
}
break;
}
}
2015-05-15 17:28:27 +02:00
void OnMouseDown(WidgetIndex widgetIndex) override
{
switch (widgetIndex)
{
case WIDX_DECREMENT:
// Decrement land rights tool size
gLandToolSize = std::max<uint16_t>(kLandToolMinimumSize, gLandToolSize - 1);
// Invalidate the window
Invalidate();
break;
case WIDX_INCREMENT:
// Decrement land rights tool size
gLandToolSize = std::min<uint16_t>(kLandToolMaximumSize, gLandToolSize + 1);
// Invalidate the window
Invalidate();
break;
}
}
void OnTextInput(WidgetIndex widgetIndex, std::string_view text) override
{
if (text.empty())
return;
if (widgetIndex != WIDX_PREVIEW)
return;
const auto res = String::Parse<int32_t>(text);
if (res.has_value())
{
uint16_t size;
size = res.value();
size = std::max(kLandToolMinimumSize, size);
size = std::min(kLandToolMaximumSize, size);
gLandToolSize = size;
Invalidate();
}
}
void OnUpdate() override
{
frame_no++;
// Close window if another tool is open
if (!LandRightsToolIsActive())
Close();
}
2015-05-15 17:28:27 +02:00
void OnPrepareDraw() override
{
SetWidgetPressed(WIDX_PREVIEW, true);
if (_landRightsMode == LAND_RIGHTS_MODE_BUY_LAND)
{
SetWidgetPressed(WIDX_BUY_LAND_RIGHTS, true);
SetWidgetPressed(WIDX_BUY_CONSTRUCTION_RIGHTS, false);
}
else if (_landRightsMode == LAND_RIGHTS_MODE_BUY_CONSTRUCTION_RIGHTS)
{
SetWidgetPressed(WIDX_BUY_LAND_RIGHTS, false);
SetWidgetPressed(WIDX_BUY_CONSTRUCTION_RIGHTS, true);
}
2015-05-15 17:28:27 +02:00
window_land_rights_widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
2015-05-15 17:28:27 +02:00
if (gLandRemainingOwnershipSales == 0)
{
SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, true);
window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_NO_LAND_RIGHTS_FOR_SALE_TIP;
}
else
{
SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, false);
window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_BUY_LAND_RIGHTS_TIP;
}
if (gLandRemainingConstructionSales == 0)
{
SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, true);
window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_NO_CONSTRUCTION_RIGHTS_FOR_SALE_TIP;
}
else
{
SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, false);
window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_BUY_CONSTRUCTION_RIGHTS_TIP;
}
}
void OnDraw(DrawPixelInfo& dpi) override
{
auto screenCoords = ScreenCoordsXY{ windowPos.x + window_land_rights_widgets[WIDX_PREVIEW].midX(),
windowPos.y + window_land_rights_widgets[WIDX_PREVIEW].midY() };
DrawWidgets(dpi);
// Draw number for tool sizes bigger than 7
if (gLandToolSize > kLandToolMaximumSizeWithSprite)
{
auto ft = Formatter();
ft.Add<uint16_t>(gLandToolSize);
DrawTextBasic(
dpi, screenCoords - ScreenCoordsXY{ 0, 2 }, STR_LAND_TOOL_SIZE_VALUE, ft, { TextAlignment::CENTRE });
}
2015-05-15 17:28:27 +02:00
// Draw cost amount
if (_landRightsCost != kMoney64Undefined && _landRightsCost != 0
&& !(GetGameState().Park.Flags & PARK_FLAGS_NO_MONEY))
{
auto ft = Formatter();
ft.Add<money64>(_landRightsCost);
screenCoords = { window_land_rights_widgets[WIDX_PREVIEW].midX() + windowPos.x,
window_land_rights_widgets[WIDX_PREVIEW].bottom + windowPos.y + 32 };
DrawTextBasic(dpi, screenCoords, STR_COST_AMOUNT, ft, { TextAlignment::CENTRE });
}
}
void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
{
MapInvalidateSelectionRect();
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
2017-06-26 20:59:52 +02:00
auto info = GetMapCoordinatesFromPos(
screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water));
if (info.SpriteType == ViewportInteractionItem::None)
{
if (_landRightsCost != kMoney64Undefined)
{
_landRightsCost = kMoney64Undefined;
WindowInvalidateByClass(WindowClass::ClearScenery);
}
return;
}
auto mapTile = info.Loc;
2017-06-26 20:59:52 +02:00
uint8_t state_changed = 0;
2017-06-26 20:59:52 +02:00
if (!(gMapSelectFlags & MAP_SELECT_FLAG_ENABLE))
{
gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE;
state_changed++;
}
2017-06-26 20:59:52 +02:00
if (gMapSelectType != MAP_SELECT_TYPE_FULL_LAND_RIGHTS)
{
gMapSelectType = MAP_SELECT_TYPE_FULL_LAND_RIGHTS;
state_changed++;
}
2017-06-26 20:59:52 +02:00
int16_t tool_size = gLandToolSize;
if (tool_size == 0)
tool_size = 1;
2017-06-26 20:59:52 +02:00
int16_t tool_length = (tool_size - 1) * 32;
2017-06-26 20:59:52 +02:00
// Move to tool bottom left
mapTile.x -= (tool_size - 1) * 16;
mapTile.y -= (tool_size - 1) * 16;
mapTile = mapTile.ToTileStart();
2017-06-26 20:59:52 +02:00
if (gMapSelectPositionA.x != mapTile.x)
{
gMapSelectPositionA.x = mapTile.x;
state_changed++;
}
2017-06-26 20:59:52 +02:00
if (gMapSelectPositionA.y != mapTile.y)
{
gMapSelectPositionA.y = mapTile.y;
state_changed++;
}
2017-06-26 20:59:52 +02:00
mapTile.x += tool_length;
mapTile.y += tool_length;
2017-06-26 20:59:52 +02:00
if (gMapSelectPositionB.x != mapTile.x)
{
gMapSelectPositionB.x = mapTile.x;
state_changed++;
}
2017-06-26 20:59:52 +02:00
if (gMapSelectPositionB.y != mapTile.y)
{
gMapSelectPositionB.y = mapTile.y;
state_changed++;
}
2019-03-17 09:25:51 +01:00
MapInvalidateSelectionRect();
if (!state_changed)
return;
2017-06-26 20:01:35 +02:00
auto landBuyRightsAction = LandBuyRightsAction(
{ gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y },
(_landRightsMode == LAND_RIGHTS_MODE_BUY_LAND) ? LandBuyRightSetting::BuyLand
: LandBuyRightSetting::BuyConstructionRights);
auto res = GameActions::Query(&landBuyRightsAction);
2017-06-26 20:01:35 +02:00
_landRightsCost = res.Error == GameActions::Status::Ok ? res.Cost : kMoney64Undefined;
2017-06-26 20:01:35 +02:00
}
void OnToolAbort(WidgetIndex widgetIndex) override
2017-06-26 20:01:35 +02:00
{
if (_landRightsMode == LAND_RIGHTS_MODE_BUY_LAND)
{
HideLandRights();
}
else
{
HideConstructionRights();
}
2017-06-26 20:01:35 +02:00
}
void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
2017-06-26 20:01:35 +02:00
{
if (_landRightsMode == LAND_RIGHTS_MODE_BUY_LAND)
{
if (screenCoords.x != LOCATION_NULL)
{
auto landBuyRightsAction = LandBuyRightsAction(
{ gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y },
LandBuyRightSetting::BuyLand);
GameActions::Execute(&landBuyRightsAction);
}
}
else
{
if (screenCoords.x != LOCATION_NULL)
{
auto landBuyRightsAction = LandBuyRightsAction(
{ gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y },
LandBuyRightSetting::BuyConstructionRights);
GameActions::Execute(&landBuyRightsAction);
}
}
}
void OnToolDrag(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
{
if (_landRightsMode == LAND_RIGHTS_MODE_BUY_LAND)
{
if (screenCoords.x != LOCATION_NULL)
{
auto landBuyRightsAction = LandBuyRightsAction(
{ gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y },
LandBuyRightSetting::BuyLand);
GameActions::Execute(&landBuyRightsAction);
}
}
else
{
if (screenCoords.x != LOCATION_NULL)
{
auto landBuyRightsAction = LandBuyRightsAction(
{ gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y },
LandBuyRightSetting::BuyConstructionRights);
GameActions::Execute(&landBuyRightsAction);
}
}
2017-06-26 20:01:35 +02:00
}
void OnResize() override
{
ResizeFrame();
}
private:
uint8_t _landRightsMode;
money64 _landRightsCost;
void InputSize()
{
Formatter ft;
ft.Add<uint16_t>(kLandToolMinimumSize);
ft.Add<uint16_t>(kLandToolMaximumSize);
WindowTextInputOpen(this, WIDX_PREVIEW, STR_SELECTION_SIZE, STR_ENTER_SELECTION_SIZE, ft, STR_NONE, STR_NONE, 3);
}
bool LandRightsToolIsActive()
{
if (!(InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)))
return false;
if (gCurrentToolWidget.window_classification != WindowClass::LandRights)
return false;
return true;
}
};
WindowBase* LandRightsOpen()
{
return WindowFocusOrCreate<LandRightsWindow>(
WindowClass::LandRights, ScreenCoordsXY(ContextGetWidth() - WW, 29), WW, WH, 0);
}
} // namespace OpenRCT2::Ui::Windows