2
0
Эх сурвалжийг харах

Merged Warmonger's changes from trunk

Michał W. Urbańczyk 15 жил өмнө
parent
commit
31fc8f6db3

+ 1 - 1
AI/EmptyAI/CEmptyAI.cpp

@@ -17,7 +17,7 @@ void CEmptyAI::heroKilled(const CGHeroInstance *)
 void CEmptyAI::heroCreated(const CGHeroInstance *)
 {
 }
-void CEmptyAI::heroMoved(const HeroMoveDetails &)
+void CEmptyAI::heroMoved(const TryMoveHero& TMH)
 {
 }
 void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)

+ 1 - 1
AI/EmptyAI/CEmptyAI.h

@@ -11,7 +11,7 @@ public:
 	void yourTurn();
 	void heroKilled(const CGHeroInstance *);
 	void heroCreated(const CGHeroInstance *);
-	void heroMoved(const HeroMoveDetails &);
+	void heroMoved(const TryMoveHero&);
 	void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
 	void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
 	void tileRevealed(int3 pos){};

+ 28 - 15
AI/GeniusAI/ExpertSystem.cpp

@@ -14,9 +14,9 @@
 
 template <typename ruleType, typename facts> template <typename cond> void ExpertSystemShell<ruleType, facts>::DataDrivenReasoning(runType type)
 {
-	std::set<ruleType>::iterator ir;
+	std::vector<ruleType>::iterator ir;
 	std::list<fact>::iterator iF;
-	std::set<std::pair<cond, input*>>::iterator ic;
+	std::vector<std::pair<cond, input*>>::iterator ic;
 	bool factWasAdded = false; //carry it over inner loop
 	switch (type)
 	{
@@ -72,7 +72,7 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
 }
 void BonusRule::fireRule()
 {
-	for (std::set<std::pair<BonusCondition, BonusHolder*>>::iterator it = cons.begin(); it != cons.end(); it++)
+	for (std::vector<std::pair<BonusCondition, BonusHolder*>>::iterator it = cons.begin(); it != cons.end(); it++)
 	{
 		switch (it->first.parameter)
 		{ //compare fact with condition
@@ -109,18 +109,31 @@ void BonusRule::fireRule()
 	}
 	//TODO: add new fact or modify existing one
 }
-//TODO: find out why it does not compile
-//template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::set<conType> &conditionSet)
-//{
-//	cons.clear();
-//	for (std::set<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
-//		cons.insert(std::make_pair<conType,input*>(*it, NULL)); //pointer to condition and null fact
-//}
-//template <typename input, typename conType> void Rule<input, conType>::refreshRule()
-//{
-//	for (std::set<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
-//		*it->second = NULL;
-//}
+
+TLogic operator&&(const TLogic &first, const TLogic &second)
+{
+	return LogicConjunction(first, second);
+}
+TLogic operator||(const TLogic &first, const TLogic &second)
+{
+	return LogicAlternative(first, second);
+}
+template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::vector<conType> &conditionSet)
+{//replace conditions with new vector
+	cons.clear();
+	std::pair <conType,input*> para;
+	para.second = NULL;
+	for (std::vector<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
+	{
+		para.first = *it;
+		cons.push_back(para); //pointer to condition and null fact
+	}
+}
+template <typename input, typename conType> void Rule<input, conType>::refreshRule()
+{//clear matching facts
+	for (std::vector<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
+		it->second = NULL;
+}
 bool BonusCondition::matchesFact(Bonus &fact)
 {
 	if (object(fact)) //Bonus(fact) matches local Selector(object)

+ 45 - 14
AI/GeniusAI/ExpertSystem.h

@@ -2,7 +2,7 @@
 #include "../vcmi/CCallback.h"
 #include "../vcmi/lib/HeroBonus.h"
 #include <boost/bind.hpp>
-#include <set>
+#include <vector>
 
 /*
  * ExpertSystem.h, part of VCMI engine
@@ -17,21 +17,22 @@ struct Bonus;
 template <typename fact> class AIholder;
 template <typename input, typename output> class Rule;
 typedef Rule<Bonus, Bonus> BRule;
+typedef boost::function<bool(int, si32)> TLogic;
 bool greaterThan (int prop, si32 val);
 
 enum conditionType {LESS_THAN, EQUAL, GREATER_THAN, UNEQUAL, PRESENT};
 
 template <typename ruleType, typename fact> class ExpertSystemShell
 {
-	enum runType {ANY_GOAL, TRESHOLD, FULL};
+	enum runType {ANY_GOAL, TRESHOLD, FULL}; //Treshold - stop when received decision has high AI value
 private:
 	ICallback* m_cb;
 protected:
-	std::set<ruleType> knowledge;
-	std::set<ruleType*> rulesToErase;
-	std::set<ruleType*> rulesToAdd;
-	std::set<fact*> factsToErase;
-	std::set<fact*> factsToAdd;
+	std::vector<ruleType> knowledge;
+	std::vector<ruleType*> rulesToErase;
+	std::vector<ruleType*> rulesToAdd;
+	std::vector<fact*> factsToErase;
+	std::vector<fact*> factsToAdd;
 	ui16 goalCounter; //count / evaluate achieved goals for runType
 public:
 	ExpertSystemShell(){goalCounter = 0;};
@@ -53,12 +54,12 @@ public:
 };
 
 template <typename input> class condition
-{//compares selected object parameter with value using functor. universal logic handler
+{//compares selected object parameter with value using functor. universal (?) logic handler
 public:
 	input object; //what the fact is, or what it's like (CSelector)
 	si32 value;
 	ui8 parameter;
-	boost::function<bool(int,si32)> functor; //value of selected parameter, condition value
+	TLogic functor; //value of selected parameter, condition value
 
 	condition(){object = NULL; value = 0; parameter = 0; functor = greaterThan;};
 
@@ -72,16 +73,16 @@ public:
 	bool fired; //if conditions of rule were met and it produces some output
 	ui8 conditionCounter;
 protected:
-	std::set<std::pair<conType, input*>> cons; //conditions and matching facts
+	std::vector<std::pair<conType, input*>> cons; //conditions and matching facts
 	input decision;
 	virtual void canBeFired(); //if this data makes any sense for rule - type check
 	virtual bool checkCondition(); //if condition is true or false
-	virtual bool checkCondition(std::set<input*> &feed);
+	virtual bool checkCondition(std::vector<input*> &feed);
 	virtual void fireRule(); //use paired conditions and facts by default
 	virtual void fireRule(ExpertSystemShell<input, conType> &system);
-	virtual void fireRule(std::set<input*> &feed);
+	virtual void fireRule(std::vector<input*> &feed);
 	virtual void refreshRule();
-	virtual void refreshRule(std::set<conType> &conditionSet); //in case conditions were erased
+	virtual void refreshRule(std::vector<conType> &conditionSet); //in case conditions were erased
 public:
 	Rule(){fired = false; conditionCounter = 0; decision = NULL;};
 	template <typename givenInput> bool matchesInput() //if condition and data match type
@@ -142,7 +143,7 @@ protected:
 	void fireRule();
 };
 
-inline bool greaterThan (int prop, si32 val)
+inline bool greaterThan (int prop, si32 val) //does it make any sense to keep functors inline?
 {
 	if ((si32)prop > val)
 		return true;
@@ -172,6 +173,36 @@ inline bool present (int prop, si32 val=0)
 	return(prop); //unfixable warning :(
 }
 
+class LogicConjunction
+{
+	const TLogic first, second; //TODO: universal argument list of functions?
+public:
+	LogicConjunction(const TLogic First, const TLogic Second)
+		:first(First), second(Second)
+	{
+	}
+	bool operator()(int prop, si32 val) const
+	{
+		return first(prop,val) && second(prop,val);
+	}
+};
+TLogic operator&&(const TLogic &first, const TLogic &second);
+
+class LogicAlternative
+{
+	const TLogic first, second;
+public:
+	LogicAlternative(const TLogic First, const TLogic Second)
+		:first(First), second(Second)
+	{
+	}
+	bool operator()(int prop, si32 val) const
+	{
+		return first(prop,val) || second(prop,val); 
+	}
+};
+TLogic operator||(const TLogic &first, const TLogic &second);
+
 class KnowledgeHandler///I'd opt for one omniscent knowledge manager, so no templates here
 {
 public:

+ 1 - 0
client/CSndHandler.cpp

@@ -46,6 +46,7 @@ void CMediaHandler::extract(int index, std::string dstfile) //saves selected fil
 
 void CMediaHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
 {
+	srcfile.erase(srcfile.find_last_of('.'));
 	if (caseSens)
 	{
 		for (size_t i=0;i<entries.size();++i)

+ 41 - 0
config/bonusnames.txt

@@ -0,0 +1,41 @@
+Bonus	Name (24 characters?)	Description
+FLYING	Fly	Can Fly (ignores obstacles)
+UNLIMITED_RETALIATIONS	Unlimited retaliations	May retaliate any number of attacks
+SHOOTER	Ranged	Creature can make a Ranged Attack
+FREE_SHOOTING	Shoot Close	Can make a Ranged Attack in Close Combat
+NO_SHOTING_PENALTY	?	???
+NO_MELEE_PENALTY	No melee penalty	Creature has no Melee Penalty
+NO_DISTANCE_PENALTY	No distance penalty	Does full ranged damage from any distance
+NO_OBSTACLES_PENALTY	No obstacle penalty	Creature has no Obstacle Penalty
+JOUSTING	Champion	Champion Distance Bonus (+5% damage per square travelled)
+RETURN_AFTER_STRIKE	Attack and Return	Returns to starting position after making a melee attack
+BLOCKS_RETALIATION	No retaliation	Enemy cannot Retaliate
+TWO_HEX_ATTACK_BREATH	Breath	Creature has a Breath Attack (2-hex range)
+THREE_HEADED_ATTACK	Three-headed attack	Creature attacks three adjacent units
+ATTACKS_ALL_ADJACENT	Attack all around	Creature attacks all adjacent enemies
+FULL_HP_REGENERATION	Regeneration	May Regenerate full Health
+LIFE_DRAIN	Drain life	Drains life equal to damage dealt
+SELF_MORALE	Positive morale	Always has Positive Morale
+SELF_LUCK	Positive luck	Always has Positive Luck
+FEAR	Fear	Has a chance to cause Fear on an enemy stack
+FEARLESS	Fearless	Immune to Fear ability
+CHARGE_IMMUNITY	Immune to Charge	Immune to Champion charge bonus
+HEALER	Healer	Heals allied units
+CATAPULT 	Catapult	Attacks siege walls
+DRAGON_NATURE	Dragon	Creature has a Dragon Nature
+NON_LIVING	Non living	Creature is immune to effects affecting Living units
+UNDEAD	Undead	Creature is Undead
+HATE	Hates %s	Does more damage to %s
+DOUBLE_DAMAGE_CHANCE	Death Blow	Has %d% chance to deal double damage
+MAGIC_RESISTANCE	Magic Resistance	Has %d% chance to resist enemy spell
+SPELL_DAMAGE_REDUCTION	Spell Resistance	Damage from spells reduced 50%.
+LEVEL_SPELL_IMMUNITY	Spell immunity 1-%d	Immune to spells levels 1-%d
+HP_REGENERATION	Regeneration	Heals %d hit points every round
+SPELL_IMMUNITY	Immune to %s	Immune to %s spell
+ENEMY_DEFENCE_REDUCTION	Reduces Enemy Defense	Reduces Enemy Defense by %d% for this attack
+MAGIC_MIRROR	Magic Mirror	Has %d% chance to redirect offensive spell back to enemy
+ADDITIONAL_RETALIATION	Additional retaliations	May Retaliate %d extra times
+CHANGES_SPELL_COST_FOR_ALLY	Reduce Casting Cost 	Reduce Casting Cost of allied hero spells by %d
+CHANGES_SPELL_COST_FOR_ENEMY	Magic Damper	Increase Casting Cost of enemy hero spells by %d
+MANA_CHANNELING	Magic Channel	%d% mana spent by enemy is transfered to your hero
+SPELL_AFTER_ATTACK	Caster - %s	%d% chance to cast %s after attack

+ 4 - 2
global.h

@@ -20,7 +20,8 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
 typedef si64 expType;
 typedef ui16 spelltype;
 typedef std::pair<ui32, ui32> TDmgRange;
-
+typedef ui8 TBonusType;
+typedef si32 TBonusSubtype;
 #include "int3.h"
 #include <map>
 #include <vector>
@@ -117,11 +118,12 @@ const int NAMES_PER_TOWN=16;
 const int CREATURES_PER_TOWN = 7; //without upgrades
 const int MAX_BUILDING_PER_TURN = 1;
 const int SPELL_LEVELS = 5;
-//const int CREEP_SIZE = 4000; // neutral stacks won't grow beyon this number
+//const int CREEP_SIZE = 4000; // neutral stacks won't grow beyond this number
 const int CREEP_SIZE = 2000000000;
 const int WEEKLY_GROWTH = 10; //percent
 const int AVAILABLE_HEROES_PER_PLAYER = 2;
 const bool DWELLINGS_ACCUMULATE_CREATURES = true;
+const bool STACK_EXP = true;
 
 const int BFIELD_WIDTH = 17;
 const int BFIELD_HEIGHT = 11;

+ 98 - 0
lib/CCreatureHandler.cpp

@@ -12,6 +12,7 @@
 #include <boost/algorithm/string/replace.hpp>
 #include "../lib/VCMI_Lib.h"
 #include "../lib/CGameState.h"
+#include <boost/foreach.hpp>
 
 using namespace boost::assign;
 extern CLodHandler * bitmaph;
@@ -590,6 +591,69 @@ void CCreatureHandler::loadCreatures()
 		inp3 >> factionToTurretCreature[g];
 	}
 	inp3.close();
+
+	//reading creature ability names
+	ifs.open(DATA_DIR "/config/bonusnames.txt");
+	{
+		std::string buf2, buf3, line;
+		int i;
+		std::map<std::string,int>::const_iterator it;
+		getline(ifs, line); //skip 1st line
+		while(!ifs.eof())
+		{
+			getline(ifs, buf, '\t');
+			getline(ifs, buf2, '\t');
+			getline(ifs, buf3);
+			it = bonusNameMap.find(buf);
+			if (it != bonusNameMap.end())
+				stackBonuses[it->second] = std::pair<std::string, std::string>(buf2,buf3);
+			else
+				tlog2 << "Bonus " << buf << " not recognized, ingoring\n";
+		}
+	}
+	ifs.close();
+
+	if (STACK_EXP) 	//reading default stack experience bonuses
+	{
+		buf = bitmaph->getTextFile("CREXPBON.TXT");
+		int it = 0;
+		si32 creid = -1;
+		commonBonuses.resize(8); //8 tiers
+		stackExperience b;
+		b.expBonuses.resize(10);
+		b.source = Bonus::STACK_EXPERIENCE;
+
+		loadToIt (dump2, buf, it, 3); //ignore first line
+		loadToIt (dump2, buf, it, 4); //ignore index
+		loadStackExp(b, buf, it);
+		loadToIt (dump2, buf, it, 4); //crop comment
+		for (i = 0; i < 8; ++i)
+		{
+			commonBonuses[i].push_back(new stackExperience(b));//health bonus common for all
+			for (int j = 0; j < 4; ++j) //four modifiers common for tiers
+			{
+				loadToIt (dump2, buf, it, 4); //ignore index
+				loadStackExp(b, buf, it);
+				commonBonuses[i].push_back(new stackExperience(b));
+				loadToIt (dump2, buf, it, 3); //crop comment
+			}
+		}
+		do //parse everything that's left
+		{
+			loadToIt(creid, buf, it, 4); //get index
+			loadStackExp(b, buf, it);
+			creatures[creid]->bonuses.push_back(new stackExperience(b)); //experience list is common for creatures of that type
+			loadToIt (dump2, buf, it, 3); //crop comment
+		} while (it < buf.size());
+
+ 		BOOST_FOREACH(CCreature *c, creatures)
+ 		{
+ 			if (it = c->level < 7)
+ 				std::copy(commonBonuses[it-1].begin(), commonBonuses[it-1].end(), c->bonuses.begin());
+ 			else
+ 				std::copy(commonBonuses[7].begin(), commonBonuses[7].end(), c->bonuses.begin()); //common for tiers 8+
+ 		}
+	} //end of stack experience
 }
 
 void CCreatureHandler::loadAnimationInfo()
@@ -662,6 +726,40 @@ void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, std::string & src, int
 	i+=2;
 }
 
+void CCreatureHandler::loadStackExp(stackExperience & b, std::string & src, int & it) //help function for parsing CREXPBON.txt, assuming all its details are already defined
+{
+	std::string buf, mod;
+	loadToIt(buf, src, it, 4);
+	loadToIt(mod, src, it, 4);
+	switch (buf[0])
+	{
+	case 'H':
+		b.type = Bonus::STACK_HEALTH;
+		break;
+	case 'A':
+		b.type = Bonus::PRIMARY_SKILL;
+		b.subtype = PrimarySkill::ATTACK;
+		break;
+	case 'D':
+		b.type = Bonus::PRIMARY_SKILL;
+		b.subtype = PrimarySkill::DEFENSE;
+		break;
+	case 'M': //Max damage
+		b.type = Bonus::CREATURE_DAMAGE;
+		b.subtype = 2;
+		break;
+	case 'm': //Min damage
+		b.type = Bonus::CREATURE_DAMAGE;
+		b.subtype = 1;
+		break;
+	}
+	loadToIt (b.val, src, it, 4); //basic value, not particularly useful but existent
+	for (int i = 0; i < 10; ++i)
+	{
+		loadToIt (b.expBonuses[i], src, it, 4); //vector must have length 10
+	}
+}
+
 CCreatureHandler::~CCreatureHandler()
 {
 }

+ 4 - 0
lib/CCreatureHandler.h

@@ -113,9 +113,13 @@ public:
 	std::vector<si8> factionAlignments; //1 for good, 0 for neutral and -1 for evil with faction ID as index
 	int factionToTurretCreature[F_NUMBER]; //which creature's animation should be used to dispaly creature in turret while siege
 
+	std::map<TBonusType, std::pair<std::string, std::string> > stackBonuses; // bonus => name, description
+	std::vector<BonusList> commonBonuses; // levels 1-8 from CREXPBON.txt
+
 	void loadCreatures();
 	void loadAnimationInfo();
 	void loadUnitAnimInfo(CCreature & unit, std::string & src, int & i);
+	void loadStackExp(stackExperience & b, std::string & src, int & it);
 
 	bool isGood (si8 faction) const;
 	bool isEvil (si8 faction) const;

+ 97 - 0
lib/CCreatureSet.cpp

@@ -8,6 +8,9 @@
 #include "CGameState.h"
 #include "CGeneralTextHandler.h"
 #include <sstream>
+#include "CSpellHandler.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string/replace.hpp>
 
 const CStackInstance &CCreatureSet::operator[](TSlot slot) const
 {
@@ -441,6 +444,100 @@ void CStackInstance::setType(const CCreature *c)
 
 	attachTo(const_cast<CCreature*>(type));
 }
+std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
+{
+	std::map<TBonusType, std::pair<std::string, std::string>>::iterator it = VLC->creh->stackBonuses.find(bonus->type);
+	if (it != VLC->creh->stackBonuses.end())
+	{
+		std::string text;
+		if (description) //long ability description
+		{
+			text = it->second.second;
+			switch (bonus->type)
+			{
+				//no additional modifiers needed
+				case Bonus::FLYING:
+				case Bonus::UNLIMITED_RETALIATIONS:
+				case Bonus::SHOOTER:
+				case Bonus::FREE_SHOOTING:
+				case Bonus::NO_SHOTING_PENALTY:
+				case Bonus::NO_MELEE_PENALTY:
+				case Bonus::NO_DISTANCE_PENALTY:
+				case Bonus::NO_OBSTACLES_PENALTY:
+				case Bonus::JOUSTING: //TODO: percent bonus?
+				case Bonus::RETURN_AFTER_STRIKE:
+				case Bonus::BLOCKS_RETALIATION:
+				case Bonus::TWO_HEX_ATTACK_BREATH:
+				case Bonus::THREE_HEADED_ATTACK:
+				case Bonus::ATTACKS_ALL_ADJACENT:
+				case Bonus::FULL_HP_REGENERATION:
+				case Bonus::LIFE_DRAIN: //TODO: chance, hp percentage?
+				case Bonus::SELF_MORALE:
+				case Bonus::SELF_LUCK:
+				case Bonus::FEAR:
+				case Bonus::FEARLESS:
+				case Bonus::CHARGE_IMMUNITY:
+				case Bonus::HEALER:
+				case Bonus::CATAPULT:
+				case Bonus::DRAGON_NATURE:
+				case Bonus::NON_LIVING:
+				case Bonus::UNDEAD:
+				break;
+				//One numeric value
+				//case Bonus::STACKS_SPEED: //Do we need description for creature stats?
+				//case Bonus::STACK_HEALTH:
+				case Bonus::MAGIC_RESISTANCE:
+				case Bonus::SPELL_DAMAGE_REDUCTION:
+				case Bonus::LEVEL_SPELL_IMMUNITY:
+				case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
+				case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
+				case Bonus::MANA_CHANNELING:
+				case Bonus::MANA_DRAIN:
+				case Bonus::HP_REGENERATION:
+				case Bonus::ADDITIONAL_RETALIATION:
+				case Bonus::DOUBLE_DAMAGE_CHANCE:
+				case Bonus::ENEMY_DEFENCE_REDUCTION:
+				case Bonus::MAGIC_MIRROR:
+				case Bonus::DARKNESS: //Darkness Dragons any1?
+					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
+					break;
+				//Complex descriptions
+				case Bonus::HATE: //TODO: customize damage percent
+					boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
+					break;
+				case Bonus::SPELL_IMMUNITY:
+					boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
+					break;
+				case Bonus::SPELL_AFTER_ATTACK:
+					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->additionalInfo % 100));
+					boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
+					break;
+				default:
+					{}//TODO: allow custom bonus types... someday, somehow
+			}
+		}
+		else //short name
+		{
+			text = it->second.first;
+			switch (bonus->type)
+			{
+				case Bonus::HATE:
+					boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
+					break;
+				case Bonus::LEVEL_SPELL_IMMUNITY:
+					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
+					break;
+				case Bonus::SPELL_IMMUNITY:
+				case Bonus::SPELL_AFTER_ATTACK:
+					boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
+					break;
+			}
+		}
+		return text;
+	}
+	else
+		return "";
+}
 
 void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
 {

+ 1 - 0
lib/CCreatureSet.h

@@ -45,6 +45,7 @@ public:
 
 	//overrides CBonusSystemNode
 	//void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const;  //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
+	std::string bonusToString(Bonus *bonus, bool description) const; // how would bonus description look for this particular type of node
 
 	int getQuantityID() const;
 	std::string getQuantityTXT(bool capitalized = true) const;

+ 4 - 6
lib/HeroBonus.h

@@ -16,10 +16,6 @@
  *
  */
 
-
-typedef ui8 TBonusType;
-typedef si32 TBonusSubtype;
-
 class CCreature;
 class CSpell;
 struct Bonus;
@@ -159,7 +155,7 @@ namespace PrimarySkill
 	BONUS_NAME(MAXED_SPELL) /*val = id*/\
 	BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
 	BONUS_NAME(SPECIAL_UPGRADE) /*val = base, additionalInfo = target */\
-	BONUS_NAME(DRAGON_NATURE) /*TODO: implement it!*/\
+	BONUS_NAME(DRAGON_NATURE) \
 	BONUS_NAME(CREATURE_DAMAGE)/*subtype 0 = both, 1 = min, 2 = max*/
 
 struct DLL_EXPORT Bonus
@@ -198,6 +194,7 @@ struct DLL_EXPORT Bonus
 		ARMY,
 		CAMPAIGN_BONUS,
 		SPECIAL_WEEK,
+		STACK_EXPERIENCE,
 		OTHER /*used for defensive stance*/
 	};
 
@@ -309,7 +306,7 @@ struct DLL_EXPORT Bonus
 
 struct DLL_EXPORT stackExperience : public Bonus
 {
-	std::vector<ui32> expBonuses; // variations for levels 1-10, copied to val field;
+	std::vector<si32> expBonuses; // variations for levels 1-10, copied to val field;
 	bool enable; //if true - turns ability on / off for zero value
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -382,6 +379,7 @@ public:
 	void getParents(TCNodes &out) const;  //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
 	void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
 
+	virtual std::string bonusToString(Bonus *bonus, bool description) const {return "";}; //description or bonus name
 
 	//////////////////////////////////////////////////////////////////////////
 	//interface