From d491bc1c3aa4edfe7f13b3b1b4358c593657d8a7 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Fri, 18 May 2012 14:02:27 +0000 Subject: [PATCH] Commanders can level up. It's non-interactive yet. Printing secondary skills for Commanders. --- AI/EmptyAI/CEmptyAI.h | 3 +- AI/VCAI/VCAI.h | 3 +- client/CCreatureWindow.cpp | 21 +++++-- client/CCreatureWindow.h | 2 +- client/CPlayerInterface.cpp | 13 ++-- client/CPlayerInterface.h | 3 +- client/NetPacksClient.cpp | 9 ++- config/commanders.json | 18 +++--- lib/CCreatureHandler.cpp | 3 +- lib/CCreatureSet.cpp | 5 +- lib/CCreatureSet.h | 5 +- lib/CGameInterface.h | 3 +- lib/GameConstants.h | 1 + lib/HeroBonus.cpp | 2 +- lib/NetPacks.h | 70 +++++++++++---------- lib/NetPacksLib.cpp | 26 +++++++- lib/RegisterTypes.h | 1 + server/CGameHandler.cpp | 117 ++++++++++++++++++++++++++++++------ server/CGameHandler.h | 2 +- 19 files changed, 222 insertions(+), 85 deletions(-) diff --git a/AI/EmptyAI/CEmptyAI.h b/AI/EmptyAI/CEmptyAI.h index c1e3a9938..ad7efcdc3 100644 --- a/AI/EmptyAI/CEmptyAI.h +++ b/AI/EmptyAI/CEmptyAI.h @@ -22,8 +22,7 @@ public: void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, int soundID, bool selection, bool cancel){}; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function &onEnd) {}; void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback); - void commanderGotLevel (const CCommanderInstance * commander, std::vector > secondarySkills, - std::vector specialSkills, boost::function &callback) {}; + void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, boost::function &callback) {}; //TODO }; #define NAME "EmptyAI 0.1" diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 6e78169ac..22f3ff02b 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -210,8 +210,7 @@ public: virtual void init(CCallback * CB); virtual void yourTurn(); virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id - virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector > secondarySkills, - std::vector specialSkills, boost::function &callback) {}; + virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, boost::function &callback) {}; //TODO virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function &onEnd) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void serialize(COSer &h, const int version) OVERRIDE; //saving diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index 8358e9023..2aaf82e7d 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -301,8 +301,7 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * { for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i) { - auto it = commander->secondarySkills.find(i); - if (it != commander->secondarySkills.end()) + if (commander->secondarySkills[i]) { std::string file = "zvs/Lib1.res/_"; switch (i) @@ -326,10 +325,22 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * file += "MP"; break; } - file += boost::lexical_cast(it->second); + 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"; - auto skillGraphics = new CPicture(file, 40 + i * 82, 121); - blitAtLoc(skillGraphics->bg, 0, 0, bitmap->bg); + //bonusGraphics = new CPicture(graphicsName, 26, 232); + //blitAtLoc(bonusGraphics->bg, 12, 2, bitmap->bg); + + auto skillGraphics = new CPicture(file, 39 + i * 82, 223); + //if (skillGraphics->bg) + // blitAtLoc(skillGraphics->bg, 0, 0, bitmap->bg); } } } diff --git a/client/CCreatureWindow.h b/client/CCreatureWindow.h index 7dc270de6..1436cb2a1 100644 --- a/client/CCreatureWindow.h +++ b/client/CCreatureWindow.h @@ -40,7 +40,7 @@ class CAnimImage; class CCreatureWindow : public CArtifactHolder { public: - enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4}; // > 3 are opened permanently + enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4, COMMANDER_LEVEL_UP = 5}; // > 3 are opened permanently //bool active; //TODO: comment me int type;//0 - rclick popup; 1 - normal window int bonusRows; //height of skill window diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 4311f6f74..c56f54010 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -487,15 +487,20 @@ void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std: CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,callback); GH.pushInt(lw); } -void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector > secondarySkills, - std::vector specialSkills, boost::function &callback) +void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector skills, boost::function &callback) { EVENT_HANDLER_CALLED_BY_CLIENT; waitWhileDialog(); CCS->soundh->playSound(soundBase::heroNewLevel); - CCreatureWindow * cw = new CCreatureWindow(commander); - GH.pushInt(cw); + //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()); + + //TODO: display full window + //CCreatureWindow * cw = new CCreatureWindow(commander); + //GH.pushInt(cw); } void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town) { diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index b19e3273f..d58e788ca 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -139,8 +139,7 @@ public: void heroCreated(const CGHeroInstance* hero) OVERRIDE; void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback) OVERRIDE; - void commanderGotLevel (const CCommanderInstance * commander, std::vector > secondarySkills, - std::vector specialSkills, boost::function &callback) OVERRIDE; + void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, boost::function &callback) OVERRIDE; void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE; void heroMoved(const TryMoveHero & details) OVERRIDE; void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 4b31c2759..34c37494e 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -537,8 +537,15 @@ void HeroLevelUp::applyCl( CClient *cl ) } void CommanderLevelUp::applyCl( CClient *cl ) { - if (commander->armyObj && vstd::contains(cl->playerint, commander->armyObj->tempOwner)) //is it possible for Commander to exist beyond armed instance? + CCommanderInstance * commander = GS(cl)->getHero(heroid)->commander; + assert (commander); + ui8 player = commander->armyObj->tempOwner; + 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); } } diff --git a/config/commanders.json b/config/commanders.json index 702b998c6..81e226641 100644 --- a/config/commanders.json +++ b/config/commanders.json @@ -24,16 +24,16 @@ //Value of bonuses given by each skill level "skillLevels": [ - {"ATTACK": [2, 5, 9, 15, 25]}, //0 - {"DEFENSE": [4, 10, 18, 30, 50]}, //1 - {"HEALTH": [10, 25, 45, 70, 100]}, //2 - {"DAMAGE": [10, 25, 45, 70, 100]}, //3 - {"SPEED": [1, 2, 3, 4, 6]}, //4 - {"SPELL_POWER":[1, 3, 6, 14, 29]}, //5 - {"CASTS": [1, 2, 3, 4, 5]}, - {"RESISTANCE": [5, 15, 35, 60, 90]} + {"name": "ATTACK", "levels": [2, 5, 9, 15, 25]}, //0 + {"name": "DEFENSE", "levels": [4, 10, 18, 30, 50]}, //1 + {"name": "HEALTH", "levels": [10, 25, 45, 70, 100]}, //2 + {"name": "DAMAGE", "levels": [10, 25, 45, 70, 100]}, //3 + {"name": "SPEED", "levels": [1, 2, 3, 4, 6]}, //4 + {"name": "SPELL_POWER", "levels": [1, 3, 6, 14, 29]}, //5 + {"name": "CASTS", "levels": [1, 2, 3, 4, 5]}, + {"name": "RESISTANCE", "levels": [5, 15, 35, 60, 90]} ], - "abilityRequiremenets": + "abilityRequirements": //Two secondary skills needed for each special ability [ {"ability": ["ENEMY_DEFENCE_REDUCTION", 50, 0, 0 ], "skills": [0, 1]}, diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 8d3640927..d90b240bb 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -624,7 +624,8 @@ void CCreatureHandler::loadCreatures() i = 0; BOOST_FOREACH (auto skill, config3["skillLevels"].Vector()) { - BOOST_FOREACH (auto skillLevel, skill.Vector()) + skillLevels.push_back (std::vector()); + BOOST_FOREACH (auto skillLevel, skill["levels"].Vector()) { skillLevels[i].push_back (skillLevel.Float()); } diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index ef0b52e9e..f92baba6f 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -981,11 +981,13 @@ void CCommanderInstance::init() { alive = true; experience = 0; + level = 1; count = 1; type = NULL; idRand = -1; _armyObj = NULL; - setNodeType (Bonus::COMMANDER); + setNodeType (Bonus::COMMANDER); + secondarySkills.resize (ECommander::SPELL_POWER + 1); } CCommanderInstance::~CCommanderInstance() @@ -1016,6 +1018,7 @@ int CCommanderInstance::getExpRank() const void CCommanderInstance::levelUp () { + level++; BOOST_FOREACH (auto bonus, VLC->creh->commanderLevelPremy) { //grant all regular level-up bonuses accumulateBonus (*bonus); diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index 2c8972e50..2471a1835 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -80,8 +80,9 @@ public: //commander class is determined by its base creature ui8 alive; + ui8 level; //required only to count callbacks std::string name; // each Commander has different name - std::map secondarySkills; //ID, level + std::vector secondarySkills; //ID -> level //std::vector arts; void init() OVERRIDE; CCommanderInstance(); @@ -98,7 +99,7 @@ public: template void serialize(Handler &h, const int version) { h & static_cast(*this); - h & alive & name & secondarySkills; + h & alive & level & name & secondarySkills; } }; diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index 1dfae360f..41ab649ba 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -75,8 +75,7 @@ public: virtual void init(CCallback * CB){}; virtual void yourTurn(){}; //called AFTER playerStartsTurn(player) virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id - virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector > secondarySkills, - std::vector specialSkills, boost::function &callback) = 0; + virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, boost::function &callback)=0; virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void serialize(COSer &h, const int version){}; //saving diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 9ec48610c..738de1318 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -178,6 +178,7 @@ namespace EBattleStackState namespace ECommander { enum SecondarySkills {ATTACK, DEFENSE, HEALTH, DAMAGE, SPEED, SPELL_POWER, CASTS, RESISTANCE}; + const int MAX_SKILL_LEVEL = 5; } namespace Obj diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index d94bb380e..e269282c6 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -658,7 +658,7 @@ void CBonusSystemNode::accumulateBonus(Bonus &b) { Bonus *bonus = exportedBonuses.getFirst(Selector::typeSubtype(b.type, b.subtype)); //only local bonuses are interesting //TODO: what about value type? if(bonus) - bonus += b.val; + bonus->val += b.val; else addNewBonus(new Bonus(b)); //duplicate needed, original may get destroyed } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 5a406761f..15a9a0ff6 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -33,6 +33,7 @@ class CSelectionScreen; class CGObjectInstance; class CArtifactInstance; //class CMapInfo; +struct StackLocation; struct ArtSlotInfo; struct QuestInfo; @@ -165,6 +166,27 @@ public: } }; +struct StackLocation +{ + ConstTransitivePtr army; + TSlot slot; + + StackLocation() + { + slot = -1; + } + StackLocation(const CArmedInstance *Army, TSlot Slot) + { + army = const_cast(Army); //we are allowed here to const cast -> change will go through one of our packages... do not abuse! + slot = Slot; + } + DLL_LINKAGE const CStackInstance *getStack(); + template void serialize(Handler &h, const int version) + { + h & army & slot; + } +}; + /***********************************************************************************************************/ @@ -500,21 +522,25 @@ struct UpdateCampaignState : public CPackForClient //119 h & camp; } }; -struct SetCommanderproperty : public CPackForClient //120 +struct SetCommanderProperty : public CPackForClient //120 { - enum ECommanderProperty {ALIVE, BONUS}; + enum ECommanderProperty {ALIVE, BONUS, SECONDARY_SKILL}; - SetCommanderproperty(){type = 120;}; + SetCommanderProperty(){type = 120;}; void applyCl(CClient *cl){}; - DLL_LINKAGE void applyGs(CGameState *gs){}; + DLL_LINKAGE void applyGs(CGameState *gs); - ui8 which; - ui8 alive; + si32 heroid; //for commander attached to hero + StackLocation sl; //for commander not on the hero? + + ui8 which; // use ECommanderProperty + ui8 amount; //0 for dead, >0 for alive + si32 additionalInfo; //for secondary skills choice Bonus accumulatedBonus; template void serialize(Handler &h, const int version) { - h & which & alive & accumulatedBonus; + h & heroid & sl & which & amount & additionalInfo & accumulatedBonus; } }; struct AddQuest : public CPackForClient //121 @@ -762,27 +788,6 @@ struct NewArtifact : public CPackForClient //520 } }; -struct StackLocation -{ - ConstTransitivePtr army; - TSlot slot; - - StackLocation() - { - slot = -1; - } - StackLocation(const CArmedInstance *Army, TSlot Slot) - { - army = const_cast(Army); //we are allowed here to const cast -> change will go through one of our packages... do not abuse! - slot = Slot; - } - DLL_LINKAGE const CStackInstance *getStack(); - template void serialize(Handler &h, const int version) - { - h & army & slot; - } -}; - struct CGarrisonOperationPack : CPackForClient { }; @@ -1159,15 +1164,16 @@ struct CommanderLevelUp : public Query void applyCl(CClient *cl); DLL_LINKAGE void applyGs(CGameState *gs); - CCommanderInstance * commander; - std::vector > secondarySkills; - std::vector specialSkills; + 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 CommanderLevelUp(){type = 2005;}; template void serialize(Handler &h, const int version) { - h & id & commander & secondarySkills & specialSkills; + h & id & heroid & sl & skills; } }; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index f7c3b8e2d..bbb401a0c 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -76,6 +76,28 @@ DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs ) hero->setSecSkillLevel(static_cast(which), val, abs); } +DLL_LINKAGE void SetCommanderProperty::applyGs(CGameState *gs) +{ + CCommanderInstance * commander = gs->getHero(heroid)->commander; + assert (commander); + + switch (which) + { + case BONUS: + commander->accumulateBonus (accumulatedBonus); + break; + case SECONDARY_SKILL: + commander->secondarySkills[additionalInfo] = amount; + break; + case ALIVE: + if (amount) + commander->setAlive(true); + else + commander->setAlive(false); + break; + } +} + DLL_LINKAGE void HeroVisitCastle::applyGs( CGameState *gs ) { CGHeroInstance *h = gs->getHero(hid); @@ -901,6 +923,8 @@ DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs ) DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs) { + CCommanderInstance * commander = gs->getHero(heroid)->commander; + assert (commander); commander->levelUp(); } @@ -1007,7 +1031,7 @@ void BattleResult::applyGs( CGameState *gs ) if (h) { h->getBonusList().remove_if(Bonus::OneBattle); - if (h->commander) + if (h->commander && h->commander->alive) { h->commander->giveStackExp(exp[i]); CBonusSystemNode::treeHasChanged(); diff --git a/lib/RegisterTypes.h b/lib/RegisterTypes.h index e28f1a245..ed753c90e 100644 --- a/lib/RegisterTypes.h +++ b/lib/RegisterTypes.h @@ -139,6 +139,7 @@ void registerTypes2(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 431e45f49..0667f4560 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -285,42 +285,123 @@ void CGameHandler::levelUpHero(int ID) } } -void CGameHandler::levelUpCommander (const CCommanderInstance * c, int secondarySkill, int specialSKill) +void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill) { - if (secondarySkill >=0 ) + SetCommanderProperty scp; + + auto hero = dynamic_cast(c->armyObj); + if (hero) + scp.heroid = hero->id; + else { - //c->secondarySkills[secondarySkill]++; //TODO: make sure to resize vector in first place + complain ("Commander is not led by hero!"); + return; } - if (specialSKill >= 0) + + scp.which = SetCommanderProperty::BONUS; + scp.accumulatedBonus.additionalInfo = 0; + scp.accumulatedBonus.duration = Bonus::PERMANENT; + scp.accumulatedBonus.turnsRemain = 0; + scp.accumulatedBonus.source = Bonus::COMMANDER; + scp.accumulatedBonus.valType = Bonus::BASE_NUMBER; + if (skill <= ECommander::SPELL_POWER) { - auto it = VLC->creh->skillRequirements.begin(); - std::advance(it, specialSKill); //suboptimal, use bmap? - //c->accumulateBonus(it->first); + auto difference = [](std::vector< std::vector > skillLevels, std::vector secondarySkills, int skill)->int + { + return skillLevels[skill][secondarySkills[skill]] - (secondarySkills[skill] ? skillLevels[skill][secondarySkills[skill]-1] : 0); + }; + switch (skill) + { + case ECommander::ATTACK: + scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL; + scp.accumulatedBonus.subtype = PrimarySkill::ATTACK; + break; + case ECommander::DEFENSE: + scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL; + scp.accumulatedBonus.subtype = PrimarySkill::DEFENSE; + break; + case ECommander::HEALTH: + scp.accumulatedBonus.type = Bonus::STACK_HEALTH; + scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE; + break; + case ECommander::DAMAGE: + scp.accumulatedBonus.type = Bonus::CREATURE_DAMAGE; + scp.accumulatedBonus.subtype = 0; + scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE; + break; + case ECommander::SPEED: + scp.accumulatedBonus.type = Bonus::STACKS_SPEED; + break; + case ECommander::SPELL_POWER: + scp.accumulatedBonus.type = Bonus::MAGIC_RESISTANCE; + scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::RESISTANCE); + sendAndApply (&scp); //additional pack + scp.accumulatedBonus.type = Bonus::CASTS; + scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::CASTS); + sendAndApply (&scp); //additional pack + scp.accumulatedBonus.type = Bonus::CREATURE_ENCHANT_POWER; //send normally + break; + } + + scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, skill); + sendAndApply (&scp); + + scp.which = SetCommanderProperty::SECONDARY_SKILL; + scp.additionalInfo = skill; + scp.amount = c->secondarySkills[skill] + 1; + sendAndApply (&scp); + } + else if (skill >= 100) + { + scp.accumulatedBonus = VLC->creh->skillRequirements[skill-100].first; + sendAndApply (&scp); } levelUpCommander (c); - //c->levelUp(); //change standard parameters } void CGameHandler::levelUpCommander(const CCommanderInstance * c) { - return; + if (c->experience < VLC->heroh->reqExp (c->level + 1)) + { + return; + } CommanderLevelUp clu; + auto hero = dynamic_cast(c->armyObj); + if (hero) + clu.heroid = hero->id; + else + { + complain ("Commander is not led by hero!"); + return; + } + //picking sec. skills for choice - int secondarySkill = -1, specialSkill = -1; - - int skills = clu.secondarySkills.size() + clu.specialSkills.size(); - - if (skills > 1) //apply and ask for secondary skill + for (int i = 0; i <= ECommander::SPELL_POWER; ++i) { - //auto callback = boost::bind (callWith, clu.specialSkills, boost::bind(&CGameHandler::levelUpCommander, this, c, _1), _1); - //applyAndAsk (&clu, c->armyObj->tempOwner, callback); //call levelUpCommander when client responds + if (c->secondarySkills[i] < ECommander::MAX_SKILL_LEVEL) + clu.skills.push_back(i); } - else if (skills == 1) //apply, give only possible skill and send info + int i = 100; + BOOST_FOREACH (auto specialSkill, VLC->creh->skillRequirements) + { + if (c->secondarySkills[specialSkill.second.first] == ECommander::MAX_SKILL_LEVEL && + c->secondarySkills[specialSkill.second.second] == ECommander::MAX_SKILL_LEVEL) + clu.skills.push_back (i); + ++i; + } + int skillAmount = clu.skills.size(); + + if (skillAmount > 1) //apply and ask for secondary skill + { + auto callback = boost::function(boost::bind(callWith, clu.skills, boost::function(boost::bind(&CGameHandler::levelUpCommander, this, c, _1)), _1)); + applyAndAsk (&clu, c->armyObj->tempOwner, callback); //call levelUpCommander when client responds + } + else if (skillAmount == 1) //apply, give only possible skill and send info { sendAndApply(&clu); - levelUpCommander(c, secondarySkill, specialSkill); + levelUpCommander(c, clu.skills.back()); } else //apply and send info { diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 22b4f7293..cd793d0ec 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -182,7 +182,7 @@ public: void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h); void levelUpHero(int ID, int skill);//handle client respond and send one more request if needed void levelUpHero(int ID);//initial call - check if hero have remaining levelups & handle them - void levelUpCommander (const CCommanderInstance * c, int secondarySkill, int specialSKill); + void levelUpCommander (const CCommanderInstance * c, int skill); //secondary skill 1 to 6, special skill : skill - 100 void levelUpCommander (const CCommanderInstance * c); void afterBattleCallback(); // called after level-ups are finished //////////////////////////////////////////////////////////////////////////