From 5679a3c0db1599cdbefe0c7bbf4f47ab6ff0687c Mon Sep 17 00:00:00 2001 From: Justin Jacobs Date: Sat, 12 Aug 2023 17:59:52 -0400 Subject: [PATCH] Display min/max damage and absorb stats on single lines in the Character menu --- RELEASE_NOTES.txt | 1 + src/ItemManager.cpp | 20 +---- src/MenuCharacter.cpp | 197 +++++++++++++++++++++++++++--------------- src/MenuCharacter.h | 1 + src/Utils.cpp | 8 ++ src/Utils.h | 2 + src/Version.cpp | 2 +- 7 files changed, 143 insertions(+), 88 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 2d8caea65..8289d106d 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -18,6 +18,7 @@ Engine fixes: * Fix crash when a book has a blank text item * Fix memory leak from dropped loot * Fix memory leak when a power's animation property was redefined. +* Display min/max damage and absorb stats on single lines in the Character menu Game updates: * Limited the number of "unique" items that can drop from a boss to 1 per kill. diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index dafb8cf40..b88da8162 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -916,14 +916,8 @@ TooltipData ItemManager::getTooltip(ItemStack stack, StatBlock *stats, int conte if (items[stack.item].base_dmg[i].max > 0) { std::stringstream dmg_str; dmg_str << eset->damage_types.list[i].name; - if (items[stack.item].base_dmg[i].min < items[stack.item].base_dmg[i].max) { - dmg_str << ": " << Utils::floatToString(items[stack.item].base_dmg[i].min, eset->number_format.item_tooltips) << "-" << Utils::floatToString(items[stack.item].base_dmg[i].max, eset->number_format.item_tooltips); - tip.addText(dmg_str.str()); - } - else { - dmg_str << ": " << Utils::floatToString(items[stack.item].base_dmg[i].max, eset->number_format.item_tooltips); - tip.addText(dmg_str.str()); - } + dmg_str << ": " << Utils::createMinMaxString(items[stack.item].base_dmg[i].min, items[stack.item].base_dmg[i].max, eset->number_format.item_tooltips); + tip.addText(dmg_str.str()); } } @@ -931,14 +925,8 @@ TooltipData ItemManager::getTooltip(ItemStack stack, StatBlock *stats, int conte if (items[stack.item].base_abs.max > 0) { std::stringstream abs_str; abs_str << msg->get("Absorb"); - if (items[stack.item].base_abs.min < items[stack.item].base_abs.max) { - abs_str << ": " << Utils::floatToString(items[stack.item].base_abs.min, eset->number_format.item_tooltips) << "-" << Utils::floatToString(items[stack.item].base_abs.max, eset->number_format.item_tooltips); - tip.addText(abs_str.str()); - } - else { - abs_str << ": " << Utils::floatToString(items[stack.item].base_abs.max, eset->number_format.item_tooltips); - tip.addText(abs_str.str()); - } + abs_str << ": " << Utils::createMinMaxString(items[stack.item].base_abs.min, items[stack.item].base_abs.max, eset->number_format.item_tooltips); + tip.addText(abs_str.str()); } // bonuses diff --git a/src/MenuCharacter.cpp b/src/MenuCharacter.cpp index 60f8ef25f..7d05d2a9d 100644 --- a/src/MenuCharacter.cpp +++ b/src/MenuCharacter.cpp @@ -306,6 +306,9 @@ void MenuCharacter::refreshStats() { for (int i=0; iresource_stats.list.size(); ++j) { @@ -323,27 +326,25 @@ void MenuCharacter::refreshStats() { // insert damage stats before absorb min if (i == Stats::ABS_MIN) { for (size_t j = 0; j < eset->damage_types.list.size(); ++j) { - if (show_stat[Stats::COUNT + (j*2)]) { - // min - ss.str(""); - ss << eset->damage_types.list[j].name_min << ": " << Utils::floatToString(pc->stats.getDamageMin(j), eset->number_format.character_menu); - statList->set(stat_index, ss.str(), damageTooltip(j*2)); - stat_index++; - } + if (show_stat[Stats::COUNT + (j*2)] || show_stat[Stats::COUNT + (j*2) + 1]) { + float min_dmg = pc->stats.getDamageMin(j); + float max_dmg = pc->stats.getDamageMax(j); - if (show_stat[Stats::COUNT + (j*2) + 1]) { - // max ss.str(""); - ss << eset->damage_types.list[j].name_max << ": " << Utils::floatToString(pc->stats.getDamageMax(j), eset->number_format.character_menu); - statList->set(stat_index, ss.str(), damageTooltip((j*2) + 1)); + ss << eset->damage_types.list[j].name << ": " << Utils::createMinMaxString(min_dmg, max_dmg, eset->number_format.character_menu); + statList->set(stat_index, ss.str(), damageTooltip(j)); stat_index++; } } - } - ss.str(""); - ss << Stats::NAME[i] << ": " << Utils::floatToString(pc->stats.get(static_cast(i)), 2); - if (Stats::PERCENT[i]) ss << "%"; + ss.str(""); + ss << msg->get("Absorb") << ": " << Utils::createMinMaxString(pc->stats.get(Stats::ABS_MIN), pc->stats.get(Stats::ABS_MAX), eset->number_format.character_menu); + } + else { + ss.str(""); + ss << Stats::NAME[i] << ": " << Utils::floatToString(pc->stats.get(static_cast(i)), 2); + if (Stats::PERCENT[i]) ss << "%"; + } statList->set(stat_index, ss.str(), statTooltip(i)); stat_index++; @@ -480,102 +481,156 @@ Color MenuCharacter::bonusColor(int stat) { return font->getColor(FontEngine::COLOR_MENU_NORMAL); } +void MenuCharacter::tooltipCreateBonusText(size_t min_index, size_t max_index, std::string* min_text, std::string* max_text) { + // per-level bonus + float min_per_level = pc->stats.per_level[min_index]; + float max_per_level = pc->stats.per_level[max_index]; + + if (min_per_level > 0) { + *min_text += msg->getv("Each level grants %s.", Utils::floatToString(min_per_level, eset->number_format.character_menu).c_str()); + } + + if (max_text && max_per_level > 0) { + *max_text += msg->getv("Each level grants %s.", Utils::floatToString(max_per_level, eset->number_format.character_menu).c_str()); + } + + // per-primary bonuses + for (size_t i = 0; i < eset->primary_stats.list.size(); ++i) { + float min_per_primary = pc->stats.per_primary[i][min_index]; + float max_per_primary = pc->stats.per_primary[i][max_index]; + + if (min_per_primary > 0) { + if (!min_text->empty()) + *min_text += "\n"; + + *min_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(min_per_primary, eset->number_format.character_menu).c_str()); + } + + if (max_text && max_per_primary > 0) { + if (!max_text->empty()) + *max_text += "\n"; + + *max_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(max_per_primary, eset->number_format.character_menu).c_str()); + } + } +} + /** * Create tooltip text showing the per_* values of a stat */ std::string MenuCharacter::statTooltip(int stat) { - std::string tooltip_text; + std::string text, min_text; - if (pc->stats.per_level[stat] > 0) - tooltip_text += msg->getv("Each level grants %s.", Utils::floatToString(pc->stats.per_level[stat], eset->number_format.character_menu).c_str()) + ' '; + std::string& description = Stats::DESC[stat]; + if (!description.empty()) + text += description; - for (size_t i = 0; i < eset->primary_stats.list.size(); ++i) { - if (pc->stats.per_primary[i][stat] > 0) - tooltip_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(pc->stats.per_primary[i][stat], eset->number_format.character_menu).c_str()) + ' '; + size_t min_index = stat; + + if (stat == Stats::ABS_MIN) { + std::string max_text; + + size_t max_index = Stats::ABS_MAX; + + tooltipCreateBonusText(min_index, max_index, &min_text, &max_text); + + if (!min_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += Stats::NAME[min_index] + ":\n" + min_text; + } + + if (!max_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += Stats::NAME[max_index] + ":\n" + max_text; + } } + else { + tooltipCreateBonusText(min_index, min_index, &min_text, NULL); - std::string full_tooltip = ""; - if (Stats::DESC[stat] != "") - full_tooltip += Stats::DESC[stat]; - if (full_tooltip != "" && tooltip_text != "") - full_tooltip += "\n"; - full_tooltip += tooltip_text; + if (!min_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += min_text; + } + } - return full_tooltip; + return text; } /** * Create tooltip text showing the per_* values of a damage stat */ std::string MenuCharacter::damageTooltip(size_t dmg_type) { - std::string tooltip_text; + std::string text, min_text, max_text; - if (pc->stats.per_level[Stats::COUNT + dmg_type] > 0) - tooltip_text += msg->getv("Each level grants %s.", Utils::floatToString(pc->stats.per_level[Stats::COUNT + dmg_type], eset->number_format.character_menu).c_str()) + ' '; + std::string& description = eset->damage_types.list[dmg_type].description; + if (!description.empty()) + text += description; - for (size_t i = 0; i < eset->primary_stats.list.size(); ++i) { - if (pc->stats.per_primary[i][Stats::COUNT + dmg_type] > 0) - tooltip_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(pc->stats.per_primary[i][Stats::COUNT + dmg_type], eset->number_format.character_menu).c_str()) + ' '; - } + size_t min_index = Stats::COUNT + (dmg_type * 2); + size_t max_index = Stats::COUNT + (dmg_type * 2) + 1; - size_t real_dmg_type = dmg_type / 2; + tooltipCreateBonusText(min_index, max_index, &min_text, &max_text); - std::string full_tooltip = ""; - if (eset->damage_types.list[real_dmg_type].description != "") - full_tooltip += eset->damage_types.list[real_dmg_type].description; - if (full_tooltip != "" && tooltip_text != "") - full_tooltip += "\n"; - full_tooltip += tooltip_text; + if (!min_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += eset->damage_types.list[dmg_type].name_min + ":\n" + min_text; + } - return full_tooltip; + if (!max_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += eset->damage_types.list[dmg_type].name_max + ":\n" + max_text; + } + + return text; } /** * Create tooltip text showing the per_* values of a resistance stat */ std::string MenuCharacter::resistTooltip(size_t resist_type) { - std::string tooltip_text; - size_t resist_index = Stats::COUNT + eset->damage_types.count + resist_type; + std::string text, bonus_text; - if (pc->stats.per_level[resist_index] > 0) - tooltip_text += msg->getv("Each level grants %s.", Utils::floatToString(pc->stats.per_level[resist_index], eset->number_format.character_menu).c_str()) + ' '; + std::string& description = eset->elements.list[resist_type].name; + if (!description.empty()) + text += msg->getv("Reduces the damage taken from \"%s\" elemental attacks.", description.c_str()); - for (size_t i = 0; i < eset->primary_stats.list.size(); ++i) { - if (pc->stats.per_primary[i][resist_index] > 0) - tooltip_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(pc->stats.per_primary[i][resist_index], eset->number_format.character_menu).c_str()) + ' '; - } + size_t resist_index = Stats::COUNT + eset->damage_types.count + resist_type; - std::string full_tooltip = msg->getv("Reduces the damage taken from \"%s\" elemental attacks.", eset->elements.list[resist_type].name.c_str()); - if (tooltip_text != "") { - full_tooltip += "\n" + tooltip_text; + tooltipCreateBonusText(resist_index, resist_index, &bonus_text, NULL); + + if (!bonus_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += bonus_text; } - return full_tooltip; + return text; } std::string MenuCharacter::resourceStatTooltip(size_t resource_index, size_t stat_index) { - std::string tooltip_text; + std::string text, bonus_text; + + std::string& description = eset->resource_stats.list[resource_index].text_desc[stat_index]; + if (!description.empty()) + text += description; + size_t offset_index = Stats::COUNT + eset->damage_types.count + eset->elements.list.size(); size_t resource_stat_index = offset_index + (resource_index * EngineSettings::ResourceStats::STAT_COUNT) + stat_index; - if (pc->stats.per_level[resource_stat_index] > 0) - tooltip_text += msg->getv("Each level grants %s.", Utils::floatToString(pc->stats.per_level[resource_stat_index], eset->number_format.character_menu).c_str()) + ' '; + tooltipCreateBonusText(resource_stat_index, resource_stat_index, &bonus_text, NULL); - for (size_t i = 0; i < eset->primary_stats.list.size(); ++i) { - if (pc->stats.per_primary[i][resource_stat_index] > 0) - tooltip_text += msg->getv("Each point of %s grants %s.", eset->primary_stats.list[i].name.c_str(), Utils::floatToString(pc->stats.per_primary[i][resource_stat_index], eset->number_format.character_menu).c_str()) + ' '; + if (!bonus_text.empty()) { + if (!text.empty()) + text += "\n\n"; + text += bonus_text; } - std::string full_tooltip = ""; - std::string text_desc = eset->resource_stats.list[resource_index].text_desc[stat_index]; - - if (!text_desc.empty()) - full_tooltip += text_desc; - if (!full_tooltip.empty() && !tooltip_text.empty()) - full_tooltip += "\n"; - full_tooltip += tooltip_text; - - return full_tooltip; + return text; } void MenuCharacter::logic() { diff --git a/src/MenuCharacter.h b/src/MenuCharacter.h index aba94af83..52d949d03 100644 --- a/src/MenuCharacter.h +++ b/src/MenuCharacter.h @@ -63,6 +63,7 @@ class MenuCharacter : public Menu { void loadGraphics(); Color bonusColor(int stat); + void tooltipCreateBonusText(size_t min_index, size_t max_index, std::string* min_text, std::string* max_text); std::string statTooltip(int stat); std::string damageTooltip(size_t dmg_type); std::string resistTooltip(size_t resist_type); diff --git a/src/Utils.cpp b/src/Utils.cpp index c53aeef7e..b55d7b305 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -898,3 +898,11 @@ void Utils::setSDL_RGBA(Uint32 *rmask, Uint32 *gmask, Uint32 *bmask, Uint32 *ama #endif } +std::string Utils::createMinMaxString(float min, float max, size_t precision) { + std::string r; + if (min != max) + r = floatToString(min, precision) + '-'; + r += floatToString(max, precision); + return r; +} + diff --git a/src/Utils.h b/src/Utils.h index ed5a9d10d..b61f3768a 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -188,6 +188,8 @@ namespace Utils { void lockFileCheck(); void setSDL_RGBA(Uint32 *rmask, Uint32 *gmask, Uint32 *bmask, Uint32 *amask); + + std::string createMinMaxString(float min, float max, size_t precision); } #endif diff --git a/src/Version.cpp b/src/Version.cpp index b7602893c..89f141610 100644 --- a/src/Version.cpp +++ b/src/Version.cpp @@ -30,7 +30,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ #include -Version VersionInfo::ENGINE(1, 14, 18); +Version VersionInfo::ENGINE(1, 14, 19); Version VersionInfo::MIN(0, 0, 0); Version VersionInfo::MAX(USHRT_MAX, USHRT_MAX, USHRT_MAX);