Pārlūkot izejas kodu

Fixed #1035.
Support for commander artifacts that accumulate bonus after battle.

DjWarmonger 13 gadi atpakaļ
vecāks
revīzija
cf45239332

+ 1 - 1
client/CCreatureWindow.cpp

@@ -542,7 +542,7 @@ void CCreatureWindow::showAll(SDL_Surface * to)
 		skillPictures[i]->showAll (to);
 	}
 
-	if (upgradeOptions[selectedOption] >= 100) //add frame to selected skill
+	if (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100) //add frame to selected skill
 	{
 		int index = selectedOption - selectableSkills.size(); //this is screwed
 		CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::MetallicGold.r, Colors::MetallicGold.g, Colors::MetallicGold.b)); 

+ 81 - 0
config/commanders.json

@@ -51,5 +51,86 @@
 		{"ability": ["JOUSTING", 0, 0, 0 ], "skills": [3, 4]},
 		{"ability": ["DEATH_STARE", 1, 1, 0 ], "skills": [3,5]},
 		{"ability": ["FLYING", 0, 0, 0 ], "skills": [4,5]}
+	],
+	"artifacts":
+	[
+		{
+			"id": 146, //axe of smashing
+			"bonusesPerLevel":
+			[
+				{
+					"level": 6,
+					"bonus": ["PRIMARY_SKILL", 1, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 147, //mithril mail
+			"bonusesPerLevel":
+			[
+				{
+					"level": 1,
+					"bonus": ["STACK_HEALTH", 1, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 148, //sword of sharpness
+			"bonusesPerLevel":
+			[
+				{
+					"level": 1,
+					"bonus": ["CREATURE_DAMAGE", 1, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 150, //pendant of sorcery
+			"bonusesPerLevel":
+			[
+				{
+					"level": 10,
+					"bonus": ["CREATURE_ENCHANT_POWER", 1, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 151, //boots of haste
+			"bonusesPerLevel":
+			[
+				{
+					"level": 10,
+					"bonus": ["STACKS_SPEED", 1, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 152, //bow of seeking
+			"thresholdBonuses":
+			[
+				{
+					"level": 5,
+					"bonus": ["SHOOTER", 0, 0, 0]
+				},
+				{
+					"level": 25,
+					"bonus": ["NO_WALL_PENALTY", 0, 0, 0]
+				},
+				{
+					"level": 50,
+					"bonus": ["NO_DISTANCE_PENALTY", 0, 0, 0]
+				}
+			]
+		},
+		{
+			"id": 153, //hardened shield
+			"bonusesPerLevel":
+			[
+				{
+					"level": 6,
+					"bonus": ["PRIMARY_SKILL", 1, 1, 0]
+				}
+			]
+		}
 	]
 }

+ 65 - 8
lib/CArtHandler.cpp

@@ -8,6 +8,7 @@
 #include "CSpellHandler.h"
 #include "CObjectHandler.h"
 #include "NetPacks.h"
+#include "../lib/JsonNode.h"
 
 extern CLodHandler *bitmaph;
 using namespace boost::assign;
@@ -23,6 +24,7 @@ using namespace boost::assign;
  */
 
 extern boost::rand48 ran;
+extern Bonus * ParseBonus (const JsonVector &ability_vec);
 
 const std::string & CArtifact::Name() const
 {
@@ -44,11 +46,6 @@ bool CArtifact::isBig () const
 {
 	return VLC->arth->isBigArtifact(id);
 }
-// 
-// bool CArtifact::isModable () const
-// {
-// 	return (bool)dynamic_cast<const IModableArt *>(this);
-// }
 
 // /**
 //  * Checks whether the artifact fits at a given slot.
@@ -193,6 +190,30 @@ void CArtifact::setDescription (std::string desc)
 	description = desc;
 }
 
+void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
+{
+	Bonus b;
+	b.type = Bonus::LEVEL_COUNTER;
+	b.val = 1;
+	b.duration = Bonus::COMMANDER_KILLED;
+	art->accumulateBonus (b);
+
+	BOOST_FOREACH (auto bonus, bonusesPerLevel)
+	{
+		if (art->valOfBonuses(Bonus::LEVEL_COUNTER) % bonus.first == 0) //every n levels
+		{
+			art->accumulateBonus (bonus.second);
+		}
+	}
+	BOOST_FOREACH (auto bonus, thresholdBonuses)
+	{
+		if (art->valOfBonuses(Bonus::LEVEL_COUNTER) == bonus.first) //every n levels
+		{
+			art->addNewBonus (&bonus.second);
+		}
+	}
+}
+
 CArtHandler::CArtHandler()
 {
 	VLC->arth = this;
@@ -215,6 +236,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 {
 	std::vector<ui16> slots;
 	slots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
+	growingArtifacts += 146, 147, 148, 150, 151, 152, 153;
 	static std::map<char, CArtifact::EartClass> classes = 
 	  map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC);
 	std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom;
@@ -226,10 +248,18 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 	VLC->generaltexth->artifNames.resize(GameConstants::ARTIFACTS_QUANTITY);
 	VLC->generaltexth->artifDescriptions.resize(GameConstants::ARTIFACTS_QUANTITY);
 	std::map<ui32,ui8>::iterator itr;
+
 	for (int i=0; i<GameConstants::ARTIFACTS_QUANTITY; i++)
 	{
-		CArtifact *art = new CArtifact();
-
+		CArtifact *art;
+		if (vstd::contains (growingArtifacts, i))
+		{
+			art = new CGrowingArtifact();
+		}
+		else
+		{
+			art = new CArtifact();
+		}
 		CArtifact &nart = *art;
 		nart.id=i;
 		loadToIt(VLC->generaltexth->artifNames[i],buf,it,4);
@@ -329,6 +359,23 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 
 		artifacts.push_back(&nart);
 	}
+	if (GameConstants::COMMANDERS)
+	{ //TODO: move all artifacts config to separate json file
+		const JsonNode config(GameConstants::DATA_DIR + "/config/commanders.json");
+		BOOST_FOREACH(const JsonNode &artifact, config["artifacts"].Vector())
+		{
+			auto ga = dynamic_cast <CGrowingArtifact *>(artifacts[artifact["id"].Float()].get()); 
+			BOOST_FOREACH (auto b, artifact["bonusesPerLevel"].Vector())
+			{
+				ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
+			}
+			BOOST_FOREACH (auto b, artifact["thresholdBonuses"].Vector())
+			{
+				ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
+			}
+		}
+	}
+
 	sortArts();
 	if(onlyTxt)
 		return;
@@ -1112,7 +1159,17 @@ void CArtifactInstance::move(ArtifactLocation src, ArtifactLocation dst)
 CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
 {
 	if(!Art->constituents)
-		return new CArtifactInstance(Art);
+	{
+		auto ret = new CArtifactInstance(Art);
+		if (dynamic_cast<CGrowingArtifact *>(Art))
+		{
+			Bonus * bonus = new Bonus;
+			bonus->type = Bonus::LEVEL_COUNTER;
+			bonus->val = 0;
+			ret->addNewBonus (bonus);
+		}
+		return ret;
+	}
 	else
 	{
 		CCombinedArtifactInstance * ret = new CCombinedArtifactInstance(Art);

+ 21 - 2
lib/CArtHandler.h

@@ -18,6 +18,7 @@ class CArtifact;
 class CGHeroInstance;
 struct ArtifactLocation;
 class CArtifactSet;
+class CArtifactInstance;
 
 namespace ArtifactPosition
 {
@@ -55,6 +56,8 @@ public:
 	int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other
 	std::string nodeName() const OVERRIDE;
 
+	virtual void levelUpArtifact (CArtifactInstance * art){};
+
 	ui32 price;
 	bmap<ui8, std::vector<ui16> > possibleSlots; //Bearer Type => ids of slots where artifact can be placed
 	std::vector<ui32> * constituents; // Artifacts IDs a combined artifact consists of, or NULL.
@@ -75,6 +78,21 @@ public:
 	//void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
 };
 
+class DLL_LINKAGE CGrowingArtifact : public CArtifact //for example commander artifacts getting bonuses after battle
+{
+public:
+	std::vector <std::pair <ui16, Bonus> > bonusesPerLevel; //bonus given each n levels
+	std::vector <std::pair <ui16, Bonus> > thresholdBonuses; //after certain level they will be added once
+
+	void levelUpArtifact (CArtifactInstance * art);
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CArtifact&>(*this);
+		h & bonusesPerLevel & thresholdBonuses;
+	}
+};
+
 class DLL_LINKAGE CArtifactInstance : public CBonusSystemNode
 {
 protected:
@@ -170,7 +188,7 @@ public:
 	std::vector< ConstTransitivePtr<CArtifact> > artifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
-	//std::map<ui32, ui8> modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus
+	std::set<ui32> growingArtifacts;
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
@@ -194,7 +212,8 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & artifacts & allowedArtifacts & treasures & minors & majors & relics;
+		h & artifacts & allowedArtifacts & treasures & minors & majors & relics
+			& growingArtifacts;
 		//if(!h.saving) sortArts();
 	}
 };

+ 0 - 18
lib/CCreatureHandler.cpp

@@ -202,24 +202,6 @@ bool CCreatureHandler::isEvil (si8 faction) const
 {
 	return faction != -1 && factionAlignments[faction] == -1;
 }
-static Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
-{
-	Bonus * b = new Bonus();
-	std::string type = ability_vec[0].String();
-	auto it = bonusNameMap.find(type);
-	if (it == bonusNameMap.end())
-	{
-		tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
-		return b;
-	}
-	b->type = it->second;
-	b->val = ability_vec[1].Float();
-	b->subtype = ability_vec[2].Float();
-	b->additionalInfo = ability_vec[3].Float();
-	b->duration = Bonus::PERMANENT;
-	b->turnsRemain = 0;
-	return b;
-}
 
 static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
 {

+ 1 - 1
lib/CCreatureSet.cpp

@@ -1010,7 +1010,7 @@ void CCommanderInstance::setAlive (bool Alive)
 	alive = Alive;
 	if (!alive)
 	{
-		//remove all bonuses from artifacts
+		getBonusList().remove_if (Bonus::UntilCommanderKilled);
 	}
 }
 

+ 7 - 1
lib/HeroBonus.h

@@ -35,6 +35,7 @@ typedef boost::function<bool(const Bonus*)> CSelector;
 
 #define BONUS_LIST										\
 	BONUS_NAME(NONE) 									\
+	BONUS_NAME(LEVEL_COUNTER) /* for commander artifacts*/ \
 	BONUS_NAME(MOVEMENT) /*both water/land*/			\
 	BONUS_NAME(LAND_MOVEMENT) \
 	BONUS_NAME(SEA_MOVEMENT) \
@@ -194,7 +195,8 @@ struct DLL_LINKAGE Bonus
 		N_DAYS = 32,
 		UNITL_BEING_ATTACKED = 64,/*removed after attack and counterattacks are performed*/
 		UNTIL_ATTACK = 128, /*removed after attack and counterattacks are performed*/
-		STACK_GETS_TURN = 256 /*removed when stack gets its turn - used for defensive stance*/
+		STACK_GETS_TURN = 256, /*removed when stack gets its turn - used for defensive stance*/
+		COMMANDER_KILLED = 512
 	};
 	enum BonusSource
 	{
@@ -303,6 +305,10 @@ struct DLL_LINKAGE Bonus
 	{
 		return hb->duration & Bonus::UNITL_BEING_ATTACKED;
 	}
+	static bool UntilCommanderKilled(const Bonus *hb)
+	{
+		return hb->duration & Bonus::COMMANDER_KILLED;
+	}
 	static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter
 	{
 		return hb.source==source && (id==0xffffff  ||  hb.sid==id);

+ 4 - 1
lib/JsonNode.cpp

@@ -1,6 +1,9 @@
 #include "StdInc.h"
 #include "JsonNode.h"
 
+
+class Bonus;
+
 const JsonNode JsonNode::nullNode;
 
 JsonNode::JsonNode(JsonType Type):
@@ -869,4 +872,4 @@ JsonValidator::JsonValidator(JsonNode &root, const JsonNode &schema, bool Minimi
 	if (schema.isNull())
 		addMessage("Schema not found!");
 	tlog3<<errors;
-}
+}

+ 217 - 196
lib/JsonNode.h

@@ -1,200 +1,221 @@
-#pragma once
-
-
-
-class JsonNode;
-typedef std::map <std::string, JsonNode> JsonMap;
-typedef std::vector <JsonNode> JsonVector;
-
-class DLL_LINKAGE JsonNode
-{
-public:
-	enum JsonType
-	{
-		DATA_NULL,
-		DATA_BOOL,
-		DATA_FLOAT,
-		DATA_STRING,
-		DATA_VECTOR,
-		DATA_STRUCT
-	};
-
-private:
-	union JsonData
-	{
-		bool Bool;
-		double Float;
-		std::string* String;
-		JsonVector* Vector;
-		JsonMap* Struct;
-	};
-
-	JsonType type;
-	JsonData data;
-
-public:
-	//Create empty node
-	JsonNode(JsonType Type = DATA_NULL);
-	//Create tree from Json-formatted input
-	explicit JsonNode(const char * data, size_t datasize);
-	//Create tree from JSON file
- 	explicit JsonNode(std::string filename);
-	//Copy c-tor
-	JsonNode(const JsonNode &copy);
-
-	~JsonNode();
-
-	void swap(JsonNode &b);
-	JsonNode& operator =(JsonNode node);
-
-	bool operator == (const JsonNode &other) const;
-	bool operator != (const JsonNode &other) const;
-
-	//removes all nodes that are identical to default entry in schema
-	void minimize(const JsonNode& schema);
-	//check schema
-	void validate(const JsonNode& schema);
-
-	//Convert node to another type. Converting to NULL will clear all data
-	void setType(JsonType Type);
-	JsonType getType() const;
-
-	bool isNull() const;
-
-	//non-const accessors, node will change type on type mismatch
-	bool & Bool();
-	double & Float();
-	std::string & String();
-	JsonVector & Vector();
-	JsonMap & Struct();
-
-	//const accessors, will cause assertion failure on type mismatch
-	const bool & Bool() const;
-	const double & Float() const;
-	const std::string & String() const;
-	const JsonVector & Vector() const;
-	const JsonMap & Struct() const;
-
-	template<typename T>
-	std::vector<T> StdVector() const
-	{
-		static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
+#pragma once
+
+#include "HeroBonus.h"
+
+class JsonNode;
+typedef std::map <std::string, JsonNode> JsonMap;
+typedef std::vector <JsonNode> JsonVector;
+
+class Bonus;
+
+class DLL_LINKAGE JsonNode
+{
+public:
+	enum JsonType
+	{
+		DATA_NULL,
+		DATA_BOOL,
+		DATA_FLOAT,
+		DATA_STRING,
+		DATA_VECTOR,
+		DATA_STRUCT
+	};
+
+private:
+	union JsonData
+	{
+		bool Bool;
+		double Float;
+		std::string* String;
+		JsonVector* Vector;
+		JsonMap* Struct;
+	};
+
+	JsonType type;
+	JsonData data;
+
+public:
+	//Create empty node
+	JsonNode(JsonType Type = DATA_NULL);
+	//Create tree from Json-formatted input
+	explicit JsonNode(const char * data, size_t datasize);
+	//Create tree from JSON file
+ 	explicit JsonNode(std::string filename);
+	//Copy c-tor
+	JsonNode(const JsonNode &copy);
+
+	~JsonNode();
+
+	void swap(JsonNode &b);
+	JsonNode& operator =(JsonNode node);
+
+	bool operator == (const JsonNode &other) const;
+	bool operator != (const JsonNode &other) const;
+
+	//removes all nodes that are identical to default entry in schema
+	void minimize(const JsonNode& schema);
+	//check schema
+	void validate(const JsonNode& schema);
+
+	//Convert node to another type. Converting to NULL will clear all data
+	void setType(JsonType Type);
+	JsonType getType() const;
+
+	bool isNull() const;
+
+	//non-const accessors, node will change type on type mismatch
+	bool & Bool();
+	double & Float();
+	std::string & String();
+	JsonVector & Vector();
+	JsonMap & Struct();
+
+	//const accessors, will cause assertion failure on type mismatch
+	const bool & Bool() const;
+	const double & Float() const;
+	const std::string & String() const;
+	const JsonVector & Vector() const;
+	const JsonMap & Struct() const;
+
+	template<typename T>
+	std::vector<T> StdVector() const
+	{
+		static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
 		std::vector<T> ret;
 		BOOST_FOREACH(const JsonNode &node, Vector())
 		{
 			ret.push_back(node.Float());
-		}
-		return ret;
-	}
-
-	//operator [], for structs only - get child node by name
-	JsonNode & operator[](std::string child);
-	const JsonNode & operator[](std::string child) const;
-
-	//error value for const operator[]
-	static const JsonNode nullNode;
-};
-
-class JsonWriter
-{
-	//prefix for each line (tabulation)
-	std::string prefix;
-	std::ostream &out;
-public:
-	template<typename Iterator>
-	void writeContainer(Iterator begin, Iterator end);
-	void writeEntry(JsonMap::const_iterator entry);
-	void writeEntry(JsonVector::const_iterator entry);
-	void writeString(const std::string &string);
-	void writeNode(const JsonNode &node);
-	JsonWriter(std::ostream &output, const JsonNode &node);
-};
-
-DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
-
-//Tiny string class that uses const char* as data for speed, members are private
-//for ease of debugging and some compatibility with std::string
-class constString
-{
-	const char *data;
-	const size_t datasize;
-
-public:
-	constString(const char * inputString, size_t stringSize):
-		data(inputString),
-		datasize(stringSize)
-	{
-	}
-
-	inline size_t size() const
-	{
-		return datasize;
-	};
-
-	inline const char& operator[] (size_t position)
-	{
-		assert (position < datasize);
-		return data[position];
-	}
-};
-
-//Internal class for string -> JsonNode conversion
-class JsonParser
-{
-	std::string errors;     // Contains description of all encountered errors
-	constString input;      // Input data
-	ui32 lineCount; // Currently parsed line, starting from 1
-	size_t lineStart;       // Position of current line start
-	size_t pos;             // Current position of parser
-
-	//Helpers
-	bool extractEscaping(std::string &str);
-	bool extractLiteral(const std::string &literal);
-	bool extractString(std::string &string);
-	bool extractWhitespace(bool verbose = true);
-	bool extractSeparator();
-	bool extractElement(JsonNode &node, char terminator);
-
-	//Methods for extracting JSON data
-	bool extractArray(JsonNode &node);
-	bool extractFalse(JsonNode &node);
-	bool extractFloat(JsonNode &node);
-	bool extractNull(JsonNode &node);
-	bool extractString(JsonNode &node);
-	bool extractStruct(JsonNode &node);
-	bool extractTrue(JsonNode &node);
-	bool extractValue(JsonNode &node);
-
-	//Add error\warning message to list
-	bool error(const std::string &message, bool warning=false);
-
-public:
-	JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
-};
-
-//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
-// - "schema" entry from root node is used for validation and will be removed
-// - any missing entries will be replaced with default value from schema (if present)
-// - if entry uses different type than defined in schema it will be removed
-// - entries nod described in schema will be kept unchanged
-class JsonValidator
-{
-	std::string errors;     // Contains description of all encountered errors
-	std::list<std::string> currentPath; // path from root node to current one
-	bool minimize;
-
-	bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
-	bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
-	bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
-	bool validateItems(JsonNode &node, const JsonNode &schema);
-	bool validateProperties(JsonNode &node, const JsonNode &schema);
-
-	bool addMessage(const std::string &message);
-public:
-	// validate node with "schema" entry
-	JsonValidator(JsonNode &root, bool minimize=false);
-	// validate with external schema
-	JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
-};
-
-
+		}
+		return ret;
+	}
+
+	//operator [], for structs only - get child node by name
+	JsonNode & operator[](std::string child);
+	const JsonNode & operator[](std::string child) const;
+
+	//error value for const operator[]
+	static const JsonNode nullNode;
+};
+
+class JsonWriter
+{
+	//prefix for each line (tabulation)
+	std::string prefix;
+	std::ostream &out;
+public:
+	template<typename Iterator>
+	void writeContainer(Iterator begin, Iterator end);
+	void writeEntry(JsonMap::const_iterator entry);
+	void writeEntry(JsonVector::const_iterator entry);
+	void writeString(const std::string &string);
+	void writeNode(const JsonNode &node);
+	JsonWriter(std::ostream &output, const JsonNode &node);
+};
+
+DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
+
+//Tiny string class that uses const char* as data for speed, members are private
+//for ease of debugging and some compatibility with std::string
+class constString
+{
+	const char *data;
+	const size_t datasize;
+
+public:
+	constString(const char * inputString, size_t stringSize):
+		data(inputString),
+		datasize(stringSize)
+	{
+	}
+
+	inline size_t size() const
+	{
+		return datasize;
+	};
+
+	inline const char& operator[] (size_t position)
+	{
+		assert (position < datasize);
+		return data[position];
+	}
+};
+
+//Internal class for string -> JsonNode conversion
+class JsonParser
+{
+	std::string errors;     // Contains description of all encountered errors
+	constString input;      // Input data
+	ui32 lineCount; // Currently parsed line, starting from 1
+	size_t lineStart;       // Position of current line start
+	size_t pos;             // Current position of parser
+
+	//Helpers
+	bool extractEscaping(std::string &str);
+	bool extractLiteral(const std::string &literal);
+	bool extractString(std::string &string);
+	bool extractWhitespace(bool verbose = true);
+	bool extractSeparator();
+	bool extractElement(JsonNode &node, char terminator);
+
+	//Methods for extracting JSON data
+	bool extractArray(JsonNode &node);
+	bool extractFalse(JsonNode &node);
+	bool extractFloat(JsonNode &node);
+	bool extractNull(JsonNode &node);
+	bool extractString(JsonNode &node);
+	bool extractStruct(JsonNode &node);
+	bool extractTrue(JsonNode &node);
+	bool extractValue(JsonNode &node);
+
+	//Add error\warning message to list
+	bool error(const std::string &message, bool warning=false);
+
+public:
+	JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
+};
+
+//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
+// - "schema" entry from root node is used for validation and will be removed
+// - any missing entries will be replaced with default value from schema (if present)
+// - if entry uses different type than defined in schema it will be removed
+// - entries nod described in schema will be kept unchanged
+class JsonValidator
+{
+	std::string errors;     // Contains description of all encountered errors
+	std::list<std::string> currentPath; // path from root node to current one
+	bool minimize;
+
+	bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
+	bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
+	bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
+	bool validateItems(JsonNode &node, const JsonNode &schema);
+	bool validateProperties(JsonNode &node, const JsonNode &schema);
+
+	bool addMessage(const std::string &message);
+public:
+	// validate node with "schema" entry
+	JsonValidator(JsonNode &root, bool minimize=false);
+	// validate with external schema
+	JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
+};
+
+//Bonus * ParseBonus (const JsonVector &ability_vec);
+
+static Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
+{
+	Bonus * b = new Bonus();
+	std::string type = ability_vec[0].String();
+	auto it = bonusNameMap.find(type);
+	if (it == bonusNameMap.end())
+	{
+		tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
+		return b;
+	}
+	b->type = it->second;
+	b->val = ability_vec[1].Float();
+	b->subtype = ability_vec[2].Float();
+	b->additionalInfo = ability_vec[3].Float();
+	b->duration = Bonus::PERMANENT;
+	b->turnsRemain = 0;
+	return b;
+}

+ 11 - 3
lib/NetPacksLib.cpp

@@ -1032,6 +1032,8 @@ DLL_LINKAGE void BattleObstaclePlaced::applyGs( CGameState *gs )
 void BattleResult::applyGs( CGameState *gs )
 {
 	//stack with SUMMONED flag but coming from garrison -> most likely resurrected, needs to be removed
+
+	//TODO: switch commander status to dead
 	BOOST_FOREACH(CStack *s, gs->curB->stacks)
 	{
 		if(s->base && s->base->armyObj && vstd::contains(s->state, EBattleStackState::SUMMONED))
@@ -1043,14 +1045,20 @@ void BattleResult::applyGs( CGameState *gs )
 	for (unsigned i = 0; i < gs->curB->stacks.size(); i++)
 		delete gs->curB->stacks[i];
 
-	//remove any "until next battle" bonuses
 	CGHeroInstance *h;
 	for (int i = 0; i < 2; ++i)
 	{
-		h = gs->curB->heroes[i];
+		h = gs->curB->heroes[i]; 
 		if (h)
 		{
-			h->getBonusList().remove_if(Bonus::OneBattle);
+			h->getBonusList().remove_if(Bonus::OneBattle); 	//remove any "until next battle" bonuses
+			if (h->commander && h->commander->alive)
+			{
+				BOOST_FOREACH (auto art, h->commander->artifactsWorn) //increment bonuses for commander artifacts
+				{
+					art.second.artifact->artType->levelUpArtifact (art.second.artifact);
+				}
+			}
 		}
 	}