mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 11:03:00 +01:00
Merge pull request #5993 from wolfreak99/improved_window_inputs/ride_price_textinput
Make ride window prices allow text input
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
0.2.0+ (in development)
|
||||
------------------------------------------------------------------------
|
||||
- Feature: [#5993] Ride window prices can now be set via text input.
|
||||
- Feature: [#6998] Guests now wait for passing vehicles before crossing railway tracks.
|
||||
- Fix: [#7628] Always-researched items can be modified in the inventory list.
|
||||
- Fix: [#7643] No Money scenarios with funding set to zero.
|
||||
|
||||
@@ -806,7 +806,7 @@ static void window_cheats_money_mouseup(rct_window *w, rct_widgetindex widgetInd
|
||||
game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_NOMONEY, gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : 1, GAME_COMMAND_CHEAT, 0, 0);
|
||||
break;
|
||||
case WIDX_MONEY_SPINNER:
|
||||
money_to_string(_moneySpinnerValue, _moneySpinnerText, MONEY_STRING_MAXLENGTH);
|
||||
money_to_string(_moneySpinnerValue, _moneySpinnerText, MONEY_STRING_MAXLENGTH, false);
|
||||
window_text_input_raw_open(w, WIDX_MONEY_SPINNER, STR_ENTER_NEW_VALUE, STR_ENTER_NEW_VALUE, _moneySpinnerText, MONEY_STRING_MAXLENGTH);
|
||||
break;
|
||||
case WIDX_SET_MONEY:
|
||||
|
||||
@@ -465,9 +465,11 @@ static constexpr const uint64 window_ride_page_enabled_widgets[] = {
|
||||
(1ULL << WIDX_GRAPH_VERTICAL) |
|
||||
(1ULL << WIDX_GRAPH_LATERAL),
|
||||
MAIN_RIDE_ENABLED_WIDGETS |
|
||||
(1ULL << WIDX_PRIMARY_PRICE) |
|
||||
(1ULL << WIDX_PRIMARY_PRICE_INCREASE) |
|
||||
(1ULL << WIDX_PRIMARY_PRICE_DECREASE) |
|
||||
(1ULL << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK) |
|
||||
(1ULL << WIDX_SECONDARY_PRICE) |
|
||||
(1ULL << WIDX_SECONDARY_PRICE_INCREASE) |
|
||||
(1ULL << WIDX_SECONDARY_PRICE_DECREASE) |
|
||||
(1ULL << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK),
|
||||
@@ -591,6 +593,7 @@ static void window_ride_income_mouseup(rct_window *w, rct_widgetindex widgetInde
|
||||
static void window_ride_income_resize(rct_window *w);
|
||||
static void window_ride_income_mousedown(rct_window *w, rct_widgetindex widgetIndex, rct_widget *widget);
|
||||
static void window_ride_income_update(rct_window *w);
|
||||
static void window_ride_income_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text);
|
||||
static void window_ride_income_invalidate(rct_window *w);
|
||||
static void window_ride_income_paint(rct_window *w, rct_drawpixelinfo *dpi);
|
||||
static bool window_ride_income_can_modify_primary_price(rct_window* w);
|
||||
@@ -880,7 +883,7 @@ static rct_window_event_list window_ride_income_events = {
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
window_ride_income_textinput,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -5840,6 +5843,8 @@ static void window_ride_graphs_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi
|
||||
|
||||
#pragma region Income
|
||||
|
||||
static utf8 _moneyInputText[MONEY_STRING_MAXLENGTH];
|
||||
|
||||
static void update_same_price_throughout_flags(uint32 shop_item)
|
||||
{
|
||||
uint32 newFlags;
|
||||
@@ -5922,6 +5927,11 @@ static void window_ride_income_toggle_secondary_price(rct_window *w)
|
||||
game_do_command(0, 1, 0, (1 << 8) | w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
}
|
||||
|
||||
static void window_ride_income_set_primary_price(rct_window *w, money16 price)
|
||||
{
|
||||
game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006AE1E4
|
||||
@@ -5936,7 +5946,7 @@ static void window_ride_income_increase_primary_price(rct_window *w)
|
||||
if (price < MONEY(20, 00))
|
||||
price++;
|
||||
|
||||
game_do_command(0, 1, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
window_ride_income_set_primary_price(w, price);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5953,7 +5963,19 @@ static void window_ride_income_decrease_primary_price(rct_window *w)
|
||||
if (price > MONEY(0, 00))
|
||||
price--;
|
||||
|
||||
game_do_command(0, 1, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
window_ride_income_set_primary_price(w, price);
|
||||
}
|
||||
|
||||
static money16 window_ride_income_get_secondary_price(rct_window *w)
|
||||
{
|
||||
Ride *ride = get_ride(w->number);
|
||||
money16 price = ride->price_secondary;
|
||||
return price;
|
||||
}
|
||||
|
||||
static void window_ride_income_set_secondary_price(rct_window *w, money16 price)
|
||||
{
|
||||
game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, (w->number & 0x00FF) | 0x0100, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
}
|
||||
|
||||
static bool window_ride_income_can_modify_primary_price(rct_window* w)
|
||||
@@ -5973,15 +5995,12 @@ static bool window_ride_income_can_modify_primary_price(rct_window* w)
|
||||
*/
|
||||
static void window_ride_income_increase_secondary_price(rct_window *w)
|
||||
{
|
||||
Ride *ride;
|
||||
money16 price = window_ride_income_get_secondary_price(w);
|
||||
|
||||
ride = get_ride(w->number);
|
||||
|
||||
money16 price = ride->price_secondary;
|
||||
if (price < MONEY(20, 00))
|
||||
price++;
|
||||
|
||||
game_do_command(0, 1, 0, (w->number & 0x00FF) | 0x0100, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
window_ride_income_set_secondary_price(w, price);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5990,15 +6009,12 @@ static void window_ride_income_increase_secondary_price(rct_window *w)
|
||||
*/
|
||||
static void window_ride_income_decrease_secondary_price(rct_window *w)
|
||||
{
|
||||
Ride *ride;
|
||||
|
||||
ride = get_ride(w->number);
|
||||
|
||||
money16 price = ride->price_secondary;
|
||||
money16 price = window_ride_income_get_secondary_price(w);
|
||||
|
||||
if (price > MONEY(0, 00))
|
||||
price--;
|
||||
|
||||
game_do_command(0, 1, 0, (w->number & 0x00FF) | 0x0100, GAME_COMMAND_SET_RIDE_PRICE, price, 0);
|
||||
window_ride_income_set_secondary_price(w, price);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6007,7 +6023,8 @@ static void window_ride_income_decrease_secondary_price(rct_window *w)
|
||||
*/
|
||||
static void window_ride_income_mouseup(rct_window *w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
switch (widgetIndex) {
|
||||
switch (widgetIndex)
|
||||
{
|
||||
case WIDX_CLOSE:
|
||||
window_close(w);
|
||||
break;
|
||||
@@ -6023,9 +6040,26 @@ static void window_ride_income_mouseup(rct_window *w, rct_widgetindex widgetInde
|
||||
case WIDX_TAB_10:
|
||||
window_ride_set_page(w, widgetIndex - WIDX_TAB_1);
|
||||
break;
|
||||
case WIDX_PRIMARY_PRICE:
|
||||
{
|
||||
if (!window_ride_income_can_modify_primary_price(w))
|
||||
return;
|
||||
|
||||
Ride* ride = get_ride(w->number);
|
||||
|
||||
money_to_string((money32)ride->price, _moneyInputText, MONEY_STRING_MAXLENGTH, true);
|
||||
window_text_input_raw_open(w, WIDX_PRIMARY_PRICE, STR_ENTER_NEW_VALUE, STR_ENTER_NEW_VALUE, _moneyInputText, MONEY_STRING_MAXLENGTH);
|
||||
break;
|
||||
}
|
||||
case WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK:
|
||||
window_ride_income_toggle_primary_price(w);
|
||||
break;
|
||||
case WIDX_SECONDARY_PRICE:{
|
||||
money32 price32 = (money32)window_ride_income_get_secondary_price(w);
|
||||
|
||||
money_to_string(price32, _moneyInputText, MONEY_STRING_MAXLENGTH, true);
|
||||
window_text_input_raw_open(w, WIDX_SECONDARY_PRICE, STR_ENTER_NEW_VALUE, STR_ENTER_NEW_VALUE, _moneyInputText, MONEY_STRING_MAXLENGTH);
|
||||
}break;
|
||||
case WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK:
|
||||
window_ride_income_toggle_secondary_price(w);
|
||||
break;
|
||||
@@ -6082,6 +6116,30 @@ static void window_ride_income_update(rct_window *w)
|
||||
}
|
||||
}
|
||||
|
||||
static void window_ride_income_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text)
|
||||
{
|
||||
if ((widgetIndex != WIDX_PRIMARY_PRICE && widgetIndex != WIDX_SECONDARY_PRICE) || text == nullptr)
|
||||
return;
|
||||
|
||||
money32 price = string_to_money(text);
|
||||
if (price == MONEY32_UNDEFINED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
price = Math::Clamp(MONEY(0, 00), price, MONEY(20, 00));
|
||||
money16 price16 = (money16)price;
|
||||
|
||||
if (widgetIndex == WIDX_PRIMARY_PRICE)
|
||||
{
|
||||
window_ride_income_set_primary_price(w, price16);
|
||||
}
|
||||
else
|
||||
{
|
||||
window_ride_income_set_secondary_price(w, price16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006ADAA3
|
||||
|
||||
@@ -1233,6 +1233,7 @@ void format_string_to_upper(utf8 *dest, size_t size, rct_string_id format, void
|
||||
money32 string_to_money(const char* string_to_monetise)
|
||||
{
|
||||
const char* decimal_char = language_get_string(STR_LOCALE_DECIMAL_POINT);
|
||||
const currency_descriptor* currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format];
|
||||
char processedString[128] = {};
|
||||
|
||||
Guard::Assert(strlen(string_to_monetise) < sizeof(processedString));
|
||||
@@ -1256,6 +1257,11 @@ money32 string_to_money(const char* string_to_monetise)
|
||||
return MONEY32_UNDEFINED;
|
||||
else
|
||||
hasDecSep = true;
|
||||
|
||||
// Replace localised decimal separator with an English one.
|
||||
*dst_ptr++ = '.';
|
||||
src_ptr++;
|
||||
continue;
|
||||
}
|
||||
else if (*src_ptr == '-')
|
||||
{
|
||||
@@ -1301,34 +1307,14 @@ money32 string_to_money(const char* string_to_monetise)
|
||||
processedString[0] = '0';
|
||||
}
|
||||
|
||||
int number = 0, decimal = 0;
|
||||
if (strstr(processedString, decimal_char) == nullptr)
|
||||
{
|
||||
// If decimal char does not exist, no tokenising is needed.
|
||||
number = atoi(processedString);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *numberText = strtok(processedString, decimal_char);
|
||||
char *decimalText = strtok(nullptr, decimal_char);
|
||||
auto number = std::stod(processedString, nullptr);
|
||||
number /= (currencyDesc->rate / 10.0);
|
||||
auto whole = static_cast<uint16>(number);
|
||||
auto fraction = static_cast<uint8>((number - whole) * 100);
|
||||
|
||||
if (numberText != nullptr)
|
||||
number = atoi(numberText);
|
||||
if (decimalText != nullptr)
|
||||
decimal = atoi(decimalText);
|
||||
|
||||
// The second parameter in MONEY must be two digits in length, while the game only ever uses
|
||||
// the first of the two digits.
|
||||
// Convert invalid numbers, such as ".6", ".234", ".05", to ".60", ".20", ".00" (respectively)
|
||||
while (decimal > 10)
|
||||
decimal /= 10;
|
||||
if (decimal < 10)
|
||||
decimal *= 10;
|
||||
}
|
||||
|
||||
money32 result = MONEY(number, decimal);
|
||||
money32 result = MONEY(whole, fraction);
|
||||
// Check if MONEY resulted in overflow
|
||||
if ((number > 0 && result < 0) || result / 10 < number)
|
||||
if ((whole > 0 && result < 0) || result / 10 < whole)
|
||||
{
|
||||
result = INT_MAX;
|
||||
}
|
||||
@@ -1336,26 +1322,50 @@ money32 string_to_money(const char* string_to_monetise)
|
||||
return result;
|
||||
}
|
||||
|
||||
void money_to_string(money32 amount, char * buffer_to_put_value_to, size_t buffer_len)
|
||||
/**
|
||||
*
|
||||
* @param amount The amount in tens of pounds, e.g. 123 = £ 12.30
|
||||
* @param buffer_to_put_value_to Output parameter.
|
||||
* @param buffer_len Length of the buffer.
|
||||
* @param forceDecimals Show decimals, even if the amount does not have them. Will be ignored if the current exchange
|
||||
* rate is too big to have decimals.
|
||||
*/
|
||||
void money_to_string(money32 amount, char * buffer_to_put_value_to, size_t buffer_len, bool forceDecimals)
|
||||
{
|
||||
if (amount == MONEY32_UNDEFINED) {
|
||||
if (amount == MONEY32_UNDEFINED)
|
||||
{
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "0");
|
||||
return;
|
||||
}
|
||||
|
||||
const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format];
|
||||
|
||||
int sign = amount >= 0 ? 1 : -1;
|
||||
int a = abs(amount);
|
||||
if (a / 10 > 0 && a % 10 > 0) { // If whole and decimal exist
|
||||
int a = abs(amount) * currencyDesc->rate;
|
||||
|
||||
bool amountIsInteger = (a / 100 > 0) && (a % 100 == 0);
|
||||
|
||||
// If whole and decimal exist
|
||||
if ((a / 100 > 0 && a % 100 > 0) || (amountIsInteger && forceDecimals && currencyDesc->rate < 100))
|
||||
{
|
||||
const char* decimal_char = language_get_string(STR_LOCALE_DECIMAL_POINT);
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%d%s%d0", (a / 10) * sign, decimal_char, a % 10);
|
||||
auto decimalPart = a % 100;
|
||||
auto precedingZero = (decimalPart < 10) ? "0" : "";
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%d%s%s%d", (a / 100) * sign, decimal_char, precedingZero, decimalPart);
|
||||
}
|
||||
else if (a / 10 > 0 && a % 10 == 0) { // If whole exists, but not decimal
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%d", (a / 10) * sign);
|
||||
// If whole exists, but not decimal
|
||||
else if (amountIsInteger)
|
||||
{
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%d", (a / 100) * sign);
|
||||
}
|
||||
else if (a / 10 == 0 && a % 10 > 0) { // If decimal exists, but not whole
|
||||
// If decimal exists, but not whole
|
||||
else if (a / 100 == 0 && a % 100 > 0)
|
||||
{
|
||||
const char* decimal_char = language_get_string(STR_LOCALE_DECIMAL_POINT);
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%s0%s%d0", sign < 0 ? "-" : "", decimal_char, a % 10);
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "%s0%s%d", sign < 0 ? "-" : "", decimal_char, a % 100);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
snprintf(buffer_to_put_value_to, buffer_len, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ sint32 get_string_length(const utf8 *text);
|
||||
// The maximum number of characters allowed for string/money conversions (anything above will risk integer overflow issues)
|
||||
#define MONEY_STRING_MAXLENGTH 14
|
||||
money32 string_to_money(const char* string_to_monetise);
|
||||
void money_to_string(money32 amount, char * buffer_to_put_value_to, size_t buffer_len);
|
||||
void money_to_string(money32 amount, char * buffer_to_put_value_to, size_t buffer_len, bool forceDecimals);
|
||||
|
||||
void user_string_clear_all();
|
||||
rct_string_id user_string_allocate(sint32 base, const utf8 *text);
|
||||
|
||||
Reference in New Issue
Block a user