Explorar o código

* flaggable objects change their color on minimap when taken over
* corrected damage inflicted by spells and ballista
* minor changes

mateuszb %!s(int64=16) %!d(string=hai) anos
pai
achega
8e63c73cf8

+ 10 - 14
CCallback.cpp

@@ -185,6 +185,11 @@ const CGHeroInstance * CCallback::getHeroInfo(int val, int mode) const //mode =
 	return NULL;
 }
 
+const CGObjectInstance * CCallback::getObjectInfo(int ID) const
+{
+	return gs->map->objects[ID];
+}
+
 bool CCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const
 {
 	const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(hero);
@@ -264,7 +269,7 @@ std::vector< std::vector< std::vector<unsigned char> > > & CCallback::getVisibil
 bool CCallback::isVisible(int3 pos, int Player) const
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
-	return gs->players[Player].fogOfWarMap[pos.x][pos.y][pos.z];
+	return gs->isVisible(pos, Player);
 }
 
 std::vector < const CGTownInstance *> CCallback::getTownsInfo(bool onlyOur) const
@@ -306,24 +311,14 @@ bool CCallback::isVisible(int3 pos) const
 
 bool CCallback::isVisible( const CGObjectInstance *obj, int Player ) const
 {
-	//object is visible when at least one blocked tile is visible
-	for(int fx=0; fx<8; ++fx)
-	{
-		for(int fy=0; fy<6; ++fy)
-		{
-			int3 pos = obj->pos + int3(fx-7,fy-5,0);
-			if(gs->map->isInTheMap(pos) 
-				&& !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1) 
-				&& isVisible(pos,Player)  )
-				return true;
-		}
-	}
-	return false;
+	return gs->isVisible(obj, Player);
 }
+
 int CCallback::getMyColor() const
 {
 	return player;
 }
+
 int CCallback::getHeroSerial(const CGHeroInstance * hero) const
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
@@ -334,6 +329,7 @@ int CCallback::getHeroSerial(const CGHeroInstance * hero) const
 	}
 	return -1;
 }
+
 const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj) const
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);

+ 1 - 0
CCallback.h

@@ -205,6 +205,7 @@ public:
 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 	std::vector< std::vector< std::vector<unsigned char> > > & getVisibilityMap() const; //returns visibility map (TODO: make it const)
 	const CGHeroInstance * getHeroInfo(int val, int mode=2) const; //mode = 0 -> val = serial; mode = 1 -> val = hero type id (subID); mode = 2 -> val = global object serial id (id)
+	const CGObjectInstance * getObjectInfo(int ID) const; //global object serial id (ID)
 	int getResourceAmount(int type) const;
 	std::vector<si32> getResourceAmount() const;
 	int howManyHeroes(bool includeGarrisoned = true) const;

+ 3 - 0
CGameInterface.h

@@ -39,6 +39,7 @@ struct SpellCast;
 struct SetStackEffect;
 struct HeroBonus;
 struct PackageApplied;
+struct SetObjectProperty;
 class CLoadFile;
 class CSaveFile;
 template <typename Serializer> class CISer;
@@ -59,6 +60,7 @@ struct StackState
 	int shotsLeft;
 	std::set<int> effects; //IDs of spells affecting stack
 	int morale, luck;
+	int dmgMultiplier; //for ballista dmg bonus handling
 };
 
 class CGameInterface
@@ -97,6 +99,7 @@ public:
 	virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
 	virtual void requestRealized(PackageApplied *pa){};
 	virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
+	virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
 	virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
 	virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
 

+ 70 - 19
client/CAdvmapInterface.cpp

@@ -45,6 +45,7 @@ extern TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX; //fonts
 using namespace boost::logic;
 using namespace boost::assign;
 using namespace CSDL_Ext;
+
 CMinimap::CMinimap(bool draw)
 {
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
@@ -157,6 +158,26 @@ void CMinimap::draw(SDL_Surface * to)
 }
 void CMinimap::redraw(int level)// (level==-1) => redraw all levels
 {
+	initMap(level);
+
+	//FoW
+	initFoW(level);
+
+	//flaggable objects
+	initFlaggableObjs(level);
+
+	//showing tiles
+	showVisibleTiles();
+}
+
+void CMinimap::initMap(int level)
+{
+	/*for(int g=0; g<map.size(); ++g)
+	{
+		SDL_FreeSurface(map[g]);
+	}
+	map.clear();*/
+
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
 	for (size_t i=0; i<CGI->mh->sizes.z; i++)
 	{
@@ -184,8 +205,17 @@ void CMinimap::redraw(int level)// (level==-1) => redraw all levels
 		map.push_back(pom);
 
 	}
+}
 
-	//FoW
+void CMinimap::initFoW(int level)
+{
+	/*for(int g=0; g<FoW.size(); ++g)
+	{
+		SDL_FreeSurface(FoW[g]);
+	}
+	FoW.clear();*/
+
+	int3 mapSizes = LOCPLINT->cb->getMapSize();
 	int mw = map[0]->w, mh = map[0]->h;//,
 		//wo = mw/mapSizes.x, ho = mh/mapSizes.y; //TODO use me
 	for(int d=0; d<CGI->mh->map->twoLevel+1; ++d)
@@ -206,8 +236,18 @@ void CMinimap::redraw(int level)// (level==-1) => redraw all levels
 		}
 		FoW.push_back(pt);
 	}
-	//FoW end
-	//flaggable objects
+}
+
+void CMinimap::initFlaggableObjs(int level)
+{
+	/*for(int g=0; g<flObjs.size(); ++g)
+	{
+		SDL_FreeSurface(flObjs[g]);
+	}
+	flObjs.clear();*/
+
+	int3 mapSizes = LOCPLINT->cb->getMapSize();
+	int mw = map[0]->w, mh = map[0]->h;
 	for(int d=0; d<CGI->mh->map->twoLevel+1; ++d)
 	{
 		if(level>=0 && d!=level)
@@ -222,30 +262,16 @@ void CMinimap::redraw(int level)// (level==-1) => redraw all levels
 		}
 		flObjs.push_back(pt);
 	}
-	//showing tiles
-	for(int d=0; d<CGI->mh->map->twoLevel+1; ++d)
-	{
-		if(level>=0 && d!=level)
-			continue;
-		for(int x=0; x<mapSizes.x; ++x)
-		{
-			for(int y=0; y<mapSizes.y; ++y)
-			{
-				if(LOCPLINT->cb->isVisible(int3(x, y, d)))
-				{
-					showTile(int3(x, y, d));
-				}
-			}
-		}
-	}
 }
 
 void CMinimap::updateRadar()
 {}
+
 void CMinimap::clickRight (tribool down)
 {
 	LOCPLINT->adventureInt->handleRightClick(rcText,down,this);
 }
+
 void CMinimap::clickLeft (tribool down)
 {
 	if (down && (!pressedL))
@@ -268,6 +294,7 @@ void CMinimap::clickLeft (tribool down)
 	newCPos.z = LOCPLINT->adventureInt->position.z;
 	LOCPLINT->adventureInt->centerOn(newCPos);
 }
+
 void CMinimap::hover (bool on)
 {
 	Hoverable::hover(on);
@@ -276,6 +303,7 @@ void CMinimap::hover (bool on)
 	else if (LOCPLINT->adventureInt->statusbar.current==statusbarTxt)
 		LOCPLINT->adventureInt->statusbar.clear();
 }
+
 void CMinimap::mouseMoved (const SDL_MouseMotionEvent & sEvent)
 {
 	if (pressedL)
@@ -291,6 +319,7 @@ void CMinimap::activate()
 	if (pressedL)
 		MotionInterested::activate();
 }
+
 void CMinimap::deactivate()
 {
 	if (pressedL)
@@ -299,6 +328,7 @@ void CMinimap::deactivate()
 	ClickableR::deactivate();
 	Hoverable::deactivate();
 }
+
 void CMinimap::showTile(const int3 &pos)
 {
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
@@ -371,6 +401,27 @@ void CMinimap::showTile(const int3 &pos)
 	}
 	//flaggable objects drawn
 }
+
+void CMinimap::showVisibleTiles(int level)
+{
+	int3 mapSizes = LOCPLINT->cb->getMapSize();
+	for(int d=0; d<CGI->mh->map->twoLevel+1; ++d)
+	{
+		if(level>=0 && d!=level)
+			continue;
+		for(int x=0; x<mapSizes.x; ++x)
+		{
+			for(int y=0; y<mapSizes.y; ++y)
+			{
+				if(LOCPLINT->cb->isVisible(int3(x, y, d)))
+				{
+					showTile(int3(x, y, d));
+				}
+			}
+		}
+	}
+}
+
 void CMinimap::hideTile(const int3 &pos)
 {
 }

+ 5 - 0
client/CAdvmapInterface.h

@@ -40,6 +40,10 @@ public:
 	~CMinimap();
 	void draw(SDL_Surface * to);
 	void redraw(int level=-1);// (level==-1) => redraw all levels
+	void initMap(int level=-1);// (level==-1) => redraw all levels
+	void initFoW(int level=-1);// (level==-1) => redraw all levels
+	void initFlaggableObjs(int level=-1);// (level==-1) => redraw all levels
+
 	void updateRadar();
 
 	void clickRight (boost::logic::tribool down);
@@ -50,6 +54,7 @@ public:
 	void deactivate(); // makes button inactive (but don't deletes)
 	void hideTile(const int3 &pos); //puts FoW
 	void showTile(const int3 &pos); //removes FoW
+	void showVisibleTiles(int level=-1);// (level==-1) => redraw all levels
 };
 class CTerrainRect
 	:  public ClickableL, public ClickableR, public Hoverable, public MotionInterested

+ 5 - 1
client/CBattleInterface.cpp

@@ -2607,6 +2607,10 @@ void CBattleHex::clickRight(boost::logic::tribool down)
 			pom->morale = myst.Morale();
 			pom->speedBonus = myst.Speed() - myst.creature->speed;
 			pom->healthBonus = myst.MaxHealth() - myst.creature->hitPoints;
+			if(myst.hasFeatureOfType(StackFeature::SIEGE_WEAPON))
+				pom->dmgMultiplier = h->getPrimSkillLevel(0) + 1;
+			else
+				pom->dmgMultiplier = 1;
 
 			pom->shotsLeft = myst.shots;
 			for(int vb=0; vb<myst.effects.size(); ++vb)
@@ -2614,7 +2618,7 @@ void CBattleHex::clickRight(boost::logic::tribool down)
 				pom->effects.insert(myst.effects[vb].id);
 			}
 			pom->currentHealth = myst.firstHPleft;
-			LOCPLINT->pushInt(new CCreInfoWindow(myst.creature->idNumber,0,myst.amount,pom,0,0,NULL));
+			LOCPLINT->pushInt(new CCreInfoWindow(myst.creature->idNumber, 0, myst.amount, pom, 0, 0, NULL));
 		}
 		delete pom;
 	}

+ 16 - 0
client/CPlayerInterface.cpp

@@ -1712,6 +1712,22 @@ void CPlayerInterface::heroExchangeStarted(si32 hero1, si32 hero2)
 	pushInt(new CExchangeWindow(hero2, hero1));
 }
 
+void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
+{
+	//redraw minimap if owner changed
+	if(sop->what == 1)
+	{
+		LOCPLINT->adventureInt->minimap.initFlaggableObjs();
+		const CGObjectInstance * obj = LOCPLINT->cb->getObjectInfo(sop->id);
+		std::set<int3> pos = obj->getBlockedPos();
+		for(std::set<int3>::const_iterator it = pos.begin(); it != pos.end(); ++it)
+		{
+			LOCPLINT->adventureInt->minimap.showTile(*it);
+		}
+	}
+
+}
+
 void CPlayerInterface::recreateWanderingHeroes()
 {
 	wanderingHeroes.clear();

+ 1 - 0
client/CPlayerInterface.h

@@ -174,6 +174,7 @@ public:
 	void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it
 	void requestRealized(PackageApplied *pa);
 	void heroExchangeStarted(si32 hero1, si32 hero2);
+	void objectPropertyChanged(const SetObjectProperty * sop);
 	void serialize(COSer<CSaveFile> &h, const int version); //saving
 	void serialize(CISer<CLoadFile> &h, const int version); //loading
 

+ 22 - 18
client/GUIClasses.cpp

@@ -75,6 +75,7 @@ static StackState* getStackState(const CGObjectInstance *obj, int pos, bool town
 	pom->luck = h->getCurrentLuck();
 	pom->morale = h->getCurrentMorale(pos,town);
 	pom->speedBonus = h->valOfBonuses(HeroBonus::STACKS_SPEED);
+	pom->dmgMultiplier = 1;
 	return pom;
 }
 
@@ -170,7 +171,7 @@ void CGarrisonSlot::clickRight (tribool down)
 	StackState *pom = getStackState(getObj(),ID, LOCPLINT->topInt() == LOCPLINT->castleInt);
 	if(down && creature)
 	{
-		LOCPLINT->pushInt(new CCreInfoWindow(creature->idNumber,0,count,pom,0,0,NULL));
+		LOCPLINT->pushInt(new CCreInfoWindow(creature->idNumber, 0, count, pom, 0, 0, NULL));
 	}
 	delete pom;
 }
@@ -196,15 +197,15 @@ void CGarrisonSlot::clickLeft(tribool down)
 				{
 
 					creWindow = new CCreInfoWindow(
-						creature->idNumber,1,count,pom2,
-						boost::bind(&CCallback::upgradeCreature,LOCPLINT->cb,getObj(),ID,pom.newID[0]), //bind upgrade function
-						boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID),&pom);
+						creature->idNumber, 1, count, pom2,
+						boost::bind(&CCallback::upgradeCreature, LOCPLINT->cb, getObj(), ID, pom.newID[0]), //bind upgrade function
+						boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), &pom);
 				}
 				else
 				{
 					creWindow = new CCreInfoWindow(
-						creature->idNumber,1,count,pom2,0, 
-						boost::bind(&CCallback::dismissCreature,LOCPLINT->cb,getObj(),ID), NULL);
+						creature->idNumber, 1, count, pom2, 0, 
+						boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), NULL);
 				}
 
 				LOCPLINT->pushInt(creWindow);
@@ -1681,7 +1682,7 @@ void CRecruitmentWindow::clickRight( boost::logic::tribool down )
 		{
 			if(isItIn(&genRect(132,102,pos.x+curx,pos.y+64),LOCPLINT->current->motion.x,LOCPLINT->current->motion.y))
 			{
-				CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID,0,0,NULL,NULL,NULL,NULL);
+				CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0, NULL, NULL, NULL, NULL);
 				LOCPLINT->pushInt(popup);
 				break;
 			}
@@ -2007,7 +2008,7 @@ void CCreInfoWindow::show(SDL_Surface * to)
 }
 
 CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState *State, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
-:type(Type),dsm(Dsm),dismiss(0),upgrade(0),ok(0)
+	: type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0)
 {
 	//active = false;
 	anf = 0;
@@ -2069,24 +2070,27 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
 	//shots
 	if(c->shots)
 	{
-		printAt(CGI->generaltexth->allTexts[198],155,86,GEOR13,zwykly,bitmap);
+		printAt(CGI->generaltexth->allTexts[198], 155, 86, GEOR13, zwykly, bitmap);
 		if(State  &&  State->shotsLeft >= 0)
-			sprintf(pom,"%d (%d)",c->shots,State->shotsLeft);
+			sprintf(pom,"%d (%d)", c->shots, State->shotsLeft);
 		else
-			SDL_itoa(c->shots,pom,10);
-		printToWR(pom,276,99,GEOR13,zwykly,bitmap);
+			SDL_itoa(c->shots, pom, 10);
+		printToWR(pom, 276, 99, GEOR13, zwykly, bitmap);
 	}
 
 	//damage
-	printAt(CGI->generaltexth->allTexts[199],155,105,GEOR13,zwykly,bitmap);
-	SDL_itoa(c->damageMin,pom,10);
-	if(c->damageMin > 0)
-		hlp = log10f(c->damageMin)+2;
+	int dmgMin = c->damageMin * State->dmgMultiplier;
+	int dmgMax = c->damageMax * State->dmgMultiplier;
+
+	printAt(CGI->generaltexth->allTexts[199], 155, 105, GEOR13, zwykly, bitmap);
+	SDL_itoa(dmgMin, pom, 10);
+	if(dmgMin > 0)
+		hlp = log10f(dmgMin) + 2;
 	else
 		hlp = 2;
 	pom[hlp-1]=' '; pom[hlp]='-'; pom[hlp+1]=' ';
-	SDL_itoa(c->damageMax,pom+hlp+2,10);
-	printToWR(pom,276,118,GEOR13,zwykly,bitmap);
+	SDL_itoa(dmgMax, pom+hlp+2, 10);
+	printToWR(pom, 276, 118, GEOR13, zwykly, bitmap);
 
 	//health
 	printAt(CGI->generaltexth->allTexts[388],155,124,GEOR13,zwykly,bitmap);

+ 10 - 0
client/NetPacksClient.cpp

@@ -280,6 +280,16 @@ void InfoWindow::applyCl( CClient *cl )
 		tlog2 << "We received InfoWindow for not our player...\n";
 }
 
+void SetObjectProperty::applyCl( CClient *cl )
+{
+	//inform all players that see this object
+	for(std::map<ui8,CGameInterface *>::const_iterator it = cl->playerint.begin(); it != cl->playerint.end(); ++it)
+	{
+		//if(cl->gs->isVisible(cl->gs->map->objects[id]), it->first)
+			INTERFACE_CALL_IF_PRESENT(it->first, objectPropertyChanged, this);
+	}
+}
+
 void HeroLevelUp::applyCl( CClient *cl )
 {
 	CGHeroInstance *h = GS(cl)->getHero(heroid);

+ 16 - 2
hch/CObjectHandler.cpp

@@ -185,8 +185,8 @@ bool CGObjectInstance::blockingAt(int x, int y) const
 	if(x<0 || y<0 || x>=getWidth() || y>=getHeight() || defInfo==NULL)
 		return false;
 	if((defInfo->blockMap[y+6-getHeight()] >> (7-(8-getWidth()+x) )) & 1)
-		return true;
-	return false;
+		return false;
+	return true;
 }
 
 bool CGObjectInstance::coveringAt(int x, int y) const
@@ -196,6 +196,20 @@ bool CGObjectInstance::coveringAt(int x, int y) const
 	return false;
 }
 
+std::set<int3> CGObjectInstance::getBlockedPos() const
+{
+	std::set<int3> ret;
+	for(int w=0; w<getWidth(); ++w)
+	{
+		for(int h=0; h<getHeight(); ++h)
+		{
+			if(blockingAt(w, h))
+				ret.insert(int3(pos.x - getWidth() + w + 1, pos.y - getHeight() + h + 1, pos.z));
+		}
+	}
+	return ret;
+}
+
 bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const  //screen printing priority comparing
 {
 	if(defInfo->printPriority==1 && cmp.defInfo->printPriority==0)

+ 1 - 0
hch/CObjectHandler.h

@@ -147,6 +147,7 @@ public:
 	int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos)
 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) form left top tile of image (x, y in tiles)
 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) form left top tile of maximal possible image (8 x 6 tiles) (x, y in tiles)
+	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
 	bool operator<(const CGObjectInstance & cmp) const;  //screen printing priority comparing
 	CGObjectInstance();
 	virtual ~CGObjectInstance();

+ 28 - 0
lib/CGameState.cpp

@@ -1754,6 +1754,28 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
 	return true;
 }
 
+bool CGameState::isVisible(int3 pos, int player)
+{
+	return players[player].fogOfWarMap[pos.x][pos.y][pos.z];
+}
+
+bool CGameState::isVisible( const CGObjectInstance *obj, int player )
+{
+	//object is visible when at least one blocked tile is visible
+	for(int fx=0; fx<8; ++fx)
+	{
+		for(int fy=0; fy<6; ++fy)
+		{
+			int3 pos = obj->pos + int3(fx-7,fy-5,0);
+			if(map->isInTheMap(pos) 
+				&& !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1) 
+				&& isVisible(pos, player)  )
+				return true;
+		}
+	}
+	return false;
+}
+
 bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
 {
 	const TerrainTile * pom = &map->getTile(dst);
@@ -1805,6 +1827,12 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		minDmg = attacker->creature->damageMin * attacker->amount, 
 		maxDmg = attacker->creature->damageMax * attacker->amount;
 
+	if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //any siege weapon, but only ballista can attack
+	{ //minDmg and maxDmg are multiplied by hero attack + 1
+		minDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
+		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
+	}
+
 	//calculating total attack/defense skills modifier
 
 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)

+ 3 - 0
lib/CGameState.h

@@ -282,6 +282,9 @@ public:
 	bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if dst tile is visitable from dst tile
 	bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
 
+	bool isVisible(int3 pos, int player);
+	bool isVisible(const CGObjectInstance *obj, int player);
+
 	CGameState(); //c-tor
 	~CGameState(); //d-tor
 	void getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand);

+ 1 - 0
lib/NetPacks.h

@@ -610,6 +610,7 @@ struct InfoWindow : public CPackForClient //103  - displays simple info window
 struct SetObjectProperty : public CPackForClient//1001
 {
 	DLL_EXPORT void applyGs(CGameState *gs);
+	void applyCl(CClient *cl);
 
 	ui32 id;
 	ui8 what; //1 - owner; 2 - blockvis; 3 - first stack count; 4 - visitors; 5 - visited; 6 - ID (if 34 then also def is replaced)

+ 35 - 15
server/CGameHandler.cpp

@@ -2499,46 +2499,57 @@ static ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster,
 		case 15: //magic arrow
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 16: //ice bolt
 			{
 				ret = caster->getPrimSkillLevel(2) * 20  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 17: //lightning bolt
 			{
 				ret = caster->getPrimSkillLevel(2) * 25  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 18: //implosion
 			{
 				ret = caster->getPrimSkillLevel(2) * 75  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 20: //frost ring
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 21: //fireball
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 22: //inferno
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 23: //meteor shower
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 24: //death ripple
 			{
 				ret = caster->getPrimSkillLevel(2) * 5  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 25: //destroy undead
 			{
 				ret = caster->getPrimSkillLevel(2) * 10  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 		case 26: //armageddon
 			{
 				ret = caster->getPrimSkillLevel(2) * 50  +  sp->powers[caster->getSpellSchoolLevel(sp)];
+				break;
 			}
 	}
 	//applying sorcerery secondary skill
@@ -2604,7 +2615,7 @@ static ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster,
 	return ret;
 }
 
-static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const std::set<CStack*> affectedCreatures)
+static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures)
 {
 	std::vector<ui32> ret;
 	for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
@@ -2613,21 +2624,30 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
 		if(sp->positiveness >= 0 && (*it)->owner == caster->tempOwner)
 			continue;
 
-		int prob = (*it)->valOfFeatures(StackFeature::MAGIC_RESISTANCE); //probability of resistance in %
-		//caster's resistance support (secondary skils and artifacts)
-		prob += caster->valOfBonuses(HeroBonus::MAGIC_RESISTANCE);
+		const CGHeroInstance * bonusHero; //hero we should take bonuses from
+		if((*it)->owner == caster->tempOwner)
+			bonusHero = caster;
+		else
+			bonusHero = hero2;
 
-		switch(caster->getSecSkillLevel(26)) //resistance
+		int prob = (*it)->valOfFeatures(StackFeature::MAGIC_RESISTANCE); //probability of resistance in %
+		if(bonusHero)
 		{
-		case 1: //basic
-			prob += 5;
-			break;
-		case 2: //advanced
-			prob += 10;
-			break;
-		case 3: //expert
-			prob += 20;
-			break;
+			//bonusHero's resistance support (secondary skils and artifacts)
+			prob += bonusHero->valOfBonuses(HeroBonus::MAGIC_RESISTANCE);
+
+			switch(bonusHero->getSecSkillLevel(26)) //resistance
+			{
+			case 1: //basic
+				prob += 5;
+				break;
+			case 2: //advanced
+				prob += 10;
+				break;
+			case 3: //expert
+				prob += 20;
+				break;
+			}
 		}
 
 		if(prob > 100) prob = 100;
@@ -2685,7 +2705,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 			std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(s, h, ba.destinationTile);
 
 			//checking if creatures resist
-			sc.resisted = calculateResistedStacks(s, h, attackedCres);
+			sc.resisted = calculateResistedStacks(s, h, secondHero, attackedCres);
 			
 			sendAndApply(&sc);