Skip to content

Commit

Permalink
Implement strings for GameAction errors
Browse files Browse the repository at this point in the history
  • Loading branch information
IntelOrca committed Apr 26, 2020
1 parent 2ad37db commit 83fe0cf
Show file tree
Hide file tree
Showing 18 changed files with 135 additions and 41 deletions.
5 changes: 5 additions & 0 deletions src/openrct2-ui/WindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ class WindowManager final : public IWindowManager
return window_error_open(title, message);
}

rct_window* ShowError(const std::string_view& title, const std::string_view& message) override
{
return window_error_open(title, message);
}

rct_window* OpenIntent(Intent* intent) override
{
switch (intent->GetWindowClass())
Expand Down
40 changes: 24 additions & 16 deletions src/openrct2-ui/windows/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static rct_window_event_list window_error_events = {
};
// clang-format on

static char _window_error_text[512];
static std::string _window_error_text;
static uint16_t _window_error_num_lines;

/**
Expand All @@ -74,30 +74,38 @@ static uint16_t _window_error_num_lines;
*/
rct_window* window_error_open(rct_string_id title, rct_string_id message)
{
utf8* dst;
auto titlez = format_string(title, gCommonFormatArgs);
auto messagez = format_string(message, gCommonFormatArgs);
return window_error_open(titlez, messagez);
}

rct_window* window_error_open(const std::string_view& title, const std::string_view& message)
{
int32_t numLines, fontHeight, width, height, maxY;
rct_window* w;

window_close_by_class(WC_ERROR);
dst = _window_error_text;
auto& buffer = _window_error_text;
buffer.clear();

// Format the title
dst = utf8_write_codepoint(dst, FORMAT_BLACK);
if (title != STR_NONE)
{
format_string(dst, 512 - (dst - _window_error_text), title, gCommonFormatArgs);
dst = get_string_end(dst);
char temp[8]{};
utf8_write_codepoint(temp, FORMAT_BLACK);
buffer.append(temp);
}
buffer.append(title);

// Format the message
if (message != STR_NONE)
if (!message.empty())
{
dst = utf8_write_codepoint(dst, FORMAT_NEWLINE);
format_string(dst, 512 - (dst - _window_error_text), message, gCommonFormatArgs);
dst = get_string_end(dst);
char temp[8]{};
utf8_write_codepoint(temp, FORMAT_NEWLINE);
buffer.append(temp);
buffer.append(message);
}

log_verbose("show error, %s", _window_error_text + 1);
log_verbose("show error, %s", buffer.c_str() + 1);

// Don't do unnecessary work in headless. Also saves checking if cursor state is null.
if (gOpenRCT2Headless)
Expand All @@ -106,15 +114,15 @@ rct_window* window_error_open(rct_string_id title, rct_string_id message)
}

// Check if there is any text to display
if (dst == _window_error_text + 1)
if (buffer.size() <= 1)
return nullptr;

gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
width = gfx_get_string_width_new_lined(_window_error_text);
width = gfx_get_string_width_new_lined(buffer.data());
width = std::clamp(width, 64, 196);

gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
gfx_wrap_string(_window_error_text, width + 1, &numLines, &fontHeight);
gfx_wrap_string(buffer.data(), width + 1, &numLines, &fontHeight);

_window_error_num_lines = numLines;
width = width + 3;
Expand Down Expand Up @@ -186,5 +194,5 @@ static void window_error_paint(rct_window* w, rct_drawpixelinfo* dpi)

l = w->windowPos.x + (w->width + 1) / 2 - 1;
t = w->windowPos.y + 1;
draw_string_centred_raw(dpi, l, t, _window_error_num_lines, _window_error_text);
draw_string_centred_raw(dpi, l, t, _window_error_num_lines, _window_error_text.data());
}
5 changes: 4 additions & 1 deletion src/openrct2-ui/windows/RideConstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1824,7 +1824,10 @@ static void window_ride_construction_construct(rct_window* w)
// Used by some functions
if (res->Error != GA_ERROR::OK)
{
gGameCommandErrorText = res->ErrorMessage;
if (auto error = std::get_if<rct_string_id>(&res->ErrorMessage))
gGameCommandErrorText = *error;
else
gGameCommandErrorText = STR_NONE;
_trackPlaceCost = MONEY32_UNDEFINED;
}
else
Expand Down
14 changes: 10 additions & 4 deletions src/openrct2-ui/windows/TopToolbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1947,9 +1947,12 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo
break;
}

if (res->ErrorMessage == STR_NOT_ENOUGH_CASH_REQUIRES || res->ErrorMessage == STR_CAN_ONLY_BUILD_THIS_ON_WATER)
if (auto message = std::get_if<rct_string_id>(&res->ErrorMessage))
{
break;
if (*message == STR_NOT_ENOUGH_CASH_REQUIRES || *message == STR_CAN_ONLY_BUILD_THIS_ON_WATER)
{
break;
}
}

if (zAttemptRange != 1)
Expand Down Expand Up @@ -1997,9 +2000,12 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo
break;
}

if (res->ErrorMessage == STR_NOT_ENOUGH_CASH_REQUIRES || res->ErrorMessage == STR_CAN_ONLY_BUILD_THIS_ON_WATER)
if (auto message = std::get_if<rct_string_id>(&res->ErrorMessage))
{
break;
if (*message == STR_NOT_ENOUGH_CASH_REQUIRES || *message == STR_CAN_ONLY_BUILD_THIS_ON_WATER)
{
break;
}
}

if (zAttemptRange != 1)
Expand Down
9 changes: 7 additions & 2 deletions src/openrct2-ui/windows/TrackDesignPlace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@
#include <openrct2/ride/TrackDesign.h>
#include <openrct2/ride/TrackDesignRepository.h>
#include <openrct2/sprites.h>
#include <openrct2/ui/UiContext.h>
#include <openrct2/ui/WindowManager.h>
#include <openrct2/windows/Intent.h>
#include <openrct2/world/Park.h>
#include <openrct2/world/Surface.h>
#include <vector>

using namespace OpenRCT2;

constexpr int16_t TRACK_MINI_PREVIEW_WIDTH = 168;
constexpr int16_t TRACK_MINI_PREVIEW_HEIGHT = 78;
constexpr uint16_t TRACK_MINI_PREVIEW_SIZE = TRACK_MINI_PREVIEW_WIDTH * TRACK_MINI_PREVIEW_HEIGHT;
Expand Down Expand Up @@ -391,8 +395,9 @@ static void window_track_place_tooldown(rct_window* w, rct_widgetindex widgetInd

// Unable to build track
audio_play_sound_at_location(SoundId::Error, trackLoc);
std::copy(res->ErrorMessageArgs.begin(), res->ErrorMessageArgs.end(), gCommonFormatArgs);
context_show_error(res->ErrorTitle, res->ErrorMessage);

auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->ShowError(res->GetErrorTitle(), res->GetErrorMessage());
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/openrct2-ui/windows/Window.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <openrct2/common.h>
#include <openrct2/ride/Ride.h>
#include <openrct2/windows/tile_inspector.h>
#include <string_view>

using loadsave_callback = void (*)(int32_t result, const utf8* path);
using scenarioselect_callback = void (*)(const utf8* path);
Expand Down Expand Up @@ -105,6 +106,7 @@ void window_title_command_editor_open(struct TitleSequence* sequence, int32_t co
rct_window* window_scenarioselect_open(scenarioselect_callback callback, bool titleEditor);

rct_window* window_error_open(rct_string_id title, rct_string_id message);
rct_window* window_error_open(const std::string_view& title, const std::string_view& message);
struct TrackDesign;
rct_window* window_loadsave_open(int32_t type, const char* defaultName, loadsave_callback callback, TrackDesign* t6Exporter);
rct_window* window_track_place_open(const struct track_design_file_ref* tdFileRef);
Expand Down
37 changes: 34 additions & 3 deletions src/openrct2/actions/GameAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
#include "../network/network.h"
#include "../platform/platform.h"
#include "../scenario/Scenario.h"
#include "../ui/UiContext.h"
#include "../ui/WindowManager.h"
#include "../world/Park.h"
#include "../world/Scenery.h"

#include <algorithm>
#include <iterator>

using namespace OpenRCT2;

GameActionResult::GameActionResult(GA_ERROR error, rct_string_id message)
{
Error = error;
Expand All @@ -45,6 +49,34 @@ GameActionResult::GameActionResult(GA_ERROR error, rct_string_id title, rct_stri
std::copy_n(args, ErrorMessageArgs.size(), ErrorMessageArgs.begin());
}

std::string GameActionResult::GetErrorTitle() const
{
std::string titlez;
if (auto title = std::get_if<std::string>(&ErrorTitle))
{
titlez = *title;
}
else
{
titlez = format_string(std::get<rct_string_id>(ErrorTitle), nullptr);
}
return titlez;
}

std::string GameActionResult::GetErrorMessage() const
{
std::string messagez;
if (auto message = std::get_if<std::string>(&ErrorMessage))
{
messagez = *message;
}
else
{
messagez = format_string(std::get<rct_string_id>(ErrorMessage), ErrorMessageArgs.data());
}
return messagez;
}

namespace GameActions
{
struct QueuedGameAction
Expand Down Expand Up @@ -486,9 +518,8 @@ namespace GameActions

if (result->Error != GA_ERROR::OK && shouldShowError)
{
// Show the error box
std::copy(result->ErrorMessageArgs.begin(), result->ErrorMessageArgs.end(), gCommonFormatArgs);
context_show_error(result->ErrorTitle, result->ErrorMessage);
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->ShowError(result->GetErrorTitle(), result->GetErrorMessage());
}

return result;
Expand Down
8 changes: 6 additions & 2 deletions src/openrct2/actions/GameAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <functional>
#include <memory>
#include <utility>
#include <variant>

/**
* Common error codes for game actions.
Expand Down Expand Up @@ -69,8 +70,8 @@ class GameActionResult
using Ptr = std::unique_ptr<GameActionResult>;

GA_ERROR Error = GA_ERROR::OK;
rct_string_id ErrorTitle = STR_NONE;
rct_string_id ErrorMessage = STR_NONE;
std::variant<rct_string_id, std::string> ErrorTitle = STR_NONE;
std::variant<rct_string_id, std::string> ErrorMessage = STR_NONE;
std::array<uint8_t, 32> ErrorMessageArgs;
CoordsXYZ Position = { LOCATION_NULL, LOCATION_NULL, LOCATION_NULL };
money32 Cost = 0;
Expand All @@ -82,6 +83,9 @@ class GameActionResult
GameActionResult(GA_ERROR error, rct_string_id title, rct_string_id message, uint8_t* args);
GameActionResult(const GameActionResult&) = delete;
virtual ~GameActionResult(){};

std::string GetErrorTitle() const;
std::string GetErrorMessage() const;
};

struct GameAction
Expand Down
10 changes: 8 additions & 2 deletions src/openrct2/actions/GameActionCompat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,14 @@ money32 maze_set_track(

// NOTE: ride_construction_tooldown_construct requires them to be set.
// Refactor result type once theres no C code referencing this function.
gGameCommandErrorText = res->ErrorMessage;
gGameCommandErrorTitle = res->ErrorTitle;
if (auto title = std::get_if<rct_string_id>(&res->ErrorTitle))
gGameCommandErrorTitle = *title;
else
gGameCommandErrorTitle = STR_NONE;
if (auto message = std::get_if<rct_string_id>(&res->ErrorMessage))
gGameCommandErrorText = *message;
else
gGameCommandErrorText = STR_NONE;

if (res->Error != GA_ERROR::OK)
{
Expand Down
2 changes: 1 addition & 1 deletion src/openrct2/actions/LandSmoothAction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActionRe
}
default:
log_error("Invalid map selection %u", _selectionType);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, res->ErrorTitle);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, std::get<rct_string_id>(res->ErrorTitle));
} // switch selectionType

// Raise / lower the land tool selection area
Expand Down
4 changes: 2 additions & 2 deletions src/openrct2/actions/MazePlaceTrackAction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameAct
{ _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 },
GetFlags(), &clearCost, CREATE_CROSSING_MODE_NONE))
{
return MakeResult(GA_ERROR::NO_CLEARANCE, res->ErrorTitle, gGameCommandErrorText, gCommonFormatArgs);
return MakeResult(GA_ERROR::NO_CLEARANCE, std::get<rct_string_id>(res->ErrorTitle), gGameCommandErrorText, gCommonFormatArgs);
}

if (gMapGroundFlags & ELEMENT_IS_UNDERWATER)
Expand Down Expand Up @@ -162,7 +162,7 @@ DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameAct
{ _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 },
GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE))
{
return MakeResult(GA_ERROR::NO_CLEARANCE, res->ErrorTitle, gGameCommandErrorText, gCommonFormatArgs);
return MakeResult(GA_ERROR::NO_CLEARANCE, std::get<rct_string_id>(res->ErrorTitle), gGameCommandErrorText, gCommonFormatArgs);
}

money32 price = (((RideTrackCosts[ride->type].track_price * TrackPricing[TRACK_ELEM_MAZE]) >> 16));
Expand Down
3 changes: 2 additions & 1 deletion src/openrct2/actions/MazeSetTrackAction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ DEFINE_GAME_ACTION(MazeSetTrackAction, GAME_COMMAND_SET_MAZE_TRACK, GameActionRe

if (!map_can_construct_at({ _loc.ToTileStart(), baseHeight, clearanceHeight }, { 0b1111, 0 }))
{
return MakeResult(GA_ERROR::NO_CLEARANCE, res->ErrorTitle, gGameCommandErrorText, gCommonFormatArgs);
return MakeResult(
GA_ERROR::NO_CLEARANCE, std::get<rct_string_id>(res->ErrorTitle), gGameCommandErrorText, gCommonFormatArgs);
}

if (gMapGroundFlags & ELEMENT_IS_UNDERWATER)
Expand Down
15 changes: 15 additions & 0 deletions src/openrct2/scripting/Duktape.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@ template<typename T> DukValue GetObjectAsDukValue(duk_context* ctx, const std::s
return DukValue::take_from_stack(ctx);
}

template<typename T>
const T AsOrDefault(const DukValue& value, const T& defaultValue = {}) = delete;

template<>
inline const std::string AsOrDefault(const DukValue& value, const std::string& defaultValue)
{
return value.type() == DukValue::STRING ? value.as_string() : defaultValue;
}

template<>
inline const int32_t AsOrDefault(const DukValue& value, const int32_t& defaultValue)
{
return value.type() == DukValue::NUMBER ? value.as_int() : defaultValue;
}

#endif
4 changes: 2 additions & 2 deletions src/openrct2/scripting/ScContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ namespace OpenRCT2::Scripting

if (res.Error != GA_ERROR::OK)
{
auto title = format_string(res.ErrorTitle, nullptr);
auto title = res.GetErrorTitle();
duk_push_string(ctx, title.c_str());
duk_put_prop_string(ctx, objIdx, "errorTitle");

auto message = format_string(res.ErrorMessage, res.ErrorMessageArgs.data());
auto message = res.GetErrorMessage();
duk_push_string(ctx, message.c_str());
duk_put_prop_string(ctx, objIdx, "errorMessage");
}
Expand Down
8 changes: 4 additions & 4 deletions src/openrct2/scripting/ScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,10 +732,10 @@ std::unique_ptr<GameActionResult> ScriptEngine::QueryOrExecuteCustomGameAction(
std::unique_ptr<GameActionResult> ScriptEngine::DukToGameActionResult(const DukValue& d)
{
auto result = std::make_unique<GameActionResult>();
result->Error = d["error"].type() == DukValue::Type::NUMBER ? static_cast<GA_ERROR>(d["error"].as_int()) : GA_ERROR::OK;
auto errorTitle = d["errorTitle"].type() == DukValue::Type::STRING ? d["errorTitle"].as_string() : std::string();
auto errorMessage = d["errorMessage"].type() == DukValue::Type::STRING ? d["errorMessage"].as_string() : std::string();
result->Cost = d["cost"].type() == DukValue::Type::NUMBER ? d["cost"].as_int() : 0;
result->Error = static_cast<GA_ERROR>(AsOrDefault<int32_t>(d["error"]));
result->ErrorTitle = AsOrDefault<std::string>(d["errorTitle"]);
result->ErrorMessage = AsOrDefault<std::string>(d["errorMessage"]);
result->Cost = AsOrDefault<int32_t>(d["cost"]);
return result;
}

Expand Down
4 changes: 4 additions & 0 deletions src/openrct2/ui/DummyWindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ namespace OpenRCT2::Ui
{
return nullptr;
}
rct_window* ShowError(const std::string_view& /*title*/, const std::string_view& /*message*/) override
{
return nullptr;
}
rct_window* OpenIntent(Intent* /*intent*/) override
{
return nullptr;
Expand Down
1 change: 1 addition & 0 deletions src/openrct2/ui/WindowManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace OpenRCT2::Ui
virtual rct_window* OpenIntent(Intent * intent) abstract;
virtual void BroadcastIntent(const Intent& intent) abstract;
virtual rct_window* ShowError(rct_string_id title, rct_string_id message) abstract;
virtual rct_window* ShowError(const std::string_view& title, const std::string_view& message) abstract;
virtual void ForceClose(rct_windowclass windowClass) abstract;
virtual void UpdateMapTooltip() abstract;
virtual void HandleInput() abstract;
Expand Down

0 comments on commit 83fe0cf

Please sign in to comment.