浏览代码

* corrected per-stack spell immunity handling
* support for new artifacts: * of Legion, shackles of war

mateuszb 16 年之前
父节点
当前提交
4fc25c7b98
共有 9 个文件被更改,包括 66 次插入13 次删除
  1. 5 0
      CCallback.cpp
  2. 2 0
      CCallback.h
  3. 23 2
      client/CBattleInterface.cpp
  4. 5 5
      hch/CArtHandler.cpp
  5. 1 1
      hch/CArtHandler.h
  6. 8 1
      hch/CObjectHandler.cpp
  7. 15 0
      lib/CGameState.cpp
  8. 1 0
      lib/CGameState.h
  9. 6 4
      server/CGameHandler.cpp

+ 5 - 0
CCallback.cpp

@@ -577,6 +577,11 @@ bool CCallback::battleCanCastSpell()
 		return gs->curB->castSpells[1] == 0 && gs->getHero(gs->curB->hero2)->getArt(17);
 }
 
+bool CCallback:: battleCanFlee()
+{
+	return gs->battleCanFlee(player);
+}
+
 void CCallback::swapGarrisonHero( const CGTownInstance *town )
 {
 	if(town->tempOwner != player) return;

+ 2 - 0
CCallback.h

@@ -172,6 +172,7 @@ public:
 	virtual bool battleIsStackMine(int ID)=0; //returns true if stack with id ID belongs to caller
 	virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
 	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
 };
 
 struct HeroMoveDetails
@@ -270,6 +271,7 @@ public:
 	bool battleIsStackMine(int ID); //returns true if stack with id ID belongs to caller
 	bool battleCanShoot(int ID, int dest); //returns true if unit with id ID can shoot to dest
 	bool battleCanCastSpell(); //returns true, if caller can cast a spell
+	bool battleCanFlee(); //returns true if caller can flee from the battle
 
 //XXX hmmm _tmain on _GNUC_ wtf?
 //friends

+ 23 - 2
client/CBattleInterface.cpp

@@ -985,8 +985,29 @@ void CBattleInterface::bSurrenderf()
 
 void CBattleInterface::bFleef()
 {
-	CFunctionList<void()> ony = boost::bind(&CBattleInterface::reallyFlee,this);
-	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[28],std::vector<SComponent*>(), ony, 0, false);
+	if( LOCPLINT->cb->battleCanFlee() )
+	{
+		CFunctionList<void()> ony = boost::bind(&CBattleInterface::reallyFlee,this);
+		LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[28],std::vector<SComponent*>(), ony, 0, false);
+	}
+	else
+	{
+		std::vector<SComponent*> comps;
+		std::string heroName;
+		//calculating fleeing hero's name
+		if(attackingHeroInstance)
+			if(attackingHeroInstance->tempOwner == LOCPLINT->cb->getMyColor())
+				heroName = attackingHeroInstance->name;
+		if(defendingHeroInstance)
+			if(defendingHeroInstance->tempOwner == LOCPLINT->cb->getMyColor())
+				heroName = defendingHeroInstance->name;
+		//calculating text
+		char buffer[1000];
+		sprintf(buffer, CGI->generaltexth->allTexts[340].c_str(), heroName.c_str());
+
+		//printing message
+		LOCPLINT->showInfoDialog(std::string(buffer), comps);
+	}
 }
 
 void CBattleInterface::reallyFlee()

+ 5 - 5
hch/CArtHandler.cpp

@@ -314,11 +314,11 @@ void CArtHandler::addBonuses()
 	giveArtBonus(116,HeroBonus::GENERATE_RESOURCE,+750,6); //Endless Bag of Gold
 	giveArtBonus(117,HeroBonus::GENERATE_RESOURCE,+500,6); //Endless Purse of Gold
 
-	giveArtBonus(118,HeroBonus::CREATURE_GROWTH,+5,2); //Legs of Legion
-	giveArtBonus(119,HeroBonus::CREATURE_GROWTH,+4,3); //Loins of Legion
-	giveArtBonus(120,HeroBonus::CREATURE_GROWTH,+3,4); //Torso of Legion
-	giveArtBonus(121,HeroBonus::CREATURE_GROWTH,+2,5); //Arms of Legion
-	giveArtBonus(122,HeroBonus::CREATURE_GROWTH,+1,6); //Head of Legion
+	giveArtBonus(118,HeroBonus::CREATURE_GROWTH,+5,1); //Legs of Legion
+	giveArtBonus(119,HeroBonus::CREATURE_GROWTH,+4,2); //Loins of Legion
+	giveArtBonus(120,HeroBonus::CREATURE_GROWTH,+3,3); //Torso of Legion
+	giveArtBonus(121,HeroBonus::CREATURE_GROWTH,+2,4); //Arms of Legion
+	giveArtBonus(122,HeroBonus::CREATURE_GROWTH,+1,5); //Head of Legion
 
 	//Sea Captain's Hat 
 	giveArtBonus(123,HeroBonus::WHIRLPOOL_PROTECTION,0); 

+ 1 - 1
hch/CArtHandler.h

@@ -28,7 +28,7 @@ public:
 	ui32 price;
 	std::vector<ui16> possibleSlots; //ids of slots where artifact can be placed
 	EartClass aClass;
-	int id;
+	ui32 id;
 	std::list<HeroBonus> bonuses; //bonuses given by artifact
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 8 - 1
hch/CObjectHandler.cpp

@@ -1173,7 +1173,7 @@ void CGDwelling::fightOver(const CGHeroInstance *h, BattleResult *result) const
 
 int CGTownInstance::getSightRadious() const //returns sight distance
 {
-	if (subID == 2 && (builtBuildings.find(21))!=builtBuildings.end())
+	if (subID == 2 && (builtBuildings.find(21))!=builtBuildings.end()) //town has lookout tower
 		return 20;
 	return 5;
 }
@@ -1241,6 +1241,13 @@ int CGTownInstance::creatureGrowth(const int & level) const
 	if(getHordeLevel(1)==level)
 		if((builtBuildings.find(24)!=builtBuildings.end()) || (builtBuildings.find(25)!=builtBuildings.end()))
 			ret+=VLC->creh->creatures[town->basicCreatures[level]].hordeGrowth;
+
+	//support for legs of legion etc.
+	if(garrisonHero)
+		ret += garrisonHero->valOfBonuses(HeroBonus::CREATURE_GROWTH, level);
+	if(visitingHero)
+		ret += visitingHero->valOfBonuses(HeroBonus::CREATURE_GROWTH, level);
+
 	return ret;
 }
 int CGTownInstance::dailyIncome() const

+ 15 - 0
lib/CGameState.cpp

@@ -1373,6 +1373,21 @@ bool CGameState::battleShootCreatureStack(int ID, int dest)
 	return true;
 }
 
+bool CGameState::battleCanFlee(int player)
+{
+	if(!curB) //there is no battle
+		return false;
+
+	const CGHeroInstance *h1 = getHero(curB->hero1);
+	const CGHeroInstance *h2 = getHero(curB->hero2);
+
+	if(h1->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war
+		|| h2->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE))
+		return false;
+
+	return true;
+}
+
 int CGameState::battleGetStack(int pos, bool onlyAlive)
 {
 	if(!curB)

+ 1 - 0
lib/CGameState.h

@@ -275,6 +275,7 @@ public:
 	bool battleMoveCreatureStack(int ID, int dest);
 	bool battleAttackCreatureStack(int ID, int dest);
 	bool battleShootCreatureStack(int ID, int dest);
+	bool battleCanFlee(int player); //returns true if player can flee from the battle
 	int battleGetStack(int pos, bool onlyAlive); //returns ID of stack at given tile
 	int battleGetBattlefieldType(int3 tile = int3());//   1. sand/shore   2. sand/mesas   3. dirt/birches   4. dirt/hills   5. dirt/pines   6. grass/hills   7. grass/pines   8. lava   9. magic plains   10. snow/mountains   11. snow/trees   12. subterranean   13. swamp/trees   14. fiery fields   15. rock lands   16. magic clouds   17. lucid pools   18. holy ground   19. clover field   20. evil fog   21. "favourable winds" text on magic plains background   22. cursed ground   23. rough   24. ship to ship   25. ship
 	si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned

+ 6 - 4
server/CGameHandler.cpp

@@ -2287,8 +2287,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		}
 	case 4: //retreat/flee
 		{
-			//TODO: check if fleeing is possible (e.g. enemy may have Shackles of War)
-			//TODO: calculate casualties
+			if( !gs->battleCanFlee(ba.side ? gs->curB->side2 : gs->curB->side1) )
+				break;
 			//TODO: remove retreating hero from map and place it in recruitment list
 			BattleResult *br = new BattleResult;
 			br->result = 1;
@@ -2681,7 +2681,8 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
 
 		if(prob > 100) prob = 100;
 
-		if(rand()%100 < prob)
+		if( (*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
+			|| rand()%100 < prob) //immunity from resistance
 			ret.push_back((*it)->ID);
 
 	}
@@ -2690,7 +2691,8 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
 	{
 		for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
 		{
-			if( (*it)->amount * (*it)->MaxHealth() + (*it)->firstHPleft 
+			if( (*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
+				|| (*it)->amount * (*it)->MaxHealth() + (*it)->firstHPleft 
 				> 
 				caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)]
 			)