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
142 lines
3.9 KiB
|
3 months ago
|
#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
|