Browse Source

A few fixes for artifacts.

Michał W. Urbańczyk 15 years ago
parent
commit
898ad292ea

+ 1 - 1
client/CCastleInterface.cpp

@@ -511,7 +511,7 @@ void CCastleInterface::buildingClicked(int building)
 				else //both heroes present, use the visiting one
 					h = town->visitingHero;
 
-				if(h && !vstd::contains(h->artifWorn,ui16(17))) //hero doesn't have spellbok
+				if(h && !h->hasSpellbook()) //hero doesn't have spellbok
 				{
 					if(LOCPLINT->cb->getResourceAmount(6) < 500) //not enough gold to buy spellbook
 					{

+ 1 - 1
client/CHeroWindow.cpp

@@ -162,7 +162,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
 	}
 
 	assert(hero == curHero);
-	assert(hero->tempOwner == LOCPLINT->playerID); //for now we won't show hero windows for non-our heroes
+	assert(hero->tempOwner == LOCPLINT->playerID || hero->tempOwner == NEUTRAL_PLAYER); //for now we won't show hero windows for non-our heroes
 
 	specArea->text = CGI->generaltexth->hTxts[hero->subID].longBonus;
 

+ 5 - 5
client/CKingdomInterface.cpp

@@ -766,8 +766,8 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 		garr = NULL;
 	}
 	char bufor[4000];
-	artLeft->block(hero->artifacts.size() <= 8);
-	artRight->block(hero->artifacts.size() <= 8);
+	artLeft->block(hero->artifactsInBackpack.size() <= 8);
+	artRight->block(hero->artifactsInBackpack.size() <= 8);
 	garr = new CGarrisonInt(pos.x+6, pos.y+78, 4, Point(), parent->slots->ourImages[parent->PicCount].bitmap,
 		Point(6,78), hero, NULL, true, true, true);
 
@@ -833,10 +833,10 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
 
 void CKingdomInterface::CHeroItem::scrollArts(int move)
 {
-	backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size();
+	backpackPos = ( backpackPos + move + hero->artifactsInBackpack.size()) % hero->artifactsInBackpack.size();
 	for (int i=0; i<backpack.size(); i++)
 	{
-		backpack[i]->type = hero->getArtTypeId(19+(backpackPos + i)%hero->artifacts.size());
+		backpack[i]->type = hero->getArtTypeId(19+(backpackPos + i)%hero->artifactsInBackpack.size());
 		if (backpack[i]->type<0)
 			backpack[i]->hoverText ="";
 		else
@@ -909,7 +909,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
 		case 2:
 			artLeft->show(to);
 			artRight->show(to);
-			int max = hero->artifacts.size();
+			int max = hero->artifactsInBackpack.size();
 			iter = std::min(8, max);
 			/*for (size_t it = 0 ; it<iter;it++)
 				blitAt(graphics->artDefs->ourImages[hero->artifacts[(it+backpackPos)%max]->id].bitmap,pos.x+293+48*it,pos.y+66,to);

+ 21 - 9
client/GUIClasses.cpp

@@ -3516,9 +3516,9 @@ CAltarWindow::CAltarWindow(const IMarket *Market, const CGHeroInstance *Hero /*=
 		printAtMiddle(CGI->generaltexth->allTexts[478], 302, 423, FONT_SMALL, tytulowy, *bg); //%s's Creatures
 
 		sacrificeAll = new AdventureMapButton(CGI->generaltexth->zelp[571],boost::bind(&CAltarWindow::SacrificeAll,this),393,520,"ALTFILL.DEF");
-		sacrificeAll->block(!hero->artifacts.size() && !hero->artifWorn.size());
+		sacrificeAll->block(!hero->artifactsInBackpack.size() && !hero->artifactsWorn.size());
 		sacrificeBackpack = new AdventureMapButton(CGI->generaltexth->zelp[570],boost::bind(&CAltarWindow::SacrificeBackpack,this),147,520,"ALTEMBK.DEF");
-		sacrificeBackpack->block(!hero->artifacts.size());
+		sacrificeBackpack->block(!hero->artifactsInBackpack.size());
 
 		slider = NULL;
 		max = NULL;
@@ -4189,9 +4189,9 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const
 		hoverName = CGI->generaltexth->tavernInfo[4];
 		boost::algorithm::replace_first(hoverName,"%s",H->name);
 
-		int artifs = h->artifWorn.size() + h->artifacts.size();
+		int artifs = h->artifactsWorn.size() + h->artifactsInBackpack.size();
 		for(int i=13; i<=17; i++) //war machines and spellbook don't count
-			if(vstd::contains(h->artifWorn,i)) 
+			if(vstd::contains(h->artifactsWorn,i)) 
 				artifs--;
 		sprintf_s(descr, sizeof(descr),CGI->generaltexth->allTexts[215].c_str(),
 				  h->name.c_str(), h->level, h->type->heroClass->name.c_str(), artifs);
@@ -4997,8 +4997,8 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
 // 	}
 
 	curHero = hero;
-	if (curHero->artifacts.size() > 0)
-		backpackPos %= curHero->artifacts.size();
+	if (curHero->artifactsInBackpack.size() > 0)
+		backpackPos %= curHero->artifactsInBackpack.size();
 	else
 		backpackPos = 0;
 
@@ -5269,13 +5269,19 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
 		}
 		else
 		{
-			commonInfo->src.art = src.getArt();
-			commonInfo->src.slotID = src.slot;
+			commonInfo->src.art = dst.getArt();
+			commonInfo->src.slotID = dst.slot;
 			assert(commonInfo->src.AOH);
-			CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[src.getArt()->artType->id].bitmap);
+			CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[dst.getArt()->artType->id].bitmap);
 			markPossibleSlots(dst.getArt());
 		}
 	}
+	else if(src.slot >= Arts::BACKPACK_START && src.slot < commonInfo->src.slotID && src.hero == commonInfo->src.AOH->curHero) //artifact taken from before currently picked one
+	{
+		int fixedSlot = src.hero->getArtPos(commonInfo->src.art);
+		commonInfo->src.slotID--;
+		assert(commonInfo->src.valid());
+	}
 	else
 	{
 		tlog1 << "Unexpected artifact movement...\n";
@@ -6937,4 +6943,10 @@ bool CArtifactsOfHero::SCommonPart::Artpos::operator==(const ArtifactLocation &a
 
 	//assert(al.getArt() == art);
 	return ret;
+}
+
+bool CArtifactsOfHero::SCommonPart::Artpos::valid()
+{
+	assert(AOH && art);
+	return art == AOH->curHero->getArt(slotID);
 }

+ 1 - 0
client/GUIClasses.h

@@ -965,6 +965,7 @@ public:
 			Artpos();
 			void clear();
 			void setTo(const CArtPlace *place, bool dontTakeBackpack);
+			bool valid();
 			bool operator==(const ArtifactLocation &al) const;
 		} src, dst;
 

+ 20 - 20
client/NetPacksClient.cpp

@@ -396,27 +396,27 @@ void SetHeroesInTown::applyCl( CClient *cl )
 		cl->playerint[t->tempOwner]->heroInGarrisonChange(t);
 }
 
-void SetHeroArtifacts::applyCl( CClient *cl )
-{
-	tlog1 << "SetHeroArtifacts :(\n";
+// void SetHeroArtifacts::applyCl( CClient *cl )
+// {
+// 	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;
 // 
-// 	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);
-
-// 	BOOST_FOREACH(Bonus bonus, gained)
-// 	{
-// 		player->heroBonusChanged(h,bonus,true);
-// 	}
-// 	BOOST_FOREACH(Bonus bonus, lost)
-// 	{
-// 		player->heroBonusChanged(h,bonus,false);
-// 	}
-}
+// 	//h->recreateArtBonuses();
+// 	//player->heroArtifactSetChanged(h);
+// 
+// // 	BOOST_FOREACH(Bonus bonus, gained)
+// // 	{
+// // 		player->heroBonusChanged(h,bonus,true);
+// // 	}
+// // 	BOOST_FOREACH(Bonus bonus, lost)
+// // 	{
+// // 		player->heroBonusChanged(h,bonus,false);
+// // 	}
+// }
 
 void HeroRecruited::applyCl( CClient *cl )
 {

+ 88 - 35
lib/CArtHandler.cpp

@@ -119,31 +119,31 @@ bool CArtifact::fitsAt (const std::map<ui16, const CArtifact*> &artifWorn, ui16
 	return true;
 }
 
-bool CArtifact::canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const
-{
-	if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID))
-		return false;
-
-	const CArtifact &artifact = *VLC->arth->artifacts[artifactID];
-	assert(artifact.constituents);
-
-	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
-	{
-		bool found = false;
-		for (std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) 
-		{
-			if (it->second->id == constituentID) 
-			{
-				found = true;
-				break;
-			}
-		}
-		if (!found)
-			return false;
-	}
-
-	return true;
-}
+// bool CArtifact::canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const
+// {
+// 	if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID))
+// 		return false;
+// 
+// 	const CArtifact &artifact = *VLC->arth->artifacts[artifactID];
+// 	assert(artifact.constituents);
+// 
+// 	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) 
+// 	{
+// 		bool found = false;
+// 		for (std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) 
+// 		{
+// 			if (it->second->id == constituentID) 
+// 			{
+// 				found = true;
+// 				break;
+// 			}
+// 		}
+// 		if (!found)
+// 			return false;
+// 	}
+// 
+// 	return true;
+// }
 
 CArtifact::CArtifact()
 {
@@ -875,11 +875,11 @@ CArtifactInstance::CArtifactInstance( CArtifact *Art)
 
 }
 
-CArtifactInstance::CArtifactInstance(int aid)
-{
-	init();
-	setType(VLC->arth->artifacts[aid]);
-}
+// CArtifactInstance::CArtifactInstance(int aid)
+// {
+// 	init();
+// 	setType(VLC->arth->artifacts[aid]);
+// }
 
 void CArtifactInstance::setType( CArtifact *Art )
 {
@@ -909,7 +909,7 @@ int CArtifactInstance::firstAvailableSlot(const CGHeroInstance *h) const
 {
 	BOOST_FOREACH(ui16 slot, artType->possibleSlots)
 	{
-		if(artType->fitsAt(h->artifWorn, slot))
+		if(canBePutAt(ArtifactLocation(h, slot))) //if(artType->fitsAt(h->artifWorn, slot))
 		{
 			//we've found a free suitable slot.
 			return slot;
@@ -987,15 +987,27 @@ bool CArtifactInstance::canBeDisassembled() const
 std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CGHeroInstance *h) const
 {
 	std::vector<const CArtifact *> ret;
-	if(!artType->constituentOf)
+	if(!artType->constituentOf //not a part of combined artifact
+		|| artType->constituents) //combined artifact already: no combining of combined artifacts... for now.
 		return ret;
 
-	BOOST_FOREACH(ui32 combination, *artType->constituentOf) 
+	BOOST_FOREACH(ui32 possibleCombinedArt, *artType->constituentOf) 
 	{
-		if (artType->canBeAssembledTo(h->artifWorn, combination)) 
+		const CArtifact * const artifact = VLC->arth->artifacts[possibleCombinedArt];
+		assert(artifact->constituents);
+		bool possible = true;
+
+		BOOST_FOREACH(ui32 constituentID, *artifact->constituents) //check if all constituents are available
 		{
-			ret.push_back(VLC->arth->artifacts[combination]);
+			if(!h->hasArt(constituentID, true)) //constituent must be equipped
+			{
+				possible = false;
+				break;
+			}
 		}
+
+		if(possible)
+			ret.push_back(artifact);
 	}
 
 	return ret;
@@ -1007,6 +1019,19 @@ void CArtifactInstance::move(ArtifactLocation &src, ArtifactLocation &dst)
 	putAt(dst.hero, dst.slot);
 }
 
+CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
+{
+	if(!Art->constituents)
+		return new CArtifactInstance(Art);
+	else
+		return new CCombinedArtifactInstance(Art);
+}
+
+CArtifactInstance * CArtifactInstance::createNewArtifactInstance(int aid)
+{
+	return createNewArtifactInstance(VLC->arth->artifacts[aid]);
+}
+
 bool CCombinedArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved /*= false*/) const
 {
 	return CArtifactInstance::canBePutAt(al, assumeDestRemoved);
@@ -1016,4 +1041,32 @@ bool CCombinedArtifactInstance::canBePutAt(const ArtifactLocation &al, bool assu
 bool CCombinedArtifactInstance::canBeDisassembled() const
 {
 	return true;
+}
+
+CCombinedArtifactInstance::CCombinedArtifactInstance(CArtifact *Art)
+	: CArtifactInstance(Art)
+{
+}
+
+CCombinedArtifactInstance::CCombinedArtifactInstance()
+{
+
+}
+
+void CCombinedArtifactInstance::createConstituents()
+{
+	assert(artType);
+	assert(artType->constituents);
+
+	BOOST_FOREACH(ui32 a, *artType->constituents)
+	{
+		constituentsInfo.push_back(ConstituentInfo(CArtifactInstance::createNewArtifactInstance(a)));
+	}
+}
+
+
+CCombinedArtifactInstance::ConstituentInfo::ConstituentInfo(CArtifactInstance *Art /*= NULL*/, ui16 Slot /*= -1*/)
+{
+	art = Art;
+	slot = Slot;
 }

+ 34 - 6
lib/CArtHandler.h

@@ -32,7 +32,7 @@ public:
 	bool isBig () const;
 	bool isModable () const;
 	bool fitsAt (const std::map<ui16, const CArtifact*> &artifWorn, ui16 slot) const;
-	bool canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const;
+	//bool canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const;
 	void addBonusesTo (BonusList *otherBonuses) const;
 	void removeBonusesFrom (BonusList *otherBonuses) const;
 	virtual void SetProperty (int mod){};
@@ -49,7 +49,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CBonusSystemNode&>(*this);;
+		h & static_cast<CBonusSystemNode&>(*this);
 		h & name & description & price & possibleSlots & constituents & constituentOf & aClass & id;
 	}
 
@@ -62,14 +62,16 @@ public:
 
 class DLL_EXPORT CArtifactInstance : public CBonusSystemNode
 {
+protected:
 	void init();
+	CArtifactInstance(CArtifact *Art);
 public:
+	CArtifactInstance();
+
 	ConstTransitivePtr<CArtifact> artType; 
 	si32 id; //id of the instance
 
-	CArtifactInstance();
-	CArtifactInstance(CArtifact *Art);
-	CArtifactInstance(int aid);
+	//CArtifactInstance(int aid);
 
 	std::string nodeName() const OVERRIDE;
 	void setType(CArtifact *Art);
@@ -79,7 +81,6 @@ public:
 
 	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);
@@ -93,13 +94,40 @@ public:
 	}
 
 	static CArtifactInstance *createScroll(const CSpell *s);
+	static CArtifactInstance *createNewArtifactInstance(CArtifact *Art);
+	static CArtifactInstance *createNewArtifactInstance(int aid);
 };
 
 class DLL_EXPORT CCombinedArtifactInstance : public CArtifactInstance
 {
+	CCombinedArtifactInstance(CArtifact *Art);
 public:
+	struct ConstituentInfo
+	{
+		ConstTransitivePtr<CArtifactInstance> art;
+		si16 slot;
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & art & slot;
+		}
+
+		ConstituentInfo(CArtifactInstance *art = NULL, ui16 slot = -1);
+	};
+
+	std::vector<ConstituentInfo> constituentsInfo;
+
 	bool canBePutAt(const ArtifactLocation &al, bool assumeDestRemoved = false) const OVERRIDE;
 	bool canBeDisassembled() const OVERRIDE;
+
+	CCombinedArtifactInstance();
+	void createConstituents();
+
+	friend class CArtifactInstance;
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CArtifactInstance&>(*this);
+		h & constituentsInfo;
+	}
 };
 
 class DLL_EXPORT IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner

+ 3 - 1
lib/CCampaignHandler.cpp

@@ -522,7 +522,9 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
 			{
 				BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
 				{
-					cgh->artifacts -= VLC->arth->artifacts[g];
+					tlog1 << "TODO TODO TODO - take artifacts from hero\n";
+					//TODO how was that supposed to work with worn artifacts?
+					//cgh->artifactsInBackpack -= VLC->arth->artifacts[g];
 				}
 			}
 		}

+ 2 - 6
lib/CGameState.cpp

@@ -1379,11 +1379,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
  				toGive = VLC->arth->artifacts[VLC->arth->getRandomArt (CArtifact::ART_TREASURE)];
 
 				CGHeroInstance *hero = k->second.heroes[0];
-				std::vector<ui16>::iterator slot = vstd::findFirstNot (hero->artifWorn, toGive->possibleSlots);
-				if(slot != toGive->possibleSlots.end())
-					VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive);
-				else
- 					hero->giveArtifact(toGive->id);
+ 				hero->giveArtifact(toGive->id);
 			}
 		}
 	}
@@ -2675,7 +2671,7 @@ struct statsHLP
 		int ret = 0;
 		for(int g=0; g<ps->heroes.size(); ++g)
 		{
-			ret += ps->heroes[g]->artifacts.size() + ps->heroes[g]->artifWorn.size();
+			ret += ps->heroes[g]->artifactsInBackpack.size() + ps->heroes[g]->artifactsWorn.size();
 		}
 		return ret;
 	}

+ 27 - 20
lib/CObjectHandler.cpp

@@ -791,10 +791,10 @@ void CGHeroInstance::initHero()
 		spells -= 0xffffffff;
 
 	if(!getArt(Arts::MACH4) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set -> use default rules for spellbook
-		putArtifact(Arts::SPELLBOOK, new CArtifactInstance(0));
+		putArtifact(Arts::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
 
 	if(!getArt(Arts::MACH4))
-		putArtifact(Arts::MACH4, new CArtifactInstance(3)); //everyone has a catapult
+		putArtifact(Arts::MACH4, CArtifactInstance::createNewArtifactInstance(3)); //everyone has a catapult
 	
 	if(portrait < 0 || portrait == 255)
 		portrait = subID;
@@ -878,7 +878,7 @@ void CGHeroInstance::initArmy(CCreatureSet *dst /*= NULL*/)
 			}
 
 			if(!getArt(slot))
-				putArtifact(slot, new CArtifactInstance(aid));
+				putArtifact(slot, CArtifactInstance::createNewArtifactInstance(aid));
 			else
 				tlog3 << "Hero " << name << " already has artifact at " << slot << ", ommiting giving " << aid << std::endl;
 		}
@@ -1429,22 +1429,24 @@ si32 CGHeroInstance::manaRegain() const
 void CGHeroInstance::giveArtifact (ui32 aid) //use only for fixed artifacts
 {
 	CArtifact * const artifact = VLC->arth->artifacts[aid]; //pointer to constant object
-
-	if (artifact->isBig()) 
-	{
-		for (std::vector<ui16>::const_iterator it = artifact->possibleSlots.begin(); it != artifact->possibleSlots.end(); ++it) 
-		{
-			if (!vstd::contains(artifWorn, *it)) 
-			{
-				VLC->arth->equipArtifact(artifWorn, *it, artifact);
-				break;
-			}
-		}
-	} 
-	else 
-	{
-		artifacts.push_back(artifact);
-	}
+	CArtifactInstance *ai = CArtifactInstance::createNewArtifactInstance(artifact);
+	ai->putAt(this, ai->firstAvailableSlot(this));
+// 
+// 	if (artifact->isBig()) 
+// 	{
+// 		for (std::vector<ui16>::const_iterator it = artifact->possibleSlots.begin(); it != artifact->possibleSlots.end(); ++it) 
+// 		{
+// 			if (!vstd::contains(artifWorn, *it)) 
+// 			{
+// 				VLC->arth->equipArtifact(artifWorn, *it, artifact);
+// 				break;
+// 			}
+// 		}
+// 	} 
+// 	else 
+// 	{
+// 		artifacts.push_back(artifact);
+// 	}
 }
 
 int CGHeroInstance::getBoatType() const
@@ -1576,6 +1578,11 @@ void CGHeroInstance::putInBackpack(CArtifactInstance *art)
 	putArtifact(art->firstBackpackSlot(this), art);
 }
 
+bool CGHeroInstance::hasSpellbook() const
+{
+	return getArt(Arts::SPELLBOOK);
+}
+
 void CGDwelling::initObj()
 {
 	switch(ID)
@@ -7016,4 +7023,4 @@ si32 CArtifactSet::getArtTypeId(ui16 pos) const
 CArtifactSet::~CArtifactSet()
 {
 
-}
+}

+ 4 - 3
lib/CObjectHandler.h

@@ -315,8 +315,8 @@ public:
 	const CGBoat *boat; //set to CGBoat when sailing
 	
 
-	std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
-	std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+	//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
+	//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 	std::set<ui32> spells; //known spells (spell IDs)
 
 
@@ -350,7 +350,7 @@ public:
 		h & static_cast<CArmedInstance&>(*this);
 		h & static_cast<CArtifactSet&>(*this);
 		h & exp & level & name & biography & portrait & mana & secSkills & movement
-			& sex & inTownGarrison & artifacts & artifWorn & spells & patrol & moveDir;
+			& sex & inTownGarrison & /*artifacts & artifWorn & */spells & patrol & moveDir;
 
 		h & type & speciality;
 		//visitied town pointer will be restored by map serialization method
@@ -368,6 +368,7 @@ public:
 
 	//////////////////////////////////////////////////////////////////////////
 	
+	bool hasSpellbook() const;
 	EAlignment getAlignment() const;
 	const std::string &getBiography() const;
 	bool needsLastStack()const;

+ 19 - 19
lib/NetPacks.h

@@ -604,25 +604,25 @@ struct SetHeroesInTown : public CPackForClient //508
 	}
 };
 
-struct SetHeroArtifacts : public CPackForClient //509
-{
-	SetHeroArtifacts(){type = 509;};
-	void applyCl(CClient *cl);
-	DLL_EXPORT void applyGs(CGameState *gs);
-	DLL_EXPORT void setArtAtPos(ui16 pos, const CArtifact* art);
-
-	si32 hid;
-	std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
-	std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & hid & artifacts & artifWorn;
-	}
-
-	std::vector<const CArtifact*> equiped, unequiped; //used locally
-	BonusList gained, lost; //used locally as hlp when applying
-};   
+// struct SetHeroArtifacts : public CPackForClient //509
+// {
+// 	SetHeroArtifacts(){type = 509;};
+// 	void applyCl(CClient *cl);
+// 	DLL_EXPORT void applyGs(CGameState *gs);
+// 	DLL_EXPORT void setArtAtPos(ui16 pos, const CArtifact* art);
+// 
+// 	si32 hid;
+// 	std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
+// 	std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
+// 
+// 	template <typename Handler> void serialize(Handler &h, const int version)
+// 	{
+// 		h & hid & artifacts & artifWorn;
+// 	}
+// 
+// 	std::vector<const CArtifact*> equiped, unequiped; //used locally
+// 	BonusList gained, lost; //used locally as hlp when applying
+// };   
 
 struct HeroRecruited : public CPackForClient //515
 {

+ 45 - 43
lib/NetPacksLib.cpp

@@ -288,6 +288,8 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
 		gs->hpool.heroesPool[h->subID] = h;
 		if(!vstd::contains(gs->hpool.pavailable, h->subID))
 			gs->hpool.pavailable[h->subID] = 0xff;
+
+		return;
 	}
 	else if (obj->ID==CREI_TYPE  &&  gs->map->version > CMapHeader::RoE) //only fixed monsters can be a part of quest
 	{
@@ -443,48 +445,48 @@ DLL_EXPORT void SetHeroesInTown::applyGs( CGameState *gs )
 	}
 }
 
-DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
-{
-	CGHeroInstance *h = gs->getHero(hid);
-	for(std::map<ui16, const CArtifact*>::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++)
-		if(!vstd::contains(artifWorn,i->first)  ||  artifWorn[i->first] != i->second)
-			unequiped.push_back(i->second);
-
-	for(std::map<ui16, const CArtifact*>::iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
-		if(!vstd::contains(h->artifWorn,i->first)  ||  h->artifWorn[i->first] != i->second)
-		{
-			equiped.push_back(i->second);
-		}
-
-	//update hero data
-	h->artifacts = artifacts;
-	h->artifWorn = artifWorn;
-}
-
-DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, const CArtifact* art)
-{
-	if(!art)
-	{
-		if(pos<19)
-			VLC->arth->unequipArtifact(artifWorn, pos);
-		else if (pos - 19 < artifacts.size())
-			artifacts.erase(artifacts.begin() + (pos - 19));
-	}
-	else
-	{
-		if (pos < 19) 
-		{
-			VLC->arth->equipArtifact(artifWorn, pos, art);
-		} 
-		else // Goes into the backpack.
-		{ 
-			if(pos - 19 < artifacts.size())
-				artifacts.insert(artifacts.begin() + (pos - 19), art);
-			else
-				artifacts.push_back(art);
-		}
-	}
-}
+// DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
+// {
+// 	CGHeroInstance *h = gs->getHero(hid);
+// 	for(std::map<ui16, const CArtifact*>::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++)
+// 		if(!vstd::contains(artifWorn,i->first)  ||  artifWorn[i->first] != i->second)
+// 			unequiped.push_back(i->second);
+// 
+// 	for(std::map<ui16, const CArtifact*>::iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+// 		if(!vstd::contains(h->artifWorn,i->first)  ||  h->artifWorn[i->first] != i->second)
+// 		{
+// 			equiped.push_back(i->second);
+// 		}
+// 
+// 	//update hero data
+// 	h->artifacts = artifacts;
+// 	h->artifWorn = artifWorn;
+// }
+// 
+// DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, const CArtifact* art)
+// {
+// 	if(!art)
+// 	{
+// 		if(pos<19)
+// 			VLC->arth->unequipArtifact(artifWorn, pos);
+// 		else if (pos - 19 < artifacts.size())
+// 			artifacts.erase(artifacts.begin() + (pos - 19));
+// 	}
+// 	else
+// 	{
+// 		if (pos < 19) 
+// 		{
+// 			VLC->arth->equipArtifact(artifWorn, pos, art);
+// 		} 
+// 		else // Goes into the backpack.
+// 		{ 
+// 			if(pos - 19 < artifacts.size())
+// 				artifacts.insert(artifacts.begin() + (pos - 19), art);
+// 			else
+// 				artifacts.push_back(art);
+// 		}
+// 	}
+// }
 
 
 DLL_EXPORT void HeroRecruited::applyGs( CGameState *gs )
@@ -588,7 +590,7 @@ DLL_EXPORT void NewArtifact::applyGs( CGameState *gs )
 	gs->map->artInstances.push_back(art);
 
 	assert(!art->parents.size());
-	art->attachTo(art->artType);
+	art->setType(art->artType);
 }
 
 DLL_EXPORT const CStackInstance * StackLocation::getStack()

+ 4 - 1
lib/RegisterTypes.cpp

@@ -79,6 +79,9 @@ void registerTypes1(Serializer &s)
 	s.template registerType<CreatureNativeTerrainLimiter>();
 	s.template registerType<CreatureFactionLimiter>();
 	s.template registerType<CreatureAlignmentLimiter>();
+
+	s.template registerType<CArtifactInstance>();
+	s.template registerType<CCombinedArtifactInstance>();
 }
 
 template<typename Serializer> DLL_EXPORT 
@@ -110,7 +113,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<RazeStructures>();
 	s.template registerType<SetAvailableCreatures>();
 	s.template registerType<SetHeroesInTown>();
-	s.template registerType<SetHeroArtifacts>();
+	//s.template registerType<SetHeroArtifacts>();
 	s.template registerType<HeroRecruited>();
 	s.template registerType<GiveHero>();
 	s.template registerType<NewTurn>();

+ 8 - 4
lib/map.cpp

@@ -2037,8 +2037,12 @@ bool Mapa::loadArtifactToSlot(CGHeroInstance *h, int slot, const unsigned char *
 	int aid = readNormalNr(bufor,i, artidlen); i+=artidlen;
 	bool isArt  =  aid != artmask;
 	if(isArt)
-		h->putArtifact(slot, createArt(aid));
-
+	{
+		if(vstd::contains(VLC->arth->bigArtifacts, aid) && slot >= Arts::BACKPACK_START)
+			tlog3 << "Warning: A big artifact (war machine) in hero's backpack, ignoring...\n";
+		else
+			h->putArtifact(slot, createArt(aid));
+	}
 	return isArt;
 }
 
@@ -2068,7 +2072,7 @@ void Mapa::loadArtifactsOfHero(const unsigned char * bufor, int & i, CGHeroInsta
 		//bag artifacts //20
 		int amount = readNormalNr(bufor,i, 2); i+=2; //number of artifacts in hero's bag
 		for(int ss = 0; ss < amount; ++ss)
-			loadArtifactToSlot(nhi, Arts::BACKPACK_START + ss, bufor, i);
+			loadArtifactToSlot(nhi, Arts::BACKPACK_START + nhi->artifactsInBackpack.size(), bufor, i);
 	} //artifacts
 }
 
@@ -2076,7 +2080,7 @@ CArtifactInstance * Mapa::createArt(int aid)
 {
 	CArtifactInstance *a = NULL;
 	if(aid >= 0)
-		a = new CArtifactInstance(aid);
+		a = CArtifactInstance::createNewArtifactInstance(aid);
 	else
 		a = new CArtifactInstance();
 

+ 29 - 31
server/CGameHandler.cpp

@@ -1190,7 +1190,7 @@ void CGameHandler::checkForBattleEnd( std::vector<CStack*> &stacks )
 
 void CGameHandler::giveSpells( const CGTownInstance *t, const CGHeroInstance *h )
 {
-	if(!vstd::contains(h->artifWorn,17))
+	if(!h->hasSpellbook())
 		return; //hero hasn't spellbok
 	ChangeSpells cs;
 	cs.hid = h->id;
@@ -1759,7 +1759,7 @@ void CGameHandler::useScholarSkill(si32 fromHero, si32 toHero)
 	}
 
 	int ScholarLevel = h1->getSecSkillLevel(CGHeroInstance::SCHOLAR);//heroes can trade up to this level
-	if (!ScholarLevel || !vstd::contains(h1->artifWorn,17) || !vstd::contains(h2->artifWorn,17) )
+	if (!ScholarLevel || !h1->hasSpellbook() || !h2->hasSpellbook() )
 		return;//no scholar skill or no spellbook
 
 	int h1Lvl = std::min(ScholarLevel+1, h1->getSecSkillLevel(CGHeroInstance::WISDOM)+2),
@@ -2707,7 +2707,7 @@ bool CGameHandler::buyArtifact( ui32 hid, si32 aid )
 	else if(aid < 7  &&  aid > 3) //war machine
 	{
 		int price = VLC->arth->artifacts[aid]->price;
-		if(vstd::contains(hero->artifWorn,ui16(9+aid)) && complain("Hero already has this machine!")
+		if(hero->getArt(9+aid) && complain("Hero already has this machine!")
 			|| !vstd::contains(town->builtBuildings,si32(16)) && complain("No blackismith!")
 			|| gs->getPlayer(hero->getOwner())->resources[Res::GOLD] < price  && complain("Not enough gold!")  //no gold
 			|| (!(town->subID == 6 && vstd::contains(town->builtBuildings,si32(22) ) )
@@ -3326,7 +3326,6 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 	{
 		SetMana sm;
 		ChangeSpells cs;
-		SetHeroArtifacts sha;
 
 		CGHeroInstance *h = gs->getHero(gs->getPlayer(player)->currentSelection);
 		if(!h && complain("Cannot realize cheat, no hero selected!")) return;
@@ -3344,15 +3343,8 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		//give mana
 		sm.val = 999;
 
-		if(!h->getArt(17)) //hero doesn't have spellbook
-		{
-			//give spellbook
-			sha.hid = h->id;
-			sha.artifacts = h->artifacts;
-			sha.artifWorn = h->artifWorn;
-			VLC->arth->equipArtifact(sha.artifWorn, 17, 0);
-			sendAndApply(&sha);
-		}
+		if(!h->hasSpellbook()) //hero doesn't have spellbook
+			giveHeroNewArtifact(h, VLC->arth->artifacts[0], Arts::SPELLBOOK); //give spellbook
 
 		sendAndApply(&cs);
 		sendAndApply(&sm);
@@ -3381,14 +3373,13 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 	{
 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
 		if(!hero) return;
-		SetHeroArtifacts sha;
-		sha.hid = hero->id;
-		sha.artifacts = hero->artifacts;
-		sha.artifWorn = hero->artifWorn;
-		VLC->arth->equipArtifact(sha.artifWorn, 13, VLC->arth->artifacts[4]);
-		VLC->arth->equipArtifact(sha.artifWorn, 14, VLC->arth->artifacts[5]);
-		VLC->arth->equipArtifact(sha.artifWorn, 15, VLC->arth->artifacts[6]);
-		sendAndApply(&sha);
+
+		if(!hero->getArt(Arts::MACH1))
+			giveHeroNewArtifact(hero, VLC->arth->artifacts[4], Arts::MACH1);
+		if(!hero->getArt(Arts::MACH2))
+			giveHeroNewArtifact(hero, VLC->arth->artifacts[5], Arts::MACH2);
+		if(!hero->getArt(Arts::MACH3))
+			giveHeroNewArtifact(hero, VLC->arth->artifacts[6], Arts::MACH3);
 	}
 	else if(message == "vcminahar") //1000000 movement points
 	{
@@ -3440,16 +3431,19 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 	{
 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
 		if(!hero) return;
-		SetHeroArtifacts sha;
-		sha.hid = hero->id;
-		sha.artifacts = hero->artifacts;
-		sha.artifWorn = hero->artifWorn;
-		sha.artifacts.push_back(VLC->arth->artifacts[2]); //grail
 		for (int g=7; g<=140; ++g)
-		{
-			sha.artifacts.push_back(VLC->arth->artifacts[g]);
-		}
-		sendAndApply(&sha);
+			giveHeroNewArtifact(hero, VLC->arth->artifacts[g], -1);
+
+// 		SetHeroArtifacts sha;
+// 		sha.hid = hero->id;
+// 		sha.artifacts = hero->artifacts;
+// 		sha.artifWorn = hero->artifWorn;
+// 		sha.artifacts.push_back(VLC->arth->artifacts[2]); //grail
+// 		for (int g=7; g<=140; ++g)
+// 		{
+// 			sha.artifacts.push_back(VLC->arth->artifacts[g]);
+// 		}
+// 		sendAndApply(&sha);
 	}
 	else
 		cheated = false;
@@ -5037,7 +5031,11 @@ void CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat
 
 void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *artType, int pos)
 {
-	CArtifactInstance *a = new CArtifactInstance();
+	CArtifactInstance *a = NULL;
+	if(artType->constituents)
+		a = new CArtifactInstance();
+	else
+		a = new CCombinedArtifactInstance();
 	a->artType = artType; //*NOT* via settype -> all bonus-related stuff must be done by NewArtifact apply
 	
 	NewArtifact na;