diff --git a/Source/control.cpp b/Source/control.cpp index e9f876b17..6985a72e6 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -717,7 +717,7 @@ void CheckPanelInfo() AddPanelString(_("Hotkey: 's'")); auto &myPlayer = Players[MyPlayerId]; const spell_id spellId = myPlayer._pRSpell; - if (spellId != SPL_INVALID && spellId != SPL_NULL) { + if (IsValidSpell(spellId)) { switch (myPlayer._pRSplType) { case RSPLTYPE_SKILL: AddPanelString(fmt::format(_("{:s} Skill"), pgettext("spell", spelldata[spellId].sSkillText))); diff --git a/Source/controls/modifier_hints.cpp b/Source/controls/modifier_hints.cpp index 6924a5293..c798ad9f1 100644 --- a/Source/controls/modifier_hints.cpp +++ b/Source/controls/modifier_hints.cpp @@ -131,7 +131,7 @@ void DrawSpellsCircleMenuHint(const Surface &out, const Point &origin) for (int slot = 0; slot < 4; ++slot) { splId = myPlayer._pSplHotKey[slot]; - if (splId != SPL_INVALID && splId != SPL_NULL && (spells & GetSpellBitmask(splId)) != 0) + if (IsValidSpell(splId) && (spells & GetSpellBitmask(splId)) != 0) splType = (currlevel == 0 && !spelldata[splId].sTownSpell) ? RSPLTYPE_INVALID : myPlayer._pSplTHotKey[slot]; else { splType = RSPLTYPE_INVALID; diff --git a/Source/items.cpp b/Source/items.cpp index a56c182b8..963aab935 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1907,7 +1907,7 @@ bool SmithItemOk(int i) return false; if (AllItemsList[i].itype == ItemType::Gold) return false; - if (AllItemsList[i].itype == ItemType::Staff && (!gbIsHellfire || AllItemsList[i].iSpell != SPL_NULL)) + if (AllItemsList[i].itype == ItemType::Staff && (!gbIsHellfire || IsValidSpell(AllItemsList[i].iSpell))) return false; if (AllItemsList[i].itype == ItemType::Ring) return false; @@ -2426,7 +2426,7 @@ void CalcPlrItemVals(Player &player, bool loadgfx) maxd += item._iMaxDam; tac += item._iAC; - if (item._iSpell != SPL_NULL) { + if (IsValidSpell(item._iSpell)) { spl |= GetSpellBitmask(item._iSpell); } @@ -4673,7 +4673,7 @@ void RepairItem(Item &item, int lvl) void RechargeItem(Item &item, Player &player) { - if (item._itype != ItemType::Staff || item._iSpell == SPL_NULL) + if (item._itype != ItemType::Staff || !IsValidSpell(item._iSpell)) return; if (item._iCharges == item._iMaxCharges) diff --git a/Source/panels/spell_book.cpp b/Source/panels/spell_book.cpp index 6f359aa2a..4a045bde8 100644 --- a/Source/panels/spell_book.cpp +++ b/Source/panels/spell_book.cpp @@ -137,7 +137,7 @@ void DrawSpellBook(const Surface &out) const int textPaddingTop = 7; for (int i = 1; i < 8; i++) { spell_id sn = SpellPages[sbooktab][i - 1]; - if (sn != SPL_INVALID && (spl & GetSpellBitmask(sn)) != 0) { + if (IsValidSpell(sn) && (spl & GetSpellBitmask(sn)) != 0) { spell_type st = GetSBookTrans(sn, true); SetSpellTrans(st); const Point spellCellPosition = GetPanelPosition(UiPanels::Spell, { 11, yp + SpellBookDescriptionHeight }); @@ -196,7 +196,7 @@ void CheckSBook() spell_id sn = SpellPages[sbooktab][(MousePosition.y - GetRightPanel().position.y - 18) / 43]; auto &player = Players[MyPlayerId]; uint64_t spl = player._pMemSpells | player._pISpells | player._pAblSpells; - if (sn != SPL_INVALID && (spl & GetSpellBitmask(sn)) != 0) { + if (IsValidSpell(sn) && (spl & GetSpellBitmask(sn)) != 0) { spell_type st = RSPLTYPE_SPELL; if ((player._pISpells & GetSpellBitmask(sn)) != 0) { st = RSPLTYPE_CHARGES; diff --git a/Source/panels/spell_list.cpp b/Source/panels/spell_list.cpp index ae329461e..9d25c3645 100644 --- a/Source/panels/spell_list.cpp +++ b/Source/panels/spell_list.cpp @@ -102,18 +102,24 @@ void DrawSpell(const Surface &out) spell_id spl = myPlayer._pRSpell; spell_type st = myPlayer._pRSplType; - // BUGFIX: Move the next line into the if statement to avoid OOB (SPL_INVALID is -1) (fixed) - if (st == RSPLTYPE_SPELL && spl != SPL_INVALID) { + if (!IsValidSpell(spl)) { + st = RSPLTYPE_INVALID; + spl = SPL_NULL; + } + + if (st == RSPLTYPE_SPELL) { int tlvl = myPlayer._pISplLvlAdd + myPlayer._pSplLvl[spl]; if (CheckSpell(MyPlayerId, spl, st, true) != SpellCheckResult::Success) st = RSPLTYPE_INVALID; if (tlvl <= 0) st = RSPLTYPE_INVALID; } + if (currlevel == 0 && st != RSPLTYPE_INVALID && !spelldata[spl].sTownSpell) st = RSPLTYPE_INVALID; + SetSpellTrans(st); - const int nCel = (spl != SPL_INVALID) ? SpellITbl[spl] : 27; + const int nCel = SpellITbl[spl]; const Point position { PANEL_X + 565, PANEL_Y + 119 }; DrawSpellCel(out, position, nCel); @@ -300,7 +306,8 @@ void ToggleSpell(int slot) auto &myPlayer = Players[MyPlayerId]; - if (myPlayer._pSplHotKey[slot] == SPL_INVALID) { + const spell_id spellId = myPlayer._pSplHotKey[slot]; + if (!IsValidSpell(spellId)) { return; } @@ -321,8 +328,7 @@ void ToggleSpell(int slot) return; } - const spell_id spellId = myPlayer._pSplHotKey[slot]; - if (spellId != SPL_INVALID && spellId != SPL_NULL && (spells & GetSpellBitmask(spellId)) != 0) { + if ((spells & GetSpellBitmask(spellId)) != 0) { myPlayer._pRSpell = spellId; myPlayer._pRSplType = myPlayer._pSplTHotKey[slot]; force_redraw = 255; @@ -339,7 +345,7 @@ void DoSpeedBook() auto &myPlayer = Players[MyPlayerId]; - if (myPlayer._pRSpell != SPL_INVALID) { + if (IsValidSpell(myPlayer._pRSpell)) { for (int i = RSPLTYPE_SKILL; i <= RSPLTYPE_CHARGES; i++) { uint64_t spells; switch (i) { diff --git a/Source/player.cpp b/Source/player.cpp index e25265e99..d0d0826c1 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -2117,6 +2117,16 @@ void Player::RestorePartialMana() } } +void Player::ReadySpellFromEquipment(inv_body_loc bodyLocation) +{ + auto &item = InvBody[bodyLocation]; + if (item._itype == ItemType::Staff && IsValidSpell(item._iSpell) && item._iCharges > 0) { + _pRSpell = item._iSpell; + _pRSplType = RSPLTYPE_CHARGES; + force_redraw = 255; + } +} + void Player::UpdatePreviewCelSprite(_cmd_id cmdId, Point point, uint16_t wParam1, uint16_t wParam2) { // if game is not running don't show a preview @@ -3551,7 +3561,7 @@ void CheckPlrSpell(bool isShiftHeld, spell_id spellID, spell_type spellType) } auto &myPlayer = Players[MyPlayerId]; - if (spellID == SPL_INVALID) { + if (!IsValidSpell(spellID)) { myPlayer.Say(HeroSpeech::IDontHaveASpellReady); return; } diff --git a/Source/player.h b/Source/player.h index 65809916a..14fed5e75 100644 --- a/Source/player.h +++ b/Source/player.h @@ -671,15 +671,7 @@ struct Player { * @brief Sets the readied spell to the spell in the specified equipment slot. Does nothing if the item does not have a valid spell. * @param bodyLocation - the body location whose item will be checked for the spell. */ - void ReadySpellFromEquipment(inv_body_loc bodyLocation) - { - auto &item = InvBody[bodyLocation]; - if (item._itype == ItemType::Staff && item._iSpell != SPL_NULL && item._iCharges > 0) { - _pRSpell = item._iSpell; - _pRSplType = RSPLTYPE_CHARGES; - force_redraw = 255; - } - } + void ReadySpellFromEquipment(inv_body_loc bodyLocation); /** * @brief Does the player currently have a ranged weapon equipped? diff --git a/Source/spells.cpp b/Source/spells.cpp index 65639475a..fbe2481a9 100644 --- a/Source/spells.cpp +++ b/Source/spells.cpp @@ -108,6 +108,13 @@ void PlacePlayer(int pnum) } // namespace +bool IsValidSpell(spell_id spl) +{ + return spl > SPL_NULL + && spl <= SPL_LAST + && (spl <= SPL_LASTDIABLO || gbIsHellfire); +} + bool IsWallSpell(spell_id spl) { return spl == SPL_FIREWALL || spl == SPL_LIGHTWALL; diff --git a/Source/spells.h b/Source/spells.h index 821f4bde2..0d9998cab 100644 --- a/Source/spells.h +++ b/Source/spells.h @@ -16,6 +16,7 @@ enum class SpellCheckResult : uint8_t { Fail_Busy, }; +bool IsValidSpell(spell_id spl); bool IsWallSpell(spell_id spl); bool TargetsMonster(spell_id id); int GetManaAmount(Player &player, spell_id sn); diff --git a/Source/stores.cpp b/Source/stores.cpp index 382e15408..514c5e272 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -456,7 +456,7 @@ bool SmithSellOk(int i) return false; if (pI->_itype == ItemType::Gold) return false; - if (pI->_itype == ItemType::Staff && (!gbIsHellfire || pI->_iSpell != SPL_NULL)) + if (pI->_itype == ItemType::Staff && (!gbIsHellfire || IsValidSpell(pI->_iSpell))) return false; if (pI->_iClass == ICLASS_QUEST) return false; @@ -753,7 +753,7 @@ bool WitchSellOk(int i) rv = false; if (pI->_iClass == ICLASS_QUEST) rv = false; - if (pI->_itype == ItemType::Staff && (!gbIsHellfire || pI->_iSpell != SPL_NULL)) + if (pI->_itype == ItemType::Staff && (!gbIsHellfire || IsValidSpell(pI->_iSpell))) rv = true; if (pI->IDidx >= IDI_FIRSTQUEST && pI->IDidx <= IDI_LASTQUEST) rv = false;