Przeglądaj źródła

* fixed remaining parts of #760
* it's possible to switch active creature during tacts phase by clicking on stack
* a few minor fixes after handleHex rewrite

Michał W. Urbańczyk 13 lat temu
rodzic
commit
c61f536d8b

+ 34 - 17
client/BattleInterface/CBattleInterface.cpp

@@ -221,7 +221,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	console->pos.h = 38;
 	if(tacticsMode)
 	{
-		btactNext = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bTacticNextStack,this), 213 + pos.x, 560 + pos.y, "icm011.def", SDLK_SPACE);
+		btactNext = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)NULL), 213 + pos.x, 560 + pos.y, "icm011.def", SDLK_SPACE);
 		btactEnd = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bEndTacticPhase,this), 419 + pos.x, 560 + pos.y, "icm012.def", SDLK_RETURN);
 		bDefence->block(true);
 		bWait->block(true);
@@ -1364,17 +1364,22 @@ void CBattleInterface::newRound(int number)
 
 }
 
-void CBattleInterface::giveCommand(ui8 action, BattleHex tile, ui32 stack, si32 additional)
+void CBattleInterface::giveCommand(ui8 action, BattleHex tile, ui32 stackID, si32 additional)
 {
-	if(!curInt->cb->battleGetStackByID(stack) && action != 1 && action != 4 && action != 5)
+	const CStack *stack = curInt->cb->battleGetStackByID(stackID);
+	if(!stack && action != BattleAction::HERO_SPELL && action != BattleAction::RETREAT && action != BattleAction::SURRENDER)
 	{
 		return;
 	}
+
+	if(stack && stack != activeStack)
+		tlog3 << "Warning: giving an order to a non-active stack?\n";
+
 	BattleAction * ba = new BattleAction(); //is deleted in CPlayerInterface::activeStack()
 	ba->side = defendingHeroInstance ? (curInt->playerID == defendingHeroInstance->tempOwner) : false;
 	ba->actionType = action;
 	ba->destinationTile = tile;
-	ba->stackNumber = stack;
+	ba->stackNumber = stackID;
 	ba->additionalInfo = additional;
 
 	//some basic validations
@@ -1391,6 +1396,7 @@ void CBattleInterface::giveCommand(ui8 action, BattleHex tile, ui32 stack, si32
 
 	if(!tacticsMode)
 	{
+		tlog5 << "Setting command for " << (stack ? stack->nodeName() : "hero") << std::endl;
 		myTurn = false;
 		activeStack = NULL;
 		givenCommand->setn(ba);
@@ -1399,7 +1405,8 @@ void CBattleInterface::giveCommand(ui8 action, BattleHex tile, ui32 stack, si32
 	{
 		curInt->cb->battleMakeTacticAction(ba);
 		vstd::clear_pointer(ba);
-		bTacticNextStack();
+		activeStack = NULL;
+		//next stack will be activated when action ends
 	}
 }
 
@@ -1415,7 +1422,7 @@ bool CBattleInterface::isTileAttackable(const BattleHex & number) const
 
 bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
 {
-	if(!siegeH)
+	if(!siegeH  ||  tacticsMode)
 		return false;
 
 	int wallUnder = curInt->cb->battleGetWallUnderHex(hex);
@@ -2298,6 +2305,7 @@ void CBattleInterface::projectileShowHelper(SDL_Surface * to)
 
 void CBattleInterface::endAction(const BattleAction* action)
 {
+	const CStack * stack = curInt->cb->battleGetStackByID(action->stackNumber);
 	//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
 // 	{
 // 		activate();
@@ -2311,7 +2319,6 @@ void CBattleInterface::endAction(const BattleAction* action)
 	}
 	if(action->actionType == BattleAction::WALK && creAnims[action->stackNumber]->getType() != 2) //walk or walk & attack
 	{
-		const CStack * stack = curInt->cb->battleGetStackByID(action->stackNumber);
 		pendingAnims.push_back(std::make_pair(new CMovementEndAnimation(this, stack, action->destinationTile), false));
 	}
 	if(action->actionType == BattleAction::CATAPULT) //catapult
@@ -2335,8 +2342,10 @@ void CBattleInterface::endAction(const BattleAction* action)
 
 	queue->update();
 
-	if(tacticsMode  //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
-		|| action->actionType == BattleAction::HERO_SPELL)
+	if(tacticsMode) //stack ended movement in tactics phase -> select the next one
+		bTacticNextStack(stack); 
+
+	if( action->actionType == BattleAction::HERO_SPELL) //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
 		redrawBackgroundWithHexes(activeStack);
 }
 
@@ -2475,6 +2484,7 @@ void CBattleInterface::waitForAnims()
 
 void CBattleInterface::bEndTacticPhase()
 {
+	activeStack = NULL;
 	btactEnd->block(true);
 	tacticsMode = false;
 }
@@ -2484,15 +2494,17 @@ static bool immobile(const CStack *s)
 	return !s->Speed(0, true); //should bound stacks be immobile?
 }
 
-void CBattleInterface::bTacticNextStack()
+void CBattleInterface::bTacticNextStack(const CStack *current /*= NULL*/)
 {
+	if(!current)
+		current = activeStack;
+
 	//no switching stacks when the current one is moving
-	if(animsAreDisplayed.get())
-		return;
+	waitForAnims();
 
 	TStacks stacksOfMine = tacticianInterface->cb->battleGetStacks(CBattleCallback::ONLY_MINE);
 	stacksOfMine.erase(std::remove_if(stacksOfMine.begin(), stacksOfMine.end(), &immobile), stacksOfMine.end());
-	TStacks::iterator it = vstd::find(stacksOfMine, activeStack);
+	TStacks::iterator it = vstd::find(stacksOfMine, current);
 	if(it != stacksOfMine.end() && ++it != stacksOfMine.end())
 		stackActivated(*it);
 	else
@@ -2605,7 +2617,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 			else
 				isCastingPossible = (curInt->cb->battleCanCastThisSpell(sp, myNumber) == ESpellCastProblem::OK);
 		}
-		else if(shere)
+		else if(shere && shere->alive())
 		{
 			//needed for genie, otherwise covered by battleCan*CastThisSpell
 			if(spellSelMode == HOSTILE_CREATURE && shere->owner == sactive->owner
@@ -2694,7 +2706,12 @@ pastCastingSpells:
 			{
 				if (shere->alive())
 				{
-					if(sactive->hasBonusOfType(Bonus::HEALER) && shere->canBeHealed()) //heal
+					if(tacticsMode) //select stack in tactics mdoe
+					{
+						consoleMsg = (boost::format(CGI->generaltexth->allTexts[481]) % shere->getName()).str(); //Select %s
+						realizeAction = [=]{ stackActivated(shere); };
+					}
+					else if(sactive->hasBonusOfType(Bonus::HEALER) && shere->canBeHealed()) //heal
 					{
 						cursorFrame = ECursor::COMBAT_HEAL;
 						consoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
@@ -2717,9 +2734,9 @@ pastCastingSpells:
 					{
 						hoveredStackAnim->playOnce(CCreatureAnim::MOUSEON);
 						lastMouseHoveredStackAnimationTime = curTime;
-						mouseHoveredStack = shere->ID;
-						noStackIsHovered = false;
 					}
+					noStackIsHovered = false;
+					mouseHoveredStack = shere->ID;
 				} //end of alive
 				else if (sactive->hasBonusOfType(Bonus::DAEMON_SUMMONING) && sactive->casts)
 				{

+ 2 - 2
client/BattleInterface/CBattleInterface.h

@@ -142,7 +142,7 @@ private:
 
 	std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield
 	void projectileShowHelper(SDL_Surface * to); //prints projectiles present on the battlefield
-	void giveCommand(ui8 action, BattleHex tile, ui32 stack, si32 additional=-1);
+	void giveCommand(ui8 action, BattleHex tile, ui32 stackID, si32 additional=-1);
 	bool isTileAttackable(const BattleHex & number) const; //returns true if tile 'number' is neighboring any tile from active stack's range or is one of these tiles
 	bool isCatapultAttackable(BattleHex hex) const; //returns true if given tile can be attacked by catapult
 
@@ -210,7 +210,7 @@ public:
 	void bDefencef();
 	void bConsoleUpf();
 	void bConsoleDownf();
-	void bTacticNextStack();
+	void bTacticNextStack(const CStack *current = NULL);
 	void bEndTacticPhase();
 	//end of button handle funcs
 	//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem

+ 4 - 1
client/CPlayerInterface.cpp

@@ -729,8 +729,10 @@ void CPlayerInterface::actionFinished(const BattleAction* action)
 
 BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack
 {
-
+	tlog5 << "Awaiting command for " << stack->nodeName() << std::endl;
 	CBattleInterface *b = battleInt;
+
+	assert(!b->givenCommand->get()); //command buffer must be clean (we don't want to use old command)
 	{
 		boost::unique_lock<boost::recursive_mutex> un(*pim);
 		b->stackActivated(stack);
@@ -751,6 +753,7 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
 	b->givenCommand->data = NULL;
 
 	//return command
+	tlog5 << "Giving command for " << stack->nodeName() << std::endl;
 	return ret;
 }
 

+ 8 - 4
lib/BattleState.cpp

@@ -265,7 +265,7 @@ void BattleInfo::makeBFS(BattleHex start, bool *accessibility, BattleHex *predec
 	}
 };
 
-std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable ) const
+std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable /*= NULL*/, bool forPassingBy /*= false*/ ) const
 {
 	std::vector<BattleHex> ret;
 	bool ac[GameConstants::BFIELD_SIZE];
@@ -314,7 +314,11 @@ std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool
 	{
 		bool rangeFits;
 		if (tacticDistance)
-			rangeFits = isInTacticRange(i);
+		{
+			rangeFits = pr[i] >= 0; //reachable in terms of obstacles
+			if(!forPassingBy) //only if we're passing through, we may step out of the tactic range -> otherwise check range
+				rangeFits = rangeFits && isInTacticRange(i);
+		}
 		else
 			rangeFits = dist[i] <= stack->Speed(0, true); //we can reach the stack
 
@@ -1965,9 +1969,9 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int
 		if(spell->id == Spells::ANIMATE_DEAD  &&  !stackUnder->hasBonusOfType(Bonus::UNDEAD))
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
 	}
-	if(spell->getTargetType() == CSpell::CREATURE  ||  spell->getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE)
+	else if(spell->getTargetType() == CSpell::CREATURE  ||  spell->getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE)
 	{
-		if(!stackUnder)
+		if(!stackUnder || !stackUnder->alive())
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
 		if(spell->isNegative() && stackUnder->owner == player)
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;

+ 1 - 1
lib/BattleState.h

@@ -94,7 +94,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
 	int getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
 	void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
 	std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
-	std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL) const; //returns vector of accessible tiles (taking into account the creature range)
+	std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
 
 	bool isObstacleOnTile(BattleHex tile) const;
 	bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack

+ 3 - 2
server/CGameHandler.cpp

@@ -705,7 +705,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 
 	//initing necessary tables
 	bool accessibility[GameConstants::BFIELD_SIZE];
-	std::vector<BattleHex> accessible = gs->curB->getAccessibility(curStack, false);
+	std::vector<BattleHex> accessible = gs->curB->getAccessibility(curStack, false, NULL, true);
 	for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
 	{
 		accessibility[b] = false;
@@ -734,7 +734,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 		return 0;
 
 	bool accessibilityWithOccupyable[GameConstants::BFIELD_SIZE];
-	std::vector<BattleHex> accOc = gs->curB->getAccessibility(curStack, true);
+	std::vector<BattleHex> accOc = gs->curB->getAccessibility(curStack, true, NULL, true);
 	for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
 	{
 		accessibilityWithOccupyable[b] = false;
@@ -5486,6 +5486,7 @@ void CGameHandler::runBattle()
 					}
 					else
 					{
+						tlog5 << "Activating " << next->nodeName() << std::endl;
 						BattleSetActiveStack sas;
 						sas.stack = next->ID;
 						sendAndApply(&sas);