You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.9 KiB

#include "control.hpp"
#include "control_chat.hpp"
#include "DiabloUI/text_input.hpp"
#include "engine/render/clx_render.hpp"
#include "inv.h"
#include "utils/display.h"
#include "utils/format_int.hpp"
#include "utils/log.hpp"
#include "utils/sdl_compat.h"
namespace devilution {
bool DropGoldFlag;
TextInputCursorState GoldDropCursor;
char GoldDropText[21];
namespace {
int8_t GoldDropInvIndex;
std::optional<NumberInputState> GoldDropInputState;
void RemoveGold(Player &player, int goldIndex, int amount)
{
const int gi = goldIndex - INVITEM_INV_FIRST;
player.InvList[gi]._ivalue -= amount;
if (player.InvList[gi]._ivalue > 0) {
SetPlrHandGoldCurs(player.InvList[gi]);
NetSyncInvItem(player, gi);
} else {
player.RemoveInvItem(gi);
}
MakeGoldStack(player.HoldItem, amount);
NewCursor(player.HoldItem);
player._pGold = CalculateGold(player);
}
int GetGoldDropMax()
{
return GoldDropInputState->max();
}
} // namespace
void DrawGoldSplit(const Surface &out)
{
const int dialogX = 30;
ClxDraw(out, GetPanelPosition(UiPanels::Inventory, { dialogX, 178 }), (*GoldBoxBuffer)[0]);
const std::string_view amountText = GoldDropText;
const TextInputCursorState &cursor = GoldDropCursor;
const int max = GetGoldDropMax();
const std::string description = fmt::format(
fmt::runtime(ngettext(
/* TRANSLATORS: {:s} is a number with separators. Dialog is shown when splitting a stash of Gold.*/
"You have {:s} gold piece. How many do you want to remove?",
"You have {:s} gold pieces. How many do you want to remove?",
max)),
FormatInteger(max));
// Pre-wrap the string at spaces, otherwise DrawString would hard wrap in the middle of words
const std::string wrapped = WordWrapString(description, 200);
// The split gold dialog is roughly 4 lines high, but we need at least one line for the player to input an amount.
// Using a clipping region 50 units high (approx 3 lines with a lineheight of 17) to ensure there is enough room left
// for the text entered by the player.
DrawString(out, wrapped, { GetPanelPosition(UiPanels::Inventory, { dialogX + 31, 75 }), { 200, 50 } },
{ .flags = UiFlags::ColorWhitegold | UiFlags::AlignCenter, .lineHeight = 17 });
// Even a ten digit amount of gold only takes up about half a line. There's no need to wrap or clip text here so we
// use the Point form of DrawString.
DrawString(out, amountText, GetPanelPosition(UiPanels::Inventory, { dialogX + 37, 128 }),
{
.flags = UiFlags::ColorWhite | UiFlags::PentaCursor,
.cursorPosition = static_cast<int>(cursor.position),
.highlightRange = { static_cast<int>(cursor.selection.begin), static_cast<int>(cursor.selection.end) },
});
}
void control_drop_gold(SDL_Keycode vkey)
{
Player &myPlayer = *MyPlayer;
if (myPlayer.hasNoLife()) {
CloseGoldDrop();
return;
}
switch (vkey) {
case SDLK_RETURN:
case SDLK_KP_ENTER:
if (const int value = GoldDropInputState->value(); value != 0) {
RemoveGold(myPlayer, GoldDropInvIndex, value);
}
CloseGoldDrop();
break;
case SDLK_ESCAPE:
CloseGoldDrop();
break;
default:
break;
}
}
void OpenGoldDrop(int8_t invIndex, int max)
{
DropGoldFlag = true;
GoldDropInvIndex = invIndex;
GoldDropText[0] = '\0';
GoldDropInputState.emplace(NumberInputState::Options {
.textOptions {
.value = GoldDropText,
.cursor = &GoldDropCursor,
.maxLength = sizeof(GoldDropText) - 1,
},
.min = 0,
.max = max,
});
SDLC_StartTextInput(ghMainWnd);
}
void CloseGoldDrop()
{
if (!DropGoldFlag)
return;
SDLC_StopTextInput(ghMainWnd);
DropGoldFlag = false;
GoldDropInputState = std::nullopt;
GoldDropInvIndex = 0;
}
bool HandleGoldDropTextInputEvent(const SDL_Event &event)
{
return HandleInputEvent(event, GoldDropInputState);
}
} // namespace devilution