Browse Source

- Restored Genie random spell
- Fixed crashes in many strange creature-spellcasting scenarios, including stack with multiple cast abilities and Enchanter with non-stadard spell

DjWarmonger 13 years ago
parent
commit
cd1a9414ac
3 changed files with 45 additions and 26 deletions
  1. 33 23
      client/BattleInterface/CBattleInterface.cpp
  2. 2 1
      client/CPlayerInterface.cpp
  3. 10 2
      server/CGameHandler.cpp

+ 33 - 23
client/BattleInterface/CBattleInterface.cpp

@@ -1564,8 +1564,11 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
 	case Spells::LIGHTNING_BOLT:
 	case Spells::TITANS_LIGHTNING_BOLT:
 	case Spells::THUNDERBOLT:
-		displayEffect(1, sc->tile);
-		displayEffect(spell.mainEffectAnim, sc->tile);
+		for (auto it = sc->affectedCres.begin(); it != sc->affectedCres.end(); ++it) //in case we have multiple targets
+		{
+			displayEffect(1, curInt->cb->battleGetStackByID(*it, false)->position);
+			displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(*it, false)->position);
+		}
 		break;
 	case Spells::DISPEL:
 	case Spells::CURE:
@@ -2668,6 +2671,8 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 	bool noStackIsHovered = true; //will cause removing a blue glow
 	
 	localActions.clear();
+	illegalActions.clear();
+
 	BOOST_FOREACH (PossibleActions action, possibleActions)
 	{
 		bool legalAction = false; //this action is legal and can't be performed
@@ -2709,11 +2714,11 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 					legalAction = true;
 				break;
 			case HOSTILE_CREATURE_SPELL: //TODO: check spell immunity
-				if (shere && !ourStack && isCastingPossibleHere (sactive, shere, myNumber))
+				if (shere && shere->alive() && !ourStack && isCastingPossibleHere (sactive, shere, myNumber))
 					legalAction = true;
 				break;
 			case FRIENDLY_CREATURE_SPELL:
-				if (shere && ourStack && isCastingPossibleHere (sactive, shere, myNumber))
+				if (shere && shere->alive() && ourStack && isCastingPossibleHere (sactive, shere, myNumber))
 					legalAction = true;
 				break;
 			case RISING_SPELL:
@@ -2727,7 +2732,6 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 					int spellID = curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE);
 					if (spellID > -1)
 					{
-						sp = CGI->spellh->spells[spellID];
 						legalAction = true;
 					}
 				}
@@ -2867,22 +2871,21 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 			case HOSTILE_CREATURE_SPELL:
 			case FRIENDLY_CREATURE_SPELL:
 			case RISING_SPELL:
-			case RANDOM_GENIE_SPELL:
-				if (sp)
+				sp = CGI->spellh->spells[creatureCasting ? creatureSpellToCast : spellToCast->additionalInfo]; //necessary if creature has random Genie spell at same time
+				consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % sp->name % shere->getName()); //Cast %s on %s
+				switch (sp->id)
 				{
-					consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % sp->name % shere->getName()); //Cast %s on %s
-					switch (sp->id)
-					{
-						case Spells::TELEPORT:
-						case Spells::SACRIFICE:
-							secondaryTarget = true;
-							break;
-					}
-					isCastingPossible = true;
+					case Spells::TELEPORT:
+					case Spells::SACRIFICE:
+						secondaryTarget = true;
+						break;
 				}
-				else //spell is random
-					consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[301]) % shere->getName()); //Cast a spell on %
-				//we assume that teleport / sacrifice will never be avaliable as random spell
+				isCastingPossible = true;
+				break;
+			case RANDOM_GENIE_SPELL: //we assume that teleport / sacrifice will never be avaliable as random spell
+				sp = NULL;
+				consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[301]) % shere->getName()); //Cast a spell on %
+				isCastingPossible = true;
 				break;
 			case TELEPORT:
 				consoleMsg = CGI->generaltexth->allTexts[25]; //Teleport Here
@@ -2975,7 +2978,14 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 			{
 				if(creatureCasting)
 				{
-					giveCommand(BattleAction::MONSTER_SPELL, myNumber, sactive->ID, creatureSpellToCast);
+					if (sp)
+					{
+						giveCommand(BattleAction::MONSTER_SPELL, myNumber, sactive->ID, creatureSpellToCast);
+					}
+					else //unknown random spell
+					{
+						giveCommand(BattleAction::MONSTER_SPELL, myNumber, sactive->ID, curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE));
+					}
 				}
 				else
 				{
@@ -2995,17 +3005,17 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 
 bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CStack * shere, BattleHex myNumber)
 {
-	creatureCasting = (stackCanCastSpell) && (shere != sactive); //is it really useful?
+	creatureCasting = stackCanCastSpell; //is it really useful?
 							
 	bool isCastingPossible = true;
 
 	int spellID = -1;
 	if (creatureCasting)
 	{
-		if (creatureSpellToCast > -1)
+		if (creatureSpellToCast > -1 && (shere != sactive)) //can't cast on itself
 			spellID = creatureSpellToCast; //TODO: merge with SpellTocast?
 	}
-	else if(spellDestSelectMode) //hero casting
+	else //hero casting
 		spellID  = spellToCast->additionalInfo;
 
 	sp = NULL;

+ 2 - 1
client/CPlayerInterface.cpp

@@ -835,7 +835,8 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
 			if (defender && !i->isSecondary())
 				battleInt->displayEffect(i->effect, defender->position);
 		}
-		StackAttackedInfo to_put = {defender, i->damageAmount, i->killedAmount, attacker, LOCPLINT->curAction->actionType==7, i->killed(), i->willRebirth(), i->cloneKilled()};
+		bool shooting = (LOCPLINT->curAction ? LOCPLINT->curAction->actionType == BattleAction::SHOOT : false); //FIXME: why action is deleted during enchanter cast?
+		StackAttackedInfo to_put = {defender, i->damageAmount, i->killedAmount, attacker, shooting, i->killed(), i->willRebirth(), i->cloneKilled()};
 		arg.push_back(to_put);
 	}
 

+ 10 - 2
server/CGameHandler.cpp

@@ -3561,7 +3561,9 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 				|| (!spell->isPositive() && stack->owner != casterColor))
 			{
 				if(stack->isValidTarget()) //TODO: allow dead targets somewhere in the future
+				{
 					attackedCres.insert(stack);
+				}
 			}
 		}
 	}
@@ -3619,7 +3621,8 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 					continue;
 
 				BattleStackAttacked bsa;
-				if ((destination > -1 && (*it)->coversPos(destination)) || spell->range[spellLvl] == "X") //display effect only upon primary target of area spell
+				if ((destination > -1 && (*it)->coversPos(destination)) || (spell->range[spellLvl] == "X" || mode == ECastingMode::ENCHANTER_CASTING))
+					//display effect only upon primary target of area spell
 				{
 					bsa.flags |= BattleStackAttacked::EFFECT;
 					bsa.effect = spell->mainEffectAnim;
@@ -3632,7 +3635,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
 					sc.dmgToDisplay += bsa.damageAmount;
 				}
 				bsa.stackAttacked = (*it)->ID;
-				bsa.attackerID = -1;
+				if (mode == ECastingMode::ENCHANTER_CASTING) //multiple damage spells cast
+					bsa.attackerID = stack->ID;
+				else
+					bsa.attackerID = -1;
 				(*it)->prepareAttacked(bsa);
 				si.stacks.push_back(bsa);
 			}
@@ -4769,6 +4775,8 @@ void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
 void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 {
 	const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
+	if (!attacker) //could be already dead
+		return;
 	attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
 
 	if(bat.bsa[0].newAmount <= 0)