Jelajahi Sumber

Stack artifacts - part 1

DjWarmonger 13 tahun lalu
induk
melakukan
b8a5d0d430

+ 42 - 6
CCallback.cpp

@@ -127,14 +127,50 @@ bool CCallback::dismissHero(const CGHeroInstance *hero)
 // 	return gs->players[player].serial;
 // }
 
-bool CCallback::swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)
+bool CCallback::swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2)
 {
-	if(player!=hero1->tempOwner && player!=hero2->tempOwner)
-		return false;
+	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(hero1->id, hero2->id, pos1, pos2);
-	sendRequest(&ea);
-	return true;
+	ExchangeArtifacts ea;
+
+	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?
+	}
+	else
+		return false;
 }
 
 /**

+ 7 - 2
CCallback.h

@@ -13,6 +13,7 @@
  *
  */
 
+class IArtifactSetBase;
 class CGHeroInstance;
 class CGameState;
 struct CPath;
@@ -60,7 +61,8 @@ public:
 	virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
 	virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//joins first stack to the second (creatures must be same type)
 	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 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 assembleArtifacts(const CGHeroInstance * hero, ui16 artifactSlot, bool assemble, ui32 assembleTo)=0;
 	virtual bool dismissCreature(const CArmedInstance *obj, int stackPos)=0;
 	virtual void endTurn()=0;
@@ -117,7 +119,10 @@ public:
 	int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
 	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 CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2);
+	bool swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2);
+	//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);
 	bool buildBuilding(const CGTownInstance *town, si32 buildingID);
 	void recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount, si32 level=-1);

+ 60 - 11
client/GUIClasses.cpp

@@ -262,14 +262,33 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
 				}
 			}
 		}
-		else //highlight
+		else //drop artifact or highlight
 		{
-			if(creature)
+			bool artSelected = false;
+			if (CHeroWindow* chw = dynamic_cast<CHeroWindow*>(GH.topInt())) //dirty solution
 			{
-				owner->highlighted = this;
+				BOOST_FOREACH(CArtifactsOfHero *aoh, chw->artSets) // why they are multiple?
+				{
+					if (const CArtifactInstance *art = aoh->commonInfo->src.art)
+					{
+						artSelected = true;
+						if (art->canBePutAt(ArtifactLocation(myStack, GameConstants::CREATURE_ART)))
+						{
+							//TODO : move
+							break;
+						}
+					}
+				}
+			}
+			if (!artSelected)
+			{
+				if(creature)
+				{
+					owner->highlighted = this;
 
-				for(size_t i = 0; i<owner->splitButtons.size(); i++)
-					owner->splitButtons[i]->block(false);
+					for(size_t i = 0; i<owner->splitButtons.size(); i++)
+						owner->splitButtons[i]->block(false);
+				}
 			}
 			redraw();
 			refr = true;
@@ -297,6 +316,7 @@ 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;
@@ -334,7 +354,11 @@ void CGarrisonSlot::showAll(SDL_Surface * to)
 		if((owner->highlighted==this)
 			|| (owner->splitting && owner->highlighted->creature == creature))
 		{
-			blitAt(imgs[-1],pos,to);
+			highlight = true;
+		}
+		{
+			if (highlight)
+				blitAt(imgs[-1],pos,to);
 		}
 	}
 	else//empty slot
@@ -2700,7 +2724,7 @@ void CTradeWindow::artifactSelected(CArtPlace *slot)
 {
 	assert(mode == EMarketMode::ARTIFACT_RESOURCE);
 	items[1][0]->setArtInstance(slot->ourArt);
-	if(slot->ourArt)
+	if(slot->ourArt && slot->ourArt->id >= 0)
 		hLeft = items[1][0];
 	else
 		hLeft = NULL;
@@ -4813,6 +4837,21 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
 	BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
 		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();
 }
@@ -5012,10 +5051,10 @@ void CArtifactsOfHero::safeRedraw()
 
 void CArtifactsOfHero::realizeCurrentTransaction()
 {
-	assert(commonInfo->src.AOH);
-	assert(commonInfo->dst.AOH);
-	LOCPLINT->cb->swapArtifacts(commonInfo->src.AOH->curHero, commonInfo->src.slotID,
-								commonInfo->dst.AOH->curHero, commonInfo->dst.slotID);
+	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);
 }
 
 void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
@@ -6273,6 +6312,16 @@ 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)

+ 6 - 1
client/GUIClasses.h

@@ -25,6 +25,7 @@
  */
 
 struct ArtifactLocation;
+class IArtifactSetBase;
 class CStackBasicDescriptor;
 class CBonusSystemNode;
 class CArtifact;
@@ -62,6 +63,7 @@ class CPlayerInterface;
 class CHeroWindow;
 class CArtifact;
 class CArtifactsOfHero;
+class CCreatureArtifactSet;
 class CResDataBar;
 struct SPuzzleInfo;
 class CGGarrison;
@@ -222,6 +224,7 @@ public:
 	int count; //number of creatures
 	int upg; //0 - up garrison, 1 - down garrison
 	bool active; //TODO: comment me
+	bool highlight;
 
 	virtual void hover (bool on); //call-in
 	const CArmedInstance * getObj();
@@ -851,12 +854,14 @@ public:
 		struct Artpos
 		{
 			int slotID;
-			const CArtifactsOfHero * AOH;
+			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;

+ 101 - 32
lib/CArtHandler.cpp

@@ -7,6 +7,7 @@
 #include "../lib/VCMI_Lib.h"
 #include "CSpellHandler.h"
 #include "CObjectHandler.h"
+//#include "CCreatureSet.h"
 #include "NetPacks.h"
 
 extern CLodHandler *bitmaph;
@@ -195,7 +196,8 @@ 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);
+	if (GameConstants::STACK_ARTIFACT)
+		creatureArtifacts += 141, 142, 143, 156; //basic Wog arts and Warlord's banner
 }
 
 CArtHandler::~CArtHandler()
@@ -225,23 +227,6 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 	for (int i=0; i<GameConstants::ARTIFACTS_QUANTITY; i++)
 	{
 		CArtifact *art = new CArtifact();
-// 		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;
@@ -941,19 +926,24 @@ int CArtifactInstance::firstBackpackSlot(const CGHeroInstance *h) const
 
 bool CArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
 {
-	if(al.slot >= GameConstants::BACKPACK_START)
+	if (al.hero)
 	{
-		if(artType->isBig())
-			return false;
+		if(al.slot >= GameConstants::BACKPACK_START)
+		{
+			if(artType->isBig())
+				return false;
 		
-		//TODO backpack limit
-		return true;
-	}
+			//TODO backpack limit
+			return true;
+		}
 
-	if(!vstd::contains(artType->possibleSlots, al.slot))
-		return false;
+		if(!vstd::contains(artType->possibleSlots, al.slot))
+			return false;
 
-	return al.hero->isPositionFree(al.slot, assumeDestRemoved);
+		return al.hero->isPositionFree(al.slot, assumeDestRemoved);
+	}
+	else
+		return false;
 }
 
 void CArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
@@ -975,6 +965,15 @@ void CArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)
 	//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();
@@ -1011,16 +1010,36 @@ std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CG
 
 void CArtifactInstance::move(ArtifactLocation &src, ArtifactLocation &dst)
 {
-	removeFrom(src.hero, src.slot);
-	putAt(dst.hero, dst.slot);
-	if (artType->id == 135 && dst.slot == ArtifactPosition::RIGHT_HAND && !dst.hero->hasSpellbook()) //Titan's Thunder creates new spellbook on equip
-		dst.hero->giveArtifact(0);
+	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);
+		if (artType->id == 135 && dst.slot == ArtifactPosition::RIGHT_HAND && !dst.hero->hasSpellbook()) //Titan's Thunder creates new spellbook on equip
+			dst.hero->giveArtifact(0);
+	}
+	else if (dst.stack)
+		putAt(dst.stack, dst.slot);
+	else
+		tlog1 << "No destination for moved artifact found!\n";
+
+
 }
 
 CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
 {
 	if(!Art->constituents)
-		return new CArtifactInstance(Art);
+	{
+		 if (vstd::contains(VLC->arth->creatureArtifacts, Art->id))
+			 return new CCreatureArtifactInstance(Art);
+		 else
+			 return new CArtifactInstance(Art);
+	}
 	else
 	{
 		CCombinedArtifactInstance * ret = new CCombinedArtifactInstance(Art);
@@ -1233,6 +1252,56 @@ 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 true; //all artifacts should fit on creature
+	}
+	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
 {

+ 32 - 3
lib/CArtHandler.h

@@ -16,6 +16,8 @@
 class CDefHandler;
 class CArtifact;
 class CGHeroInstance;
+class CStackInstance;
+//class CCreatureArtifactSet;
 struct ArtifactLocation;
 
 namespace ArtifactPosition
@@ -75,7 +77,7 @@ public:
 
 	//CArtifactInstance(int aid);
 
-	std::string nodeName() const OVERRIDE;
+	virtual std::string nodeName() const OVERRIDE;
 	void deserializationFix();
 	void setType(CArtifact *Art);
 
@@ -87,6 +89,8 @@ public:
 	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 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;
@@ -147,6 +151,30 @@ 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:
@@ -212,7 +240,7 @@ public:
 	std::vector< ConstTransitivePtr<CArtifact> > artifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
-	//std::map<ui32, ui8> modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus
+	std::set<ui32> creatureArtifacts; // can be held by Stacks
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
@@ -235,6 +263,7 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & artifacts & allowedArtifacts & treasures & minors & majors & relics;
+		h & creatureArtifacts;
 		//if(!h.saving) sortArts();
 	}
 };
@@ -299,7 +328,7 @@ public:
 class DLL_LINKAGE CCreatureArtifactSet : public IArtifactSetBase
 { ///creature artifacts
 public:
-	std::vector<ArtSlotInfo> artifactsInBackpack; //artifacts carried by creature - 4 max
+	std::vector<ArtSlotInfo> artifactsInBackpack; //artifacts carried by creature - 4 max (according to WoG)
 	ArtSlotInfo activeArtifact; //position 0 - Arts::CREATURE_ART
 
 	ArtSlotInfo &retreiveNewArtSlot(ui16 slot);

+ 5 - 4
lib/CCreatureSet.h

@@ -3,11 +3,12 @@
 
 #include "HeroBonus.h"
 #include "GameConstants.h"
+#include "CArtHandler.h"
 
 class CCreature;
 class CGHeroInstance;
 class CArmedInstance;
-
+class CCreatureArtifactSet;
 
 class DLL_LINKAGE CStackBasicDescriptor
 {
@@ -25,20 +26,20 @@ public:
 	}
 };
 
-class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor
+class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CCreatureArtifactSet
 {
 	const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
 public:
 	int idRand; //hlp variable used during loading game -> "id" placeholder for randomization
 
 	const CArmedInstance * const & armyObj; //stack must be part of some army, army must be part of some object
-	ui32 experience; //TODO: handle
-	//TODO: stack artifacts
+	ui32 experience;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & static_cast<CBonusSystemNode&>(*this);
 		h & static_cast<CStackBasicDescriptor&>(*this);
+		h & static_cast<CCreatureArtifactSet&>(*this);
 		h & _armyObj & experience;
 		BONUS_TREE_DESERIALIZATION_FIX
 	}

+ 1 - 0
lib/CGameState.cpp

@@ -1410,6 +1410,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 				CGHeroInstance *hero = k->second.heroes[0];
  				hero->giveArtifact(toGive->id);
 			}
+			break;
 		}
 	}
 	/****************************TOWNS************************************************/

+ 6 - 2
lib/GameConstants.h

@@ -83,13 +83,17 @@ namespace GameConstants
 	const int WEEKLY_GROWTH = 10; //percent
 	const int AVAILABLE_HEROES_PER_PLAYER = 2;
 	const bool DWELLINGS_ACCUMULATE_CREATURES = false;
-	const bool STACK_EXP = true;
-	const bool STACK_ARTIFACT = true;
 	const int SPELLBOOK_GOLD_COST = 500;
 
 	const ui16 BACKPACK_START = 19;
 	const int ID_CATAPULT = 3, ID_LOCK = 145;
 	const ui16 CREATURE_ART = 0;
+
+	//game modules
+	const bool STACK_EXP = true;
+	const bool STACK_ARTIFACT = true; //now toggle for testing
+	const bool COMMANDERS = false;
+	const bool MITHRIL = false;
 }
 
 // Enum declarations

+ 12 - 2
lib/NetPacks.h

@@ -845,6 +845,7 @@ typedef si32 TArtPos;
 struct ArtifactLocation
 {
 	ConstTransitivePtr<CGHeroInstance> hero;
+	ConstTransitivePtr<CStackInstance> stack;
 	TArtPos slot;
 
 	ArtifactLocation()
@@ -854,6 +855,13 @@ struct ArtifactLocation
 	ArtifactLocation(const CGHeroInstance *Hero, 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;
+		slot = Slot;
+	}
+	ArtifactLocation(const CStackInstance *Stack, 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;
 		slot = Slot;
 	}
 	DLL_LINKAGE const CArtifactInstance *getArt() const;
@@ -861,7 +869,7 @@ struct ArtifactLocation
 	DLL_LINKAGE const ArtSlotInfo *getSlot() const;
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hero & slot;
+		h & hero & stack & slot;
 	}
 };
 
@@ -1746,17 +1754,19 @@ struct GarrisonHeroSwap : public CPackForServer
 };
 
 struct ExchangeArtifacts : public CPackForServer
+//TODO: allow exchange between heroes, stacks and commanders
 {
 	ExchangeArtifacts(){};
 	ExchangeArtifacts(si32 H1, si32 H2, ui16 S1, ui16 S2)
 		:hid1(H1),hid2(H2),slot1(S1),slot2(S2){};
 	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 & slot1 & slot2;
+		h & hid1 & hid2 & s1 & s2 & slot1 & slot2;
 	}
 };
 

+ 1 - 0
lib/RegisterTypes.h

@@ -94,6 +94,7 @@ void registerTypes1(Serializer &s)
 	s.template registerType<BattleInfo>();
 	s.template registerType<CArtifactInstance>();
 	s.template registerType<CCombinedArtifactInstance>();
+	s.template registerType<CCreatureArtifactInstance>();
 }
 
 template<typename Serializer> 

+ 42 - 9
server/CGameHandler.cpp

@@ -2572,6 +2572,40 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 	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;
+	sendAndApply(&ma);
+}
+
+
+
 /**
  * Assembles or disassembles a combination artifact.
  * @param heroID ID of hero holding the artifact(s).
@@ -5501,21 +5535,20 @@ void CGameHandler::putArtifact(const ArtifactLocation &al, const CArtifactInstan
 	sendAndApply(&pa);
 }
 
-void CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2)
-{
-	MoveArtifact ma;
-	ma.src = al1;
-	ma.dst = al2;
-	sendAndApply(&ma);
-}
-
 void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *artType, int pos)
 {
 	CArtifactInstance *a = NULL;
 	if(!artType->constituents)
-		a = new CArtifactInstance();
+	{
+		if (vstd::contains(VLC->arth->creatureArtifacts, artType->id))
+			a = new CCreatureArtifactInstance();
+		else
+			a = new CArtifactInstance();
+	}
 	else
+	{
 		a = new CCombinedArtifactInstance();
+	}
 	a->artType = artType; //*NOT* via settype -> all bonus-related stuff must be done by NewArtifact apply
 	
 	NewArtifact na;

+ 3 - 0
server/CGameHandler.h

@@ -210,6 +210,9 @@ public:
 	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);