Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement quick spell cycling #6861

Merged
merged 6 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Source/DiabloUI/settingsmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,19 @@ void UiSettingsMenu()
break;
}
break;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_MOUSEWHEEL:
if (event.wheel.y > 0) {
key = MouseScrollUpButton;
} else if (event.wheel.y < 0) {
key = MouseScrollDownButton;
} else if (event.wheel.x > 0) {
key = MouseScrollLeftButton;
} else if (event.wheel.x < 0) {
key = MouseScrollRightButton;
}
break;
#endif
}
// Ignore unknown keys
if (key == SDLK_UNKNOWN)
Expand Down
10 changes: 0 additions & 10 deletions Source/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ inline bool CanPanelsCoverView()
const Rectangle &mainPanel = GetMainPanel();
return GetScreenWidth() <= mainPanel.size.width && GetScreenHeight() <= SidePanelSize.height + mainPanel.size.height;
}
void DrawSpellList(const Surface &out);
void SetSpell();
void SetSpeedSpell(size_t slot);
void ToggleSpell(size_t slot);

void AddPanelString(std::string_view str);
void AddPanelString(std::string &&str);
Expand Down Expand Up @@ -127,12 +123,6 @@ void DrawFlaskValues(const Surface &out, Point pos, int currValue, int maxValue)
*/
void control_update_life_mana();

/**
* @brief draws the current right mouse button spell.
* @param out screen buffer representing the main UI panel
*/
void DrawSpell(const Surface &out);

void InitControlPan();
void DrawCtrlPan(const Surface &out);

Expand Down
1 change: 1 addition & 0 deletions Source/controls/game_controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "gamemenu.h"
#include "gmenu.h"
#include "options.h"
#include "panels/spell_list.hpp"
#include "qol/stash.h"
#include "stores.h"

Expand Down
1 change: 1 addition & 0 deletions Source/controls/touch/event_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "gmenu.h"
#include "inv.h"
#include "panels/spell_book.hpp"
#include "panels/spell_list.hpp"
#include "qol/stash.h"
#include "stores.h"
#include "utils/ui_fwd.h"
Expand Down
80 changes: 80 additions & 0 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,43 @@ void GameEventHandler(const SDL_Event &event, uint16_t modState)
MousePosition = { event.button.x, event.button.y };
HandleMouseButtonUp(event.button.button, modState);
return;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_MOUSEWHEEL:
if (event.wheel.y > 0) { // Up
if (stextflag != TalkID::None) {
StoreUp();
} else if (QuestLogIsOpen) {
QuestlogUp();
} else if (HelpFlag) {
HelpScrollUp();
} else if (ChatLogFlag) {
ChatLogScrollUp();
} else if (IsStashOpen) {
Stash.PreviousPage();
} else {
sgOptions.Keymapper.KeyPressed(MouseScrollUpButton);
}
} else if (event.wheel.y < 0) { // down
if (stextflag != TalkID::None) {
StoreDown();
} else if (QuestLogIsOpen) {
QuestlogDown();
} else if (HelpFlag) {
HelpScrollDown();
} else if (ChatLogFlag) {
ChatLogScrollDown();
} else if (IsStashOpen) {
Stash.NextPage();
} else {
sgOptions.Keymapper.KeyPressed(MouseScrollDownButton);
}
} else if (event.wheel.x > 0) { // left
sgOptions.Keymapper.KeyPressed(MouseScrollLeftButton);
} else if (event.wheel.x < 0) { // right
sgOptions.Keymapper.KeyPressed(MouseScrollRightButton);
}
break;
#endif
default:
if (IsCustomEvent(event.type)) {
if (gbIsMultiplayer)
Expand Down Expand Up @@ -1577,6 +1614,33 @@ void SpellBookKeyPressed()
CloseInventory();
}

void CycleSpellHotkeys(bool next)
{
StaticVector<size_t, NumHotkeys> validHotKeyIndexes;
std::optional<size_t> currentIndex;
for (size_t slot = 0; slot < NumHotkeys; slot++) {
if (!IsValidSpeedSpell(slot))
continue;
if (MyPlayer->_pRSpell == MyPlayer->_pSplHotKey[slot] && MyPlayer->_pRSplType == MyPlayer->_pSplTHotKey[slot]) {
// found current
currentIndex = validHotKeyIndexes.size();
}
validHotKeyIndexes.emplace_back(slot);
}
if (validHotKeyIndexes.size() == 0)
return;

size_t newIndex;
if (!currentIndex) {
newIndex = next ? 0 : (validHotKeyIndexes.size() - 1);
} else if (next) {
newIndex = (*currentIndex == validHotKeyIndexes.size() - 1) ? 0 : (*currentIndex + 1);
} else {
newIndex = *currentIndex == 0 ? (validHotKeyIndexes.size() - 1) : (*currentIndex - 1);
}
ToggleSpell(validHotKeyIndexes[newIndex]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks.... more complicated than it needs to be, at least at first glance.

Have you considered just creating 2 separate functions, "NextSkill" and "PreviousSkill", instead of combining both here?

Also, isn't there something in C++ like a "circular iterator" that we could tap into? Then, it would be a matter of walking forward or backward on it, while checking for the first valid spell occurrence using those predicate lambdas.

I don't know..... this might be me just misremembering how awful C++ is, but this looks incredibly convoluted for such a simple operation conceptually. Maybe we are just lacking some abstraction here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't given it much thought.
But I don't know anything about a circular iterator.
If you want you can give it a try to improve it. 🙂


bool IsPlayerDead()
{
return MyPlayer->_pmode == PM_DEATH || MyPlayerIsDead;
Expand Down Expand Up @@ -1643,6 +1707,22 @@ void InitKeymapActions()
CanPlayerTakeAction,
i + 1);
}
sgOptions.Keymapper.AddAction(
"QuickSpellPrevious",
N_("Previous quick spell"),
N_("Selects the previous quick spell (cycles)."),
MouseScrollUpButton,
[] { CycleSpellHotkeys(false); },
nullptr,
CanPlayerTakeAction);
sgOptions.Keymapper.AddAction(
"QuickSpellNext",
N_("Next quick spell"),
N_("Selects the next quick spell (cycles)."),
MouseScrollDownButton,
[] { CycleSpellHotkeys(true); },
nullptr,
CanPlayerTakeAction);
sgOptions.Keymapper.AddAction(
"UseHealthPotion",
N_("Use health potion"),
Expand Down
20 changes: 1 addition & 19 deletions Source/engine/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
case SDL_TEXTEDITING:
case SDL_TEXTINPUT:
case SDL_WINDOWEVENT:
case SDL_MOUSEWHEEL:
#else
case SDL_ACTIVEEVENT:
#endif
Expand All @@ -120,25 +121,6 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
*event = e;
break;
#ifndef USE_SDL1
case SDL_MOUSEWHEEL:
#ifdef _DEBUG
if (IsConsoleOpen()) {
*event = e;
break;
}
#endif
// This is a hack, mousewheel events should be handled directly by their consumers instead.
event->type = SDL_KEYDOWN;
if (e.wheel.y > 0) {
event->key.keysym.sym = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_PLUS : SDLK_UP;
Comment on lines -130 to -133
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm super happy to see this gone, thank you! 🎉
Did we lose the Control + Wheel functionality to zoom the map with this change though?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this logic is also removed. You can still zoom with the +/- keys.
But if we want this back as special case, we can implement them the same way as scrolling in shops etc. is done. 🙂

} else if (e.wheel.y < 0) {
event->key.keysym.sym = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_MINUS : SDLK_DOWN;
} else if (e.wheel.x > 0) {
event->key.keysym.sym = SDLK_LEFT;
} else if (e.wheel.x < 0) {
event->key.keysym.sym = SDLK_RIGHT;
}
break;
#if SDL_VERSION_ATLEAST(2, 0, 4)
case SDL_AUDIODEVICEADDED:
return FalseAvail("SDL_AUDIODEVICEADDED", e.adevice.which);
Expand Down
1 change: 1 addition & 0 deletions Source/engine/render/scrollrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "options.h"
#include "panels/charpanel.hpp"
#include "panels/console.hpp"
#include "panels/spell_list.hpp"
#include "plrmsg.h"
#include "qol/chatlog.h"
#include "qol/floatingnumbers.h"
Expand Down
4 changes: 4 additions & 0 deletions Source/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,10 @@ KeymapperOptions::KeymapperOptions()
keyIDToKeyName.emplace(SDL_BUTTON_MIDDLE | KeymapperMouseButtonMask, "MMOUSE");
keyIDToKeyName.emplace(SDL_BUTTON_X1 | KeymapperMouseButtonMask, "X1MOUSE");
keyIDToKeyName.emplace(SDL_BUTTON_X2 | KeymapperMouseButtonMask, "X2MOUSE");
keyIDToKeyName.emplace(MouseScrollUpButton, "SCROLlUPMOUSE");
keyIDToKeyName.emplace(MouseScrollDownButton, "SCROLLDOWNMOUSE");
keyIDToKeyName.emplace(MouseScrollLeftButton, "SCROLlLEFTMOUSE");
keyIDToKeyName.emplace(MouseScrollRightButton, "SCROLLRIGHTMOUSE");

keyIDToKeyName.emplace(SDLK_BACKQUOTE, "`");
keyIDToKeyName.emplace(SDLK_LEFTBRACKET, "[");
Expand Down
4 changes: 4 additions & 0 deletions Source/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ struct LanguageOptions : OptionCategoryBase {
};

constexpr uint32_t KeymapperMouseButtonMask = 1 << 31;
constexpr uint32_t MouseScrollUpButton = 65536 | KeymapperMouseButtonMask;
constexpr uint32_t MouseScrollDownButton = 65537 | KeymapperMouseButtonMask;
constexpr uint32_t MouseScrollLeftButton = 65538 | KeymapperMouseButtonMask;
constexpr uint32_t MouseScrollRightButton = 65539 | KeymapperMouseButtonMask;

/** The Keymapper maps keys to actions. */
struct KeymapperOptions : OptionCategoryBase {
Expand Down
23 changes: 18 additions & 5 deletions Source/panels/spell_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ void SetSpeedSpell(size_t slot)
return;
}
Player &myPlayer = *MyPlayer;

if (myPlayer._pSplHotKey[slot] == pSpell && myPlayer._pSplTHotKey[slot] == pSplType) {
// Unset spell hotkey
myPlayer._pSplHotKey[slot] = SpellID::Invalid;
return;
}

for (size_t i = 0; i < NumHotkeys; ++i) {
if (myPlayer._pSplHotKey[i] == pSpell && myPlayer._pSplTHotKey[i] == pSplType)
myPlayer._pSplHotKey[i] = SpellID::Invalid;
Expand All @@ -282,15 +289,15 @@ void SetSpeedSpell(size_t slot)
myPlayer._pSplTHotKey[slot] = pSplType;
}

void ToggleSpell(size_t slot)
bool IsValidSpeedSpell(size_t slot)
{
uint64_t spells;

Player &myPlayer = *MyPlayer;

const SpellID spellId = myPlayer._pSplHotKey[slot];
if (!IsValidSpell(spellId)) {
return;
return false;
}

switch (myPlayer._pSplTHotKey[slot]) {
Expand All @@ -307,11 +314,17 @@ void ToggleSpell(size_t slot)
spells = myPlayer._pISpells;
break;
case SpellType::Invalid:
return;
return false;
}

if ((spells & GetSpellBitmask(spellId)) != 0) {
myPlayer._pRSpell = spellId;
return (spells & GetSpellBitmask(spellId)) != 0;
}

void ToggleSpell(size_t slot)
{
if (IsValidSpeedSpell(slot)) {
Player &myPlayer = *MyPlayer;
myPlayer._pRSpell = myPlayer._pSplHotKey[slot];
myPlayer._pRSplType = myPlayer._pSplTHotKey[slot];
RedrawEverything();
}
Expand Down
5 changes: 5 additions & 0 deletions Source/panels/spell_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ struct SpellListItem {
bool isSelected;
};

/**
* @brief draws the current right mouse button spell.
* @param out screen buffer representing the main UI panel
*/
void DrawSpell(const Surface &out);
void DrawSpellList(const Surface &out);
std::vector<SpellListItem> GetSpellListItems();
void SetSpell();
void SetSpeedSpell(size_t slot);
bool IsValidSpeedSpell(size_t slot);
void ToggleSpell(size_t slot);

/**
Expand Down
Loading