Browse Source

Use HoldItem for determining if an item is held

This cleans up a bit of code and solves a few edge cases where an item
could be lost, the game be unresponsive, or miss fire an event during
lag cause of the cursor not reflecting the currently held item.
pull/4482/head
Anders Jenbo 4 years ago
parent
commit
dc706e8ed5
  1. 4
      Source/control.cpp
  2. 14
      Source/controls/plrctrls.cpp
  3. 4
      Source/controls/touch/event_handlers.cpp
  4. 2
      Source/controls/touch/renderers.cpp
  5. 12
      Source/cursor.cpp
  6. 6
      Source/cursor.h
  7. 2
      Source/debug.cpp
  8. 4
      Source/diablo.cpp
  9. 2
      Source/hwcursor.cpp
  10. 12
      Source/inv.cpp
  11. 2
      Source/miniwin/misc_msg.cpp
  12. 2
      Source/player.cpp
  13. 3
      Source/qol/stash.cpp
  14. 11
      Source/scrollrt.cpp
  15. 2
      Source/towners.cpp
  16. 10
      test/cursor_test.cpp

4
Source/control.cpp

@ -852,10 +852,10 @@ void DrawInfoBox(const Surface &out)
InfoColor = UiFlags::ColorWhite;
ClearPanel();
}
auto &myPlayer = Players[MyPlayerId];
if (spselflag || trigflag) {
InfoColor = UiFlags::ColorWhite;
} else if (pcurs >= CURSOR_FIRSTITEM) {
auto &myPlayer = Players[MyPlayerId];
} else if (!myPlayer.HoldItem.isEmpty()) {
if (myPlayer.HoldItem._itype == ItemType::Gold) {
int nGold = myPlayer.HoldItem._ivalue;
InfoString = fmt::format(ngettext("{:d} gold piece", "{:d} gold pieces", nGold), nGold);

14
Source/controls/plrctrls.cpp

@ -713,16 +713,16 @@ void ResetInvCursorPosition()
mousePos = GetSlotCoord(Slot);
}
if (pcurs >= CURSOR_FIRSTITEM) {
if (!MyPlayer->HoldItem.isEmpty()) {
mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX };
}
} else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) {
mousePos = GetSlotCoord(Slot);
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX };
} else {
mousePos = InvGetEquipSlotCoordFromInvSlot((inv_xy_slot)Slot);
if (pcurs >= CURSOR_FIRSTITEM) {
if (!MyPlayer->HoldItem.isEmpty()) {
Size itemSize = GetInventorySize(MyPlayer->HoldItem);
mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX * itemSize.height };
}
@ -1085,7 +1085,7 @@ void StashMove(AxisDirection dir)
// Jump from general inventory to stash
if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) {
int firstSlot = Slot;
if (pcurs < CURSOR_FIRSTITEM) {
if (MyPlayer->HoldItem.isEmpty()) {
int8_t itemId = GetItemIdOnSlot(Slot);
if (itemId != 0) {
firstSlot = FindFirstSlotOnItem(itemId);
@ -1848,7 +1848,7 @@ void PerformSpellAction()
return;
if (invflag) {
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
TryDropItem();
else if (pcurs > CURSOR_HAND) {
TryIconCurs();
@ -1864,7 +1864,7 @@ void PerformSpellAction()
return;
}
if (pcurs >= CURSOR_FIRSTITEM && !TryDropItem())
if (!MyPlayer->HoldItem.isEmpty() && !TryDropItem())
return;
if (pcurs > CURSOR_HAND)
NewCursor(CURSOR_HAND);
@ -1963,7 +1963,7 @@ void PerformSecondaryAction()
return;
}
if (pcurs >= CURSOR_FIRSTITEM && !TryDropItem())
if (!MyPlayer->HoldItem.isEmpty() && !TryDropItem())
return;
if (pcurs > CURSOR_HAND)
NewCursor(CURSOR_HAND);

4
Source/controls/touch/event_handlers.cpp

@ -89,7 +89,7 @@ bool HandleSpeedBookInteraction(const SDL_Event &event)
void HandleBottomPanelInteraction(const SDL_Event &event)
{
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
return;
ClearPanBtn();
@ -118,7 +118,7 @@ void HandleCharacterPanelInteraction(const SDL_Event &event)
void HandleStashPanelInteraction(const SDL_Event &event)
{
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
return;
if (event.type != SDL_FINGERUP) {

2
Source/controls/touch/renderers.cpp

@ -466,7 +466,7 @@ VirtualGamepadButtonType SecondaryActionButtonRenderer::GetButtonType()
VirtualGamepadButtonType SpellActionButtonRenderer::GetButtonType()
{
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
return GetDropButtonType(virtualPadButton->isHeld);
if (invflag && pcursinvitem != -1 && pcurs == CURSOR_HAND) {

12
Source/cursor.cpp

@ -68,6 +68,7 @@ const uint16_t InvItemWidth2[] = {
// clang-format on
};
constexpr uint16_t InvItems1Size = sizeof(InvItemWidth1) / sizeof(InvItemWidth1[0]);
constexpr uint16_t InvItems2Size = sizeof(InvItemWidth2) / sizeof(InvItemWidth2[0]);
/** Maps from objcurs.cel frame number to frame height. */
const uint16_t InvItemHeight1[InvItems1Size] = {
@ -93,7 +94,7 @@ const uint16_t InvItemHeight1[InvItems1Size] = {
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
};
const uint16_t InvItemHeight2[] = {
const uint16_t InvItemHeight2[InvItems2Size] = {
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
@ -105,8 +106,6 @@ const uint16_t InvItemHeight2[] = {
} // namespace
/** Pixel size of the current cursor image */
Size cursSize;
/** Current highlighted monster */
int pcursmonst = -1;
@ -172,7 +171,6 @@ void NewCursor(int cursId)
MyPlayer->HoldItem._itype = ItemType::None;
}
pcurs = cursId;
cursSize = cursId == CURSOR_NONE ? Size { 0, 0 } : GetInvItemSize(cursId);
if (IsHardwareCursorEnabled() && ControlDevice == ControlTypes::KeyboardAndMouse) {
if (ArtCursor.surface == nullptr && cursId == CURSOR_NONE)
@ -190,8 +188,8 @@ void CelDrawCursor(const Surface &out, Point position, int cursId)
{
const auto &sprite = GetInvItemSprite(cursId);
const int frame = GetInvItemFrame(cursId);
if (IsItemSprite(cursId)) {
const auto &heldItem = Players[MyPlayerId].HoldItem;
if (!MyPlayer->HoldItem.isEmpty()) {
const auto &heldItem = MyPlayer->HoldItem;
CelBlitOutlineTo(out, GetOutlineColor(heldItem, true), position, sprite, frame, false);
CelDrawItem(heldItem, out, position, sprite, frame);
} else {
@ -367,7 +365,7 @@ void CheckCursMove()
if (myPlayer._pInvincible) {
return;
}
if (pcurs >= CURSOR_FIRSTITEM || spselflag) {
if (!myPlayer.HoldItem.isEmpty() || spselflag) {
cursPosition = { mx, my };
return;
}

6
Source/cursor.h

@ -32,7 +32,6 @@ enum cursor_id : uint8_t {
CURSOR_FIRSTITEM,
};
extern DVL_API_FOR_TEST Size cursSize;
extern int pcursmonst;
extern int8_t pcursinvitem;
extern uint16_t pcursstashitem;
@ -51,11 +50,6 @@ void CheckRportal();
void CheckTown();
void CheckCursMove();
inline bool IsItemSprite(int cursId)
{
return cursId >= CURSOR_FIRSTITEM;
}
void CelDrawCursor(const Surface &out, Point position, int cursId);
/** Returns the sprite for the given inventory index. */

2
Source/debug.cpp

@ -783,7 +783,7 @@ std::string DebugCmdItemInfo(const string_view parameter)
{
auto &myPlayer = Players[MyPlayerId];
Item *pItem = nullptr;
if (pcurs >= CURSOR_FIRSTITEM) {
if (!myPlayer.HoldItem.isEmpty()) {
pItem = &myPlayer.HoldItem;
} else if (pcursinvitem != -1) {
if (pcursinvitem <= INVITEM_INV_LAST)

4
Source/diablo.cpp

@ -342,9 +342,9 @@ void LeftMouseDown(int wParam)
CheckStashButtonPress(MousePosition);
} else if (sbookflag && GetRightPanel().Contains(MousePosition)) {
CheckSBook();
} else if (pcurs >= CURSOR_FIRSTITEM) {
} else if (!MyPlayer->HoldItem.isEmpty()) {
if (TryInvPut()) {
NetSendCmdPItem(true, CMD_PUTITEM, cursPosition, Players[MyPlayerId].HoldItem);
NetSendCmdPItem(true, CMD_PUTITEM, cursPosition, MyPlayer->HoldItem);
NewCursor(CURSOR_HAND);
}
} else {

2
Source/hwcursor.cpp

@ -98,7 +98,7 @@ bool SetHardwareCursor(SDL_Surface *surface, HotpointPosition hotpointPosition)
bool SetHardwareCursorFromSprite(int pcurs)
{
const bool isItem = IsItemSprite(pcurs);
const bool isItem = !MyPlayer->HoldItem.isEmpty();
if (isItem && !*sgOptions.Graphics.hardwareCursorForItems)
return false;

12
Source/inv.cpp

@ -582,7 +582,7 @@ void CheckInvPaste(int pnum, Point cursorPosition)
CalcPlrInv(player, true);
if (pnum == MyPlayerId) {
if (cn == CURSOR_HAND && !IsHardwareCursor())
SetCursorPos(MousePosition + Displacement(cursSize / 2));
SetCursorPos(MousePosition + Displacement { itemSize * INV_SLOT_HALF_SIZE_PX });
NewCursor(cn);
}
}
@ -856,6 +856,7 @@ void CheckInvCut(int pnum, Point cursorPosition, bool automaticMove, bool dropIt
NewCursor(holdItem._iCurs + CURSOR_FIRSTITEM);
if (!IsHardwareCursor() && !dropItem) {
// For a hardware cursor, we set the "hot point" to the center of the item instead.
Size cursSize = GetInvItemSize(holdItem._iCurs + CURSOR_FIRSTITEM);
SetCursorPos(cursorPosition - Displacement(cursSize / 2));
}
}
@ -1596,7 +1597,7 @@ void TransferItemToStash(Player &player, int location)
void CheckInvItem(bool isShiftHeld, bool isCtrlHeld)
{
if (pcurs >= CURSOR_FIRSTITEM) {
if (!MyPlayer->HoldItem.isEmpty()) {
CheckInvPaste(MyPlayerId, MousePosition);
} else if (IsStashOpen && isCtrlHeld) {
TransferItemToStash(*MyPlayer, pcursinvitem);
@ -1627,7 +1628,7 @@ void InvGetItem(int pnum, int ii)
auto &player = Players[pnum];
if (MyPlayerId == pnum && pcurs >= CURSOR_FIRSTITEM)
if (MyPlayerId == pnum && !player.HoldItem.isEmpty())
NetSendCmdPItem(true, CMD_SYNCPUTITEM, player.position.tile, player.HoldItem);
item._iCreateInfo &= ~CF_PREGEN;
@ -1635,12 +1636,11 @@ void InvGetItem(int pnum, int ii)
CheckQuestItem(player, player.HoldItem);
UpdateBookLevel(player, player.HoldItem);
player.HoldItem._iStatFlag = player.CanUseItem(player.HoldItem);
bool cursorUpdated = false;
if (player.HoldItem._itype == ItemType::Gold && GoldAutoPlace(player, player.HoldItem))
cursorUpdated = true;
player.HoldItem._itype == ItemType::None;
CleanupItems(ii);
pcursitem = -1;
if (!cursorUpdated)
if (!player.HoldItem.isEmpty())
NewCursor(player.HoldItem._iCurs + CURSOR_FIRSTITEM);
}

2
Source/miniwin/misc_msg.cpp

@ -296,7 +296,7 @@ bool FalseAvail(const char *name, int value)
*/
bool BlurInventory()
{
if (pcurs >= CURSOR_FIRSTITEM) {
if (!MyPlayer->HoldItem.isEmpty()) {
if (!TryDropItem()) {
Players[MyPlayerId].Say(HeroSpeech::WhereWouldIPutThis);
return false;

2
Source/player.cpp

@ -3136,7 +3136,7 @@ StartPlayerKill(int pnum, int earflag)
if (pnum == MyPlayerId) {
drawhpflag = true;
if (pcurs >= CURSOR_FIRSTITEM) {
if (!player.HoldItem.isEmpty()) {
DeadItem(player, std::move(player.HoldItem), { 0, 0 });
NewCursor(CURSOR_HAND);
}

3
Source/qol/stash.cpp

@ -225,6 +225,7 @@ void CheckStashCut(Point cursorPosition, bool automaticMove)
NewCursor(holdItem._iCurs + CURSOR_FIRSTITEM);
if (!IsHardwareCursor()) {
// For a hardware cursor, we set the "hot point" to the center of the item instead.
Size cursSize = GetInvItemSize(holdItem._iCurs + CURSOR_FIRSTITEM);
SetCursorPos(cursorPosition - Displacement(cursSize / 2));
}
}
@ -381,7 +382,7 @@ void DrawStash(const Surface &out)
void CheckStashItem(Point mousePosition, bool isShiftHeld, bool isCtrlHeld)
{
if (pcurs >= CURSOR_FIRSTITEM) {
if (!MyPlayer->HoldItem.isEmpty()) {
CheckStashPaste(mousePosition);
} else if (isCtrlHeld) {
TransferItemToInventory(*MyPlayer, pcursstashitem);

11
Source/scrollrt.cpp

@ -265,12 +265,17 @@ bool ShouldShowCursor()
*/
void DrawCursor(const Surface &out)
{
if (pcurs <= CURSOR_NONE || cursSize.width == 0 || cursSize.height == 0 || !ShouldShowCursor()) {
if (pcurs <= CURSOR_NONE || !ShouldShowCursor()) {
return;
}
Size cursSize = GetInvItemSize(pcurs);
if (cursSize.width == 0 || cursSize.height == 0) {
return;
}
// Copy the buffer before the item cursor and its 1px outline are drawn to a temporary buffer.
const int outlineWidth = IsItemSprite(pcurs) ? 1 : 0;
const int outlineWidth = !MyPlayer->HoldItem.isEmpty() ? 1 : 0;
if (MousePosition.x < -cursSize.width - outlineWidth || MousePosition.x - outlineWidth >= out.w() || MousePosition.y < -cursSize.height - outlineWidth || MousePosition.y - outlineWidth >= out.h())
return;
@ -1573,7 +1578,7 @@ void ScrollView()
{
bool scroll;
if (pcurs >= CURSOR_FIRSTITEM)
if (!MyPlayer->HoldItem.isEmpty())
return;
scroll = false;

2
Source/towners.cpp

@ -876,7 +876,7 @@ void TalkToTowner(Player &player, int t)
if (player.position.tile.WalkingDistance(towner.position) >= 2)
return;
if (pcurs >= CURSOR_FIRSTITEM) {
if (!player.HoldItem.isEmpty()) {
return;
}

10
test/cursor_test.cpp

@ -1,15 +1,11 @@
#include <gtest/gtest.h>
#include "cursor.h"
#include "itemdat.h"
using namespace devilution;
TEST(Cursor, SetCursor)
TEST(Cursor, NewCursor)
{
int i = ICURS_SPIKED_CLUB + CURSOR_FIRSTITEM;
NewCursor(i);
EXPECT_EQ(pcurs, i);
EXPECT_EQ(cursSize.width, 1 * 28);
EXPECT_EQ(cursSize.height, 3 * 28);
NewCursor(CURSOR_HOURGLASS);
EXPECT_EQ(pcurs, CURSOR_HOURGLASS);
}

Loading…
Cancel
Save