diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index d017cb5a2..833950cd4 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -10,6 +10,7 @@ #include "../lib/CBonusTypeHandler.h" #include "../lib/CGeneralTextHandler.h" #include "../lib/CModHandler.h" +#include "../lib/CHeroHandler.h" #include "../lib/CSpellHandler.h" #include "gui/CGuiHandler.h" @@ -127,6 +128,49 @@ void CStackWindow::CWindowSection::printStat(int index, std::string name, int va printStatBase(index, name, value, value); } +std::string CStackWindow::generateStackExpDescription() +{ + const CStackInstance * stack = info->stackNode; + const CCreature * creature = info->creature; + + int tier = stack->type->level; + int rank = stack->getExpRank(); + if (!vstd::iswithin(tier, 1, 7)) + tier = 0; + int number; + std::string expText = CGI->generaltexth->zcrexp[325]; + boost::replace_first (expText, "%s", creature->namePl); + boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]); + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank)); + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience)); + number = CGI->creh->expRanks[tier][rank] - stack->experience; + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); + + number = CGI->creh->maxExpPerBattle[tier]; //percent + boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number)); + number *= CGI->creh->expRanks[tier].back() / 100; //actual amount + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); + + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack + + int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1); + number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO + + boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier + number = CGI->creh->expAfterUpgrade; + boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier + + expmin = CGI->creh->expRanks[tier][9]; + int expmax = CGI->creh->expRanks[tier][10]; + number = expmax - expmin; + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Experience after Rank 10 + number = (stack->count * (expmax - expmin)) / expmin; + boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience + + return expText; +} + void CStackWindow::CWindowSection::createStackInfo(bool showExp, bool showArt) { OBJ_CONSTRUCTION_CAPTURING_ALL; @@ -182,9 +226,33 @@ void CStackWindow::CWindowSection::createStackInfo(bool showExp, bool showArt) auto luck = new MoraleLuckBox(false, genRect(42, 42, 375, 110)); luck->set(parent->info->stackNode); - //TODO: artifacts + //TODO: stack artifact - //TODO: stack artifacts + //TODO: stack experience + if (showExp) + { + const CStackInstance * stack = parent->info->stackNode; + Point pos = showArt ? Point(321, 32) : Point(347, 32); + if (parent->info->commander) + { + const CCommanderInstance * commander = parent->info->commander; + new CAnimImage("PSKIL42", 4, 0, pos.x, pos.y); // experience icon + + auto expArea = new LRClickableAreaWTextComp(Rect(pos.x, pos.y, 44, 44), CComponent::experience); + expArea->text = CGI->generaltexth->allTexts[2]; + expArea->bonusValue = commander->getExpRank(); + boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->getExpRank())); + boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(commander->getExpRank()+1))); + boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->experience)); + } + else + { + new CAnimImage("stackWindow/levels", stack->getExpRank(), 0, pos.x, pos.y); + auto expArea = new LRClickableAreaWText(Rect(pos.x, pos.y, 44, 44)); + expArea->text = parent->generateStackExpDescription(); + } + new CLabel(pos.x + 21, pos.y + 52, FONT_SMALL, CENTER, Colors::WHITE, makeNumberShort<TExpType>(stack->experience, 6)); + } } void CStackWindow::CWindowSection::createActiveSpells() @@ -312,6 +380,8 @@ void CStackWindow::CWindowSection::createCommander() }; } } + + //TODO: commander artifacts } void CStackWindow::CWindowSection::createCommanderAbilities() diff --git a/client/CCreatureWindow.h b/client/CCreatureWindow.h index 29f2eb782..370c5e43c 100644 --- a/client/CCreatureWindow.h +++ b/client/CCreatureWindow.h @@ -87,6 +87,8 @@ class CStackWindow : public CWindowObject void init(); + std::string generateStackExpDescription(); + public: // for battles CStackWindow(const CStack * stack, bool popup); diff --git a/client/gui/SDL_Extensions.h b/client/gui/SDL_Extensions.h index 0e88302fb..64bdfc7e8 100644 --- a/client/gui/SDL_Extensions.h +++ b/client/gui/SDL_Extensions.h @@ -63,15 +63,16 @@ typename boost::enable_if_c<boost::is_unsigned<T>::type, T>::type abs(T arg) } template<typename IntType> -std::string makeNumberShort(IntType number) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k) +std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k) { - if (abs(number) < 1000) + IntType max = pow(10, maxLength); + if (abs(number) < max) return boost::lexical_cast<std::string>(number); - std::string symbols = "kMGTPE"; + std::string symbols = " kMGTPE"; auto iter = symbols.begin(); - while (number >= 1000) + while (number >= max) { number /= 1000; iter++; diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 6cd415dc8..031bf413d 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -427,7 +427,18 @@ CGeneralTextHandler::CGeneralTextHandler() { CLegacyConfigParser parser("DATA/ZCREXP.TXT"); parser.endLine();//header - do + for (size_t iter=0; iter<325; iter++) + { + parser.readString(); //ignore 1st column with description + zcrexp.push_back(parser.readString()); + parser.endLine(); + } + // line 325 - some weird formatting here + zcrexp.push_back(parser.readString()); + parser.readString(); + parser.endLine(); + + do // rest of file can be read normally { parser.readString(); //ignore 1st column with description zcrexp.push_back(parser.readString());