Bläddra i källkod

Partially functional artifact screen.
[TBD compound artifacts, backpack arranging, "live" modifying values, many details]

Michał W. Urbańczyk 15 år sedan
förälder
incheckning
401b364ad7

+ 4 - 1
CGameInterface.h

@@ -52,6 +52,7 @@ class CSaveFile;
 typedef si32 TQuantity;
 template <typename Serializer> class CISer;
 template <typename Serializer> class COSer;
+struct ArtifactLocation;
 
 class CBattleGameInterface
 {
@@ -100,7 +101,9 @@ public:
 	//virtual void garrisonChanged(const CGObjectInstance * obj){};
 
 	//artifacts operations
-	virtual void heroArtifactSetChanged(const CGHeroInstance*hero){};
+	virtual void artifactPut(const ArtifactLocation &al){};
+	virtual void artifactRemoved(const ArtifactLocation &al){};
+	virtual void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst){};
 
 	virtual void heroCreated(const CGHeroInstance*){};
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id

+ 0 - 2
client/CAdvmapInterface.cpp

@@ -1189,7 +1189,6 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis
 	//townList.init();
 	//townList.genList();
 
-	heroWindow = NULL;
 
 	for (int g=0; g<ADVOPT.gemG.size(); ++g)
 	{
@@ -1203,7 +1202,6 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis
 CAdvMapInt::~CAdvMapInt()
 {
 	SDL_FreeSurface(bg);
-	delete heroWindow;
 
 	for(int i=0; i<gems.size(); i++)
 		delete gems[i];

+ 0 - 2
client/CAdvmapInterface.h

@@ -177,8 +177,6 @@ public:
 
 	const CSpell *spellBeingCasted; //NULL if none
 
-	CHeroWindow * heroWindow;
-
 	const CArmedInstance *selection; //currently selected town/hero
 
 	//functions bound to buttons

+ 31 - 34
client/CHeroWindow.cpp

@@ -47,10 +47,9 @@ void CHeroSwitcher::clickLeft(tribool down, bool previousState)
 {
 	if(!down)
 	{
-		getOwner()->deactivate();
 		const CGHeroInstance * buf = LOCPLINT->getWHero(id);
-		getOwner()->setHero(buf);
-		getOwner()->activate();
+		GH.popIntTotally(getOwner());
+		GH.pushInt(new CHeroWindow(buf));
 	}
 }
 
@@ -61,7 +60,7 @@ CHeroWindow * CHeroSwitcher::getOwner()
 
 CHeroSwitcher::CHeroSwitcher(int serial)
 {
-	pos = Rect(677, 95 + serial * 54, 48, 32)  +  pos;
+	pos = Rect(612, 87 + serial * 54, 48, 32)  +  pos;
 	id = serial;
 	used = LCLICK;
 }
@@ -69,9 +68,8 @@ CHeroSwitcher::CHeroSwitcher(int serial)
 CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	artifs = NULL;
 	garr = NULL;
-	curHero = NULL;
+	curHero = hero;
 	player = hero->tempOwner;
 
 	background = new CPicture("HeroScr4.BMP");
@@ -118,12 +116,11 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 
 	specArea = new LRClickableAreaWText(Rect(18, 180, 136, 42), CGI->generaltexth->heroscrn[27]);
 	expArea = new LRClickableAreaWText(Rect(18, 228, 136, 42), CGI->generaltexth->heroscrn[9]);
-	
 	morale = new MoraleLuckBox(true, Rect(175,179,53,45));
 	luck = new MoraleLuckBox(false, Rect(233,179,53,45));
 	spellPointsArea = new LRClickableAreaWText(Rect(162,228, 136, 42), CGI->generaltexth->heroscrn[22]);
 
-	for(int i=0; i<SKILL_PER_HERO; ++i)
+	for(int i = 0; i < std::min(hero->secSkills.size(), 8u); ++i)
 	{
 		Rect r = Rect(i%2 == 0  ?  18  :  162,  276 + 48 * (i/2),  136,  42);
 		secSkillAreas.push_back(new LRClickableAreaWTextComp(r, SComponent::secskill));
@@ -141,7 +138,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 	new CPicture(graphics->pskillsm->ourImages[4].bitmap, 20, 230, false);
 	new CPicture(graphics->pskillsm->ourImages[3].bitmap, 162, 230, false);
 
-	setHero(hero);
+	update(hero);
 }
 
 CHeroWindow::~CHeroWindow()
@@ -154,21 +151,16 @@ CHeroWindow::~CHeroWindow()
 	//artifs->dispose();
 }
 
-void CHeroWindow::setHero(const CGHeroInstance *hero)
+void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/)
 {	
 	if(!hero) //something strange... no hero? it shouldn't happen
 	{
 		tlog1 << "Set NULL hero? no way...\n";
 		return;
 	}
-	if(hero == curHero)
-	{
-		tlog3 << "Spurious call to CHeroWindow::setHero\n";
-		return;
-	}
 
+	assert(hero == curHero);
 	assert(hero->tempOwner == LOCPLINT->playerID); //for now we won't show hero windows for non-our heroes
-	curHero = hero;
 
 	specArea->text = CGI->generaltexth->hTxts[hero->subID].longBonus;
 
@@ -179,21 +171,29 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name);
 	portraitArea->text = hero->getBiography();
 
+	
 	{
-		delete garr;
+		AdventureMapButton * split = NULL;
+		{
+			BLOCK_CAPTURING;
+			split = new AdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], boost::bind(&CGarrisonInt::splitClick,garr), 604, 527, "hsbtns9.def", false, NULL, false); //deleted by garrison destructor
+			boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]);
+		}
+		//delete garr;
 		OBJ_CONSTRUCTION_CAPTURING_ALL;
-		garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
-		artifs = new CArtifactsOfHero(Point(-65, -8), true);
-		artifs->setHero(hero);
+		if(!garr)
+		{
+			garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
+			garr->addSplitBtn(split);
+		}
+		if(!artSets.size())
+		{
+			CArtifactsOfHero *arts = new CArtifactsOfHero(Point(-65, -8), true);
+			arts->setHero(hero);
+			artSets.push_back(arts);
+		}
 	}
 
-	AdventureMapButton * split = NULL;
-	{
-		BLOCK_CAPTURING;
-		split = new AdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], boost::bind(&CGarrisonInt::splitClick,garr), 604, 527, "hsbtns9.def", false, NULL, false); //deleted by garrison destructor
-	}
-	boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]);
-	garr->addSplitBtn(split);
 
 	//primary skills support
 	for(size_t g=0; g<primSkillAreas.size(); ++g)
@@ -202,7 +202,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	}
 
 	//secondary skills support
-	for(size_t g=0; g<std::min(secSkillAreas.size(),hero->secSkills.size()); ++g)
+	for(size_t g=0; g< secSkillAreas.size(); ++g)
 	{
 		int skill = hero->secSkills[g].first,
 			level = hero->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(hero->secSkills[g].first));
@@ -212,7 +212,6 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 		secSkillAreas[g]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]);
 	}
 
-
 	//printing experience - original format does not support ui64
 	expArea->text = CGI->generaltexth->allTexts[2];
 	boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(hero->level));
@@ -252,11 +251,13 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 
 	morale->set(hero);
 	luck->set(hero);
+
+	if(redrawNeeded)
+		redraw();
 }
 
 void CHeroWindow::quit()
 {
-	adventureInt->heroWindow = NULL;
 	GH.popIntTotally(this);
 }
 
@@ -322,10 +323,6 @@ void CHeroWindow::showAll(SDL_Surface * to)
 	 	printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, zwykly, to);
 	}
 	 
-	//morale and luck printing
-	blitAtLoc(graphics->luck42->ourImages[curHero->LuckVal()+3].bitmap, 239, 182, to);
-	blitAtLoc(graphics->morale42->ourImages[curHero->MoraleVal()+3].bitmap, 181, 182, to);
-	 
 	blitAtLoc(flags->ourImages[player].bitmap, 606, 8, to);
 	 
 	//hero list blitting

+ 3 - 4
client/CHeroWindow.h

@@ -38,7 +38,7 @@ public:
 
 
 
-class CHeroWindow: public CWindowWithGarrison
+class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts
 {
 	enum ELabel {};
 	std::map<ELabel, CLabel*> labels;
@@ -52,8 +52,6 @@ class CHeroWindow: public CWindowWithGarrison
 	//AdventureMapButton * gar4button; //splitting
 	std::vector<CHeroSwitcher *> heroListMi; //new better list of heroes
 
-	CArtifactsOfHero * artifs;
-
 	//clickable areas
 	LRClickableAreaWText * portraitArea;
 	std::vector<LRClickableAreaWTextComp *> primSkillAreas;
@@ -71,7 +69,8 @@ public:
 	int player;
 	CHeroWindow(const CGHeroInstance *hero); //c-tor
 	~CHeroWindow(); //d-tor
-	void setHero(const CGHeroInstance * hero); //sets main displayed hero
+
+	void update(const CGHeroInstance * hero, bool redrawNeeded = false); //sets main displayed hero
 	void showAll(SDL_Surface * to); //shows and activates adv. map interface
 //		void redrawCurBack(); //redraws curBAck from scratch
 		void quit(); //stops displaying hero window and disposes

+ 30 - 6
client/CPlayerInterface.cpp

@@ -46,6 +46,7 @@
 #include <sstream>
 #include <boost/filesystem.hpp>
 #include "../StartInfo.h"
+#include <boost/foreach.hpp>
 
 #ifdef min
 #undef min
@@ -508,7 +509,7 @@ void CPlayerInterface::garrisonChanged(const CGObjectInstance * obj)
 	{
 		if((*i)->type & IShowActivable::WITH_GARRISON)
 		{
-			CGarrisonHolder *cgh = static_cast<CGarrisonHolder*>(*i);
+			CGarrisonHolder *cgh = dynamic_cast<CGarrisonHolder*>(*i);
 			cgh->updateGarrisons();
 		}
 		else if(CTradeWindow *cmw = dynamic_cast<CTradeWindow*>(*i))
@@ -954,11 +955,9 @@ void CPlayerInterface::tileHidden(const std::set<int3> &pos)
 void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	adventureInt->heroWindow = new CHeroWindow(hero);
-	adventureInt->heroWindow->setHero(hero);
-	GH.pushInt(adventureInt->heroWindow);
+	GH.pushInt(new CHeroWindow(hero));
 }
-
+/*
 void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
@@ -997,7 +996,7 @@ void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero)
 	}
 
 	updateInfo(hero);
-}
+}*/
 
 void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
 {
@@ -2121,21 +2120,25 @@ void CPlayerInterface::sendCustomEvent( int code )
 
 void CPlayerInterface::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(location.army);
 }
 
 void CPlayerInterface::stackChangedType(const StackLocation &location, const CCreature &newType)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(location.army);
 }
 
 void CPlayerInterface::stacksErased(const StackLocation &location)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(location.army);
 }
 
 void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(loc1.army);
 	if(loc2.army != loc1.army)
 		garrisonChanged(loc2.army);
@@ -2143,16 +2146,37 @@ void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocat
 
 void CPlayerInterface::newStackInserted(const StackLocation &location, const CStackInstance &stack)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(location.army);
 }
 
 void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
 {
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	garrisonChanged(src.army);
 	if(dst.army != src.army)
 		garrisonChanged(dst.army);
 }
 
+void CPlayerInterface::artifactPut(const ArtifactLocation &al)
+{
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
+}
+
+void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
+{
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
+}
+
+void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
+{
+	boost::unique_lock<boost::recursive_mutex> un(*pim);
+	BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+		if(isa->type & IShowActivable::WITH_ARTIFACTS)
+			BOOST_FOREACH(CArtifactsOfHero *aoh, (dynamic_cast<CWindowWithArtifacts*>(isa))->artSets)
+				aoh->artifactMoved(src, dst);
+}
+
 CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()
 {
 	spellbookLastPageBattle = spellbokLastPageAdvmap = 0;

+ 5 - 1
client/CPlayerInterface.h

@@ -166,7 +166,11 @@ public:
 	void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) OVERRIDE;
 	void newStackInserted(const StackLocation &location, const CStackInstance &stack) OVERRIDE; //new stack inserted at given (previously empty position)
 	void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) OVERRIDE; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
-	void heroArtifactSetChanged(const CGHeroInstance* hero) OVERRIDE;
+
+	void artifactPut(const ArtifactLocation &al);
+	void artifactRemoved(const ArtifactLocation &al);
+	void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
+
 	void heroCreated(const CGHeroInstance* hero) OVERRIDE;
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE;
 	void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;

+ 5 - 0
client/GUIBase.cpp

@@ -1023,4 +1023,9 @@ Rect Rect::createCentered( int w, int h )
 Rect Rect::around(const Rect &r, int width /*= 1*/) /*creates rect around another */
 {
 	return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
+}
+
+Rect Rect::centerIn(const Rect &r)
+{
+	return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
 }

+ 3 - 2
client/GUIBase.h

@@ -149,6 +149,7 @@ struct Rect : public SDL_Rect
 		h = surf->h;
 	}
 
+	Rect centerIn(const Rect &r);
 	static Rect createCentered(int w, int h);
 	static Rect around(const Rect &r, int width = 1); //creates rect around another
 
@@ -300,7 +301,7 @@ public:
 class IShowActivable : public IShowable, public IActivable
 {
 public:
-	enum {WITH_GARRISON = 1, BLOCK_ADV_HOTKEYS = 2};
+	enum {WITH_GARRISON = 1, BLOCK_ADV_HOTKEYS = 2, WITH_ARTIFACTS = 4};
 	int type; //bin flags using etype
 	IShowActivable();
 	virtual ~IShowActivable(){}; //d-tor
@@ -435,7 +436,7 @@ public:
 	virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
 };
 
-class CGarrisonHolder : public CIntObject// to unify updating garrisons via PlayerInterface
+class CGarrisonHolder : public virtual CIntObject// to unify updating garrisons via PlayerInterface
 {
 public:
 	CGarrisonHolder();

+ 236 - 151
client/GUIClasses.cpp

@@ -326,7 +326,7 @@ CGarrisonSlot::~CGarrisonSlot()
 	if(active)
 		deactivate();
 }
-void CGarrisonSlot::show(SDL_Surface * to)
+void CGarrisonSlot::showAll(SDL_Surface * to)
 {
 	std::map<int,SDL_Surface*> &imgs = (owner->smallIcons ? graphics->smallImgs : graphics->bigImgs);
 	if(creature)
@@ -2200,10 +2200,10 @@ void CCreInfoWindow::init(const CCreature *cre, const CBonusSystemNode *stackNod
 	printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
 
 	//setting morale
-	morale = new MoraleLuckBox(true, genRect(42, 42, pos.x + 24, pos.y + 189));
+	morale = new MoraleLuckBox(true, genRect(42, 42, 24, 189));
 	morale->set(stackNode);
 	//setting luck
-	luck = new MoraleLuckBox(false, genRect(42, 42, pos.x + 77, pos.y + 189));
+	luck = new MoraleLuckBox(false, genRect(42, 42, 77, 189));
 	luck->set(stackNode);
 
 	//luck and morale
@@ -2628,20 +2628,20 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
 		if(type == ARTIFACT_PLACEHOLDER)
 		{
 			CAltarWindow *aw = static_cast<CAltarWindow *>(mw);
-			const CArtifactInstance *movedArt = aw->arts->commonInfo->srcArtifact;
+			const CArtifactInstance *movedArt = aw->arts->commonInfo->src.art;
 			if(movedArt)
 			{
-				aw->moveFromSlotToAltar(aw->arts->commonInfo->srcSlotID, this, movedArt->id);
+				aw->moveFromSlotToAltar(aw->arts->commonInfo->src.slotID, this, movedArt->id);
 			}
 			else if(const CArtifactInstance *art = getArtInstance())
 			{
 				movedArt = art;
-				aw->arts->commonInfo->srcAOH = aw->arts;
-				aw->arts->commonInfo->srcArtifact = movedArt;
-				aw->arts->commonInfo->srcSlotID = aw->hero->CArtifactSet::getArtPos(art);// vstd::findPos(aw->hero->artifacts, const_cast<CArtifact*>(movedArt));
+				aw->arts->commonInfo->src.AOH = aw->arts;
+				aw->arts->commonInfo->src.art = movedArt;
+				aw->arts->commonInfo->src.slotID = aw->hero->CArtifactSet::getArtPos(art);// vstd::findPos(aw->hero->artifacts, const_cast<CArtifact*>(movedArt));
 
-				aw->arts->commonInfo->destAOH = aw->arts;
-				CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap);
+				aw->arts->commonInfo->dst.AOH = aw->arts;
+				CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->artType->id].bitmap);
 
 				id = -1;
 				subtitle = "";
@@ -3825,12 +3825,12 @@ void CAltarWindow::artifactPicked()
 void CAltarWindow::showAll(SDL_Surface * to)
 {
 	CTradeWindow::showAll(to);
-	if(mode == ARTIFACT_EXP && arts && arts->commonInfo->srcArtifact)
+	if(mode == ARTIFACT_EXP && arts && arts->commonInfo->src.art)
 	{
-		blitAtLoc(graphics->artDefs->ourImages[arts->commonInfo->srcArtifact->id].bitmap, 281, 442, to);
+		blitAtLoc(graphics->artDefs->ourImages[arts->commonInfo->src.art->artType->id].bitmap, 281, 442, to);
 
 		int dmp, val;
-		market->getOffer(arts->commonInfo->srcArtifact->id, 0, dmp, val, ARTIFACT_EXP);
+		market->getOffer(arts->commonInfo->src.art->artType->id, 0, dmp, val, ARTIFACT_EXP);
 		printAtMiddleLoc(boost::lexical_cast<std::string>(val), 304, 498, FONT_SMALL, zwykly, to);
 	}
 }
@@ -3864,10 +3864,10 @@ bool CAltarWindow::putOnAltar(CTradeableItem* altarSlot, int artID)
 
 void CAltarWindow::moveFromSlotToAltar(int slotID, CTradeableItem* altarSlot, int artID)
 {
-	if(arts->commonInfo->srcArtifact)
+	if(arts->commonInfo->src.art)
 	{
-		arts->commonInfo->destSlotID = 65500;
-		arts->commonInfo->destAOH = arts;
+		arts->commonInfo->dst.slotID = 65500;
+		arts->commonInfo->dst.AOH = arts;
 	}
 
 	if(putOnAltar(altarSlot, artID))
@@ -4159,8 +4159,7 @@ void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState)
 {
 	if(down && h)
 	{
-		adventureInt->heroWindow->setHero(h);
-		GH.pushInt(new CRClickPopupInt(adventureInt->heroWindow,false));
+		GH.pushInt(new CRClickPopupInt(new CHeroWindow(h), true));
 	}
 }
 
@@ -4539,7 +4538,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 	//LRClickableAreaWTextComp::clickLeft(down);
 	
 	// If clicked on spellbook, open it only if no artifact is held at the moment.
-	if(ourArt && !down && previousState && !ourOwner->commonInfo->srcAOH)
+	if(ourArt && !down && previousState && !ourOwner->commonInfo->src.AOH)
 	{
 		if(ourArt->artType->id == 0)
 		{
@@ -4553,7 +4552,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 		if(ourArt && ourArt->id == 0) //spellbook
 			return; //this is handled separately
 
-		if(!ourOwner->commonInfo->srcAOH) //nothing has been clicked
+		if(!ourOwner->commonInfo->src.AOH) //nothing has been clicked
 		{
 			if(ourArt  //to prevent selecting empty slots (bugfix to what GrayFace reported)
 				&&  ourOwner->curHero->tempOwner == LOCPLINT->playerID)//can't take art from another player
@@ -4567,11 +4566,15 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 				select();
 			}
 		}
+		else if(ourArt == ourOwner->commonInfo->src.art) //restore previously picked artifact
+		{
+			deselect();
+		}
 		else //perform artifact substitution
 		{
 			if (slotID >= 19) // Backpack destination.
 			{
-				const CArtifact * const cur = ourOwner->commonInfo->srcArtifact->artType;
+				const CArtifact * const cur = ourOwner->commonInfo->src.art->artType;
 
 				switch(cur->id)
 				{
@@ -4584,6 +4587,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 					break;
 				default:
 					setMeAsDest();
+					amin(ourOwner->commonInfo->dst.slotID, ourOwner->curHero->artifactsInBackpack.size() + Arts::BACKPACK_START);
 // 
 // 					// Correction for backpack position when src lies before dest.
 // 					int correction = (ourOwner->commonInfo->srcAOH == ourOwner
@@ -4597,21 +4601,21 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 				}
 			}
 			//check if swap is possible
-			else if (this->fitsHere(ourOwner->commonInfo->srcArtifact) &&
+			else if (fitsHere(ourOwner->commonInfo->src.art) &&
 				(!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID))
 			{
 				setMeAsDest();
-
-				// Special case when the dest artifact can't be fit into the src slot.
-				//CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
-				const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->srcAOH;
-				ui16 srcSlotID = ourOwner->commonInfo->srcSlotID;
-				if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) 
-				{
-					// Put dest artifact into owner's backpack.
-					ourOwner->commonInfo->srcAOH = ourOwner;
-					ourOwner->commonInfo->srcSlotID = ourOwner->curHero->artifacts.size() + 19;
-				}
+// 
+// 				// Special case when the dest artifact can't be fit into the src slot.
+// 				//CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
+// 				const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->src.AOH;
+// 				ui16 srcSlotID = ourOwner->commonInfo->src.slotID;
+// 				if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) 
+// 				{
+// 					// Put dest artifact into owner's backpack.
+// 					ourOwner->commonInfo->src.AOH = ourOwner;
+// 					ourOwner->commonInfo->src.slotID = ourOwner->curHero->artifacts.size() + 19;
+// 				}
 
 				ourOwner->realizeCurrentTransaction();
 			}
@@ -4674,24 +4678,16 @@ void CArtPlace::select ()
 
 	int backpackCorrection = -(slotID - 19 < ourOwner->backpackPos);
 
-	CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->id].bitmap);
+	CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->artType->id].bitmap);
 
-	ourOwner->commonInfo->srcArtifact = ourArt;
-	ourOwner->commonInfo->srcSlotID = slotID;
-	ourOwner->commonInfo->srcAOH = ourOwner;
+	ourOwner->commonInfo->src.setTo(this, false);
 
 	// Temporarily remove artifact from hero.
-// 	if (slotID < 19)
-// 		CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
-// 	else
-// 		ourOwner->curHero->artifacts.erase(ourOwner->curHero->artifacts.begin() + (slotID - 19));
 	ourOwner->markPossibleSlots(ourArt);
-	//ourOwner->curHero->recreateArtBonuses();
-
-
-	if (slotID >= 19)
-		ourOwner->scrollBackpack(backpackCorrection);
-	else
+// 
+// 	if (slotID >= 19)
+// 		ourOwner->scrollBackpack(backpackCorrection);
+// 	else
 		ourOwner->eraseSlotData(this, slotID);
 
 	// Update the hero bonuses.
@@ -4706,6 +4702,11 @@ void CArtPlace::deselect ()
 {
 	CCS->curh->dragAndDropCursor(NULL);
 	ourOwner->unmarkSlots();
+
+	ourOwner->commonInfo->src.clear();
+
+	ourOwner->updateParentWindow();
+	ourOwner->safeRedraw();
 }
 
 void CArtPlace::deactivate()
@@ -4749,7 +4750,7 @@ bool CArtPlace::fitsHere(const CArtifactInstance * art) const
 	if (slotID >= 19)
 		return !CGI->arth->isBigArtifact(art->id);
 
-	return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID));
+	return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID), true);
 }
 
 CArtPlace::~CArtPlace()
@@ -4764,13 +4765,7 @@ bool CArtPlace::locked() const
 
 void CArtPlace::setMeAsDest(bool backpackAsVoid /*= true*/)
 {
-	ourOwner->commonInfo->destAOH = ourOwner;
-	ourOwner->commonInfo->destSlotID = slotID;
-	if(slotID >= 19)
-		ourOwner->commonInfo->destArtifact = NULL;
-	else
-		ourOwner->commonInfo->destArtifact = ourArt;
-
+	ourOwner->commonInfo->dst.setTo(this, backpackAsVoid);
 }
 
 void HoverableArea::hover (bool on)
@@ -4897,74 +4892,72 @@ LRClickableAreaOpenTown::LRClickableAreaOpenTown()
 
 void CArtifactsOfHero::SCommonPart::reset()
 {
-	destAOH = srcAOH = NULL;
-	destArtifact = srcArtifact = NULL;
-	destSlotID = srcSlotID = -1;
+	src.clear();
+	dst.clear();
 	CCS->curh->dragAndDropCursor(NULL);
 }
 
 void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 {
-	// An update is made, rather than initialization.
-	if (curHero && curHero->id == hero->id) 
-	{
-		if(curHero != hero)
-		{
-			//delete	curHero;
-			curHero = hero; //was: creating a copy
-		}
-
-		// Compensate backpack pos if an artifact was insertad before it.
-		if (commonInfo->destSlotID >= 19 && commonInfo->destAOH == this
-			&& commonInfo->destSlotID - 19 < backpackPos)
-		{
-			backpackPos++;
-		}
-
-		if (updateState && commonInfo->srcAOH == this) 
-		{
-			// A swap was made, make the replaced artifact the current selected.
-			if (commonInfo->destSlotID < 19 && commonInfo->destArtifact) 
-			{
-// 				// Temporarily remove artifact from hero.
-// 				if (commonInfo->srcSlotID < 19)
-// 					CGI->arth->unequipArtifact(curHero->artifWorn, commonInfo->srcSlotID);
-// 				else
-// 					curHero->artifacts.erase(curHero->artifacts.begin() + (commonInfo->srcSlotID - 19));
-
-				updateParentWindow(); //TODO: evil! but does the thing
-
-				// Source <- Dest
-				commonInfo->srcArtifact = commonInfo->destArtifact;
-
-				// Reset destination parameters.
-				commonInfo->destAOH = NULL;
-				commonInfo->destArtifact = NULL;
-				commonInfo->destSlotID = -1;
-
-				CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[commonInfo->srcArtifact->id].bitmap);
-				markPossibleSlots(commonInfo->srcArtifact);
-			} 
-			else if (commonInfo->destAOH != NULL) 
-			{
-				// Reset all parameters.
-				commonInfo->reset();
-				unmarkSlots();
-			}
-		}
-	} 
-	else 
-	{
-		commonInfo->reset();
-	}
-
-	if(hero != curHero)
-	{
-// 		delete curHero;
-		// 		curHero = new CGHeroInstance(*hero);
-		curHero = hero; //was: creating a copy
-	}
+// 	// An update is made, rather than initialization.
+// 	if (curHero && curHero->id == hero->id) 
+// 	{
+// 		if(curHero != hero)
+// 		{
+// 			//delete	curHero;
+// 			curHero = hero; //was: creating a copy
+// 		}
+// 
+// 		// Compensate backpack pos if an artifact was insertad before it.
+// 		if (commonInfo->dst.slotID >= 19 && commonInfo->destAOH == this
+// 			&& commonInfo->dst.slotID - 19 < backpackPos)
+// 		{
+// 			backpackPos++;
+// 		}
+// 
+// 		if (updateState && commonInfo->srcAOH == this) 
+// 		{
+// 			// A swap was made, make the replaced artifact the current selected.
+// 			if (commonInfo->dst.slotID < 19 && commonInfo->destArtifact) 
+// 			{
+// // 				// Temporarily remove artifact from hero.
+// // 				if (commonInfo->srcSlotID < 19)
+// // 					CGI->arth->unequipArtifact(curHero->artifWorn, commonInfo->srcSlotID);
+// // 				else
+// // 					curHero->artifacts.erase(curHero->artifacts.begin() + (commonInfo->srcSlotID - 19));
+// 
+// 				updateParentWindow(); //TODO: evil! but does the thing
+// 
+// 				// Source <- Dest
+// 				commonInfo->srcArtifact = commonInfo->destArtifact;
+// 
+// 				// Reset destination parameters.
+// 				commonInfo->dst.clear();
+// 
+// 				CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[commonInfo->srcArtifact->id].bitmap);
+// 				markPossibleSlots(commonInfo->srcArtifact);
+// 			} 
+// 			else if (commonInfo->destAOH != NULL) 
+// 			{
+// 				// Reset all parameters.
+// 				commonInfo->reset();
+// 				unmarkSlots();
+// 			}
+// 		}
+// 	} 
+// 	else 
+// 	{
+// 		commonInfo->reset();
+// 	}
+// 
+// 	if(hero != curHero)
+// 	{
+// // 		delete curHero;
+// 		// 		curHero = new CGHeroInstance(*hero);
+// 		curHero = hero; //was: creating a copy
+// 	}
 
+	curHero = hero;
 	if (curHero->artifacts.size() > 0)
 		backpackPos %= curHero->artifacts.size();
 	else
@@ -5045,19 +5038,10 @@ void CArtifactsOfHero::scrollBackpack(int dir)
  */
 void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
 {
-	for (std::set<CArtifactsOfHero *>::iterator it = commonInfo->participants.begin();
-		it != commonInfo->participants.end();
-		++it)
-	{
-		for (int i = 0; i < (*it)->artWorn.size(); i++) 
-		{
-			if ((*it)->artWorn[i]->fitsHere(art))
-				(*it)->artWorn[i]->marked = true;
-			else
-				(*it)->artWorn[i]->marked = false;
-		}
-	}
-
+	BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
+		BOOST_FOREACH(CArtPlace *place, aoh->artWorn)
+			place->marked = art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true);
+	
 	safeRedraw();
 }
 
@@ -5066,16 +5050,9 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
  */
 void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/)
 {
-	if(!commonInfo) return;
-	for (std::set<CArtifactsOfHero *>::iterator it = commonInfo->participants.begin();
-		it != commonInfo->participants.end();
-		++it)
-	{
-		for (int i = 0; i < (*it)->artWorn.size(); i++) 
-		{
-			(*it)->artWorn[i]->marked = false;
-		}
-	}
+	BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
+		BOOST_FOREACH(CArtPlace *place, aoh->artWorn)
+			place->marked = false;
 
 	if(withRedraw)
 		safeRedraw();
@@ -5084,7 +5061,7 @@ void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/)
 /**
  * Assigns an artifacts to an artifact place depending on it's new slot ID.
  */
-void CArtifactsOfHero::setSlotData (CArtPlace* artPlace, int slotID)
+void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID)
 {
 	artPlace->slotID = slotID;
 	artPlace->ourArt = curHero->CArtifactSet::getArt(slotID);
@@ -5175,11 +5152,7 @@ void CArtifactsOfHero::updateParentWindow()
 		if(updateState)
 			chw->curHero = curHero;
 		else
-		{
-			chw->deactivate();
-			chw->setHero(curHero);
-			chw->activate();
-		}
+			chw->update(curHero, true);
 	} 
 	else if(CExchangeWindow* cew = dynamic_cast<CExchangeWindow*>(GH.topInt()))
 	{
@@ -5218,10 +5191,78 @@ void CArtifactsOfHero::safeRedraw()
 
 void CArtifactsOfHero::realizeCurrentTransaction()
 {
-	assert(commonInfo->srcAOH);
-	assert(commonInfo->destAOH);
-	LOCPLINT->cb->swapArtifacts(commonInfo->srcAOH->curHero, commonInfo->srcSlotID, 
-								commonInfo->destAOH->curHero, commonInfo->destSlotID);
+	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);
+}
+
+void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
+{
+	BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) //update affected slots
+	{
+		if(src.hero == aoh->curHero)
+			setSlotData(aoh->getArtPlace(src.slot), src.slot);
+		if(dst.hero == aoh->curHero)
+			setSlotData(aoh->getArtPlace(dst.slot), dst.slot);
+	}
+	updateParentWindow();
+
+	if(commonInfo->src == src) //artifact was taken from us
+	{
+		assert(commonInfo->dst == dst  ||  dst.slot == dst.hero->artifactsInBackpack.size() + Arts::BACKPACK_START);
+		commonInfo->reset();
+		unmarkSlots();
+	}
+	else if(commonInfo->dst == src) //the dest artifact was moved -> we are picking it
+	{
+		assert(dst.slot >= Arts::BACKPACK_START);
+		commonInfo->reset();
+
+		CArtPlace *ap = NULL;
+		BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
+		{
+			if(aoh->curHero == dst.hero)
+			{
+				commonInfo->src.AOH = aoh;
+				if(ap = aoh->getArtPlace(dst.slot))
+					break;
+			}
+		}
+
+		if(ap)
+		{
+			ap->select();
+		}
+		else
+		{
+			commonInfo->src.art = src.getArt();
+			commonInfo->src.slotID = src.slot;
+			assert(commonInfo->src.AOH);
+			CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[src.getArt()->artType->id].bitmap);
+			markPossibleSlots(dst.getArt());
+		}
+	}
+	else
+	{
+		tlog1 << "Unexpected artifact movement...\n";
+	}
+}
+
+CArtPlace * CArtifactsOfHero::getArtPlace(int slot)
+{
+	if(slot < Arts::BACKPACK_START)
+	{
+		return artWorn[slot];
+	}
+	else
+	{
+		BOOST_FOREACH(CArtPlace *ap, backpack)
+			if(ap->slotID == slot)
+				return ap;
+	}
+
+	return NULL;
 }
 
 void CExchangeWindow::close()
@@ -6461,7 +6502,9 @@ void MoraleLuckBox::set(const CBonusSystemNode *node)
 void MoraleLuckBox::showAll(SDL_Surface * to)
 {
 	CDefEssential *def = morale ? graphics->morale42 : graphics->luck42;
-	blitAt(def->ourImages[bonusValue].bitmap, pos, to);
+	SDL_Surface *img = def->ourImages[bonusValue + 3].bitmap;
+	
+	blitAt(img, Rect(img).centerIn(pos), to); //put img in the center of our pos
 }
 
 MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r)
@@ -6811,3 +6854,45 @@ void CFocusable::moveFocus()
 		}
 	}
 }
+
+CWindowWithArtifacts::CWindowWithArtifacts()
+{
+	type |= WITH_ARTIFACTS;
+}
+
+CWindowWithArtifacts::~CWindowWithArtifacts()
+{
+}
+
+void CArtifactsOfHero::SCommonPart::Artpos::clear()
+{
+	slotID = -1;
+	AOH = NULL;
+	art = NULL;
+}
+
+CArtifactsOfHero::SCommonPart::Artpos::Artpos()
+{
+	clear();
+}
+
+void CArtifactsOfHero::SCommonPart::Artpos::setTo(const CArtPlace *place, bool dontTakeBackpack)
+{
+	slotID = place->slotID;
+	AOH = place->ourOwner;
+
+	if(slotID >= 19 && dontTakeBackpack)
+		art = NULL;
+	else
+		art = place->ourArt;
+}
+
+bool CArtifactsOfHero::SCommonPart::Artpos::operator==(const ArtifactLocation &al) const
+{
+	if(!AOH)
+		return false;
+	bool ret = al.hero == AOH->curHero  &&  al.slot == slotID;
+
+	//assert(al.getArt() == art);
+	return ret;
+}

+ 25 - 8
client/GUIClasses.h

@@ -25,6 +25,7 @@
  *
  */
 
+struct ArtifactLocation;
 class CStackBasicDescriptor;
 class CBonusSystemNode;
 class CArtifact;
@@ -214,7 +215,7 @@ public:
 	void clickLeft(tribool down, bool previousState);
 	void activate();
 	void deactivate();
-	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CStackInstance * Creature=NULL);
 	~CGarrisonSlot(); //d-tor
 };
@@ -907,6 +908,15 @@ public:
 	void show(SDL_Surface * to);
 };
 
+class CWindowWithArtifacts : public virtual CIntObject
+{
+public:
+	std::vector<CArtifactsOfHero *> artSets;
+
+	CWindowWithArtifacts();
+	~CWindowWithArtifacts();
+};
+
 class CArtPlace: public LRClickableAreaWTextComp
 {
 public:
@@ -932,7 +942,6 @@ public:
 	~CArtPlace(); //d-tor
 };
 
-
 class CArtifactsOfHero : public CIntObject
 {
 	const CGHeroInstance * curHero; //local copy of hero on which we operate
@@ -944,13 +953,19 @@ class CArtifactsOfHero : public CIntObject
 public:
 	struct SCommonPart
 	{
+		struct Artpos
+		{
+			int slotID;
+			const CArtifactsOfHero * AOH;
+			const CArtifactInstance *art;
+
+			Artpos();
+			void clear();
+			void setTo(const CArtPlace *place, bool dontTakeBackpack);
+			bool operator==(const ArtifactLocation &al) const;
+		} src, dst;
+
 		std::set<CArtifactsOfHero *> participants; // Needed to mark slots.
-		const CArtifactInstance * srcArtifact;    // Held artifact.
-		const CArtifactsOfHero * srcAOH;  // Following two needed to uniquely identify the source.
-		int srcSlotID;                    //
-		const CArtifactsOfHero * destAOH; // For swapping. (i.e. changing what is held)
-		int destSlotID;	                  // Needed to determine what kind of action was last taken in setHero
-		const CArtifactInstance * destArtifact;   // For swapping.
 
 		void reset();
 	} * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally
@@ -962,6 +977,8 @@ public:
 	std::multiset<int> artifactsOnAltar; //artifacts id that are technically present in backpack but in GUI are moved to the altar - they'll be ommited in backpack slots
 
 	void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
+	void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
+	CArtPlace *getArtPlace(int slot);
 
 	void setHero(const CGHeroInstance * hero);
 	void dispose(); //free resources not needed after closing windows and reset state

+ 12 - 6
client/NetPacksClient.cpp

@@ -169,15 +169,19 @@ void RebalanceStacks::applyCl( CClient *cl )
 
 void PutArtifact::applyCl( CClient *cl )
 {
-
+	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactPut, al);
 }
 
 void EraseArtifact::applyCl( CClient *cl )
 {
+	INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactRemoved, al);
 }
 
 void MoveArtifact::applyCl( CClient *cl )
 {
+	INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst);
+	if(src.hero->tempOwner != dst.hero->tempOwner)
+		INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst);
 }
 
 void GiveBonus::applyCl( CClient *cl )
@@ -394,13 +398,15 @@ void SetHeroesInTown::applyCl( CClient *cl )
 
 void SetHeroArtifacts::applyCl( CClient *cl )
 {
-	CGHeroInstance *h = GS(cl)->getHero(hid);
-	CGameInterface *player = (vstd::contains(cl->playerint,h->tempOwner) ? cl->playerint[h->tempOwner] : NULL);
-	if(!player)
-		return;
+	tlog1 << "SetHeroArtifacts :(\n";
+// 
+// 	CGHeroInstance *h = GS(cl)->getHero(hid);
+// 	CGameInterface *player = (vstd::contains(cl->playerint,h->tempOwner) ? cl->playerint[h->tempOwner] : NULL);
+// 	if(!player)
+// 		return;
 
 	//h->recreateArtBonuses();
-	player->heroArtifactSetChanged(h);
+	//player->heroArtifactSetChanged(h);
 
 // 	BOOST_FOREACH(Bonus bonus, gained)
 // 	{

+ 2 - 1
lib/CArtHandler.cpp

@@ -958,7 +958,8 @@ void CArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
 	asi.artifact = this;
 	asi.locked = false;
 
-	h->attachTo(this);
+	if(slot < Arts::BACKPACK_START)
+		h->attachTo(this);
 }
 
 void CArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)

+ 15 - 0
lib/CObjectHandler.cpp

@@ -1190,6 +1190,21 @@ void CGHeroInstance::UpdateSpeciality()
 }
 void CGHeroInstance::updateSkill(int which, int val)
 {
+	if(which == LEADERSHIP || which == LUCK)
+	{
+		bool luck = which == LUCK;
+		Bonus::BonusType type[] = {Bonus::MORALE, Bonus::LUCK};
+
+		Bonus *b = getBonus(Selector::type(type[luck]) && Selector::sourceType(Bonus::SECONDARY_SKILL));
+		if(!b)
+		{
+			b = new Bonus(Bonus::PERMANENT, type[luck], Bonus::SECONDARY_SKILL, +val, which, which, Bonus::BASE_NUMBER);
+			addNewBonus(b);
+		}
+		else
+			b->val = +val;
+	}
+
 	int skillVal = 0;
 	switch (which)
 	{

+ 4 - 1
lib/NetPacksLib.cpp

@@ -712,7 +712,10 @@ DLL_EXPORT void EraseArtifact::applyGs( CGameState *gs )
 
 DLL_EXPORT void MoveArtifact::applyGs( CGameState *gs )
 {
-
+	assert(!dst.getArt());
+	CArtifactInstance *a = src.getArt();
+	a->removeFrom(src.hero, src.slot);
+	a->putAt(dst.hero, dst.slot);
 }
 
 DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )

+ 13 - 6
server/CGameHandler.cpp

@@ -2486,8 +2486,8 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 	// Check if src/dest slots are appropriate for the artifacts exchanged.
 	// Moving to the backpack is always allowed.
 	if ((!srcArtifact || destSlot < Arts::BACKPACK_START)
-		&& srcArtifact && !srcArtifact->canBePutAt(dst))
-		COMPLAIN_RET("Cannot swap artifacts!");
+		&& srcArtifact && !srcArtifact->canBePutAt(dst, true))
+		COMPLAIN_RET("Cannot move artifact!");
 
 	if ((srcArtifact && srcArtifact->artType->id == Arts::ID_LOCK) || (destArtifact && destArtifact->artType->id == Arts::ID_LOCK)) 
 		COMPLAIN_RET("Cannot move artifact locks.");
@@ -2497,6 +2497,16 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 	if (srcSlot == Arts::MACH4 || destSlot == Arts::MACH4) 
 		COMPLAIN_RET("Cannot move catapult!");
 
+	if(dst.slot >= Arts::BACKPACK_START)
+		amin(dst.slot, Arts::BACKPACK_START + dst.hero->artifactsInBackpack.size());
+
+ 	// Correction for destination from removing source artifact in backpack.
+ 	if (src.slot >= 19 && dst.slot >= 19 && src.slot < dst.slot)
+ 		dst.slot--;
+
+	if (src.slot == dst.slot)
+		COMPLAIN_RET("Won't move artifact: Dest same as source!");
+
 	//moving art to backpack is always allowed (we've ruled out exceptions)
 	if(destSlot >= Arts::BACKPACK_START)
 	{
@@ -2506,7 +2516,7 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 	{
 		if(destArtifact) //old artifact must be removed first
 		{
-			moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size()-1));
+			moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size() + Arts::BACKPACK_START));
 		}
 		moveArtifact(src, dst);
 	}
@@ -2526,9 +2536,6 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 // 	// Internal hero artifact arrangement.
 // 	if(srcHero == destHero) 
 // 	{
-// 		// Correction for destination from removing source artifact in backpack.
-// 		if (srcSlot >= 19 && destSlot >= 19 && srcSlot < destSlot)
-// 			destSlot--;
 // 
 // 		sha.setArtAtPos(destSlot, srcHero->getArtAtPos(srcSlot));
 // 	}