Преглед изворни кода

* second part of sieges
* minor changes

mateuszb пре 16 година
родитељ
комит
adcfb3c020
11 измењених фајлова са 397 додато и 100 уклоњено
  1. 9 0
      CCallback.cpp
  2. 2 0
      CCallback.h
  3. 211 94
      client/CBattleInterface.cpp
  4. 11 2
      client/CBattleInterface.h
  5. 100 0
      config/wall_pos.txt
  6. 1 1
      hch/CArtHandler.cpp
  7. 30 0
      hch/CHeroHandler.cpp
  8. 4 1
      hch/CHeroHandler.h
  9. 13 1
      lib/CGameState.h
  10. 1 0
      lib/VCMI_Lib.cpp
  11. 15 1
      server/CGameHandler.cpp

+ 9 - 0
CCallback.cpp

@@ -609,6 +609,15 @@ const CGTownInstance *CCallback::battleGetDefendedTown()
 	return gs->map->towns[gs->curB->tid];
 }
 
+ui8 CCallback::battleGetWallState(int partOfWall)
+{
+	if(!gs->curB || gs->curB->siege == 0)
+	{
+		return 0;
+	}
+	return gs->curB->si.wallState[partOfWall];
+}
+
 void CCallback::swapGarrisonHero( const CGTownInstance *town )
 {
 	if(town->tempOwner != player) return;

+ 2 - 0
CCallback.h

@@ -175,6 +175,7 @@ public:
 	virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
 	virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
 	virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
+	virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
 };
 
 struct HeroMoveDetails
@@ -277,6 +278,7 @@ public:
 	bool battleCanCastSpell(); //returns true, if caller can cast a spell
 	bool battleCanFlee(); //returns true if caller can flee from the battle
 	const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
+	ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
 
 //XXX hmmm _tmain on _GNUC_ wtf?
 //friends

+ 211 - 94
client/CBattleInterface.cpp

@@ -95,13 +95,13 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
 	const CGTownInstance * town = LOCPLINT->cb->battleGetDefendedTown();
 	if(town)
 	{
-		siegeH = new SiegeHelper(town);
+		siegeH = new SiegeHelper(town, this);
 	}
 
 	//preparing menu background and terrain
 	if(siegeH)
 	{
-		background = BitmapHandler::loadBitmap( siegeH->getBackgroundName() );
+		background = BitmapHandler::loadBitmap( siegeH->getSiegeName(0) );
 	}
 	else
 	{
@@ -476,6 +476,12 @@ void CBattleInterface::show(SDL_Surface * to)
 		blitAt(images[((animCount+1)/(4/settings.animSpeed))%images.size()].bitmap, x, y, to);
 	}
 
+	//showing siege background
+	if(siegeH)
+	{
+		siegeH->printSiegeBackground(to);
+	}
+
 	//showing hero animations
 	if(attackingHero)
 		attackingHero->show(to);
@@ -512,94 +518,10 @@ void CBattleInterface::show(SDL_Surface * to)
 		{
 			int curStackID = stackAliveByHex[b][v];
 			
-			if(creAnims.find(curStackID) == creAnims.end()) //eg. for summoned but not yet handled stacks
-				continue;
-
-			const CStack &curStack = stacks[curStackID];
-			int animType = creAnims[curStackID]->getType();
-
-			int affectingSpeed = settings.animSpeed;
-			if(animType == 1 || animType == 2) //standing stacks should not stand faster :)
-				affectingSpeed = 2;
-			bool incrementFrame = (animCount%(4/affectingSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
-
-			if(animType == 2)
-			{
-				if(standingFrame.find(curStackID)!=standingFrame.end())
-				{
-					incrementFrame = (animCount%(8/affectingSpeed)==0);
-					if(incrementFrame)
-					{
-						++standingFrame[curStackID];
-						if(standingFrame[curStackID] == creAnims[curStackID]->framesInGroup(2))
-						{
-							standingFrame.erase(standingFrame.find(curStackID));
-						}
-					}
-				}
-				else
-				{
-					if((rand()%50) == 0)
-					{
-						standingFrame.insert(std::make_pair(curStackID, 0));
-					}
-				}
-			}
-
-			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(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
-						)
-					)
-					&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine...
-			)
-			{
-				int xAdd = curStack.attackerOwned ? 220 : 202;
-
-				//blitting amoutn background box
-				SDL_Surface *amountBG = NULL;
-				if(curStack.effects.size() == 0)
-				{
-					amountBG = amountNormal;
-				}
-				else
-				{
-					int pos=0; //determining total positiveness of effects
-					for(int c=0; c<curStack.effects.size(); ++c)
-					{
-						pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
-					}
-					if(pos > 0)
-					{
-						amountBG = amountPositive;
-					}
-					else if(pos < 0)
-					{
-						amountBG = amountNegative;
-					}
-					else
-					{
-						amountBG = amountEffNeutral;
-					}
-				}
-				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
-				CSDL_Ext::printAtMiddleWB(
-					makeNumberShort(curStack.amount),
-					creAnims[curStackID]->pos.x + xAdd + 14 + pos.x,
-					creAnims[curStackID]->pos.y + 260 + 4 + pos.y,
-					GEOR13,
-					20,
-					zwykly,
-					to
-                );
-			}
+			showAliveStack(stackAliveByHex[b][v], stacks, to);
 		}
+
+		showPieceOfWall(to, b);
 	}
 	//units shown
 	projectileShowHelper(to);//showing projectiles
@@ -2269,7 +2191,7 @@ void CBattleInterface::attackingShowHelper()
 				if (attackingInfo->sh == -1)
 					attackingInfo->sh = CGI->soundh->playSound(aStack->creature->sounds.attack);
 
-				std::map<int, int> dirToType = boost::assign::map_list_of (0, 11)(1, 11)(2, 12)(3, 13)(4, 13)(5, 12);
+				static std::map<int, int> dirToType = boost::assign::map_list_of (0, 11)(1, 11)(2, 12)(3, 13)(4, 13)(5, 12);
 				int type; //dependent on attack direction
 				if(aStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
 				{
@@ -2410,6 +2332,117 @@ void CBattleInterface::attackingShowHelper()
 	}
 }
 
+void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to)
+{
+	if(creAnims.find(ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
+		return;
+
+	const CStack &curStack = stacks.find(ID)->second;
+	int animType = creAnims[ID]->getType();
+
+	int affectingSpeed = settings.animSpeed;
+	if(animType == 1 || animType == 2) //standing stacks should not stand faster :)
+		affectingSpeed = 2;
+	bool incrementFrame = (animCount%(4/affectingSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
+
+	if(animType == 2)
+	{
+		if(standingFrame.find(ID)!=standingFrame.end())
+		{
+			incrementFrame = (animCount%(8/affectingSpeed)==0);
+			if(incrementFrame)
+			{
+				++standingFrame[ID];
+				if(standingFrame[ID] == creAnims[ID]->framesInGroup(2))
+				{
+					standingFrame.erase(standingFrame.find(ID));
+				}
+			}
+		}
+		else
+		{
+			if((rand()%50) == 0)
+			{
+				standingFrame.insert(std::make_pair(ID, 0));
+			}
+		}
+	}
+
+	creAnims[ID]->nextFrame(to, creAnims[ID]->pos.x + pos.x, creAnims[ID]->pos.y + pos.y, creDir[ID], animCount, incrementFrame, ID==activeStack, ID==mouseHoveredStack); //increment always when moving, never if stack died
+
+	//printing amount
+	if(curStack.amount > 0 //don't print if stack is not alive
+		&& (!LOCPLINT->curAction
+			|| (LOCPLINT->curAction->stackNumber != ID //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
+				)
+			)
+			&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine...
+	)
+	{
+		int xAdd = curStack.attackerOwned ? 220 : 202;
+
+		//blitting amoutn background box
+		SDL_Surface *amountBG = NULL;
+		if(curStack.effects.size() == 0)
+		{
+			amountBG = amountNormal;
+		}
+		else
+		{
+			int pos=0; //determining total positiveness of effects
+			for(int c=0; c<curStack.effects.size(); ++c)
+			{
+				pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
+			}
+			if(pos > 0)
+			{
+				amountBG = amountPositive;
+			}
+			else if(pos < 0)
+			{
+				amountBG = amountNegative;
+			}
+			else
+			{
+				amountBG = amountEffNeutral;
+			}
+		}
+		SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd + pos.x, creAnims[ID]->pos.y + 260 + pos.y));
+		//blitting amount
+		CSDL_Ext::printAtMiddleWB(
+			makeNumberShort(curStack.amount),
+			creAnims[ID]->pos.x + xAdd + 14 + pos.x,
+			creAnims[ID]->pos.y + 260 + 4 + pos.y,
+			GEOR13,
+			20,
+			zwykly,
+			to
+        );
+	}
+}
+
+void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex)
+{
+	if(!siegeH)
+		return;
+
+	static std::map<int, int> hexToPart = boost::assign::map_list_of(12, 8)(29, 7)(62, 12)(78, 6)(112, 10)(147, 5)(165, 11)(182, 4);
+
+	std::map<int, int>::const_iterator it = hexToPart.find(hex);
+	if(it != hexToPart.end())
+	{
+		siegeH->printPartOfWall(to, it->second);
+	}
+
+	//additionally print lower tower
+	if(hex == 182)
+	{
+		siegeH->printPartOfWall(to, 3);
+	}
+}
+
 void CBattleInterface::redrawBackgroundWithHexes(int activeStack)
 {
 	shadedHexes = LOCPLINT->cb->battleGetAvailableHexes(activeStack, true);
@@ -3169,12 +3202,96 @@ void CBattleOptionsWindow::bExitf()
 
 std::string CBattleInterface::SiegeHelper::townTypeInfixes[F_NUMBER] = {"CS", "RM", "TW", "IN", "NC", "DN", "ST", "FR" "EL"};
 
-CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown)
-: town(siegeTown)
+CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
+: town(siegeTown), owner(_owner)
+{
+	backWall = BitmapHandler::loadBitmap( getSiegeName(1) );
+
+	for(int g=0; g<ARRAY_COUNT(walls); ++g)
+	{
+		walls[g] = BitmapHandler::loadBitmap( getSiegeName(g + 2) );
+	}
+}
+
+CBattleInterface::SiegeHelper::~SiegeHelper()
+{
+	if(backWall)
+		SDL_FreeSurface(backWall);
+
+	for(int g=0; g<ARRAY_COUNT(walls); ++g)
+	{
+		SDL_FreeSurface(walls[g]);
+	}
+}
+
+std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInfo) const
+{
+	char buf[100];
+	itoa(additInfo, buf, 10);
+	std::string addit(buf);
+	switch(what)
+	{
+	case 0: //background
+		return "SG" + townTypeInfixes[town->town->typeID] + "BACK.BMP";
+	case 1: //background wall
+		return "SG" + townTypeInfixes[town->town->typeID] + "TPW1.BMP";
+	case 2: //keep
+		return "SG" + townTypeInfixes[town->town->typeID] + "MAN" + addit + ".BMP";
+	case 3: //bottom tower
+		return "SG" + townTypeInfixes[town->town->typeID] + "TW1" + addit + ".BMP";
+	case 4: //bottom wall
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA1" + addit + ".BMP";
+	case 5: //below gate
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA3" + addit + ".BMP";
+	case 6: //over gate
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA4" + addit + ".BMP";
+	case 7: //upper wall
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA6" + addit + ".BMP";
+	case 8: //upper tower
+		return "SG" + townTypeInfixes[town->town->typeID] + "TW2" + addit + ".BMP";
+	case 9: //gate
+		return "SG" + townTypeInfixes[town->town->typeID] + "DRW" + addit + ".BMP";
+	case 10: //gate arch
+		return "SG" + townTypeInfixes[town->town->typeID] + "ARCH.BMP";
+	case 11: //bottom static wall
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA2.BMP";
+	case 12: //upper static wall
+		return "SG" + townTypeInfixes[town->town->typeID] + "WA5.BMP";
+	default:
+		return "";
+	}
+}
+
+void CBattleInterface::SiegeHelper::printSiegeBackground(SDL_Surface * to)
 {
+	blitAt(backWall, owner->pos.w + owner->pos.x - backWall->w, 50 + owner->pos.y, to);
 }
 
-std::string CBattleInterface::SiegeHelper::getBackgroundName() const
+void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
 {
-	return "SG" + townTypeInfixes[town->town->typeID] + "BACK.BMP";
+	Point pos = Point(-1, -1);
+	switch(what)
+	{
+	case 2: //keep
+		pos = Point(owner->pos.w + owner->pos.x - walls[what-2]->w, 154 + owner->pos.y);
+		break;
+	case 3: //bottom tower
+	case 4: //bottom wall
+	case 5: //below gate
+	case 6: //over gate
+	case 7: //upper wall
+	case 8: //upper tower
+	case 9: //gate
+	case 10: //gate arch
+	case 11: //bottom static wall
+	case 12: //upper static wall
+		pos.x = CGI->heroh->wallPositions[town->town->typeID][what - 3].first + owner->pos.x;
+		pos.y = CGI->heroh->wallPositions[town->town->typeID][what - 3].second + owner->pos.y;
+		break;
+	};
+
+	if(pos.x != -1)
+	{
+		blitAt(walls[what-2], pos.x, pos.y, to);
+	}
 }

+ 11 - 2
client/CBattleInterface.h

@@ -197,6 +197,8 @@ private:
 		int sh;			   // temporary sound handler
 	} * attackingInfo;
 	void attackingShowHelper();
+	void showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to); //helper function for function show
+	void showPieceOfWall(SDL_Surface * to, int hex); //helper function for show
 	void redrawBackgroundWithHexes(int activeStack);
 	void printConsoleAttacked(int ID, int dmg, int killed, int IDby);
 
@@ -231,12 +233,19 @@ private:
 	{
 	private:
 		static std::string townTypeInfixes[F_NUMBER]; //for internal use only - to build filenames
+		SDL_Surface * backWall;
+		SDL_Surface * walls[11];
+		const CBattleInterface * owner;
 	public:
 		const CGTownInstance * town; //besieged town
-		SiegeHelper(const CGTownInstance * siegeTown); //c-tor
+		SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
+		~SiegeHelper(); //d-tor
 
 		//filename getters
-		std::string getBackgroundName() const;
+		std::string getSiegeName(ui16 what, ui16 additInfo = 1) const; //what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall; additInfo: 1 - intact, 2 - damaged, 3 - destroyed
+
+		void printSiegeBackground(SDL_Surface * to);
+		void printPartOfWall(SDL_Surface * to, int what);//what: 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall
 	} * siegeH;
 public:
 	CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect); //c-tor

+ 100 - 0
config/wall_pos.txt

@@ -0,0 +1,100 @@
+//this file is a description of positions of wall parts' positions, following lines contain positions of: bottom tower, bottom wall, wall below gate, wall over gate, upper wall, upper tower, gate, gate arch, bottom static wall and upper static wall (x, y)
+//castle
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//rampart
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//tower
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//inferno
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//necropolis
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//dungeon
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//stronghold
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//fortress
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54
+//conflux
+602 494
+557 469
+474 300
+491 188
+544 57
+567 16
+391 260
+471 164
+518 305
+500 54

+ 1 - 1
hch/CArtHandler.cpp

@@ -43,7 +43,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 {
 	std::vector<ui16> slots;
 	slots += 17, 16, 15,14,13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
-	std::map<char, CArtifact::EartClass> classes = 
+	static std::map<char, CArtifact::EartClass> classes = 
 	  map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC);
 	std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom;
 	int it=0;

+ 30 - 0
hch/CHeroHandler.cpp

@@ -123,6 +123,36 @@ CHeroHandler::~CHeroHandler()
 CHeroHandler::CHeroHandler()
 {}
 
+void CHeroHandler::loadWallPositions()
+{
+	std::ifstream inp;
+	inp.open("config" PATHSEPARATOR "wall_pos.txt", std::ios_base::in|std::ios_base::binary);
+	if(!inp.is_open())
+	{
+		tlog1<<"missing file: config/wall_pos.txt"<<std::endl;
+	}
+	else
+	{
+		const int MAX_BUF = 2000;
+		char buf[MAX_BUF+1];
+
+		inp.getline(buf, MAX_BUF);
+		std::string dump;
+		for(int g=0; g<ARRAY_COUNT(wallPositions); ++g)
+		{
+			inp >> dump;
+			for(int b=0; b<10; ++b)
+			{
+				std::pair<int, int> pt;
+				inp >> pt.first;
+				inp >> pt.second;
+				wallPositions[g].push_back(pt);
+			}
+		}
+	}
+	inp.close();
+}
+
 void CHeroHandler::loadObstacles()
 {
 	std::ifstream inp;

+ 4 - 1
hch/CHeroHandler.h

@@ -108,6 +108,9 @@ public:
 	};
 	std::vector<SBallisticsLevelInfo> ballistics; //info about ballistics ability per level; [0] - none; [1] - basic; [2] - adv; [3] - expert
 
+	std::vector<std::pair<int, int>> wallPositions[F_NUMBER]; //positions of different pieces of wall <x, y>
+	void loadWallPositions();
+
 	std::map<int, CObstacleInfo> obstacles; //info about obstacles that may be placed on battlefield
 	std::vector<int> nativeTerrains; //info about native terrains of different factions
 
@@ -126,7 +129,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & heroClasses & heroes & expPerLevel & ballistics & obstacles & nativeTerrains;
+		h & heroClasses & heroes & expPerLevel & ballistics & wallPositions & obstacles & nativeTerrains;
 		if(!h.saving)
 		{
 			//restore class pointers

+ 13 - 1
lib/CGameState.h

@@ -105,6 +105,17 @@ struct DLL_EXPORT CObstacleInstance
 	}
 };
 
+//only for use in BattleInfo
+struct DLL_EXPORT SiegeInfo
+{
+	ui8 wallState[7]; //[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; 1 - intact, 2 - damaged, 3 - destroyed
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & wallState;
+	}
+};
+
 struct DLL_EXPORT BattleInfo
 {
 	ui8 side1, side2; //side1 - attacker, side2 - defender
@@ -117,11 +128,12 @@ struct DLL_EXPORT BattleInfo
 	std::vector<CStack*> stacks;
 	std::vector<CObstacleInstance> obstacles;
 	ui8 castSpells[2]; //[0] - attacker, [1] - defender
+	SiegeInfo si;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & hero1 & hero2 & obstacles
-			& castSpells;
+			& castSpells & si;
 	}
 	CStack * getNextStack(); //which stack will have turn after current one
 	std::vector<CStack> getStackQueue(); //returns stack in order of their movement action

+ 1 - 0
lib/VCMI_Lib.cpp

@@ -174,6 +174,7 @@ void LibClasses::init()
 	heroh = new CHeroHandler;
 	heroh->loadHeroes();
 	heroh->loadObstacles();
+	heroh->loadWallPositions();
 	tlog0 <<"\tHero handler: "<<pomtime.getDif()<<std::endl;
 
 	arth = new CArtHandler;

+ 15 - 1
server/CGameHandler.cpp

@@ -997,9 +997,23 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
 			stacks.push_back(stack);
 		}
 	}
+	if(town && hero1) //catapult
+	{
+		CStack * stack = BattleInfo::generateNewStack(hero1, 145, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120);
+		stacks.push_back(stack);
+	}
 	//war machines added
 	std::stable_sort(stacks.begin(),stacks.end(),cmpst);
 
+	//seting up siege
+	if(town)
+	{
+		for(int b=0; b<ARRAY_COUNT(curB->si.wallState); ++b)
+		{
+			curB->si.wallState[b] = 1;
+		}
+	}
+
 	//randomize obstacles
 	bool obAv[BFIELD_SIZE]; //availability of hexes for obstacles;
 	std::vector<int> possibleObstacles;
@@ -2569,7 +2583,7 @@ static ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster,
 
 	//15 - magic arrows, 16 - ice bolt, 17 - lightning bolt, 18 - implosion, 20 - frost ring, 21 - fireball, 22 - inferno, 23 - meteor shower,
 	//24 - death ripple, 25 - destroy undead, 26 - armageddon
-	std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50);
+	static std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50);
 
 	ret = caster->getPrimSkillLevel(2) * dmgMultipliers[sp->id]  +  sp->powers[caster->getSpellSchoolLevel(sp)];