Explorar el Código

Support for Enchanter ability.

DjWarmonger hace 14 años
padre
commit
5e40d3da72
Se han modificado 8 ficheros con 81 adiciones y 26 borrados
  1. 10 3
      config/creatures.json
  2. 1 1
      global.h
  3. 2 1
      lib/BattleState.cpp
  4. 3 2
      lib/BattleState.h
  5. 1 1
      lib/HeroBonus.h
  6. 1 1
      lib/NetPacks.h
  7. 15 0
      lib/NetPacksLib.cpp
  8. 48 17
      server/CGameHandler.cpp

+ 10 - 3
config/creatures.json

@@ -1416,7 +1416,14 @@
 				"level": 6,
 				"name": [ "Enchanter" ],
 				"faction": -1,
-				"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ] ],			//Enchanter		//first aid tent can heal
+				"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ],
+								 [ "ENCHANTER", 3, 28, 3],		//air shield
+								 [ "ENCHANTER", 3, 41, 3],		//bless
+								 [ "ENCHANTER", 3, 45, 3],		//wealness
+								 [ "ENCHANTER", 3, 46, 3],		//stone skin
+								 [ "ENCHANTER", 3, 53, 3],		//slow
+								 [ "ENCHANTER", 3, 54, 3],		//haster
+								 [ "CASTS", 5, 0, 0]],			//Enchanter
 				"defname": "CENCH.DEF",
 				"projectile_defname": "SMBALX.DEF",
 				"projectile_spin": false
@@ -1427,8 +1434,8 @@
 				"level": 4,
 				"name": [ "Sharpshooter" ],
 				"faction": -1,
-				"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ],					//arrow turret
-							   	 [ "NO_DISTANCE_PENALTY", 0, 0, 0 ] ],			//Sharpshooter	//Ammo Cart
+				"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ],			
+							   	 [ "NO_DISTANCE_PENALTY", 0, 0, 0 ] ],			//Sharpshooter
 				"defname": "CSHARP.DEF",
 				"projectile_defname": "PELFX.DEF",
 				"projectile_spin": false

+ 1 - 1
global.h

@@ -327,7 +327,7 @@ namespace SpellCasting
 	};
 
 	enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING, //also includes cast before attack
-			MAGIC_MIRROR, CREATURE_ACTIVE_CASTING};
+			MAGIC_MIRROR, CREATURE_ACTIVE_CASTING, ENCHANTER_CASTING};
 }
 
 namespace Buildings

+ 2 - 1
lib/BattleState.cpp

@@ -1462,6 +1462,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
 	curB->heroes[1] = const_cast<CGHeroInstance*>(heroes[1]);
 	curB->round = -2;
 	curB->activeStack = -1;
+	curB->enchanterCounter[0] = curB->enchanterCounter[1] = 0; //ready to cast
 
 	if(town)
 	{
@@ -1915,7 +1916,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int play
 	if(moreGeneralProblem != SpellCasting::OK)
 		return moreGeneralProblem;
 
-	if (mode != SpellCasting::CREATURE_ACTIVE_CASTING)
+	if (mode != SpellCasting::CREATURE_ACTIVE_CASTING && mode != SpellCasting::ENCHANTER_CASTING)
 		return battleIsImmune(getHero(player), spell, mode, dest);
 	else
 		return battleIsImmune(NULL, spell, mode, dest);

+ 3 - 2
lib/BattleState.h

@@ -58,7 +58,8 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	std::vector<CStack*> stacks;
 	std::vector<CObstacleInstance> obstacles;
 	ui8 castSpells[2]; //how many spells each side has cast this turn [0] - attacker, [1] - defender
-	std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill 
+	std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill
+	si16 enchanterCounter[2]; //tends to pass through 0, so sign is needed
 	SiegeInfo si;
 	si32 battlefieldType;
 
@@ -70,7 +71,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 		h & sides & round & activeStack & siege & town & tile & stacks & belligerents & obstacles
 			& castSpells & si & battlefieldType;
 		h & heroes;
-		h & usedSpellsHistory;
+		h & usedSpellsHistory & enchanterCounter;
 		h & tacticsSide & tacticDistance;
 		h & static_cast<CBonusSystemNode&>(*this);
 	}

+ 1 - 1
lib/HeroBonus.h

@@ -135,7 +135,7 @@ namespace PrimarySkill
 	BONUS_NAME(NO_DISTANCE_PENALTY)						\
 	BONUS_NAME(NO_OBSTACLES_PENALTY)					\
 	BONUS_NAME(SELF_LUCK) /*halfling*/					\
-	BONUS_NAME(ENCHANTER)/* for Enchanter spells, subtype - spell id */ \
+	BONUS_NAME(ENCHANTER)/* for Enchanter spells, val - skill level, subtype - spell id, additionalInfo - cooldown */ \
 	BONUS_NAME(HEALER)									\
 	BONUS_NAME(SIEGE_WEAPON)							\
 	BONUS_NAME(HYPNOTIZED)								\

+ 1 - 1
lib/NetPacks.h

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

+ 15 - 0
lib/NetPacksLib.cpp

@@ -839,6 +839,11 @@ DLL_EXPORT void BattleStart::applyGs( CGameState *gs )
 DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
 {
 	gs->curB->castSpells[0] = gs->curB->castSpells[1] = 0;
+	for (int i = 0; i < 2; ++i)
+	{
+		amax(--gs->curB->enchanterCounter[i], 0);
+	}
+
 	gs->curB->round = round;
 
 	BOOST_FOREACH(CStack *s, gs->curB->stacks)
@@ -1296,6 +1301,16 @@ DLL_EXPORT void BattleSetStackProperty::applyGs(CGameState *gs)
 			amax(stack->casts, 0);
 			break;
 		}
+		case ENCHANTER_COUNTER:
+		{
+			int side = gs->curB->whatSide(stack->owner);
+			if (absolute)
+				gs->curB->enchanterCounter[side] = val;
+			else
+				gs->curB->enchanterCounter[side] += val;
+			amax(gs->curB->enchanterCounter[side], 0);
+			break;
+		}
 	}
 }
 

+ 48 - 17
server/CGameHandler.cpp

@@ -3344,13 +3344,6 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 
 			handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, NULL, secHero, 0, SpellCasting::CREATURE_ACTIVE_CASTING, stack);
 
-			BattleSetStackProperty ssp;
-			ssp.stackID = ba.stackNumber;
-			ssp.which = BattleSetStackProperty::CASTS; //reduce number of casts
-			ssp.val = -1;
-			ssp.absolute = false;
-			sendAndApply(&ssp);
-
 			sendAndApply(&end_action);
 			break;
 		}
@@ -3505,10 +3498,27 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
 	sc.attackerType = (stack ? stack->type->idNumber : -1);
 
 	//calculating affected creatures for all spells
-	std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
-	for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
+	std::set<CStack*> attackedCres;
+	if (mode != SpellCasting::ENCHANTER_CASTING)
+	{
+		attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
+		for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
+		{
+			sc.affectedCres.insert((*it)->ID);
+		}
+	}
+	else //enchanter - hit all possible stacks
 	{
-		sc.affectedCres.insert((*it)->ID);
+		BOOST_FOREACH (CStack * stack, gs->curB->stacks)
+		{
+			/*if it's non negative spell and our unit or non positive spell and hostile unit */
+			if((spell->positiveness >= 0 && stack->owner == casterColor)
+				||(spell->positiveness <= 0 && stack->owner != casterColor ))
+			{
+				if(stack->alive()) //TODO: allow dead targets somewhere in the future
+					attackedCres.insert(stack);
+			}
+		}
 	}
 
 	//checking if creatures resist
@@ -3844,6 +3854,16 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
 	if(!si.stacks.empty()) //after spellcast info shows
 		sendAndApply(&si);
 
+	if (mode == SpellCasting::CREATURE_ACTIVE_CASTING || mode == SpellCasting::ENCHANTER_CASTING) //reduce number of casts remaining
+	{
+		BattleSetStackProperty ssp;
+		ssp.stackID = stack->ID;
+		ssp.which = BattleSetStackProperty::CASTS;
+		ssp.val = -1;
+		ssp.absolute = false;
+		sendAndApply(&ssp);
+	}
+
 	//Magic Mirror effect
 	if (spell->positiveness < 0 && mode != SpellCasting::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
 	{
@@ -4007,14 +4027,25 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 				}
 			}
 		}
-		BonusList * bl = st->getBonuses(Selector::type(Bonus::ENCHANTER)).get();
-		if (bl->size())
+		BonusList bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTER)));
+		int side = gs->curB->whatSide(st->owner);
+		if (bl.size() && st->casts && !gs->curB->enchanterCounter[side])
 		{
-			bte.effect = Bonus::ENCHANTER;
-			int index = rand() % bl->size();
-			bte.val = (*bl)[index]->subtype; //spell ID
-			bte.additionalInfo = (*bl)[index]->val; //spell level
-			sendAndApply(&bte);
+			int index = rand() % bl.size();
+			int spellID = bl[index]->subtype; //spell ID
+			if (gs->curB->battleCanCastThisSpell(st->owner, VLC->spellh->spells[spellID], SpellCasting::ENCHANTER_CASTING)); //TODO: select another?
+			{
+				int spellLeveL = bl[index]->val; //spell level
+				const CGHeroInstance * enemyHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
+				handleSpellCasting(spellID, spellLeveL, -1, side, st->owner, NULL, enemyHero, 0, SpellCasting::ENCHANTER_CASTING, st);
+
+				BattleSetStackProperty ssp;
+				ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
+				ssp.absolute = false;
+				ssp.val = bl[index]->additionalInfo; //increase cooldown counter
+				ssp.stackID = st->ID;
+				sendAndApply(&ssp);
+			}
 		}
 	}
 }