Ver código fonte

Redesigned artifact randomization.

Fixed #119, #128, #433, #493
DjWarmonger 15 anos atrás
pai
commit
12f6d5a380

+ 79 - 6
hch/CArtHandler.cpp

@@ -9,6 +9,7 @@
 #include <boost/assign/list_of.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
+#include <boost/random/linear_congruential.hpp>
 #include "../lib/VCMI_Lib.h"
 extern CLodHandler *bitmaph;
 using namespace boost::assign;
@@ -23,6 +24,8 @@ using namespace boost::assign;
  *
  */
 
+extern boost::rand48 ran;
+
 const std::string & CArtifact::Name() const
 {
 	if(name.size())
@@ -349,26 +352,96 @@ int CArtHandler::convertMachineID(int id, bool creToArt )
 
 void CArtHandler::sortArts()
 {
-	for(int i=0;i<144;i++) //do 144, bo nie chcemy bzdurek
+	for (int i=0; i<allowedArtifacts.size(); ++i) //do 144, bo nie chcemy bzdurek
 	{
-		switch (artifacts[i]->aClass)
+		switch (allowedArtifacts[i]->aClass)
 		{
 		case CArtifact::ART_TREASURE:
-			treasures.push_back(artifacts[i]);
+			treasures.push_back(allowedArtifacts[i]);
 			break;
 		case CArtifact::ART_MINOR:
-			minors.push_back(artifacts[i]);
+			minors.push_back(allowedArtifacts[i]);
 			break;
 		case CArtifact::ART_MAJOR:
-			majors.push_back(artifacts[i]);
+			majors.push_back(allowedArtifacts[i]);
 			break;
 		case CArtifact::ART_RELIC:
-			relics.push_back(artifacts[i]);
+			relics.push_back(allowedArtifacts[i]);
 			break;
 		}
 	}
 }
+void CArtHandler::erasePickedArt (si32 id)
+{
+	std::vector<CArtifact*>* ptr;
+	CArtifact *art = artifacts[id];
+	switch (art->aClass)
+	{
+		case CArtifact::ART_TREASURE:
+			ptr = &treasures;
+			break;
+		case CArtifact::ART_MINOR:
+			ptr = &minors;
+			break;
+		case CArtifact::ART_MAJOR:
+			ptr = &majors;
+			break;
+		case CArtifact::ART_RELIC:
+			ptr = &relics;
+			break;
+		default: //special artifacts should not be erased
+			return;
+	}
+	ptr->erase (std::find(ptr->begin(), ptr->end(), art)); //remove the artifact from avaliable list
+}
+ui16 CArtHandler::getRandomArt(int flags)
+{
+	std::vector<CArtifact*> out;
+	getAllowed(out, flags);
+	ui16 id = out[ran() % out.size()]->id;
+	erasePickedArt (id);
+	return id;
+}
+ui16 CArtHandler::getArtSync (ui32 rand, int flags)
+{
+	std::vector<CArtifact*> out;
+	getAllowed(out, flags);
+	CArtifact *art = out[rand % out.size()];
+	return art->id;	
+}
+void CArtHandler::getAllowed(std::vector<CArtifact*> &out, int flags)
+{
+	if (flags & CArtifact::ART_TREASURE)
+		getAllowedArts (out, &treasures, CArtifact::ART_TREASURE);
+	if (flags & CArtifact::ART_MINOR)
+		getAllowedArts (out, &minors, CArtifact::ART_MINOR);
+	if (flags & CArtifact::ART_MAJOR)
+		getAllowedArts (out, &majors, CArtifact::ART_MAJOR);
+	if (flags & CArtifact::ART_RELIC)
+		getAllowedArts (out, &relics, CArtifact::ART_RELIC);
+	if (!out.size()) //no arts are avaliable
+	{
+		out.resize (64);
+		std::fill_n (out.begin(), 64, artifacts[2]); //magic
+	}
+}
+void CArtHandler::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> *arts, int flag)
+{
+	if (arts->empty()) //restock avaliable arts
+	{
+		for (int i = 0; i < allowedArtifacts.size(); ++i)
+		{
+			if (allowedArtifacts[i]->aClass == flag)
+				arts->push_back(allowedArtifacts[i]);
+		}
+	}
 
+	for (int i = 0; i < arts->size(); ++i)
+	{
+		CArtifact *art = (*arts)[i];
+		out.push_back(art);
+	}
+}
 void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType )
 {
 	Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);

+ 8 - 3
hch/CArtHandler.h

@@ -51,12 +51,18 @@ class DLL_EXPORT CArtHandler //handles artifacts
 public:
 	std::vector<CArtifact*> treasures, minors, majors, relics;
 	std::vector<CArtifact *> artifacts;
+	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();
 	void addBonuses();
 	void clear();
+	ui16 getRandomArt (int flags);
+	ui16 getArtSync (ui32 rand, int flags);
+	void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> *arts, int flag);
+	void getAllowed(std::vector<CArtifact*> &out, int flags);
+	void erasePickedArt (si32 id);
 	bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();}
 	void equipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID, ui32 artifactID, BonusList *bonuses = NULL);
 	void unequipArtifact (std::map<ui16, ui32> &artifWorn, ui16 slotID, BonusList *bonuses = NULL);
@@ -66,9 +72,8 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & artifacts;
-		if(!h.saving)
-			sortArts();
+		h & artifacts & allowedArtifacts & treasures & minors & majors & relics;
+		//if(!h.saving) sortArts();
 	}
 };
 

+ 30 - 51
hch/CObjectHandler.cpp

@@ -1767,39 +1767,6 @@ void CGTownInstance::newTurn() const
 				cb->setObjProperty (id, 12, (*i)->id); //reset visitors for Mana Vortex
 		}
 	}
-
-	if(cb->getDate(2) == 1) //reset on new month
-	{
-		std::vector<CArtifact*>::iterator index;
-		for (ui8 i = 0; i < 3; ++i) //each tier
-		{	
-			int count = 0;
-			std::vector<CArtifact*> arts; //to avoid addition of different tiers
-			switch (i)
-			{
-			case 0:
-				cb->getAllowed (arts, CArtifact::ART_TREASURE);
-				count = 3; // first row - three treasures,
-				break;
-			case 1:
-				cb->getAllowed (arts, CArtifact::ART_MINOR);
-				count = 3; // second row three minors
-				break;
-			case 2:
-				cb->getAllowed (arts, CArtifact::ART_MAJOR);
-				count = 1; // and a third row - one major
-				break;
-			}
-			for (ui8 n = 0; n < count; n++)
-			{
-				
-// 				index = arts.begin() + val % arts.size();
-// 				advMapArts [advMapArts.size()] = new Component (Component::ARTIFACT, (*index)->id, 0, 0);
-// 				arts.erase(index);
-// 				val *= (id + n * i); //randomize
-			}
-		}
-	}
 }
 
 int3 CGTownInstance::getSightCenter() const
@@ -5023,25 +4990,12 @@ void CBank::reset(ui16 var1) //prevents desync
 void CBank::initialize() const
 {
 	cb->setObjProperty (id, 14, ran()); //synchronous reset
+	ui32 artid;
 	for (ui8 i = 0; i <= 3; i++)
 	{
 		for (ui8 n = 0; n < bc->artifacts[i]; n++) //new function using proper randomization algorithm
-		{
-			switch (i)
-			{
-				case 0:
-					cb->setObjProperty(id, 18, cb->getRandomArt (CArtifact::ART_TREASURE));
-					break;
-				case 1:
-					cb->setObjProperty(id, 18, cb->getRandomArt (CArtifact::ART_MINOR));
-					break;
-				case 2:
-					cb->setObjProperty(id, 18, cb->getRandomArt (CArtifact::ART_MAJOR));
-					break;
-				case 3:
-					cb->setObjProperty(id, 18, cb->getRandomArt (CArtifact::ART_RELIC));
-					break;				
-			}
+		{	
+				cb->setObjProperty (id, 18 + i, ran()); //synchronic
 		}
 	}
 }
@@ -5052,7 +5006,7 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
 	{
 		case 11: //daycounter
 			if (val == 0)
-				daycounter = 0;
+				daycounter = 1; //yes, 1
 			else
 				daycounter++;
 			break;
@@ -5118,8 +5072,33 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
 			}
 			break;
 		case 18: //add Artifact
-			artifacts.push_back (val);
+		{
+			int id = cb->getArtSync(val, CArtifact::ART_TREASURE);
+			artifacts.push_back (id);
+			cb->erasePickedArt(id);
+			break;
+		}
+		case 19: //add Artifact
+		{
+			int id = cb->getArtSync(val, CArtifact::ART_MINOR);
+			artifacts.push_back (id);
+			cb->erasePickedArt(id);
+			break;
+		}
+		case 20: //add Artifact
+		{
+			int id = cb->getArtSync(val, CArtifact::ART_MAJOR);
+			artifacts.push_back (id);
+			cb->erasePickedArt(id);
 			break;
+		}
+		case 21: //add Artifact
+		{
+			int id = cb->getArtSync(val, CArtifact::ART_RELIC);
+			artifacts.push_back (id);
+			cb->erasePickedArt(id);
+			break;
+		}
 	}
 }
 

+ 11 - 1
hch/CObjectHandler.h

@@ -302,6 +302,16 @@ public:
 			h & patrolling & patrolRadious;
 		}
 	} patrol;
+	struct DLL_EXPORT HeroSpecial : CBonusSystemNode
+	{
+		bool growthsWithLevel;
+		void RecalculateSpecials(){};
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & static_cast<CBonusSystemNode&>(*this);
+			h & growthsWithLevel;
+		}
+	} speciality;
 
 	//BonusList bonuses;
 	//////////////////////////////////////////////////////////////////////////
@@ -313,7 +323,7 @@ public:
 		h & exp & level & name & biography & portrait & mana & secSkills & movement
 			& sex & inTownGarrison & artifacts & artifWorn & spells & patrol & moveDir;
 
-		h & type;
+		h & type & speciality;
 		//visitied town pointer will be restored by map serialization method
 	}
 	//////////////////////////////////////////////////////////////////////////

+ 30 - 19
lib/CGameState.cpp

@@ -904,28 +904,16 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
 {
 	switch(obj->ID)
 	{
-	case 65: //random artifact
-		return std::pair<int,int>(5,(ran()%136)+7); //the only reasonable range - there are siege weapons and blanks we must ommit
-	case 66: //random treasure artifact
- 		return std::pair<int,int>(5,VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id);
-	case 67: //random minor artifact
- 		return std::pair<int,int>(5,VLC->arth->minors[ran()%VLC->arth->minors.size()]->id);
-	case 68: //random major artifact
-		return std::pair<int,int>(5,VLC->arth->majors[ran()%VLC->arth->majors.size()]->id);
-	case 69: //random relic artifact
-		return std::pair<int,int>(5,VLC->arth->relics[ran()%VLC->arth->relics.size()]->id);
-	/*
 	case 65: //random artifact //how the hell use IGameCallback for this?
-		return std::pair<int,int>(5, obj->cb->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
+		return std::pair<int,int>(5, VLC->arth->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
 	case 66: //random treasure artifact
-		return std::pair<int,int>(5, cb->getRandomArt(CArtifact::ART_TREASURE));
+		return std::pair<int,int>(5, VLC->arth->getRandomArt (CArtifact::ART_TREASURE));
 	case 67: //random minor artifact
-		return std::pair<int,int>(5, cb->getRandomArt (CArtifact::ART_MINOR));
+		return std::pair<int,int>(5, VLC->arth->getRandomArt (CArtifact::ART_MINOR));
 	case 68: //random major artifact
-		return std::pair<int,int>(5, cb->getRandomArt (CArtifact::ART_MAJOR));
+		return std::pair<int,int>(5, VLC->arth->getRandomArt (CArtifact::ART_MAJOR));
 	case 69: //random relic artifact
-		return std::pair<int,int>(5, cb->getRandomArt (CArtifact::ART_RELIC));
-		*/
+		return std::pair<int,int>(5, VLC->arth->getRandomArt (CArtifact::ART_RELIC));
 	case 70: //random hero
 		{
 			return std::pair<int,int>(HEROI_TYPE,pickHero(obj->tempOwner));
@@ -1185,6 +1173,11 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 	{
 	case 0:
 		map = new Mapa(si->mapname);
+		for (int i=0; i<144; ++i) //yes, 144
+		{
+			if (map->allowedArtifact[i])
+				VLC->arth->allowedArtifacts.push_back(VLC->arth->artifacts[i]);
+		}
 		break;
 	case 2:
 		campaign = new CCampaignState();
@@ -1192,6 +1185,11 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 		std::string &mapContent = campaign->camp->mapPieces[si->whichMapInCampaign];
 		map = new Mapa();
 		map->initFromBytes((const unsigned char*)mapContent.c_str());
+		for (int i=0; i<144; ++i)
+		{
+			if (map->allowedArtifact[i])
+				VLC->arth->allowedArtifacts.push_back(VLC->arth->artifacts[i]);
+		}
 		break;
 	}
 	tlog0 << "Map loaded!" << std::endl;
@@ -3816,11 +3814,24 @@ PlayerState::PlayerState()
 
 void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
 {
-	//TODO: global effects
+	/*
+	for (std::vector<CGHeroInstance *>::const_iterator it = heroes.begin(); it != heroes.end(); ++it)
+	{
+		if (*it != root)
+			(*it)->getParents(out, root);
+	}
+	for (std::vector<CGTownInstance *>::const_iterator it = towns.begin(); it != towns.end(); ++it)
+	{
+		if (*it != root)
+			(*it)->getParents(out, root);
+	}
+	*/
+	//TODO - dwellings
 }
 
 void PlayerState::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
-{
+{//temporary
+	//CBonusSystemNode::getBonuses(out, selector, root);
 }
 
 InfoAboutHero::InfoAboutHero()

+ 10 - 59
lib/IGameCallback.cpp

@@ -175,27 +175,6 @@ bool IGameCallback::isAllowed( int type, int id )
 	}
 }
 
-void IGameCallback::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts, int flag)
-{
-	if (!(VLC->arth->*arts).size()) //restock avaliable arts
-	{
-		for (int i = 0; i < VLC->arth->artifacts.size(); i++)
-		{
-			if (VLC->arth->artifacts[i]->aClass == flag)
-				(VLC->arth->*arts).push_back(VLC->arth->artifacts[i]);
-		}
-	}
-
-	for (int i = 0; i < (VLC->arth->*arts).size(); i++)
-	{
-		CArtifact *art = (VLC->arth->*arts)[i];
-		if(isAllowed(1, art->id))
-		{
-			out.push_back(art);
-		}
-	}
-}
-
 void IGameCallback::pickAllowedArtsSet(std::vector<const CArtifact*> &out)
 {
 	for (int i = 0; i < 2; i++)
@@ -208,50 +187,22 @@ void IGameCallback::pickAllowedArtsSet(std::vector<const CArtifact*> &out)
 	out.push_back(VLC->arth->artifacts[getRandomArt(CArtifact::ART_MAJOR)]);
 }
 
-void IGameCallback::getAllowed(std::vector<CArtifact*> &out, int flags)
+ui16 IGameCallback::getRandomArt (int flags)
 {
-	if(flags & CArtifact::ART_TREASURE)
-		getAllowedArts(out,&CArtHandler::treasures, CArtifact::ART_TREASURE);
-	if(flags & CArtifact::ART_MINOR)
-		getAllowedArts(out,&CArtHandler::minors, CArtifact::ART_MINOR);
-	if(flags & CArtifact::ART_MAJOR)
-		getAllowedArts(out,&CArtHandler::majors, CArtifact::ART_MAJOR);
-	if(flags & CArtifact::ART_RELIC)
-		getAllowedArts(out,&CArtHandler::relics, CArtifact::ART_RELIC);
-	if (!out.size()) //no arts are avaliable
-	{
-		out.resize(64);
-		std::fill_n(out.begin(), 64, VLC->arth->artifacts[2]); //magic
-	}
+	return VLC->arth->getRandomArt(flags);
 }
 
-ui16 IGameCallback::getRandomArt (int flags)
+ui16 IGameCallback::getArtSync (ui32 rand, int flags)
 {
-	std::vector<CArtifact*> out;
-	getAllowed(out, flags);
-	CArtifact *art = out[ran() % out.size()];
-	std::vector<CArtifact*>* ptr;
-	switch (art->aClass)
-	{
-		case CArtifact::ART_TREASURE:
-			ptr = &VLC->arth->treasures;
-			break;
-		case CArtifact::ART_MINOR:
-			ptr = &VLC->arth->minors;
-			break;
-		case CArtifact::ART_MAJOR:
-			ptr = &VLC->arth->majors;
-			break;
-		case CArtifact::ART_RELIC:
-			ptr = &VLC->arth->relics;
-			break;
-		default: //special artifacts should not be erased
-			return art->id;
-	}
-	ptr->erase (std::find(ptr->begin(), ptr->end(), art)); //remove the artifact from avaliable list
-	return art->id;
+	return VLC->arth->getArtSync (rand, flags);
 }
 
+void IGameCallback::erasePickedArt (si32 id)
+{
+	VLC->arth->erasePickedArt(id);
+}
+
+
 void IGameCallback::getAllowedSpells(std::vector<ui16> &out, ui16 level)
 {
 

+ 2 - 2
lib/IGameCallback.h

@@ -60,9 +60,9 @@ public:
 	virtual void getAllTiles (std::set<int3> &tiles, int player=-1, int level=-1, int surface=0); //returns all tiles on given level (-1 - both levels, otherwise number of level); surface: 0 - land and water, 1 - only land, 2 - only water
 	virtual bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact
 	virtual ui16 getRandomArt (int flags);
-	virtual void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts, int flag);
+	virtual ui16 getArtSync (ui32 rand, int flags); //synchronic
 	virtual void pickAllowedArtsSet(std::vector<const CArtifact*> &out); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
-	virtual void getAllowed(std::vector<CArtifact*> &out, int flags); //flags: bitfield uses EartClass
+	virtual void erasePickedArt (si32 id);
 	virtual void getAllowedSpells(std::vector<ui16> &out, ui16 level);
 	virtual int3 getMapSize(); //returns size of the map
 	virtual TerrainTile * getTile(int3 pos);

+ 0 - 1
server/CGameHandler.cpp

@@ -1906,7 +1906,6 @@ void CGameHandler::takeCreatures (int objid, TSlots creatures) //probably we cou
 		int slot = newArmy.getSlotFor(creatures.begin()->second.type->idNumber);
 		if (slot < 0)
 			break;
-		//newArmy.slots[slot].type = creatures.begin()->second.type;
 		newArmy.slots[slot].count -= creatures.begin()->second.count;
 		if (newArmy.getStack(slot).count < 1)
 			newArmy.eraseStack(slot);