소스 검색

Support for WoG "cast before attack" bonus. Minor fixes.

DjWarmonger 14 년 전
부모
커밋
79a453f442
7개의 변경된 파일39개의 추가작업 그리고 14개의 파일을 삭제
  1. 1 0
      config/bonusnames.txt
  2. 1 1
      global.h
  3. 5 0
      lib/CCreatureHandler.cpp
  4. 4 1
      lib/CCreatureSet.cpp
  5. 1 0
      lib/HeroBonus.h
  6. 24 11
      server/CGameHandler.cpp
  7. 3 1
      server/CGameHandler.h

+ 1 - 0
config/bonusnames.txt

@@ -5,6 +5,7 @@ RETURN_AFTER_STRIKE	Attack and Return	Returns after melee attack
 SPELL_RESISTANCE_AURA	Aura of Resistance	Nearby stacks get %d% resistance
 TWO_HEX_ATTACK_BREATH	Breath	Breath Attack (2-hex range)
 SPELL_AFTER_ATTACK	Caster - %s	%d% chance to cast after attack
+SPELL_BEFORE_ATTACK	Caster - %s	%d% chance to cast before attack
 CATAPULT	Catapult	Attacks siege walls
 JOUSTING	Champion Charge	+5% damage per hex travelled
 DOUBLE_DAMAGE_CHANCE	Death Blow	%d% chance for double damage

+ 1 - 1
global.h

@@ -325,7 +325,7 @@ namespace SpellCasting
 		NO_APPROPRIATE_TARGET, STACK_IMMUNE_TO_SPELL, WRONG_SPELL_TARGET
 	};
 
-	enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING};
+	enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING}; //also includes cast before attack
 }
 
 namespace Buildings

+ 5 - 0
lib/CCreatureHandler.cpp

@@ -1029,6 +1029,11 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
 		b.type= Bonus::HATE;
 		b.subtype = stringToNumber(mod);
 		break;
+	case 'p':
+		b.type = Bonus::SPELL_BEFORE_ATTACK;
+		b.subtype = stringToNumber(mod);
+		b.additionalInfo = 3; //always expert?
+		break;
 	default:
 		tlog3 << "Not parsed bonus " << buf << mod << "\n";
 		return;

+ 4 - 1
lib/CCreatureSet.cpp

@@ -620,6 +620,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
 					boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
 					break;
 				case Bonus::SPELL_AFTER_ATTACK:
+				case Bonus::SPELL_BEFORE_ATTACK:
 				{
 					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
 					boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
@@ -650,6 +651,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
 					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
 					break;
 				case Bonus::SPELL_AFTER_ATTACK:
+				case Bonus::SPELL_BEFORE_ATTACK:
 					boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
 					break;
 				case Bonus::SPELL_IMMUNITY:
@@ -683,7 +685,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
 		case Bonus::SPELL_AFTER_ATTACK:
 			fileName = "E_CAST.bmp"; break;
 			//"E_CAST1.bmp"
-			//"E_CAST2.bmp"
+		case Bonus::SPELL_BEFORE_ATTACK:
+			fileName ="E_CAST2.bmp"; break;
 			//"E_CASTER.bmp"
 		case Bonus::JOUSTING:
 			fileName = "E_CHAMP.bmp"; break;

+ 1 - 0
lib/HeroBonus.h

@@ -93,6 +93,7 @@ namespace PrimarySkill
 	BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
 	BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
 	BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
+	BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
 	BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
 	BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
 	BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/	\

+ 24 - 11
server/CGameHandler.cpp

@@ -3046,6 +3046,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			//attack
 			BattleAttack bat;
 			prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo);
+			handleAttackBeforeCasting(bat); //only before first attack
 			sendAndApply(&bat);
 			handleAfterAttackCasting(bat);
 
@@ -3096,6 +3097,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			BattleAttack bat;
 			bat.flags |= BattleAttack::SHOT;
 			prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
+			handleAttackBeforeCasting(bat);
 			sendAndApply(&bat);
 			handleAfterAttackCasting(bat);
 
@@ -3107,7 +3109,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile);
 				sendAndApply(&bat2);
 			}
-
+			//TODO: allow more than one additional attack
 			if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
 				&& curStack->alive()
 				&& destStack->alive()
@@ -3473,7 +3475,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
 					continue;
 
 				BattleStackAttacked bsa;
-				if (destination > -1 && (*it)->coversPos(destination)) //display effect only upon primary target of area spell
+				if (destination > -1 && (*it)->coversPos(destination) || spell->range[spellLvl] == "X") //display effect only upon primary target of area spell
 				{
 					bsa.flags |= BattleStackAttacked::EFFECT;
 					bsa.effect = spell->mainEffectAnim;
@@ -4317,13 +4319,12 @@ bool CGameHandler::dig( const CGHeroInstance *h )
 	return true;
 }
 
-void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
+void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker)
 {
-	const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
-	if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
+	if(attacker->hasBonusOfType(attackMode))
 	{
 		std::set<ui32> spellsToCast;
-		boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK));
+		boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(attackMode));
 		BOOST_FOREACH(const Bonus *sf, *spells)
 		{
 			spellsToCast.insert (sf->subtype);
@@ -4344,7 +4345,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 			if(oneOfAttacked == NULL) //all attacked creatures have been killed
 				return;
 			int spellLevel = 0;
-			boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID));
+			boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
 			BOOST_FOREACH(const Bonus *sf, *spellsByType)
 			{
 				amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
@@ -4352,24 +4353,36 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 				if (meleeRanged == 0 || (meleeRanged == 1 && bat.shot()) || (meleeRanged == 2 && !bat.shot()))
 					castMe = true;
 			}
-			int chance = attacker->valOfBonuses((Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID)));
+			int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID)));
 			amin (chance, 100);
 			int destination = oneOfAttacked->position;
 
 			const CSpell * spell = VLC->spellh->spells[spellID];
-			if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position)
-				!= SpellCasting::OK)
+			if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position) != SpellCasting::OK)
 				continue;
 
 			//check if spell should be casted (probability handling)
 			if(rand()%100 >= chance)
 				continue;
 
-			//casting
+			//casting //TODO: check if spell can be blocked or target is immune
 			if (castMe) //stacks use 0 spell power. If needed, default = 3 or custom value is used
 				handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, 0, SpellCasting::AFTER_ATTACK_CASTING, attacker);
 		}
 	}
+}
+
+void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
+{
+	const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
+	attackCasting(bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no detah stare / acid bretah needed?
+}
+
+void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
+{
+	const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
+	attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
+
 	if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79
 	{
 		int staredCreatures = 0;

+ 3 - 1
server/CGameHandler.h

@@ -249,7 +249,9 @@ public:
 
 	void run(bool resume);
 	void newTurn();
-	void handleAfterAttackCasting( const BattleAttack & bat );
+	void handleAttackBeforeCasting (const BattleAttack & bat);
+	void handleAfterAttackCasting (const BattleAttack & bat);
+	void attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker);
 	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot);
 	friend class CVCMIServer;
 	friend class CScriptCallback;