浏览代码

Support for Bind ability.

DjWarmonger 14 年之前
父节点
当前提交
95f23cf20f
共有 6 个文件被更改,包括 64 次插入14 次删除
  1. 1 1
      client/CBattleInterface.cpp
  2. 25 11
      lib/BattleState.cpp
  3. 2 1
      lib/BattleState.h
  4. 1 1
      lib/NetPacks.h
  5. 5 0
      lib/NetPacksLib.cpp
  6. 30 0
      server/CGameHandler.cpp

+ 1 - 1
client/CBattleInterface.cpp

@@ -4129,7 +4129,7 @@ void CBattleInterface::bEndTacticPhase()
 
 static bool immobile(const CStack *s)
 {
-	return !s->Speed();
+	return !s->Speed(0, true); //should bound stacks be immobile?
 }
 
 void CBattleInterface::bTacticNextStack()

+ 25 - 11
lib/BattleState.cpp

@@ -315,15 +315,17 @@ std::vector<THex> BattleInfo::getAccessibility( const CStack * stack, bool addOc
 		}
 	}
 	
-	for (int i=0; i < BFIELD_SIZE ; ++i)
+	for (int i = 0; i < BFIELD_SIZE; ++i)
 	{
-		bool rangeFits = tacticDistance 
-						? isInTacticRange(i)
-						: dist[i] <= stack->Speed();
+		bool rangeFits;
+		if (tacticDistance)
+			rangeFits = isInTacticRange(i);
+		else
+			rangeFits = dist[i] <= stack->Speed(0, true); //we can reach the stack
 
 		if(	( !addOccupiable && rangeFits && ac[i] ) 
 			|| ( addOccupiable && rangeFits && isAccessible(i, ac, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), true) )//we can reach it
-			|| (vstd::contains(occupyable, i) && (!tacticDistance && dist[ i + (stack->attackerOwned ? 1 : -1 ) ] <= stack->Speed() ) && ac[i + (stack->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
+			|| (vstd::contains(occupyable, i) && (!tacticDistance && dist[ i + (stack->attackerOwned ? 1 : -1 ) ] <= stack->Speed(0, true) ) && ac[i + (stack->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
 			)
 		{
 			ret.push_back(i);
@@ -918,6 +920,20 @@ std::set<THex> BattleInfo::getAttackedHexes(const CStack* attacker, THex destina
 	return attackedHexes;
 }
 
+std::set<CStack*> BattleInfo::getAdjacentCreatures (const CStack * stack)
+{
+	std::set<CStack*> stacks;
+
+	CStack * localStack;
+	BOOST_FOREACH (THex hex, stack->getSurroundingHexes())
+	{
+		localStack = getStackT(hex, true); //only alive?
+		if (localStack)
+			stacks.insert(localStack);
+	}
+	return stacks;
+}
+
 int BattleInfo::calculateSpellDuration( const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower)
 {
 	if(!caster)
@@ -2306,7 +2322,7 @@ void CStack::postInit()
 	state.insert(ALIVE);  //alive state indication
 }
 
-ui32 CStack::Speed( int turn /*= 0*/ ) const
+ui32 CStack::Speed( int turn /*= 0*/ , bool useBind /* = false*/) const
 {
 	if(hasBonus(Selector::type(Bonus::SIEGE_WEAPON) && Selector::turns(turn))) //war machines cannot move
 		return 0;
@@ -2324,8 +2340,8 @@ ui32 CStack::Speed( int turn /*= 0*/ ) const
 
 	speed = ((100 + percentBonus) * speed)/100;
 
-	//bind effect check
-	if(getEffect(72)) 
+	//bind effect check - doesn't influence stack initiative
+	if (useBind && getEffect(72)) 
 	{
 		return 0;
 	}
@@ -2493,9 +2509,7 @@ void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
 		sf.back().sid = sse.sid;
 		break;
 	case 72: //Bind
-		sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -100, 1, Bonus::PERCENT_TO_ALL)); //sets speed to zero
-		sf.back().sid = sse.sid;
-		sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 0)); //marker, TODO: handle it
+		sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 1)); //marker
 		sf.back().duration = Bonus::PERMANENT;
 	 	sf.back().sid = sse.sid;
 		break;

+ 2 - 1
lib/BattleState.h

@@ -103,6 +103,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, THex destinationTile, THex attackerPos); //hexes around target that could be attacked in melee
 	std::set<CStack*> getAttackedCreatures(const CStack* attacker, THex destinationTile, THex attackerPos = THex::INVALID); //calculates range of multi-hex attacks
 	std::set<THex> getAttackedHexes(const CStack* attacker, THex destinationTile, THex attackerPos = THex::INVALID); //calculates range of multi-hex attacks
+	std::set<CStack*> getAdjacentCreatures (const CStack * stack);
 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower);
 	CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, THex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
 	CStack * generateNewStack(const CStackBasicDescriptor &base, int stackID, bool attackerOwned, int slot, THex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
@@ -180,7 +181,7 @@ public:
 	bool ableToRetaliate() const; //if stack can retaliate after attacked
 	bool moved(int turn = 0) const; //if stack was already moved this turn
 	bool canMove(int turn = 0) const; //if stack can move
-	ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
+	ui32 Speed(int turn = 0, bool useBind = false) const; //get speed of creature with all modificators
 	static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);
 	std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
 	const CGHeroInstance *getMyHero() const; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise

+ 1 - 1
lib/NetPacks.h

@@ -1508,7 +1508,7 @@ struct BattleSetStackProperty : public CPackForClient //3018
 {
 	BattleSetStackProperty(){type = 3018;};
 
-	enum BattleStackProperty {CASTS, ENCHANTER_COUNTER};
+	enum BattleStackProperty {CASTS, ENCHANTER_COUNTER, UNBIND};
 
 	DLL_EXPORT void applyGs(CGameState *gs);
 	//void applyCl(CClient *cl){};

+ 5 - 0
lib/NetPacksLib.cpp

@@ -1304,6 +1304,11 @@ DLL_EXPORT void BattleSetStackProperty::applyGs(CGameState *gs)
 			amax(gs->curB->enchanterCounter[side], 0);
 			break;
 		}
+		case UNBIND:
+		{
+			stack->popBonuses(Selector::type(Bonus::BIND_EFFECT));
+			break;
+		}
 	}
 }
 

+ 30 - 0
server/CGameHandler.cpp

@@ -3663,6 +3663,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
 			pseudoBonus.val = spellLvl;
 			pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, stackSpellPower ? stackSpellPower : usedSpellPower);
 			CStack::stackEffectToFeature(sse.effect, pseudoBonus);
+			if (spellID == 72 && stack)//bind
+			{
+				sse.effect.back().additionalInfo = stack->ID; //we need to know who casted Bind
+			}
 			const Bonus * bonus = NULL;
 			if (caster)
 				bonus = caster->getBonus(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
@@ -3984,6 +3988,32 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 	bte.additionalInfo = 0;
 	if (st->alive())
 	{
+		//unbind
+		if (st->getEffect(72))
+		{
+			bool unbind = true;
+			BonusList bl = *(st->getBonuses(Selector::type(Bonus::BIND_EFFECT)));
+			std::set<CStack*> stacks = gs->curB->getAdjacentCreatures(st);
+
+			BOOST_FOREACH(Bonus * b, bl)
+			{
+				const CStack * stack = gs->curB->getStack(b->additionalInfo); //binding stack must be alive and adjacent
+				if (stack)
+				{
+					if (vstd::contains(stacks, stack)) //binding stack is still present
+					{
+						unbind = false;
+					}
+				}
+			}
+			if (unbind)
+			{
+				BattleSetStackProperty ssp;
+				ssp.which = BattleSetStackProperty::UNBIND;
+				ssp.stackID = st->ID;
+				sendAndApply(&ssp);
+			}
+		}
 		//regeneration
 		if(st->hasBonusOfType(Bonus::HP_REGENERATION))
 		{