diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index b4c842e3f..2cd6db8c4 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -29,6 +29,7 @@ using namespace CSDL_Ext; class CBonusItem; class CCreatureArtifactInstance; +class CSelectableSkill; /* * CCreatureWindow.cpp, part of VCMI engine @@ -146,6 +147,28 @@ CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander): dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d); } +CCreatureWindow::CCreatureWindow (std::vector &skills, const CCommanderInstance * Commander, boost::function &callback): + CWindowObject(PLAYER_COLORED), + type(COMMANDER_LEVEL_UP), + upgradeOptions(skills), //copy skills to choose from + commander (Commander), + levelUp (callback), + selectedOption (0) //choose something before drawing +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + + init(commander, commander, dynamic_cast(commander->armyObj)); + + boost::function Dsm; + CFunctionList fs[2]; + //on dismiss confirmed + fs[0] += Dsm; //dismiss + fs[0] += boost::bind(&CCreatureWindow::close,this);//close this window + CFunctionList cfl; + cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector()); + dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d); +} + void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner) { creatureArtifact = NULL; //may be set later @@ -311,41 +334,11 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * creArt = true; for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i) { - if (commander->secondarySkills[i]) + if (commander->secondarySkills[i] || vstd::contains(upgradeOptions, i)) { - std::string file = "zvs/Lib1.res/_"; - switch (i) - { - case ECommander::ATTACK: - file += "AT"; - break; - case ECommander::DEFENSE: - file += "DF"; - break; - case ECommander::HEALTH: - file += "HP"; - break; - case ECommander::DAMAGE: - file += "DM"; - break; - case ECommander::SPEED: - file += "SP"; - break; - case ECommander::SPELL_POWER: - file += "MP"; - break; - } - std::string sufix = boost::lexical_cast((int)(commander->secondarySkills[i] - 1)); //casting ui8 causes ascii char conversion - if (type == COMMANDER_LEVEL_UP) - { - if (commander->secondarySkills[i] < ECommander::MAX_SKILL_LEVEL) - sufix += "="; //level-up highlight - else - sufix = "no"; //not avaliable - no number - } - file += sufix += ".bmp"; + std::string file = skillToFile(i); - new CPicture(file, 37 + i * 84, 224); + skillPictures.push_back(new CPicture(file, 37 + i * 84, 224)); } } //print commander level @@ -354,6 +347,30 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * new CLabel(488, 82, FONT_SMALL, CENTER, Colors::Cornsilk, boost::lexical_cast(stack->experience)); + + if (type == COMMANDER_LEVEL_UP) + { + BOOST_FOREACH (auto option, upgradeOptions) + { + ui32 index = selectableSkills.size(); + + CSelectableSkill * selectableSkill = new CSelectableSkill(); + if (option < 100) + { + selectableSkill->pos = skillPictures[option]->pos; //should match picture + } + else + { + selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll + Bonus b = CGI->creh->skillRequirements[option-100].first; + bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(&b, false), stack->bonusToString(&b, true), stack->bonusToGraphics(&b))); + } + + selectableSkill->callback = boost::bind(&CCreatureWindow::selectSkill, this, index); + selectableSkills.push_back (selectableSkill); + //TODO: add clickable abilities to bonusItems + } + } } if (creArt) //stack or commander artifacts { @@ -492,6 +509,15 @@ void CCreatureWindow::showAll(SDL_Surface * to) BOOST_FOREACH(CBonusItem* b, bonusItems) b->showAll (to); + + BOOST_FOREACH(auto s, selectableSkills) + s->showAll (to); + + for (int i = 0; i < skillPictures.size(); i++) + { + skillPictures[i]->bg = BitmapHandler::loadBitmap (skillToFile(i)); + skillPictures[i]->showAll (to); + } } void CCreatureWindow::show(SDL_Surface * to) @@ -501,12 +527,57 @@ void CCreatureWindow::show(SDL_Surface * to) } +void CCreatureWindow::close() +{ + if (upgradeOptions.size()) //a skill for commander was chosen + levelUp (upgradeOptions[selectedOption]); //callback + + GH.popIntTotally(this); +} + void CCreatureWindow::sliderMoved(int newpos) { recreateSkillList(newpos); //move components redraw(); } +std::string CCreatureWindow::skillToFile (int skill) +{ + std::string file = "zvs/Lib1.res/_"; + switch (skill) + { + case ECommander::ATTACK: + file += "AT"; + break; + case ECommander::DEFENSE: + file += "DF"; + break; + case ECommander::HEALTH: + file += "HP"; + break; + case ECommander::DAMAGE: + file += "DM"; + break; + case ECommander::SPEED: + file += "SP"; + break; + case ECommander::SPELL_POWER: + file += "MP"; + break; + } + std::string sufix = boost::lexical_cast((int)(commander->secondarySkills[skill])); //casting ui8 causes ascii char conversion + if (type == COMMANDER_LEVEL_UP) + { + if (upgradeOptions.size() && upgradeOptions[selectedOption] == skill)//that one specific skill is selected + sufix += "="; //level-up highlight + else if (!vstd::contains(upgradeOptions, skill)) + sufix = "no"; //not avaliable - no number + } + file += sufix += ".bmp"; + + return file; +} + void CCreatureWindow::setArt(const CArtifactInstance *art) { creatureArtifact = art; @@ -562,6 +633,12 @@ void CCreatureWindow::artifactMoved (const ArtifactLocation &artLoc, const Artif artifactRemoved (artLoc); //same code } +void CCreatureWindow::selectSkill (ui32 which) +{ + selectedOption = which; + redraw(); +} + CCreatureWindow::~CCreatureWindow() { for (int i=0; i upgradeOptions; + std::vector selectableSkills; + std::vector skillPictures; //secondary skills + + std::string skillToFile(int skill); //return bitmap for secondary skill depending on selection / avaliability + void selectSkill (ui32 which); void setArt(const CArtifactInstance *creatureArtifact); void artifactRemoved (const ArtifactLocation &artLoc); @@ -75,11 +84,13 @@ public: boost::function dsm; //dismiss button callback boost::function Upg; //upgrade button callback + boost::function levelUp; //choose commander skill to level up CCreatureWindow(const CStack & stack, int type); //battle c-tor CCreatureWindow (const CStackInstance &stack, int Type); //pop-up c-tor CCreatureWindow(const CStackInstance &st, int Type, boost::function Upg, boost::function Dsm, UpgradeInfo *ui); //full garrison window CCreatureWindow(const CCommanderInstance * commander); //commander window + CCreatureWindow(std::vector &skills, const CCommanderInstance * commander, boost::function &callback); CCreatureWindow(int Cid, int Type, int creatureCount); //c-tor void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner); @@ -87,6 +98,7 @@ public: void show(SDL_Surface * to); void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false); void sliderMoved(int newpos); + void close(); ~CCreatureWindow(); //d-tor void recreateSkillList(int pos); @@ -109,6 +121,15 @@ public: void showAll (SDL_Surface * to); }; +class CSelectableSkill : public LRClickableAreaWText +{ +public: + boost::function callback; //TODO: create more generic clickable class than AdvMapButton? + + virtual void clickLeft(tribool down, bool previousState); + virtual void clickRight(tribool down, bool previousState){}; +}; + /// original creature info window class CCreInfoWindow : public CWindowObject { diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 07f7e8663..95edfc485 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -482,14 +482,12 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, waitWhileDialog(); CCS->soundh->playSound(soundBase::heroNewLevel); - //boost::function(boost::bind(&CCallback::selectionMade,cl->callbacks[h->tempOwner].get(),_1,id)) - auto callback2 = boost::bind (&CCallback::selectionMade, cb, 0, playerID); - showYesNoDialog ("Commander got level", callback2, callback2, true, std::vector()); - //showYesNoDialog ("Commander got level", callback, callback, true, std::vector()); + //auto callback2 = boost::bind (&CCallback::selectionMade, cb, 0, playerID); + //showYesNoDialog ("Commander got level", callback2, callback2, true, std::vector()); //TODO: display full window - //CCreatureWindow * cw = new CCreatureWindow(commander); - //GH.pushInt(cw); + CCreatureWindow * cw = new CCreatureWindow(skills, commander, callback); + GH.pushInt(cw); } void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town) { diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index fa7095d59..f4d9cfef6 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -543,9 +543,7 @@ void CommanderLevelUp::applyCl( CClient *cl ) if (commander->armyObj && vstd::contains(cl->playerint, player)) //is it possible for Commander to exist beyond armed instance? { auto callback = boost::function(boost::bind(&CCallback::selectionMade,cl->callbacks[player].get(),_1,id)); - - cl->playerint[player]->showBlockingDialog("Commander got level", std::vector(), id, -1, false, true); - //cl->playerint[player]->commanderGotLevel(commander, skills, callback); + cl->playerint[player]->commanderGotLevel(commander, skills, callback); } } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index eb59a3b26..7a02d2507 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -1167,7 +1167,7 @@ struct CommanderLevelUp : public Query si32 heroid; //for commander attached to hero StackLocation sl; //for commander not on the hero? - std::vector skills; //1-6 - secondary skills, val - 100 - special skill + std::vector skills; //0-5 - secondary skills, val-100 - special skill CommanderLevelUp(){type = 2005;};