Sfoglia il codice sorgente

* enum for secondary skills
* THex for battle positions
* towards removal of battleGetStackByID

TODO:
investigate the necessity of putting implementation of BattleAction CGlobalAI::activeStack( const CStack * stack ) in CGeniusAI.cpp

mateuszb 15 anni fa
parent
commit
4929cf9782

+ 22 - 12
AI/GeniusAI/CGeniusAI.cpp

@@ -1305,7 +1305,7 @@ void CGeniusAI::battleNewRound(int round)
 /**
  *
  */
-void CGeniusAI::battleStackMoved(int ID, int dest, int distance, bool end)
+void CGeniusAI::battleStackMoved(int ID, THex dest, int distance, bool end)
 {
 	std::string message("\t\t\tCGeniusAI::battleStackMoved ID(");
 	message += boost::lexical_cast<std::string>(ID);
@@ -1338,13 +1338,13 @@ void CGeniusAI::battleSpellCast(const BattleSpellCast *sc)
 /**
  *
  */
-void CGeniusAI::battleStackMoved(int ID,
-                                 int dest,
-                                 bool startMoving,
-                                 bool endMoving)
-{
-	DbgBox("\t\t\tCGeniusAI::battleStackMoved");
-}
+// void CGeniusAI::battleStackMoved(int ID,
+//                                  THex dest,
+//                                  bool startMoving,
+//                                  bool endMoving)
+// {
+// 	DbgBox("\t\t\tCGeniusAI::battleStackMoved");
+// }
 
 
 /**
@@ -1372,15 +1372,25 @@ void CGeniusAI::battleStackIsAttacked(int ID,
 /**
  * called when it's turn of that stack
  */
-BattleAction CGeniusAI::activeStack(int stackID)
+BattleAction CGeniusAI::activeStack(const CStack * stack)
 {
 	std::string message("\t\t\tCGeniusAI::activeStack stackID(");
 
-	message += boost::lexical_cast<std::string>(stackID);
+	message += boost::lexical_cast<std::string>(stack->ID);
 	message += ")";
 	DbgBox(message.c_str());
 
-	BattleAction bact = m_battleLogic->MakeDecision(stackID);
+	BattleAction bact = m_battleLogic->MakeDecision(stack->ID);
 	assert(m_cb->battleGetStackByID(bact.stackNumber));
 	return bact;
-};
+}
+
+
+//WTF?!? why is this needed?!?!?!
+BattleAction CGlobalAI::activeStack( const CStack * stack )
+{
+	BattleAction ba; ba.actionType = BattleAction::DEFEND;
+	ba.stackNumber = stack->ID;
+	return ba;
+}
+

+ 3 - 3
AI/GeniusAI/CGeniusAI.h

@@ -205,15 +205,15 @@ public:
 	virtual void battleStacksAttacked(const std::set<BattleStackAttacked> & bsa); //called when stack receives damage (after battleAttack())
 	virtual void battleEnd(const BattleResult *br);
 	virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
-	virtual void battleStackMoved(int ID, int dest, int distance, bool end);
+	virtual void battleStackMoved(int ID, THex dest, int distance, bool end);
 	virtual void battleSpellCast(const BattleSpellCast *sc);
 	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 	//
-	virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);
+	//virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);
 	virtual void battleStackAttacking(int ID, int dest);
 	virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting);
-	virtual BattleAction activeStack(int stackID);
+	virtual BattleAction activeStack(const CStack * stack);
 	void battleResultsApplied();
 	friend class Priorities;
 };

+ 4 - 3
AI/StupidAI/StupidAI.cpp

@@ -1,5 +1,6 @@
 #include "stdafx.h"
 #include "StupidAI.h"
+#include "../../lib/CGameState.h"
 
 CStupidAI::CStupidAI(void)
 {
@@ -25,10 +26,10 @@ void CStupidAI::actionStarted( const BattleAction *action )
 
 }
 
-BattleAction CStupidAI::activeStack( int stackID )
+BattleAction CStupidAI::activeStack( const CStack * stack )
 {
 	BattleAction ba;
-	ba.DEFEND;
-	ba.stackNumber = stackID;
+	ba.actionType = BattleAction::DEFEND;
+	ba.stackNumber = stack->ID;
 	return ba;
 }

+ 1 - 1
AI/StupidAI/StupidAI.h

@@ -9,6 +9,6 @@ public:
 	void init(IBattleCallback * CB) OVERRIDE;
 	void actionFinished(const BattleAction *action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
 	void actionStarted(const BattleAction *action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
-	BattleAction activeStack(int stackID) OVERRIDE; //called when it's turn of that stack
+	BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack
 };
 

+ 8 - 0
CGameInterface.cpp

@@ -1,5 +1,6 @@
 #include "stdafx.h"
 #include "CGameInterface.h"
+#include "lib/CGameState.h"
 
 #ifdef _WIN32
 	#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
@@ -70,3 +71,10 @@ CBattleGameInterface * CAIHandler::getNewBattleAI( CCallback * cb, std::string d
 {
 	return createAnyAI<CBattleGameInterface>(cb, dllname, "GetNewBattleAI");
 }
+
+BattleAction CGlobalAI::activeStack( const CStack * stack )
+{
+	BattleAction ba; ba.actionType = BattleAction::DEFEND;
+	ba.stackNumber = stack->ID;
+	return ba;
+}

+ 10 - 10
CGameInterface.h

@@ -45,6 +45,7 @@ struct CatapultAttack;
 struct BattleStacksRemoved;
 struct StackLocation;
 class CStackInstance;
+class CStack;
 class CCreature;
 class CLoadFile;
 class CSaveFile;
@@ -66,20 +67,19 @@ public:
 	//battle call-ins
 	virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero
 	virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
-	virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
+	virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
 	virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack
 	virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
 	virtual void battleEnd(const BattleResult *br){};
 	virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
 	virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
-	virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
+	virtual void battleStackMoved(int ID, THex dest, int distance, bool end){};
 	virtual void battleSpellCast(const BattleSpellCast *sc){};
 	virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
 	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
-	//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
 	virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
-	virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
+	virtual void battleNewStackAppeared(const CStack * stack){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
 	virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set  of obstacles is removed from batlefield; IDs of them are given
 	virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
 	virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
@@ -154,13 +154,13 @@ class CGlobalAI : public CGameInterface // AI class (to derivate)
 {
 public:
 	//CGlobalAI();
-	virtual void yourTurn(){};
+	virtual void yourTurn() OVERRIDE{};
 	virtual void heroKilled(const CGHeroInstance*){};
-	virtual void heroCreated(const CGHeroInstance*){};
-	virtual void battleStackMoved(int ID, int dest, int distance){};
-	virtual void battleStackAttacking(int ID, int dest){};
-	virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting){};
-	virtual BattleAction activeStack(int stackID) {BattleAction ba; ba.actionType = 3; ba.stackNumber = stackID; return ba;};
+	virtual void heroCreated(const CGHeroInstance*) OVERRIDE{};
+	virtual void battleStackMoved(int ID, THex dest, int distance, bool end) OVERRIDE{};
+	virtual void battleStackAttacking(int ID, int dest) {};
+	virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) OVERRIDE{};
+	virtual BattleAction activeStack(const CStack * stack) OVERRIDE;
 };
 
 #endif // __CGAMEINTERFACE_H__

+ 31 - 30
client/CBattleInterface.cpp

@@ -304,7 +304,7 @@ void CSpellEffectAnim::endAnim()
 	delete this;
 }
 
-CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx, int _dy, bool _Vflip)
+CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, THex _destTile, int _dx, int _dy, bool _Vflip)
 :CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), dx(_dx), dy(_dy), Vflip(_Vflip)
 {
 }
@@ -321,7 +321,7 @@ CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * _owner, int stac
 {
 }
 
-bool CBattleStackAnimation::isToReverseHlp(int hexFrom, int hexTo, bool curDir)
+bool CBattleStackAnimation::isToReverseHlp(THex hexFrom, THex hexTo, bool curDir)
 {
 	int fromMod = hexFrom % BFIELD_WIDTH;
 	int fromDiv = hexFrom / BFIELD_WIDTH;
@@ -347,7 +347,7 @@ bool CBattleStackAnimation::isToReverseHlp(int hexFrom, int hexTo, bool curDir)
 	return false; //should never happen
 }
 
-bool CBattleStackAnimation::isToReverse(int hexFrom, int hexTo, bool curDir, bool toDoubleWide, bool toDir)
+bool CBattleStackAnimation::isToReverse(THex hexFrom, THex hexTo, bool curDir, bool toDoubleWide, bool toDir)
 {
 	if(hexTo < 0) //turret
 		return false;
@@ -442,7 +442,7 @@ void CReverseAnim::endAnim()
 	delete this;
 }
 
-CReverseAnim::CReverseAnim(CBattleInterface * _owner, int stack, int dest, bool _priority)
+CReverseAnim::CReverseAnim(CBattleInterface * _owner, int stack, THex dest, bool _priority)
 : CBattleStackAnimation(_owner, stack), partOfAnim(1), secondPartSetup(false), hex(dest), priority(_priority)
 {
 }
@@ -723,7 +723,7 @@ void CBattleStackMoved::endAnim()
 	delete this;
 }
 
-CBattleStackMoved::CBattleStackMoved(CBattleInterface * _owner, int _number, int _destHex, bool _endMoving, int _distance)
+CBattleStackMoved::CBattleStackMoved(CBattleInterface * _owner, int _number, THex _destHex, bool _endMoving, int _distance)
 : CBattleStackAnimation(_owner, _number), destHex(_destHex), endMoving(_endMoving), distance(_distance), stepX(0.0f), stepY(0.0f)
 {
 	curStackPos = owner->curInt->cb->battleGetPos(stackID);
@@ -815,7 +815,7 @@ void CBattleMoveEnd::endAnim()
 	delete this;
 }
 
-CBattleMoveEnd::CBattleMoveEnd(CBattleInterface * _owner, int stack, int destTile)
+CBattleMoveEnd::CBattleMoveEnd(CBattleInterface * _owner, int stack, THex destTile)
 : CBattleStackAnimation(_owner, stack), destinationTile(destTile)
 {
 }
@@ -847,7 +847,7 @@ bool CBattleAttack::checkInitialConditions()
 	return isEarliest(false);
 }
 
-CBattleAttack::CBattleAttack(CBattleInterface * _owner, int _stackID, int _dest, int _attackedID)
+CBattleAttack::CBattleAttack(CBattleInterface * _owner, int _stackID, THex _dest, int _attackedID)
 : CBattleStackAnimation(_owner, _stackID), dest(_dest)
 {
 	attackedStack = owner->curInt->cb->battleGetStackByID(_attackedID, false);
@@ -954,7 +954,7 @@ void CMeleeAttack::endAnim()
 	delete this;
 }
 
-CMeleeAttack::CMeleeAttack(CBattleInterface * _owner, int attacker, int _dest, int _attackedID)
+CMeleeAttack::CMeleeAttack(CBattleInterface * _owner, int attacker, THex _dest, int _attackedID)
 : CBattleAttack(_owner, attacker, _dest, _attackedID)
 {
 }
@@ -1081,7 +1081,7 @@ void CShootingAnim::endAnim()
 	delete this;
 }
 
-CShootingAnim::CShootingAnim(CBattleInterface * _owner, int attacker, int _dest, int _attackedID, bool _catapult, int _catapultDmg)
+CShootingAnim::CShootingAnim(CBattleInterface * _owner, int attacker, THex _dest, int _attackedID, bool _catapult, int _catapultDmg)
 : CBattleAttack(_owner, attacker, _dest, _attackedID), catapultDamage(_catapultDmg), catapult(_catapult)
 {
 	if(catapult) //catapult attack
@@ -1145,7 +1145,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	std::vector<const CStack*> stacks = curInt->cb->battleGetStacks();
 	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		newStack(s->ID);
+		newStack(s);
 	}
 
 	//preparing menu background and terrain
@@ -2225,37 +2225,36 @@ void CBattleInterface::bConsoleDownf()
 	console->scrollDown();
 }
 
-void CBattleInterface::newStack(int stackID)
+void CBattleInterface::newStack(const CStack * stack)
 {
-	const CStack * newStack = curInt->cb->battleGetStackByID(stackID);
+	Point coords = CBattleHex::getXYUnitAnim(stack->position, stack->owner == attackingHeroInstance->tempOwner, stack, this);;
 
-	Point coords = CBattleHex::getXYUnitAnim(newStack->position, newStack->owner == attackingHeroInstance->tempOwner, newStack, this);;
-
-	if(newStack->position < 0) //turret
+	if(stack->position < 0) //turret
 	{
 		const CCreature & turretCreature = *CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ];
-		creAnims[stackID] = new CCreatureAnimation(turretCreature.animDefName);	
+		creAnims[stack->ID] = new CCreatureAnimation(turretCreature.animDefName);	
 	}
 	else
 	{
-		creAnims[stackID] = new CCreatureAnimation(newStack->getCreature()->animDefName);	
+		creAnims[stack->ID] = new CCreatureAnimation(stack->getCreature()->animDefName);	
 	}
-	creAnims[stackID]->setType(2);
-	creAnims[stackID]->pos = Rect(coords.x, coords.y, creAnims[newStack->ID]->fullWidth, creAnims[newStack->ID]->fullHeight);
-	creDir[stackID] = newStack->attackerOwned;
+	creAnims[stack->ID]->setType(2);
+	creAnims[stack->ID]->pos = Rect(coords.x, coords.y, creAnims[stack->ID]->fullWidth, creAnims[stack->ID]->fullHeight);
+	creDir[stack->ID] = stack->attackerOwned;
 }
 
-void CBattleInterface::stackRemoved(int stackID)
+void CBattleInterface::stackRemoved(const CStack * stack)
 {
+	int stackID = stack->ID;
 	delete creAnims[stackID];
 	creAnims.erase(stackID);
 	creDir.erase(stackID);
 }
 
-void CBattleInterface::stackActivated(int number)
+void CBattleInterface::stackActivated(const CStack * stack)
 {
 	//givenCommand = NULL;
-	stackToActivate = number;
+	stackToActivate = stack->ID;
 	if(pendingAnims.size() == 0)
 		activateStack();
 }
@@ -2273,9 +2272,16 @@ void CBattleInterface::stacksAreAttacked(std::vector<SStackAttackedInfo> attacke
 	}
 }
 
-void CBattleInterface::stackAttacking(int ID, int dest, int attackedID)
+void CBattleInterface::stackAttacking( const CStack * attacker, THex dest, const CStack * attacked, bool shooting )
 {
-	addNewAnim(new CMeleeAttack(this, ID, dest, attackedID));
+	if (shooting)
+	{
+		addNewAnim(new CShootingAnim(this, attacker->ID, dest, attacked->ID));
+	}
+	else
+	{
+		addNewAnim(new CMeleeAttack(this, attacker->ID, dest, attacked->ID));
+	}
 }
 
 void CBattleInterface::newRoundFirst( int round )
@@ -2636,11 +2642,6 @@ void CBattleInterface::hexLclicked(int whichOne)
 	}
 }
 
-void CBattleInterface::stackIsShooting(int ID, int dest, int attackedID)
-{
-	addNewAnim(new CShootingAnim(this, ID, dest, attackedID));
-}
-
 void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca)
 {
 	for(std::set< std::pair< std::pair< ui8, si16 >, ui8> >::const_iterator it = ca.attackedParts.begin(); it != ca.attackedParts.end(); ++it)

+ 18 - 20
client/CBattleInterface.h

@@ -91,7 +91,7 @@ class CSpellEffectAnim : public CBattleAnimation
 {
 private:
 	ui32 effect;
-	int destTile;
+	THex destTile;
 	std::string customAnim;
 	int x, y, dx, dy;
 	bool Vflip;
@@ -100,7 +100,7 @@ public:
 	void nextFrame();
 	void endAnim();
 
-	CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false);
+	CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, THex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false);
 	CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false);
 };
 
@@ -110,8 +110,8 @@ public:
 	int stackID; //id of stack whose animation it is
 
 	CBattleStackAnimation(CBattleInterface * _owner, int stack);
-	static bool isToReverseHlp(int hexFrom, int hexTo, bool curDir); //helper for isToReverse
-	static bool isToReverse(int hexFrom, int hexTo, bool curDir /*if true, creature is in attacker's direction*/, bool toDoubleWide, bool toDir); //determines if creature should be reversed (it stands on hexFrom and should 'see' hexTo)
+	static bool isToReverseHlp(THex hexFrom, THex hexTo, bool curDir); //helper for isToReverse
+	static bool isToReverse(THex hexFrom, THex hexTo, bool curDir /*if true, creature is in attacker's direction*/, bool toDoubleWide, bool toDir); //determines if creature should be reversed (it stands on hexFrom and should 'see' hexTo)
 };
 
 class CReverseAnim : public CBattleStackAnimation
@@ -119,14 +119,14 @@ class CReverseAnim : public CBattleStackAnimation
 private:
 	int partOfAnim; //1 - first, 2 - second
 	bool secondPartSetup;
-	int hex;
+	THex hex;
 public:
 	bool priority; //true - high, false - low
 	bool init();
 	void nextFrame();
 	void endAnim();
 
-	CReverseAnim(CBattleInterface * _owner, int stack, int dest, bool _priority);
+	CReverseAnim(CBattleInterface * _owner, int stack, THex dest, bool _priority);
 };
 
 class CDefenceAnim : public CBattleStackAnimation
@@ -149,7 +149,7 @@ public:
 class CBattleStackMoved : public CBattleStackAnimation
 {
 private:
-	int destHex; //destination
+	THex destHex; //destination
 	bool endMoving; //if this is end of move
 	int distance;
 	float stepX, stepY; //how far stack is moved in one frame
@@ -161,7 +161,7 @@ public:
 	void nextFrame();
 	void endAnim();
 
-	CBattleStackMoved(CBattleInterface * _owner, int _number, int _destHex, bool _endMoving, int _distance);
+	CBattleStackMoved(CBattleInterface * _owner, int _number, THex _destHex, bool _endMoving, int _distance);
 };
 
 class CBattleMoveStart : public CBattleStackAnimation
@@ -177,20 +177,20 @@ public:
 class CBattleMoveEnd : public CBattleStackAnimation
 {
 private:
-	int destinationTile;
+	THex destinationTile;
 public:
 	bool init();
 	void nextFrame();
 	void endAnim();
 
-	CBattleMoveEnd(CBattleInterface * _owner, int stack, int destTile);
+	CBattleMoveEnd(CBattleInterface * _owner, int stack, THex destTile);
 };
 
 class CBattleAttack : public CBattleStackAnimation
 {
 protected:
 	int IDby; //attacked stack
-	int dest; //atacked hex
+	THex dest; //atacked hex
 	int posShiftDueToDist;
 	bool shooting;
 	int group; //if shooting is true, print this animation group
@@ -203,7 +203,7 @@ public:
 	bool checkInitialConditions();
 
 
-	CBattleAttack(CBattleInterface * _owner, int _stackID, int _dest, int _attackedID);
+	CBattleAttack(CBattleInterface * _owner, int _stackID, THex _dest, int _attackedID);
 };
 
 class CMeleeAttack : public CBattleAttack
@@ -213,7 +213,7 @@ public:
 	void nextFrame();
 	void endAnim();
 
-	CMeleeAttack(CBattleInterface * _owner, int attacker, int _dest, int _attackedID);
+	CMeleeAttack(CBattleInterface * _owner, int attacker, THex _dest, int _attackedID);
 };
 
 class CShootingAnim : public CBattleAttack
@@ -226,7 +226,7 @@ public:
 	void nextFrame();
 	void endAnim();
 
-	CShootingAnim(CBattleInterface * _owner, int attacker, int _dest, int _attackedID, bool _catapult = false, int _catapultDmg = 0); //last param only for catapult attacks
+	CShootingAnim(CBattleInterface * _owner, int attacker, THex _dest, int _attackedID, bool _catapult = false, int _catapultDmg = 0); //last param only for catapult attacks
 };
 
 //end of battle animation handlers
@@ -491,17 +491,15 @@ public:
 
 	//call-ins
 	void startAction(const BattleAction* action);
-	void newStack(int stackID); //new stack appeared on battlefield
-	void stackRemoved(int stackID); //stack disappeared from batlefiled
-	//void stackKilled(int ID, int dmg, int killed, int IDby, bool byShooting); //stack has been killed (but corpses remain)
-	void stackActivated(int number); //active stack has been changed
+	void newStack(const CStack * stack); //new stack appeared on battlefield
+	void stackRemoved(const CStack * stack); //stack disappeared from batlefiled
+	void stackActivated(const CStack * stack); //active stack has been changed
 	void stackMoved(int number, int destHex, bool endMoving, int distance); //stack with id number moved to destHex
 	void stacksAreAttacked(std::vector<SStackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
-	void stackAttacking(int ID, int dest, int attackedID); //called when stack with id ID is attacking something on hex dest
+	void stackAttacking(const CStack * attacker, THex dest, const CStack * attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
 	void newRoundFirst( int round );
 	void newRound(int number); //caled when round is ended; number is the number of round
 	void hexLclicked(int whichOne); //hex only call-in
-	void stackIsShooting(int ID, int dest, int attackedID); //called when stack with id ID is shooting to hex dest
 	void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
 	void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
 	const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end

+ 2 - 2
client/CHeroWindow.cpp

@@ -201,7 +201,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	for(size_t g=0; g<std::min(secSkillAreas.size(),hero->secSkills.size()); ++g)
 	{
 		int skill = hero->secSkills[g].first,
-			level = hero->getSecSkillLevel(hero->secSkills[g].first);
+			level = hero->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(hero->secSkills[g].first));
 		secSkillAreas[g]->type = skill;
 		secSkillAreas[g]->bonusValue = level;
 		secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
@@ -232,7 +232,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	}
 	dismissButton->block(!!hero->visitedTown || noDismiss);
 
-	if(hero->getSecSkillLevel(19) == 0)
+	if(hero->getSecSkillLevel(CGHeroInstance::TACTICS) == 0)
 		tacticsButton->block(true);
 	else
 	{

+ 1 - 1
client/CKingdomInterface.cpp

@@ -164,7 +164,7 @@ CKingdomInterface::CKingdomInterface()
 	incomesVal[7] = incomesVal[6]*1000;//gold mines -> total income
 	std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
 	for(size_t i=0; i<heroes.size();i++)
-		switch(heroes[i]->getSecSkillLevel(13))//some heroes may have estates
+		switch(heroes[i]->getSecSkillLevel(CGHeroInstance::ESTATES))//some heroes may have estates
 		{
 		case 1: //basic
 			incomesVal[7] += 125;

+ 14 - 10
client/CPlayerInterface.cpp

@@ -600,7 +600,7 @@ void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, u
 	}
 }
 
-void CPlayerInterface::battleNewStackAppeared(int stackID)
+void CPlayerInterface::battleNewStackAppeared(const CStack * stack)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -608,7 +608,7 @@ void CPlayerInterface::battleNewStackAppeared(int stackID)
 	}
 
 	//changing necessary things in battle interface
-	battleInt->newStack(stackID);
+	battleInt->newStack(stack);
 }
 
 void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
@@ -652,7 +652,7 @@ void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
 
 	for(std::set<ui32>::const_iterator it = bsr.stackIDs.begin(); it != bsr.stackIDs.end(); ++it) //for each removed stack
 	{
-		battleInt->stackRemoved(*it);
+		battleInt->stackRemoved(LOCPLINT->cb->battleGetStackByID(*it));
 	}
 }
 
@@ -692,14 +692,13 @@ void CPlayerInterface::actionFinished(const BattleAction* action)
 	battleInt->endAction(action);
 }
 
-BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack
+BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack
 {
 
 	CBattleInterface *b = battleInt;
 	{
 		boost::unique_lock<boost::recursive_mutex> un(*pim);
 
-		const CStack *stack = cb->battleGetStackByID(stackID);
 		if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale
 		{
 			std::string hlp = CGI->generaltexth->allTexts[33];
@@ -708,7 +707,7 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
 			battleInt->console->addText(hlp);
 		}
 
-		b->stackActivated(stackID);
+		b->stackActivated(stack);
 	}
 	//wait till BattleInterface sets its command
 	boost::unique_lock<boost::mutex> lock(b->givenCommand->mx);
@@ -735,7 +734,7 @@ void CPlayerInterface::battleEnd(const BattleResult *br)
 	battleInt->battleFinished(*br);
 }
 
-void CPlayerInterface::battleStackMoved(int ID, int dest, int distance, bool end)
+void CPlayerInterface::battleStackMoved(int ID, THex dest, int distance, bool end)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -819,14 +818,18 @@ void CPlayerInterface::battleAttack(const BattleAttack *ba)
 	}
 	//TODO: bad luck?
 
+	const CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);
+
 	if(ba->shot())
 	{
 		for(std::vector<BattleStackAttacked>::const_iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
-			battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(i->stackAttacked), i->stackAttacked);
+		{
+			const CStack * attacked = cb->battleGetStackByID(i->stackAttacked);
+			battleInt->stackAttacking(attacker, cb->battleGetPos(i->stackAttacked), attacked, true);
+		}
 	}
 	else
 	{//WARNING: does not support multiple attacked creatures
-		const CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);
 		int shift = 0;
 		if(ba->counter() && BattleInfo::mutualPosition(curAction->destinationTile, attacker->position) < 0)
 		{
@@ -838,7 +841,8 @@ void CPlayerInterface::battleAttack(const BattleAttack *ba)
 			else
 				shift = -1;
 		}
-		battleInt->stackAttacking( ba->stackAttacking, ba->counter() ? curAction->destinationTile + shift : curAction->additionalInfo, ba->bsa.begin()->stackAttacked );
+		const CStack * attacked = cb->battleGetStackByID(ba->bsa.begin()->stackAttacked);
+		battleInt->stackAttacking( attacker, ba->counter() ? curAction->destinationTile + shift : curAction->additionalInfo, attacked, false);
 	}
 }
 

+ 4 - 5
client/CPlayerInterface.h

@@ -158,7 +158,7 @@ public:
 	const CGHeroInstance *getWHero(int pos); //returns NULL if position is not valid
 	int getLastIndex(std::string namePrefix);
 
-	//overloaded funcs from CGameInterface
+	//overridden funcs from CGameInterface
 	void buildChanged(const CGTownInstance *town, int buildingID, int what) OVERRIDE; //what: 1 - built, 2 - demolished
 	void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) OVERRIDE; //if absolute, change is the new count; otherwise count was modified by adding change
 	void stackChangedType(const StackLocation &location, const CCreature &newType) OVERRIDE; //used eg. when upgrading creatures
@@ -208,19 +208,18 @@ public:
 	//for battles
 	void actionFinished(const BattleAction* action) OVERRIDE;//occurs AFTER action taken by active stack or by the hero
 	void actionStarted(const BattleAction* action) OVERRIDE;//occurs BEFORE action taken by active stack or by the hero
-	BattleAction activeStack(int stackID) OVERRIDE; //called when it's turn of that stack
+	BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack
 	void battleAttack(const BattleAttack *ba) OVERRIDE; //stack performs attack
 	void battleEnd(const BattleResult *br) OVERRIDE; //end of battle
-	//void battleResultQuited();
 	void battleNewRoundFirst(int round) OVERRIDE; //called at the beginning of each turn before changes are applied; used for HP regen handling
 	void battleNewRound(int round) OVERRIDE; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
-	void battleStackMoved(int ID, int dest, int distance, bool end) OVERRIDE;
+	void battleStackMoved(int ID, THex dest, int distance, bool end) OVERRIDE;
 	void battleSpellCast(const BattleSpellCast *sc) OVERRIDE;
 	void battleStacksEffectsSet(const SetStackEffect & sse) OVERRIDE; //called when a specific effect is set to stacks
 	void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) OVERRIDE;
 	void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) OVERRIDE; //called by engine when battle starts; side=0 - left, side=1 - right
 	void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom) OVERRIDE; //called when stacks are healed / resurrected
-	void battleNewStackAppeared(int stackID) OVERRIDE; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
+	void battleNewStackAppeared(const CStack * stack) OVERRIDE; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
 	void battleObstaclesRemoved(const std::set<si32> & removedObstacles) OVERRIDE; //called when a certain set  of obstacles is removed from batlefield; IDs of them are given
 	void battleCatapultAttacked(const CatapultAttack & ca) OVERRIDE; //called when catapult makes an attack
 	void battleStacksRemoved(const BattleStacksRemoved & bsr) OVERRIDE; //called when certain stack is completely removed from battlefield

+ 1 - 1
client/Client.cpp

@@ -116,7 +116,7 @@ void CClient::waitForMoveAndSend(int color)
 {
 	try
 	{
-		BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
+		BattleAction ba = playerint[color]->activeStack(gs->curB->getStack(gs->curB->activeStack, false));
 		*serv << &MakeAction(ba);
 		return;
 	}HANDLE_EXCEPTION

+ 5 - 3
client/GUIClasses.cpp

@@ -2304,7 +2304,9 @@ CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<u
 	cb = callback;
 	for(int i=0;i<skills.size();i++)
 	{
-		comps.push_back(new CSelectableComponent(SComponent::secskill44,skills[i],hero->getSecSkillLevel(skills[i])+1,boost::bind(&CLevelWindow::selectionChanged,this,i)));
+		comps.push_back(new CSelectableComponent(SComponent::secskill44, skills[i],
+			hero->getSecSkillLevel( static_cast<CGHeroInstance::SecondarySkill>(skills[i]) )+1,
+			boost::bind(&CLevelWindow::selectionChanged,this,i)));
 		comps.back()->assignedKeys.insert(SDLK_1 + i);
 	}
 	SDL_Surface *hhlp = BitmapHandler::loadBitmap("LVLUPBKG.bmp");
@@ -3734,7 +3736,7 @@ void CAltarWindow::calcTotalExp()
 			val += valOfArt * arts->artifactsOnAltar.count(*i);
 		}
 	}
-	val *=(100+hero->getSecSkillLevel(21)*5)/100.0f;
+	val *=(100+hero->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 	expOnAltar->setTxt(boost::lexical_cast<std::string>(val));
 }
 
@@ -5866,7 +5868,7 @@ void CUniversityWindow::CItem::hover(bool on)
 
 int CUniversityWindow::CItem::state()
 {
-	if (parent->hero->getSecSkillLevel(ID))//hero know this skill
+	if (parent->hero->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(ID)))//hero know this skill
 		return 1;
 	if (parent->hero->secSkills.size() >= SKILL_PER_HERO)//can't learn more skills
 		return 0;

+ 2 - 2
client/NetPacksClient.cpp

@@ -575,9 +575,9 @@ void BattleSpellCast::applyCl( CClient *cl )
 	if(id >= 66 && id <= 69) //elemental summoning
 	{
 		if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
-			cl->playerint[GS(cl)->curB->side1]->battleNewStackAppeared(GS(cl)->curB->stacks.size() - 1);
+			cl->playerint[GS(cl)->curB->side1]->battleNewStackAppeared(GS(cl)->curB->stacks[GS(cl)->curB->stacks.size() - 1]);
 		if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
-			cl->playerint[GS(cl)->curB->side2]->battleNewStackAppeared(GS(cl)->curB->stacks.size() - 1);
+			cl->playerint[GS(cl)->curB->side2]->battleNewStackAppeared(GS(cl)->curB->stacks[GS(cl)->curB->stacks.size() - 1]);
 	}
 }
 

+ 1 - 0
global.h

@@ -16,6 +16,7 @@ typedef boost::int16_t si16; //signed int 16 bits (2 bytes)
 typedef boost::int8_t si8; //signed int 8 bits (1 byte)
 typedef si64 expType;
 typedef ui16 spelltype;
+typedef ui16 THex; //for battle stacks' positions
 #include "int3.h"
 #include <map>
 #include <vector>

+ 5 - 5
lib/CGameState.cpp

@@ -393,7 +393,7 @@ const CStack * BattleInfo::getStack(int stackID, bool onlyAlive) const
 	return const_cast<BattleInfo * const>(this)->getStack(stackID, onlyAlive);
 }
 
-CStack * BattleInfo::getStackT(int tileID, bool onlyAlive)
+CStack * BattleInfo::getStackT(THex tileID, bool onlyAlive)
 {
 	for(unsigned int g=0; g<stacks.size(); ++g)
 	{
@@ -410,7 +410,7 @@ CStack * BattleInfo::getStackT(int tileID, bool onlyAlive)
 	return NULL;
 }
 
-const CStack * BattleInfo::getStackT(int tileID, bool onlyAlive) const
+const CStack * BattleInfo::getStackT(THex tileID, bool onlyAlive) const
 {
 	return const_cast<BattleInfo * const>(this)->getStackT(tileID, onlyAlive);
 }
@@ -639,7 +639,7 @@ bool BattleInfo::isStackBlocked(int ID)
 	return false;
 }
 
-signed char BattleInfo::mutualPosition(int hex1, int hex2)
+signed char BattleInfo::mutualPosition(THex hex1, THex hex2)
 {
 	if(hex2 == hex1 - ( (hex1/17)%2 ? 18 : 17 )) //top left
 		return 0;
@@ -1864,7 +1864,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 					}
 					break;
 				case 6: //sec skills
-					hero->setSecSkillLevel(curBonus.info2, curBonus.info3, true);
+					hero->setSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(curBonus.info2), curBonus.info3, true);
 					break;
 				}
 			}
@@ -4789,7 +4789,7 @@ si8 BattleInfo::canTeleportTo(int stackID, int destHex, int telportLevel)
 // 	}
 // }
 
-si8 BattleInfo::getDistance( int hex1, int hex2 )
+si8 BattleInfo::getDistance( THex hex1, THex hex2 )
 {
 	int xDst = std::abs(hex1 % BFIELD_WIDTH - hex2 % BFIELD_WIDTH),
 		yDst = std::abs(hex1 / BFIELD_WIDTH - hex2 / BFIELD_WIDTH);

+ 5 - 5
lib/CGameState.h

@@ -229,8 +229,8 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
 	CStack * getStack(int stackID, bool onlyAlive = true);
 	const CStack * getStack(int stackID, bool onlyAlive = true) const;
-	CStack * getStackT(int tileID, bool onlyAlive = true);
-	const CStack * getStackT(int tileID, bool onlyAlive = true) const;
+	CStack * getStackT(THex tileID, bool onlyAlive = true);
+	const CStack * getStackT(THex tileID, bool onlyAlive = true) const;
 	void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<int> & occupyable, bool flying, int stackToOmmit=-1) const; //send pointer to at least 187 allocated bytes
 	static bool isAccessible(int hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
 	void makeBFS(int start, bool*accessibility, int *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
@@ -238,9 +238,9 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	std::vector<int> getAccessibility(int stackID, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range)
 
 	bool isStackBlocked(int ID); //returns true if there is neighboring enemy stack
-	static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
+	static signed char mutualPosition(THex hex1, THex hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
 	static std::vector<int> neighbouringTiles(int hex);
-	static si8 getDistance(int hex1, int hex2); //returns distance between given hexes
+	static si8 getDistance(THex hex1, THex hex2); //returns distance between given hexes
 	ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting)
 	std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
@@ -272,7 +272,7 @@ public:
 	ui32 firstHPleft; //HP of first creature in stack
 	ui8 owner, slot;  //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
 	ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
-	si16 position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
+	THex position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
 	ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
 	si16 shots; //how many shots left
 

+ 28 - 25
lib/CObjectHandler.cpp

@@ -591,7 +591,7 @@ unsigned int CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainT
 	else 
 	{
 		ret = type->heroClass->terrCosts[from.tertype];
-		ret = std::max(ret - 25*unsigned(getSecSkillLevel(0)), 100u); //reduce 25% of terrain penalty for each pathfinding level
+		ret = std::max(ret - 25*unsigned(getSecSkillLevel(CGHeroInstance::PATHFINDING)), 100u); //reduce 25% of terrain penalty for each pathfinding level
 	}
 	return ret;
 }
@@ -660,7 +660,7 @@ int CGHeroInstance::getPrimSkillLevel(int id) const
 	return ret;
 }
 
-ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
+ui8 CGHeroInstance::getSecSkillLevel(SecondarySkill skill) const
 {
 	for(size_t i=0; i < secSkills.size(); ++i)
 		if(secSkills[i].first==ID)
@@ -668,7 +668,7 @@ ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
 	return 0;
 }
 
-void CGHeroInstance::setSecSkillLevel(int which, int val, bool abs)
+void CGHeroInstance::setSecSkillLevel(SecondarySkill which, int val, bool abs)
 {
 	if(getSecSkillLevel(which) == 0)
 	{
@@ -1277,7 +1277,9 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSc
 #define TRY_SCHOOL(schoolName, schoolMechanicsId, schoolOutId)	\
 	if(spell-> schoolName)									\
 	{															\
-		int thisSchool = std::max<int>(getSecSkillLevel(14 + (schoolMechanicsId)), valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << (schoolMechanicsId))); \
+		int thisSchool = std::max<int>(getSecSkillLevel( \
+			static_cast<CGHeroInstance::SecondarySkill>(14 + (schoolMechanicsId))), \
+			valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << (schoolMechanicsId))); \
 		if(thisSchool > skill)									\
 		{														\
 			skill = thisSchool;									\
@@ -1328,7 +1330,7 @@ bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
  */
 CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &battleResult) const
 {
-	const ui8 necromancyLevel = getSecSkillLevel(12);
+	const ui8 necromancyLevel = getSecSkillLevel(CGHeroInstance::NECROMANCY);
 
 	// Hero knows necromancy.
 	if (necromancyLevel > 0) 
@@ -1405,7 +1407,7 @@ int3 CGHeroInstance::getSightCenter() const
 
 int CGHeroInstance::getSightRadious() const
 {
-	return 5 + getSecSkillLevel(3) + valOfBonuses(Bonus::SIGHT_RADIOUS); //default + scouting
+	return 5 + getSecSkillLevel(CGHeroInstance::SCOUTING) + valOfBonuses(Bonus::SIGHT_RADIOUS); //default + scouting
 }
 
 si32 CGHeroInstance::manaRegain() const
@@ -2515,7 +2517,7 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 		case 100: //give exp
 			{
 				const CGHeroInstance *h = cb->getHero(heroID);
-				val = val*(100+h->getSecSkillLevel(21)*5)/100.0f;
+				val = val*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 				InfoWindow iw;
 				iw.soundID = sound;
 				iw.components.push_back(Component(id,subid,val,0));
@@ -2582,7 +2584,7 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 		case 41://library of enlightenment
 			{
 				const CGHeroInstance *h = cb->getHero(heroID);
-				if(h->level  <  10 - 2*h->getSecSkillLevel(4)) //not enough level
+				if(h->level  <  10 - 2*h->getSecSkillLevel(CGHeroInstance::DIPLOMACY)) //not enough level
 				{
 					InfoWindow iw;
 					iw.soundID = sound;
@@ -2810,7 +2812,7 @@ void CTownBonus::onHeroVisit (const CGHeroInstance * h) const
 						break;
 					case 5://academy of battle scholars
 						what = 4;
-						val = 1000*(100+h->getSecSkillLevel(21)*5)/100.0f;
+						val = 1000*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 						mid = 583;
 						iw.components.push_back (Component(Component::EXPERIENCE, 0, val, 0));
 						break;
@@ -3033,12 +3035,12 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
 			sympathy++;
 		
 
-		int charisma = factor + h->getSecSkillLevel(4) + sympathy;
+		int charisma = factor + h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy;
 		if(charisma >= character) //creatures might join...
 		{
-			if(h->getSecSkillLevel(4) + sympathy + 1 >= character)
+			if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) + sympathy + 1 >= character)
 				return 0; //join for free
-			else if(h->getSecSkillLevel(4) * 2  +  sympathy  +  1 >= character)
+			else if(h->getSecSkillLevel(CGHeroInstance::DIPLOMACY) * 2  +  sympathy  +  1 >= character)
 				return VLC->creh->creatures[subID]->cost[6] * getStackCount(0); //join for gold
 		}
 	}
@@ -3864,7 +3866,7 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
 				sd.player = h->tempOwner;
 				sd.text << std::pair<ui8,ui32>(11,146);
 				sd.components.push_back(Component(2,6,val1,0));
-				int expVal = val2*(100+h->getSecSkillLevel(21)*5)/100.0f;
+				int expVal = val2*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 				sd.components.push_back(Component(5,0,expVal, 0));
 				sd.soundID = soundBase::chest;
 				boost::function<void(ui32)> fun = boost::bind(&CGPickable::chosen,this,_1,h->id);
@@ -3885,7 +3887,7 @@ void CGPickable::chosen( int which, int heroID ) const
 		cb->giveResource(cb->getOwner(heroID),6,val1);
 		break;
 	case 2: //player pick exp
-		cb->changePrimSkill(heroID, 4, val2*(100+h->getSecSkillLevel(21)*5)/100.0f);
+		cb->changePrimSkill(heroID, 4, val2*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f);
 		break;
 	default:
 		throw std::string("Unhandled treasure choice");
@@ -4322,7 +4324,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
 			
 			switch (rewardType)
 			{
-				case 1: bd.components.push_back (Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(21)*5)/100.0f, 0));
+				case 1: bd.components.push_back (Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f, 0));
 					break;
 				case 2: bd.components.push_back (Component (Component::PRIM_SKILL, 5, rVal, 0));
 					break;
@@ -4421,7 +4423,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 	{
 		case 1: //experience
 		{
-			int expVal = rVal*(100+h->getSecSkillLevel(21)*5)/100.0f;
+			int expVal = rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 			cb->changePrimSkill(h->id, 4, expVal, false);
 			break;
 		}
@@ -4502,7 +4504,7 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
 	if(!hasVisited(h->tempOwner))
 		cb->setObjProperty(id,10,h->tempOwner);
 
-	if(h->getSecSkillLevel(ability)) //you alredy know this skill
+	if(h->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(ability))) //you alredy know this skill
 	{
 		iw.text << std::pair<ui8,ui32>(11,172);
 		iw.text.addReplacement(MetaString::SEC_SKILL_NAME, ability);
@@ -4531,7 +4533,7 @@ const std::string & CGWitchHut::getHoverText() const
 		hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s)
 		boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]);
 		const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
-		if(h && h->getSecSkillLevel(ability)) //hero knows that ability
+		if(h && h->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(ability))) //hero knows that ability
 			hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned)
 	}
 	return hoverName;
@@ -4874,7 +4876,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 
 	if(gainedExp || changesPrimSkill || abilities.size())
 	{
-		expType expVal = gainedExp*(100+h->getSecSkillLevel(21)*5)/100.0f;
+		expType expVal = gainedExp*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 		getText(iw,afterBattle,175,h);
 
 		if(expVal)
@@ -4899,7 +4901,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 		//give sec skills
 		for(int i=0; i<abilities.size(); i++)
 		{
-			int curLev = h->getSecSkillLevel(abilities[i]);
+			int curLev = h->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(abilities[i]));
 
 			if( (curLev  &&  curLev < abilityLevels[i])
 				|| (h->secSkills.size() < SKILL_PER_HERO) )
@@ -4917,7 +4919,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 		std::vector<ConstTransitivePtr<CSpell> > * sp = &VLC->spellh->spells;
 		for(std::vector<si32>::const_iterator i=spells.begin(); i != spells.end(); i++)
 		{
-			if ((*sp)[*i]->level <= h->getSecSkillLevel(7) + 2) //enough wisdom
+			if ((*sp)[*i]->level <= h->getSecSkillLevel(CGHeroInstance::WISDOM) + 2) //enough wisdom
 			{
 				iw.components.push_back(Component(Component::SPELL,*i,0,0));
 				spellsToGive.insert(*i);
@@ -5156,7 +5158,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		iw.text.addTxt(MetaString::ADVOB_TXT,131);
 	}
-	else if(ID == 90  &&  !h->getSecSkillLevel(7)) //it's third level spell and hero doesn't have wisdom
+	else if(ID == 90  &&  !h->getSecSkillLevel(CGHeroInstance::WISDOM)) //it's third level spell and hero doesn't have wisdom
 	{
 		iw.text.addTxt(MetaString::ADVOB_TXT,130);
 	}
@@ -5243,10 +5245,11 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
 	int type = bonusType;
 	int bid = bonusID;
 	//check if the bonus if applicable, if not - give primary skill (always possible)
-	int ssl = h->getSecSkillLevel(bid); //current sec skill level, used if bonusType == 1
+	int ssl = h->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(bid)); //current sec skill level, used if bonusType == 1
 	if((type == 1
 			&& ((ssl == 3)  ||  (!ssl  &&  h->secSkills.size() == SKILL_PER_HERO))) ////hero already has expert level in the skill or (don't know skill and doesn't have free slot)
-		|| (type == 2  &&  (!h->getArt(17) || vstd::contains(h->spells, (ui32) bid) || (VLC->spellh->spells[bid]->level > h->getSecSkillLevel(7) + 2)
+		|| (type == 2  &&  (!h->getArt(17) || vstd::contains(h->spells, (ui32) bid)
+		|| (VLC->spellh->spells[bid]->level > h->getSecSkillLevel(CGHeroInstance::WISDOM) + 2)
 		))) //hero doesn't have a spellbook or already knows the spell or doesn't have Wisdom
 	{
 		type = 0;
@@ -5976,7 +5979,7 @@ void CGPyramid::endBattle (const CGHeroInstance *h, const BattleResult *result)
 		iw.text.addTxt (MetaString::SPELL_NAME, spell);
 		if (!h->getArt(17))						
 			iw.text.addTxt (MetaString::ADVOB_TXT, 109); //no spellbook
-		else if (h->getSecSkillLevel(7) < 3)	
+		else if (h->getSecSkillLevel(CGHeroInstance::WISDOM) < 3)	
 			iw.text.addTxt (MetaString::ADVOB_TXT, 108); //no expert Wisdom
 		else
 		{

+ 9 - 2
lib/CObjectHandler.h

@@ -246,6 +246,13 @@ public:
 class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator
 {
 public:
+	enum SecondarySkill
+	{
+		PATHFINDING = 0, ARCHERY, LOGISTICS, SCOUTING, DIPLOMACY, NAVIGATION, LEADERSHIP, WISDOM, MYSTICISM,
+		LUCK, BALLISTICS, EAGLE_EYE, NECROMANCY, ESTATES, FIRE_MAGIC, AIR_MAGIC, WATER_MAGIC, EARTH_MAGIC,
+		SCHOLAR, TACTICS, ARTILLERY, LEARNING, OFFENCE, ARMORER, INTELLIGENCE, SORCERY, RESISTANCE,
+		FIRST_AID
+	};
 	//////////////////////////////////////////////////////////////////////////
 
 	ui8 moveDir; //format:	123
@@ -338,8 +345,8 @@ public:
 	int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered
 	TModDescr getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
 	int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
-	ui8 getSecSkillLevel(const int & ID) const; //0 - no skill
-	void setSecSkillLevel(int which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
+	ui8 getSecSkillLevel(SecondarySkill skill) const; //0 - no skill
+	void setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
 
 	int maxMovePoints(bool onLand) const;
 

+ 1 - 1
lib/NetPacksLib.cpp

@@ -77,7 +77,7 @@ DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs )
 DLL_EXPORT void SetSecSkill::applyGs( CGameState *gs )
 {
 	CGHeroInstance *hero = gs->getHero(id);
-	hero->setSecSkillLevel(which, val, abs);
+	hero->setSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(which), val, abs);
 }
 
 DLL_EXPORT void HeroVisitCastle::applyGs( CGameState *gs )

+ 16 - 16
server/CGameHandler.cpp

@@ -332,9 +332,9 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 	//end battle, remove all info, free memory
 	giveExp(*battleResult.data);
 	if (hero1)
-		battleResult.data->exp[0] *= (100+hero1->getSecSkillLevel(21)*5)/100.0f;//sholar skill
+		battleResult.data->exp[0] *= (100+hero1->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;//sholar skill
 	if (hero2)
-		battleResult.data->exp[1] *= (100+hero2->getSecSkillLevel(21)*5)/100.0f;
+		battleResult.data->exp[1] *= (100+hero2->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
 
 	ui8 sides[2];
 	sides[0] = gs->curB->side1;
@@ -1201,7 +1201,7 @@ void CGameHandler::giveSpells( const CGTownInstance *t, const CGHeroInstance *h
 	ChangeSpells cs;
 	cs.hid = h->id;
 	cs.learn = true;
-	for(int i=0; i<std::min(t->mageGuildLevel(),h->getSecSkillLevel(7)+2);i++)
+	for(int i=0; i<std::min(t->mageGuildLevel(),h->getSecSkillLevel(CGHeroInstance::WISDOM)+2);i++)
 	{
 		if (t->subID == 8 && vstd::contains(t->builtBuildings, 26)) //Aurora Borealis
 		{
@@ -1842,18 +1842,18 @@ void CGameHandler::useScholarSkill(si32 fromHero, si32 toHero)
 	const CGHeroInstance * h1 = getHero(fromHero);
 	const CGHeroInstance * h2 = getHero(toHero);
 
-	if ( h1->getSecSkillLevel(18) < h2->getSecSkillLevel(18) )
+	if ( h1->getSecSkillLevel(CGHeroInstance::SCHOLAR) < h2->getSecSkillLevel(CGHeroInstance::SCHOLAR) )
 	{
 		std::swap (h1,h2);//1st hero need to have higher scholar level for correct message
 		std::swap(fromHero, toHero);
 	}
 
-	int ScholarLevel = h1->getSecSkillLevel(18);//heroes can trade up to this level
+	int ScholarLevel = h1->getSecSkillLevel(CGHeroInstance::SCHOLAR);//heroes can trade up to this level
 	if (!ScholarLevel || !vstd::contains(h1->artifWorn,17) || !vstd::contains(h2->artifWorn,17) )
 		return;//no scholar skill or no spellbook
 
-	int h1Lvl = std::min(ScholarLevel+1, h1->getSecSkillLevel(7)+2),
-	    h2Lvl = std::min(ScholarLevel+1, h2->getSecSkillLevel(7)+2);//heroes can receive this levels
+	int h1Lvl = std::min(ScholarLevel+1, h1->getSecSkillLevel(CGHeroInstance::WISDOM)+2),
+	    h2Lvl = std::min(ScholarLevel+1, h2->getSecSkillLevel(CGHeroInstance::WISDOM)+2);//heroes can receive this levels
 
 	ChangeSpells cs1;
 	cs1.learn = true;
@@ -2855,7 +2855,7 @@ bool CGameHandler::buySecSkill( const IMarket *m, const CGHeroInstance *h, int s
 	if (!h)
 		COMPLAIN_RET("You need hero to buy a skill!");
 		
-	if (h->getSecSkillLevel(skill))
+	if (h->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(skill)))
 		COMPLAIN_RET("Hero already know this skill");
 		
 	if (h->secSkills.size() >= SKILL_PER_HERO)//can't learn more skills
@@ -3258,7 +3258,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		{
 			sendAndApply(&StartAction(ba));
 			const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
-			CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(10)]; //ballistics
+			CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(CGHeroInstance::BALLISTICS)];
 			
 			int attackedPart = gs->curB->hexToWallPart(ba.destinationTile);
 			if(attackedPart == -1)
@@ -4637,7 +4637,7 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
 	int dump, exp;
 	market->getOffer(crid, 0, dump, exp, CREATURE_EXP);
 	exp *= count;
-	changePrimSkill(hero->id, 4, exp*(100+hero->getSecSkillLevel(21)*5)/100.0f);
+	changePrimSkill(hero->id, 4, exp*(100+hero->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f);
 
 	return true;
 }
@@ -4804,8 +4804,8 @@ void CGameHandler::runBattle()
 
 	//tactic round
 	{
-		if( (gs->curB->heroes[0] && gs->curB->heroes[0]->getSecSkillLevel(19)>0) || 
-			( gs->curB->heroes[1] && gs->curB->heroes[1]->getSecSkillLevel(19)>0)  )//someone has tactics
+		if( (gs->curB->heroes[0] && gs->curB->heroes[0]->getSecSkillLevel(CGHeroInstance::TACTICS)>0) || 
+			( gs->curB->heroes[1] && gs->curB->heroes[1]->getSecSkillLevel(CGHeroInstance::TACTICS)>0)  )//someone has tactics
 		{
 			//TODO: tactic round (round -1)
 			NEW_ROUND;
@@ -4891,8 +4891,8 @@ void CGameHandler::runBattle()
 
 			const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
 
-			if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics
-				|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
+			if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::BALLISTICS) == 0)) //arrow turret, hero has no ballistics
+				|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::ARTILLERY) == 0))) //ballista, hero has no artillery
 			{
 				BattleAction attack;
 				attack.actionType = BattleAction::SHOOT;
@@ -4914,7 +4914,7 @@ void CGameHandler::runBattle()
 				continue;
 			}
 
-			if(next->getCreature()->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
+			if(next->getCreature()->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::BALLISTICS) == 0)) //catapult, hero has no ballistics
 			{
 				BattleAction attack;
 				static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
@@ -4929,7 +4929,7 @@ void CGameHandler::runBattle()
 				continue;
 			}
 
-			if(next->getCreature()->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
+			if(next->getCreature()->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::FIRST_AID) == 0)) //first aid tent, hero has no first aid
 			{
 				BattleAction heal;