Pārlūkot izejas kodu

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 15 gadi atpakaļ
vecāks
revīzija
bce805dacc

+ 1 - 0
CCallback.cpp

@@ -17,6 +17,7 @@
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #include "hch/CSpellHandler.h"
+#include "hch/CArtHandler.h"
 #ifdef min
 #undef min
 #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++)
 	{
-		artifacts[i]->type = hero->getArtAtPos(i);
+		artifacts[i]->type = hero->getArtAtPos(i)->id;
 		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
 			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
 		else
@@ -796,7 +796,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 	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)
 			backpack[i]->hoverText ="";
 		else
@@ -847,7 +847,7 @@ void CKingdomInterface::CHeroItem::scrollArts(int move)
 	backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size();
 	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)
 			backpack[i]->hoverText ="";
 		else
@@ -912,7 +912,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
 		case 0://equipped arts
 			for (int i = iter ; i<iter+9;i++)
 			{
-				int artID = hero->getArtAtPos(i);
+				int artID = hero->getArtAtPos(i)->id;
 				if (artID>=0)
 					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();
 			iter = std::min(8, max);
 			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;
 	}
 	show(to);

+ 2 - 1
client/Client.h

@@ -117,7 +117,8 @@ public:
 	void heroVisitCastle(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
-	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, 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

+ 7 - 7
client/GUIClasses.cpp

@@ -2640,7 +2640,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
 				movedArt = CGI->arth->artifacts[id];
 				aw->arts->commonInfo->srcAOH = aw->arts;
 				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;
 				CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap);
@@ -3622,10 +3622,10 @@ void CAltarWindow::SacrificeAll()
 	}
 	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();
@@ -3778,13 +3778,13 @@ void CAltarWindow::SacrificeBackpack()
 
 	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;
 		}
 
-		putOnAltar(NULL, hero->artifacts[i]);
+		putOnAltar(NULL, hero->artifacts[i]->id);
 	}
 	arts->scrollBackpack(0);
 	calcTotalExp();

+ 70 - 33
hch/CArtHandler.cpp

@@ -10,6 +10,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 #include <boost/random/linear_congruential.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include "../lib/VCMI_Lib.h"
 extern CLodHandler *bitmaph;
 using namespace boost::assign;
@@ -47,25 +48,31 @@ 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.
  * @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))
 		return false;
 
 	// 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;
 
 	// Check if a combination artifact fits.
 	// 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.
-	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 miscSlots[] = {9, 10, 11, 12, 18};
 		int rings = 0;
@@ -108,7 +115,7 @@ bool CArtifact::fitsAt (const std::map<ui16, ui32> &artifWorn, ui16 slotID) cons
 	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))
 		return false;
@@ -119,9 +126,9 @@ bool CArtifact::canBeAssembledTo (const std::map<ui16, ui32> &artifWorn, ui32 ar
 	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
 	{
 		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;
 				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()
 {
 	VLC->arth = this;
@@ -181,11 +194,13 @@ CArtHandler::CArtHandler()
 	// War machines are the default big artifacts.
 	for (ui32 i = 3; i <= 6; 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()
 {
-	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)->constituentOf;
 	}
@@ -205,9 +220,28 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 	}
 	VLC->generaltexth->artifNames.resize(ARTIFACTS_QUANTITY);
 	VLC->generaltexth->artifDescriptions.resize(ARTIFACTS_QUANTITY);
+	std::map<ui32,ui8>::iterator itr;
 	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;
 		nart.id=i;
 		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 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);
 
-	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 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))
 		return;
 
-	const CArtifact &artifact = *artifacts[artifWorn[slotID]];
+	const CArtifact &artifact = *artifWorn[slotID];
 
 	// Remove artifact, if it's not already removed.
 	artifWorn.erase(slotID);
@@ -788,7 +825,7 @@ void CArtHandler::unequipArtifact(std::map<ui16, ui32> &artifWorn, ui16 slotID)
 			{
 				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);
 						break;

+ 33 - 15
hch/CArtHandler.h

@@ -17,19 +17,24 @@
  *
  */
 class CDefHandler;
+class CArtifact;
 
 class DLL_EXPORT CArtifact : public CBonusSystemNode //container for artifacts
 {
+protected:
 	std::string name, description; //set if custom
 public:
 	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 &Description() const; //getter
 	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 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
 
 	ui32 price;
@@ -52,46 +57,58 @@ public:
 	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:
-	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:
+	CScroll(){spellid=0;};
+	CScroll(spelltype sid){spellid = sid;};
 	spelltype spellid;
-	void Init(){};
+	void Init();
+	void SetProperty (int mod){spellid = mod;};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		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:
 	ui8 mode;
+	CCustomizableArt(){mode=0;};
 	void Init(){};
-	void SelectMode (int mod){};
+	void SetProperty (int mod){};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & mode;
 	}
 };
 
-class DLL_EXPORT CCommanderArt : public CArtifact, public IModableArt // Growing with time
+class DLL_EXPORT CCommanderArt : public IModableArt // Growing with time
 {
 public:
 	ui32 level;
+	CCommanderArt(){level = 0;};
 	void Init(){};
+	void SetProperty (int mod){level = mod;};
 	void Upgrade(){level++;};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & level;
 	}
 };
@@ -104,6 +121,7 @@ public:
 	std::vector<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
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
@@ -116,8 +134,8 @@ public:
 	void getAllowed(std::vector<CArtifact*> &out, int flags);
 	void erasePickedArt (si32 id);
 	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
 	static int convertMachineID(int id, bool creToArt);
 	CArtHandler();

+ 1 - 1
hch/CCampaignHandler.cpp

@@ -522,7 +522,7 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
 			{
 				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;
 }
 
-ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
+CArtifact* CGHeroInstance::getArtAtPos(ui16 pos) const
 {
 	if(pos<19)
 		if(vstd::contains(artifWorn,pos))
 			return artifWorn.find(pos)->second;
 		else
-			return -1;
+			return NULL;
 	else
 		if(pos-19 < artifacts.size())
 			return artifacts[pos-19];
 		else 
-			return -1;
+			return NULL;
 }
 
 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
@@ -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
 	{
-		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)
 		portrait = subID;
@@ -886,13 +882,13 @@ void CGHeroInstance::initArmy(CCreatureSet *dst /*= NULL*/)
 			switch (creID)
 			{
 			case 145: //catapult
-				VLC->arth->equipArtifact(artifWorn, 16, 3);
+				VLC->arth->equipArtifact(artifWorn, 16, VLC->arth->artifacts[3]);
 				break;
 			default:
 				VLC->arth->equipArtifact(
 					artifWorn,
 					9+CArtHandler::convertMachineID(creID,true),
-					  CArtHandler::convertMachineID(creID,true));
+					  VLC->arth->artifacts[CArtHandler::convertMachineID(creID,true)]);
 				break;
 			}
 		}
@@ -1421,8 +1417,8 @@ si32 CGHeroInstance::manaRegain() 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 -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
  * 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)) 
 			{
-				VLC->arth->equipArtifact(artifWorn, *it, aid);
+				VLC->arth->equipArtifact(artifWorn, *it, artifact);
 				break;
 			}
 		}
 	} 
 	else 
 	{
-		artifacts.push_back(aid);
+		artifacts.push_back(artifact);
 	}
 }
 
 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 false;
@@ -1500,8 +1497,8 @@ void CGHeroInstance::getParents(TCNodes &out, const CBonusSystemNode *root /*= N
 			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);
 }
@@ -3594,24 +3591,36 @@ void CGArtifact::initObj()
 	blockVisit = true;
 	if(ID == 5)
 		hoverName = VLC->arth->artifacts[subID]->Name();
+	if(ID == 93)
+		subID = 1;
 }
 
 void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 {
 	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);
 	}
 	else
@@ -3632,13 +3641,22 @@ void CGArtifact::onHeroVisit( 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);
 }
@@ -4373,7 +4391,7 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 			case CQuest::MISSION_ART:
 				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;
 			case CQuest::MISSION_ARMY:

+ 4 - 3
hch/CObjectHandler.h

@@ -47,6 +47,7 @@ struct InfoWindow;
 struct Component;
 struct BankConfig;
 struct UpdateHeroSpeciality;
+struct NewArtifact;
 class CGBoat;
 
 class DLL_EXPORT CQuest
@@ -266,8 +267,8 @@ public:
 	ui8 inTownGarrison; // if hero is in town garrison 
 	const CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
 	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)
 
 	struct DLL_EXPORT Patrol
@@ -337,7 +338,7 @@ public:
 
 	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;
 	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)

+ 1 - 1
lib/CGameState.cpp

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

+ 3 - 1
lib/CGameState.h

@@ -61,6 +61,7 @@ struct TerrainTile;
 class CHeroClass;
 class CCampaign;
 class CCampaignState;
+class IModableArt;
 
 namespace boost
 {
@@ -142,7 +143,8 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		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 & static_cast<CBonusSystemNode&>(*this);
 	}

+ 2 - 1
lib/Connection.cpp

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

+ 2 - 1
lib/IGameCallback.h

@@ -93,7 +93,8 @@ public:
 	virtual void heroVisitCastle(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 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, 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

+ 19 - 4
lib/NetPacks.h

@@ -602,18 +602,18 @@ struct SetHeroArtifacts : public CPackForClient //509
 	SetHeroArtifacts(){type = 509;};
 	void applyCl(CClient *cl);
 	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;
-	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)
 	{
 		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
 };   
 
@@ -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
 {
 	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 )
 {
 	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)
 			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)
+		{
 			equiped.push_back(i->second);
+		}
 
 	//update hero data
 	h->artifacts = artifacts;
 	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)
 	{
@@ -477,14 +479,14 @@ DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art)
 	{
 		if (pos < 19) 
 		{
-			VLC->arth->equipArtifact(artifWorn, pos, (ui32) art);
+			VLC->arth->equipArtifact(artifWorn, pos, art);
 		} 
 		else // Goes into the backpack.
 		{ 
 			if(pos - 19 < artifacts.size())
-				artifacts.insert(artifacts.begin() + (pos - 19), art);
+				artifacts.insert(artifacts.begin() + (pos - 19), const_cast<CArtifact*>(art));
 			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();
 	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 )
 {

+ 1 - 0
lib/RegisterTypes.cpp

@@ -137,6 +137,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<AdvmapSpellCast>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<NewObject>();
+	s.template registerType<NewArtifact>();
 	s.template registerType<SetAvailableArtifacts>();
 
 	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;
 			if(id != artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, pom, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, pom, VLC->arth->artifacts[id]);
 		}
 		//misc5 art //17
 		if(version>=SoD)
 		{
 			int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			if(id!=artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, 16, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, 16, VLC->arth->artifacts[id]);
 			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
 		int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 		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..
 		if(version>RoE)
 		{
 			id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 			if(id!=artmask)
-				VLC->arth->equipArtifact(nhi->artifWorn, 18, id);
+				VLC->arth->equipArtifact(nhi->artifWorn, 18, VLC->arth->artifacts[id]);
 		}
 		else
 			i+=1;
@@ -1102,7 +1102,7 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
 					{
 						int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						if(id!=artmask)
-							VLC->arth->equipArtifact(cgh->artifWorn, pom, id);
+							VLC->arth->equipArtifact(cgh->artifWorn, pom, VLC->arth->artifacts[id]);
 					}
 					//misc5 art //17
 					if(version>=SoD)
@@ -1115,13 +1115,13 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
 					//spellbook
 					int id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 					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..
 					if(version>RoE)
 					{
 						id = readNormalNr(bufor,i, artidlen); i+=artidlen;
 						if(id!=artmask)
-							VLC->arth->equipArtifact(cgh->artifWorn, 18, id);
+							VLC->arth->equipArtifact(cgh->artifWorn, 18, VLC->arth->artifacts[id]);
 					}
 					else
 						i+=1;

+ 3 - 2
lib/map.h

@@ -30,7 +30,7 @@ class CGHeroInstance;
 class CGCreature;
 class CQuest;
 class CGTownInstance;
-
+class IModableArt;
 
 
 struct DLL_EXPORT TerrainTile
@@ -279,6 +279,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	std::vector<CGObjectInstance*> objects;
 	std::vector<CGHeroInstance*> heroes;
 	std::vector<CGTownInstance*> towns;
+	std::vector<IModableArt *> artInstances; //stores single scrolls
 	std::map<ui16, CGCreature*> monsters;
 	std::map<ui16, CGHeroInstance*> heroesToBeat;
 
@@ -313,7 +314,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	{
 		h & static_cast<CMapHeader&>(*this);
 		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
 		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
 {
 	const CGHeroInstance* h = getHero(hid);
-	const CArtifact &art = *VLC->arth->artifacts[artid];
+	CArtifact * const art = VLC->arth->artifacts[artid];
 
 	SetHeroArtifacts sha;
 	sha.hid = hid;
@@ -2237,38 +2237,84 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
 		if(position == -2)
 		{
 			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.
-					VLC->arth->equipArtifact(sha.artifWorn, art.possibleSlots[i], artid);
+					VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], VLC->arth->artifacts[artid]);
 					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
 	{
-		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);
 }
-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);
 
@@ -2277,15 +2323,15 @@ bool CGameHandler::removeArtifact(int artid, int hid)
 	sha.artifacts = h->artifacts;
 	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);
 	else //worn
 	{
-		std::map<ui16,ui32>::iterator itr;
+		std::map<ui16,CArtifact*>::iterator 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);
 				break;
@@ -2760,7 +2806,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 			return false;
 		}
 
-		removeArtifact(2, t->visitingHero->id);
+		removeArtifact(VLC->arth->artifacts[2], t->visitingHero->id);
 	}
 
 	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.
 	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
 	{
-		sha.setArtAtPos(srcSlot, -1);
+		sha.setArtAtPos(srcSlot, NULL);
 		if (!vstd::contains(sha.artifWorn, destSlot))
 			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 (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);
 	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)
-		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact->id : -1);
+		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL);
 
 	// Internal hero artifact arrangement.
 	if(srcHero == destHero) 
@@ -3211,7 +3257,7 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot,
 		sha2.hid = destHeroID;
 		sha2.artifacts = destHero->artifacts;
 		sha2.artifWorn = destHero->artifWorn;
-		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact->id : -1);
+		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL);
 		if (!destFits)
 			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
 		sendAndApply(&sha2);
@@ -3243,20 +3289,24 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 	sha.artifacts = hero->artifacts;
 	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.");
 			return false;
 		}
 
-		if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo)) {
+		if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo))
+		{
 			complain("Artifact cannot be assembled.");
 			return false;
 		}
 
 		const CArtifact &artifact = *VLC->arth->artifacts[assembleTo];
 
-		if (artifact.constituents == NULL) {
+		if (artifact.constituents == NULL)
+		{
 			complain("Not a combinational artifact.");
 			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.
 		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;
 				continue;
 			}
 
 			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.
-						if (it->first == artifactSlot) {
-							it->second = assembleTo;
+						if (it->first == artifactSlot)
+						{
+							it->second = VLC->arth->artifacts[assembleTo];
 							destConsumed = true;
 
 							found = true;
 							break;
 						}
-					} else {
+					}
+					else
+					{
 						// 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;
-						} else {
-							it->second = 145;
+						}
+						else
+						{
+							it->second = VLC->arth->artifacts[145];
 						}
 
 						found = true;
@@ -3303,19 +3364,27 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 				return false;
 			}
 		}
-	} else {
+	}
+	else
+	{
 		// Perform disassembly.
 		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];
 
-			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;
-			} 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;
 					}
 				}
@@ -4049,9 +4118,9 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		sha.hid = hero->id;
 		sha.artifacts = hero->artifacts;
 		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);
 	}
 	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.artifacts = hero->artifacts;
 		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)
 		{
-			sha.artifacts.push_back(g);
+			sha.artifacts.push_back(VLC->arth->artifacts[g]);
 		}
 		sendAndApply(&sha);
 	}
@@ -5231,13 +5300,13 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
 	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!");
 
 	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);
 	return true;
 }

+ 3 - 2
server/CGameHandler.h

@@ -143,8 +143,9 @@ public:
 	void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);
 	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 giveNewArtifact(int hid, int position);
 	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, 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
@@ -222,7 +223,7 @@ public:
 	void run(bool resume);
 	void newTurn();
 	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 CScriptCallback;
 };

+ 1 - 1
server/NetPacksServer.cpp

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