浏览代码

* amounts of units taking actions / being an object of actions won't be shown until action ends
* provisional support for "Save" button in System Options Window
* forbidden buildings will be shown as forbidden, even if there are no res / other conditions are not fulfilled
* improved damage calculation formula
* several minor improvements

Michał W. Urbańczyk 16 年之前
父节点
当前提交
42773e67f2
共有 13 个文件被更改,包括 128 次插入63 次删除
  1. 26 16
      CBattleInterface.cpp
  2. 5 0
      CCallback.cpp
  3. 2 0
      CCallback.h
  4. 1 1
      CGameInterface.h
  5. 46 33
      CGameState.cpp
  6. 1 1
      CMessage.cpp
  7. 27 4
      CPlayerInterface.cpp
  8. 5 4
      CPlayerInterface.h
  9. 3 1
      CPreGame.cpp
  10. 9 1
      hch/CCreatureHandler.cpp
  11. 1 1
      hch/CObjectHandler.cpp
  12. 1 1
      lib/NetPacks.h
  13. 1 0
      server/CGameHandler.cpp

+ 26 - 16
CBattleInterface.cpp

@@ -485,19 +485,22 @@ void CBattleInterface::show(SDL_Surface * to)
 	{
 		for(size_t v=0; v<stackAliveByHex[b].size(); ++v)
 		{
-			int animType = creAnims[stackAliveByHex[b][v]]->getType();
+			int curStackID = stackAliveByHex[b][v];
+			const CStack &curStack = stacks[curStackID];
+			int animType = creAnims[curStackID]->getType();
 			bool incrementFrame = (animCount%(4/animSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
+
 			if(animType == 2)
 			{
-				if(standingFrame.find(stackAliveByHex[b][v])!=standingFrame.end())
+				if(standingFrame.find(curStackID)!=standingFrame.end())
 				{
 					incrementFrame = (animCount%(8/animSpeed)==0);
 					if(incrementFrame)
 					{
-						++standingFrame[stackAliveByHex[b][v]];
-						if(standingFrame[stackAliveByHex[b][v]] == creAnims[stackAliveByHex[b][v]]->framesInGroup(2))
+						++standingFrame[curStackID];
+						if(standingFrame[curStackID] == creAnims[curStackID]->framesInGroup(2))
 						{
-							standingFrame.erase(standingFrame.find(stackAliveByHex[b][v]));
+							standingFrame.erase(standingFrame.find(curStackID));
 						}
 					}
 				}
@@ -505,29 +508,36 @@ void CBattleInterface::show(SDL_Surface * to)
 				{
 					if((rand()%50) == 0)
 					{
-						standingFrame.insert(std::make_pair(stackAliveByHex[b][v], 0));
+						standingFrame.insert(std::make_pair(curStackID, 0));
 					}
 				}
 			}
 
-			creAnims[stackAliveByHex[b][v]]->nextFrame(to, creAnims[stackAliveByHex[b][v]]->pos.x + pos.x, creAnims[stackAliveByHex[b][v]]->pos.y + pos.y, creDir[stackAliveByHex[b][v]], animCount, incrementFrame, stackAliveByHex[b][v]==activeStack, stackAliveByHex[b][v]==mouseHoveredStack); //increment always when moving, never if stack died
+			creAnims[curStackID]->nextFrame(to, creAnims[curStackID]->pos.x + pos.x, creAnims[curStackID]->pos.y + pos.y, creDir[curStackID], animCount, incrementFrame, curStackID==activeStack, curStackID==mouseHoveredStack); //increment always when moving, never if stack died
+
 			//printing amount
-			if(stacks[stackAliveByHex[b][v]].amount > 0) //don't print if stack is not alive
+			if(curStack.amount > 0 //don't print if stack is not alive
+				&& !LOCPLINT->curAction
+					|| (LOCPLINT->curAction->stackNumber != curStackID //don't print if stack is currently taking an action
+						&& (LOCPLINT->curAction->actionType != 6  ||  curStack.position != LOCPLINT->curAction->additionalInfo) //nor if it's an object of attack
+						&& (LOCPLINT->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action
+					)
+			)
 			{
-				int xAdd = stacks[stackAliveByHex[b][v]].attackerOwned ? 220 : 202;
+				int xAdd = curStack.attackerOwned ? 220 : 202;
 
 				//blitting amoutn background box
 				SDL_Surface *amountBG = NULL;
-				if(stacks[stackAliveByHex[b][v]].effects.size() == 0)
+				if(curStack.effects.size() == 0)
 				{
 					amountBG = amountNormal;
 				}
 				else
 				{
 					int pos=0; //determining total positiveness of effects
-					for(int c=0; c<stacks[stackAliveByHex[b][v]].effects.size(); ++c)
+					for(int c=0; c<curStack.effects.size(); ++c)
 					{
-						pos += CGI->spellh->spells[ stacks[stackAliveByHex[b][v]].effects[c].id ].positiveness;
+						pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
 					}
 					if(pos > 0)
 					{
@@ -542,14 +552,14 @@ void CBattleInterface::show(SDL_Surface * to)
 						amountBG = amountEffNeutral;
 					}
 				}
-				SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackAliveByHex[b][v]]->pos.x + xAdd + pos.x, creAnims[stackAliveByHex[b][v]]->pos.y + 260 + pos.y));
+				SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[curStackID]->pos.x + xAdd + pos.x, creAnims[curStackID]->pos.y + 260 + pos.y));
 				//blitting amount
 				std::stringstream ss;
-				ss<<stacks[stackAliveByHex[b][v]].amount;
+				ss<<curStack.amount;
 				CSDL_Ext::printAtMiddleWB(
 					ss.str(),
-					creAnims[stackAliveByHex[b][v]]->pos.x + xAdd + 14 + pos.x,
-					creAnims[stackAliveByHex[b][v]]->pos.y + 260 + 4 + pos.y,
+					creAnims[curStackID]->pos.x + xAdd + 14 + pos.x,
+					creAnims[curStackID]->pos.y + 260 + 4 + pos.y,
 					GEOR13,
 					20,
 					zwykly,

+ 5 - 0
CCallback.cpp

@@ -698,4 +698,9 @@ CPath * CCallback::getPath( int3 src, int3 dest, const CGHeroInstance * hero )
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->getPath(src,dest,hero);
+}
+
+void CCallback::save( const std::string &fname )
+{
+	cl->save(fname);
 }

+ 2 - 0
CCallback.h

@@ -47,6 +47,7 @@ public:
 	virtual void setFormation(const CGHeroInstance * hero, bool tight)=0;
 	virtual void setSelection(const CArmedInstance * obj)=0;
 	virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0;
+	virtual void save(const std::string &fname) = 0;
 
 //get info
 	virtual bool verifyPath(CPath * path, bool blockSea)const =0;
@@ -136,6 +137,7 @@ public:
 	void setFormation(const CGHeroInstance * hero, bool tight);
 	void setSelection(const CArmedInstance * obj);
 	void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero);
+	void save(const std::string &fname);
 
 //get info
 	bool verifyPath(CPath * path, bool blockSea) const;

+ 1 - 1
CGameInterface.h

@@ -62,7 +62,7 @@ public:
 	virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
 	virtual void init(ICallback * CB){};
 	virtual void receivedResource(int type, int val){};
-	virtual void showInfoDialog(std::string &text, const std::vector<Component*> &components){};
+	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components){};
 	virtual void showSelDialog(std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	virtual void showYesNoDialog(std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	virtual void tileHidden(const std::set<int3> &pos){};

+ 46 - 33
CGameState.cpp

@@ -1455,12 +1455,6 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 {
 	int ret = 7; //allowed by default
 
-	//can we build it?
-	if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
-		ret = 2; //forbidden
-	else if(t->builded >= MAX_BUILDING_PER_TURN)
-		ret = 5; //building limit
-
 	//checking resources
 	CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
 	for(int res=0;res<7;res++) //TODO: support custom amount of resources
@@ -1478,6 +1472,12 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 			ret = 8; //lack of requirements - cannot build
 	}
 
+	//can we build it?
+	if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
+		ret = 2; //forbidden
+	else if(t->builded >= MAX_BUILDING_PER_TURN)
+		ret = 5; //building limit
+
 	if(ID == 13) //capitol
 	{
 		for(int in = 0; in < map->towns.size(); in++)
@@ -1672,17 +1672,22 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
 
 int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
 {
-	int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0);
+	int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0),
+		defenderDefenseBonus = defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0),
+		attackDefenseBonus = 0,
+		minDmg = attacker->creature->damageMin * attacker->amount, 
+		maxDmg = attacker->creature->damageMax * attacker->amount;
+
+	//calculating total attack/defense skills modifier
 	if(attacker->getEffect(56)) //frenzy for attacker
 	{
 		attackerAttackBonus += (VLC->spellh->spells[attacker->getEffect(56)->id].powers[attacker->getEffect(56)->level]/100.0) *(attacker->creature->defence + (attackerHero ? attackerHero->getPrimSkillLevel(1) : 0));
 	}
-	int defenderDefenseBonus = defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0);
 	if(defender->getEffect(56)) //frenzy for defender
 	{
 		defenderDefenseBonus = 0;
 	}
-	int attackDefenseBonus = attackerAttackBonus - defenderDefenseBonus;
+	attackDefenseBonus = attackerAttackBonus - defenderDefenseBonus;
 	if(defender->getEffect(48)) //defender's prayer handling
 	{
 		attackDefenseBonus -= VLC->spellh->spells[defender->getEffect(48)->id].powers[defender->getEffect(48)->level];
@@ -1703,27 +1708,10 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 	{
 		attackDefenseBonus += VLC->spellh->spells[attacker->getEffect(43)->id].powers[attacker->getEffect(43)->level];
 	}
-	int damageBase = 0;
-	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
-	{
-		damageBase = attacker->creature->damageMin;
-		damageBase -= VLC->spellh->spells[attacker->getEffect(42)->id].powers[attacker->getEffect(42)->level];
-	}
-	else if(attacker->getEffect(41)) //bless handling
-	{
-		damageBase = attacker->creature->damageMax;
-		damageBase += VLC->spellh->spells[attacker->getEffect(41)->id].powers[attacker->getEffect(41)->level];
-	}
-	else if(attacker->creature->damageMax == attacker->creature->damageMin) //constant damage
-	{
-		damageBase = attacker->creature->damageMin;
-	}
-	else
-	{
-		damageBase = rand()%(attacker->creature->damageMax - attacker->creature->damageMin) + attacker->creature->damageMin + 1;
-	}
 
 	float dmgBonusMultiplier = 1.0f;
+
+	//bonus from attack/defense skills
 	if(attackDefenseBonus < 0) //decreasing dmg
 	{
 		if(0.02f * (-attackDefenseBonus) > 0.3f)
@@ -1746,6 +1734,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 			dmgBonusMultiplier += 0.05f * attackDefenseBonus;
 		}
 	}
+
 	//handling secondary abilities
 	if(attackerHero)
 	{
@@ -1766,7 +1755,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		}
 		else
 		{
-			switch(attackerHero->getSecSkillLevel(22)) //offence
+			switch(attackerHero->getSecSkillLevel(22)) //offense
 			{
 			case 1: //basic
 				dmgBonusMultiplier *= 1.1f;
@@ -1782,7 +1771,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 	}
 	if(defendingHero)
 	{
-		switch(defendingHero->getSecSkillLevel(23)) //armourer
+		switch(defendingHero->getSecSkillLevel(23)) //armorer
 		{
 		case 1: //basic
 			dmgBonusMultiplier *= 0.95f;
@@ -1803,20 +1792,44 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		else //adv or expert
 			dmgBonusMultiplier *= 0.7f;
 	}
-	if(shooting && defender->getEffect(28)) //air shield
+	else if(shooting && defender->getEffect(28)) //air shield
 	{
 		if(defender->getEffect(28)->level<=1) //none or basic
 			dmgBonusMultiplier *= 0.75f;
 		else //adv or expert
 			dmgBonusMultiplier *= 0.5f;
 	}
-	if(attacker->getEffect(42)) //curse, second part of handling
+	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	{
 		if(attacker->getEffect(42)->level>=2) //adv or expert
 			dmgBonusMultiplier *= 0.8f;
 	}
 
-	return int(  (float)damageBase * (float)attacker->amount * dmgBonusMultiplier  );
+
+
+	minDmg *= dmgBonusMultiplier;
+	maxDmg *= dmgBonusMultiplier;
+
+	if(attacker->getEffect(42)) //curse handling (rest)
+	{
+		minDmg -= VLC->spellh->spells[attacker->getEffect(42)->id].powers[attacker->getEffect(42)->level];
+		return minDmg;
+	}
+	else if(attacker->getEffect(41)) //bless handling
+	{
+		maxDmg += VLC->spellh->spells[attacker->getEffect(41)->id].powers[attacker->getEffect(41)->level];
+		return maxDmg;
+	}
+	else
+	{
+		if(minDmg != maxDmg)
+			return minDmg  +  rand() % (maxDmg - minDmg + 1);
+		else
+			return minDmg;
+	}
+
+	tlog1 << "We are too far in calculateDmg...\n";
+	return -1;
 }
 
 void BattleInfo::calculateCasualties( std::set<std::pair<ui32,si32> > *casualties )

+ 1 - 1
CMessage.cpp

@@ -279,7 +279,7 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_
 	curh += imgToBmp;
 	blitAt(bitmap,(ret->w/2)-(bitmap->w/2),curh,ret);
 	curh += bitmap->h + 5;
-	CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+(  ((*txtg)[0][0]->h) / 2  ),GEOR13,zwykly,ret);
+	CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+10,GEOR13,zwykly,ret);
 	delete tekst;
 	delete txtg;
 	return ret;

+ 27 - 4
CPlayerInterface.cpp

@@ -33,6 +33,7 @@
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/assign/std/vector.hpp> 
 #include <boost/assign/list_of.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/thread.hpp>
 #include <cmath>
 #include <queue>
@@ -1081,6 +1082,7 @@ void TimeInterested::deactivate()
 CPlayerInterface::CPlayerInterface(int Player, int serial)
 {
 	LOCPLINT = this;
+	curAction = NULL;
 	curint = NULL;
 	playerID=Player;
 	serialID=serial;
@@ -2374,7 +2376,7 @@ void CPlayerInterface::showComp(SComponent comp)
 	adventureInt->infoBar.showComp(&comp,4000);
 }
 
-void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<Component*> &components)
+void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component*> &components)
 {
 	std::vector<SComponent*> intComps;
 	for(int i=0;i<components.size();i++)
@@ -2382,7 +2384,7 @@ void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<Compo
 	showInfoDialog(text,intComps);
 }
 
-void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<SComponent*> & components)
+void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, bool deactivateCur)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 
@@ -2392,9 +2394,12 @@ void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<SComp
 
 	if(makingTurn && curint)
 	{
-		temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
 		showingDialog->set(true);
-		curint->deactivate(); //dezaktywacja starego interfejsu
+		if(deactivateCur)
+		{
+			temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
+			curint->deactivate(); //dezaktywacja starego interfejsu
+		}
 		temp->activate();
 		LOCPLINT->objsToBlit.push_back(temp);
 	}
@@ -4249,6 +4254,8 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface
 	CSDL_Ext::printAt(CGI->generaltexth->allTexts[577], 283, 217, GEOR16, zwykly, background); //spell book animation
 
 	//setting up buttons
+	save = new AdventureMapButton (CGI->generaltexth->zelp[321].first, CGI->generaltexth->zelp[321].second, boost::bind(&CSystemOptionsWindow::bsavef, this), 516, 354, "SOSAVE.DEF", SDLK_s);
+	std::swap(save->imgs[0][0], save->imgs[0][1]);
 	quitGame = new AdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), 405, 471, "soquit.def", SDLK_q);
 	std::swap(quitGame->imgs[0][0], quitGame->imgs[0][1]);
 	backToMap = new AdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), 516, 471, "soretrn.def", SDLK_RETURN);
@@ -4274,6 +4281,7 @@ CSystemOptionsWindow::~CSystemOptionsWindow()
 {
 	SDL_FreeSurface(background);
 
+	delete save;
 	delete quitGame;
 	delete backToMap;
 	delete heroMoveSpeed;
@@ -4303,8 +4311,21 @@ void CSystemOptionsWindow::breturnf()
 	LOCPLINT->curint->activate();
 }
 
+
+void CSystemOptionsWindow::bsavef()
+{
+	using namespace boost::posix_time;
+	std::ostringstream fnameStream;
+	fnameStream << second_clock::local_time();
+	std::string fname = fnameStream.str();
+	boost::algorithm::replace_all(fname,":","");
+	boost::algorithm::replace_all(fname," ","-");
+	LOCPLINT->showYesNoDialog("Do you want to save current game as " + fname, std::vector<SComponent*>(), boost::bind(&CCallback::save, LOCPLINT->cb, fname), boost::bind(&CSystemOptionsWindow::activate, this), false, false);
+}
+
 void CSystemOptionsWindow::activate()
 {
+	save->activate();
 	quitGame->activate();
 	backToMap->activate();
 	heroMoveSpeed->activate();
@@ -4313,6 +4334,7 @@ void CSystemOptionsWindow::activate()
 
 void CSystemOptionsWindow::deactivate()
 {
+	save->deactivate();
 	quitGame->deactivate();
 	backToMap->deactivate();
 	heroMoveSpeed->deactivate();
@@ -4327,6 +4349,7 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
 
 	SDL_BlitSurface(background, NULL, to, &pos);
 
+	save->show(to);
 	quitGame->show(to);
 	backToMap->show(to);
 	heroMoveSpeed->show(to);

+ 5 - 4
CPlayerInterface.h

@@ -538,7 +538,7 @@ public:
 	void heroMovePointsChanged(const CGHeroInstance * hero);
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void receivedResource(int type, int val);
-	void showInfoDialog(std::string &text, const std::vector<Component*> &components);
+	void showInfoDialog(const std::string &text, const std::vector<Component*> &components);
 	void showSelDialog(std::string &text, const std::vector<Component*> &components, ui32 askID);
 	void showYesNoDialog(std::string &text, const std::vector<Component*> &components, ui32 askID);
 	void tileHidden(const std::set<int3> &pos);
@@ -577,7 +577,7 @@ public:
 	void init(ICallback * CB);
 	int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
 	void removeObjToBlit(IShowable* obj);
-	void showInfoDialog(std::string &text, const std::vector<SComponent*> & components);
+	void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, bool deactivateCur=true);
 	void showYesNoDialog(std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool deactivateCur, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
 	bool moveHero(const CGHeroInstance *h, CPath * path);
 
@@ -838,14 +838,15 @@ class CSystemOptionsWindow : public IShowActivable, public CIntObject
 {
 private:
 	SDL_Surface * background; //background of window
-	AdventureMapButton * quitGame, * backToMap;
+	AdventureMapButton *load, *save, *restart, *mainMenu, * quitGame, * backToMap; //load, restart and main menu are not used yet
 	CHighlightableButtonsGroup * heroMoveSpeed;
 	CHighlightableButtonsGroup * mapScrollSpeed;
 public:
 	CSystemOptionsWindow(const SDL_Rect & pos, CPlayerInterface * owner); //c-tor
 	~CSystemOptionsWindow(); //d-tor
 
-	//functions for butons
+	//functions bound to buttons
+	void bsavef(); //save game
 	void bquitf(); //quit game
 	void breturnf(); //return to game
 

+ 3 - 1
CPreGame.cpp

@@ -973,7 +973,8 @@ void MapSel::printMaps(int from, int to, int at, bool abs)
 		}
 		else
 		{
-			CSDL_Ext::printAtMiddle(curVector()[(i-at)+from]->filename,192,13,GEOR13,nasz,scenin, 2);
+			std::string &name = curVector()[(i-at)+from]->filename;
+			CSDL_Ext::printAtMiddle(name.substr(6,name.size()-12),192,13,GEOR13,nasz,scenin, 2);
 		}
 		if (curVector()[(i-at)+from]->victoryCondition.condition == winStandard)
 			temp=11;
@@ -1064,6 +1065,7 @@ void MapSel::show()
 	//print scenario list
 	printMaps(0,18);
 
+	slid->whereAreWe = 0;
 	slid->activate();
 
 	//SDL_Flip(screen);

+ 9 - 1
hch/CCreatureHandler.cpp

@@ -458,7 +458,15 @@ void CCreatureHandler::loadCreatures()
 	creatures[140].abilities.insert(DOUBLE_WIDE);//boar should be treated as double-wide
 	creatures[142].abilities.insert(DOUBLE_WIDE);//nomads should be treated as double-wide
 
-	creatures[46].abilities -= FLYING;
+	creatures[46].abilities -= FLYING; //hell hound
+	creatures[47].abilities -= FLYING; //cerberus
+	creatures[52].abilities += FLYING; //Efreeti
+	creatures[53].abilities += FLYING; //Efreet Sultan
+
+	creatures[47].abilities += MULTI_HEAD_ATTACK; //cerberus
+
+
+	creatures[88].abilities += TWICE_ATTACK; //wolf raider
 }
 
 void CCreatureHandler::loadAnimationInfo()

+ 1 - 1
hch/CObjectHandler.cpp

@@ -709,7 +709,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
 		{
 			char buf[100];
 			sprintf(buf,VLC->generaltexth->arraytxt[117].c_str(),VLC->creh->creatures[13].namePl.c_str());
-			ret.push_back(std::pair<int,std::string>(-1,buf)); //%s in group +1
+			ret.push_back(std::pair<int,std::string>(1,buf)); //%s in group +1
 		}
 	}
 

+ 1 - 1
lib/NetPacks.h

@@ -824,7 +824,7 @@ struct EndTurn : public CPackForServer
 struct DismissHero : public CPackForServer
 {
 	DismissHero(){};
-	DismissHero(si32 HID) : hid(hid) {};
+	DismissHero(si32 HID) : hid(HID) {};
 	si32 hid;
 
 	void applyGh(CGameHandler *gh);

+ 1 - 0
server/CGameHandler.cpp

@@ -481,6 +481,7 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)
 
 void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
 {
+	bat.bsa.clear();
 	bat.stackAttacking = att->ID;
 	std::set<BattleStackAttacked>::iterator i = bat.bsa.insert(BattleStackAttacked()).first;
 	BattleStackAttacked *bsa = (BattleStackAttacked *) &*i;