Răsfoiți Sursa

Redid stack artifacts. Broken save compatibility. Added serializer support for boost::variant and sending CStackInstace* over network by implicitly passing IDs. Moved seeds and checksum to StartInfo. Various minor changes.

Michał W. Urbańczyk 13 ani în urmă
părinte
comite
722ec55384

+ 6 - 44
CCallback.cpp

@@ -128,51 +128,13 @@ bool CCallback::dismissHero(const CGHeroInstance *hero)
 // 	return gs->players[player].serial;
 // }
 
-bool CCallback::swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2)
+bool CCallback::swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)
 {
-	const CStackInstance * stack1 = dynamic_cast<const CStackInstance*>(src);
-	const CStackInstance * stack2 = dynamic_cast<const CStackInstance*>(dest);
-	const CGHeroInstance * hero1 = dynamic_cast<const CGHeroInstance*>(src);
-	const CGHeroInstance * hero2 = dynamic_cast<const CGHeroInstance*>(dest);
-
-	ExchangeArtifacts ea(0,0,0,0);
-
-	if (hero1 && hero2)
-	{
-		if(player!=hero1->tempOwner && player!=hero2->tempOwner) //player can exchange artifacts only between his own heroes
-			return false;
-		else
-		{
-			ExchangeArtifacts ea(hero1->id, hero2->id, pos1, pos2);
-			sendRequest(&ea);
-			return true;
-		}
-	}
-	else if (hero1 && stack2) //move artifact from hero to stack
-	{
-		ea.hid1 = hero1->id;
-		ea.s2 = StackLocation(stack2->armyObj, stack2->armyObj->findStack(stack2));
-		ea.slot1 = pos1;
-		ea.slot2 = pos2;
-		sendRequest(&ea);
-		return true;
-	}
-	else if (stack1 && hero2) //move artifacts from stakc to hero
-	{
-		ea.s1 = StackLocation(stack1->armyObj, stack1->armyObj->findStack(stack1));
-		ea.hid2 = hero2->id;
-		ea.slot1 = pos1;
-		ea.slot2 = pos2;
-		sendRequest(&ea);
-		return true;
-	}
-	else if (stack1 && stack2)
-	{
-		//TODO: merge stacks?
-		return false;
-	}
-	else
-		return false;
+	ExchangeArtifacts ea;
+	ea.src = l1;
+	ea.dst = l2;
+	sendRequest(&ea);
+	return true;
 }
 
 /**

+ 2 - 3
CCallback.h

@@ -13,7 +13,6 @@
  *
  */
 
-class IArtifactSetBase;
 class CGHeroInstance;
 class CGameState;
 struct CPath;
@@ -63,7 +62,7 @@ public:
 	virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) =0; //first goes to the second
 	virtual int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack
 	//virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
-	virtual bool swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2)=0;
+	virtual bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)=0;
 	virtual bool assembleArtifacts(const CGHeroInstance * hero, ui16 artifactSlot, bool assemble, ui32 assembleTo)=0;
 	virtual bool dismissCreature(const CArmedInstance *obj, int stackPos)=0;
 	virtual void endTurn()=0;
@@ -127,7 +126,7 @@ public:
 	int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val);
 	bool dismissHero(const CGHeroInstance * hero);
 	//bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2);
-	bool swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2);
+	bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2);
 	//bool moveArtifact(const CGHeroInstance * hero, ui16 src, const CStackInstance * stack, ui16 dest); // TODO: unify classes
 	//bool moveArtifact(const CStackInstance * stack, ui16 src , const CGHeroInstance * hero, ui16 dest); // TODO: unify classes
 	bool assembleArtifacts(const CGHeroInstance * hero, ui16 artifactSlot, bool assemble, ui32 assembleTo);

+ 1 - 0
Global.h

@@ -68,6 +68,7 @@
 #include <boost/range/algorithm.hpp>
 #include <boost/thread.hpp>
 #include <boost/unordered_set.hpp>
+#include <boost/variant.hpp>
 
 #ifdef ANDROID
 #include <android/log.h>

+ 4 - 5
client/CCreatureWindow.cpp

@@ -121,6 +121,7 @@ CCreatureWindow::CCreatureWindow(const CStackInstance &st, int Type, boost::func
 
 void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner)
 {
+	creatureArtifact = NULL; //may be set later
 	stack = Stack;
 	c = stack->type;
 	if(!StackNode)
@@ -264,11 +265,9 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
 				if (heroOwner)
 					passArtToHero = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, 0), 437, 148, "OVBUTN1.DEF", SDLK_HOME);
 			}
-			if (const CArtifactInstance * art = stack->getArt(GameConstants::CREATURE_ART))
-				blitAt(graphics->artDefs->ourImages[art->id].bitmap, 466, 161, *bitmap);
+			if (creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT))
+				blitAt(graphics->artDefs->ourImages[creatureArtifact->artType->id].bitmap, 466, 100, *bitmap);
 		}
-		else
-			creatureArtifact = NULL;
 	}
 
 	if (battleStack) //only during battle
@@ -398,7 +397,7 @@ void CCreatureWindow::sliderMoved(int newpos)
 void CCreatureWindow::scrollArt(int dir)
 {
 	//TODO: get next artifact
-	creatureArtifact = const_cast<CArtifactInstance*>(stack->getArt(GameConstants::CREATURE_ART));
+	creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT);
 }
 
 void CCreatureWindow::passArtifactToHero()

+ 1 - 1
client/CCreatureWindow.h

@@ -48,7 +48,7 @@ public:
 	const CStackInstance *stack;
 	const CBonusSystemNode *stackNode;
 	const CGHeroInstance *heroOwner;
-	CArtifactInstance *creatureArtifact; //currently worn artifact
+	const CArtifactInstance *creatureArtifact; //currently worn artifact
 	std::vector<CComponent*> upgResCost; //cost of upgrade (if not possible then empty)
 	std::vector<CBonusItem*> bonusItems;
 	std::vector<LRClickableAreaWText*> spellEffects;

+ 6 - 0
client/CMT.cpp

@@ -99,6 +99,12 @@ void startGameFromFile(const std::string &fname)
 	{
 		StartInfo si;
 		CLoadFile out(fname);
+		if(!out.sfile || !*out.sfile)
+		{
+			tlog1 << "Failed to open startfile, falling back to the main menu!\n";
+			GH.curInt = new CGPreGame;
+			return;
+		}
 		out >> si;
 		while(GH.topInt())
 			GH.popIntTotally(GH.topInt());

+ 2 - 5
client/Client.cpp

@@ -333,15 +333,12 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	c << myPlayers;
 
 
-	ui32 seed, sum;
-	si32 seedPostInit;
-	c >> si	>> sum >> seed >> seedPostInit;
+	c >> si;
 	tlog0 <<"\tSending/Getting info to/from the server: "<<tmh.getDiff()<<std::endl;
-	tlog0 << "\tUsing random seed: "<<seed << std::endl;
 
 	gs = const_cast<CGameInfo*>(CGI)->state;
 	gs->scenarioOps = si;
-	gs->init(si, sum, seed, seedPostInit);
+	gs->init(si);
 	tlog0 <<"Initializing GameState (together): "<<tmh.getDiff()<<std::endl;
 
 	if(gs->map)

+ 1 - 1
client/Client.h

@@ -189,7 +189,7 @@ public:
 	void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, int pos) OVERRIDE {};
 	void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) OVERRIDE {}; 
 	void removeArtifact(const ArtifactLocation &al) OVERRIDE {};
-	void moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) OVERRIDE {};
+	bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) OVERRIDE {return false;};
 
 	void showCompInfo(ShowInInfobox * comp) OVERRIDE {};
 	void heroVisitCastle(int obj, int heroID) OVERRIDE {};

+ 46 - 67
client/GUIClasses.cpp

@@ -262,25 +262,31 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
 				}
 			}
 		}
-		else //drop artifact or highlight
+		else //highlight or drop artifact
 		{
 			bool artSelected = false;
-			if (CHeroWindow* chw = dynamic_cast<CHeroWindow*>(GH.topInt())) //dirty solution
+			if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution
 			{
-				BOOST_FOREACH(CArtifactsOfHero *aoh, chw->artSets) // why they are multiple?
+				const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo;
+				if (const CArtifactInstance *art = commonInfo->src.art)
 				{
-					if (const CArtifactInstance *art = aoh->commonInfo->src.art)
-					{
-						artSelected = true;
-						if (art->canBePutAt(ArtifactLocation(myStack, GameConstants::CREATURE_ART)))
-						{	//equip clicked stack
-							LOCPLINT->cb->swapArtifacts(aoh->getHero(), aoh->commonInfo->src.slotID, myStack, GameConstants::CREATURE_ART);
-							break;
+					const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero();
+					artSelected = true;
+					ArtifactLocation src(srcHero, commonInfo->src.slotID);
+					ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
+					if (art->canBePutAt(dst, true))
+					{	//equip clicked stack
+						if(dst.getArt())
+						{
+							//creature can wear only one active artifact
+							//if we are placing a new one, the old one will be returned to the hero's backpack
+							LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
 						}
+						LOCPLINT->cb->swapArtifacts(src, dst);
 					}
 				}
 			}
-			if (artSelected || creature)
+			if (!artSelected && creature)
 			{
 				owner->highlighted = this;
 				if(creature)
@@ -315,7 +321,6 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg
 {
 	//assert(Creature == CGI->creh->creatures[Creature->idNumber]);
 	active = false;
-	highlight = false;
 	upg = Upg;
 	ID = IID;
 	myStack = Creature;
@@ -353,11 +358,7 @@ void CGarrisonSlot::showAll(SDL_Surface * to)
 		if((owner->highlighted==this)
 			|| (owner->splitting && owner->highlighted->creature == creature))
 		{
-			highlight = true;
-		}
-		{
-			if (highlight)
-				blitAt(imgs[-1],pos,to);
+			blitAt(imgs[-1],pos,to);
 		}
 	}
 	else//empty slot
@@ -2738,7 +2739,7 @@ void CTradeWindow::artifactSelected(CArtPlace *slot)
 {
 	assert(mode == EMarketMode::ARTIFACT_RESOURCE);
 	items[1][0]->setArtInstance(slot->ourArt);
-	if(slot->ourArt && slot->ourArt->id >= 0)
+	if(slot->ourArt)
 		hLeft = items[1][0];
 	else
 		hLeft = NULL;
@@ -3606,7 +3607,7 @@ void CAltarWindow::moveFromSlotToAltar(int slotID, CTradeableItem* altarSlot, co
 	if(putOnAltar(altarSlot, art))
 	{
 		if(slotID < GameConstants::BACKPACK_START)
-			LOCPLINT->cb->swapArtifacts(hero, slotID, hero, freeBackpackSlot);
+			LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero, slotID), ArtifactLocation(hero, freeBackpackSlot));
 		else
 		{
 			arts->commonInfo->src.clear();
@@ -4418,7 +4419,7 @@ void CArtPlace::clickRight(tribool down, bool previousState)
 {
 	if(down && ourArt && !locked && text.size() && !picked)  //if there is no description or it's a lock, do nothing ;]
 	{
-		if (slotID < 19)
+		if (slotID < GameConstants::BACKPACK_START)
 		{
 			if(ourOwner->allowedAssembling)
 			{
@@ -4556,7 +4557,7 @@ bool CArtPlace::fitsHere(const CArtifactInstance * art) const
 		return true;
 
 	// Anything can but War Machines can be placed in backpack.
-	if (slotID >= 19)
+	if (slotID >= GameConstants::BACKPACK_START)
 		return !CGI->arth->isBigArtifact(art->id);
 
 	return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID), true);
@@ -4812,7 +4813,7 @@ void CArtifactsOfHero::scrollBackpack(int dir)
 
 		if (s < artsInBackpack)
 		{
-			int slotID = 19 + (s + backpackPos)%artsInBackpack;
+			int slotID = GameConstants::BACKPACK_START + (s + backpackPos)%artsInBackpack;
 			const CArtifactInstance *art = curHero->getArt(slotID);
 			assert(art);
 			if(!vstd::contains(toOmit, art))
@@ -4829,7 +4830,7 @@ void CArtifactsOfHero::scrollBackpack(int dir)
 		}
 	}
 	for( ; s - omitedSoFar < backpack.size(); s++)
-		eraseSlotData(backpack[s-omitedSoFar], 19 + s);
+		eraseSlotData(backpack[s-omitedSoFar], GameConstants::BACKPACK_START + s);
 
 	//in artifact merchant selling artifacts we may have highlight on one of backpack artifacts -> market needs update, cause artifact under highlight changed
 	if(highlightModeCallback)
@@ -4864,21 +4865,6 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
 		BOOST_FOREACH(CArtPlace *place, aoh->artWorn)
 			place->marked = art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true);
 
-	if (CHeroWindow* chw = dynamic_cast<CHeroWindow*>(GH.topInt()))
-	{
-		//FIXME: garrison window has two rows of cretaures :?
-		BOOST_FOREACH (CGarrisonSlot *g, chw->garr->slotsDown)
-		{
-			if (g->myStack)
-				if (art->canBePutAt(ArtifactLocation(g->myStack, GameConstants::CREATURE_ART), false));
-					g->highlight = true;
-		}
-	}
-	/*else if(CExchangeWindow* cew = dynamic_cast<CExchangeWindow*>(GH.topInt()))
-	{
-		//TODO
-	}*/
-
 	safeRedraw();
 }
 
@@ -4966,7 +4952,7 @@ CArtifactsOfHero::CArtifactsOfHero(std::vector<CArtPlace *> ArtWorn, std::vector
 	for(size_t s=0; s<backpack.size(); ++s)
 	{
 		backpack[s]->ourOwner = this;
-		eraseSlotData(backpack[s], 19 + s);
+		eraseSlotData(backpack[s], GameConstants::BACKPACK_START + s);
 	}
 
 	leftArtRoll->callback  += boost::bind(&CArtifactsOfHero::scrollBackpack,this,-1);
@@ -5077,28 +5063,31 @@ void CArtifactsOfHero::safeRedraw()
 
 void CArtifactsOfHero::realizeCurrentTransaction()
 {
-	assert(commonInfo->src.AOH || commonInfo->src.CAS);
-	assert(commonInfo->dst.AOH || commonInfo->dst.CAS);
-	LOCPLINT->cb->swapArtifacts(commonInfo->src.AOH ? (IArtifactSetBase*)commonInfo->src.AOH->curHero : commonInfo->src.CAS, commonInfo->src.slotID,
-								commonInfo->dst.AOH ? (IArtifactSetBase*)commonInfo->dst.AOH->curHero : commonInfo->dst.CAS, commonInfo->dst.slotID);
+	assert(commonInfo->src.AOH);
+	assert(commonInfo->dst.AOH);
+	LOCPLINT->cb->swapArtifacts(ArtifactLocation(commonInfo->src.AOH->curHero, commonInfo->src.slotID),
+								ArtifactLocation(commonInfo->dst.AOH->curHero, commonInfo->dst.slotID));
 }
 
 void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
 {
-	if(src.hero == curHero && src.slot >= GameConstants::BACKPACK_START)
+	bool isCurHeroSrc = src.isHolder(curHero),
+		isCurHeroDst = dst.isHolder(curHero);
+	if(isCurHeroSrc && src.slot >= GameConstants::BACKPACK_START)
 		updateSlot(src.slot);
-	if(dst.hero == curHero && dst.slot >= GameConstants::BACKPACK_START)
+	if(isCurHeroDst && dst.slot >= GameConstants::BACKPACK_START)
 		updateSlot(dst.slot);
-	if(src.hero == curHero  ||  dst.hero == curHero) //we need to update all slots, artifact might be combined and affect more slots
+	if(isCurHeroSrc  ||  isCurHeroDst) //we need to update all slots, artifact might be combined and affect more slots
 		updateWornSlots(false);
 
-	if (src.hero != curHero && dst.hero != curHero)
+	if (!src.isHolder(curHero) && !isCurHeroDst)
 		return;
 
 	if(commonInfo->src == src) //artifact was taken from us
 	{
-		//assert(commonInfo->dst == dst  ||  dst.slot == dst.hero->artifactsInBackpack.size() + GameConstants::BACKPACK_START);
-		//FIXME: assertion fails for stack artifacts
+		assert(commonInfo->dst == dst  //expected movement from slot ot slot
+			||  dst.slot == dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START //artifact moved back to backpack (eg. to make place for art we are moving)
+			|| dst.getHolderArtSet()->bearerType() == ArtBearer::CREATURE);
 		commonInfo->reset();
 		unmarkSlots();
 	}
@@ -5110,7 +5099,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
 		CArtPlace *ap = NULL;
 		BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
 		{
-			if(aoh->curHero == dst.hero)
+			if(dst.isHolder(aoh->curHero))
 			{
 				commonInfo->src.AOH = aoh;
 				if((ap = aoh->getArtPlace(dst.slot)))
@@ -5133,7 +5122,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
 	}
 	else if(src.slot >= GameConstants::BACKPACK_START &&
 	        src.slot <  commonInfo->src.slotID &&
-			src.hero == commonInfo->src.AOH->curHero) //artifact taken from before currently picked one
+			src.isHolder(commonInfo->src.AOH->curHero)) //artifact taken from before currently picked one
 	{
 		//int fixedSlot = src.hero->getArtPos(commonInfo->src.art);
 		commonInfo->src.slotID--;
@@ -5157,14 +5146,14 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
 	if(dst.slot < GameConstants::BACKPACK_START  &&  src.slot - GameConstants::BACKPACK_START < backpackPos)
  		shift--;
 
-	if( (src.hero == curHero && src.slot >= GameConstants::BACKPACK_START)
-	 || (dst.hero == curHero && dst.slot >= GameConstants::BACKPACK_START) )
+	if( (isCurHeroSrc && src.slot >= GameConstants::BACKPACK_START)
+	 || (isCurHeroDst && dst.slot >= GameConstants::BACKPACK_START) )
 		scrollBackpack(shift); //update backpack slots
 }
 
 void CArtifactsOfHero::artifactRemoved(const ArtifactLocation &al)
 {
-	if(al.hero == curHero)
+	if(al.isHolder(curHero))
 	{
 		if(al.slot < GameConstants::BACKPACK_START)
 			updateWornSlots(0);
@@ -5191,13 +5180,13 @@ CArtPlace * CArtifactsOfHero::getArtPlace(int slot)
 
 void CArtifactsOfHero::artifactAssembled(const ArtifactLocation &al)
 {
-	if(al.hero == curHero)
+	if(al.isHolder(curHero))
 		updateWornSlots();
 }
 
 void CArtifactsOfHero::artifactDisassembled(const ArtifactLocation &al)
 {
-	if(al.hero == curHero)
+	if(al.isHolder(curHero))
 		updateWornSlots();
 }
 
@@ -6323,21 +6312,11 @@ void CArtifactsOfHero::SCommonPart::Artpos::setTo(const CArtPlace *place, bool d
 		art = place->ourArt;
 }
 
-IArtifactSetBase * CArtifactsOfHero::SCommonPart::Artpos::getArtHolder()
-{
-	if (AOH)
-		return (IArtifactSetBase*)AOH;
-	if (CAS)
-		return (IArtifactSetBase*)CAS;
-	tlog2 <<"Warning! Artpos without source\n";
-	return NULL;
-}
-
 bool CArtifactsOfHero::SCommonPart::Artpos::operator==(const ArtifactLocation &al) const
 {
 	if(!AOH)
 		return false;
-	bool ret = al.hero == AOH->curHero  &&  al.slot == slotID;
+	bool ret = al.isHolder(AOH->curHero)  &&  al.slot == slotID;
 
 	//assert(al.getArt() == art);
 	return ret;

+ 0 - 3
client/GUIClasses.h

@@ -25,7 +25,6 @@
  */
 
 struct ArtifactLocation;
-class IArtifactSetBase;
 class CStackBasicDescriptor;
 class CBonusSystemNode;
 class CArtifact;
@@ -858,13 +857,11 @@ public:
 		{
 			int slotID;
 			const CArtifactsOfHero *AOH;
-			const CCreatureArtifactSet *CAS;
 			const CArtifactInstance *art;
 
 			Artpos();
 			void clear();
 			void setTo(const CArtPlace *place, bool dontTakeBackpack);
-			IArtifactSetBase * getArtHolder(); // returns AOH or CAS
 			bool valid();
 			bool operator==(const ArtifactLocation &al) const;
 		} src, dst;

+ 7 - 8
client/NetPacksClient.cpp

@@ -210,30 +210,29 @@ void RebalanceStacks::applyCl( CClient *cl )
 
 void PutArtifact::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactPut, al);
+	INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactPut, al);
 }
 
 void EraseArtifact::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactRemoved, al);
+	INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactRemoved, al);
 }
 
 void MoveArtifact::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst);
-	if (src.hero.get() && dst.hero.get())
-		if(src.hero->tempOwner != dst.hero->tempOwner)
-			INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst);
+	INTERFACE_CALL_IF_PRESENT(src.owningPlayer(), artifactMoved, src, dst);
+	if(src.owningPlayer() != dst.owningPlayer())
+		INTERFACE_CALL_IF_PRESENT(src.owningPlayer(), artifactMoved, src, dst);
 }
 
 void AssembledArtifact::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactAssembled, al);
+	INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactAssembled, al);
 }
 
 void DisassembledArtifact::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactDisassembled, al);
+	INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactDisassembled, al);
 }
 
 void HeroVisit::applyCl( CClient *cl )

+ 99 - 239
lib/CArtHandler.cpp

@@ -7,7 +7,6 @@
 #include "../lib/VCMI_Lib.h"
 #include "CSpellHandler.h"
 #include "CObjectHandler.h"
-//#include "CCreatureSet.h"
 #include "NetPacks.h"
 
 extern CLodHandler *bitmaph;
@@ -196,8 +195,7 @@ CArtHandler::CArtHandler()
 	// War machines are the default big artifacts.
 	for (ui32 i = 3; i <= 6; i++)
 		bigArtifacts.insert(i);
-	if (GameConstants::STACK_ARTIFACT)
-		creatureArtifacts += 141, 142, 143, 156; //basic Wog arts and Warlord's banner
+	//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()
@@ -233,11 +231,13 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 		loadToIt(VLC->generaltexth->artifNames[i],buf,it,4);
 		loadToIt(pom,buf,it,4);
 		nart.price=atoi(pom.c_str());
+		nart.possibleSlots[ArtBearer::HERO]; //we want to generate map entry even if it will be empty
+		nart.possibleSlots[ArtBearer::CREATURE]; //we want to generate map entry even if it will be empty
 		for(int j=0;j<slots.size();j++)
 		{
 			loadToIt(pom,buf,it,4);
 			if(pom.size() && pom[0]=='x')
-				nart.possibleSlots.push_back(slots[j]);
+				nart.possibleSlots[ArtBearer::HERO].push_back(slots[j]);
 		}
 		loadToIt(pom,buf,it,4);
 		nart.aClass = classes[pom[0]];
@@ -739,9 +739,19 @@ void CArtHandler::addBonuses()
 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +4, Res::CRYSTAL);
 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +4, Res::GEMS);
 
+
 	//Stack artifact test
 	if (GameConstants::STACK_ARTIFACT)
 	{
+		auto makeItCreatureArt = [this](int aid)
+		{
+			CArtifact *a = artifacts[aid];
+			a->possibleSlots[ArtBearer::CREATURE].push_back(ArtifactPosition::CREATURE_SLOT);
+		};
+		makeItCreatureArt(141);
+		makeItCreatureArt(142);
+		makeItCreatureArt(143);
+		makeItCreatureArt(156);
 		giveArtBonus(141, Bonus::STACK_HEALTH, +400, -1, Bonus::PERCENT_TO_BASE); //Magic Wans
 		giveArtBonus(142, Bonus::STACK_HEALTH, +400, -1, Bonus::PERCENT_TO_BASE); //Tower Arrow
 		giveArtBonus(143, Bonus::STACK_HEALTH, +400, -1, Bonus::PERCENT_TO_BASE); //Monster's Power
@@ -910,11 +920,11 @@ void CArtifactInstance::init()
 	setNodeType(ARTIFACT_INSTANCE);
 }
 
-int CArtifactInstance::firstAvailableSlot(const CGHeroInstance *h) const
+int CArtifactInstance::firstAvailableSlot(const CArtifactSet *h) const
 {
-	BOOST_FOREACH(ui16 slot, artType->possibleSlots)
+	BOOST_FOREACH(ui16 slot, artType->possibleSlots[h->bearerType()])
 	{
-		if(canBePutAt(ArtifactLocation(h, slot))) //if(artType->fitsAt(h->artifWorn, slot))
+		if(canBePutAt(h, slot)) //if(artType->fitsAt(h->artifWorn, slot))
 		{
 			//we've found a free suitable slot.
 			return slot;
@@ -925,7 +935,7 @@ int CArtifactInstance::firstAvailableSlot(const CGHeroInstance *h) const
 	return firstBackpackSlot(h);
 }
 
-int CArtifactInstance::firstBackpackSlot(const CGHeroInstance *h) const
+int CArtifactInstance::firstBackpackSlot(const CArtifactSet *h) const
 {
 	if(!artType->isBig()) //discard big artifact
 		return GameConstants::BACKPACK_START + h->artifactsInBackpack.size();
@@ -935,60 +945,51 @@ int CArtifactInstance::firstBackpackSlot(const CGHeroInstance *h) const
 
 bool CArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
 {
-	if (al.hero)
-	{
-		if(al.slot >= GameConstants::BACKPACK_START)
-		{
-			if(artType->isBig())
-				return false;
-		
-			//TODO backpack limit
-			return true;
-		}
+	return canBePutAt(al.getHolderArtSet(), al.slot, assumeDestRemoved);
+}
 
-		if(!vstd::contains(artType->possibleSlots, al.slot))
+bool CArtifactInstance::canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved /*= false*/) const
+{
+	if(slot >= GameConstants::BACKPACK_START)
+	{
+		if(artType->isBig())
 			return false;
 
-		return al.hero->isPositionFree(al.slot, assumeDestRemoved);
+		//TODO backpack limit
+		return true;
 	}
-	else
+
+	if(!vstd::contains(artType->possibleSlots[artSet->bearerType()], slot))
 		return false;
+
+	return artSet->isPositionFree(slot, assumeDestRemoved);
 }
 
-void CArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
+void CArtifactInstance::putAt(ArtifactLocation &al)
 {
-	assert(canBePutAt(ArtifactLocation(h, slot)));
+	assert(canBePutAt(al));
 
-	h->setNewArtSlot(slot, this, false);
-	if(slot < GameConstants::BACKPACK_START)
-		h->attachTo(this);
+	al.getHolderArtSet()->setNewArtSlot(al.slot, this, false);
+	if(al.slot < GameConstants::BACKPACK_START)
+		al.getHolderNode()->attachTo(this);
 }
 
-void CArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)
+void CArtifactInstance::removeFrom(ArtifactLocation &al)
 {
-	assert(h->CArtifactSet::getArt(slot) == this);
-	h->eraseArtSlot(slot);
-	if(slot < GameConstants::BACKPACK_START)
-		h->detachFrom(this);
+	assert(al.getHolderArtSet()->getArt(al.slot) == this);
+	al.getHolderArtSet()->eraseArtSlot(al.slot);
+	if(al.slot < GameConstants::BACKPACK_START)
+		al.getHolderNode()->detachFrom(this);
 
 	//TODO delete me?
 }
 
-void CArtifactInstance::putAt(CStackInstance *s, ui16 slot)
-{
-	tlog2 <<"Hero artifacts shouldn't be put on creatures!\n";
-}
-void CArtifactInstance::removeFrom(CStackInstance *s, ui16 slot)
-{
-	tlog2 <<"Strange, we try to remove hero artifact from CStackInstance\n";
-}
-
 bool CArtifactInstance::canBeDisassembled() const
 {
 	return artType->constituents && artType->constituentOf->size();
 }
 
-std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CGHeroInstance *h) const
+std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet *h) const
 {
 	std::vector<const CArtifact *> ret;
 	if(!artType->constituentOf //not a part of combined artifact
@@ -1019,30 +1020,14 @@ std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CG
 
 void CArtifactInstance::move(ArtifactLocation &src, ArtifactLocation &dst)
 {
-	if (src.hero)
-		removeFrom(src.hero, src.slot);
-	else if (src.stack)
-		removeFrom(src.stack, src.slot);
-	else
-		tlog1 << "No source for moved artifact found!\n";
-
-	if (dst.hero)
-		putAt(dst.hero, dst.slot);
-	else if (dst.stack)
-		putAt(dst.stack, dst.slot);
-	else
-		tlog1 << "No destination for moved artifact found!\n";
+	removeFrom(src);
+	putAt(dst);
 }
 
 CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
 {
 	if(!Art->constituents)
-	{
-		 if (vstd::contains(VLC->arth->creatureArtifacts, Art->id))
-			 return new CCreatureArtifactInstance(Art);
-		 else
-			 return new CArtifactInstance(Art);
-	}
+		return new CArtifactInstance(Art);
 	else
 	{
 		CCombinedArtifactInstance * ret = new CCombinedArtifactInstance(Art);
@@ -1077,12 +1062,12 @@ bool CArtifactInstance::isPart(const CArtifactInstance *supposedPart) const
 	return supposedPart == this;
 }
 
-bool CCombinedArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
+bool CCombinedArtifactInstance::canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved /*= false*/) const 
 {
-	bool canMainArtifactBePlaced = CArtifactInstance::canBePutAt(al, assumeDestRemoved);
+	bool canMainArtifactBePlaced = CArtifactInstance::canBePutAt(artSet, slot, assumeDestRemoved);
 	if(!canMainArtifactBePlaced)
 		return false; //no is no...
-	if(al.slot >= GameConstants::BACKPACK_START)
+	if(slot >= GameConstants::BACKPACK_START)
 		return true; //we can always remove combined art to the backapck
 
 
@@ -1093,16 +1078,16 @@ bool CCombinedArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assu
 	//so we remove from the list all constituents that are already present on dst hero in the form of locks
 	BOOST_FOREACH(const ConstituentInfo &constituent, constituentsInfo)
 	{
-		if(constituent.art == al.hero->getArt(constituent.slot, false)) //no need to worry about locked constituent
+		if(constituent.art == artSet->getArt(constituent.slot, false)) //no need to worry about locked constituent
 			constituentsToBePlaced -= constituent;
 	}
-	
+
 	//we iterate over all active slots and check if constituents fits them
 	for (int i = 0; i < GameConstants::BACKPACK_START; i++)
 	{
 		for(std::vector<ConstituentInfo>::iterator art = constituentsToBePlaced.begin(); art != constituentsToBePlaced.end(); art++)
 		{
-			if(art->art->canBePutAt(ArtifactLocation(al.hero, i), i == al.slot)) // i == al.slot because we can remove already worn artifact only from that slot  that is our main destination
+			if(art->art->canBePutAt(artSet, i, i == slot)) // i == al.slot because we can remove already worn artifact only from that slot  that is our main destination
 			{
 				constituentsToBePlaced.erase(art);
 				break;
@@ -1146,31 +1131,35 @@ void CCombinedArtifactInstance::addAsConstituent(CArtifactInstance *art, int slo
 	attachTo(art);
 }
 
-void CCombinedArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
+void CCombinedArtifactInstance::putAt(ArtifactLocation &al)
 {
-	if(slot >= GameConstants::BACKPACK_START)
+	if(al.slot >= GameConstants::BACKPACK_START)
 	{
-		CArtifactInstance::putAt(h, slot);
+		CArtifactInstance::putAt(al);
 		BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
 			ci.slot = -1;
 	}
 	else
 	{
-		CArtifactInstance *mainConstituent = figureMainConstituent(slot); //it'll be replaced with combined artifact, not a lock
-		CArtifactInstance::putAt(h, slot); //puts combined art (this)
+		CArtifactInstance *mainConstituent = figureMainConstituent(al); //it'll be replaced with combined artifact, not a lock
+		CArtifactInstance::putAt(al); //puts combined art (this)
 
 		BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
 		{
 			if(ci.art != mainConstituent)
 			{
+				const ArtifactLocation suggestedPos(al.artHolder, ci.slot);
+				const bool inActiveSlot = vstd::isbetween(ci.slot, 0, GameConstants::BACKPACK_START);
+				const bool suggestedPosValid = ci.art->canBePutAt(suggestedPos);
+
 				int pos = -1;
-				if(vstd::isbetween(ci.slot, 0, GameConstants::BACKPACK_START)  &&  ci.art->canBePutAt(ArtifactLocation(h, ci.slot))) //there is a valid suggestion where to place lock 
+				if(inActiveSlot  &&  suggestedPosValid) //there is a valid suggestion where to place lock 
 					pos = ci.slot;
 				else
-					ci.slot = pos = ci.art->firstAvailableSlot(h);
+					ci.slot = pos = ci.art->firstAvailableSlot(al.getHolderArtSet());
 
 				assert(pos < GameConstants::BACKPACK_START);
-				h->setNewArtSlot(pos, ci.art, true); //sets as lock
+				al.getHolderArtSet()->setNewArtSlot(pos, ci.art, true); //sets as lock
 			}
 			else
 			{
@@ -1180,11 +1169,11 @@ void CCombinedArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
 	}
 }
 
-void CCombinedArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)
+void CCombinedArtifactInstance::removeFrom(ArtifactLocation &al)
 {
-	if(slot >= GameConstants::BACKPACK_START)
+	if(al.slot >= GameConstants::BACKPACK_START)
 	{
-		CArtifactInstance::removeFrom(h, slot);
+		CArtifactInstance::removeFrom(al);
 	}
 	else
 	{
@@ -1192,30 +1181,30 @@ void CCombinedArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)
 		{
 			if(ci.slot >= 0)
 			{
-				h->eraseArtSlot(ci.slot);
+				al.getHolderArtSet()->eraseArtSlot(ci.slot);
 				ci.slot = -1;
 			}
 			else
 			{
 				//main constituent
-				CArtifactInstance::removeFrom(h, slot);
+				CArtifactInstance::removeFrom(al);
 			}
 		}
 	}
 }
 
-CArtifactInstance * CCombinedArtifactInstance::figureMainConstituent(ui16 slot)
+CArtifactInstance * CCombinedArtifactInstance::figureMainConstituent(const ArtifactLocation &al)
 {
 	CArtifactInstance *mainConstituent = NULL; //it'll be replaced with combined artifact, not a lock
 	BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
-		if(ci.slot == slot)
+		if(ci.slot == al.slot)
 			mainConstituent = ci.art;
 
 	if(!mainConstituent)
 	{
 		BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
 		{
-			if(vstd::contains(ci.art->artType->possibleSlots, slot))
+			if(vstd::contains(ci.art->artType->possibleSlots[al.getHolderArtSet()->bearerType()], al.slot))
 			{
 				mainConstituent = ci.art;
 			}
@@ -1255,58 +1244,8 @@ bool CCombinedArtifactInstance::ConstituentInfo::operator==(const ConstituentInf
 {
 	return art == rhs.art && slot == rhs.slot;
 }
-CCreatureArtifactInstance::CCreatureArtifactInstance()
-{
-	init();
-}
-
-CCreatureArtifactInstance::CCreatureArtifactInstance(CArtifact *Art)
-{
-	init();
-	setType(Art);
-}
-
-bool CCreatureArtifactInstance::isPart(const CArtifactInstance *supposedPart) const
-{
-	return false; //TODO: any other proposals?
-}
-
-std::string CCreatureArtifactInstance::nodeName() const
-{
-	return "Creature artifact instance of " + (artType ? artType->Name() : std::string("uninitialized")) + " type";
-}
 
-bool CCreatureArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
-{
-	if (al.stack)
-	{
-		return al.stack->isPositionFree(al.slot, assumeDestRemoved);
-	}
-	else if(al.slot >= GameConstants::BACKPACK_START)
-	{	//TODO backpack limit?
-		return true;
-	}
-	return false; //hero can't wear creature art
-}
-
-void CCreatureArtifactInstance::putAt(CStackInstance *s, ui16 slot)
-{
-	assert(canBePutAt(ArtifactLocation(s, slot)));
-
-	s->setNewArtSlot(slot, this, false);
-	if(slot == GameConstants::CREATURE_ART)
-		s->attachTo(this);
-}
-
-void CCreatureArtifactInstance::removeFrom(CStackInstance *s, ui16 slot)
-{
-	assert(s->CCreatureArtifactSet::getArt(slot) == this);
-	s->eraseArtSlot(slot);
-	if(slot == GameConstants::CREATURE_ART) //we remove worn artifact
-		s->detachFrom(this);
-}
-
-const CArtifactInstance* IArtifactSetBase::getArt(ui16 pos, bool excludeLocked) const
+const CArtifactInstance* CArtifactSet::getArt(ui16 pos, bool excludeLocked /*= true*/) const
 {
 	if(const ArtSlotInfo *si = getSlot(pos))
 	{
@@ -1317,29 +1256,9 @@ const CArtifactInstance* IArtifactSetBase::getArt(ui16 pos, bool excludeLocked)
 	return NULL;
 }
 
-bool IArtifactSetBase::hasArt(ui32 aid, bool onlyWorn) const
+CArtifactInstance* CArtifactSet::getArt(ui16 pos, bool excludeLocked /*= true*/)
 {
-	return getArtPos(aid, onlyWorn) != -1;
-}
-
-bool IArtifactSetBase::isPositionFree(ui16 pos, bool onlyLockCheck) const
-{
-	if(const ArtSlotInfo *s = getSlot(pos))
-		return (onlyLockCheck || !s->artifact) && !s->locked;
-
-	return true; //no slot means not used
-}
-
-void IArtifactSetBase::setNewArtSlot(ui16 slot, CArtifactInstance *art, bool locked)
-{
-	ArtSlotInfo &asi = retreiveNewArtSlot(slot);
-	asi.artifact = art;
-	asi.locked = locked;
-}
-
-CArtifactInstance* IArtifactSetBase::getArt(ui16 pos, bool excludeLocked /*= true*/)
-{
-	return const_cast<CArtifactInstance*>((const_cast<const IArtifactSetBase*>(this))->getArt(pos, excludeLocked));
+	return const_cast<CArtifactInstance*>((const_cast<const CArtifactSet*>(this))->getArt(pos, excludeLocked));
 }
 
 si32 CArtifactSet::getArtPos(int aid, bool onlyWorn /*= true*/) const
@@ -1384,6 +1303,11 @@ const CArtifactInstance * CArtifactSet::getArtByInstanceId(int artInstId) const
 	return NULL;
 }
 
+bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/) const
+{
+	return getArtPos(aid, onlyWorn) != -1;
+}
+
 const ArtSlotInfo * CArtifactSet::getSlot(ui16 pos) const
 {
 	if(vstd::contains(artifactsWorn, pos))
@@ -1400,6 +1324,14 @@ const ArtSlotInfo * CArtifactSet::getSlot(ui16 pos) const
 	return NULL;
 }
 
+bool CArtifactSet::isPositionFree(ui16 pos, bool onlyLockCheck /*= false*/) const
+{
+	if(const ArtSlotInfo *s = getSlot(pos))
+		return (onlyLockCheck || !s->artifact) && !s->locked;
+
+	return true; //no slot means not used
+}
+
 si32 CArtifactSet::getArtTypeId(ui16 pos) const
 {
 	const CArtifactInstance * const a = getArt(pos);
@@ -1426,6 +1358,13 @@ ArtSlotInfo & CArtifactSet::retreiveNewArtSlot(ui16 slot)
 	return ret;
 }
 
+void CArtifactSet::setNewArtSlot(ui16 slot, CArtifactInstance *art, bool locked)
+{
+	ArtSlotInfo &asi = retreiveNewArtSlot(slot);
+	asi.artifact = art;
+	asi.locked = locked;
+}
+
 void CArtifactSet::eraseArtSlot(ui16 slot)
 {
 	if(slot < GameConstants::BACKPACK_START)
@@ -1439,88 +1378,9 @@ void CArtifactSet::eraseArtSlot(ui16 slot)
 	}
 }
 
-ArtSlotInfo & CCreatureArtifactSet::retreiveNewArtSlot(ui16 slot)
+void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
 {
-	ArtSlotInfo &ret = slot == GameConstants::CREATURE_ART
-		? activeArtifact
-		: *artifactsInBackpack.insert(artifactsInBackpack.begin() + (slot - GameConstants::CREATURE_ART), ArtSlotInfo());
-
-	return ret;
-}
-
-void CCreatureArtifactSet::eraseArtSlot(ui16 slot)
-{
-	if(slot == GameConstants::CREATURE_ART)
-	{
-		activeArtifact.artifact = NULL; //hmm?
-	}
-	else
-	{
-		slot -= 1;
-		artifactsInBackpack.erase(artifactsInBackpack.begin() + slot);
-	}
-}
-
-const ArtSlotInfo * CCreatureArtifactSet::getSlot(ui16 pos) const
-{
-	if (pos == GameConstants::CREATURE_ART)
-		return &activeArtifact;
-	else if(pos > GameConstants::CREATURE_ART)
-	{
-		int backpackPos = (int)pos - 1;
-		if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
-			return NULL;
-		else
-			return &artifactsInBackpack[backpackPos];
-	}
-	return NULL;
-}
-
-si32 CCreatureArtifactSet::getArtPos(int aid, bool onlyWorn) const
-{
-	if (aid == activeArtifact.artifact->artType->id )
-		return GameConstants::CREATURE_ART;
-
-	for(int i = 0; i < artifactsInBackpack.size(); i++)
-	{
-		if(artifactsInBackpack[i].artifact->artType->id == aid)
-			return i + 1;
-	}
-
-	return -1;
-}
-
-si32 CCreatureArtifactSet::getArtPos(const CArtifactInstance *art) const
-{
-	if (activeArtifact.artifact == art)
-		return GameConstants::CREATURE_ART;
-
-	for(int i = 0; i < artifactsInBackpack.size(); i++)
-		if(artifactsInBackpack[i].artifact == art)
-			return i + 1;
-
-	return -1;
-}
-
-const CArtifactInstance * CCreatureArtifactSet::getArtByInstanceId(int artInstId) const
-{
-	if (activeArtifact.artifact->id == artInstId)
-		return activeArtifact.artifact;
-
-	for(int i = 0; i < artifactsInBackpack.size(); i++)
-		if(artifactsInBackpack[i].artifact->id == artInstId)
-			return artifactsInBackpack[i].artifact;
-
-	return NULL;
-}
-
-si32 CCreatureArtifactSet::getArtTypeId(ui16 pos) const
-{
-	const CArtifactInstance * const a = getArt(pos);
-	if(!a)
-	{
-		tlog2 << "Stack has no artifact at " << pos << " (getArtTypeId)\n";
-		return -1;
-	}
-	return a->artType->id;
-}
+	for(bmap<ui16, ArtSlotInfo>::iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
+		if(i->second.artifact && !i->second.locked)
+			node->attachTo(i->second.artifact);
+}

+ 37 - 88
lib/CArtHandler.h

@@ -16,9 +16,8 @@
 class CDefHandler;
 class CArtifact;
 class CGHeroInstance;
-class CStackInstance;
-//class CCreatureArtifactSet;
 struct ArtifactLocation;
+class CArtifactSet;
 
 namespace ArtifactPosition
 {
@@ -27,7 +26,17 @@ namespace ArtifactPosition
 		PRE_FIRST = -1, 
 		HEAD, SHOULDERS, NECK, RIGHT_HAND, LEFT_HAND, TORSO, RIGHT_RING, LEFT_RING, FEET, MISC1, MISC2, MISC3, MISC4,
 		MACH1, MACH2, MACH3, MACH4, SPELLBOOK, MISC5, 
-		AFTER_LAST
+		AFTER_LAST,
+		//cres
+		CREATURE_SLOT = 0
+	};
+}
+
+namespace ArtBearer
+{
+	enum
+	{
+		HERO, CREATURE
 	};
 }
 
@@ -45,7 +54,7 @@ public:
 	std::string nodeName() const OVERRIDE;
 
 	ui32 price;
-	std::vector<ui16> possibleSlots; //ids of slots where artifact can be placed
+	bmap<ui8, std::vector<ui16> > possibleSlots; //Bearer Type => ids of slots where artifact can be placed
 	std::vector<ui32> * constituents; // Artifacts IDs a combined artifact consists of, or NULL.
 	std::vector<ui32> * constituentOf; // Reverse map of constituents.
 	EartClass aClass;
@@ -77,23 +86,22 @@ public:
 
 	//CArtifactInstance(int aid);
 
-	virtual std::string nodeName() const OVERRIDE;
+	std::string nodeName() const OVERRIDE;
 	void deserializationFix();
 	void setType(CArtifact *Art);
 
-	int firstAvailableSlot(const CGHeroInstance *h) const;
-	int firstBackpackSlot(const CGHeroInstance *h) const;
+	int firstAvailableSlot(const CArtifactSet *h) const;
+	int firstBackpackSlot(const CArtifactSet *h) const;
 	int getGivenSpellID() const; //to be used with scrolls (and similar arts), -1 if none
 
-	virtual bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const;
+	virtual bool canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved = false) const;
+	bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const;  //forwards to the above one
 	virtual bool canBeDisassembled() const;
-	virtual void putAt(CGHeroInstance *h, ui16 slot);
-	virtual void removeFrom(CGHeroInstance *h, ui16 slot);
-	virtual void putAt(CStackInstance *s, ui16 slot);
-	virtual void removeFrom(CStackInstance *s, ui16 slot);
+	virtual void putAt(ArtifactLocation &al);
+	virtual void removeFrom(ArtifactLocation &al);
 	virtual bool isPart(const CArtifactInstance *supposedPart) const; //checks if this a part of this artifact: artifact instance is a part of itself, additionally truth is returned for consituents of combined arts
 
-	std::vector<const CArtifact *> assemblyPossibilities(const CGHeroInstance *h) const;
+	std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet *h) const;
 	void move(ArtifactLocation &src, ArtifactLocation &dst);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -127,15 +135,15 @@ public:
 
 	std::vector<ConstituentInfo> constituentsInfo;
 
-	bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const OVERRIDE;
+	bool canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved = false) const OVERRIDE;
 	bool canBeDisassembled() const OVERRIDE;
-	void putAt(CGHeroInstance *h, ui16 slot) OVERRIDE;
-	void removeFrom(CGHeroInstance *h, ui16 slot) OVERRIDE;
+	void putAt(ArtifactLocation &al) OVERRIDE;
+	void removeFrom(ArtifactLocation &al) OVERRIDE;
 	bool isPart(const CArtifactInstance *supposedPart) const OVERRIDE;
 
 	void createConstituents();
 	void addAsConstituent(CArtifactInstance *art, int slot);
-	CArtifactInstance *figureMainConstituent(ui16 slot); //main constituent is replcaed with us (combined art), not lock
+	CArtifactInstance *figureMainConstituent(const ArtifactLocation &al); //main constituent is replcaed with us (combined art), not lock
 
 	CCombinedArtifactInstance();
 
@@ -151,30 +159,6 @@ public:
 	}
 };
 
-class DLL_LINKAGE CCreatureArtifactInstance : public CArtifactInstance
-{
-	CCreatureArtifactInstance(CArtifact *Art);
-public:
-
-	bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const OVERRIDE;
-	void putAt(CStackInstance *s, ui16 slot) OVERRIDE;
-	void removeFrom(CStackInstance *s, ui16 slot) OVERRIDE;
-	bool isPart(const CArtifactInstance *supposedPart) const OVERRIDE;
-
-	std::string nodeName() const OVERRIDE;
-
-	CCreatureArtifactInstance();
-
-	//void deserializationFix(); ..inherit from CArtifactInstance
-
-	friend class CArtifactInstance;
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & static_cast<CArtifactInstance&>(*this);
-		//BONUS_TREE_DESERIALIZATION_FIX
-	}
-};
-
 // class DLL_LINKAGE IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner
 // { //used only for dynamic cast :P
 // public:
@@ -240,7 +224,7 @@ public:
 	std::vector< ConstTransitivePtr<CArtifact> > artifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
-	std::set<ui32> creatureArtifacts; // can be held by Stacks
+	//std::map<ui32, ui8> modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
@@ -263,7 +247,6 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & artifacts & allowedArtifacts & treasures & minors & majors & relics;
-		h & creatureArtifacts;
 		//if(!h.saving) sortArts();
 	}
 };
@@ -283,67 +266,33 @@ struct DLL_LINKAGE ArtSlotInfo
 	}
 };
 
-class DLL_LINKAGE IArtifactSetBase 
-{ ///artifacts container
-public:
-	virtual void setNewArtSlot(ui16 slot, CArtifactInstance *art, bool locked);
-	virtual const CArtifactInstance* getArt(ui16 pos, bool excludeLocked = true) const;
-	virtual CArtifactInstance* getArt(ui16 pos, bool excludeLocked = true); //NULL - no artifact
-	virtual bool hasArt(ui32 aid, bool onlyWorn = false) const;
-	virtual bool isPositionFree(ui16 pos, bool onlyLockCheck = false) const;
-
-	virtual ArtSlotInfo &retreiveNewArtSlot(ui16 slot)=0;
-	virtual void eraseArtSlot(ui16 slot)=0;
-
-	virtual const ArtSlotInfo *getSlot(ui16 pos) const=0;
-	virtual si32 getArtPos(int aid, bool onlyWorn = true) const=0; //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)
-	virtual si32 getArtPos(const CArtifactInstance *art) const=0;
-	virtual const CArtifactInstance *getArtByInstanceId(int artInstId) const=0;
-	virtual si32 getArtTypeId(ui16 pos) const=0;
-};
-
-class DLL_LINKAGE CArtifactSet : public IArtifactSetBase
-{ ///hero artifacts
+class DLL_LINKAGE CArtifactSet
+{
 public:
 	std::vector<ArtSlotInfo> artifactsInBackpack; //hero's artifacts from bag
 	bmap<ui16, ArtSlotInfo> artifactsWorn; //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
 
 	ArtSlotInfo &retreiveNewArtSlot(ui16 slot);
+	void setNewArtSlot(ui16 slot, CArtifactInstance *art, bool locked);
 	void eraseArtSlot(ui16 slot);
 
 	const ArtSlotInfo *getSlot(ui16 pos) const;
-	si32 getArtPos(int aid, bool onlyWorn = true) const;
+	const CArtifactInstance* getArt(ui16 pos, bool excludeLocked = true) const; //NULL - no artifact
+	CArtifactInstance* getArt(ui16 pos, bool excludeLocked = true); //NULL - no artifact
+	si32 getArtPos(int aid, bool onlyWorn = true) 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(const CArtifactInstance *art) const;
 	const CArtifactInstance *getArtByInstanceId(int artInstId) const;
+	bool hasArt(ui32 aid, bool onlyWorn = false) const; //checks if hero possess artifact of given id (either in backack or worn)
+	bool isPositionFree(ui16 pos, bool onlyLockCheck = false) const;
 	si32 getArtTypeId(ui16 pos) const;
 
+	virtual ui8 bearerType() const = 0;
 	virtual ~CArtifactSet();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & artifactsInBackpack & artifactsWorn;
 	}
-};
-
-class DLL_LINKAGE CCreatureArtifactSet : public IArtifactSetBase
-{ ///creature artifacts
-public:
-	std::vector<ArtSlotInfo> artifactsInBackpack; //artifacts carried by creature - 4 max (according to WoG)
-	ArtSlotInfo activeArtifact; //position 0 - GameConstants::CREATURE_ART
-
-	ArtSlotInfo &retreiveNewArtSlot(ui16 slot);
-	void eraseArtSlot(ui16 slot);
-
-	const ArtSlotInfo *getSlot(ui16 pos)const;
-	si32 getArtPos(int aid, bool onlyWorn = true) const;
-	si32 getArtPos(const CArtifactInstance *art) const;
-	const CArtifactInstance *getArtByInstanceId(int artInstId) const;
-	si32 getArtTypeId(ui16 pos) const;
-
-	virtual ~CCreatureArtifactSet(){};
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & artifactsInBackpack & activeArtifact;
-	}
+	
+	void artDeserializationFix(CBonusSystemNode *node);
 };

+ 6 - 15
lib/CCreatureSet.cpp

@@ -874,18 +874,6 @@ void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
 		attachTo(const_cast<CArmedInstance*>(_armyObj));
 	}
 }
-// void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*= NULL*/) const
-// {
-// 	out.insert(type);
-// 
-// 	if(source && source != this) //we should be root, if not - do not inherit anything
-// 		return;
-// 
-// 	if(armyObj)
-// 		out.insert(armyObj);
-// 	else
-// 		out.insert(&IObjectInterface::cb->gameState()->globalEffects);
-// }
 
 std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const
 {
@@ -930,9 +918,7 @@ void CStackInstance::deserializationFix()
 	const CArmedInstance *armyBackup = _armyObj;
 	_armyObj = NULL;
 	setArmyObj(armyBackup);
-
-	if(activeArtifact.artifact)
-		attachTo(activeArtifact.artifact);
+	artDeserializationFix(this);
 }
 
 int CStackInstance::getCreatureID() const
@@ -954,6 +940,11 @@ ui64 CStackInstance::getPower() const
 	return type->AIValue * count;
 }
 
+ui8 CStackInstance::bearerType() const
+{
+	return ArtBearer::CREATURE;
+}
+
 CStackBasicDescriptor::CStackBasicDescriptor()
 {
 	type = NULL;

+ 4 - 3
lib/CCreatureSet.h

@@ -26,7 +26,7 @@ public:
 	}
 };
 
-class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CCreatureArtifactSet
+class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CArtifactSet
 {
 	const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
 public:
@@ -39,7 +39,7 @@ public:
 	{
 		h & static_cast<CBonusSystemNode&>(*this);
 		h & static_cast<CStackBasicDescriptor&>(*this);
-		h & static_cast<CCreatureArtifactSet&>(*this);
+		h & static_cast<CArtifactSet&>(*this);
 		h & _armyObj & experience;
 		BONUS_TREE_DESERIALIZATION_FIX
 	}
@@ -67,7 +67,8 @@ public:
 	void setArmyObj(const CArmedInstance *ArmyObj);
 	void giveStackExp(expType exp);
 	bool valid(bool allowUnrandomized) const;
-	virtual std::string nodeName() const OVERRIDE;
+	ui8 bearerType() const OVERRIDE; //from CArtifactSet
+	virtual std::string nodeName() const OVERRIDE; //from CBonusSystemnode
 	void deserializationFix();
 };
 

+ 17 - 11
lib/CGameState.cpp

@@ -818,7 +818,7 @@ BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2],
 	return BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
 }
 
-void CGameState::init(StartInfo * si, ui32 checksum, int Seed, int expectedPostInitSeed /*= -1*/)
+void CGameState::init(StartInfo * si)
 {
 	struct HLP
 	{
@@ -852,7 +852,7 @@ void CGameState::init(StartInfo * si, ui32 checksum, int Seed, int expectedPostI
 				case 4: //spell scroll
 					{
 						CArtifactInstance * scroll = CArtifactInstance::createScroll(VLC->spellh->spells[curBonus.info2]);
-						scroll->putAt(hero, scroll->firstAvailableSlot(hero));
+						scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
 					}
 					break;
 				case 5: //prim skill
@@ -904,8 +904,8 @@ void CGameState::init(StartInfo * si, ui32 checksum, int Seed, int expectedPostI
 		}
 	};
 
-	seed = Seed;
-	ran.seed((boost::int32_t)seed);
+	tlog0 << "\tUsing random seed: "<< si->seedToBeUsed << std::endl;
+	ran.seed((boost::int32_t)si->seedToBeUsed);
 	scenarioOps = new StartInfo(*si);
 	initialOpts = new StartInfo(*si);
 	si = NULL;
@@ -986,16 +986,18 @@ void CGameState::init(StartInfo * si, ui32 checksum, int Seed, int expectedPostI
 
 
 	//tlog0 <<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl;
-	if(checksum)
+	tlog0 << "\tOur checksum for the map: "<< map->checksum << std::endl;
+	if(scenarioOps->mapfileChecksum)
 	{
-		tlog0 << "\tServer checksum for " << scenarioOps->mapname <<": "<< checksum << std::endl;
-		tlog0 << "\tOur checksum for the map: "<< map->checksum << std::endl;
-		if(map->checksum != checksum)
+		tlog0 << "\tServer checksum for " << scenarioOps->mapname <<": "<< scenarioOps->mapfileChecksum << std::endl;
+		if(map->checksum != scenarioOps->mapfileChecksum)
 		{
 			tlog1 << "Wrong map checksum!!!" << std::endl;
 			throw std::string("Wrong checksum");
 		}
 	}
+	else
+		scenarioOps->mapfileChecksum = map->checksum;
 
 	day = 0;
 	loadTownDInfos();
@@ -1576,10 +1578,14 @@ void CGameState::init(StartInfo * si, ui32 checksum, int Seed, int expectedPostI
 
 	map->checkForObjectives(); //needs to be run when all objects are properly placed
 
-	if(expectedPostInitSeed >= 0)
+	if(scenarioOps->seedPostInit > 0)
 	{
 		int actualSeed = ran();
-		assert(expectedPostInitSeed == actualSeed); //RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
+		assert(scenarioOps->seedPostInit == actualSeed); //RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
+	}
+	else
+	{
+		scenarioOps->seedPostInit = ran(); //store the post init "seed"
 	}
 }
 
@@ -2473,7 +2479,7 @@ void CGameState::giveHeroArtifact(CGHeroInstance *h, int aid)
 	 CArtifact * const artifact = VLC->arth->artifacts[aid]; //pointer to constant object
 	 CArtifactInstance *ai = CArtifactInstance::createNewArtifactInstance(artifact);
 	 map->addNewArtifactInstance(ai);
-	 ai->putAt(h, ai->firstAvailableSlot(h));
+	 ai->putAt(ArtifactLocation(h, ai->firstAvailableSlot(h)));
 }
 
 int3 CPath::startPos() const

+ 2 - 3
lib/CGameState.h

@@ -348,7 +348,6 @@ class DLL_LINKAGE CGameState : public CNonConstInfoCallback
 public:
 	ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
 	ConstTransitivePtr<CCampaignState> campaign;
-	ui32 seed;
 	ui8 currentPlayer; //ID of player currently having turn
 	ConstTransitivePtr<BattleInfo> curB; //current battle
 	ui32 day; //total number of days in game
@@ -374,7 +373,7 @@ public:
 
 	boost::shared_mutex *mx;
 
-	void init(StartInfo * si, ui32 checksum, int Seed, int expectedPostInitSeed = -1);
+	void init(StartInfo * si);
 	void loadTownDInfos();
 	void randomizeObject(CGObjectInstance *cur);
 	std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
@@ -413,7 +412,7 @@ public:
 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & scenarioOps & initialOpts & seed & currentPlayer & day & map & players & teams & hpool & globalEffects & campaign;
+		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects & campaign;
 		h & villages & forts & capitols;
 		if(!h.saving)
 		{

+ 7 - 6
lib/CObjectHandler.cpp

@@ -1473,7 +1473,7 @@ std::string CGHeroInstance::nodeName() const
 void CGHeroInstance::putArtifact(ui16 pos, CArtifactInstance *art)
 {
 	assert(!getArt(pos));
-	art->putAt(this, pos);
+	art->putAt(ArtifactLocation(this, pos));
 }
 
 void CGHeroInstance::putInBackpack(CArtifactInstance *art)
@@ -1488,11 +1488,7 @@ bool CGHeroInstance::hasSpellbook() const
 
 void CGHeroInstance::deserializationFix()
 {
-	for(bmap<ui16, ArtSlotInfo>::iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
-		if(i->second.artifact && !i->second.locked)
-			attachTo(i->second.artifact);
-
-	//attachTo(&speciality);
+	artDeserializationFix(this);
 }
 
 CBonusSystemNode * CGHeroInstance::whereShouldBeAttached(CGameState *gs)
@@ -1535,6 +1531,11 @@ CGHeroInstance::ECanDig CGHeroInstance::diggingStatus() const
 	}
 }
 
+ui8 CGHeroInstance::bearerType() const
+{
+	return ArtBearer::HERO;
+}
+
 void CGDwelling::initObj()
 {
 	switch(ID)

+ 3 - 1
lib/CObjectHandler.h

@@ -395,7 +395,9 @@ public:
 
 	CGHeroInstance();
 	virtual ~CGHeroInstance();
-
+	//////////////////////////////////////////////////////////////////////////
+	//
+	ui8 bearerType() const OVERRIDE;
 	//////////////////////////////////////////////////////////////////////////
 
 	virtual CBonusSystemNode *whereShouldBeAttached(CGameState *gs) OVERRIDE;

+ 3 - 0
lib/Connection.cpp

@@ -56,6 +56,8 @@ void CConnection::init()
 {
 	CISer<CConnection>::smartPointerSerialization = false;
 	COSer<CConnection>::smartPointerSerialization = false;
+	CISer<CConnection>::sendStackInstanceByIds = true;
+	COSer<CConnection>::sendStackInstanceByIds = true;
 	registerTypes(static_cast<CISer<CConnection>&>(*this));
 	registerTypes(static_cast<COSer<CConnection>&>(*this));
 #ifdef LIL_ENDIAN
@@ -382,6 +384,7 @@ CSerializer::~CSerializer()
 CSerializer::CSerializer()
 {
 	smartVectorMembersSerialization = false;
+	sendStackInstanceByIds = false;
 }
 
 

+ 124 - 3
lib/Connection.h

@@ -20,9 +20,10 @@
 
 #include "ConstTransitivePtr.h"
 
-const ui32 version = 731;
+const ui32 version = 732;
 class CConnection;
 class CGObjectInstance;
+class CStackInstance;
 class CGameState;
 class CCreature;
 class LibClasses;
@@ -246,6 +247,7 @@ public:
 	TTypeVecMap vectors; //entry must be a pointer to vector containing pointers to the objects of key type
 
 	bool smartVectorMembersSerialization;
+	bool sendStackInstanceByIds; 
 
 	CSerializer();
 	~CSerializer();
@@ -344,6 +346,63 @@ struct VectorisedTypeFor
 		>::type type;
 };
 
+template <typename Handler>
+struct VariantVisitorSaver : boost::static_visitor<>
+{
+	Handler &h;
+	VariantVisitorSaver(Handler &H):h(H)
+	{
+	}
+
+	template <typename T>
+	void operator()(const T &t)
+	{
+		h << t;
+	}
+};
+
+template<typename Ser,typename T>
+struct SaveIfStackInstance
+{
+	static bool invoke(Ser &s, const T &data)
+	{
+		return false;
+	}
+};
+template<typename Ser>
+struct SaveIfStackInstance<Ser, CStackInstance *>
+{
+	static bool invoke(Ser &s, const CStackInstance* const &data)
+	{
+		assert(data->armyObj);
+		TSlot slot = data->armyObj->findStack(data);
+		s << data->armyObj << slot;
+		return true;
+	}
+};
+template<typename Ser,typename T>
+struct LoadIfStackInstance
+{
+	static bool invoke(Ser &s, T &data)
+	{
+		return false;
+	}
+};
+template<typename Ser>
+struct LoadIfStackInstance<Ser, CStackInstance *>
+{
+	static bool invoke(Ser &s, CStackInstance* &data)
+	{
+		CArmedInstance *armedObj;
+		TSlot slot;
+		s >> armedObj >> slot;
+		assert(armedObj->hasStackAtSlot(slot));
+		data = armedObj->stacks[slot];
+		return true;
+	}
+};
+
+
 /// The class which manages saving objects.
 template <typename Serializer> class DLL_LINKAGE COSer : public CSaverBase
 {
@@ -424,6 +483,12 @@ public:
  			}
  		}
 
+		if(sendStackInstanceByIds)
+		{
+			const bool gotSaved = SaveIfStackInstance<Serializer,T>::invoke(*This(), data);
+			if(gotSaved)
+				return;
+		}
 
 		if(smartPointerSerialization)
 		{
@@ -552,6 +617,15 @@ public:
 		for(typename std::map<T1,T2>::const_iterator i=data.begin();i!=data.end();i++)
 			*this << i->first << i->second;
 	}
+	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+	void saveSerializable(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
+	{
+		si32 which = data.which();
+		*this << which;
+
+		VariantVisitorSaver<Serializer> visitor(*this->This());
+		boost::apply_visitor(visitor, data);
+	}
 };
 
 
@@ -663,8 +737,9 @@ public:
 	{
 		this->This()->read(&data,sizeof(data));
 	}
+
 	template <typename T>
-	void loadSerializable(T &data)
+	void loadSerializableBySerializeCall(T &data)
 	{
 		////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
 		typedef typename boost::remove_const<T>::type nonConstT;
@@ -672,6 +747,12 @@ public:
 		hlp.serialize(*this,myVersion);
 		//data.serialize(*this,myVersion);
 	}	
+
+	template <typename T>
+	void loadSerializable(T &data)
+	{
+		loadSerializableBySerializeCall(data);
+	}
 	template <typename T>
 	void loadArray(T &data)
 	{
@@ -706,6 +787,13 @@ public:
 			}
 		}
 
+		if(sendStackInstanceByIds)
+		{
+			bool gotLoaded = LoadIfStackInstance<Serializer,T>::invoke(*This(), data);
+			if(gotLoaded)
+				return;
+		}
+
 		ui32 pid = 0xffffffff; //pointer id (or maybe rather pointee id) 
 		if(smartPointerSerialization)
 		{
@@ -832,10 +920,43 @@ public:
 		data.resize(length);
 		this->This()->read((void*)data.c_str(),length);
 	}
+	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+	void loadSerializable(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
+	{
+		si32 which;
+		*this >> which;
+		if(which == 0)
+		{
+			T0 obj;
+			*this >> obj;
+			data = obj;
+		}
+		else if(which == 1)
+		{
+			T1 obj;
+			*this >> obj;
+			data = obj;
+		}
+		else
+			assert(0);
+		//TODO write more if needed, general solution would be much longer
+	}
+	void loadSerializable(CStackInstance *&s)
+	{
+		if(sendStackInstanceByIds)
+		{
+			CArmedInstance *armed;
+			TSlot slot;
+			*this >> armed >> slot;
+			assert(armed->hasStackAtSlot(slot));
+			s = armed->stacks[slot];
+		}
+		else
+			loadSerializableBySerializeCall(s);
+	}
 
 };
 
-
 class DLL_LINKAGE CSaveFile
 	: public COSer<CSaveFile>
 {

+ 5 - 1
lib/GameConstants.h

@@ -88,7 +88,6 @@ namespace GameConstants
 
 	const ui16 BACKPACK_START = 19;
 	const int ID_CATAPULT = 3, ID_LOCK = 145;
-	const ui16 CREATURE_ART = 0; //position in CCreatureArtifactSet
 
 	//game modules
 	const bool STACK_EXP = true;
@@ -98,6 +97,11 @@ namespace GameConstants
 }
 
 // Enum declarations
+namespace PrimarySkill
+{
+	enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
+}
+
 namespace EVictoryConditionType
 {
 	enum EVictoryConditionType { ARTIFACT, GATHERTROOP, GATHERRESOURCE, BUILDCITY, BUILDGRAIL, BEATHERO,

+ 1 - 6
lib/HeroBonus.h

@@ -1,7 +1,5 @@
 #pragma once
 
-
-#include <boost/range.hpp>
 #include "GameConstants.h"
 
 /*
@@ -31,10 +29,7 @@ typedef std::set<const CBonusSystemNode*> TCNodes;
 typedef std::vector<CBonusSystemNode *> TNodesVector;
 typedef boost::function<bool(const Bonus*)> CSelector;
 
-namespace PrimarySkill
-{
-	enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
-}
+
 
 #define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();
 

+ 1 - 1
lib/IGameCallback.h

@@ -307,7 +307,7 @@ public:
 	virtual void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, int pos) = 0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
 	virtual void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) = 0;
 	virtual void removeArtifact(const ArtifactLocation &al) = 0;
-	virtual void moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0;
+	virtual bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0;
 
 	virtual void showCompInfo(ShowInInfobox * comp)=0;
 	virtual void heroVisitCastle(int obj, int heroID)=0;

+ 31 - 20
lib/NetPacks.h

@@ -845,34 +845,52 @@ typedef si32 TArtPos;
 
 struct ArtifactLocation
 {
-	ConstTransitivePtr<CGHeroInstance> hero;
-	ConstTransitivePtr<CStackInstance> stack;
+	typedef boost::variant<ConstTransitivePtr<CGHeroInstance>, ConstTransitivePtr<CStackInstance> > TArtHolder;
+
+	TArtHolder artHolder;
 	TArtPos slot;
 
 	ArtifactLocation()
 	{
+		artHolder = ConstTransitivePtr<CGHeroInstance>();
 		slot = -1;
-		stack = NULL;
-		hero = NULL;
 	}
-	ArtifactLocation(const CGHeroInstance *Hero, TArtPos Slot)
+	template <typename T>
+	ArtifactLocation(const T *ArtHolder, TArtPos Slot)
 	{
-		hero = const_cast<CGHeroInstance*>(Hero); //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
-		stack = NULL;
+
+		artHolder = const_cast<T*>(ArtHolder); //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
 		slot = Slot;
 	}
-	ArtifactLocation(const CStackInstance *Stack, TArtPos Slot)
+	ArtifactLocation(TArtHolder ArtHolder, TArtPos Slot)
 	{
-		stack = const_cast<CStackInstance*>(Stack); //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
-		hero = NULL;
+		artHolder = ArtHolder;
 		slot = Slot;
 	}
+
+	template <typename T>
+	bool isHolder(const T *t) const
+	{
+		if(auto ptrToT = boost::get<ConstTransitivePtr<T> >(&artHolder))
+		{
+			return ptrToT->get() == t;
+		}
+		return false;
+	}
+
+	DLL_LINKAGE const CArmedInstance *relatedObj() const; //hero or the stack owner
+	DLL_LINKAGE int owningPlayer() const;
+	DLL_LINKAGE CArtifactSet *getHolderArtSet();
+	DLL_LINKAGE CBonusSystemNode *getHolderNode();
+	DLL_LINKAGE const CArtifactSet *getHolderArtSet() const;
+	DLL_LINKAGE const CBonusSystemNode *getHolderNode() const;
+
 	DLL_LINKAGE const CArtifactInstance *getArt() const;
 	DLL_LINKAGE CArtifactInstance *getArt();
 	DLL_LINKAGE const ArtSlotInfo *getSlot() const;
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hero & stack & slot;
+		h & artHolder & slot;
 	}
 };
 
@@ -1764,20 +1782,13 @@ struct GarrisonHeroSwap : public CPackForServer
 struct ExchangeArtifacts : public CPackForServer
 //TODO: allow exchange between heroes, stacks and commanders
 {
+	ArtifactLocation src, dst;
 	ExchangeArtifacts(){};
-	ExchangeArtifacts(si32 H1, si32 H2, ui16 S1, ui16 S2)
-		:hid1(H1),hid2(H2),slot1(S1),slot2(S2)
-	{
-		s1 = s2 = StackLocation(NULL,0);
-	};
-	si32 hid1, hid2;
-	StackLocation s1, s2; //for creature stacks
-	ui16 slot1, slot2;
 
 	bool applyGh(CGameHandler *gh);
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hid1 & hid2 & s1 & s2 & slot1 & slot2;
+		h & src & dst;
 	}
 };
 

+ 79 - 19
lib/NetPacksLib.cpp

@@ -536,6 +536,48 @@ DLL_LINKAGE const CStackInstance * StackLocation::getStack()
 	return &army->getStack(slot);
 }
 
+struct ObjectRetriever : boost::static_visitor<const CArmedInstance *>
+{
+	const CArmedInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
+	{
+		return h;
+	}
+	const CArmedInstance * operator()(const ConstTransitivePtr<CStackInstance> &s) const
+	{
+		return s->armyObj;
+	}
+};
+template <typename T>
+struct GetBase : boost::static_visitor<T*>
+{
+	template <typename TArg>
+	T * operator()(TArg &arg) const
+	{
+		return arg;
+	}
+};
+
+DLL_LINKAGE const CArmedInstance * ArtifactLocation::relatedObj() const
+{
+	return boost::apply_visitor(ObjectRetriever(), artHolder);
+}
+
+DLL_LINKAGE int ArtifactLocation::owningPlayer() const
+{
+	auto obj = relatedObj();
+	return obj ? obj->tempOwner : GameConstants::NEUTRAL_PLAYER;
+}
+
+DLL_LINKAGE CArtifactSet *ArtifactLocation::getHolderArtSet()
+{
+	return boost::apply_visitor(GetBase<CArtifactSet>(), artHolder);
+}
+
+DLL_LINKAGE CBonusSystemNode *ArtifactLocation::getHolderNode()
+{
+	return boost::apply_visitor(GetBase<CBonusSystemNode>(), artHolder);
+}
+
 DLL_LINKAGE const CArtifactInstance *ArtifactLocation::getArt() const
 {
 	const ArtSlotInfo *s = getSlot();
@@ -552,6 +594,18 @@ DLL_LINKAGE const CArtifactInstance *ArtifactLocation::getArt() const
 	return NULL;
 }
 
+DLL_LINKAGE const CArtifactSet * ArtifactLocation::getHolderArtSet() const
+{
+	ArtifactLocation *t = const_cast<ArtifactLocation*>(this);
+	return t->getHolderArtSet();
+}
+
+DLL_LINKAGE const CBonusSystemNode * ArtifactLocation::getHolderNode() const
+{
+	ArtifactLocation *t = const_cast<ArtifactLocation*>(this);
+	return t->getHolderNode();
+}
+
 DLL_LINKAGE CArtifactInstance *ArtifactLocation::getArt()
 {
 	const ArtifactLocation *t = this;
@@ -560,11 +614,7 @@ DLL_LINKAGE CArtifactInstance *ArtifactLocation::getArt()
 
 DLL_LINKAGE const ArtSlotInfo *ArtifactLocation::getSlot() const
 {
-	if (hero)
-		return hero->getSlot(slot);
-	if (stack)
-		return stack->getSlot(slot);
-	return NULL;
+	return getHolderArtSet()->getSlot(slot);
 }
 
 DLL_LINKAGE void ChangeStackCount::applyGs( CGameState *gs )
@@ -662,14 +712,15 @@ DLL_LINKAGE void RebalanceStacks::applyGs( CGameState *gs )
 DLL_LINKAGE void PutArtifact::applyGs( CGameState *gs )
 {
 	assert(art->canBePutAt(al));
-	al.hero->putArtifact(al.slot, art);
+	art->putAt(al);
+	//al.hero->putArtifact(al.slot, art);
 }
 
 DLL_LINKAGE void EraseArtifact::applyGs( CGameState *gs )
 {
 	CArtifactInstance *a = al.getArt();
 	assert(a);
-	a->removeFrom(al.hero, al.slot);
+	a->removeFrom(al);
 }
 
 DLL_LINKAGE void MoveArtifact::applyGs( CGameState *gs )
@@ -681,49 +732,58 @@ DLL_LINKAGE void MoveArtifact::applyGs( CGameState *gs )
 	a->move(src, dst);
 
 	//TODO what'll happen if Titan's thunder is equiped by pickin git up or the start of game?
-	if (a->artType->id == 135 && dst.hero && dst.slot == ArtifactPosition::RIGHT_HAND && !dst.hero->hasSpellbook()) //Titan's Thunder creates new spellbook on equip
-		gs->giveHeroArtifact(dst.hero, 0);
+	if (a->artType->id == 135 && dst.slot == ArtifactPosition::RIGHT_HAND) //Titan's Thunder creates new spellbook on equip
+	{
+		auto hPtr = boost::get<ConstTransitivePtr<CGHeroInstance> >(&dst.artHolder);
+		if(hPtr)
+		{
+			CGHeroInstance *h = *hPtr;
+			if(h && !h->hasSpellbook())
+				gs->giveHeroArtifact(h, 0);
+		}
+	}
 }
 
 DLL_LINKAGE void AssembledArtifact::applyGs( CGameState *gs )
 {
-	CGHeroInstance *h = al.hero;
+	CArtifactSet *artSet = al.getHolderArtSet();
 	const CArtifactInstance *transformedArt = al.getArt();
 	assert(transformedArt);
-	assert(vstd::contains(transformedArt->assemblyPossibilities(al.hero), builtArt));
+	assert(vstd::contains(transformedArt->assemblyPossibilities(artSet), builtArt));
 
 	CCombinedArtifactInstance *combinedArt = new CCombinedArtifactInstance(builtArt);
 	gs->map->addNewArtifactInstance(combinedArt);
 	//retrieve all constituents
 	BOOST_FOREACH(si32 constituentID, *builtArt->constituents)
 	{
-		int pos = h->getArtPos(constituentID);
+		int pos = artSet->getArtPos(constituentID);
 		assert(pos >= 0);
-		CArtifactInstance *constituentInstance = h->getArt(pos);
+		CArtifactInstance *constituentInstance = artSet->getArt(pos);
 
 		//move constituent from hero to be part of new, combined artifact
-		constituentInstance->removeFrom(h, pos);
+		constituentInstance->removeFrom(al);
 		combinedArt->addAsConstituent(constituentInstance, pos);
-		if(!vstd::contains(combinedArt->artType->possibleSlots, al.slot) && vstd::contains(combinedArt->artType->possibleSlots, pos))
+		if(!vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], al.slot) && vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], pos))
 			al.slot = pos;
 	}
 
 	//put new combined artifacts
-	combinedArt->putAt(h, al.slot);
+	combinedArt->putAt(al);
 }
 
 DLL_LINKAGE void DisassembledArtifact::applyGs( CGameState *gs )
 {
-	CGHeroInstance *h = al.hero;
 	CCombinedArtifactInstance *disassembled = dynamic_cast<CCombinedArtifactInstance*>(al.getArt());
 	assert(disassembled);
 
 	std::vector<CCombinedArtifactInstance::ConstituentInfo> constituents = disassembled->constituentsInfo;
-	disassembled->removeFrom(h, al.slot);
+	disassembled->removeFrom(al);
 	BOOST_FOREACH(CCombinedArtifactInstance::ConstituentInfo &ci, constituents)
 	{
+		ArtifactLocation constituentLoc = al;
+		constituentLoc.slot = (ci.slot >= 0 ? ci.slot : al.slot); //-1 is slot of main constituent -> it'll replace combined artifact in its pos
 		disassembled->detachFrom(ci.art);
-		ci.art->putAt(h, ci.slot >= 0 ? ci.slot : al.slot); //-1 is slot of main constituent -> it'll replace combined artifact in its pos
+		ci.art->putAt(constituentLoc);
 	}
 
 	gs->map->eraseArtifactInstance(disassembled);

+ 1 - 1
lib/RegisterTypes.h

@@ -94,7 +94,7 @@ void registerTypes1(Serializer &s)
 	s.template registerType<BattleInfo>();
 	s.template registerType<CArtifactInstance>();
 	s.template registerType<CCombinedArtifactInstance>();
-	s.template registerType<CCreatureArtifactInstance>();
+	//s.template registerType<CCreatureArtifactInstance>();
 	//s.template registerType<ArtSlotInfo>();
 	//s.template registerType<ArtifactLocation>();
 	//s.template registerType<StackLocation>();

+ 6 - 0
lib/StartInfo.h

@@ -58,6 +58,9 @@ struct StartInfo
 	typedef bmap<int, PlayerSettings> TPlayerInfos;
 	TPlayerInfos playerInfos; //color indexed
 
+	ui32 seedToBeUsed; //0 if not sure (client requests server to decide, will be send in reply pack)
+	ui32 seedPostInit; //so we know that game is correctly synced at the start; 0 if not known yet
+	ui32 mapfileChecksum; //0 if not relevant
 	ui8 turnTime; //in minutes, 0=unlimited
 	std::string mapname;
 	ui8 whichMapInCampaign; //used only for mode CAMPAIGN
@@ -84,6 +87,8 @@ struct StartInfo
 		h & mode;
 		h & difficulty;
 		h & playerInfos;
+		h & seedToBeUsed & seedPostInit;
+		h & mapfileChecksum;
 		h & turnTime;
 		h & mapname;
 		h & whichMapInCampaign;
@@ -92,6 +97,7 @@ struct StartInfo
 
 	StartInfo()
 	{
+		mapfileChecksum = seedPostInit = seedToBeUsed = 0;
 		mode = INVALID;
 		choosenCampaignBonus = -1;
 	}

+ 24 - 64
server/CGameHandler.cpp

@@ -794,7 +794,6 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 
 CGameHandler::CGameHandler(void)
 {
-	seedInitial = seedPostInit = -1;
 	QID = 1;
 	//gs = NULL;
 	IObjectInterface::cb = this;
@@ -814,13 +813,12 @@ CGameHandler::~CGameHandler(void)
 void CGameHandler::init(StartInfo *si)
 {
 	extern DLL_LINKAGE boost::rand48 ran;
-	if(seedInitial < 0)
-		seedInitial = std::time(NULL);
+	if(!si->seedToBeUsed)
+		si->seedToBeUsed = std::time(NULL);
 
 	gs = new CGameState();
 	tlog0 << "Gamestate created!" << std::endl;
-	gs->init(si, 0, seedInitial);
-	seedPostInit = ran();
+	gs->init(si);
 	tlog0 << "Gamestate initialized!" << std::endl;
 
 	for(std::map<ui8,PlayerState>::iterator i = gs->players.begin(); i != gs->players.end(); i++)
@@ -1207,8 +1205,7 @@ void CGameHandler::run(bool resume)
 		//ui32 seed;
 		if(!resume)
 		{
-			ui32 sum = gs->map ? gs->map->checksum : 612;
-			(*cc) << gs->initialOpts << sum << gs->seed << seedPostInit; // gs->scenarioOps
+			(*cc) << gs->initialOpts; // gs->scenarioOps
 		}
 
 		(*cc) >> quantity; //how many players will be handled at that client
@@ -2503,14 +2500,14 @@ bool CGameHandler::garrisonSwap( si32 tid )
 
 // With the amount of changes done to the function, it's more like transferArtifacts.
 // Function moves artifact from src to dst. If dst is not a backpack and is already occupied, old dst art goes to backpack and is replaced.
-bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot)
+bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2)
 {
-	const CGHeroInstance *srcHero = getHero(srcHeroID);
-	const CGHeroInstance *destHero = getHero(destHeroID);
-	ArtifactLocation src(srcHero, srcSlot), dst(destHero, destSlot);
-
+	ArtifactLocation src = al1, dst = al2;
+	const int srcPlayer = src.owningPlayer(), dstPlayer = dst.owningPlayer();
+	const CArmedInstance *srcObj = src.relatedObj(), *dstObj = dst.relatedObj();
+	
 	// Make sure exchange is even possible between the two heroes.
-	if(!isAllowedExchange(srcHeroID, destHeroID))
+	if(!isAllowedExchange(srcObj->id, dstObj->id))
 		COMPLAIN_RET("That heroes cannot make any exchange!");
 
 	const CArtifactInstance *srcArtifact = src.getArt();
@@ -2518,72 +2515,38 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 
 	if (srcArtifact == NULL)
 		COMPLAIN_RET("No artifact to move!");
-	if (destArtifact && srcHero->tempOwner != destHero->tempOwner)
+	if (destArtifact && srcPlayer != dstPlayer)
 		COMPLAIN_RET("Can't touch artifact on hero of another player!");
-	
+
 	// Check if src/dest slots are appropriate for the artifacts exchanged.
 	// Moving to the backpack is always allowed.
-	if ((!srcArtifact || destSlot < GameConstants::BACKPACK_START)
+	if ((!srcArtifact || dst.slot < GameConstants::BACKPACK_START)
 		&& srcArtifact && !srcArtifact->canBePutAt(dst, true))
 		COMPLAIN_RET("Cannot move artifact!");
 
 	if ((srcArtifact && srcArtifact->artType->id == GameConstants::ID_LOCK) || (destArtifact && destArtifact->artType->id == GameConstants::ID_LOCK)) 
 		COMPLAIN_RET("Cannot move artifact locks.");
 
-	if (destSlot >= GameConstants::BACKPACK_START && srcArtifact->artType->isBig()) 
+	if (dst.slot >= GameConstants::BACKPACK_START && srcArtifact->artType->isBig()) 
 		COMPLAIN_RET("Cannot put big artifacts in backpack!");
-	if (srcSlot == ArtifactPosition::MACH4 || destSlot == ArtifactPosition::MACH4) 
+	if (src.slot == ArtifactPosition::MACH4 || dst.slot == ArtifactPosition::MACH4) 
 		COMPLAIN_RET("Cannot move catapult!");
 
 	if(dst.slot >= GameConstants::BACKPACK_START)
-		vstd::amin(dst.slot, GameConstants::BACKPACK_START + dst.hero->artifactsInBackpack.size());
+		vstd::amin(dst.slot, GameConstants::BACKPACK_START + dst.getHolderArtSet()->artifactsInBackpack.size());
 
-	if (src.slot == dst.slot  &&  src.hero == dst.hero)
+	if (src.slot == dst.slot  &&  src.artHolder == dst.artHolder)
 		COMPLAIN_RET("Won't move artifact: Dest same as source!");
 
-	//moving art to backpack is always allowed (we've ruled out exceptions)
-	if(destSlot >= GameConstants::BACKPACK_START)
+	if(dst.slot < GameConstants::BACKPACK_START  &&  destArtifact) //moving art to another slot
 	{
-		moveArtifact(src, dst);
-	}
-	else //moving art to another slot
-	{
-		if(destArtifact) //old artifact must be removed first
-		{
-			moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size() + GameConstants::BACKPACK_START));
-		}
-		moveArtifact(src, dst);
+		//old artifact must be removed first
+		moveArtifact(dst, ArtifactLocation(dst.artHolder, dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START));
 	}
 
-	return true;
-}
-bool CGameHandler::moveArtifact(StackLocation s1, StackLocation s2, ui16 srcSlot, ui16 destSlot)
-{
-	ArtifactLocation src(s1.getStack(), srcSlot), dst(s2.getStack(), destSlot);
-	moveArtifact(src, dst);
-	return true;
-}
-bool CGameHandler::moveArtifact(si32 srcHeroID, StackLocation s2, ui16 srcSlot, ui16 destSlot)
-{
-	ArtifactLocation src(getHero(srcHeroID), srcSlot);
-	ArtifactLocation dst(s2.getStack(), destSlot);
-	moveArtifact(src, dst);
-	return true;
-}
-bool CGameHandler::moveArtifact(StackLocation s1, si32 destHeroID, ui16 srcSlot, ui16 destSlot)
-{
-	ArtifactLocation src(s1.getStack(), srcSlot);
-	ArtifactLocation dst(getHero(destHeroID), destSlot);
-	//hero should not wear stack artifact
-	vstd::amin(dst.slot, GameConstants::BACKPACK_START + dst.hero->artifactsInBackpack.size()); //put on first free position
-	moveArtifact(src, dst);
-	return true;
-}
-void CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2)
-{
 	MoveArtifact ma;
-	ma.src = al1;
-	ma.dst = al2;
+	ma.src = src;
+	ma.dst = dst;
 	sendAndApply(&ma);
 }
 
@@ -5550,7 +5513,7 @@ void CGameHandler::giveHeroArtifact(const CGHeroInstance *h, const CArtifactInst
 {
 	assert(a->artType);
 	ArtifactLocation al;
-	al.hero = h;
+	al.artHolder = const_cast<CGHeroInstance*>(h);
 
 	int slot = -1;
 	if(pos < 0)
@@ -5588,10 +5551,7 @@ void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact
 	CArtifactInstance *a = NULL;
 	if(!artType->constituents)
 	{
-		if (vstd::contains(VLC->arth->creatureArtifacts, artType->id))
-			a = new CCreatureArtifactInstance();
-		else
-			a = new CArtifactInstance();
+		a = new CArtifactInstance();
 	}
 	else
 	{

+ 1 - 7
server/CGameHandler.h

@@ -91,8 +91,6 @@ public:
 	PlayerStatuses states; //player color -> player state
 	std::set<CConnection*> conns;
 
-	si32 seedInitial, seedPostInit;
-
 	//queries stuff
 	boost::recursive_mutex gsm;
 	ui32 QID;
@@ -158,7 +156,7 @@ public:
 	void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, int pos) OVERRIDE;
 	void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) OVERRIDE; 
 	void removeArtifact(const ArtifactLocation &al) OVERRIDE;
-	void moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) OVERRIDE;
+	bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) OVERRIDE;
 
 	void showCompInfo(ShowInInfobox * comp) OVERRIDE;
 	void heroVisitCastle(int obj, int heroID) OVERRIDE;
@@ -212,10 +210,6 @@ public:
 	bool buyArtifact( const IMarket *m, const CGHeroInstance *h, int rid, int aid); //for artifact merchant and black market -> buying for any resource in special building / advobject
 	bool sellArtifact( const IMarket *m, const CGHeroInstance *h, int aid, int rid); //for artifact merchant selling
 	bool buySecSkill( const IMarket *m, const CGHeroInstance *h, int skill);
-	bool moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot);
-	bool moveArtifact(StackLocation s1, StackLocation s2, ui16 srcSlot, ui16 destSlot); //called when stacks merge
-	bool moveArtifact(si32 srcHeroID, StackLocation s2, ui16 srcSlot, ui16 destSlot); //equip artifact
-	bool moveArtifact(StackLocation s1, si32 destHeroID, ui16 srcSlot, ui16 destSlot); //return artifact to backpack
 	bool garrisonSwap(si32 tid);
 	bool upgradeCreature( ui32 objid, ui8 pos, ui32 upgID );
 	bool recruitCreatures(si32 objid, ui32 crid, ui32 cram, si32 level);

+ 2 - 15
server/NetPacksServer.cpp

@@ -133,21 +133,8 @@ bool GarrisonHeroSwap::applyGh( CGameHandler *gh )
 
 bool ExchangeArtifacts::applyGh( CGameHandler *gh )
 {
-	ERROR_IF_NOT_OWNS(hid1);//second hero can be ally
-	if (hid1)
-	{ //TODO: polymorph
-		if (hid2)
-			return gh->moveArtifact(hid1,hid2,slot1,slot2);
-		else
-			return gh->moveArtifact(hid1,s2,slot1,slot2);
-	}
-	else
-	{
-		if (hid2)
-			return gh->moveArtifact(s1,hid2,slot1,slot2);
-		else
-			return gh->moveArtifact(s1,s2,slot1,slot2);
-	}
+	ERROR_IF_NOT(src.owningPlayer());//second hero can be ally
+	return gh->moveArtifact(src, dst);
 }
 
 bool AssembleArtifacts::applyGh( CGameHandler *gh )