diff --git a/Source/diablo.cpp b/Source/diablo.cpp index e50b62433bd..c84b70dbb12 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1792,6 +1792,13 @@ void InitKeymapActions() SDLK_RCTRL, nullptr, [] { ToggleItemLabelHighlight(); }); + sgOptions.Keymapper.AddAction( + "Show Base Stats", + N_("Show item base stats"), + N_("Shows item base armor/damage without including bonuses"), + SDLK_LCTRL, + [] { showItemBaseStats = true; }, + [] { showItemBaseStats = false; }); sgOptions.Keymapper.AddAction( "Toggle Automap", N_("Toggle automap"), diff --git a/Source/inv.cpp b/Source/inv.cpp index 02384c43bc4..d12dac237c4 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -1916,11 +1916,7 @@ int8_t CheckInvHLight() } else { InfoColor = pi->getTextColor(); InfoString = pi->getName(); - if (pi->_iIdentified) { - PrintItemDetails(*pi); - } else { - PrintItemDur(*pi); - } + PrintItemDetails(*pi); } return rv; diff --git a/Source/items.cpp b/Source/items.cpp index 2c7effdee29..1d47f655aaf 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -43,7 +43,6 @@ #include "utils/format_int.hpp" #include "utils/language.h" #include "utils/log.hpp" -#include "utils/math.h" #include "utils/str_case.hpp" #include "utils/str_cat.hpp" #include "utils/utf8.hpp" @@ -58,6 +57,7 @@ bool ShowUniqueItemInfoBox; CornerStoneStruct CornerStone; bool UniqueItemFlags[128]; int MaxGold = GOLD_MAX_LIMIT; +bool showItemBaseStats = false; /** Maps from item_cursor_graphic to in-memory item type. */ int8_t ItemCAnimTbl[] = { @@ -2471,20 +2471,6 @@ void InitItems() initItemGetRecords(); } -int GetBonusAC(const Item &item) -{ - if (item._iPLAC != 0) { - int tempAc = item._iAC; - tempAc *= item._iPLAC; - tempAc /= 100; - if (tempAc == 0) - tempAc = math::Sign(item._iPLAC); - return tempAc; - } - - return 0; -} - void CalcPlrDamage(Player &player, int minDamage, int maxDamage) { const uint8_t playerLevel = player.getCharacterLevel(); @@ -2816,7 +2802,7 @@ void CalcPlrItemVals(Player &player, bool loadgfx) if (item._iMagical == ITEM_QUALITY_NORMAL || item._iIdentified) { dam += item._iPLDam; toHit += item._iPLToHit; - bonusAc += GetBonusAC(item); + bonusAc += item.getBonusAC(); flags |= item._iFlags; damAcFlags |= item._iDamAcFlags; strength += item._iPLStr; @@ -4096,77 +4082,50 @@ void PrintItemDetails(const Item &item) return; if (item._iClass == ICLASS_WEAPON) { + std::pair realDamage = item.getFinalDamage(showItemBaseStats || !item._iIdentified); if (item._iMinDam == item._iMaxDam) { if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Indestructible")), item._iMinDam)); + AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Indestructible")), realDamage.first)); else - AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d} Dur: {:d}/{:d}")), item._iMinDam, item._iDurability, item._iMaxDur)); + AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d} Dur: {:d}/{:d}")), realDamage.first, item._iDurability, item._iMaxDur)); } else { if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Indestructible")), item._iMinDam, item._iMaxDam)); + AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Indestructible")), realDamage.first, realDamage.second)); else - AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d}-{:d} Dur: {:d}/{:d}")), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur)); + AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d}-{:d} Dur: {:d}/{:d}")), realDamage.first, realDamage.second, item._iDurability, item._iMaxDur)); } } if (item._iClass == ICLASS_ARMOR) { + int realAC = item._iAC; + if (!showItemBaseStats && item._iIdentified) { + realAC += item.getBonusAC(); + } if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Indestructible")), item._iAC)); + AddInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Indestructible")), realAC)); else - AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "armor: {:d} Dur: {:d}/{:d}")), item._iAC, item._iDurability, item._iMaxDur)); + AddInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "armor: {:d} Dur: {:d}/{:d}")), realAC, item._iDurability, item._iMaxDur)); } if (item._iMiscId == IMISC_STAFF && item._iMaxCharges != 0) { AddInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges)); } - if (item._iPrePower != -1) { - AddInfoBoxString(PrintItemPower(item._iPrePower, item)); - } - if (item._iSufPower != -1) { - AddInfoBoxString(PrintItemPower(item._iSufPower, item)); - } - if (item._iMagical == ITEM_QUALITY_UNIQUE) { - AddInfoBoxString(_("unique item")); - ShowUniqueItemInfoBox = true; - curruitem = item; - } - PrintItemInfo(item); -} - -void PrintItemDur(const Item &item) -{ - if (HeadlessMode) - return; - - if (item._iClass == ICLASS_WEAPON) { - if (item._iMinDam == item._iMaxDam) { - if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Indestructible")), item._iMinDam)); - else - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Dur: {:d}/{:d}")), item._iMinDam, item._iDurability, item._iMaxDur)); + if (item._iMagical != ITEM_QUALITY_NORMAL) { + if (item._iIdentified) { + if (item._iPrePower != -1) { + AddInfoBoxString(PrintItemPower(item._iPrePower, item)); + } + if (item._iSufPower != -1) { + AddInfoBoxString(PrintItemPower(item._iSufPower, item)); + } + if (item._iMagical == ITEM_QUALITY_UNIQUE) { + AddInfoBoxString(_("unique item")); + ShowUniqueItemInfoBox = true; + curruitem = item; + } } else { - if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Indestructible")), item._iMinDam, item._iMaxDam)); - else - AddInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Dur: {:d}/{:d}")), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur)); - } - if (item._iMiscId == IMISC_STAFF && item._iMaxCharges > 0) { - AddInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges)); - } - if (item._iMagical != ITEM_QUALITY_NORMAL) - AddInfoBoxString(_("Not Identified")); - } - if (item._iClass == ICLASS_ARMOR) { - if (item._iMaxDur == DUR_INDESTRUCTIBLE) - AddInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Indestructible")), item._iAC)); - else - AddInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Dur: {:d}/{:d}")), item._iAC, item._iDurability, item._iMaxDur)); - if (item._iMagical != ITEM_QUALITY_NORMAL) AddInfoBoxString(_("Not Identified")); - if (item._iMiscId == IMISC_STAFF && item._iMaxCharges > 0) { - AddInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges)); } } - if (IsAnyOf(item._itype, ItemType::Ring, ItemType::Amulet)) - AddInfoBoxString(_("Not Identified")); + PrintItemInfo(item); } diff --git a/Source/items.h b/Source/items.h index 014f90e415f..76933ed8743 100644 --- a/Source/items.h +++ b/Source/items.h @@ -15,6 +15,7 @@ #include "engine/point.hpp" #include "itemdat.h" #include "monster.h" +#include "utils/math.h" #include "utils/string_or_view.hpp" namespace devilution { @@ -420,6 +421,33 @@ struct Item { return _iSeed == seed && IDidx == itemIndex && _iCreateInfo == createInfo; } + int getBonusAC() const + { + if (_iPLAC != 0) { + int tempAc = _iAC; + tempAc *= _iPLAC; + tempAc /= 100; + if (tempAc == 0) + tempAc = math::Sign(_iPLAC); + return tempAc; + } + + return 0; + } + + std::pair getFinalDamage(bool baseDamage) const + { + int minDmg = _iMinDam; + int maxDmg = _iMaxDam; + if (!baseDamage) { + minDmg += minDmg * _iPLDam / 100; + maxDmg += maxDmg * _iPLDam / 100; + minDmg += _iPLDamMod; + maxDmg += _iPLDamMod; + } + return { minDmg, maxDmg }; + } + UiFlags getTextColor() const { switch (_iMagical) { @@ -483,6 +511,7 @@ extern int8_t dItem[MAXDUNX][MAXDUNY]; extern bool ShowUniqueItemInfoBox; extern CornerStoneStruct CornerStone; extern DVL_API_FOR_TEST bool UniqueItemFlags[128]; +extern bool showItemBaseStats; uint8_t GetOutlineColor(const Item &item, bool checkReq); bool IsItemAvailable(int i); @@ -544,7 +573,6 @@ bool DoOil(Player &player, int cii); [[nodiscard]] StringOrView PrintItemPower(char plidx, const Item &item); void DrawUniqueInfo(const Surface &out); void PrintItemDetails(const Item &item); -void PrintItemDur(const Item &item); void UseItem(Player &player, item_misc_id Mid, SpellID spellID, int spellFrom); bool UseItemOpensHive(const Item &item, Point position); bool UseItemOpensGrave(const Item &item, Point position); diff --git a/Source/qol/stash.cpp b/Source/qol/stash.cpp index c4a5320871f..2de0885ec1a 100644 --- a/Source/qol/stash.cpp +++ b/Source/qol/stash.cpp @@ -447,11 +447,7 @@ uint16_t CheckStashHLight(Point mousePosition) InfoColor = item.getTextColor(); InfoString = item.getName(); - if (item._iIdentified) { - PrintItemDetails(item); - } else { - PrintItemDur(item); - } + PrintItemDetails(item); return itemId; } diff --git a/Source/stores.cpp b/Source/stores.cpp index 588eec54595..8ac8540cc57 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -305,10 +305,16 @@ void PrintStoreItem(const Item &item, int l, UiFlags flags, bool cursIndent = fa } if (item._itype != ItemType::Misc) { - if (item._iClass == ICLASS_WEAPON) - productLine = fmt::format(fmt::runtime(_("Damage: {:d}-{:d} ")), item._iMinDam, item._iMaxDam); - else if (item._iClass == ICLASS_ARMOR) - productLine = fmt::format(fmt::runtime(_("Armor: {:d} ")), item._iAC); + if (item._iClass == ICLASS_WEAPON) { + std::pair realDamage = item.getFinalDamage(showItemBaseStats || !item._iIdentified); + productLine = fmt::format(fmt::runtime(_("Damage: {:d}-{:d} ")), realDamage.first, realDamage.second); + } else if (item._iClass == ICLASS_ARMOR) { + int realAC = item._iAC; + if (!showItemBaseStats && item._iIdentified) { + realAC += item.getBonusAC(); + } + productLine = fmt::format(fmt::runtime(_("Armor: {:d} ")), realAC); + } if (item._iMaxDur != DUR_INDESTRUCTIBLE && item._iMaxDur != 0) productLine += fmt::format(fmt::runtime(_("Dur: {:d}/{:d}")), item._iDurability, item._iMaxDur); else