mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	[refactor]
* spells are now more configurable (unused yet, WiP) * a few more cleanups
This commit is contained in:
		| @@ -186,7 +186,7 @@ ui32 BattleInfo::calculateHealedHP(const CSpell * spell, int usedSpellPower, int | ||||
| } | ||||
| bool BattleInfo::resurrects(TSpell spellid) const | ||||
| { | ||||
| 	return vstd::contains(VLC->spellh->risingSpells, spellid); | ||||
| 	return VLC->spellh->spells[spellid]->isRisingSpell(); | ||||
| } | ||||
|  | ||||
| const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive) | ||||
| @@ -931,170 +931,146 @@ si32 CStack::magicResistance() const | ||||
|  | ||||
| void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse) | ||||
| { | ||||
| 	si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val]; | ||||
| 	//TODO: get rid of this spaghetti code | ||||
|  | ||||
| 	const CSpell * sp = VLC->spellh->spells[sse.sid]; | ||||
| 	si32 power = sp->powers[sse.val]; | ||||
|  | ||||
| 	auto add = [&](Bonus::BonusType type, si16 subtype, si32 value,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) | ||||
| 	{ | ||||
| 	 	sf.push_back(featureGenerator(type, subtype, value, sse.turnsRemain,additionalInfo, limit)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	}; | ||||
|  | ||||
| 	auto addVT = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 valType,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) | ||||
| 	{ | ||||
| 		add(type, subtype, value, additionalInfo, limit); | ||||
| 		sf.back().valType = valType; | ||||
| 	}; | ||||
|  | ||||
| 	auto addDur = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 duration ,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) | ||||
| 	{ | ||||
| 		add(type, subtype, value, additionalInfo, limit); | ||||
| 		sf.back().duration = duration; | ||||
| 	}; | ||||
|  | ||||
| 	switch(sse.sid) | ||||
| 	{ | ||||
| 	case 27: //shield | ||||
| 	 	sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 28: //air shield | ||||
| 	 	sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 29: //fire shield | ||||
| 	 	sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 30: //protection from air | ||||
| 	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 31: //protection from fire | ||||
| 	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 32: //protection from water | ||||
| 	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 33: //protection from earth | ||||
| 	 	sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 34: //anti-magic | ||||
| 	 	sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, sse.turnsRemain)); | ||||
| 		sf.back().valType = Bonus::INDEPENDENT_MAX; | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 36: //magic mirror | ||||
| 		sf.push_back(featureGenerator(Bonus::MAGIC_MIRROR, -1, power, sse.turnsRemain)); | ||||
| 		sf.back().valType = Bonus::INDEPENDENT_MAX; | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	case 41: //bless | ||||
| 		sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain)); | ||||
| 		sf.back().valType = Bonus::INDEPENDENT_MAX; | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 42: //curse | ||||
| 	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, sse.turnsRemain, sse.val >= 2 ? 20 : 0)); | ||||
| 		sf.back().valType = Bonus::INDEPENDENT_MAX; | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 43: //bloodlust | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 44: //precision | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 45: //weakness | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 46: //stone skin | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 47: //disrupting ray | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 		sf.back().valType = Bonus::ADDITIVE_VALUE; | ||||
| 	 	break; | ||||
| 	case 48: //prayer | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 49: //mirth | ||||
| 	 	sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 50: //sorrow | ||||
| 	 	sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 51: //fortune | ||||
| 	 	sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 52: //misfortune | ||||
| 	 	sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 53: //haste | ||||
| 	 	sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 54: //slow | ||||
| 	 	sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 55: //slayer | ||||
| 	 	sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	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().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 58: //counterstrike | ||||
| 	 	sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 59: //bersek | ||||
| 	 	sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 60: //hypnotize | ||||
| 	 	sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case 61: //forgetfulness | ||||
| 	 	sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case Spells::BLIND: //blind | ||||
| 		sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); | ||||
| 		sf.back().sid = sse.sid; | ||||
| 		sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain)); | ||||
| 		sf.back().sid = sse.sid; | ||||
| 		sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack | ||||
| 		sf.back().sid = sse.sid; | ||||
| 	 	break; | ||||
| 	case Spells::STONE_GAZE: //Stone Gaze | ||||
| 	case Spells::PARALYZE: //Paralyze | ||||
| 		sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); | ||||
| 		sf.back().sid = sse.sid; | ||||
| 		sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack | ||||
| 		sf.back().sid = sse.sid; | ||||
| 	case Spells::SHIELD: | ||||
| 		add(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power); | ||||
| 		break; | ||||
| 	case 71: //Poison | ||||
| 		sf.push_back(featureGeneratorVT(Bonus::POISON, 0, 30, sse.turnsRemain, Bonus::INDEPENDENT_MAX)); //max hp penalty from this source | ||||
| 		sf.back().sid = sse.sid; | ||||
| 		sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -10, sse.turnsRemain, Bonus::PERCENT_TO_ALL)); | ||||
| 		sf.back().sid = sse.sid; | ||||
| 	case Spells::AIR_SHIELD: | ||||
| 	 	add(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power); | ||||
| 	 	break; | ||||
| 	case Spells::FIRE_SHIELD: | ||||
| 	 	add(Bonus::FIRE_SHIELD, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::PROTECTION_FROM_AIR: | ||||
| 	 	add(Bonus::SPELL_DAMAGE_REDUCTION, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::PROTECTION_FROM_FIRE: | ||||
| 	 	add(Bonus::SPELL_DAMAGE_REDUCTION, 1, power); | ||||
| 	 	break; | ||||
| 	case Spells::PROTECTION_FROM_WATER: | ||||
| 	 	add(Bonus::SPELL_DAMAGE_REDUCTION, 2, power); | ||||
| 	 	break; | ||||
| 	case Spells::PROTECTION_FROM_EARTH: | ||||
| 	 	add(Bonus::SPELL_DAMAGE_REDUCTION, 3, power); | ||||
| 	 	break; | ||||
| 	case Spells::ANTI_MAGIC: | ||||
| 	 	addVT(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, Bonus::INDEPENDENT_MAX);break; | ||||
| 	case Spells::MAGIC_MIRROR: | ||||
| 		addVT(Bonus::MAGIC_MIRROR, -1, power,Bonus::INDEPENDENT_MAX); | ||||
| 		break; | ||||
| 	case 72: //Bind | ||||
| 	case Spells::BLESS: | ||||
| 		addVT(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power,Bonus::INDEPENDENT_MAX); | ||||
| 	 	break; | ||||
| 	case Spells::CURSE: | ||||
| 		addVT(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, Bonus::INDEPENDENT_MAX, sse.val >= 2 ? 20 : 0); | ||||
| 	 	break; | ||||
| 	case Spells::BLOODLUST: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_MELEE_FIGHT); | ||||
| 	 	break; | ||||
| 	case Spells::PRECISION: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_DISTANCE_FIGHT); | ||||
| 	 	break; | ||||
| 	case Spells::WEAKNESS: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power); | ||||
| 		break; | ||||
| 	case Spells::STONE_SKIN: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power); | ||||
| 	 	break; | ||||
| 	case Spells::DISRUPTING_RAY: | ||||
| 		addVT(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power,Bonus::ADDITIVE_VALUE); | ||||
| 	 	break; | ||||
| 	case Spells::PRAYER: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power); | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power); | ||||
| 		add(Bonus::STACKS_SPEED, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::MIRTH: | ||||
| 		add(Bonus::MORALE, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::SORROW: | ||||
| 		add(Bonus::MORALE, 0, -1 * power); | ||||
| 	 	break; | ||||
| 	case Spells::FORTUNE: | ||||
| 		add(Bonus::LUCK, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::MISFORTUNE: | ||||
| 		add(Bonus::LUCK, 0, -1 * power); | ||||
| 	 	break; | ||||
| 	case Spells::HASTE: //haste | ||||
| 		add(Bonus::STACKS_SPEED, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::SLOW: | ||||
| 		addVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ),Bonus::PERCENT_TO_ALL); | ||||
| 	 	break; | ||||
| 	case Spells::SLAYER: | ||||
| 		add(Bonus::SLAYER, 0, sse.val); | ||||
| 	 	break; | ||||
| 	case Spells::FRENZY: | ||||
| 		add(Bonus::IN_FRENZY, 0, power/100.0); | ||||
| 	 	break; | ||||
| 	case Spells::COUNTERSTRIKE: | ||||
| 		add(Bonus::ADDITIONAL_RETALIATION, 0, power); | ||||
| 	 	break; | ||||
| 	case Spells::BERSERK: | ||||
| 		add(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val); | ||||
| 	 	break; | ||||
| 	case Spells::HYPNOTIZE: | ||||
| 	 	add(Bonus::HYPNOTIZED, 0, sse.val); | ||||
| 	 	break; | ||||
| 	case Spells::FORGETFULNESS: | ||||
| 		add(Bonus::FORGETFULL, 0, sse.val); | ||||
| 	 	break; | ||||
| 	case Spells::BLIND: | ||||
| 		addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS); | ||||
| 		addDur(Bonus::GENERAL_ATTACK_REDUCTION, 0, power, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS); | ||||
| 		addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED); | ||||
| 	 	break; | ||||
| 	case Spells::STONE_GAZE: | ||||
| 	case Spells::PARALYZE: | ||||
| 		addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS); | ||||
| 		addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED); | ||||
| 		break; | ||||
| 	case Spells::POISON: //Poison | ||||
| 		addVT(Bonus::POISON, 0, 30,Bonus::INDEPENDENT_MAX); //max hp penalty from this source | ||||
| 		addVT(Bonus::STACK_HEALTH, 0, -10, Bonus::PERCENT_TO_ALL); | ||||
| 		break; | ||||
| 	case Spells::BIND: | ||||
| 		sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 1)); //marker | ||||
| 		sf.back().duration = Bonus::PERMANENT; | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 		break; | ||||
| 	case 73: //Disease | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2 , sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2 , sse.turnsRemain)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 	case Spells::DISEASE: | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2); | ||||
| 		add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2); | ||||
| 		break; | ||||
| 	case 75: //Age | ||||
| 		sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -50, sse.turnsRemain, Bonus::PERCENT_TO_ALL)); | ||||
| 		sf.back().sid = sse.sid; | ||||
| 	case Spells::AGE: | ||||
| 		addVT(Bonus::STACK_HEALTH, 0, -50, Bonus::PERCENT_TO_ALL); | ||||
| 		break; | ||||
| 	case 80: //Acid Breath | ||||
| 	case Spells::ACID_BREATH_DEFENSE: | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -sse.turnsRemain, 1)); | ||||
| 	 	sf.back().sid = sse.sid; | ||||
| 		sf.back().duration = Bonus::PERMANENT; | ||||
|   | ||||
| @@ -33,8 +33,8 @@ struct BattleStackAttacked; | ||||
| //only for use in BattleInfo | ||||
| struct DLL_LINKAGE SiegeInfo | ||||
| { | ||||
| 	ui8 wallState[EWallParts::PARTS_COUNT];  | ||||
| 	 | ||||
| 	ui8 wallState[EWallParts::PARTS_COUNT]; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & wallState; | ||||
| @@ -101,7 +101,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb | ||||
|  | ||||
| 	ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting) | ||||
| 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount) | ||||
| 	 | ||||
|  | ||||
| 	//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee | ||||
| 	//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks | ||||
| 	//std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks | ||||
| @@ -114,7 +114,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb | ||||
| 	ui32 calculateHealedHP(int healedHealth, const CSpell * spell, const CStack * stack) const; //for Archangel | ||||
| 	ui32 calculateHealedHP(const CSpell * spell, int usedSpellPower, int spellSchoolLevel, const CStack * stack) const; //unused | ||||
| 	bool resurrects(TSpell spellid) const; //TODO: move it to spellHandler? | ||||
| 	 | ||||
|  | ||||
| 	const CGHeroInstance * getHero(int player) const; //returns fighting hero that belongs to given player | ||||
|  | ||||
|  | ||||
| @@ -136,7 +136,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor | ||||
| {  | ||||
| { | ||||
| public: | ||||
| 	const CStackInstance *base; //garrison slot from which stack originates (NULL for war machines, summoned cres, etc) | ||||
|  | ||||
| @@ -179,7 +179,6 @@ public: | ||||
| 	{ | ||||
| 		Bonus hb = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo); | ||||
| 		hb.effectRange = limit; | ||||
| 		hb.source = Bonus::SPELL_EFFECT; | ||||
| 		return hb; | ||||
| 	} | ||||
|  | ||||
| @@ -187,7 +186,6 @@ public: | ||||
| 	{ | ||||
| 		Bonus ret = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain); | ||||
| 		ret.valType = valType; | ||||
| 		ret.source = Bonus::SPELL_EFFECT; | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -782,7 +782,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c | ||||
| 		minDmg = info.attackerBonuses->getMinDamage() * info.attackerCount, | ||||
| 		maxDmg = info.attackerBonuses->getMaxDamage() * info.attackerCount; | ||||
|  | ||||
| 	const CCreature *attackerType = info.attacker->getCreature(),  | ||||
| 	const CCreature *attackerType = info.attacker->getCreature(), | ||||
| 		*defenderType = info.defender->getCreature(); | ||||
|  | ||||
| 	if(attackerType->idNumber == 149) //arrow turret | ||||
| @@ -1591,7 +1591,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C | ||||
| 			if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY)) | ||||
| 				return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; | ||||
| 		} | ||||
| 		if (vstd::contains(VLC->spellh->mindSpells, spell->id)) | ||||
| 		if (spell->isMindSpell()) | ||||
| 		{ | ||||
| 			if (subject->hasBonusOfType(Bonus::MIND_IMMUNITY)) | ||||
| 				return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; | ||||
| @@ -1706,7 +1706,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell | ||||
| 	switch(spell->getTargetType()) | ||||
| 	{ | ||||
| 	case CSpell::CREATURE: | ||||
| 	case CSpell::CREATURE_EXPERT_MASSIVE:   | ||||
| 	case CSpell::CREATURE_EXPERT_MASSIVE: | ||||
| 		if(mode == ECastingMode::HERO_CASTING) | ||||
| 		{ | ||||
| 			const CGHeroInstance * caster = battleGetFightingHero(side); | ||||
| @@ -1909,7 +1909,7 @@ ui32 CBattleInfoCallback::calculateSpellDmg( const CSpell * sp, const CGHeroInst | ||||
| 	ui32 ret = 0; //value to return | ||||
|  | ||||
| 	//check if spell really does damage - if not, return 0 | ||||
| 	if(VLC->spellh->damageSpells.find(sp->id) == VLC->spellh->damageSpells.end()) | ||||
| 	if(!sp->isDamageSpell()) | ||||
| 		return 0; | ||||
|  | ||||
| 	ret = usedSpellPower * sp->power; | ||||
| @@ -2373,7 +2373,7 @@ const CGHeroInstance * CPlayerBattleCallback::battleGetMyHero() const | ||||
|  | ||||
| InfoAboutHero CPlayerBattleCallback::battleGetEnemyHero() const | ||||
| { | ||||
| 	InfoAboutHero ret;  | ||||
| 	InfoAboutHero ret; | ||||
| 	assert(0); | ||||
| 	///TODO implement and replace usages of battleGetFightingHero obtaining enemy hero | ||||
| 	return ret; | ||||
|   | ||||
| @@ -176,7 +176,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 	} | ||||
| 	else if (type == ART_EVNTS) | ||||
| 	{ | ||||
| 		dst = VLC->arth->artifacts[ser]->EventText();  | ||||
| 		dst = VLC->arth->artifacts[ser]->EventText(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -522,7 +522,7 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj) | ||||
| 	{ | ||||
| 	case Obj::RANDOM_ART: | ||||
| 		return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC)); | ||||
| 	case Obj::RANDOM_TREASURE_ART:  | ||||
| 	case Obj::RANDOM_TREASURE_ART: | ||||
| 		return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_TREASURE)); | ||||
| 	case Obj::RANDOM_MINOR_ART: | ||||
| 		return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_MINOR)); | ||||
| @@ -573,7 +573,7 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj) | ||||
| 		return std::pair<int,int>(Obj::MONSTER, VLC->creh->pickRandomMonster(boost::ref(ran), 6)); | ||||
| 	case Obj::RANDOM_MONSTER_L7: | ||||
| 		return std::pair<int,int>(Obj::MONSTER, VLC->creh->pickRandomMonster(boost::ref(ran), 7)); | ||||
| 	case Obj::RANDOM_DWELLING:  | ||||
| 	case Obj::RANDOM_DWELLING: | ||||
| 	case Obj::RANDOM_DWELLING_LVL: | ||||
| 	case Obj::RANDOM_DWELLING_FACTION: | ||||
| 		{ | ||||
| @@ -1963,7 +1963,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const | ||||
| 		{ | ||||
| 			if(obj->blockVisit) | ||||
| 			{ | ||||
| 				if (obj->ID == 54) // Monster | ||||
| 				if (obj->ID == Obj::MONSTER) // Monster | ||||
| 					guards.push_back(obj); | ||||
| 			} | ||||
| 		} | ||||
| @@ -1976,11 +1976,11 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const | ||||
| 			if (map->isInTheMap(pos)) | ||||
| 			{ | ||||
| 				TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z]; | ||||
|                 if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER)) | ||||
|                 if (tile.visitable && (tile.isWater() == posTile.isWater())) | ||||
| 				{ | ||||
| 					BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) | ||||
| 					{ | ||||
| 						if (obj->ID == 54  &&  checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile | ||||
| 						if (obj->ID == Obj::MONSTER  &&  checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile | ||||
| 						{ | ||||
| 							guards.push_back(obj); | ||||
| 						} | ||||
| @@ -2010,7 +2010,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const | ||||
| 		{ | ||||
| 			if(obj->blockVisit) | ||||
| 			{ | ||||
| 				if (obj->ID == 54) // Monster | ||||
| 				if (obj->ID == Obj::MONSTER) // Monster | ||||
| 					return pos; | ||||
| 				else | ||||
| 					return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures | ||||
| @@ -2027,11 +2027,11 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const | ||||
| 			if (map->isInTheMap(pos)) | ||||
| 			{ | ||||
| 				TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z]; | ||||
|                 if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER)) | ||||
|                 if (tile.visitable && (tile.isWater() == posTile.isWater())) | ||||
| 				{ | ||||
| 					BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) | ||||
| 					{ | ||||
| 						if (obj->ID == 54  &&  checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile | ||||
| 						if (obj->ID == Obj::MONSTER  &&  checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile | ||||
| 						{ | ||||
| 							return pos; | ||||
| 						} | ||||
| @@ -2429,7 +2429,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) | ||||
| 	} | ||||
| 	if(level >= 4) //obelisks found | ||||
| 	{ | ||||
| 		//TODO | ||||
| 		//TODO: obtainPlayersStats - obelisks found | ||||
| 	} | ||||
| 	if(level >= 5) //artifacts | ||||
| 	{ | ||||
| @@ -2441,7 +2441,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) | ||||
| 	} | ||||
| 	if(level >= 7) //income | ||||
| 	{ | ||||
| 		//TODO | ||||
| 		//TODO:obtainPlayersStats - income | ||||
| 	} | ||||
| 	if(level >= 8) //best hero's stats | ||||
| 	{ | ||||
| @@ -2507,18 +2507,11 @@ int CGameState::lossCheck( ui8 player ) const | ||||
| 		switch(map->lossCondition.typeOfLossCon) | ||||
| 		{ | ||||
| 		case ELossConditionType::LOSSCASTLE: | ||||
| 			{ | ||||
| 				const CGTownInstance *t = dynamic_cast<const CGTownInstance *>(map->lossCondition.obj); | ||||
| 				assert(t); | ||||
| 				if(t->tempOwner != player) | ||||
| 					return 1; | ||||
| 			} | ||||
| 			break; | ||||
| 		case ELossConditionType::LOSSHERO: | ||||
| 			{ | ||||
| 				const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(map->lossCondition.obj); | ||||
| 				assert(h); | ||||
| 				if(h->tempOwner != player) | ||||
| 				const CGObjectInstance *obj = map->lossCondition.obj; | ||||
| 				assert(obj); | ||||
| 				if(obj->tempOwner != player) | ||||
| 					return 1; | ||||
| 			} | ||||
| 			break; | ||||
| @@ -3177,13 +3170,6 @@ bool CPathfinder::canMoveBetween(const int3 &a, const int3 &b) const | ||||
| 	return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a); | ||||
| } | ||||
|  | ||||
| bool CPathfinder::canStepOntoDst() const | ||||
| { | ||||
| 	//TODO remove | ||||
| 	assert(0); | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile *tinfo) const | ||||
| { | ||||
| 	CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE); | ||||
| @@ -3194,7 +3180,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile | ||||
|  | ||||
| 	if(tinfo->visitable) | ||||
| 	{ | ||||
| 		if(tinfo->visitableObjects.front()->ID == 80 && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary | ||||
| 		if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary | ||||
| 		{ | ||||
| 			return CGPathNode::BLOCKED; | ||||
| 		} | ||||
|   | ||||
| @@ -368,7 +368,6 @@ private: | ||||
|  | ||||
| 	CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const; | ||||
| 	bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility) | ||||
| 	bool canStepOntoDst() const; | ||||
|  | ||||
| public: | ||||
| 	CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero); | ||||
|   | ||||
| @@ -292,6 +292,7 @@ void CModHandler::loadActiveMods() | ||||
| 		handleData(VLC->townh, config["factions"]); | ||||
| 		handleData(VLC->creh, config["creatures"]); | ||||
| 		handleData(VLC->arth, config["artifacts"]); | ||||
| 		//todo: spells | ||||
|  | ||||
| 		handleData(&VLC->heroh->classes, config["heroClasses"]); | ||||
| 		handleData(VLC->heroh, config["heroes"]); | ||||
|   | ||||
| @@ -1384,13 +1384,12 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta | ||||
| 	{ | ||||
| 		iw.text.addTxt(MetaString::GENERAL_TXT, 145); | ||||
| 		iw.text.addReplacement(raisedStack.count); | ||||
| 		iw.text.addReplacement(MetaString::CRE_PL_NAMES, raisedStack.type->idNumber); | ||||
| 	} | ||||
| 	else // Practicing the dark arts of necromancy, ... (singular) | ||||
| 	{ | ||||
| 		iw.text.addTxt(MetaString::GENERAL_TXT, 146); | ||||
| 		iw.text.addReplacement(MetaString::CRE_SING_NAMES, raisedStack.type->idNumber); | ||||
| 	} | ||||
| 	iw.text.addReplacement(raisedStack); | ||||
|  | ||||
| 	cb->showInfoDialog(&iw); | ||||
| } | ||||
| @@ -4772,7 +4771,7 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const | ||||
| const std::string & CGWitchHut::getHoverText() const | ||||
| { | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current | ||||
| 	if(wasVisited(cb->getLocalPlayer())) | ||||
| 	{ | ||||
| 		hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s) | ||||
| 		boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]); | ||||
| @@ -6113,14 +6112,12 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons | ||||
| 		//display loot | ||||
| 		if (!iw.components.empty()) | ||||
| 		{ | ||||
| 			iw.text.addTxt (MetaString::ADVOB_TXT, textID); | ||||
| 			if (textID == 34) | ||||
| 			{ | ||||
| 				iw.text.addTxt(MetaString::ADVOB_TXT, 34);//Heaving defeated %s, you discover %s | ||||
| 				iw.text.addReplacement(MetaString::CRE_PL_NAMES, result->casualties[1].begin()->first); | ||||
| 				iw.text.addReplacement(loot.buildList()); | ||||
| 			} | ||||
| 			else | ||||
| 				iw.text.addTxt (MetaString::ADVOB_TXT, textID); | ||||
| 			cb->showInfoDialog(&iw); | ||||
| 		} | ||||
| 		loot.clear(); | ||||
|   | ||||
| @@ -167,7 +167,7 @@ public: | ||||
| 	mutable std::string hoverName; | ||||
| 	int3 pos; //h3m pos | ||||
| 	si32 ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34 | ||||
| 	si32 id;//number of object in CObjectHandler's vector | ||||
| 	si32 id;//number of object in map's vector | ||||
| 	CGDefInfo * defInfo; | ||||
| 	ui8 animPhaseShift; | ||||
|  | ||||
|   | ||||
| @@ -96,7 +96,7 @@ namespace SRSLPraserHelpers | ||||
| 			mainPointForLayer[b] = hexToPair(center); | ||||
|  | ||||
| 		for(int it=1; it<=high; ++it) //it - distance to the center | ||||
| 		{		 | ||||
| 		{ | ||||
| 			for(int b=0; b<6; ++b) | ||||
| 				mainPointForLayer[b] = gotoDir(mainPointForLayer[b], b); | ||||
|  | ||||
| @@ -122,11 +122,19 @@ namespace SRSLPraserHelpers | ||||
| 		return ret; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| using namespace SRSLPraserHelpers; | ||||
| CSpellHandler::CSpellHandler() | ||||
| { | ||||
| 	VLC->spellh = this; | ||||
| } | ||||
|  | ||||
| CSpell::CSpell() | ||||
| { | ||||
| 	_isDamage = false; | ||||
| 	_isMind = false; | ||||
| 	_isRising = false; | ||||
| } | ||||
|  | ||||
| std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const | ||||
| { | ||||
| 	std::vector<BattleHex> ret; | ||||
| @@ -238,7 +246,7 @@ CSpell::ETargetType CSpell::getTargetType() const //TODO: parse these at game la | ||||
|  | ||||
| 	if(attributes.find("OBSTACLE_TARGET") != std::string::npos) | ||||
| 		return OBSTACLE; | ||||
| 	 | ||||
|  | ||||
| 	return NO_TARGET; | ||||
| } | ||||
|  | ||||
| @@ -254,13 +262,30 @@ bool CSpell::isNegative() const | ||||
|  | ||||
| bool CSpell::isRisingSpell() const | ||||
| { | ||||
| 	return vstd::contains(VLC->spellh->risingSpells, id); | ||||
| 	return _isRising; | ||||
| } | ||||
|  | ||||
| bool CSpell::isDamageSpell() const | ||||
| { | ||||
| 	return vstd::contains(VLC->spellh->damageSpells, id); | ||||
| 	return _isDamage; | ||||
| } | ||||
|  | ||||
| bool CSpell::isMindSpell() const | ||||
| { | ||||
| 	return _isMind; | ||||
| } | ||||
|  | ||||
| void CSpell::getEffects(std::vector<Bonus>& lst) const | ||||
| { | ||||
| 	lst.reserve(lst.size() + _effects.size()); | ||||
|  | ||||
| 	BOOST_FOREACH (Bonus b, _effects) | ||||
| 	{ | ||||
| 		lst.push_back(b); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos) | ||||
| { | ||||
| 	int3 diff = pos - center; | ||||
| @@ -343,7 +368,10 @@ void CSpellHandler::loadSpells() | ||||
| 	} | ||||
| 	while (parser.endLine() && !parser.isNextEntryEmpty()); | ||||
|  | ||||
| 	boost::replace_first (spells[47]->attributes, "2", ""); // disrupting ray will now affect single creature | ||||
| 	boost::replace_first (spells[Spells::DISRUPTING_RAY]->attributes, "2", ""); // disrupting ray will now affect single creature | ||||
|  | ||||
|  | ||||
| 	spells.push_back(spells[Spells::ACID_BREATH_DEFENSE]); //clone Acid Breath attributes for Acid Breath damage effect | ||||
|  | ||||
| 	//loading of additional spell traits | ||||
| 	const JsonNode config(ResourceID("config/spell_info.json")); | ||||
| @@ -367,16 +395,50 @@ void CSpellHandler::loadSpells() | ||||
| 		s->identifier = spell.first; | ||||
| 		VLC->modh->identifiers.registerObject("spell." + spell.first, spellID); | ||||
|  | ||||
| 		const JsonNode & flags_node = spell.second["flags"]; | ||||
| 		if (!flags_node.isNull()) | ||||
| 		{ | ||||
| 			auto flags = flags_node.convertTo<std::vector<std::string> >(); | ||||
|  | ||||
| 			BOOST_FOREACH (const auto & flag, flags) | ||||
| 			{ | ||||
| 				if (flag == "damage") | ||||
| 				{ | ||||
| 					s->_isDamage = true; | ||||
| 				} | ||||
| 				else if (flag == "rising") | ||||
| 				{ | ||||
| 					s->_isRising = true; | ||||
| 				} | ||||
| 				else if (flag == "mind") | ||||
| 				{ | ||||
| 					s->_isMind = true; | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		const JsonNode & effects_node = spell.second["effects"]; | ||||
|  | ||||
| 		if (!effects_node.isNull()) | ||||
| 		{ | ||||
| 			BOOST_FOREACH (const JsonNode & bonus_node, effects_node.Vector()) | ||||
| 			{ | ||||
| 				Bonus * b = JsonUtils::parseBonus(bonus_node); | ||||
| 				b->sid = s->id; | ||||
| 				b->source = Bonus::SPELL_EFFECT; | ||||
| 				b->duration = Bonus::N_TURNS; //default | ||||
| 				//TODO: make duration configurable | ||||
| 				s->_effects.push_back(*b); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	//spell fixes | ||||
|  | ||||
| 	spells.push_back(spells[80]); //clone Acid Breath attributes for Acid Breath damage effect | ||||
| 	//forgetfulness needs to get targets automatically on expert level | ||||
| 	boost::replace_first(spells[61]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead? | ||||
|  | ||||
| 	damageSpells += 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 57, 77; | ||||
| 	risingSpells += 38, 39, 40; | ||||
| 	mindSpells += 50, 59, 60, 61, 62; | ||||
| 	boost::replace_first(spells[Spells::FORGETFULNESS]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead? | ||||
| } | ||||
|  | ||||
| std::vector<ui8> CSpellHandler::getDefaultAllowedSpells() const | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "../lib/ConstTransitivePtr.h" | ||||
| #include "int3.h" | ||||
| #include "GameConstants.h" | ||||
| #include "HeroBonus.h" | ||||
|  | ||||
| /* | ||||
|  * CSpellHandler.h, part of VCMI engine | ||||
| @@ -44,20 +45,38 @@ public: | ||||
| 	std::vector<std::string> range; //description of spell's range in SRSL by magic school level | ||||
| 	std::vector<TSpell> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs) | ||||
|  | ||||
| 	CSpell(); | ||||
|  | ||||
| 	std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret) | ||||
| 	si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none) | ||||
| 	ETargetType getTargetType() const; | ||||
|  | ||||
| 	bool isPositive() const; | ||||
| 	bool isNegative() const; | ||||
|  | ||||
| 	bool isRisingSpell() const; | ||||
| 	bool isDamageSpell() const; | ||||
| 	bool isMindSpell() const; | ||||
|  | ||||
|  | ||||
| 	void getEffects(std::vector<Bonus> & lst) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & identifier & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs | ||||
| 			& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range & counteredSpells & mainEffectAnim; | ||||
| 		h & _isRising & _isDamage & _isMind; | ||||
| 		h & _effects; | ||||
| 	} | ||||
| 	friend class CSpellHandler; | ||||
|  | ||||
| private: | ||||
| 	bool _isRising; | ||||
| 	bool _isDamage; | ||||
| 	bool _isMind; | ||||
|  | ||||
| 	std::vector<Bonus> _effects; | ||||
|  | ||||
| }; | ||||
|  | ||||
| namespace Spells | ||||
| @@ -68,18 +87,18 @@ namespace Spells | ||||
| 		FLY=6, WATER_WALK=7, DIMENSION_DOOR=8, TOWN_PORTAL=9, | ||||
|  | ||||
| 		QUICKSAND=10, LAND_MINE=11, FORCE_FIELD=12, FIRE_WALL=13, EARTHQUAKE=14, | ||||
| 		MAGIC_ARROW=15, ICE_BOLT=16, LIGHTNING_BOLT=17, IMPLOSION=18,  | ||||
| 		CHAIN_LIGHTNING=19, FROST_RING=20, FIREBALL=21, INFERNO=22,  | ||||
| 		METEOR_SHOWER=23, DEATH_RIPPLE=24, DESTROY_UNDEAD=25, ARMAGEDDON=26,  | ||||
| 		SHIELD=27, AIR_SHIELD=28, FIRE_SHIELD=29, PROTECTION_FROM_AIR=30,  | ||||
| 		PROTECTION_FROM_FIRE=31, PROTECTION_FROM_WATER=32,  | ||||
| 		PROTECTION_FROM_EARTH=33, ANTI_MAGIC=34, DISPEL=35, MAGIC_MIRROR=36,  | ||||
| 		CURE=37, RESURRECTION=38, ANIMATE_DEAD=39, SACRIFICE=40, BLESS=41,  | ||||
| 		CURSE=42, BLOODLUST=43, PRECISION=44, WEAKNESS=45, STONE_SKIN=46,  | ||||
| 		DISRUPTING_RAY=47, PRAYER=48, MIRTH=49, SORROW=50, FORTUNE=51,  | ||||
| 		MISFORTUNE=52, HASTE=53, SLOW=54, SLAYER=55, FRENZY=56,  | ||||
| 		TITANS_LIGHTNING_BOLT=57, COUNTERSTRIKE=58, BERSERK=59, HYPNOTIZE=60,  | ||||
| 		FORGETFULNESS=61, BLIND=62, TELEPORT=63, REMOVE_OBSTACLE=64, CLONE=65,  | ||||
| 		MAGIC_ARROW=15, ICE_BOLT=16, LIGHTNING_BOLT=17, IMPLOSION=18, | ||||
| 		CHAIN_LIGHTNING=19, FROST_RING=20, FIREBALL=21, INFERNO=22, | ||||
| 		METEOR_SHOWER=23, DEATH_RIPPLE=24, DESTROY_UNDEAD=25, ARMAGEDDON=26, | ||||
| 		SHIELD=27, AIR_SHIELD=28, FIRE_SHIELD=29, PROTECTION_FROM_AIR=30, | ||||
| 		PROTECTION_FROM_FIRE=31, PROTECTION_FROM_WATER=32, | ||||
| 		PROTECTION_FROM_EARTH=33, ANTI_MAGIC=34, DISPEL=35, MAGIC_MIRROR=36, | ||||
| 		CURE=37, RESURRECTION=38, ANIMATE_DEAD=39, SACRIFICE=40, BLESS=41, | ||||
| 		CURSE=42, BLOODLUST=43, PRECISION=44, WEAKNESS=45, STONE_SKIN=46, | ||||
| 		DISRUPTING_RAY=47, PRAYER=48, MIRTH=49, SORROW=50, FORTUNE=51, | ||||
| 		MISFORTUNE=52, HASTE=53, SLOW=54, SLAYER=55, FRENZY=56, | ||||
| 		TITANS_LIGHTNING_BOLT=57, COUNTERSTRIKE=58, BERSERK=59, HYPNOTIZE=60, | ||||
| 		FORGETFULNESS=61, BLIND=62, TELEPORT=63, REMOVE_OBSTACLE=64, CLONE=65, | ||||
| 		SUMMON_FIRE_ELEMENTAL=66, SUMMON_EARTH_ELEMENTAL=67, SUMMON_WATER_ELEMENTAL=68, SUMMON_AIR_ELEMENTAL=69, | ||||
|  | ||||
| 		STONE_GAZE=70, POISON=71, BIND=72, DISEASE=73, PARALYZE=74, AGE=75, DEATH_CLOUD=76, THUNDERBOLT=77, | ||||
| @@ -96,9 +115,7 @@ class DLL_LINKAGE CSpellHandler | ||||
| public: | ||||
| 	CSpellHandler(); | ||||
| 	std::vector< ConstTransitivePtr<CSpell> > spells; | ||||
| 	std::set<TSpell> damageSpells; //they inflict damage and require particular threatment | ||||
| 	std::set<TSpell> risingSpells; //they affect dead stacks and need special target selection | ||||
| 	std::set<TSpell> mindSpells; | ||||
|  | ||||
| 	void loadSpells(); | ||||
|  | ||||
| 	/** | ||||
| @@ -110,6 +127,6 @@ public: | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & spells & damageSpells & risingSpells & mindSpells; | ||||
| 		h & spells ; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -955,7 +955,7 @@ void CMapLoaderH3M::readDefInfo() | ||||
| 			defInfo->visitMap[zi] = reverse(bytes[6 + zi]); | ||||
| 		} | ||||
| 		pos += 16; | ||||
| 		if(defInfo->id != Obj::HERO && defInfo->id != 70) | ||||
| 		if(defInfo->id != Obj::HERO && defInfo->id != Obj::RANDOM_HERO) | ||||
| 		{ | ||||
| 			CGDefInfo * h = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid]; | ||||
| 			if(!h) | ||||
| @@ -1160,11 +1160,22 @@ void CMapLoaderH3M::readObjects() | ||||
| 		case Obj::FLOTSAM: | ||||
| 		case Obj::SEA_CHEST: | ||||
| 		case Obj::SHIPWRECK_SURVIVOR: | ||||
| 		case Obj::TREASURE_CHEST: | ||||
| 			{ | ||||
| 				nobj = new CGPickable(); | ||||
| 				break; | ||||
| 			} | ||||
| 		case Obj::TREASURE_CHEST: | ||||
| 				if(defInfo->subid == 0) | ||||
| 				{ | ||||
| 					nobj = new CGPickable(); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					//WoG pickable object | ||||
| 					//TODO: possible special handling | ||||
| 					nobj = new CGObjectInstance(); | ||||
| 				} | ||||
| 				break; | ||||
| 		case Obj::MONSTER:  //Monster | ||||
| 		case Obj::RANDOM_MONSTER: | ||||
| 		case Obj::RANDOM_MONSTER_L1: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user