Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0f56db6
Add Disable Search Spell Option and enable Infravision for Monk skill
wkdgmr Mar 17, 2025
0ef002a
Fix options reference
wkdgmr Mar 17, 2025
4ca7450
Make disableSearch option visible
wkdgmr Mar 17, 2025
19c2d6f
Disable Search Add idx reroll to SpawnItem
wkdgmr Mar 17, 2025
d28987d
fix clang
wkdgmr Mar 17, 2025
fdf84e6
Refactor Search Reroll logic, fix spellbook selection
wkdgmr Mar 17, 2025
07037ad
remove disableSearch check from WitchItemOkay as this is handled upst…
wkdgmr Mar 17, 2025
d45a9b4
disableSearch fix GetSpellListSelection() bug
wkdgmr Mar 17, 2025
08def45
Finalizing Pull Request
wkdgmr Mar 17, 2025
bd33779
Fixing unintended line changes
wkdgmr Mar 17, 2025
825e9c9
removing IsAnyOf() references that are invalid
wkdgmr Mar 17, 2025
a3347e2
fixing iSpell item reference
wkdgmr Mar 17, 2025
9420302
Fixing GetSpellListSelection()
wkdgmr Mar 17, 2025
b7c6acc
bug fix for potential morph and desync issues
wkdgmr Mar 18, 2025
9417c1c
disableSearch crash proofing
wkdgmr Mar 18, 2025
5893ea6
reroll limit store original pointer and clear item
wkdgmr Mar 18, 2025
417a348
DeleteItem(ii) before return, simplify SetupBaseItem logic
wkdgmr Mar 18, 2025
441ec3e
No Search Vendor and CreateItemType skip no morph
wkdgmr Mar 21, 2025
bde4c6e
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Mar 21, 2025
1a00076
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Mar 21, 2025
d3414cb
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Mar 23, 2025
60349c7
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Apr 2, 2025
6f58070
Stop Adria from selling Books of Search
wkdgmr Apr 3, 2025
454ccaf
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Apr 7, 2025
eee34c6
fix stop adria from selling books of search
wkdgmr Apr 7, 2025
dba412d
refactor reroll logic
wkdgmr Apr 7, 2025
de61bf3
search on all of the time when disabled
wkdgmr Apr 7, 2025
8cfd652
forgot the include
wkdgmr Apr 7, 2025
e76a6dd
Update options description search effect always enabled
wkdgmr Apr 7, 2025
5af0b98
delete erroneous file
wkdgmr Apr 8, 2025
dd2771e
code refactor to deduplicate item setup logic
wkdgmr Apr 8, 2025
b507049
death by underscore
wkdgmr Apr 8, 2025
ce494fc
final refactor
wkdgmr Apr 8, 2025
985aff9
fix disableSearch bug
wkdgmr Apr 10, 2025
f583ab7
sgGameInitInfo disableSearch multiplayer handling
wkdgmr Apr 10, 2025
ef0217c
Merge branch 'diasurgical:master' into disableSearchInfraMonkOptions
wkdgmr Apr 10, 2025
d0118a1
Syncing branch and resetting CreateRndItem
wkdgmr Apr 10, 2025
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
1 change: 1 addition & 0 deletions Source/DiabloUI/multi/selgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@
uint32_t firstPublicGameInfoRequestSend = 0;
size_t HighlightedItem;

void selgame_FreeVectors()

Check warning on line 51 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:51:6 [readability-identifier-naming]

invalid case style for function 'selgame_FreeVectors'
{
vecSelGameDlgItems.clear();

vecSelGameDialog.clear();
}

void selgame_Init()

Check warning on line 58 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:58:6 [readability-identifier-naming]

invalid case style for function 'selgame_Init'
{
LoadBackgroundArt("ui_art\\selgame");
LoadScrollBar();
}

void selgame_Free()

Check warning on line 64 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:64:6 [readability-identifier-naming]

invalid case style for function 'selgame_Free'
{
ArtBackground = std::nullopt;
UnloadScrollBar();
Expand All @@ -77,7 +77,7 @@
return false;
}

static std::string GetErrorMessageIncompatibility(const GameData &data)

Check warning on line 80 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:80:20 [readability-static-definition-in-anonymous-namespace]

'GetErrorMessageIncompatibility' is a static definition in anonymous namespace; static is redundant here
{
if (data.programid != GAME_ID) {
std::string_view gameMode;
Expand All @@ -98,12 +98,12 @@
return std::string(_("The host is running a different game than you."));
}
return fmt::format(fmt::runtime(_("The host is running a different game mode ({:s}) than you.")), gameMode);
} else {

Check warning on line 101 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:101:4 [readability-else-after-return]

do not use 'else' after 'return'
return fmt::format(fmt::runtime(_(/* TRANSLATORS: Error message when somebody tries to join a game running another version. */ "Your version {:s} does not match the host {:d}.{:d}.{:d}.")), PROJECT_VERSION, data.versionMajor, data.versionMinor, data.versionPatch);
}
}

void UiInitGameSelectionList(std::string_view search)

Check warning on line 106 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:106:6 [misc-no-recursion]

function 'UiInitGameSelectionList' is within a recursive call chain
{
selgame_enteringGame = false;
selgame_selectedGame = 0;
Expand Down Expand Up @@ -263,7 +263,7 @@
}
infoString += '\n';
infoString.append(_("Players: "));
for (auto &playerName : gameInfo.players) {

Check warning on line 266 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:266:9 [readability-qualified-auto]

'auto &playerName' can be declared as 'const auto &playerName'
infoString.append(playerName);
infoString += ' ';
}
Expand All @@ -289,7 +289,7 @@
return true;
}

void selgame_GameSelection_Select(size_t value)

Check warning on line 292 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:292:6 [misc-no-recursion]

function 'selgame_GameSelection_Select' is within a recursive call chain
{
selgame_enteringGame = true;
selgame_selectedGame = value;
Expand Down Expand Up @@ -601,7 +601,7 @@
return false;
}

void selgame_Password_Select(size_t /*value*/)

Check warning on line 604 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:604:6 [readability-function-cognitive-complexity]

function 'selgame_Password_Select' has cognitive complexity of 43 (threshold 25)

Check warning on line 604 in Source/DiabloUI/multi/selgame.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/multi/selgame.cpp:604:6 [misc-no-recursion]

function 'selgame_Password_Select' is within a recursive call chain
{
char *gamePassword = nullptr;
if (selgame_selectedGame == 0)
Expand Down Expand Up @@ -660,6 +660,7 @@
m_game_data->bRunInTown = *GetOptions().Gameplay.runInTown ? 1 : 0;
m_game_data->bTheoQuest = *GetOptions().Gameplay.theoQuest ? 1 : 0;
m_game_data->bCowQuest = *GetOptions().Gameplay.cowQuest ? 1 : 0;
m_game_data->bDisableSearch = *GetOptions().Gameplay.disableSearch ? 1 : 0;

GameData gameInitInfo = *m_game_data;
gameInitInfo.swapLE();
Expand Down
3 changes: 2 additions & 1 deletion Source/automap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "engine/render/primitive_render.hpp"
#include "levels/gendung.h"
#include "levels/setmaps.h"
#include "options.h"
#include "player.h"
#include "utils/attributes.h"
#include "utils/enum_traits.h"
Expand Down Expand Up @@ -1842,7 +1843,7 @@ void DrawAutomap(const Surface &out)
}
}

if (AutoMapShowItems)
if (AutoMapShowItems || *GetOptions().Gameplay.disableSearch)
SearchAutomapItem(out, myPlayerOffset, 8, [](Point position) { return dItem[position.x][position.y] != 0; });
#ifdef _DEBUG
if (IsDebugAutomapHighlightNeeded())
Expand Down
42 changes: 32 additions & 10 deletions Source/items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,8 @@ _item_indexes RndUItem(Monster *monster)
return false;
if (IsAnyOf(item.itype, ItemType::Gold, ItemType::Misc))
return false;
if (sgGameInitInfo.bDisableSearch == 1 && item.iSpell == SpellID::Search)
return false;
return true;
});
}
Expand All @@ -1414,6 +1416,8 @@ _item_indexes RndAllItems()

int itemMaxLevel = ItemsGetCurrlevel() * 2;
return GetItemIndexForDroppableItem(false, [&itemMaxLevel](const ItemData &item) {
if (sgGameInitInfo.bDisableSearch == 1 && item.iSpell == SpellID::Search)
return false;
if (itemMaxLevel < item.iMinMLvl)
return false;
return true;
Expand All @@ -1430,6 +1434,8 @@ _item_indexes RndTypeItems(ItemType itemType, int imid, int lvl)
return false;
if (imid != -1 && item.iMiscId != imid)
return false;
if (sgGameInitInfo.bDisableSearch == 1 && item.iSpell == SpellID::Search)
return false;
return true;
});
}
Expand Down Expand Up @@ -1522,7 +1528,12 @@ void SetupBaseItem(Point position, _item_indexes idx, bool onlygood, bool sendms
GetSuperItemSpace(position, ii);
int curlv = ItemsGetCurrlevel();

SetupAllItems(*MyPlayer, item, idx, AdvanceRndSeed(), 2 * curlv, 1, onlygood, delta);
do {
auto originalPos = item.position;
item = {};
item.position = originalPos;
SetupAllItems(*MyPlayer, item, idx, AdvanceRndSeed(), 2 * curlv, 1, onlygood, delta, false);
} while (item._iSpell == SpellID::Search && sgGameInitInfo.bDisableSearch == 1);
TryRandomUniqueItem(item, idx, 2 * curlv, 1, onlygood, delta);
SetupItem(item);

Expand Down Expand Up @@ -2005,7 +2016,8 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player)
&& premiumItem._iMinStr <= strength
&& premiumItem._iMinMag <= magic
&& premiumItem._iMinDex <= dexterity
&& premiumItem._iIvalue >= itemValue) {
&& premiumItem._iIvalue >= itemValue
&& (sgGameInitInfo.bDisableSearch != 1 || premiumItem._iSpell != SpellID::Search)) {
break;
}
}
Expand Down Expand Up @@ -2187,7 +2199,7 @@ void CreateMagicItem(Point position, int lvl, ItemType itemType, int imid, int i
SetupAllItems(*MyPlayer, item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, delta);
TryRandomUniqueItem(item, idx, 2 * lvl, 1, true, delta);
SetupItem(item);
if (item._iCurs == icurs)
if (item._iCurs == icurs && (sgGameInitInfo.bDisableSearch != 1 || item._iSpell != SpellID::Search))
break;

idx = RndTypeItems(itemType, imid, lvl);
Expand Down Expand Up @@ -3250,6 +3262,8 @@ _item_indexes RndItemForMonsterLevel(int8_t monsterLevel)
return IDI_GOLD;

return GetItemIndexForDroppableItem(true, [&monsterLevel](const ItemData &item) {
if (sgGameInitInfo.bDisableSearch == 1 && item.iSpell == SpellID::Search)
return false;
return item.iMinMLvl <= monsterLevel;
});
}
Expand Down Expand Up @@ -3460,7 +3474,12 @@ void SpawnItem(Monster &monster, Point position, bool sendmsg, bool spawn /*= fa
if (!gbIsHellfire && monster.type().type == MT_DIABLO)
mLevel -= 15;

SetupAllItems(*MyPlayer, item, idx, AdvanceRndSeed(), mLevel, uper, onlygood, false, false);
do {
auto originalPos = item.position;
item = {};
item.position = originalPos;
SetupAllItems(*MyPlayer, item, idx, AdvanceRndSeed(), mLevel, uper, onlygood, false, false);
} while (sgGameInitInfo.bDisableSearch == 1 && item._iSpell == SpellID::Search);
TryRandomUniqueItem(item, idx, mLevel, uper, onlygood, false);
SetupItem(item);

Expand Down Expand Up @@ -4476,10 +4495,12 @@ void SpawnWitch(int lvl)
if (i < PinnedItemCount + MaxPinnedBookCount && bookCount < pinnedBookCount) {
_item_indexes bookType = PinnedBookTypes[i - PinnedItemCount];
if (lvl >= AllItemsList[bookType].iMinMLvl) {
item._iSeed = AdvanceRndSeed();
SetRndSeed(item._iSeed);
DiscardRandomValues(1);
GetItemAttrs(item, bookType, lvl);
do {
item._iSeed = AdvanceRndSeed();
SetRndSeed(item._iSeed);
DiscardRandomValues(1);
GetItemAttrs(item, bookType, lvl);
} while (sgGameInitInfo.bDisableSearch == 1 && item._iSpell == SpellID::Search);
item._iCreateInfo = lvl | CF_WITCH;
item._iIdentified = true;
bookCount++;
Expand All @@ -4506,7 +4527,7 @@ void SpawnWitch(int lvl)
maxlvl = 2 * lvl;
if (maxlvl != -1)
GetItemBonus(*MyPlayer, item, maxlvl / 2, maxlvl, true, true);
} while (item._iIvalue > maxValue);
} while (item._iIvalue > maxValue || item._iSpell == SpellID::Search && sgGameInitInfo.bDisableSearch == 1);

item._iCreateInfo = lvl | CF_WITCH;
item._iIdentified = true;
Expand Down Expand Up @@ -4622,7 +4643,8 @@ void SpawnBoy(int lvl)
|| BoyItem._iMinStr > strength
|| BoyItem._iMinMag > magic
|| BoyItem._iMinDex > dexterity
|| BoyItem._iIvalue < ivalue)
|| BoyItem._iIvalue < ivalue
|| (BoyItem._iSpell == SpellID::Search && sgGameInitInfo.bDisableSearch == 1))
&& count < 250));
BoyItem._iCreateInfo = lvl | CF_BOY;
BoyItem._iIdentified = true;
Expand Down
1 change: 1 addition & 0 deletions Source/multi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ void InitGameInfo()
sgGameInitInfo.bCowQuest = *options.Gameplay.cowQuest ? 1 : 0;
sgGameInitInfo.bFriendlyFire = *options.Gameplay.friendlyFire ? 1 : 0;
sgGameInitInfo.fullQuests = (!gbIsMultiplayer || *options.Gameplay.multiplayerFullQuests) ? 1 : 0;
sgGameInitInfo.bDisableSearch = *options.Gameplay.disableSearch ? 1 : 0;
}

void NetSendLoPri(uint8_t playerId, const std::byte *data, size_t size)
Expand Down
1 change: 1 addition & 0 deletions Source/multi.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct GameData {
uint8_t bCowQuest;
uint8_t bFriendlyFire;
uint8_t fullQuests;
uint8_t bDisableSearch;
/** Used to initialise the seed table for dungeon levels so players in multiplayer games generate the same layout */
uint32_t gameSeed[4];

Expand Down
2 changes: 2 additions & 0 deletions Source/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ GameplayOptions::GameplayOptions()
, randomizeQuests("Randomize Quests", OptionEntryFlags::CantChangeInGame, N_("Randomize Quests"), N_("Randomly selecting available quests for new games."), true)
, showMonsterType("Show Monster Type", OptionEntryFlags::None, N_("Show Monster Type"), N_("Hovering over a monster will display the type of monster in the description box in the UI."), false)
, showItemLabels("Show Item Labels", OptionEntryFlags::None, N_("Show Item Labels"), N_("Show labels for items on the ground when enabled."), false)
, disableSearch("Disable Search Spell", OptionEntryFlags::CantChangeInMultiPlayer, N_("Disable Search Spell"), N_("Search spell will not appear on Scrolls, Books, or Staves generated by monsters you kill or objects and vendors you interact with. Set Monk class skill to Infravision. Search effect always enabled when using the map."), false)
, autoRefillBelt("Auto Refill Belt", OptionEntryFlags::None, N_("Auto Refill Belt"), N_("Refill belt from inventory when belt item is consumed."), false)
, disableCripplingShrines("Disable Crippling Shrines", OptionEntryFlags::None, N_("Disable Crippling Shrines"), N_("When enabled Cauldrons, Fascinating Shrines, Goat Shrines, Ornate Shrines, Sacred Shrines and Murphy's Shrines are not able to be clicked on and labeled as disabled."), false)
, quickCast("Quick Cast", OptionEntryFlags::None, N_("Quick Cast"), N_("Spell hotkeys instantly cast the spell, rather than switching the readied spell."), false)
Expand Down Expand Up @@ -835,6 +836,7 @@ std::vector<OptionEntryBase *> GameplayOptions::GetEntries()
&enemyHealthBar,
&showMonsterType,
&showItemLabels,
&disableSearch,
&enableFloatingNumbers,
&autoRefillBelt,
&autoEquipWeapons,
Expand Down
2 changes: 2 additions & 0 deletions Source/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,8 @@ struct GameplayOptions : OptionCategoryBase {
OptionEntryBoolean showMonsterType;
/** @brief Displays item labels for items on the ground. */
OptionEntryBoolean showItemLabels;
/** @brief Search spell will not appear on Scrolls, Books, or Staves generated by monsters you kill or objects and vendors you interact with. Set Monk class skill to Infravision. */
OptionEntryBoolean disableSearch;
/** @brief Refill belt from inventory, or rather, use potions/scrolls from inventory first when belt item is consumed. */
OptionEntryBoolean autoRefillBelt;
/** @brief Locally disable clicking on shrines which permanently cripple character. */
Expand Down
8 changes: 6 additions & 2 deletions Source/panels/spell_book.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "engine/render/text_render.hpp"
#include "game_mode.hpp"
#include "missiles.h"
#include "options.h"
#include "panels/spell_icons.hpp"
#include "panels/ui_panels.hpp"
#include "player.h"
Expand Down Expand Up @@ -64,7 +65,7 @@ SpellID GetSpellFromSpellPage(size_t page, size_t entry)
case HeroClass::Sorcerer:
return SpellID::StaffRecharge;
case HeroClass::Monk:
return SpellID::Search;
return *GetOptions().Gameplay.disableSearch ? SpellID::Infravision : SpellID::Search;
case HeroClass::Bard:
return SpellID::Identify;
case HeroClass::Barbarian:
Expand All @@ -89,8 +90,11 @@ void PrintSBookStr(const Surface &out, Point position, std::string_view text, Ui
SpellType GetSBookTrans(SpellID ii, bool townok)
{
Player &player = *InspectPlayer;
if ((player._pClass == HeroClass::Monk) && (ii == SpellID::Search))

if (player._pClass == HeroClass::Monk && ((ii == SpellID::Infravision && *GetOptions().Gameplay.disableSearch) || (ii == SpellID::Search && !*GetOptions().Gameplay.disableSearch))) {
return SpellType::Skill;
}

SpellType st = SpellType::Spell;
if ((player._pISpells & GetSpellBitmask(ii)) != 0) {
st = SpellType::Charges;
Expand Down
7 changes: 5 additions & 2 deletions Source/panels/spell_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ bool GetSpellListSelection(SpellID &pSpell, SpellType &pSplType)
if (spellListItem.isSelected) {
pSpell = spellListItem.id;
pSplType = spellListItem.type;
if (myPlayer._pClass == HeroClass::Monk && spellListItem.id == SpellID::Search)
pSplType = SpellType::Skill;
if (myPlayer._pClass == HeroClass::Monk) {
if ((spellListItem.id == SpellID::Search && !*GetOptions().Gameplay.disableSearch) || (spellListItem.id == SpellID::Infravision && *GetOptions().Gameplay.disableSearch)) {
pSplType = SpellType::Skill;
}
}
return true;
}
}
Expand Down
6 changes: 6 additions & 0 deletions Source/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,12 @@ void InitPlayer(Player &player, bool firstTime)

player._pAblSpells = GetSpellBitmask(GetPlayerStartingLoadoutForClass(player._pClass).skill);

// Override for Monk: if disableSearch is enabled, use Infravision instead of Search.
player._pAblSpells = GetSpellBitmask(
player._pClass == HeroClass::Monk && *GetOptions().Gameplay.disableSearch
? SpellID::Infravision
: GetPlayerStartingLoadoutForClass(player._pClass).skill);

player._pInvincible = false;

if (&player == MyPlayer) {
Expand Down
Loading