Browse Source

Commanders can level up. It's non-interactive yet.

Printing secondary skills for Commanders.
DjWarmonger 13 years ago
parent
commit
d491bc1c3a

+ 1 - 2
AI/EmptyAI/CEmptyAI.h

@@ -22,8 +22,7 @@ public:
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel){};
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) {};
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
-	void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
-							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) {};
+	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) {}; //TODO
 };
 
 #define NAME "EmptyAI 0.1"

+ 1 - 2
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<ui16> &skills, boost::function<void(ui32)> &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<std::pair<ui8, ui8> > secondarySkills,
-		std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) {};
+	virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) {}; //TODO
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &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<void()> &onEnd) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void serialize(COSer<CSaveFile> &h, const int version) OVERRIDE; //saving

+ 16 - 5
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<std::string>(it->second);
+				std::string sufix = boost::lexical_cast<std::string>((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";
+
+				//bonusGraphics = new CPicture(graphicsName, 26, 232);
+				//blitAtLoc(bonusGraphics->bg, 12, 2, bitmap->bg);
 
-				auto skillGraphics = new CPicture(file, 40 + i * 82, 121);
-				blitAtLoc(skillGraphics->bg, 0, 0, bitmap->bg);
+				auto skillGraphics = new CPicture(file, 39 + i * 82, 223);
+				//if (skillGraphics->bg)
+				//	blitAtLoc(skillGraphics->bg, 0, 0, bitmap->bg);
 			}
 		}
 	}

+ 1 - 1
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

+ 9 - 4
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<std::pair<ui8, ui8> > secondarySkills,
-										std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback)
+void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
 	CCS->soundh->playSound(soundBase::heroNewLevel);
 
-	CCreatureWindow * cw = new CCreatureWindow(commander);
-	GH.pushInt(cw);
+	//boost::function<void(ui32)>(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<CComponent*>());
+	//showYesNoDialog ("Commander got level", callback, callback, true, std::vector<CComponent*>());
+
+	//TODO: display full window
+	//CCreatureWindow * cw = new CCreatureWindow(commander);
+	//GH.pushInt(cw);
 }
 void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 {

+ 1 - 2
client/CPlayerInterface.h

@@ -139,8 +139,7 @@ public:
 
 	void heroCreated(const CGHeroInstance* hero) OVERRIDE;
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE;
-	void commanderGotLevel (const CCommanderInstance * commander, std::vector<std::pair<ui8, ui8> > secondarySkills,
-							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) OVERRIDE;
+	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) OVERRIDE;
 	void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;
 	void heroMoved(const TryMoveHero & details) OVERRIDE;
 	void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;

+ 8 - 1
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<void(ui32)>(boost::bind(&CCallback::selectionMade,cl->callbacks[player].get(),_1,id));
+		
+		cl->playerint[player]->showBlockingDialog("Commander got level", std::vector<Component>(), id, -1, false, true);
+		//cl->playerint[player]->commanderGotLevel(commander, skills, callback);
 	}
 }
 

+ 9 - 9
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]},

+ 2 - 1
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<ui8>());
+		BOOST_FOREACH (auto skillLevel, skill["levels"].Vector())
 		{
 			skillLevels[i].push_back (skillLevel.Float());
 		}

+ 4 - 1
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);

+ 3 - 2
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 <ui8, ui8> secondarySkills; //ID, level
+	std::vector <ui8> secondarySkills; //ID -> level
 	//std::vector <CArtifactInstance *> arts;
 	void init() OVERRIDE;
 	CCommanderInstance();
@@ -98,7 +99,7 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & static_cast<CStackInstance&>(*this);
-		h & alive & name & secondarySkills;
+		h & alive & level & name & secondarySkills;
 	}
 };
 

+ 1 - 2
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<ui16> &skills, boost::function<void(ui32)> &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<std::pair<ui8, ui8> > secondarySkills,
-							std::vector<Bonus *> specialSkills, boost::function<void(ui32)> &callback) = 0;
+	virtual	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)=0;
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &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<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving

+ 1 - 0
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

+ 1 - 1
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
 }

+ 38 - 32
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<CArmedInstance> army;
+	TSlot slot;
+
+	StackLocation()
+	{
+		slot = -1;
+	}
+	StackLocation(const CArmedInstance *Army, TSlot Slot)
+	{
+		army = const_cast<CArmedInstance*>(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 <typename Handler> 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);
+
+	si32 heroid; //for commander attached to hero
+	StackLocation sl; //for commander not on the hero?
 
-	ui8 which;
-	ui8 alive;
+	ui8 which; // use ECommanderProperty
+	ui8 amount; //0 for dead, >0 for alive
+	si32 additionalInfo; //for secondary skills choice
 	Bonus accumulatedBonus;
 
 	template <typename Handler> 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<CArmedInstance> army;
-	TSlot slot;
-
-	StackLocation()
-	{
-		slot = -1;
-	}
-	StackLocation(const CArmedInstance *Army, TSlot Slot)
-	{
-		army = const_cast<CArmedInstance*>(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 <typename Handler> 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<std::pair<ui8, ui8> > secondarySkills;
-	std::vector<Bonus *> specialSkills;
+	si32 heroid; //for commander attached to hero
+	StackLocation sl; //for commander not on the hero?
+
+	std::vector<ui32> skills; //1-6 - secondary skills, val - 100 - special skill
 
 	CommanderLevelUp(){type = 2005;};
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & id & commander & secondarySkills & specialSkills;
+		h & id & heroid & sl & skills;
 	}
 };
 

+ 25 - 1
lib/NetPacksLib.cpp

@@ -76,6 +76,28 @@ DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs )
 	hero->setSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(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();

+ 1 - 0
lib/RegisterTypes.h

@@ -139,6 +139,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<SetHoverName>();
 	s.template registerType<HeroLevelUp>();
 	s.template registerType<CommanderLevelUp>();
+	s.template registerType<SetCommanderProperty>();
 	s.template registerType<BlockingDialog>();
 	s.template registerType<GarrisonDialog>();
 	s.template registerType<BattleStart>();

+ 98 - 17
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<const CGHeroInstance *>(c->armyObj);
+	if (hero)
+		scp.heroid = hero->id;
+	else
+	{
+		complain ("Commander is not led by hero!");
+		return;
+	}
+
+	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)
 	{
-		//c->secondarySkills[secondarySkill]++; //TODO: make sure to resize vector in first place
+		auto difference = [](std::vector< std::vector <ui8> > skillLevels, std::vector <ui8> 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);
 	}
-	if (specialSKill >= 0)
+	else if (skill >= 100)
 	{
-		auto it = VLC->creh->skillRequirements.begin();
-		std::advance(it, specialSKill); //suboptimal, use bmap?
-		//c->accumulateBonus(it->first);
+		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;
 
-	//picking sec. skills for choice
+	auto hero = dynamic_cast<const CGHeroInstance *>(c->armyObj);
+	if (hero)
+		clu.heroid = hero->id;
+	else
+	{
+		complain ("Commander is not led by hero!");
+		return;
+	}
 
-	int secondarySkill = -1, specialSkill = -1;
+	//picking sec. skills for choice
 
-	int skills = clu.secondarySkills.size() + clu.specialSkills.size();
+	for (int i = 0; i <= ECommander::SPELL_POWER; ++i)
+	{
+		if (c->secondarySkills[i] < ECommander::MAX_SKILL_LEVEL)
+			clu.skills.push_back(i);
+	}
+	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 (skills > 1) //apply and ask for secondary skill
+	if (skillAmount > 1) //apply and ask for secondary skill
 	{
-		//auto callback = boost::bind (callWith<ui16>, clu.specialSkills, boost::bind(&CGameHandler::levelUpCommander, this, c, _1), _1);
-		//applyAndAsk (&clu, c->armyObj->tempOwner, callback); //call levelUpCommander when client responds
+		auto callback = boost::function<void(ui32)>(boost::bind(callWith<ui32>, clu.skills, boost::function<void(ui32)>(boost::bind(&CGameHandler::levelUpCommander, this, c, _1)), _1));
+		applyAndAsk (&clu, c->armyObj->tempOwner, callback); //call levelUpCommander when client responds
 	}
-	else if (skills == 1) //apply, give only possible skill  and send info
+	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
 	{

+ 1 - 1
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
 	//////////////////////////////////////////////////////////////////////////