/* * StackInfoBasicPanel.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "StackInfoBasicPanel.h" #include "../widgets/Images.h" #include "../widgets/TextControls.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CStack.h" #include "../../lib/GameLibrary.h" #include "../../lib/spells/CSpellHandler.h" #include "../../lib/texts/CGeneralTextHandler.h" #include "../../lib/texts/TextOperations.h" StackInfoBasicPanel::StackInfoBasicPanel(const CStack * stack, bool initializeBackground) : CIntObject(0) { OBJECT_CONSTRUCTION; if(initializeBackground) { background = std::make_shared(ImagePath::builtin("CCRPOP")); background->pos.y += 37; background->setPlayerColor(stack->getOwner()); background2 = std::make_shared(ImagePath::builtin("CHRPOP")); background2->setPlayerColor(stack->getOwner()); } initializeData(stack); } void StackInfoBasicPanel::initializeData(const CStack * stack) { OBJECT_CONSTRUCTION; icons.push_back(std::make_shared(AnimationPath::builtin("TWCRPORT"), stack->creatureId().getNum() + 2, 0, 10, 6)); labels.push_back(std::make_shared(10 + 58, 6 + 64, FONT_MEDIUM, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, TextOperations::formatMetric(stack->getCount(), 4))); int damageMultiplier = 1; if (stack->hasBonusOfType(BonusType::SIEGE_WEAPON)) { static const auto bonusSelector = Selector::sourceTypeSel(BonusSource::ARTIFACT).Or( Selector::sourceTypeSel(BonusSource::HERO_BASE_SKILL)).And( Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK))); damageMultiplier += stack->valOfBonuses(bonusSelector); } auto attack = std::to_string(LIBRARY->creatures()->getByIndex(stack->creatureIndex())->getAttack(stack->isShooter())) + "(" + std::to_string(stack->getAttack(stack->isShooter())) + ")"; auto defense = std::to_string(LIBRARY->creatures()->getByIndex(stack->creatureIndex())->getDefense(stack->isShooter())) + "(" + std::to_string(stack->getDefense(stack->isShooter())) + ")"; auto damage = std::to_string(damageMultiplier * stack->getMinDamage(stack->isShooter())) + "-" + std::to_string(damageMultiplier * stack->getMaxDamage(stack->isShooter())); auto health = stack->getMaxHealth(); auto morale = stack->moraleVal(); auto luck = stack->luckVal(); auto killed = stack->getKilled(); auto healthRemaining = TextOperations::formatMetric(std::max(stack->getAvailableHealth() - static_cast(stack->getCount() - 1) * health, 0), 4); //primary stats*/ labels.push_back(std::make_shared(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[380] + ":")); labels.push_back(std::make_shared(9, 87, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[381] + ":")); labels.push_back(std::make_shared(9, 99, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[386] + ":")); labels.push_back(std::make_shared(9, 111, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[389] + ":")); labels.push_back(std::make_shared(69, 87, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, attack)); labels.push_back(std::make_shared(69, 99, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, defense)); labels.push_back(std::make_shared(69, 111, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, damage)); labels.push_back(std::make_shared(69, 123, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(health))); //morale+luck labels.push_back(std::make_shared(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[384] + ":")); labels.push_back(std::make_shared(9, 143, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[385] + ":")); icons.push_back(std::make_shared(AnimationPath::builtin("IMRL22"), std::clamp(morale + 3, 0, 6), 0, 47, 131)); icons.push_back(std::make_shared(AnimationPath::builtin("ILCK22"), std::clamp(luck + 3, 0, 6), 0, 47, 143)); //extra information labels.push_back(std::make_shared(9, 168, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->translate("vcmi.battleWindow.killed") + ":")); labels.push_back(std::make_shared(9, 180, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->allTexts[389] + ":")); labels.push_back(std::make_shared(69, 180, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(killed))); labels.push_back(std::make_shared(69, 192, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, healthRemaining)); //spells static const Point firstPos(15, 206); // position of 1st spell box static const Point offset(0, 38); // offset of each spell box from previous for(int i = 0; i < 3; i++) icons.push_back(std::make_shared(AnimationPath::builtin("SpellInt"), 78, 0, firstPos.x + offset.x * i, firstPos.y + offset.y * i)); int printed=0; //how many effect pics have been printed std::vector spells = stack->activeSpells(); for(SpellID effect : spells) { //not all effects have graphics (for eg. Acid Breath) //for modded spells iconEffect is added to SpellInt.def const bool hasGraphics = (effect < SpellID::THUNDERBOLT) || (effect >= SpellID::AFTER_LAST); if (hasGraphics) { //FIXME: support permanent duration auto spellBonuses = stack->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect))); if (spellBonuses->empty()) throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey()); int duration = spellBonuses->front()->turnsRemain; icons.push_back(std::make_shared(AnimationPath::builtin("SpellInt"), effect.getNum() + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed)); if(settings["general"]["enableUiEnhancements"].Bool()) labels.push_back(std::make_shared(firstPos.x + offset.x * printed + 46, firstPos.y + offset.y * printed + 36, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(duration))); ++printed; if(printed >= 3 || (printed == 2 && spells.size() > 3)) // interface limit reached break; } } if(spells.empty()) labelsMultiline.push_back(std::make_shared(Rect(firstPos.x, firstPos.y, 48, 36), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, LIBRARY->generaltexth->allTexts[674])); if(spells.size() > 3) labelsMultiline.push_back(std::make_shared(Rect(firstPos.x + offset.x * 2, firstPos.y + offset.y * 2 - 4, 48, 36), EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, "...")); } void StackInfoBasicPanel::update(const CStack * updatedInfo) { icons.clear(); labels.clear(); labelsMultiline.clear(); initializeData(updatedInfo); } void StackInfoBasicPanel::show(Canvas & to) { showAll(to); CIntObject::show(to); }