Browse Source

* more or less fixed spells
* certain hero specialties are still broken

mateuszb 14 years ago
parent
commit
824d2b52db
7 changed files with 233 additions and 230 deletions
  1. 18 12
      client/CBattleInterface.cpp
  2. 166 165
      lib/BattleState.cpp
  3. 9 9
      lib/BattleState.h
  4. 19 13
      lib/HeroBonus.h
  5. 1 1
      lib/NetPacks.h
  6. 10 22
      lib/NetPacksLib.cpp
  7. 10 8
      server/CGameHandler.cpp

+ 18 - 12
client/CBattleInterface.cpp

@@ -2788,26 +2788,32 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
 
 void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
 {
-	if(sse.effect.id != -1) //can be -1 for defensive stance effect
+	int effID = sse.effect.back().id;
+	if(effID != -1) //can be -1 for defensive stance effect
 	{
 		for(std::vector<ui32>::const_iterator ci = sse.stacks.begin(); ci!=sse.stacks.end(); ++ci)
 		{
-			displayEffect(CGI->spellh->spells[sse.effect.id]->mainEffectAnim, curInt->cb->battleGetStackByID(*ci)->position);
+			displayEffect(CGI->spellh->spells[effID]->mainEffectAnim, curInt->cb->battleGetStackByID(*ci)->position);
 		}
 	}
-	else if (sse.effect.source == Bonus::OTHER && sse.effect.type == Bonus::PRIMARY_SKILL && sse.stacks.size() == 1)
+	else if (sse.stacks.size() == 1 && sse.effect.size() == 1)
 	{
-		//defensive stance (I hope)
-		const CStack * stack = LOCPLINT->cb->battleGetStackByID(*sse.stacks.begin());
-		int txtid = 120;
+		const Bonus & bns = sse.effect.back();
+		if (bns.source == Bonus::OTHER && bns.type == Bonus::PRIMARY_SKILL)
+		{
+			//defensive stance (I hope)
+			const CStack * stack = LOCPLINT->cb->battleGetStackByID(*sse.stacks.begin());
+			int txtid = 120;
 
-		if(stack->count != 1)
-			txtid++; //move to plural text
+			if(stack->count != 1)
+				txtid++; //move to plural text
 
-		char txt[4000];
-		int val = stack->Defense() - (stack->Defense() * 100 )/ (100 + sse.effect.val);
-		sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->count != 1) ? stack->getCreature()->namePl.c_str() : stack->getCreature()->nameSing.c_str(), val);
-		console->addText(txt);
+			char txt[4000];
+			int val = stack->Defense() - (stack->Defense() * 100 )/ (100 + bns.val);
+			sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->count != 1) ? stack->getCreature()->namePl.c_str() : stack->getCreature()->nameSing.c_str(), val);
+			console->addText(txt);
+		}
+		
 	}
 
 

+ 166 - 165
lib/BattleState.cpp

@@ -1684,171 +1684,172 @@ const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
 	return NULL;
 }
 
-void CStack::stackEffectToFeature(BonusList & sf, const Bonus & sse)
+void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
 {
-	// 	si32 power = VLC->spellh->spells[sse.id]->powers[sse.val];
-	// 	Bonus * bonus = getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, sse.id));
-	// 	if (bonus)
-	// 	{
-	// 		switch(bonus->additionalInfo)
-	// 		{
-	// 			case 0: //normal
-	// 				switch(type->level)
-	// 				{
-	// 					case 1: case 2:
-	// 						power += 3; //it doesn't necessarily make sense for some spells, use it wisely
-	// 					break;
-	// 					case 3: case 4:
-	// 						power += 2;
-	// 					break;
-	// 					case 5: case 6:
-	// 						power += 1;
-	// 					break;
-	// 				}
-	// 			break;
-	// 			case 1: //only Coronius as yet
-	// 				power = std::max(5 - type->level, 0);
-	// 			break;
-	// 		}
-	// 	}
-	// 
-	// 	switch(sse.id)
-	// 	{
-	// 	case 27: //shield 
-	// 		sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 28: //air shield
-	// 		sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 29: //fire shield
-	// 		sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 30: //protection from air
-	// 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 31: //protection from fire
-	// 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 32: //protection from water
-	// 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 33: //protection from earth
-	// 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 34: //anti-magic
-	// 		sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 41: //bless
-	// 		if (hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, 41)) //TODO: better handling of bonus percentages
-	// 		{
-	// 			int damagePercent = dynamic_cast<const CGHeroInstance*>(armyObj)->level * valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / type->level;
-	// 			sf.push_back(featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, sse.turnsRemain));
-	// 			sf.back().id = sse.id;
-	// 			sf.back().valType = Bonus::PERCENT_TO_ALL;
-	// 		}
-	// 		sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 42: //curse
-	// 		sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 43: //bloodlust
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 44: //precision
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 45: //weakness
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 46: //stone skin
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 47: //disrupting ray
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 48: //prayer
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 49: //mirth
-	// 		sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 50: //sorrow
-	// 		sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 51: //fortune
-	// 		sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 52: //misfortune
-	// 		sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 53: //haste
-	// 		sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 54: //slow
-	// 		sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 55: //slayer
-	// 		if (bonus) //Coronius
-	// 		{
-	// 			sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
-	// 			sf.back().id = sse.id;
-	// 		}
-	// 		sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 56: //frenzy
-	// 		sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 58: //counterstrike
-	// 		sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 59: //bersek
-	// 		sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 60: //hypnotize
-	// 		sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 61: //forgetfulness
-	// 		sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	case 62: //blind
-	// 		sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
-	// 		sf.back().id = sse.id;
-	// 		break;
-	// 	}
+	si32 power = VLC->spellh->spells[sse.id]->powers[sse.val];
+	//why, why, WHY this code is here?!?
+// 	Bonus * bonus = getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, sse.id));
+// 	if (bonus)
+// 	{
+// 	 	switch(bonus->additionalInfo)
+// 	 	{
+// 	 		case 0: //normal
+// 	 			switch(type->level)
+// 	 			{
+// 	 				case 1: case 2:
+// 	 					power += 3; //it doesn't necessarily make sense for some spells, use it wisely
+// 	 				break;
+// 	 				case 3: case 4:
+// 	 					power += 2;
+// 	 				break;
+// 	 				case 5: case 6:
+// 	 					power += 1;
+// 	 				break;
+// 	 			}
+// 	 		break;
+// 	 		case 1: //only Coronius as yet
+// 	 			power = std::max(5 - type->level, 0);
+// 	 		break;
+// 	 	}
+// 	}
+	 
+	switch(sse.id)
+	{
+	case 27: //shield 
+	 	sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 28: //air shield
+	 	sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 29: //fire shield
+	 	sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 30: //protection from air
+	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 31: //protection from fire
+	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 32: //protection from water
+	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 33: //protection from earth
+	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 34: //anti-magic
+	 	sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 41: //bless
+// 	 	if (hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, 41)) //TODO: better handling of bonus percentages
+// 	 	{
+// 	 		int damagePercent = dynamic_cast<const CGHeroInstance*>(armyObj)->level * valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / type->level;
+// 	 		sf.push_back(featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, sse.turnsRemain));
+// 	 		sf.back().id = sse.id;
+// 	 		sf.back().valType = Bonus::PERCENT_TO_ALL;
+// 	 	}
+	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 42: //curse
+	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 43: //bloodlust
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 44: //precision
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 45: //weakness
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 46: //stone skin
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 47: //disrupting ray
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 48: //prayer
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 49: //mirth
+	 	sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 50: //sorrow
+	 	sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 51: //fortune
+	 	sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 52: //misfortune
+	 	sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 53: //haste
+	 	sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 54: //slow
+	 	sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 55: //slayer
+// 	 	if (bonus) //Coronius
+// 	 	{
+// 	 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
+// 	 		sf.back().id = sse.id;
+// 	 	}
+	 	sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 56: //frenzy
+	 	sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 58: //counterstrike
+	 	sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 59: //bersek
+	 	sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 60: //hypnotize
+	 	sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 61: //forgetfulness
+	 	sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
+	 	sf.back().id = sse.id;
+	 	break;
+	case 62: //blind
+		sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
+		sf.back().id = sse.id;
+		sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
+		sf.back().id = sse.id;
+	 	break;
+	}
 }
 
 ui8 CStack::howManyEffectsSet(ui16 id) const
@@ -1904,7 +1905,7 @@ THex CStack::occupiedHex() const
 }
 BonusList CStack::getSpellBonuses() const
 {
-	return getBonuses(Selector::sourceTypeSel(Bonus::CASTED_SPELL));
+	return getBonuses(Selector::sourceTypeSel(Bonus::SPELL_EFFECT));
 }
 
 std::vector<si32> CStack::activeSpells() const

+ 9 - 9
lib/BattleState.h

@@ -148,23 +148,23 @@ public:
 	bool canMove(int turn = 0) const; //if stack can move
 	ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
 	BonusList getSpellBonuses() const;
-	void stackEffectToFeature(BonusList & sf, const Bonus & sse);
+	static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);
 	std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
 	const CGHeroInstance *getMyHero() const; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise
 
-	static inline Bonus *featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
+	static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
 	{
-		Bonus *hb = makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
-		hb->effectRange = limit;
-		hb->source = Bonus::CASTED_SPELL; //right?
+		Bonus hb = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
+		hb.effectRange = limit;
+		hb.source = Bonus::SPELL_EFFECT;
 		return hb;
 	}
 
-	static inline Bonus *featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
+	static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
 	{
-		Bonus *ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
-		ret->valType = valType;
-		ret->source = Bonus::CASTED_SPELL; //right?
+		Bonus ret = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain);
+		ret.valType = valType;
+		ret.source = Bonus::SPELL_EFFECT;
 		return ret;
 	}
 

+ 19 - 13
lib/HeroBonus.h

@@ -184,10 +184,9 @@ struct DLL_EXPORT Bonus
 	};
 	enum BonusSource
 	{
-		ARTIFACT, 
-		ARTIFACT_INSTANCE, 
-		OBJECT, 
-		CASTED_SPELL,
+		ARTIFACT,
+		ARTIFACT_INSTANCE,
+		OBJECT,
 		CREATURE_ABILITY,
 		TERRAIN_NATIVE,
 		TERRAIN_OVERLAY,
@@ -458,20 +457,27 @@ namespace NBonus
 };
 
 //generates HeroBonus from given data
-inline Bonus* makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
+inline Bonus makeFeatureVal(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
 {
-	Bonus* sf = new Bonus();
-	sf->type = type;
-	sf->duration = duration;
-	sf->source = source;
-	sf->turnsRemain = turnsRemain;
-	sf->subtype = subtype;
-	sf->val = value;
-	sf->additionalInfo = additionalInfo;
+	Bonus sf;
+	sf.type = type;
+	sf.duration = duration;
+	sf.source = source;
+	sf.turnsRemain = turnsRemain;
+	sf.subtype = subtype;
+	sf.val = value;
+	sf.additionalInfo = additionalInfo;
 
 	return sf;
 }
 
+//generates HeroBonus from given data
+inline Bonus * makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
+{
+	return new Bonus(makeFeatureVal(type, duration, subtype, value, source, turnsRemain, additionalInfo));
+}
+
+
 class DLL_EXPORT CSelectorsConjunction
 {
 	const CSelector first, second;

+ 1 - 1
lib/NetPacks.h

@@ -1327,7 +1327,7 @@ struct SetStackEffect : public CPackForClient //3010
 	void applyCl(CClient *cl);
 
 	std::vector<ui32> stacks; //affected stacks (IDs)
-	Bonus effect; //type of effect
+	std::vector<Bonus> effect; //bonuses to apply
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & stacks & effect;

+ 10 - 22
lib/NetPacksLib.cpp

@@ -888,7 +888,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
 
 		//remove effects and restore only those with remaining turns in duration
 		BonusList tmpEffects = s->bonuses;
-		s->bonuses.removeSpells(Bonus::CASTED_SPELL);
+		s->bonuses.removeSpells(Bonus::SPELL_EFFECT);
 
 		BOOST_FOREACH(Bonus *it, tmpEffects)
 		{
@@ -1072,7 +1072,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
 					}
 					
 				}
-				s->bonuses.removeSpells(Bonus::CASTED_SPELL); //removing all effects
+				s->bonuses.removeSpells(Bonus::SPELL_EFFECT); //removing all effects
 				s->bonuses = remainingEff; //assigning effects that should remain
 
 				//removing all features from spells
@@ -1135,27 +1135,17 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
 	}
 }
 
-void actualizeEffect(CStack * s, Bonus & ef)
+void actualizeEffect(CStack * s, const std::vector<Bonus> & ef)
 {
-	//actualizing effects vector
-	BOOST_FOREACH(Bonus *it, s->bonuses)
-	{
-		if(it->id == ef.id)
-		{
-			it->turnsRemain = std::max(it->turnsRemain, ef.turnsRemain);
-		}
-	}
 	//actualizing features vector
-	BonusList sf;
-	s->stackEffectToFeature(sf, ef);
 
-	BOOST_FOREACH(const Bonus *fromEffect, sf)
+	BOOST_FOREACH(const Bonus &fromEffect, ef)
 	{
 		BOOST_FOREACH(Bonus *stackBonus, s->bonuses) //TODO: optimize
 		{
-			if(stackBonus->source == Bonus::SPELL_EFFECT && stackBonus->type == fromEffect->type && stackBonus->subtype == fromEffect->subtype)
+			if(stackBonus->source == Bonus::SPELL_EFFECT && stackBonus->type == fromEffect.type && stackBonus->subtype == fromEffect.subtype)
 			{
-				stackBonus->turnsRemain = std::max(stackBonus->turnsRemain, ef.turnsRemain);
+				stackBonus->turnsRemain = std::max(stackBonus->turnsRemain, fromEffect.turnsRemain);
 			}
 		}
 	}
@@ -1169,14 +1159,12 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
 		CStack *s = gs->curB->getStack(id);
 		if(s)
 		{
-			if(effect.id == 42 || !s->hasBonus(Selector::source(Bonus::CASTED_SPELL, effect.id)))//disrupting ray or not on the list - just add	
+			int id = effect.begin()->id; //effects' source ID
+			if(id == 47 || !s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, id)))//disrupting ray or not on the list - just add	
 			{
-				s->addNewBonus(new Bonus(effect));
-				BonusList sf;
-				s->stackEffectToFeature(sf, effect);
-				BOOST_FOREACH(Bonus *fromEffect, sf)
+				BOOST_FOREACH(Bonus &fromEffect, effect)
 				{
-					s->addNewBonus(fromEffect);
+					s->addNewBonus( new Bonus(fromEffect));
 				}
 			}
 			else //just actualize

+ 10 - 8
server/CGameHandler.cpp

@@ -3037,7 +3037,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		{
 			//defensive stance
 			SetStackEffect sse;
-			sse.effect = Bonus(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 20, -1, PrimarySkill::DEFENSE, Bonus::PERCENT_TO_ALL);
+			sse.effect.push_back( Bonus(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 20, -1, PrimarySkill::DEFENSE, Bonus::PERCENT_TO_ALL) );
 			sse.stacks.push_back(ba.stackNumber);
 			sendAndApply(&sse);
 
@@ -3644,9 +3644,11 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
 					continue;
 				sse.stacks.push_back((*it)->ID);
 			}
-			sse.effect.id = spellID;
-			sse.effect.val = spellLvl;
-			sse.effect.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
+			Bonus pseudoBonus;
+			pseudoBonus.id = spellID;
+			pseudoBonus.val = spellLvl;
+			pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
+			CStack::stackEffectToFeature(sse.effect, pseudoBonus);
 			if(!sse.stacks.empty())
 				sendAndApply(&sse);
 			break;
@@ -4444,7 +4446,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
 				COMPLAIN_RET("Destination tile doesn't exist!");
 			if(!h->movement)
 				COMPLAIN_RET("Hero needs movement points to cast Dimension Door!");
-			if(h->getBonusesCount(Bonus::CASTED_SPELL, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn
+			if(h->getBonusesCount(Bonus::SPELL_EFFECT, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn
 			{
 				InfoWindow iw;
 				iw.player = h->tempOwner;
@@ -4456,7 +4458,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
 
 			GiveBonus gb;
 			gb.id = h->id;
-			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::NONE, Bonus::CASTED_SPELL, 0, Spells::DIMENSION_DOOR);
+			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::NONE, Bonus::SPELL_EFFECT, 0, Spells::DIMENSION_DOOR);
 			sendAndApply(&gb);
 			
 			if(!dest->isClear(curr)) //wrong dest tile
@@ -4489,7 +4491,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
 
 			GiveBonus gb;
 			gb.id = h->id;
-			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::FLYING_MOVEMENT, Bonus::CASTED_SPELL, 0, Spells::FLY, subtype);
+			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::FLYING_MOVEMENT, Bonus::SPELL_EFFECT, 0, Spells::FLY, subtype);
 			sendAndApply(&gb);
 		}
 		break;
@@ -4499,7 +4501,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
 
 			GiveBonus gb;
 			gb.id = h->id;
-			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::WATER_WALKING, Bonus::CASTED_SPELL, 0, Spells::FLY, subtype);
+			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::WATER_WALKING, Bonus::SPELL_EFFECT, 0, Spells::FLY, subtype);
 			sendAndApply(&gb);
 		}
 		break;