Quellcode durchsuchen

Restored Warmonger's changes to artifacts system.
They will be subject of my further work, along with next part of bonus system.

Michał W. Urbańczyk vor 15 Jahren
Ursprung
Commit
bce805dacc

+ 1 - 0
CCallback.cpp

@@ -17,6 +17,7 @@
 #include <boost/thread.hpp>
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #include "hch/CSpellHandler.h"
 #include "hch/CSpellHandler.h"
+#include "hch/CArtHandler.h"
 #ifdef min
 #ifdef min
 #undef min
 #undef min
 #endif
 #endif

+ 5 - 5
client/CKingdomInterface.cpp

@@ -784,7 +784,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 
 	for (int i=0; i<artifacts.size(); i++)
 	for (int i=0; i<artifacts.size(); i++)
 	{
 	{
-		artifacts[i]->type = hero->getArtAtPos(i);
+		artifacts[i]->type = hero->getArtAtPos(i)->id;
 		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
 		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
 			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
 			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
 		else
 		else
@@ -796,7 +796,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 
 	for (int i=0; i<backpack.size(); i++)
 	for (int i=0; i<backpack.size(); i++)
 	{
 	{
-		backpack[i]->type = hero->getArtAtPos(19+i);
+		backpack[i]->type = hero->getArtAtPos(19+i)->id;
 		if (backpack[i]->type<0)
 		if (backpack[i]->type<0)
 			backpack[i]->hoverText ="";
 			backpack[i]->hoverText ="";
 		else
 		else
@@ -847,7 +847,7 @@ void CKingdomInterface::CHeroItem::scrollArts(int move)
 	backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size();
 	backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size();
 	for (int i=0; i<backpack.size(); i++)
 	for (int i=0; i<backpack.size(); i++)
 	{
 	{
-		backpack[i]->type = hero->getArtAtPos(19+(backpackPos + i)%hero->artifacts.size());
+		backpack[i]->type = hero->getArtAtPos(19+(backpackPos + i)%hero->artifacts.size())->id;
 		if (backpack[i]->type<0)
 		if (backpack[i]->type<0)
 			backpack[i]->hoverText ="";
 			backpack[i]->hoverText ="";
 		else
 		else
@@ -912,7 +912,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
 		case 0://equipped arts
 		case 0://equipped arts
 			for (int i = iter ; i<iter+9;i++)
 			for (int i = iter ; i<iter+9;i++)
 			{
 			{
-				int artID = hero->getArtAtPos(i);
+				int artID = hero->getArtAtPos(i)->id;
 				if (artID>=0)
 				if (artID>=0)
 					blitAt(graphics->artDefs->ourImages[artID].bitmap,pos.x+268+48*(i%9),pos.y+66,to);
 					blitAt(graphics->artDefs->ourImages[artID].bitmap,pos.x+268+48*(i%9),pos.y+66,to);
 			}
 			}
@@ -923,7 +923,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
 			int max = hero->artifacts.size();
 			int max = hero->artifacts.size();
 			iter = std::min(8, max);
 			iter = std::min(8, max);
 			for (size_t it = 0 ; it<iter;it++)
 			for (size_t it = 0 ; it<iter;it++)
-				blitAt(graphics->artDefs->ourImages[hero->artifacts[(it+backpackPos)%max]].bitmap,pos.x+293+48*it,pos.y+66,to);
+				blitAt(graphics->artDefs->ourImages[hero->artifacts[(it+backpackPos)%max]->id].bitmap,pos.x+293+48*it,pos.y+66,to);
 			break;
 			break;
 	}
 	}
 	show(to);
 	show(to);

+ 2 - 1
client/Client.h

@@ -117,7 +117,8 @@ public:
 	void heroVisitCastle(int obj, int heroID){};
 	void heroVisitCastle(int obj, int heroID){};
 	void stopHeroVisitCastle(int obj, int heroID){};
 	void stopHeroVisitCastle(int obj, int heroID){};
 	void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
 	void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
-	bool removeArtifact(int artid, int hid){return false;};
+	void giveNewArtifact(int hid, int position){};
+	bool removeArtifact(CArtifact* art, int hid){return false;};
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle

+ 7 - 7
client/GUIClasses.cpp

@@ -2640,7 +2640,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
 				movedArt = CGI->arth->artifacts[id];
 				movedArt = CGI->arth->artifacts[id];
 				aw->arts->commonInfo->srcAOH = aw->arts;
 				aw->arts->commonInfo->srcAOH = aw->arts;
 				aw->arts->commonInfo->srcArtifact = movedArt;
 				aw->arts->commonInfo->srcArtifact = movedArt;
-				aw->arts->commonInfo->srcSlotID = 19 + vstd::findPos(aw->hero->artifacts, movedArt->id);
+				aw->arts->commonInfo->srcSlotID = 19 + vstd::findPos(aw->hero->artifacts, const_cast<CArtifact*>(movedArt));
 
 
 				aw->arts->commonInfo->destAOH = aw->arts;
 				aw->arts->commonInfo->destAOH = aw->arts;
 				CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap);
 				CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap);
@@ -3622,10 +3622,10 @@ void CAltarWindow::SacrificeAll()
 	}
 	}
 	else
 	else
 	{
 	{
-		for(std::map<ui16,ui32>::const_iterator i = hero->artifWorn.begin(); i != hero->artifWorn.end(); i++)
+		for(std::map<ui16,CArtifact*>::const_iterator i = hero->artifWorn.begin(); i != hero->artifWorn.end(); i++)
 		{
 		{
-			if(i->second != 145) //ignore locks from assembled artifacts
-				moveFromSlotToAltar(i->first, NULL, i->second);
+			if(i->second->id != 145) //ignore locks from assembled artifacts
+				moveFromSlotToAltar(i->first, NULL, i->second->id);
 		}
 		}
 
 
 		SacrificeBackpack();
 		SacrificeBackpack();
@@ -3778,13 +3778,13 @@ void CAltarWindow::SacrificeBackpack()
 
 
 	for (int i = 0; i < hero->artifacts.size(); i++)
 	for (int i = 0; i < hero->artifacts.size(); i++)
 	{
 	{
-		if(vstd::contains(toOmmit, hero->artifacts[i]))
+		if(vstd::contains(toOmmit, hero->artifacts[i]->id))
 		{
 		{
-			toOmmit -= hero->artifacts[i];
+			toOmmit -= hero->artifacts[i]->id;
 			continue;
 			continue;
 		}
 		}
 
 
-		putOnAltar(NULL, hero->artifacts[i]);
+		putOnAltar(NULL, hero->artifacts[i]->id);
 	}
 	}
 	arts->scrollBackpack(0);
 	arts->scrollBackpack(0);
 	calcTotalExp();
 	calcTotalExp();

+ 70 - 33
hch/CArtHandler.cpp

@@ -10,6 +10,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 #include <boost/foreach.hpp>
 #include <boost/random/linear_congruential.hpp>
 #include <boost/random/linear_congruential.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMI_Lib.h"
 extern CLodHandler *bitmaph;
 extern CLodHandler *bitmaph;
 using namespace boost::assign;
 using namespace boost::assign;
@@ -47,25 +48,31 @@ bool CArtifact::isBig () const
 	return VLC->arth->isBigArtifact(id);
 	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.
  * Checks whether the artifact fits at a given slot.
  * @param artifWorn A hero's set of worn artifacts.
  * @param artifWorn A hero's set of worn artifacts.
  */
  */
-bool CArtifact::fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slotID) const
+bool CArtifact::fitsAt (const std::map<ui16, CArtifact*> &artifWorn, ui16 slotID) const
 {
 {
 	if (!vstd::contains(possibleSlots, slotID))
 	if (!vstd::contains(possibleSlots, slotID))
 		return false;
 		return false;
 
 
 	// Can't put an artifact in a locked slot.
 	// Can't put an artifact in a locked slot.
-	std::map<ui16, ui32>::const_iterator it = artifWorn.find(slotID);
-	if (it != artifWorn.end() && it->second == 145)
+	std::map<ui16, CArtifact*>::const_iterator it = artifWorn.find(slotID);
+	if (it != artifWorn.end() && it->second->id == 145)
 		return false;
 		return false;
 
 
 	// Check if a combination artifact fits.
 	// Check if a combination artifact fits.
 	// TODO: Might want a more general algorithm?
 	// TODO: Might want a more general algorithm?
 	//       Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates.
 	//       Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates.
-	if (constituents != NULL) {
-		std::map<ui16, ui32> tempArtifWorn = artifWorn;
+	if (constituents != NULL)
+	{
+		std::map<ui16, CArtifact*> tempArtifWorn = artifWorn;
 		const ui16 ringSlots[] = {6, 7};
 		const ui16 ringSlots[] = {6, 7};
 		const ui16 miscSlots[] = {9, 10, 11, 12, 18};
 		const ui16 miscSlots[] = {9, 10, 11, 12, 18};
 		int rings = 0;
 		int rings = 0;
@@ -108,7 +115,7 @@ bool CArtifact::fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slotID) cons
 	return true;
 	return true;
 }
 }
 
 
-bool CArtifact::canBeAssembledTo (const std::map<ui16, ui32> &artifWorn, ui32 artifactID) const
+bool CArtifact::canBeAssembledTo (const std::map<ui16, CArtifact*> &artifWorn, ui32 artifactID) const
 {
 {
 	if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID))
 	if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID))
 		return false;
 		return false;
@@ -119,9 +126,9 @@ bool CArtifact::canBeAssembledTo (const std::map<ui16, ui32> &artifWorn, ui32 ar
 	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
 	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
 	{
 	{
 		bool found = false;
 		bool found = false;
-		for (std::map<ui16, ui32>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) 
+		for (std::map<ui16, CArtifact*>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) 
 		{
 		{
-			if (it->second == constituentID) 
+			if (it->second->id == constituentID) 
 			{
 			{
 				found = true;
 				found = true;
 				break;
 				break;
@@ -174,6 +181,12 @@ void CArtifact::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/
 	}
 	}
 }
 }
 
 
+void CScroll::Init()
+{
+	bonuses.push_back (Bonus (Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT, 1, id, spellid, Bonus::INDEPENDENT_MAX));
+	//boost::algorithm::replace_first(description, "[spell name]", VLC->spellh->spells[spellid].name);
+}
+
 CArtHandler::CArtHandler()
 CArtHandler::CArtHandler()
 {
 {
 	VLC->arth = this;
 	VLC->arth = this;
@@ -181,11 +194,13 @@ CArtHandler::CArtHandler()
 	// War machines are the default big artifacts.
 	// War machines are the default big artifacts.
 	for (ui32 i = 3; i <= 6; i++)
 	for (ui32 i = 3; i <= 6; i++)
 		bigArtifacts.insert(i);
 		bigArtifacts.insert(i);
+	modableArtifacts = boost::assign::map_list_of(1, 1)(146,3)(147,3)(148,3)(150,3)(151,3)(152,3)(154,3)(156,2);
 }
 }
 
 
 CArtHandler::~CArtHandler()
 CArtHandler::~CArtHandler()
 {
 {
-	for (std::vector<CArtifact*>::iterator it = artifacts.begin(); it != artifacts.end(); ++it) {
+	for (std::vector<CArtifact*>::iterator it = artifacts.begin(); it != artifacts.end(); ++it)
+	{
 		delete (*it)->constituents;
 		delete (*it)->constituents;
 		delete (*it)->constituentOf;
 		delete (*it)->constituentOf;
 	}
 	}
@@ -205,9 +220,28 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 	}
 	}
 	VLC->generaltexth->artifNames.resize(ARTIFACTS_QUANTITY);
 	VLC->generaltexth->artifNames.resize(ARTIFACTS_QUANTITY);
 	VLC->generaltexth->artifDescriptions.resize(ARTIFACTS_QUANTITY);
 	VLC->generaltexth->artifDescriptions.resize(ARTIFACTS_QUANTITY);
+	std::map<ui32,ui8>::iterator itr;
 	for (int i=0; i<ARTIFACTS_QUANTITY; i++)
 	for (int i=0; i<ARTIFACTS_QUANTITY; i++)
 	{
 	{
-		CArtifact *art = new CArtifact;
+		CArtifact *art;
+		if ((itr = modableArtifacts.find(i)) != modableArtifacts.end())
+		{
+			switch (itr->second)
+			{
+				case 1:
+					art = new CScroll;
+					break;
+				case 2:
+					art = new CCustomizableArt;
+					break;
+				case 3:
+					art = new CCommanderArt;
+					break;
+			};
+		}
+		else
+			art = new CArtifact;
+
 		CArtifact &nart = *art;
 		CArtifact &nart = *art;
 		nart.id=i;
 		nart.id=i;
 		loadToIt(VLC->generaltexth->artifNames[i],buf,it,4);
 		loadToIt(VLC->generaltexth->artifNames[i],buf,it,4);
@@ -718,36 +752,39 @@ void CArtHandler::clear()
  * @param artifWorn A hero's set of worn artifacts.
  * @param artifWorn A hero's set of worn artifacts.
  * @param bonuses Optional list of bonuses to update.
  * @param bonuses Optional list of bonuses to update.
  */
  */
-void CArtHandler::equipArtifact(std::map<ui16, ui32> &artifWorn, ui16 slotID, ui32 artifactID)
+void CArtHandler::equipArtifact(std::map<ui16, CArtifact*> &artifWorn, ui16 slotID, const CArtifact* newArtifact)
 {
 {
 	unequipArtifact(artifWorn, slotID);
 	unequipArtifact(artifWorn, slotID);
 
 
-	const CArtifact &artifact = *artifacts[artifactID];
-
-	// Add artifact.
-	artifWorn[slotID] = artifactID;
-
-	// Add locks, in reverse order of being removed.
-	if (artifact.constituents != NULL) 
+	if (newArtifact) //false when artifact is NULL -> slot set to empty
 	{
 	{
-		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
+		const CArtifact &artifact = *newArtifact;
 
 
-		BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
+		// Add artifact.
+		artifWorn[slotID] = const_cast<CArtifact*>(newArtifact);
+
+		// Add locks, in reverse order of being removed.
+		if (artifact.constituents != NULL) 
 		{
 		{
-			const CArtifact &constituent = *artifacts[constituentID];
+			bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
 
 
-			if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) 
+			BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
 			{
 			{
-				destConsumed = true;
-			} 
-			else 
-			{
-				BOOST_FOREACH(ui16 slot, constituent.possibleSlots) 
+				const CArtifact &constituent = *artifacts[constituentID];
+
+				if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) 
+				{
+					destConsumed = true;
+				} 
+				else 
 				{
 				{
-					if (!vstd::contains(artifWorn, slot)) 
+					BOOST_FOREACH(ui16 slot, constituent.possibleSlots) 
 					{
 					{
-						artifWorn[slot] = 145;
-						break;
+						if (!vstd::contains(artifWorn, slot)) 
+						{
+							artifWorn[slot] = VLC->arth->artifacts[145]; //lock
+							break;
+						}
 					}
 					}
 				}
 				}
 			}
 			}
@@ -761,12 +798,12 @@ void CArtHandler::equipArtifact(std::map<ui16, ui32> &artifWorn, ui16 slotID, ui
  * @param artifWorn A hero's set of worn artifacts.
  * @param artifWorn A hero's set of worn artifacts.
  * @param bonuses Optional list of bonuses to update.
  * @param bonuses Optional list of bonuses to update.
  */
  */
-void CArtHandler::unequipArtifact(std::map<ui16, ui32> &artifWorn, ui16 slotID)
+void CArtHandler::unequipArtifact(std::map<ui16, CArtifact*> &artifWorn, ui16 slotID)
 {
 {
 	if (!vstd::contains(artifWorn, slotID))
 	if (!vstd::contains(artifWorn, slotID))
 		return;
 		return;
 
 
-	const CArtifact &artifact = *artifacts[artifWorn[slotID]];
+	const CArtifact &artifact = *artifWorn[slotID];
 
 
 	// Remove artifact, if it's not already removed.
 	// Remove artifact, if it's not already removed.
 	artifWorn.erase(slotID);
 	artifWorn.erase(slotID);
@@ -788,7 +825,7 @@ void CArtHandler::unequipArtifact(std::map<ui16, ui32> &artifWorn, ui16 slotID)
 			{
 			{
 				BOOST_REVERSE_FOREACH(ui16 slot, constituent.possibleSlots) 
 				BOOST_REVERSE_FOREACH(ui16 slot, constituent.possibleSlots) 
 				{
 				{
-					if (vstd::contains(artifWorn, slot) && artifWorn[slot] == 145) 
+					if (vstd::contains(artifWorn, slot) && artifWorn[slot]->id == 145) 
 					{
 					{
 						artifWorn.erase(slot);
 						artifWorn.erase(slot);
 						break;
 						break;

+ 33 - 15
hch/CArtHandler.h

@@ -17,19 +17,24 @@
  *
  *
  */
  */
 class CDefHandler;
 class CDefHandler;
+class CArtifact;
 
 
 class DLL_EXPORT CArtifact : public CBonusSystemNode //container for artifacts
 class DLL_EXPORT CArtifact : public CBonusSystemNode //container for artifacts
 {
 {
+protected:
 	std::string name, description; //set if custom
 	std::string name, description; //set if custom
 public:
 public:
 	enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes
 	enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes
 	const std::string &Name() const; //getter
 	const std::string &Name() const; //getter
 	const std::string &Description() const; //getter
 	const std::string &Description() const; //getter
 	bool isBig () const;
 	bool isBig () const;
-	bool fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slot) const;
-	bool canBeAssembledTo (const std::map<ui16, ui32> &artifWorn, ui32 artifactID) const;
+	bool isModable () const;
+	bool fitsAt (const std::map<ui16, CArtifact*> &artifWorn, ui16 slot) const;
+	bool canBeAssembledTo (const std::map<ui16, CArtifact*> &artifWorn, ui32 artifactID) const;
 	void addBonusesTo (BonusList *otherBonuses) const;
 	void addBonusesTo (BonusList *otherBonuses) const;
 	void removeBonusesFrom (BonusList *otherBonuses) const;
 	void removeBonusesFrom (BonusList *otherBonuses) const;
+	virtual void SetProperty (int mod){};
+	virtual void Init(){};
 	int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other
 	int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other
 
 
 	ui32 price;
 	ui32 price;
@@ -52,46 +57,58 @@ public:
 	void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
 	void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
 };
 };
 
 
-class DLL_EXPORT IModableArt //artifact which can have different properties, such as scroll or banner
-{
+class DLL_EXPORT IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner
+{ //used only for dynamic cast :P
 public:
 public:
-	virtual void Init() = 0;
+	si32 ID; //used for smart serialization
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CArtifact&>(*this);
+		h & ID;
+	}
 };
 };
 
 
-class DLL_EXPORT CScroll : public CArtifact, public IModableArt // Spell Scroll
+class DLL_EXPORT CScroll : public IModableArt // Spell Scroll
 {
 {
 public:
 public:
+	CScroll(){spellid=0;};
+	CScroll(spelltype sid){spellid = sid;};
 	spelltype spellid;
 	spelltype spellid;
-	void Init(){};
+	void Init();
+	void SetProperty (int mod){spellid = mod;};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & spellid;
 		h & spellid;
 	}
 	}
 };
 };
 
 
-class DLL_EXPORT CCustomizableArt : public CArtifact, public IModableArt // Warlord's Banner with multiple options
+class DLL_EXPORT CCustomizableArt : public IModableArt // Warlord's Banner with multiple options
 {
 {
 public:
 public:
 	ui8 mode;
 	ui8 mode;
+	CCustomizableArt(){mode=0;};
 	void Init(){};
 	void Init(){};
-	void SelectMode (int mod){};
+	void SetProperty (int mod){};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & mode;
 		h & mode;
 	}
 	}
 };
 };
 
 
-class DLL_EXPORT CCommanderArt : public CArtifact, public IModableArt // Growing with time
+class DLL_EXPORT CCommanderArt : public IModableArt // Growing with time
 {
 {
 public:
 public:
 	ui32 level;
 	ui32 level;
+	CCommanderArt(){level = 0;};
 	void Init(){};
 	void Init(){};
+	void SetProperty (int mod){level = mod;};
 	void Upgrade(){level++;};
 	void Upgrade(){level++;};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & level;
 		h & level;
 	}
 	}
 };
 };
@@ -104,6 +121,7 @@ public:
 	std::vector<CArtifact *> artifacts;
 	std::vector<CArtifact *> artifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
 	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
 
 
 	void loadArtifacts(bool onlyTxt);
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
 	void sortArts();
@@ -116,8 +134,8 @@ public:
 	void getAllowed(std::vector<CArtifact*> &out, int flags);
 	void getAllowed(std::vector<CArtifact*> &out, int flags);
 	void erasePickedArt (si32 id);
 	void erasePickedArt (si32 id);
 	bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();}
 	bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();}
-	void equipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID, ui32 artifactID);
-	void unequipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID);
+	void equipArtifact (std::map<ui16, CArtifact*> &artifWorn, ui16 slotID, const CArtifact* art);
+	void unequipArtifact (std::map<ui16, CArtifact*> &artifWorn, ui16 slotID);
 	void initAllowedArtifactsList(const std::vector<ui8> &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed
 	void initAllowedArtifactsList(const std::vector<ui8> &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed
 	static int convertMachineID(int id, bool creToArt);
 	static int convertMachineID(int id, bool creToArt);
 	CArtHandler();
 	CArtHandler();

+ 1 - 1
hch/CCampaignHandler.cpp

@@ -522,7 +522,7 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
 			{
 			{
 				BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
 				BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
 				{
 				{
-					cgh->artifacts -= g;
+					cgh->artifacts -= VLC->arth->artifacts[g];
 				}
 				}
 			}
 			}
 		}
 		}

+ 60 - 42
hch/CObjectHandler.cpp

@@ -729,27 +729,23 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
 	return int(base + base*modifier) + bonus;
 	return int(base + base*modifier) + bonus;
 }
 }
 
 
-ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
+CArtifact* CGHeroInstance::getArtAtPos(ui16 pos) const
 {
 {
 	if(pos<19)
 	if(pos<19)
 		if(vstd::contains(artifWorn,pos))
 		if(vstd::contains(artifWorn,pos))
 			return artifWorn.find(pos)->second;
 			return artifWorn.find(pos)->second;
 		else
 		else
-			return -1;
+			return NULL;
 	else
 	else
 		if(pos-19 < artifacts.size())
 		if(pos-19 < artifacts.size())
 			return artifacts[pos-19];
 			return artifacts[pos-19];
 		else 
 		else 
-			return -1;
+			return NULL;
 }
 }
 
 
 const CArtifact * CGHeroInstance::getArt(int pos) const
 const CArtifact * CGHeroInstance::getArt(int pos) const
 {
 {
-	int id = getArtAtPos(pos);
-	if(id>=0)
-		return VLC->arth->artifacts[id];
-	else
-		return NULL;
+	return getArtAtPos(pos);
 }
 }
 
 
 // int CGHeroInstance::getSpellSecLevel(int spell) const
 // int CGHeroInstance::getSpellSecLevel(int spell) const
@@ -814,9 +810,9 @@ void CGHeroInstance::initHero()
 
 
 	if(!vstd::contains(artifWorn, 16) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set
 	if(!vstd::contains(artifWorn, 16) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set
 	{
 	{
-		VLC->arth->equipArtifact(artifWorn, 17, 0); //give spellbook
+		VLC->arth->equipArtifact(artifWorn, 17, VLC->arth->artifacts[0]); //give spellbook
 	}
 	}
-	VLC->arth->equipArtifact(artifWorn, 16, 3); //everyone has a catapult
+	VLC->arth->equipArtifact(artifWorn, 16, VLC->arth->artifacts[3]); //everyone has a catapult
 
 
 	if(portrait < 0 || portrait == 255)
 	if(portrait < 0 || portrait == 255)
 		portrait = subID;
 		portrait = subID;
@@ -886,13 +882,13 @@ void CGHeroInstance::initArmy(CCreatureSet *dst /*= NULL*/)
 			switch (creID)
 			switch (creID)
 			{
 			{
 			case 145: //catapult
 			case 145: //catapult
-				VLC->arth->equipArtifact(artifWorn, 16, 3);
+				VLC->arth->equipArtifact(artifWorn, 16, VLC->arth->artifacts[3]);
 				break;
 				break;
 			default:
 			default:
 				VLC->arth->equipArtifact(
 				VLC->arth->equipArtifact(
 					artifWorn,
 					artifWorn,
 					9+CArtHandler::convertMachineID(creID,true),
 					9+CArtHandler::convertMachineID(creID,true),
-					  CArtHandler::convertMachineID(creID,true));
+					  VLC->arth->artifacts[CArtHandler::convertMachineID(creID,true)]);
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -1421,8 +1417,8 @@ si32 CGHeroInstance::manaRegain() const
 
 
 si32 CGHeroInstance::getArtPos(int aid) const
 si32 CGHeroInstance::getArtPos(int aid) const
 {
 {
-	for(std::map<ui16,ui32>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		if(i->second == aid)
+	for(std::map<ui16,CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+		if(i->second->id == aid)
 			return i->first;
 			return i->first;
 	return -1;
 	return -1;
 }
 }
@@ -1431,33 +1427,34 @@ si32 CGHeroInstance::getArtPos(int aid) const
  * Places an artifact in hero's backpack. If it's a big artifact equips it
  * Places an artifact in hero's backpack. If it's a big artifact equips it
  * or discards it if it cannot be equipped.
  * or discards it if it cannot be equipped.
  */
  */
-void CGHeroInstance::giveArtifact (ui32 aid)
+void CGHeroInstance::giveArtifact (ui32 aid) //use only for fixed artifacts
 {
 {
-	const CArtifact &artifact = *VLC->arth->artifacts[aid];
+	CArtifact * const artifact = VLC->arth->artifacts[aid]; //pointer to constant object
 
 
-	if (artifact.isBig()) 
+	if (artifact->isBig()) 
 	{
 	{
-		for (std::vector<ui16>::const_iterator it = artifact.possibleSlots.begin(); it != artifact.possibleSlots.end(); ++it) 
+		for (std::vector<ui16>::const_iterator it = artifact->possibleSlots.begin(); it != artifact->possibleSlots.end(); ++it) 
 		{
 		{
 			if (!vstd::contains(artifWorn, *it)) 
 			if (!vstd::contains(artifWorn, *it)) 
 			{
 			{
-				VLC->arth->equipArtifact(artifWorn, *it, aid);
+				VLC->arth->equipArtifact(artifWorn, *it, artifact);
 				break;
 				break;
 			}
 			}
 		}
 		}
 	} 
 	} 
 	else 
 	else 
 	{
 	{
-		artifacts.push_back(aid);
+		artifacts.push_back(artifact);
 	}
 	}
 }
 }
 
 
 bool CGHeroInstance::hasArt( ui32 aid ) const
 bool CGHeroInstance::hasArt( ui32 aid ) const
 {
 {
-	if(vstd::contains(artifacts, aid))
-		return true;
-	for(std::map<ui16,ui32>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		if(i->second == aid)
+	for(std::vector<CArtifact*>::const_iterator i = artifacts.begin(); i != artifacts.end(); i++)
+		if((*i)->id == aid)
+			return true;
+	for(std::map<ui16,CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+		if(i->second->id == aid)
 			return true;
 			return true;
 
 
 	return false;
 	return false;
@@ -1500,8 +1497,8 @@ void CGHeroInstance::getParents(TCNodes &out, const CBonusSystemNode *root /*= N
 			out.insert(visitedTown);
 			out.insert(visitedTown);
 	}
 	}
 
 
-	for (std::map<ui16,ui32>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		out.insert(VLC->arth->artifacts[i->second]);
+	for (std::map<ui16,CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+		out.insert(i->second);
 
 
 	out.insert(&speciality);
 	out.insert(&speciality);
 }
 }
@@ -3594,24 +3591,36 @@ void CGArtifact::initObj()
 	blockVisit = true;
 	blockVisit = true;
 	if(ID == 5)
 	if(ID == 5)
 		hoverName = VLC->arth->artifacts[subID]->Name();
 		hoverName = VLC->arth->artifacts[subID]->Name();
+	if(ID == 93)
+		subID = 1;
 }
 }
 
 
 void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 {
 {
 	if(!stacksCount())
 	if(!stacksCount())
 	{
 	{
-		if(ID == 5)
+		InfoWindow iw;
+		iw.soundID = soundBase::treasure;
+		iw.player = h->tempOwner;
+		switch(ID)
 		{
 		{
-			InfoWindow iw;
-			iw.soundID = soundBase::treasure;
-			iw.player = h->tempOwner;
-			iw.components.push_back(Component(4,subID,0,0));
-			if(message.length())
-				iw.text <<  message;
-			else
-				iw.text << std::pair<ui8,ui32>(12,subID);
-			cb->showInfoDialog(&iw);
+			case 5:
+			{
+				iw.components.push_back(Component(4,subID,0,0));
+				if(message.length())
+					iw.text <<  message;
+				else
+					iw.text << std::pair<ui8,ui32>(12,subID);
+			}
+			break;
+			case 93:
+				iw.components.push_back (Component(Component::SPELL, spell,0,0));
+				iw.text.addTxt (MetaString::ADVOB_TXT,135);
+				iw.text.addReplacement(MetaString::SPELL_NAME, spell);
+			break;
+
 		}
 		}
+		cb->showInfoDialog(&iw);
 		pick(h);
 		pick(h);
 	}
 	}
 	else
 	else
@@ -3632,13 +3641,22 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 
 
 void CGArtifact::pick(const CGHeroInstance * h) const
 void CGArtifact::pick(const CGHeroInstance * h) const
 {
 {
-	if(ID == 5) //Artifact
-	{
-		cb->giveHeroArtifact(subID,h->id,-2);
+	if (VLC->arth->artifacts[subID]->isModable())
+	{//TODO: create new instance, initialize it
+		if (ID == 93) //scroll
+		{
+			NewArtifact na;
+			na.value = spell;
+			na.artid = subID;
+			cb->sendAndApply(&na);
+			cb->giveNewArtifact(h->id, -2);
+		}
+		else
+			cb->giveNewArtifact(h->id, -2);; //nothing / zero / empty by default
 	}
 	}
-	else if(ID == 93) // Spell scroll 
+	else
 	{
 	{
-		//TODO: support for the spell scroll
+		cb->giveHeroArtifact(subID,h->id,-2);
 	}
 	}
 	cb->removeObject(id);
 	cb->removeObject(id);
 }
 }
@@ -4373,7 +4391,7 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 			case CQuest::MISSION_ART:
 			case CQuest::MISSION_ART:
 				for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
 				for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
 				{
 				{
-					cb->removeArtifact(*it, h->id);
+					cb->removeArtifact(VLC->arth->artifacts[*it], h->id);
 				}
 				}
 				break;
 				break;
 			case CQuest::MISSION_ARMY:
 			case CQuest::MISSION_ARMY:

+ 4 - 3
hch/CObjectHandler.h

@@ -47,6 +47,7 @@ struct InfoWindow;
 struct Component;
 struct Component;
 struct BankConfig;
 struct BankConfig;
 struct UpdateHeroSpeciality;
 struct UpdateHeroSpeciality;
+struct NewArtifact;
 class CGBoat;
 class CGBoat;
 
 
 class DLL_EXPORT CQuest
 class DLL_EXPORT CQuest
@@ -266,8 +267,8 @@ public:
 	ui8 inTownGarrison; // if hero is in town garrison 
 	ui8 inTownGarrison; // if hero is in town garrison 
 	const CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
 	const CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
 	const CGBoat *boat; //set to CGBoat when sailing
 	const CGBoat *boat; //set to CGBoat when sailing
-	std::vector<ui32> artifacts; //hero's artifacts from bag
-	std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+	std::vector<CArtifact*> artifacts; //hero's artifacts from bag
+	std::map<ui16, CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 	std::set<ui32> spells; //known spells (spell IDs)
 	std::set<ui32> spells; //known spells (spell IDs)
 
 
 	struct DLL_EXPORT Patrol
 	struct DLL_EXPORT Patrol
@@ -337,7 +338,7 @@ public:
 
 
 	int maxMovePoints(bool onLand) const;
 	int maxMovePoints(bool onLand) const;
 
 
-	ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact
+	CArtifact* getArtAtPos(ui16 pos) const; //NULL - no artifact
 	const CArtifact * getArt(int pos) const;
 	const CArtifact * getArt(int pos) const;
 	si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
 	si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
 	bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn)
 	bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn)

+ 1 - 1
lib/CGameState.cpp

@@ -1949,7 +1949,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 				CGHeroInstance *hero = k->second.heroes[0];
 				CGHeroInstance *hero = k->second.heroes[0];
 				std::vector<ui16>::iterator slot = vstd::findFirstNot (hero->artifWorn, toGive->possibleSlots);
 				std::vector<ui16>::iterator slot = vstd::findFirstNot (hero->artifWorn, toGive->possibleSlots);
 				if(slot != toGive->possibleSlots.end())
 				if(slot != toGive->possibleSlots.end())
-					VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id);
+					VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive);
 				else
 				else
  					hero->giveArtifact(toGive->id);
  					hero->giveArtifact(toGive->id);
 			}
 			}

+ 3 - 1
lib/CGameState.h

@@ -61,6 +61,7 @@ struct TerrainTile;
 class CHeroClass;
 class CHeroClass;
 class CCampaign;
 class CCampaign;
 class CCampaignState;
 class CCampaignState;
+class IModableArt;
 
 
 namespace boost
 namespace boost
 {
 {
@@ -142,7 +143,8 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
 		h & color & human & currentSelection & team & resources & status;
 		h & color & human & currentSelection & team & resources & status;
-		h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle;
+		h & heroes & towns & availableHeroes & dwellings & bonuses;
+		h & status & daysWithoutCastle;
 		h & enteredLosingCheatCode & enteredWinningCheatCode;
 		h & enteredLosingCheatCode & enteredWinningCheatCode;
 		h & static_cast<CBonusSystemNode&>(*this);
 		h & static_cast<CBonusSystemNode&>(*this);
 	}
 	}

+ 2 - 1
lib/Connection.cpp

@@ -402,8 +402,9 @@ CSerializer::CSerializer()
 void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
 void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
 {
 {
 	registerVectoredType(&gs->map->objects, &CGObjectInstance::id);
 	registerVectoredType(&gs->map->objects, &CGObjectInstance::id);
+	registerVectoredType(&lib->heroh->heroes, &CHero::ID);
 	registerVectoredType(&lib->creh->creatures, &CCreature::idNumber);
 	registerVectoredType(&lib->creh->creatures, &CCreature::idNumber);
 	registerVectoredType(&lib->arth->artifacts, &CArtifact::id);
 	registerVectoredType(&lib->arth->artifacts, &CArtifact::id);
-	registerVectoredType(&lib->heroh->heroes, &CHero::ID);
+	registerVectoredType(&gs->map->artInstances, &IModableArt::ID);
 	smartVectorMembersSerialization = true;
 	smartVectorMembersSerialization = true;
 }
 }

+ 2 - 1
lib/IGameCallback.h

@@ -93,7 +93,8 @@ public:
 	virtual void heroVisitCastle(int obj, int heroID)=0;
 	virtual void heroVisitCastle(int obj, int heroID)=0;
 	virtual void stopHeroVisitCastle(int obj, int heroID)=0;
 	virtual void stopHeroVisitCastle(int obj, int heroID)=0;
 	virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
 	virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
-	virtual bool removeArtifact(int artid, int hid) = 0;
+	virtual void giveNewArtifact(int hid, int position)=0;
+	virtual bool removeArtifact(CArtifact* art, int hid) = 0;
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
 	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle

+ 19 - 4
lib/NetPacks.h

@@ -602,18 +602,18 @@ struct SetHeroArtifacts : public CPackForClient //509
 	SetHeroArtifacts(){type = 509;};
 	SetHeroArtifacts(){type = 509;};
 	void applyCl(CClient *cl);
 	void applyCl(CClient *cl);
 	DLL_EXPORT void applyGs(CGameState *gs);
 	DLL_EXPORT void applyGs(CGameState *gs);
-	DLL_EXPORT void setArtAtPos(ui16 pos, int art);
+	DLL_EXPORT void setArtAtPos(ui16 pos, const CArtifact* art);
 
 
 	si32 hid;
 	si32 hid;
-	std::vector<ui32> artifacts; //hero's artifacts from bag
-	std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+	std::vector<CArtifact*> artifacts; //hero's artifacts from bag
+	std::map<ui16,CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
 		h & hid & artifacts & artifWorn;
 		h & hid & artifacts & artifWorn;
 	}
 	}
 
 
-	std::vector<ui32> equiped, unequiped; //used locally
+	std::vector<CArtifact*> equiped, unequiped; //used locally
 	BonusList gained, lost; //used locally as hlp when applying
 	BonusList gained, lost; //used locally as hlp when applying
 };   
 };   
 
 
@@ -697,6 +697,21 @@ struct SetAvailableArtifacts  : public CPackForClient //519
 	}
 	}
 };
 };
 
 
+struct NewArtifact : public CPackForClient
+{
+	NewArtifact(){type = 520;};
+	//void applyCl(CClient *cl);
+	DLL_EXPORT void applyGs(CGameState *gs);
+
+	si32 artid;
+	si32 value; //initializing parameter
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & artid & value;
+	}
+};
+
 struct NewTurn : public CPackForClient //101
 struct NewTurn : public CPackForClient //101
 {
 {
 	enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE};
 	enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE};

+ 33 - 6
lib/NetPacksLib.cpp

@@ -451,20 +451,22 @@ DLL_EXPORT void SetHeroesInTown::applyGs( CGameState *gs )
 DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
 DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
 {
 {
 	CGHeroInstance *h = gs->getHero(hid);
 	CGHeroInstance *h = gs->getHero(hid);
-	for(std::map<ui16,ui32>::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++)
+	for(std::map<ui16,CArtifact*>::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++)
 		if(!vstd::contains(artifWorn,i->first)  ||  artifWorn[i->first] != i->second)
 		if(!vstd::contains(artifWorn,i->first)  ||  artifWorn[i->first] != i->second)
 			unequiped.push_back(i->second);
 			unequiped.push_back(i->second);
 
 
-	for(std::map<ui16,ui32>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+	for(std::map<ui16,CArtifact*>::iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
 		if(!vstd::contains(h->artifWorn,i->first)  ||  h->artifWorn[i->first] != i->second)
 		if(!vstd::contains(h->artifWorn,i->first)  ||  h->artifWorn[i->first] != i->second)
+		{
 			equiped.push_back(i->second);
 			equiped.push_back(i->second);
+		}
 
 
 	//update hero data
 	//update hero data
 	h->artifacts = artifacts;
 	h->artifacts = artifacts;
 	h->artifWorn = artifWorn;
 	h->artifWorn = artifWorn;
 }
 }
 
 
-DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art)
+DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, const CArtifact* art)
 {
 {
 	if(art < 0)
 	if(art < 0)
 	{
 	{
@@ -477,14 +479,14 @@ DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art)
 	{
 	{
 		if (pos < 19) 
 		if (pos < 19) 
 		{
 		{
-			VLC->arth->equipArtifact(artifWorn, pos, (ui32) art);
+			VLC->arth->equipArtifact(artifWorn, pos, art);
 		} 
 		} 
 		else // Goes into the backpack.
 		else // Goes into the backpack.
 		{ 
 		{ 
 			if(pos - 19 < artifacts.size())
 			if(pos - 19 < artifacts.size())
-				artifacts.insert(artifacts.begin() + (pos - 19), art);
+				artifacts.insert(artifacts.begin() + (pos - 19), const_cast<CArtifact*>(art));
 			else
 			else
-				artifacts.push_back(art);
+				artifacts.push_back(const_cast<CArtifact*>(art));
 		}
 		}
 	}
 	}
 }
 }
@@ -584,6 +586,31 @@ DLL_EXPORT void NewObject::applyGs( CGameState *gs )
 	o->initObj();
 	o->initObj();
 	assert(o->defInfo);
 	assert(o->defInfo);
 }
 }
+DLL_EXPORT void NewArtifact::applyGs( CGameState *gs )
+{
+	IModableArt * art;
+
+	std::map<ui32,ui8>::iterator itr = VLC->arth->modableArtifacts.find(artid);
+	switch (itr->second)
+	{
+			case 1:
+				art = new CScroll;
+				break;
+			case 2:
+				art = new CCustomizableArt;
+				break;
+			case 3:
+				art = new CCommanderArt;
+				break;
+			default:
+				tlog1<<"unhandled customizable artifact!\n";
+	};
+	*art = *static_cast<IModableArt*>(VLC->arth->artifacts[artid]); //copy properties
+	art->ID = gs->map->artInstances.size();
+	art->SetProperty (value); //init scroll, banner, commander art
+	art->Init(); //set bonuses for new instance
+	gs->map->artInstances.push_back(art);
+}
 
 
 DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )
 DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )
 {
 {

+ 1 - 0
lib/RegisterTypes.cpp

@@ -137,6 +137,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<AdvmapSpellCast>();
 	s.template registerType<AdvmapSpellCast>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<NewObject>();
 	s.template registerType<NewObject>();
+	s.template registerType<NewArtifact>();
 	s.template registerType<SetAvailableArtifacts>();
 	s.template registerType<SetAvailableArtifacts>();
 
 
 	s.template registerType<SaveGame>();
 	s.template registerType<SaveGame>();

+ 8 - 8
lib/map.cpp

@@ -858,27 +858,27 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int
 		{
 		{
 			int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			if(id != artmask)
 			if(id != artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, pom, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, pom, VLC->arth->artifacts[id]);
 		}
 		}
 		//misc5 art //17
 		//misc5 art //17
 		if(version>=SoD)
 		if(version>=SoD)
 		{
 		{
 			int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			if(id!=artmask)
 			if(id!=artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, 16, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, 16, VLC->arth->artifacts[id]);
 			else
 			else
-				VLC->arth->equipArtifact(nhi->artifWorn, 16, 3); //catapult by default
+				VLC->arth->equipArtifact(nhi->artifWorn, 16, VLC->arth->artifacts[3]); //catapult by default
 		}
 		}
 		//spellbook
 		//spellbook
 		int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 		int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 		if(id!=artmask)
 		if(id!=artmask)
-			VLC->arth->equipArtifact(nhi->artifWorn, 17, id);
+			VLC->arth->equipArtifact(nhi->artifWorn, 17, VLC->arth->artifacts[id]);
 		//19 //???what is that? gap in file or what? - it's probably fifth slot..
 		//19 //???what is that? gap in file or what? - it's probably fifth slot..
 		if(version>RoE)
 		if(version>RoE)
 		{
 		{
 			id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			if(id!=artmask)
 			if(id!=artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, 18, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, 18, VLC->arth->artifacts[id]);
 		}
 		}
 		else
 		else
 			i+=1;
 			i+=1;
@@ -1102,7 +1102,7 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
 					{
 					{
 						int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						if(id!=artmask)
 						if(id!=artmask)
-							VLC->arth->equipArtifact(cgh->artifWorn, pom, id);
+							VLC->arth->equipArtifact(cgh->artifWorn, pom, VLC->arth->artifacts[id]);
 					}
 					}
 					//misc5 art //17
 					//misc5 art //17
 					if(version>=SoD)
 					if(version>=SoD)
@@ -1115,13 +1115,13 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
 					//spellbook
 					//spellbook
 					int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 					int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 					if(id!=artmask)
 					if(id!=artmask)
-						VLC->arth->equipArtifact(cgh->artifWorn, 17, id);
+						VLC->arth->equipArtifact(cgh->artifWorn, 17, VLC->arth->artifacts[id]);
 					//19 //???what is that? gap in file or what? - it's probably fifth slot..
 					//19 //???what is that? gap in file or what? - it's probably fifth slot..
 					if(version>RoE)
 					if(version>RoE)
 					{
 					{
 						id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						if(id!=artmask)
 						if(id!=artmask)
-							VLC->arth->equipArtifact(cgh->artifWorn, 18, id);
+							VLC->arth->equipArtifact(cgh->artifWorn, 18, VLC->arth->artifacts[id]);
 					}
 					}
 					else
 					else
 						i+=1;
 						i+=1;

+ 3 - 2
lib/map.h

@@ -30,7 +30,7 @@ class CGHeroInstance;
 class CGCreature;
 class CGCreature;
 class CQuest;
 class CQuest;
 class CGTownInstance;
 class CGTownInstance;
-
+class IModableArt;
 
 
 
 
 struct DLL_EXPORT TerrainTile
 struct DLL_EXPORT TerrainTile
@@ -279,6 +279,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	std::vector<CGObjectInstance*> objects;
 	std::vector<CGObjectInstance*> objects;
 	std::vector<CGHeroInstance*> heroes;
 	std::vector<CGHeroInstance*> heroes;
 	std::vector<CGTownInstance*> towns;
 	std::vector<CGTownInstance*> towns;
+	std::vector<IModableArt *> artInstances; //stores single scrolls
 	std::map<ui16, CGCreature*> monsters;
 	std::map<ui16, CGCreature*> monsters;
 	std::map<ui16, CGHeroInstance*> heroesToBeat;
 	std::map<ui16, CGHeroInstance*> heroesToBeat;
 
 
@@ -313,7 +314,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	{
 	{
 		h & static_cast<CMapHeader&>(*this);
 		h & static_cast<CMapHeader&>(*this);
 		h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos;
 		h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos;
-		h & monsters & heroesToBeat; //hoprfully serialization is now automagical?
+		h & monsters & heroesToBeat & artInstances; //hopefully serialization is now automagical?
 
 
 		//TODO: viccondetails
 		//TODO: viccondetails
 		if(h.saving)
 		if(h.saving)

+ 126 - 57
server/CGameHandler.cpp

@@ -2225,7 +2225,7 @@ void CGameHandler::stopHeroVisitCastle(int obj, int heroID)
 void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 - first free slot in backpack
 void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 - first free slot in backpack
 {
 {
 	const CGHeroInstance* h = getHero(hid);
 	const CGHeroInstance* h = getHero(hid);
-	const CArtifact &art = *VLC->arth->artifacts[artid];
+	CArtifact * const art = VLC->arth->artifacts[artid];
 
 
 	SetHeroArtifacts sha;
 	SetHeroArtifacts sha;
 	sha.hid = hid;
 	sha.hid = hid;
@@ -2237,38 +2237,84 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
 		if(position == -2)
 		if(position == -2)
 		{
 		{
 			int i;
 			int i;
-			for(i=0; i<art.possibleSlots.size(); i++) //try to put artifact into first available slot
+			for(i=0; i<art->possibleSlots.size(); i++) //try to put artifact into first available slot
 			{
 			{
-				if(art.fitsAt(sha.artifWorn, art.possibleSlots[i]))
+				if(art->fitsAt(sha.artifWorn, art->possibleSlots[i]))
 				{
 				{
 					//we've found a free suitable slot.
 					//we've found a free suitable slot.
-					VLC->arth->equipArtifact(sha.artifWorn, art.possibleSlots[i], artid);
+					VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], VLC->arth->artifacts[artid]);
 					break;
 					break;
 				}
 				}
 			}
 			}
-			if(i == art.possibleSlots.size() && !art.isBig()) //if haven't find proper slot, use backpack or discard big artifact
-				sha.artifacts.push_back(artid);
+			if(i == art->possibleSlots.size() && !art->isBig()) //if haven't find proper slot, use backpack or discard big artifact
+				sha.artifacts.push_back(art);
 		}
 		}
-		else if (!art.isBig()) //should be -1 => put artifact into backpack
+		else if (!art->isBig()) //should be -1 => put artifact into backpack
 		{
 		{
-			sha.artifacts.push_back(artid);
+			sha.artifacts.push_back(art);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		if(art.fitsAt(sha.artifWorn, ui16(position)))
+		if(art->fitsAt(sha.artifWorn, ui16(position)))
 		{
 		{
-			VLC->arth->equipArtifact(sha.artifWorn, position, artid);
+			VLC->arth->equipArtifact(sha.artifWorn, position, art);
 		}
 		}
-		else if (!art.isBig())
+		else if (!art->isBig())
 		{
 		{
-			sha.artifacts.push_back(artid);
+			sha.artifacts.push_back(art);
 		}
 		}
 	}
 	}
 
 
 	sendAndApply(&sha);
 	sendAndApply(&sha);
 }
 }
-bool CGameHandler::removeArtifact(int artid, int hid)
+void CGameHandler::giveNewArtifact(int hid, int position)
+{
+	const CGHeroInstance* h = getHero(hid);
+	CArtifact * art = gs->map->artInstances.back(); //we use it only to immediatelly equip new artifact
+
+	SetHeroArtifacts sha;
+	sha.hid = hid;
+	sha.artifacts = h->artifacts;
+	sha.artifWorn = h->artifWorn;
+
+	if(position<0)
+	{
+		if(position == -2)
+		{
+			int i;
+			for(i=0; i<art->possibleSlots.size(); i++) //try to put artifact into first available slot
+			{
+				if( !vstd::contains(sha.artifWorn, art->possibleSlots[i]) )
+				{
+					//we've found a free suitable slot
+					VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], art);
+					break;
+				}
+			}
+			if(i == art->possibleSlots.size() && !art->isBig()) //if haven't find proper slot, use backpack or discard big artifact
+				sha.artifacts.push_back(art);
+		}
+		else if (!art->isBig()) //should be -1 => put artifact into backpack
+		{
+			sha.artifacts.push_back(art);
+		}
+	}
+	else
+	{
+		if(!vstd::contains(sha.artifWorn,ui16(position)))
+		{
+			VLC->arth->equipArtifact(sha.artifWorn, position, art);
+		}
+		else if (!art->isBig())
+		{
+			sha.artifacts.push_back(art);
+		}
+	}
+
+	sendAndApply(&sha);
+}
+bool CGameHandler::removeArtifact(CArtifact* art, int hid)
 {
 {
 	const CGHeroInstance* h = getHero(hid);
 	const CGHeroInstance* h = getHero(hid);
 
 
@@ -2277,15 +2323,15 @@ bool CGameHandler::removeArtifact(int artid, int hid)
 	sha.artifacts = h->artifacts;
 	sha.artifacts = h->artifacts;
 	sha.artifWorn = h->artifWorn;
 	sha.artifWorn = h->artifWorn;
 	
 	
-	std::vector<ui32>::iterator it;
-	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), artid)) != sha.artifacts.end()) //it is in backpack
+	std::vector<CArtifact*>::iterator it;
+	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), art)) != sha.artifacts.end()) //it is in backpack
 		sha.artifacts.erase(it);
 		sha.artifacts.erase(it);
 	else //worn
 	else //worn
 	{
 	{
-		std::map<ui16,ui32>::iterator itr;
+		std::map<ui16,CArtifact*>::iterator itr;
 		for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
 		for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
 		{
 		{
-			if (itr->second == artid)
+			if (itr->second == art)
 			{
 			{
 				VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
 				VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
 				break;
 				break;
@@ -2760,7 +2806,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 			return false;
 			return false;
 		}
 		}
 
 
-		removeArtifact(2, t->visitingHero->id);
+		removeArtifact(VLC->arth->artifacts[2], t->visitingHero->id);
 	}
 	}
 
 
 	NewStructures ns;
 	NewStructures ns;
@@ -3152,7 +3198,7 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
 	// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
 	// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
 	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
 	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
 	{
 	{
-		sha.setArtAtPos(srcSlot, -1);
+		sha.setArtAtPos(srcSlot, NULL);
 		if (!vstd::contains(sha.artifWorn, destSlot))
 		if (!vstd::contains(sha.artifWorn, destSlot))
 			destArtifact = NULL;
 			destArtifact = NULL;
 	}
 	}
@@ -3186,14 +3232,14 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
 
 
 	// If dest does not fit in src, put it in dest's backpack instead.
 	// If dest does not fit in src, put it in dest's backpack instead.
 	if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first.
 	if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first.
-		sha.setArtAtPos(destSlot, -1);
+		sha.setArtAtPos(destSlot, NULL);
 	const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
 	const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
 	if (srcHeroID == destHeroID && destArtifact)
 	if (srcHeroID == destHeroID && destArtifact)
-		sha.setArtAtPos(destSlot, destArtifact->id);
+		sha.setArtAtPos(destSlot, destArtifact);
 
 
-	sha.setArtAtPos(srcSlot, -1);
+	sha.setArtAtPos(srcSlot, NULL);
 	if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
 	if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
-		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact->id : -1);
+		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL);
 
 
 	// Internal hero artifact arrangement.
 	// Internal hero artifact arrangement.
 	if(srcHero == destHero) 
 	if(srcHero == destHero) 
@@ -3211,7 +3257,7 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
 		sha2.hid = destHeroID;
 		sha2.hid = destHeroID;
 		sha2.artifacts = destHero->artifacts;
 		sha2.artifacts = destHero->artifacts;
 		sha2.artifWorn = destHero->artifWorn;
 		sha2.artifWorn = destHero->artifWorn;
-		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact->id : -1);
+		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL);
 		if (!destFits)
 		if (!destFits)
 			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
 			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
 		sendAndApply(&sha2);
 		sendAndApply(&sha2);
@@ -3243,20 +3289,24 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 	sha.artifacts = hero->artifacts;
 	sha.artifacts = hero->artifacts;
 	sha.artifWorn = hero->artifWorn;
 	sha.artifWorn = hero->artifWorn;
 
 
-	if (assemble) {
-		if (VLC->arth->artifacts.size() < assembleTo) {
+	if (assemble)
+	{
+		if (VLC->arth->artifacts.size() < assembleTo)
+		{
 			complain("Illegal artifact to assemble to.");
 			complain("Illegal artifact to assemble to.");
 			return false;
 			return false;
 		}
 		}
 
 
-		if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo)) {
+		if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo))
+		{
 			complain("Artifact cannot be assembled.");
 			complain("Artifact cannot be assembled.");
 			return false;
 			return false;
 		}
 		}
 
 
 		const CArtifact &artifact = *VLC->arth->artifacts[assembleTo];
 		const CArtifact &artifact = *VLC->arth->artifacts[assembleTo];
 
 
-		if (artifact.constituents == NULL) {
+		if (artifact.constituents == NULL)
+		{
 			complain("Not a combinational artifact.");
 			complain("Not a combinational artifact.");
 			return false;
 			return false;
 		}
 		}
@@ -3265,32 +3315,43 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
 		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
 		const bool destSpecific = vstd::contains(artifact.possibleSlots, artifactSlot); // Prefer the chosen slot as the location for the assembled artifact.
 		const bool destSpecific = vstd::contains(artifact.possibleSlots, artifactSlot); // Prefer the chosen slot as the location for the assembled artifact.
 
 
-		BOOST_FOREACH(ui32 constituentID, *artifact.constituents) {
-			if (destSpecific && constituentID == destArtifact->id) {
-				sha.artifWorn[artifactSlot] = assembleTo;
+		BOOST_FOREACH(ui32 constituentID, *artifact.constituents)
+		{
+			if (destSpecific && constituentID == destArtifact->id)
+			{
+				sha.artifWorn[artifactSlot] = VLC->arth->artifacts[assembleTo];
 				destConsumed = true;
 				destConsumed = true;
 				continue;
 				continue;
 			}
 			}
 
 
 			bool found = false;
 			bool found = false;
-			for (std::map<ui16, ui32>::iterator it = sha.artifWorn.begin(); it != sha.artifWorn.end(); ++it) {
-				if (it->second == constituentID) { // Found possible constituent to substitute.
-					if (destSpecific && !destConsumed && it->second == destArtifact->id) {
+			for (std::map<ui16, CArtifact*>::iterator it = sha.artifWorn.begin(); it != sha.artifWorn.end(); ++it)
+			{
+				if (it->second->id == constituentID)
+				{ // Found possible constituent to substitute.
+					if (destSpecific && !destConsumed && it->second->id == destArtifact->id)
+					{
 						// Find the specified destination for assembled artifact.
 						// Find the specified destination for assembled artifact.
-						if (it->first == artifactSlot) {
-							it->second = assembleTo;
+						if (it->first == artifactSlot)
+						{
+							it->second = VLC->arth->artifacts[assembleTo];
 							destConsumed = true;
 							destConsumed = true;
 
 
 							found = true;
 							found = true;
 							break;
 							break;
 						}
 						}
-					} else {
+					}
+					else
+					{
 						// Either put the assembled artifact in a fitting spot, or put a lock.
 						// Either put the assembled artifact in a fitting spot, or put a lock.
-						if (!destSpecific && !destConsumed && vstd::contains(artifact.possibleSlots, it->first)) {
-							it->second = assembleTo;
+						if (!destSpecific && !destConsumed && vstd::contains(artifact.possibleSlots, it->first))
+						{
+							it->second = VLC->arth->artifacts[assembleTo];
 							destConsumed = true;
 							destConsumed = true;
-						} else {
-							it->second = 145;
+						}
+						else
+						{
+							it->second = VLC->arth->artifacts[145];
 						}
 						}
 
 
 						found = true;
 						found = true;
@@ -3303,19 +3364,27 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 				return false;
 				return false;
 			}
 			}
 		}
 		}
-	} else {
+	}
+	else
+	{
 		// Perform disassembly.
 		// Perform disassembly.
 		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
 		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
-		BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents) {
+		BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents)
+		{
 			const CArtifact &constituent = *VLC->arth->artifacts[constituentID];
 			const CArtifact &constituent = *VLC->arth->artifacts[constituentID];
 
 
-			if (!destConsumed && vstd::contains(constituent.possibleSlots, artifactSlot)) {
-				sha.artifWorn[artifactSlot] = constituentID;
+			if (!destConsumed && vstd::contains(constituent.possibleSlots, artifactSlot))
+			{
+				sha.artifWorn[artifactSlot] = VLC->arth->artifacts[constituentID];
 				destConsumed = true;
 				destConsumed = true;
-			} else {
-				BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots) {
-					if (vstd::contains(sha.artifWorn, slotID) && sha.artifWorn[slotID] == 145) {
-						sha.artifWorn[slotID] = constituentID;
+			}
+			else
+			{
+				BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots)
+				{
+					if (vstd::contains(sha.artifWorn, slotID) && sha.artifWorn[slotID]->id == 145)
+					{
+						sha.artifWorn[slotID]->id = constituentID;
 						break;
 						break;
 					}
 					}
 				}
 				}
@@ -4049,9 +4118,9 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		sha.hid = hero->id;
 		sha.hid = hero->id;
 		sha.artifacts = hero->artifacts;
 		sha.artifacts = hero->artifacts;
 		sha.artifWorn = hero->artifWorn;
 		sha.artifWorn = hero->artifWorn;
-		VLC->arth->equipArtifact(sha.artifWorn, 13, 4);
-		VLC->arth->equipArtifact(sha.artifWorn, 14, 5);
-		VLC->arth->equipArtifact(sha.artifWorn, 15, 6);
+		VLC->arth->equipArtifact(sha.artifWorn, 13, VLC->arth->artifacts[4]);
+		VLC->arth->equipArtifact(sha.artifWorn, 14, VLC->arth->artifacts[5]);
+		VLC->arth->equipArtifact(sha.artifWorn, 15, VLC->arth->artifacts[6]);
 		sendAndApply(&sha);
 		sendAndApply(&sha);
 	}
 	}
 	else if(message == "vcminahar") //1000000 movement points
 	else if(message == "vcminahar") //1000000 movement points
@@ -4108,10 +4177,10 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		sha.hid = hero->id;
 		sha.hid = hero->id;
 		sha.artifacts = hero->artifacts;
 		sha.artifacts = hero->artifacts;
 		sha.artifWorn = hero->artifWorn;
 		sha.artifWorn = hero->artifWorn;
-		sha.artifacts.push_back(2); //grail
+		sha.artifacts.push_back(VLC->arth->artifacts[2]); //grail
 		for (int g=7; g<=140; ++g)
 		for (int g=7; g<=140; ++g)
 		{
 		{
-			sha.artifacts.push_back(g);
+			sha.artifacts.push_back(VLC->arth->artifacts[g]);
 		}
 		}
 		sendAndApply(&sha);
 		sendAndApply(&sha);
 	}
 	}
@@ -5231,13 +5300,13 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
 	return true;
 	return true;
 }
 }
 
 
-bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ui32 artID)
+bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, CArtifact* art)
 {
 {
-	if(!removeArtifact(artID, hero->id))
+	if(!removeArtifact(art, hero->id))
 		COMPLAIN_RET("Cannot find artifact to sacrifice!");
 		COMPLAIN_RET("Cannot find artifact to sacrifice!");
 
 
 	int dmp, expToGive;
 	int dmp, expToGive;
-	m->getOffer(artID, 0, dmp, expToGive, ARTIFACT_EXP);
+	m->getOffer(art->id, 0, dmp, expToGive, ARTIFACT_EXP);
 	changePrimSkill(hero->id, 4, expToGive);
 	changePrimSkill(hero->id, 4, expToGive);
 	return true;
 	return true;
 }
 }

+ 3 - 2
server/CGameHandler.h

@@ -143,8 +143,9 @@ public:
 	void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);
 	void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);
 	void stopHeroVisitCastle(int obj, int heroID);
 	void stopHeroVisitCastle(int obj, int heroID);
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack
+	void giveNewArtifact(int hid, int position);
 	void moveArtifact(int hid, int oldPosition, int destPos);
 	void moveArtifact(int hid, int oldPosition, int destPos);
-	bool removeArtifact(int artid, int hid);
+	bool removeArtifact(CArtifact* art, int hid);
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
@@ -222,7 +223,7 @@ public:
 	void run(bool resume);
 	void run(bool resume);
 	void newTurn();
 	void newTurn();
 	void handleAfterAttackCasting( const BattleAttack & bat );
 	void handleAfterAttackCasting( const BattleAttack & bat );
-	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ui32 artID);
+	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, CArtifact* art);
 	friend class CVCMIServer;
 	friend class CVCMIServer;
 	friend class CScriptCallback;
 	friend class CScriptCallback;
 };
 };

+ 1 - 1
server/NetPacksServer.cpp

@@ -166,7 +166,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
 	case CREATURE_EXP:
 	case CREATURE_EXP:
 		return gh->sacrificeCreatures(m, hero, r1, val);
 		return gh->sacrificeCreatures(m, hero, r1, val);
 	case ARTIFACT_EXP:
 	case ARTIFACT_EXP:
-		return gh->sacrificeArtifact(m, hero, r1);
+		return gh->sacrificeArtifact(m, hero, hero->getArtAtPos(r1));
 	default:
 	default:
 		COMPLAIN_AND_RETURN("Unknown exchange mode!");
 		COMPLAIN_AND_RETURN("Unknown exchange mode!");
 	}
 	}