瀏覽代碼

Little more work on artifacts.

Michał W. Urbańczyk 15 年之前
父節點
當前提交
c9189119b9

+ 10 - 8
client/CHeroWindow.cpp

@@ -69,6 +69,7 @@ CHeroSwitcher::CHeroSwitcher(int serial)
 CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	artifs = NULL;
 	garr = NULL;
 	curHero = NULL;
 	player = hero->tempOwner;
@@ -162,6 +163,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	}
 	if(hero == curHero)
 	{
+		tlog3 << "Spurious call to CHeroWindow::setHero\n";
 		return;
 	}
 
@@ -180,13 +182,15 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
 	{
 		delete garr;
 		OBJ_CONSTRUCTION_CAPTURING_ALL;
-		garr = new CGarrisonInt(80, 493, 8, Point(), background->bg, Point(16,486), curHero);
+		garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
+		artifs = new CArtifactsOfHero(Point(-65, -8), true);
+		artifs->setHero(hero);
 	}
 
 	AdventureMapButton * split = NULL;
 	{
 		BLOCK_CAPTURING;
-		split = new AdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], boost::bind(&CGarrisonInt::splitClick,garr), pos.x+604, pos.y+527, "hsbtns9.def", false, NULL, false); //deleted by garrison destructor
+		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);
@@ -326,14 +330,14 @@ void CHeroWindow::showAll(SDL_Surface * to)
 	 
 	//hero list blitting
 	 
-	for(int pos=0, g=0; g<LOCPLINT->wanderingHeroes.size(); ++g)
+	for(int slotPos=0, g=0; g<LOCPLINT->wanderingHeroes.size(); ++g)
 	{
 	 	const CGHeroInstance * cur = LOCPLINT->wanderingHeroes[g];
 	 	if (cur->inTownGarrison)
 	 		// Only display heroes that are not in garrison
 	 		continue;
 	 
-	 	blitAtLoc(graphics->portraitSmall[cur->portrait], 611, 87+pos*54, to);
+	 	blitAtLoc(graphics->portraitSmall[cur->portrait], 611, 87+slotPos*54, to);
 	 	//printing yellow border
 	 	if(cur->name == curHero->name)
 	 	{
@@ -341,13 +345,11 @@ void CHeroWindow::showAll(SDL_Surface * to)
 	 		{
 	 			for(int h=0; h<graphics->portraitSmall[cur->portrait]->h; ++h)
 	 				if(f==0 || h==0 || f==graphics->portraitSmall[cur->portrait]->w-1 || h==graphics->portraitSmall[cur->portrait]->h-1)
-	 				{
-	 					CSDL_Ext::SDL_PutPixelWithoutRefresh(to, 611+f, 87+pos*54+h, 240, 220, 120);
-	 				}
+	 					CSDL_Ext::SDL_PutPixelWithoutRefresh(to, pos.x + 611+f, pos.y + 87+slotPos*54+h, 240, 220, 120);
 	 		}
 	 	}
 	 
-	 	pos ++;
+	 	slotPos ++;
 	}
 	 
 	//secondary skills

+ 4 - 4
client/CKingdomInterface.cpp

@@ -773,7 +773,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 	for (int i=0; i<artifacts.size(); i++)
 	{
-		artifacts[i]->type = hero->getArtAtPos(i)->id;
+		artifacts[i]->type = hero->getArtTypeId(i);
 		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
 			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
 		else
@@ -785,7 +785,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 	for (int i=0; i<backpack.size(); i++)
 	{
-		backpack[i]->type = hero->getArtAtPos(19+i)->id;
+		backpack[i]->type = hero->getArtTypeId(19+i);
 		if (backpack[i]->type<0)
 			backpack[i]->hoverText ="";
 		else
@@ -836,7 +836,7 @@ void CKingdomInterface::CHeroItem::scrollArts(int move)
 	backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size();
 	for (int i=0; i<backpack.size(); i++)
 	{
-		backpack[i]->type = hero->getArtAtPos(19+(backpackPos + i)%hero->artifacts.size())->id;
+		backpack[i]->type = hero->getArtTypeId(19+(backpackPos + i)%hero->artifacts.size());
 		if (backpack[i]->type<0)
 			backpack[i]->hoverText ="";
 		else
@@ -901,7 +901,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
 		case 0://equipped arts
 			for (int i = iter ; i<iter+9;i++)
 			{
-				int artID = hero->getArtAtPos(i)->id;
+				int artID = hero->getArtTypeId(i);
 				if (artID>=0)
 					blitAt(graphics->artDefs->ourImages[artID].bitmap,pos.x+268+48*(i%9),pos.y+66,to);
 			}

+ 126 - 106
client/GUIClasses.cpp

@@ -2607,7 +2607,7 @@ void CTradeWindow::CTradeableItem::showAll(SDL_Surface * to)
 		if(downSelection)
 			posToSubCenter.y += 8;
 		break;
-	case ARTIFACT:
+	case ARTIFACT_TYPE:
 		posToSubCenter = Point(19, 58);
 		break;
 	}
@@ -2628,17 +2628,17 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
 		if(type == ARTIFACT_PLACEHOLDER)
 		{
 			CAltarWindow *aw = static_cast<CAltarWindow *>(mw);
-			const CArtifact *movedArt = aw->arts->commonInfo->srcArtifact;
+			const CArtifactInstance *movedArt = aw->arts->commonInfo->srcArtifact;
 			if(movedArt)
 			{
 				aw->moveFromSlotToAltar(aw->arts->commonInfo->srcSlotID, this, movedArt->id);
 			}
-			else if(id >= 0)
+			else if(const CArtifactInstance *art = getArtInstance())
 			{
-				movedArt = CGI->arth->artifacts[id];
+				movedArt = art;
 				aw->arts->commonInfo->srcAOH = aw->arts;
 				aw->arts->commonInfo->srcArtifact = movedArt;
-				aw->arts->commonInfo->srcSlotID = 19 + vstd::findPos(aw->hero->artifacts, const_cast<CArtifact*>(movedArt));
+				aw->arts->commonInfo->srcSlotID = 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);
@@ -2679,7 +2679,7 @@ SDL_Surface * CTradeWindow::CTradeableItem::getSurface()
 		return graphics->resources32->ourImages[id].bitmap;
 	case PLAYER:
 		return graphics->flags->ourImages[id].bitmap;
-	case ARTIFACT:
+	case ARTIFACT_TYPE:
 	case ARTIFACT_PLACEHOLDER:
 		return id >= 0 ? graphics->artDefs->ourImages[id].bitmap : NULL;
 	case CREATURE:
@@ -2737,7 +2737,7 @@ void CTradeWindow::CTradeableItem::clickRight(tribool down, bool previousState)
 		case CREATURE_PLACEHOLDER:
 			//GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl));
 			break;
-		case ARTIFACT:
+		case ARTIFACT_TYPE:
 		case ARTIFACT_PLACEHOLDER:
 			if(id >= 0)
 				adventureInt->handleRightClick(CGI->arth->artifacts[id]->Description(), down);
@@ -2759,13 +2759,40 @@ std::string CTradeWindow::CTradeableItem::getName(int number /*= -1*/) const
 			return CGI->creh->creatures[id]->nameSing;
 		else
 			return CGI->creh->creatures[id]->namePl;
-	case ARTIFACT:
+	case ARTIFACT_TYPE:
 		return CGI->arth->artifacts[id]->Name();
 	}
 	assert(0);
 	return "";
 }
 
+const CArtifactInstance * CTradeWindow::CTradeableItem::getArtInstance() const
+{
+	switch(type)
+	{
+	case ARTIFACT_PLACEHOLDER:
+	case ARTIFACT_INSTANCE:
+		return (const CArtifactInstance *)hlp;
+	default:
+		return NULL;
+	}
+}
+
+const CArtifact * CTradeWindow::CTradeableItem::getArt() const
+{
+	return NULL;
+}
+
+void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art) const
+{
+
+}
+
+void CTradeWindow::CTradeableItem::setArt(const CArtifact *artT) const
+{
+
+}
+
 CTradeWindow::CTradeWindow(const IMarket *Market, const CGHeroInstance *Hero, EMarketMode Mode)
 	: market(Market), hero(Hero),  arts(NULL), hLeft(NULL), hRight(NULL), readyToTrade(false)
 {
@@ -2792,14 +2819,14 @@ void CTradeWindow::initTypes()
 		break;
 	case RESOURCE_ARTIFACT:
 		itemsType[1] = RESOURCE;
-		itemsType[0] = ARTIFACT;
+		itemsType[0] = ARTIFACT_TYPE;
 		break;
 	case CREATURE_EXP:
 		itemsType[1] = CREATURE;
 		itemsType[0] = CREATURE_PLACEHOLDER;
 		break;
 	case ARTIFACT_EXP:
-		itemsType[1] = ARTIFACT;
+		itemsType[1] = ARTIFACT_TYPE;
 		itemsType[0] = ARTIFACT_PLACEHOLDER;
 		break;
 	}
@@ -2869,7 +2896,7 @@ std::vector<int> *CTradeWindow::getItemsIds(bool Left)
 					ids->push_back(i);
 			break;
 
-		case ARTIFACT:
+		case ARTIFACT_TYPE:
 			ids = new std::vector<int>(market->availableItemsIds(mode));
 			break;
 		}
@@ -3318,7 +3345,7 @@ std::string CMarketplaceWindow::selectionSubtitle(bool Left) const
 		{
 		case RESOURCE:
 			return boost::lexical_cast<std::string>( slider->value * r2 );
-		case ARTIFACT:
+		case ARTIFACT_TYPE:
 			return (deal->blocked ? "0" : "1");
 		case PLAYER:
 			return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
@@ -3346,7 +3373,7 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const
 		{
 		case RESOURCE:
 			return Point(410, 446);
-		case ARTIFACT:
+		case ARTIFACT_TYPE:
 			return Point(425, 447);
 		case PLAYER:
 			return Point(417, 451);
@@ -3392,7 +3419,7 @@ void CMarketplaceWindow::getBaseForPositions(EType type, int &dx, int &dy, int &
 		dy = 98;
 		assert(!Right);
 		break;
-	case ARTIFACT://45,123
+	case ARTIFACT_TYPE://45,123
 		x = 340-289;
 		y = 180;
 		w = 44;
@@ -4494,7 +4521,7 @@ CRClickPopupInt::~CRClickPopupInt()
 	CCS->curh->show();
 }
 
-CArtPlace::CArtPlace(const CArtifact* Art)
+CArtPlace::CArtPlace(const CArtifactInstance* Art)
 	: marked(false), ourArt(Art)
 {
 }
@@ -4514,7 +4541,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 	// If clicked on spellbook, open it only if no artifact is held at the moment.
 	if(ourArt && !down && previousState && !ourOwner->commonInfo->srcAOH)
 	{
-		if(ourArt->id == 0)
+		if(ourArt->artType->id == 0)
 		{
 			CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), ourOwner->curHero, LOCPLINT, LOCPLINT->battleInt);
 			GH.pushInt(spellWindow);
@@ -4523,7 +4550,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 
 	if (!down && previousState)
 	{
-		if(ourArt && ourArt->id == 0)
+		if(ourArt && ourArt->id == 0) //spellbook
 			return; //this is handled separately
 
 		if(!ourOwner->commonInfo->srcAOH) //nothing has been clicked
@@ -4544,7 +4571,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 		{
 			if (slotID >= 19) // Backpack destination.
 			{
-				const CArtifact * cur = ourOwner->commonInfo->srcArtifact;
+				const CArtifact * const cur = ourOwner->commonInfo->srcArtifact->artType;
 
 				switch(cur->id)
 				{
@@ -4552,30 +4579,20 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 					//should not happen, catapult cannot be selected
 					assert(cur->id != 3);
 					break;
-				case 4: case 5: case 6:
-					{
-						std::string text = CGI->generaltexth->allTexts[153];
-						boost::algorithm::replace_first(text, "%s", cur->Name());
-						LOCPLINT->showInfoDialog(text);
-					}
+				case 4: case 5: case 6: //war machines cannot go to backpack
+					LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % cur->Name()));
 					break;
 				default:
-					ourOwner->commonInfo->destAOH = ourOwner;
-					ourOwner->commonInfo->destSlotID = slotID;
-					ourOwner->commonInfo->destArtifact = NULL;
-
-					// Correction for backpack position when src lies before dest.
-					ourOwner->commonInfo->destSlotID +=
-						(ourOwner->commonInfo->srcAOH == ourOwner
-						&& ourOwner->commonInfo->srcSlotID >= 19
-						&& ourOwner->commonInfo->srcSlotID <= slotID);
-
-					LOCPLINT->cb->swapArtifacts(
-						ourOwner->commonInfo->srcAOH->curHero,
-						ourOwner->commonInfo->srcSlotID,
-						ourOwner->curHero,
-						ourOwner->commonInfo->destSlotID);
-
+					setMeAsDest();
+// 
+// 					// Correction for backpack position when src lies before dest.
+// 					int correction = (ourOwner->commonInfo->srcAOH == ourOwner
+// 						&& ourOwner->commonInfo->srcSlotID >= 19
+// 						&& ourOwner->commonInfo->srcSlotID <= slotID);
+// 					ourOwner->commonInfo->destSlotID += correction;
+						
+
+					ourOwner->realizeCurrentTransaction();
 					break;
 				}
 			}
@@ -4583,26 +4600,20 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 			else if (this->fitsHere(ourOwner->commonInfo->srcArtifact) &&
 				(!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID))
 			{
-				ourOwner->commonInfo->destAOH = ourOwner;
-				ourOwner->commonInfo->destSlotID = slotID;
-				ourOwner->commonInfo->destArtifact = ourArt;
+				setMeAsDest();
 
 				// Special case when the dest artifact can't be fit into the src slot.
-				CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
+				//CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID);
 				const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->srcAOH;
 				ui16 srcSlotID = ourOwner->commonInfo->srcSlotID;
-				if (ourArt && srcSlotID < 19 && !ourArt->fitsAt(srcAOH->curHero->artifWorn, 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;
 				}
 
-				LOCPLINT->cb->swapArtifacts(
-						srcAOH->curHero,
-						srcSlotID,
-						ourOwner->curHero,
-						slotID);
+				ourOwner->realizeCurrentTransaction();
 			}
 		}
 	}
@@ -4614,39 +4625,36 @@ void CArtPlace::clickRight(tribool down, bool previousState)
 	{
 		if (slotID < 19) 
 		{
-			selectedNo = false;
 			if(ourOwner->allowedAssembling)
 			{
+				std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
+
 				// If the artifact can be assembled, display dialog.
-				if (ourArt->constituentOf != NULL) 
+				BOOST_FOREACH(const CArtifact *combination, assemblyPossibilities) 
 				{
-					BOOST_FOREACH(ui32 combination, *ourArt->constituentOf) 
+					LOCPLINT->showArtifactAssemblyDialog(
+						ourArt->artType->id,
+						combination->id,
+						true,
+						boost::bind(&CCallback::assembleArtifacts, LOCPLINT->cb, ourOwner->curHero, slotID, true, combination->id),
+						0);
+
+					if(assemblyPossibilities.size())
 					{
-						if (ourArt->canBeAssembledTo(ourOwner->curHero->artifWorn, combination)) 
-						{
-							LOCPLINT->showArtifactAssemblyDialog(
-								ourArt->id,
-								combination,
-								true,
-								boost::bind(&CCallback::assembleArtifacts, LOCPLINT->cb, ourOwner->curHero, slotID, true, combination),
-								boost::bind(&CArtPlace::userSelectedNo, this));
-							if (!selectedNo)
-								return;
-						}
+						tlog3 << "More than one possibility of assembling... taking only first\n";
+						break;
 					}
 				}
 
 				// Otherwise if the artifact can be diasassembled, display dialog.
-				if (ourArt->constituents != NULL) 
+				if(ourArt->canBeDisassembled())
 				{
 					LOCPLINT->showArtifactAssemblyDialog(
-						ourArt->id,
+						ourArt->artType->id,
 						0,
 						false,
 						boost::bind(&CCallback::assembleArtifacts, LOCPLINT->cb, ourOwner->curHero, slotID, false, 0),
-						boost::bind(&CArtPlace::userSelectedNo, this));
-					if (!selectedNo)
-						return;
+						0);
 				}
 			}
 		}
@@ -4656,14 +4664,6 @@ void CArtPlace::clickRight(tribool down, bool previousState)
 	}
 }
 
-/**
- * Helper function to catch when a user selects no in an artifact assembly dialog.
- */
-void CArtPlace::userSelectedNo ()
-{
-	selectedNo = true;
-}
-
 /**
  * Selects artifact slot so that the containing artifact looks like it's picked up.
  */
@@ -4681,10 +4681,10 @@ void CArtPlace::select ()
 	ourOwner->commonInfo->srcAOH = ourOwner;
 
 	// 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));
+// 	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();
 
@@ -4719,7 +4719,7 @@ void CArtPlace::deactivate()
 void CArtPlace::showAll(SDL_Surface *to)
 {
 	if (ourArt)
-		blitAt(graphics->artDefs->ourImages[ourArt->id].bitmap, pos.x, pos.y, to);
+		blitAt(graphics->artDefs->ourImages[ourArt->artType->id].bitmap, pos.x, pos.y, to);
 
 	if(marked && active)
 	{
@@ -4739,7 +4739,7 @@ void CArtPlace::showAll(SDL_Surface *to)
 	}
 }
 
-bool CArtPlace::fitsHere(const CArtifact * art) const
+bool CArtPlace::fitsHere(const CArtifactInstance * art) const
 {
 	// You can place 'no artifact' anywhere.
 	if(!art)
@@ -4749,7 +4749,7 @@ bool CArtPlace::fitsHere(const CArtifact * art) const
 	if (slotID >= 19)
 		return !CGI->arth->isBigArtifact(art->id);
 
-	return art->fitsAt(ourOwner->curHero->artifWorn, slotID);
+	return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID));
 }
 
 CArtPlace::~CArtPlace()
@@ -4762,6 +4762,17 @@ bool CArtPlace::locked() const
 	return ourArt && ourArt->id == 145;
 }
 
+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;
+
+}
+
 void HoverableArea::hover (bool on)
 {
 	if (on)
@@ -4900,7 +4911,7 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 		if(curHero != hero)
 		{
 			//delete	curHero;
-			//hero = curHero = new CGHeroInstance(*hero);
+			curHero = hero; //was: creating a copy
 		}
 
 		// Compensate backpack pos if an artifact was insertad before it.
@@ -4915,11 +4926,11 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 			// 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));
+// 				// 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
 
@@ -4950,7 +4961,8 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 	if(hero != curHero)
 	{
 // 		delete curHero;
-// 		curHero = new CGHeroInstance(*hero);
+		// 		curHero = new CGHeroInstance(*hero);
+		curHero = hero; //was: creating a copy
 	}
 
 	if (curHero->artifacts.size() > 0)
@@ -4974,18 +4986,18 @@ void CArtifactsOfHero::dispose()
 void CArtifactsOfHero::scrollBackpack(int dir)
 {
 	backpackPos += dir;
-	if (curHero->artifacts.size() > 0) 
+	if (curHero->artifactsInBackpack.size() > 0) 
 	{
 		if (backpackPos < 0) // No guarantee of modulus behavior with negative operands.
 		{ 
 			do 
 			{
-				backpackPos += curHero->artifacts.size();
+				backpackPos += curHero->artifactsInBackpack.size();
 			} while (backpackPos < 0);
 		} 
 		else 
 		{
-			backpackPos %= curHero->artifacts.size();
+			backpackPos %= curHero->artifactsInBackpack.size();
 		}
 	}
 
@@ -4994,22 +5006,22 @@ void CArtifactsOfHero::scrollBackpack(int dir)
 
 	//set new data
 	size_t s = 0;
-	for( ; s < curHero->artifacts.size(); ++s) 
+	for( ; s < curHero->artifactsInBackpack.size(); ++s) 
 	{
 
-		if (s < curHero->artifacts.size())
+		if (s < curHero->artifactsInBackpack.size())
 		{
-			int slotID = 19 + (s + backpackPos)%curHero->artifacts.size();
-			const CArtifact *art = curHero->getArt(slotID);
+			int slotID = 19 + (s + backpackPos)%curHero->artifactsInBackpack.size();
+			const CArtifactInstance *art = curHero->getArt(slotID);
 			assert(art);
-			if(!vstd::contains(toOmmit, art->id))
+			if(!vstd::contains(toOmmit, art->artType->id))
 			{
 				if(s - ommited < 5)
 					setSlotData(backpack[s-ommited], slotID);
 			}
 			else
 			{
-				toOmmit -= art->id;
+				toOmmit -= art->artType->id;
 				ommited ++;
 				continue;
 			}
@@ -5019,8 +5031,8 @@ void CArtifactsOfHero::scrollBackpack(int dir)
 		eraseSlotData(backpack[s-ommited], 19 + s);
 
 	//blocking scrolling if there is not enough artifacts to scroll
-	leftArtRoll->block(curHero->artifacts.size() - ommited <= backpack.size());
-	rightArtRoll->block(curHero->artifacts.size() - ommited <= backpack.size());
+	leftArtRoll->block(curHero->artifactsInBackpack.size() - ommited <= backpack.size());
+	rightArtRoll->block(curHero->artifactsInBackpack.size() - ommited <= backpack.size());
 
 	safeRedraw();
 
@@ -5031,7 +5043,7 @@ void CArtifactsOfHero::scrollBackpack(int dir)
  *
  * @param art Artifact checked against.
  */
-void CArtifactsOfHero::markPossibleSlots (const CArtifact* art)
+void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
 {
 	for (std::set<CArtifactsOfHero *>::iterator it = commonInfo->participants.begin();
 		it != commonInfo->participants.end();
@@ -5075,15 +5087,15 @@ void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/)
 void CArtifactsOfHero::setSlotData (CArtPlace* artPlace, int slotID)
 {
 	artPlace->slotID = slotID;
-	artPlace->ourArt = curHero->getArt(slotID);
+	artPlace->ourArt = curHero->CArtifactSet::getArt(slotID);
 
 	if (artPlace->ourArt) 
 	{
-		artPlace->text = artPlace->ourArt->Description();
+		artPlace->text = artPlace->ourArt->artType->Description();
 		if (artPlace->locked()) // Locks should appear as empty.
 			artPlace->hoverText = CGI->generaltexth->allTexts[507];
 		else
-			artPlace->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % artPlace->ourArt->Name().c_str());
+			artPlace->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % artPlace->ourArt->artType->Name());
 	} 
 	else 
 	{
@@ -5204,6 +5216,14 @@ void CArtifactsOfHero::safeRedraw()
 		redraw();
 }
 
+void CArtifactsOfHero::realizeCurrentTransaction()
+{
+	assert(commonInfo->srcAOH);
+	assert(commonInfo->destAOH);
+	LOCPLINT->cb->swapArtifacts(commonInfo->srcAOH->curHero, commonInfo->srcSlotID, 
+								commonInfo->destAOH->curHero, commonInfo->destSlotID);
+}
+
 void CExchangeWindow::close()
 {
 	GH.popIntTotally(this);

+ 22 - 10
client/GUIClasses.h

@@ -68,6 +68,7 @@ class CGGarrison;
 class CStackInstance;
 class IMarket;
 class CTextBox;
+class CArtifactInstance;
 
 extern SDL_Color tytulowy, tlo, zwykly ;
 
@@ -582,7 +583,7 @@ class CTradeWindow : public CIntObject //base for markets and altar of sacrifice
 public:
 	enum EType
 	{
-		RESOURCE, PLAYER, ARTIFACT, CREATURE, CREATURE_PLACEHOLDER,ARTIFACT_PLACEHOLDER
+		RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE
 	};
 	class CTradeableItem : public CIntObject
 	{
@@ -593,6 +594,13 @@ public:
 		bool left;
 		std::string subtitle; //empty if default
 
+		void *hlp; //holds ptr to artifact instance id type artifact 
+
+		const CArtifactInstance *getArtInstance() const;
+		const CArtifact *getArt() const;
+		void setArtInstance(const CArtifactInstance *art) const;
+		void setArt(const CArtifact *artT) const;
+
 		CFunctionList<void()> callback;
 		bool downSelection;
 
@@ -905,10 +913,10 @@ public:
 	int slotID; //0   	head	1 	shoulders		2 	neck		3 	right hand		4 	left hand		5 	torso		6 	right ring		7 	left ring		8 	feet		9 	misc. slot 1		10 	misc. slot 2		11 	misc. slot 3		12 	misc. slot 4		13 	ballista (war machine 1)		14 	ammo cart (war machine 2)		15 	first aid tent (war machine 3)		16 	catapult		17 	spell book		18 	misc. slot 5		19+ 	backpack slots
 
 	bool marked;
-	bool selectedNo;
 	CArtifactsOfHero * ourOwner;
-	const CArtifact * ourArt;
-	CArtPlace(const CArtifact * Art); //c-tor
+	const CArtifactInstance * ourArt;
+
+	CArtPlace(const CArtifactInstance * Art); //c-tor
 	void clickLeft(tribool down, bool previousState);
 	void clickRight(tribool down, bool previousState);
 	void select ();
@@ -916,16 +924,18 @@ public:
 	void activate();
 	void deactivate();
 	void showAll(SDL_Surface * to);
-	bool fitsHere (const CArtifact * art) const; //returns true if given artifact can be placed here
+	bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
 	bool locked () const;
-	void userSelectedNo ();
+
+	void setMeAsDest(bool backpackAsVoid = true);
+
 	~CArtPlace(); //d-tor
 };
 
 
 class CArtifactsOfHero : public CIntObject
 {
-	CGHeroInstance * curHero; //local copy of hero on which we operate
+	const CGHeroInstance * curHero; //local copy of hero on which we operate
 
 	std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 	std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
@@ -935,12 +945,12 @@ public:
 	struct SCommonPart
 	{
 		std::set<CArtifactsOfHero *> participants; // Needed to mark slots.
-		const CArtifact * srcArtifact;    // Held artifact.
+		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 CArtifact * destArtifact;   // For swapping.
+		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
@@ -951,12 +961,14 @@ public:
 	bool allowedAssembling;
 	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 setHero(const CGHeroInstance * hero);
 	void dispose(); //free resources not needed after closing windows and reset state
 	void scrollBackpack(int dir); //dir==-1 => to left; dir==1 => to right
 
 	void safeRedraw();
-	void markPossibleSlots (const CArtifact* art);
+	void markPossibleSlots(const CArtifactInstance* art);
 	void unmarkSlots(bool withRedraw = true);
 	void setSlotData (CArtPlace* artPlace, int slotID);
 	void eraseSlotData (CArtPlace* artPlace, int slotID);

+ 1 - 0
global.h

@@ -151,6 +151,7 @@ namespace Arts
 		AFTER_LAST
 	};
 	const ui16 BACKPACK_START = 19;
+	const int LOCK_ID = 145;
 }
 
 enum EAlignment

+ 46 - 3
lib/CArtHandler.cpp

@@ -922,13 +922,23 @@ int CArtifactInstance::firstBackpackSlot(const CGHeroInstance *h) const
 	return -1;
 }
 
-bool CArtifactInstance::canBePutAt(const ArtifactLocation &al) const
+bool CArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
 {
+	if(al.slot >= Arts::BACKPACK_START)
+	{
+		if(artType->isBig())
+			return false;
+		
+		//TODO backpack limit
+		return true;
+	}
+
 	if(!vstd::contains(artType->possibleSlots, al.slot))
 		return false;
 
-	//simple artifact -> test if slot is free [combined artifacts have this function overridden]
-	return al.hero->isPositionFree(al.slot);
+	if(!assumeDestRemoved) //test if slot is free
+		return al.hero->isPositionFree(al.slot);
+	return true;
 }
 
 void CArtifactInstance::putAt(CGHeroInstance *h, ui16 slot)
@@ -960,4 +970,37 @@ void CArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot)
 	}
 
 	//TODO delete me?
+}
+
+bool CArtifactInstance::canBeDisassembled() const
+{
+	return false;
+}
+
+std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CGHeroInstance *h) const
+{
+	std::vector<const CArtifact *> ret;
+	if(!artType->constituentOf)
+		return ret;
+
+	BOOST_FOREACH(ui32 combination, *artType->constituentOf) 
+	{
+		if (artType->canBeAssembledTo(h->artifWorn, combination)) 
+		{
+			ret.push_back(VLC->arth->artifacts[combination]);
+		}
+	}
+
+	return ret;
+}
+
+bool CCombinedArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
+{
+	return CArtifactInstance::canBePutAt(al, assumeDestRemoved);
+	//TODO look for place for constituents
+}
+
+bool CCombinedArtifactInstance::canBeDisassembled() const
+{
+	return true;
 }

+ 7 - 2
lib/CArtHandler.h

@@ -75,7 +75,11 @@ public:
 
 	int firstAvailableSlot(const CGHeroInstance *h) const;
 	int firstBackpackSlot(const CGHeroInstance *h) const;
-	bool canBePutAt(const ArtifactLocation &al) const;
+
+	virtual bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const;
+	virtual bool canBeDisassembled() const;
+
+	std::vector<const CArtifact *> assemblyPossibilities(const CGHeroInstance *h) const;
 
 	void putAt(CGHeroInstance *h, ui16 slot);
 	void removeFrom(CGHeroInstance *h, ui16 slot);
@@ -92,7 +96,8 @@ public:
 class DLL_EXPORT CCombinedArtifactInstance : public CArtifactInstance
 {
 public:
-
+	bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const OVERRIDE;
+	bool canBeDisassembled() const OVERRIDE;
 };
 
 class DLL_EXPORT IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner

+ 5 - 0
lib/CCreatureHandler.cpp

@@ -144,6 +144,11 @@ bool CCreature::valid() const
 	return this == VLC->creh->creatures[idNumber];
 }
 
+std::string CCreature::nodeName() const
+{
+	return "Type of creature " + namePl;
+}
+
 int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
 {
 	befi=i;

+ 1 - 0
lib/CCreatureHandler.h

@@ -64,6 +64,7 @@ public:
 	bool valid() const;
 
 	void addBonus(int val, int type, int subtype = -1);
+	std::string nodeName() const OVERRIDE;
 	//void getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const;
 
 	template<typename RanGen>

+ 43 - 42
lib/CObjectHandler.cpp

@@ -663,7 +663,7 @@ int CGHeroInstance::getPrimSkillLevel(int id) const
 ui8 CGHeroInstance::getSecSkillLevel(SecondarySkill skill) const
 {
 	for(size_t i=0; i < secSkills.size(); ++i)
-		if(secSkills[i].first==ID)
+		if(secSkills[i].first == skill)
 			return secSkills[i].second;
 	return 0;
 }
@@ -729,25 +729,6 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
 	return int(base + base*modifier) + bonus;
 }
 
-const CArtifact* CGHeroInstance::getArtAtPos(ui16 pos) const
-{
-	if(pos<19)
-		if(vstd::contains(artifWorn,pos))
-			return artifWorn.find(pos)->second;
-		else
-			return NULL;
-	else
-		if(pos-19 < artifacts.size())
-			return artifacts[pos-19];
-		else 
-			return NULL;
-}
-
-const CArtifact * CGHeroInstance::getArt(int pos) const
-{
-	return getArtAtPos(pos);
-}
-
 // int CGHeroInstance::getSpellSecLevel(int spell) const
 // {
 // 	int bestslvl = 0;
@@ -1418,14 +1399,6 @@ si32 CGHeroInstance::manaRegain() const
 	return 1 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 8) + valOfBonuses(Bonus::MANA_REGENERATION); //1 + Mysticism level 
 }
 
-si32 CGHeroInstance::getArtPos(int aid) const
-{
-	for(std::map<ui16, const CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		if(i->second->id == aid)
-			return i->first;
-	return -1;
-}
-
 /**
  * Places an artifact in hero's backpack. If it's a big artifact equips it
  * or discards it if it cannot be equipped.
@@ -1451,18 +1424,6 @@ void CGHeroInstance::giveArtifact (ui32 aid) //use only for fixed artifacts
 	}
 }
 
-bool CGHeroInstance::hasArt( ui32 aid ) const
-{
-	for(std::vector<const CArtifact*>::const_iterator i = artifacts.begin(); i != artifacts.end(); i++)
-		if((*i)->id == aid)
-			return true;
-	for(std::map<ui16, const CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		if(i->second->id == aid)
-			return true;
-
-	return false;
-}
-
 int CGHeroInstance::getBoatType() const
 {
 	int alignment = type->heroType / 6; 
@@ -4389,7 +4350,7 @@ void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
 			case CQuest::MISSION_ART:
 				for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
 				{
-					cb->removeArtifact(VLC->arth->artifacts[*it], h->id);
+					cb->removeArtifact(ArtifactLocation(h, h->getArtPos(*it, false)));
 				}
 				break;
 			case CQuest::MISSION_ARMY:
@@ -6938,6 +6899,17 @@ const CArtifactInstance* CArtifactSet::getArt(ui16 pos) const
 	return NULL;
 }
 
+// if(pos<19)
+// 	if(vstd::contains(artifWorn,pos))
+// 		return artifWorn.find(pos)->second;
+// 	else
+// 		return NULL;
+// else
+// 	if(pos-19 < artifacts.size())
+// 		return artifacts[pos-19];
+// 	else 
+// 		return NULL;
+
 si32 CArtifactSet::getArtPos(int aid, bool onlyWorn /*= true*/) const
 {
 	for(std::map<ui16, ArtSlotInfo>::const_iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
@@ -6954,7 +6926,20 @@ si32 CArtifactSet::getArtPos(int aid, bool onlyWorn /*= true*/) const
 	return -1;
 }
 
-bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= true*/) const
+si32 CArtifactSet::getArtPos(const CArtifactInstance *art) const
+{
+	for(std::map<ui16, ArtSlotInfo>::const_iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
+		if(i->second.artifact == art)
+			return i->first;
+
+	for(int i = 0; i < artifactsInBackpack.size(); i++)
+		if(artifactsInBackpack[i].artifact == art)
+			return Arts::BACKPACK_START + i;
+
+	return -1;
+}
+
+bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/) const
 {
 	return getArtPos(aid, onlyWorn) != -1;
 }
@@ -6981,4 +6966,20 @@ bool CArtifactSet::isPositionFree(ui16 pos) const
 		return !s->artifact && !s->locked;
 
 	return true; //no slot means not used
+}
+
+si32 CArtifactSet::getArtTypeId(ui16 pos) const
+{
+	const CArtifactInstance * const a = getArt(pos);
+	if(!a)
+	{
+		tlog2 << (dynamic_cast<const CGHeroInstance*>(this))->name << " has no artifact at " << pos << " (getArtTypeId)\n";
+		return -1;
+	}
+	return a->artType->id;
+}
+
+CArtifactSet::~CArtifactSet()
+{
+
 }

+ 9 - 5
lib/CObjectHandler.h

@@ -267,8 +267,12 @@ public:
 	const ArtSlotInfo *getSlot(ui16 pos) const;
 	const CArtifactInstance* getArt(ui16 pos) const; //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)
-	bool hasArt(ui32 aid, bool onlyWorn = true) const; //checks if hero possess artifact of given id (either in backack or worn)
+	si32 getArtPos(const CArtifactInstance *art) 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) const;
+	si32 getArtTypeId(ui16 pos) const;
+
+	virtual ~CArtifactSet();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -384,10 +388,10 @@ public:
 
 	int maxMovePoints(bool onLand) const;
 
-	const CArtifact* getArtAtPos(ui16 pos) const; //NULL - no artifact
-	const CArtifact * getArt(int pos) const;
-	si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
-	bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn)
+// 	const CArtifact* getArtAtPos(ui16 pos) const; //NULL - no artifact
+// 	const CArtifact * getArt(int pos) const;
+// 	si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
+// 	bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn)
 
 	//int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error
 	static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest

+ 1 - 1
lib/IGameCallback.h

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

+ 11 - 2
lib/NetPacksLib.cpp

@@ -604,8 +604,17 @@ DLL_EXPORT const CStackInstance * StackLocation::getStack()
 DLL_EXPORT const CArtifactInstance *ArtifactLocation::getArt() const
 {
 	const ArtSlotInfo *s = getSlot();
-	if(s && !s->locked && s->artifact)
-		return s->artifact;
+	if(s && s->artifact)
+	{
+		if(!s->locked)
+			return s->artifact;
+		else
+		{
+			tlog3 << "ArtifactLocation::getArt: That location is locked!\n";
+			return NULL;
+		}
+	}
+	return NULL;
 }
 
 DLL_EXPORT CArtifactInstance *ArtifactLocation::getArt()

+ 1 - 1
lib/VCMI_Lib.cpp

@@ -207,7 +207,7 @@ void LibClasses::init()
 	spellh->loadSpells();
 	tlog0<<"\tSpell handler: "<<pomtime.getDif()<<std::endl;
 
-	IS_AI_ENABLED = true;
+	IS_AI_ENABLED = false;
 }
 
 void LibClasses::clear()

+ 131 - 123
server/CGameHandler.cpp

@@ -1610,43 +1610,46 @@ void CGameHandler::stopHeroVisitCastle(int obj, int heroID)
 	sendAndApply(&vc);
 }
 
-bool CGameHandler::removeArtifact(const CArtifact* art, int hid)
-{
-	const CGHeroInstance* h = getHero(hid);
-
-	SetHeroArtifacts sha;
-	sha.hid = hid;
-	sha.artifacts = h->artifacts;
-	sha.artifWorn = h->artifWorn;
-	
-	std::vector<const CArtifact*>::iterator it;
-	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), art)) != sha.artifacts.end()) //it is in backpack
-		sha.artifacts.erase(it);
-	else //worn
-	{
-		std::map<ui16, const CArtifact*>::iterator itr;
-		for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
-		{
-			if (itr->second == art)
-			{
-				VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
-				break;
-			}
-		}
-
-		if(itr == sha.artifWorn.end())
-		{
-			tlog2 << "Cannot find artifact to remove!\n";
-			return false;
-		}
-	}
-	sendAndApply(&sha);
-	return true;
-}
+// bool CGameHandler::removeArtifact(const CArtifact* art, int hid)
+// {
+// 	const CGHeroInstance* h = getHero(hid);
+// 
+// 	SetHeroArtifacts sha;
+// 	sha.hid = hid;
+// 	sha.artifacts = h->artifacts;
+// 	sha.artifWorn = h->artifWorn;
+// 	
+// 	std::vector<const CArtifact*>::iterator it;
+// 	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), art)) != sha.artifacts.end()) //it is in backpack
+// 		sha.artifacts.erase(it);
+// 	else //worn
+// 	{
+// 		std::map<ui16, const CArtifact*>::iterator itr;
+// 		for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
+// 		{
+// 			if (itr->second == art)
+// 			{
+// 				VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
+// 				break;
+// 			}
+// 		}
+// 
+// 		if(itr == sha.artifWorn.end())
+// 		{
+// 			tlog2 << "Cannot find artifact to remove!\n";
+// 			return false;
+// 		}
+// 	}
+// 	sendAndApply(&sha);
+// 	return true;
+// }
 
 void CGameHandler::removeArtifact(const ArtifactLocation &al)
 {
-
+	assert(al.getArt());
+	EraseArtifact ea;
+	ea.al = al;
+	sendAndApply(&ea);
 }
 void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town) //use hero=NULL for no hero
 {
@@ -1656,10 +1659,10 @@ void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstanc
 	if(army2->tempOwner < PLAYER_LIMIT)
 		states.setFlag(army2->tempOwner,&PlayerStatus::engagedIntoBattle,true);
 
-	const CArmedInstance *armies[2];
+	static const CArmedInstance *armies[2];
 	armies[0] = army1;
 	armies[1] = army2;
-	const CGHeroInstance*heroes[2];
+	static const CGHeroInstance*heroes[2];
 	heroes[0] = hero1;
 	heroes[1] = hero2;
 
@@ -2098,7 +2101,8 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 			return false;
 		}
 
-		removeArtifact(VLC->arth->artifacts[2], t->visitingHero->id);
+		//remove grail
+		removeArtifact(ArtifactLocation(t->visitingHero, t->visitingHero->getArtPos(2, false)));
 	}
 
 	NewStructures ns;
@@ -2450,103 +2454,97 @@ bool CGameHandler::garrisonSwap( si32 tid )
 }
 
 // With the amount of changes done to the function, it's more like transferArtifacts.
-bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot)
+// 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)
 {
 	CGHeroInstance *srcHero = gs->getHero(srcHeroID);
 	CGHeroInstance *destHero = gs->getHero(destHeroID);
+	ArtifactLocation src(srcHero, srcSlot), dst(destHero, destSlot);
 
 	// Make sure exchange is even possible between the two heroes.
-	if (distance(srcHero->pos,destHero->pos) > 1.5 )
-		return false;
+	if(!isAllowedExchange(srcHeroID, destHeroID))
+		COMPLAIN_RET("That heroes cannot make any exchange!");
 
-	const CArtifact *srcArtifact = srcHero->getArt(srcSlot);
-	const CArtifact *destArtifact = destHero->getArt(destSlot);
+	const CArtifactInstance *srcArtifact = src.getArt();
+	const CArtifactInstance *destArtifact = dst.getArt();
 
 	if (srcArtifact == NULL)
-	{
-		complain("No artifact to swap!");
-		return false;
-	}
-	
+		COMPLAIN_RET("No artifact to move!");
 	if (destArtifact && srcHero->tempOwner != destHero->tempOwner)
-	{
-		complain("Can't take artifact from hero of another player!");
-		return false;
-	}
+		COMPLAIN_RET("Can't touch artifact on hero of another player!");
 
-	SetHeroArtifacts sha;
-	sha.hid = srcHeroID;
-	sha.artifacts = srcHero->artifacts;
-	sha.artifWorn = srcHero->artifWorn;
 
-	// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
-	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
-	{
-		sha.setArtAtPos(srcSlot, NULL);
-		if (!vstd::contains(sha.artifWorn, destSlot))
-			destArtifact = NULL;
-	}
+
+// 	// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
+// 	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
+// 	{
+// 		sha.setArtAtPos(srcSlot, NULL);
+// 		if (!vstd::contains(sha.artifWorn, destSlot))
+// 			destArtifact = NULL;
+// 	}
 
 	// Check if src/dest slots are appropriate for the artifacts exchanged.
 	// Moving to the backpack is always allowed.
-	if ((!srcArtifact || destSlot < 19)
-		&& (srcArtifact && !srcArtifact->fitsAt(srcHeroID == destHeroID ? sha.artifWorn : destHero->artifWorn, destSlot)))
-	{
-		complain("Cannot swap artifacts!");
-		return false;
-	}
+	if ((!srcArtifact || destSlot < Arts::BACKPACK_START)
+		&& srcArtifact && !srcArtifact->canBePutAt(dst))
+		COMPLAIN_RET("Cannot swap artifacts!");
 
-	if ((srcArtifact && srcArtifact->id == 145) || (destArtifact && destArtifact->id == 145)) 
-	{
-		complain("Cannot move artifact locks.");
-		return false;
-	}
+	if ((srcArtifact && srcArtifact->artType->id == Arts::LOCK_ID) || (destArtifact && destArtifact->artType->id == Arts::LOCK_ID)) 
+		COMPLAIN_RET("Cannot move artifact locks.");
 
-	if (destSlot >= 19 && srcArtifact->isBig()) 
-	{
-		complain("Cannot put big artifacts in backpack!");
-		return false;
-	}
+	if (destSlot >= Arts::BACKPACK_START && srcArtifact->artType->isBig()) 
+		COMPLAIN_RET("Cannot put big artifacts in backpack!");
+	if (srcSlot == Arts::MACH4 || destSlot == Arts::MACH4) 
+		COMPLAIN_RET("Cannot move catapult!");
 
-	if (srcSlot == 16 || destSlot == 16) 
+	//moving art to backpack is always allowed (we've ruled out exceptions)
+	if(destSlot >= Arts::BACKPACK_START)
 	{
-		complain("Cannot move catapult!");
-		return false;
+		moveArtifact(src, dst);
 	}
-
-	// If dest does not fit in src, put it in dest's backpack instead.
-	if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first.
-		sha.setArtAtPos(destSlot, NULL);
-	const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
-	if (srcHeroID == destHeroID && destArtifact)
-		sha.setArtAtPos(destSlot, destArtifact);
-
-	sha.setArtAtPos(srcSlot, NULL);
-	if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
-		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL);
-
-	// 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));
-	}
-	if (srcHeroID != destHeroID) 
+	else //moving art to another slot
 	{
-		// Exchange between two different heroes.
-		SetHeroArtifacts sha2;
-		sha2.hid = destHeroID;
-		sha2.artifacts = destHero->artifacts;
-		sha2.artifWorn = destHero->artifWorn;
-		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL);
-		if (!destFits)
-			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
-		sendAndApply(&sha2);
-	}
-	sendAndApply(&sha);
+		if(destArtifact) //old artifact must be removed first
+		{
+			moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size()-1));
+		}
+		moveArtifact(src, dst);
+	}
+
+// 
+// 	// If dest does not fit in src, put it in dest's backpack instead.
+// 	if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first.
+// 		sha.setArtAtPos(destSlot, NULL);
+// 	const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
+// 	if (srcHeroID == destHeroID && destArtifact)
+// 		sha.setArtAtPos(destSlot, destArtifact);
+// 
+// 	sha.setArtAtPos(srcSlot, NULL);
+// 	if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
+// 		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL);
+// 
+// 	// 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));
+// 	}
+// 	if (srcHeroID != destHeroID) 
+// 	{
+// 		// Exchange between two different heroes.
+// 		SetHeroArtifacts sha2;
+// 		sha2.hid = destHeroID;
+// 		sha2.artifacts = destHero->artifacts;
+// 		sha2.artifWorn = destHero->artifWorn;
+// 		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL);
+// 		if (!destFits)
+// 			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
+// 		sendAndApply(&sha2);
+// 	}
+// 	sendAndApply(&sha);
 	return true;
 }
 
@@ -2566,8 +2564,8 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 	}
 
 	CGHeroInstance *hero = gs->getHero(heroID);
-	const CArtifact *destArtifact = hero->getArt(artifactSlot);
-
+	const CArtifactInstance *destArtifact = hero->getArt(artifactSlot);
+	/*
 	SetHeroArtifacts sha;
 	sha.hid = heroID;
 	sha.artifacts = hero->artifacts;
@@ -2678,7 +2676,8 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 
 	sendAndApply(&sha);
 
-	return true;
+	return true;*/
+	return false;
 }
 
 bool CGameHandler::buyArtifact( ui32 hid, si32 aid )
@@ -2711,7 +2710,7 @@ bool CGameHandler::buyArtifact( ui32 hid, si32 aid )
 			return false;
 		}
 
-		giveResource(hero->getOwner(),6,-price);
+		giveResource(hero->getOwner(),Res::GOLD,-price);
 		giveHeroNewArtifact(hero, VLC->arth->artifacts[aid], 9+aid);
 		return true;
 	}
@@ -4562,13 +4561,19 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
 	return true;
 }
 
-bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const CArtifact* art)
+bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot)
 {
-	if(!removeArtifact(art, hero->id))
+	ArtifactLocation al(hero, slot);
+	const CArtifactInstance *a = al.getArt();
+
+	if(!a)
 		COMPLAIN_RET("Cannot find artifact to sacrifice!");
 
+
 	int dmp, expToGive;
-	m->getOffer(art->id, 0, dmp, expToGive, ARTIFACT_EXP);
+	m->getOffer(hero->getArtTypeId(slot), 0, dmp, expToGive, ARTIFACT_EXP);
+
+	removeArtifact(al);
 	changePrimSkill(hero->id, 4, expToGive);
 	return true;
 }
@@ -4977,7 +4982,10 @@ void CGameHandler::putArtifact(const ArtifactLocation &al, const CArtifactInstan
 
 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)
@@ -4987,7 +4995,7 @@ void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact
 	
 	NewArtifact na;
 	na.art = a;
-	sendAndApply(&na);
+	sendAndApply(&na); // -> updates a!!!
 
 	giveHeroArtifact(h, a, pos);
 }

+ 3 - 3
server/CGameHandler.h

@@ -168,7 +168,7 @@ public:
 	void showCompInfo(ShowInInfobox * comp) OVERRIDE;
 	void heroVisitCastle(int obj, int heroID) OVERRIDE;
 	void stopHeroVisitCastle(int obj, int heroID) OVERRIDE;
-	bool removeArtifact(const CArtifact* art, int hid) OVERRIDE;
+	//bool removeArtifact(const CArtifact* art, int hid) OVERRIDE;
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL) OVERRIDE; //use hero=NULL for no hero
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used
 	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) OVERRIDE; //for hero<=>neutral army
@@ -212,7 +212,7 @@ public:
 	bool buyArtifact( ui32 hid, si32 aid ); //for blacksmith and mage guild only -> buying for gold in common buildings
 	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 buySecSkill( const IMarket *m, const CGHeroInstance *h, int skill);
-	bool swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot);
+	bool moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot);
 	bool garrisonSwap(si32 tid);
 	bool upgradeCreature( ui32 objid, ui8 pos, ui32 upgID );
 	bool recruitCreatures(si32 objid, ui32 crid, ui32 cram, si32 level);
@@ -252,7 +252,7 @@ public:
 	void run(bool resume);
 	void newTurn();
 	void handleAfterAttackCasting( const BattleAttack & bat );
-	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const CArtifact* art);
+	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot);
 	friend class CVCMIServer;
 	friend class CScriptCallback;
 };

+ 2 - 2
server/NetPacksServer.cpp

@@ -112,7 +112,7 @@ bool GarrisonHeroSwap::applyGh( CGameHandler *gh )
 bool ExchangeArtifacts::applyGh( CGameHandler *gh )
 {
 	ERROR_IF_NOT_OWNS(hid1);//second hero can be ally
-	return gh->swapArtifacts(hid1,hid2,slot1,slot2);
+	return gh->moveArtifact(hid1,hid2,slot1,slot2);
 }
 
 bool AssembleArtifacts::applyGh( CGameHandler *gh )
@@ -170,7 +170,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
 	case CREATURE_EXP:
 		return gh->sacrificeCreatures(m, hero, r1, val);
 	case ARTIFACT_EXP:
-		return gh->sacrificeArtifact(m, hero, hero->getArtAtPos(r1));
+		return gh->sacrificeArtifact(m, hero, r1);
 	default:
 		COMPLAIN_AND_RETURN("Unknown exchange mode!");
 	}