diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 926f70b6c..4400bc9fa 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -2508,11 +2508,11 @@ bool TryIconCurs() if (pcurs == CURSOR_TELEPORT) { if (pcursmonst != -1) - NetSendCmdParam4(true, CMD_TSPELLID, pcursmonst, static_cast(myPlayer._pTSpell), myPlayer.GetSpellLevel(myPlayer._pTSpell), myPlayer.queuedSpell.spellFrom); + NetSendCmdParam4(true, CMD_TSPELLID, pcursmonst, static_cast(myPlayer.inventorySpell), myPlayer.GetSpellLevel(myPlayer.inventorySpell), myPlayer.spellFrom); else if (pcursplr != -1) - NetSendCmdParam4(true, CMD_TSPELLPID, pcursplr, static_cast(myPlayer._pTSpell), myPlayer.GetSpellLevel(myPlayer._pTSpell), myPlayer.queuedSpell.spellFrom); + NetSendCmdParam4(true, CMD_TSPELLPID, pcursplr, static_cast(myPlayer.inventorySpell), myPlayer.GetSpellLevel(myPlayer.inventorySpell), myPlayer.spellFrom); else - NetSendCmdLocParam3(true, CMD_TSPELLXY, cursPosition, static_cast(myPlayer._pTSpell), myPlayer.GetSpellLevel(myPlayer._pTSpell), myPlayer.queuedSpell.spellFrom); + NetSendCmdLocParam3(true, CMD_TSPELLXY, cursPosition, static_cast(myPlayer.inventorySpell), myPlayer.GetSpellLevel(myPlayer.inventorySpell), myPlayer.spellFrom); NewCursor(CURSOR_HAND); return true; } diff --git a/Source/inv.cpp b/Source/inv.cpp index ecf33aaf3..28c6c725a 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -2094,7 +2094,7 @@ bool UseInvItem(int cii) else if (&player == MyPlayer) PlaySFX(ItemInvSnds[idata]); - UseItem(player.getId(), item->_iMiscId, item->_iSpell); + UseItem(player.getId(), item->_iMiscId, item->_iSpell, cii); if (speedlist) { if (player.SpdList[c]._iMiscId == IMISC_NOTE) { @@ -2104,8 +2104,6 @@ bool UseInvItem(int cii) } if (!item->isScroll() && !item->isRune()) player.RemoveSpdBarItem(c); - else - player.queuedSpell.spellFrom = cii; return true; } if (player.InvList[c]._iMiscId == IMISC_MAPOFDOOM) @@ -2117,8 +2115,6 @@ bool UseInvItem(int cii) } if (!item->isScroll() && !item->isRune()) player.RemoveInvItem(c); - else - player.queuedSpell.spellFrom = cii; return true; } diff --git a/Source/items.cpp b/Source/items.cpp index 0cb46b54d..a1d697c9f 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -3975,9 +3975,10 @@ void PrintItemDur(const Item &item) PrintItemInfo(item); } -void UseItem(size_t pnum, item_misc_id mid, SpellID spl) +void UseItem(size_t pnum, item_misc_id mid, SpellID spellID, int spellFrom) { Player &player = Players[pnum]; + std::optional prepareSpellID; switch (mid) { case IMISC_HEAL: @@ -4047,30 +4048,28 @@ void UseItem(size_t pnum, item_misc_id mid, SpellID spl) break; case IMISC_SCROLL: case IMISC_SCROLLT: - if (ControlMode == ControlTypes::KeyboardAndMouse && GetSpellData(spl).isTargeted()) { - player._pTSpell = spl; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + if (ControlMode == ControlTypes::KeyboardAndMouse && GetSpellData(spellID).isTargeted()) { + prepareSpellID = spellID; } else { ClrPlrPath(player); - player.queuedSpell.spellId = spl; + player.queuedSpell.spellId = spellID; player.queuedSpell.spellType = SpellType::Scroll; player.queuedSpell.spellFrom = 0; player.destAction = ACTION_SPELL; player.destParam1 = cursPosition.x; player.destParam2 = cursPosition.y; - if (&player == MyPlayer && spl == SpellID::Nova) + if (&player == MyPlayer && spellID == SpellID::Nova) NetSendCmdLoc(pnum, true, CMD_NOVA, cursPosition); } break; case IMISC_BOOK: - player._pMemSpells |= GetSpellBitmask(spl); - if (player._pSplLvl[static_cast(spl)] < MaxSpellLevel) - player._pSplLvl[static_cast(spl)]++; + player._pMemSpells |= GetSpellBitmask(spellID); + if (player._pSplLvl[static_cast(spellID)] < MaxSpellLevel) + player._pSplLvl[static_cast(spellID)]++; if (HasNoneOf(player._pIFlags, ItemSpecialEffect::NoMana)) { - player._pMana += GetSpellData(spl).sManaCost << 6; + player._pMana += GetSpellData(spellID).sManaCost << 6; player._pMana = std::min(player._pMana, player._pMaxMana); - player._pManaBase += GetSpellData(spl).sManaCost << 6; + player._pManaBase += GetSpellData(spellID).sManaCost << 6; player._pManaBase = std::min(player._pManaBase, player._pMaxManaBase); } if (&player == MyPlayer) { @@ -4115,33 +4114,31 @@ void UseItem(size_t pnum, item_misc_id mid, SpellID spl) ModifyPlrVit(player, 3); break; case IMISC_RUNEF: - player._pTSpell = SpellID::RuneOfFire; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + prepareSpellID = SpellID::RuneOfFire; break; case IMISC_RUNEL: - player._pTSpell = SpellID::RuneOfLight; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + prepareSpellID = SpellID::RuneOfLight; break; case IMISC_GR_RUNEL: - player._pTSpell = SpellID::RuneOfNova; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + prepareSpellID = SpellID::RuneOfNova; break; case IMISC_GR_RUNEF: - player._pTSpell = SpellID::RuneOfImmolation; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + prepareSpellID = SpellID::RuneOfImmolation; break; case IMISC_RUNES: - player._pTSpell = SpellID::RuneOfStone; - if (&player == MyPlayer) - NewCursor(CURSOR_TELEPORT); + prepareSpellID = SpellID::RuneOfStone; break; default: break; } + + if (prepareSpellID) { + assert(IsValidSpellFrom(spellFrom)); + player.inventorySpell = *prepareSpellID; + player.spellFrom = spellFrom; + if (&player == MyPlayer) + NewCursor(CURSOR_TELEPORT); + } } bool UseItemOpensHive(const Item &item, Point position) diff --git a/Source/items.h b/Source/items.h index 36a88005f..832fcc0c9 100644 --- a/Source/items.h +++ b/Source/items.h @@ -530,7 +530,7 @@ bool DoOil(Player &player, int cii); void DrawUniqueInfo(const Surface &out); void PrintItemDetails(const Item &item); void PrintItemDur(const Item &item); -void UseItem(size_t pnum, item_misc_id Mid, SpellID spl); +void UseItem(size_t pnum, item_misc_id Mid, SpellID spellID, int spellFrom); bool UseItemOpensHive(const Item &item, Point position); bool UseItemOpensGrave(const Item &item, Point position); void SpawnSmith(int lvl); diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 86efcda7d..cc3f50ab1 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -360,9 +360,13 @@ void LoadPlayer(LoadHelper &file, Player &player) player.queuedSpell.spellId = static_cast(file.NextLE()); player.queuedSpell.spellType = static_cast(file.NextLE()); - player.queuedSpell.spellFrom = file.NextLE(); + auto spellFrom = file.NextLE(); + if (!IsValidSpellFrom(spellFrom)) + spellFrom = 0; + player.spellFrom = spellFrom; + player.queuedSpell.spellFrom = spellFrom; file.Skip(2); // Alignment - player._pTSpell = static_cast(file.NextLE()); + player.inventorySpell = static_cast(file.NextLE()); file.Skip(); // Skip _pTSplType file.Skip(3); // Alignment player._pRSpell = static_cast(file.NextLE()); @@ -1136,7 +1140,7 @@ void SavePlayer(SaveHelper &file, const Player &player) file.WriteLE(static_cast(player.queuedSpell.spellType)); file.WriteLE(player.queuedSpell.spellFrom); file.Skip(2); // Alignment - file.WriteLE(static_cast(player._pTSpell)); + file.WriteLE(static_cast(player.inventorySpell)); file.Skip(); // Skip _pTSplType file.Skip(3); // Alignment file.WriteLE(static_cast(player._pRSpell)); diff --git a/Source/player.h b/Source/player.h index 319004aec..9937da164 100644 --- a/Source/player.h +++ b/Source/player.h @@ -332,7 +332,10 @@ struct Player { SpellCastInfo queuedSpell; /** @brief The spell that is currently being cast */ SpellCastInfo executedSpell; - SpellID _pTSpell; + /* @brief Which spell should be executed with CURSOR_TELEPORT */ + SpellID inventorySpell; + /* @brief Inventory location for scrolls with CURSOR_TELEPORT */ + int8_t spellFrom; SpellID _pRSpell; SpellType _pRSplType; SpellID _pSBkSpell; diff --git a/Source/qol/stash.cpp b/Source/qol/stash.cpp index a4bdd7d78..a1a693f2a 100644 --- a/Source/qol/stash.cpp +++ b/Source/qol/stash.cpp @@ -503,7 +503,7 @@ bool UseStashItem(uint16_t c) else PlaySFX(ItemInvSnds[ItemCAnimTbl[item->_iCurs]]); - UseItem(MyPlayerId, item->_iMiscId, item->_iSpell); + UseItem(MyPlayerId, item->_iMiscId, item->_iSpell, -1); if (Stash.stashList[c]._iMiscId == IMISC_MAPOFDOOM) return true; diff --git a/Source/spells.cpp b/Source/spells.cpp index af90a3e5b..fdb32d589 100644 --- a/Source/spells.cpp +++ b/Source/spells.cpp @@ -113,6 +113,17 @@ bool IsValidSpell(SpellID spl) && (spl <= SpellID::LastDiablo || gbIsHellfire); } +bool IsValidSpellFrom(int spellFrom) +{ + if (spellFrom == 0) + return true; + if (spellFrom >= INVITEM_INV_FIRST && spellFrom <= INVITEM_INV_LAST) + return true; + if (spellFrom >= INVITEM_BELT_FIRST && spellFrom <= INVITEM_BELT_LAST) + return true; + return false; +} + bool IsWallSpell(SpellID spl) { return spl == SpellID::FireWall || spl == SpellID::LightningWall; diff --git a/Source/spells.h b/Source/spells.h index 8c1f3a659..b1354e3a4 100644 --- a/Source/spells.h +++ b/Source/spells.h @@ -17,6 +17,7 @@ enum class SpellCheckResult : uint8_t { }; bool IsValidSpell(SpellID spl); +bool IsValidSpellFrom(int spellFrom); bool IsWallSpell(SpellID spl); bool TargetsMonster(SpellID id); int GetManaAmount(const Player &player, SpellID sn); diff --git a/test/player_test.cpp b/test/player_test.cpp index a804c7a14..747590e57 100644 --- a/test/player_test.cpp +++ b/test/player_test.cpp @@ -136,7 +136,7 @@ static void AssertPlayer(Player &player) ASSERT_EQ(player.queuedSpell.spellId, SpellID::Null); ASSERT_EQ(player.queuedSpell.spellType, SpellType::Skill); ASSERT_EQ(player.queuedSpell.spellFrom, 0); - ASSERT_EQ(player._pTSpell, SpellID::Null); + ASSERT_EQ(player.inventorySpell, SpellID::Null); ASSERT_EQ(player._pRSpell, SpellID::TrapDisarm); ASSERT_EQ(player._pRSplType, SpellType::Skill); ASSERT_EQ(player._pSBkSpell, SpellID::Null); diff --git a/test/writehero_test.cpp b/test/writehero_test.cpp index f81f8d978..837286f48 100644 --- a/test/writehero_test.cpp +++ b/test/writehero_test.cpp @@ -312,7 +312,7 @@ void AssertPlayer(Player &player) ASSERT_EQ(player.queuedSpell.spellId, SpellID::Invalid); ASSERT_EQ(player.queuedSpell.spellType, SpellType::Invalid); ASSERT_EQ(player.queuedSpell.spellFrom, 0); - ASSERT_EQ(player._pTSpell, SpellID::Null); + ASSERT_EQ(player.inventorySpell, SpellID::Null); ASSERT_EQ(player._pRSpell, SpellID::Invalid); ASSERT_EQ(player._pRSplType, SpellType::Invalid); ASSERT_EQ(player._pSBkSpell, SpellID::Invalid);