Browse Source

Improved creature casting GUI.
* "F" is new hotkey for creature spells
* creature spells now have lowest priority unless F pressed
* creatures can cast NO_LOCATION spells (only with hotkey)

AlexVinS 9 years ago
parent
commit
b256c4c36d
2 changed files with 91 additions and 17 deletions
  1. 87 16
      client/battle/CBattleInterface.cpp
  2. 4 1
      client/battle/CBattleInterface.h

+ 87 - 16
client/battle/CBattleInterface.cpp

@@ -583,7 +583,11 @@ void CBattleInterface::keyPressed(const SDL_KeyboardEvent & key)
 			showQueue();
 
 	}
-	else if(key.keysym.sym == SDLK_ESCAPE && spellDestSelectMode)
+	else if(key.keysym.sym == SDLK_f && key.state == SDL_PRESSED)
+	{
+		enterCreatureCastingMode();
+	}
+	else if(key.keysym.sym == SDLK_ESCAPE)
 	{
 		endCastingSpell();
 	}
@@ -773,7 +777,7 @@ void CBattleInterface::setBattleCursor(const int myNumber)
 
 void CBattleInterface::clickRight(tribool down, bool previousState)
 {
-	if(!down && spellDestSelectMode)
+	if(!down)
 	{
 		endCastingSpell();
 	}
@@ -1596,29 +1600,84 @@ void CBattleInterface::activateStack()
 		creatureSpellToCast = -1;
 	}
 
-	getPossibleActionsForStack (s);
+	getPossibleActionsForStack(s, false);
 
 	GH.fakeMouseMove();
 }
 
 void CBattleInterface::endCastingSpell()
 {
-	assert(spellDestSelectMode);
+	if(spellDestSelectMode)
+	{
+		vstd::clear_pointer(spellToCast);
 
-	vstd::clear_pointer(spellToCast);
+		sp = nullptr;
+		spellDestSelectMode = false;
+		CCS->curh->changeGraphic(ECursor::COMBAT, ECursor::COMBAT_POINTER);
 
-	sp = nullptr;
-	spellDestSelectMode = false;
-	CCS->curh->changeGraphic(ECursor::COMBAT, ECursor::COMBAT_POINTER);
+		if (activeStack)
+		{
+			getPossibleActionsForStack(activeStack, false); //restore actions after they were cleared
+			myTurn = true;
+		}
+	}
+	else
+	{
+		if (activeStack)
+		{
+			getPossibleActionsForStack(activeStack, false);
+			GH.fakeMouseMove();
+		}
+	}
+}
 
-	if (activeStack)
+void CBattleInterface::enterCreatureCastingMode()
+{
+	//silently check for possible errors
+	if(!myTurn)
+		return;
+
+	if(tacticsMode)
+		return;
+
+    //hero is casting a spell
+	if(spellDestSelectMode)
+		return;
+
+	if(!activeStack)
+		return;
+
+	if(!stackCanCastSpell)
+		return;
+
+	//random spellcaster
+	if(creatureSpellToCast == -1)
+		return;
+
+	if(vstd::contains(possibleActions, NO_LOCATION))
+	{
+		const ISpellCaster * caster = activeStack;
+		const CSpell * spell = SpellID(creatureSpellToCast).toSpell();
+
+		const bool isCastingPossible = (curInt->cb->battleCanCastThisSpellHere(caster, spell, ECastingMode::CREATURE_ACTIVE_CASTING, BattleHex::INVALID) == ESpellCastProblem::OK);
+
+		if(isCastingPossible)
+		{
+			myTurn = false;
+			giveCommand(Battle::MONSTER_SPELL, BattleHex::INVALID, activeStack->ID, creatureSpellToCast);
+			selectedStack = nullptr;
+
+			CCS->curh->changeGraphic(ECursor::COMBAT, ECursor::COMBAT_POINTER);
+		}
+	}
+	else
 	{
-		getPossibleActionsForStack (activeStack); //restore actions after they were cleared
-		myTurn = true;
+		getPossibleActionsForStack(activeStack, true);
+		GH.fakeMouseMove();
 	}
 }
 
-void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
+void CBattleInterface::getPossibleActionsForStack(const CStack * stack, const bool forceCast)
 {
 	possibleActions.clear();
 	if (tacticsMode)
@@ -1628,6 +1687,7 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
 	}
 	else
 	{
+		PossibleActions notPriority = INVALID;
 		//first action will be prioritized over later ones
 		if (stack->casts) //TODO: check for battlefield effects that prevent casting?
 		{
@@ -1637,10 +1697,16 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
 				{
 					const CSpell * spell = SpellID(creatureSpellToCast).toSpell();
 					PossibleActions act = getCasterAction(spell, stack, ECastingMode::CREATURE_ACTIVE_CASTING);
-					if(act == NO_LOCATION)
-						logGlobal->error("NO_LOCATION action target is not yet supported for creatures");
-					else
+
+					if (forceCast)
+					{
+						//forced action to be only one possible
 						possibleActions.push_back(act);
+						return;
+					}
+					else
+						//if cast is not forced, cast action will have lowest priority
+						notPriority = act;
 				}
 			}
 			if (stack->hasBonusOfType (Bonus::RANDOM_SPELLCASTER))
@@ -1663,6 +1729,9 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
 			possibleActions.push_back (CATAPULT);
 		if (stack->hasBonusOfType (Bonus::HEALER))
 			possibleActions.push_back (HEAL);
+
+		if (notPriority != INVALID)
+			possibleActions.push_back(notPriority);
 	}
 }
 
@@ -2004,6 +2073,8 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 	localActions.clear();
 	illegalActions.clear();
 
+	const bool forcedAction = possibleActions.size() == 1;
+
 	for (PossibleActions action : possibleActions)
 	{
 		bool legalAction = false; //this action is legal and can be performed
@@ -2125,7 +2196,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 		}
 		if (legalAction)
 			localActions.push_back (action);
-		else if (notLegal)
+		else if (notLegal || forcedAction)
 			illegalActions.push_back (action);
 	}
 	illegalAction = INVALID; //clear it in first place

+ 4 - 1
client/battle/CBattleInterface.h

@@ -174,9 +174,12 @@ private:
 
 	void requestAutofightingAIToTakeAction();
 
-	void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn
+	void getPossibleActionsForStack (const CStack * stack, const bool forceCast); //called when stack gets its turn
 	void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
 
+	//force active stack to cast a spell if possible
+	void enterCreatureCastingMode();
+
 	void printConsoleAttacked(const CStack * defender, int dmg, int killed, const CStack * attacker, bool Multiple);
 
 	std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield