Procházet zdrojové kódy

Implemented artifact placement rules for advMap objects, but not for the random artifacts placed via editor. (feature #119)

DjWarmonger před 16 roky
rodič
revize
1683a419a3
5 změnil soubory, kde provedl 119 přidání a 76 odebrání
  1. 70 67
      hch/CObjectHandler.cpp
  2. 2 1
      hch/CObjectHandler.h
  3. 2 0
      lib/CGameState.h
  4. 42 7
      lib/IGameCallback.cpp
  5. 3 1
      lib/IGameCallback.h

+ 70 - 67
hch/CObjectHandler.cpp

@@ -1201,6 +1201,8 @@ void CGHeroInstance::recreateArtBonuses()
 
 void CGDwelling::initObj()
 {
+	if (getOwner() != 255)
+		cb->gameState()->players[getOwner()].dwellings.push_back (this);
 	switch(ID)
 	{
 	case 17:
@@ -1272,7 +1274,14 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 	}
 
 	if(h->tempOwner != tempOwner)
+	{
+		std::vector<CGDwelling *>* dwellings = &(cb->gameState()->players[tempOwner].dwellings);
+		dwellings->erase (std::find(dwellings->begin(), dwellings->end(), this));
 		cb->setOwner(id, h->tempOwner);
+		dwellings = &(cb->gameState()->players[h->tempOwner].dwellings);
+		//dwellings->push_back (this);
+		//cb->gameState()->players[getOwner()].dwellings.push_back (this);
+	}
 
 	BlockingDialog bd;
 	bd.player = h->tempOwner;
@@ -2836,7 +2845,7 @@ void CGPickable::initObj()
 			else
 			{
 				val1 = 1000;
-				val2 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
+				val2 = cb->getRandomArt (CArtifact::ART_TREASURE);
 				type = 1;
 			}
 		}
@@ -2845,13 +2854,13 @@ void CGPickable::initObj()
 		{
 			int hlp = ran()%100;
 			if(hlp < 55)
-				val1 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
+				val1 = cb->getRandomArt (CArtifact::ART_TREASURE);
 			else if(hlp < 75)
-				val1 = VLC->arth->minors[ran()%VLC->arth->minors.size()]->id;
+				val1 = cb->getRandomArt (CArtifact::ART_MINOR);
 			else if(hlp < 95)
-				val1 = VLC->arth->majors[ran()%VLC->arth->majors.size()]->id;
+				val1 = cb->getRandomArt (CArtifact::ART_MAJOR);
 			else
-				val1 = VLC->arth->relics[ran()%VLC->arth->relics.size()]->id;
+				val1 = cb->getRandomArt (CArtifact::ART_RELIC);
 		}
 		break;
 	case 101: //treasure chest
@@ -2860,7 +2869,7 @@ void CGPickable::initObj()
 			if(hlp >= 95)
 			{
 				type = 1;
-				val1 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
+				val1 = cb->getRandomArt (CArtifact::ART_TREASURE);
 				return;
 			}
 			else if (hlp >= 65)
@@ -3902,9 +3911,7 @@ void CGOnceVisitable::initObj()
 			if(hlp < 20)
 			{
 				artOrRes = 1;
-				std::vector<CArtifact*> arts; 
-				cb->getAllowed(arts, CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR);
-				bonusType = arts[ran() % arts.size()]->id;
+				bonusType = cb->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR);
 			}
 			else
 			{
@@ -3925,19 +3932,15 @@ void CGOnceVisitable::initObj()
 		{
 			artOrRes = 1;
 
-			std::vector<CArtifact*> arts; 
-
 			int hlp = ran()%100;
 			if(hlp < 30)
-				cb->getAllowed(arts,CArtifact::ART_TREASURE);
+				bonusType = cb->getRandomArt (CArtifact::ART_TREASURE);
 			else if(hlp < 80)
-				cb->getAllowed(arts,CArtifact::ART_MINOR);
+				bonusType = cb->getRandomArt (CArtifact::ART_MINOR);
 			else if(hlp < 95)
-				cb->getAllowed(arts,CArtifact::ART_MAJOR);
+				bonusType = cb->getRandomArt (CArtifact::ART_MAJOR);
 			else
-				cb->getAllowed(arts,CArtifact::ART_RELIC);
-
-			bonusType = arts[ran() % arts.size()]->id;
+				bonusType = cb->getRandomArt (CArtifact::ART_RELIC);
 		}
 		break;
 
@@ -3952,9 +3955,7 @@ void CGOnceVisitable::initObj()
 			else if(hlp < 50) //minor or treasure art
 			{
 				artOrRes = 1;
-				std::vector<CArtifact*> arts; 
-				cb->getAllowed(arts, CArtifact::ART_TREASURE | CArtifact::ART_MINOR);
-				bonusType = arts[ran() % arts.size()]->id;
+				bonusType = cb->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR);
 			}
 			else //2 - 5 of non-gold resource
 			{
@@ -4031,7 +4032,7 @@ const std::string & CBank::getHoverText() const
 		hoverName += " " + VLC->generaltexth->allTexts[353];
 	return hoverName;
 }
-void CBank::reset(ui16 var1, ui16 var2) //prevents desync
+void CBank::reset(ui16 var1) //prevents desync
 {
 	ui8 chance = 0;
 	for (ui8 i = 0; i < VLC->objh->banksInfo[index].size(); i++)
@@ -4043,35 +4044,32 @@ void CBank::reset(ui16 var1, ui16 var2) //prevents desync
 		}
 	}
 	artifacts.clear();
-	std::vector<CArtifact*>::iterator index;
+}
+
+void CBank::initialize() const
+{
+	cb->setObjProperty (id, 14, ran()); //synchronous reset
 	for (ui8 i = 0; i <= 3; i++)
-	{	
-		std::vector<CArtifact*> arts; //to avoid addition of different tiers
-		switch (i)
-		{
-			case 0:
-				cb->getAllowed (arts, CArtifact::ART_TREASURE);
-				break;
-			case 1:
-				cb->getAllowed (arts, CArtifact::ART_MINOR);
-				break;
-			case 2:
-				cb->getAllowed (arts, CArtifact::ART_MAJOR);
-				break;
-			case 3:
-				cb->getAllowed (arts, CArtifact::ART_RELIC);
-				break;
-		}
-		for (ui8 n = 0; n < bc->artifacts[i]; n++)
+	{
+		for (ui8 n = 0; n < bc->artifacts[i]; n++) //new function using proper randomization algorithm
 		{
-
-			index = arts.begin() + var2 % arts.size();
-			artifacts.push_back ((*index)->id);
-			arts.erase(index);
-			var2 *= (var1 + n * i); //almost like random
+			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;				
+			}
 		}
 	}
-
 }
 void CBank::setPropertyDer (ui8 what, ui32 val)
 /// random values are passed as arguments and processed identically on all clients
@@ -4091,7 +4089,7 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
 			bc = &VLC->objh->banksInfo[index][val];
 			break;
 		case 14:
-			reset (val%100, val);
+			reset (val%100);
 			break;
 		case 15:
 			bc = NULL;
@@ -4100,30 +4098,35 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
 			artifacts.clear();
 			break;
 		case 17: //set ArmedInstance army
-			int upgraded = 0;
-			if (val%100 < bc->upgradeChance) //once again anti-desync
-				upgraded = 1;
-			switch (bc->guards.size())
 			{
-				case 1:
-					for	(int i = 0; i <= 4; i++)
-						army.setCreature (i, bc->guards[0].first + upgraded, bc->guards[0].second  / 5 );
-					break;
-				case 4:
+				int upgraded = 0;
+				if (val%100 < bc->upgradeChance) //once again anti-desync
+					upgraded = 1;
+				switch (bc->guards.size())
 				{
-					std::vector< std::pair <ui16, ui32> >::const_iterator it;
-					for (it = bc->guards.begin(); it != bc->guards.end(); it++)
+					case 1:
+						for	(int i = 0; i <= 4; i++)
+							army.setCreature (i, bc->guards[0].first + upgraded, bc->guards[0].second  / 5 );
+						break;
+					case 4:
 					{
-						int n = army.slots.size(); //debug
-						army.setCreature (n, it->first, it->second);
+						std::vector< std::pair <ui16, ui32> >::const_iterator it;
+						for (it = bc->guards.begin(); it != bc->guards.end(); it++)
+						{
+							int n = army.slots.size(); //debug
+							army.setCreature (n, it->first, it->second);
+						}
 					}
+						break;
+					default:
+						tlog1 << "Error: Unexpected army data: " << bc->guards.size() <<" items found";
+						return;
 				}
-					break;
-				default:
-					tlog1 << "Error: Unexpected army data: " << bc->guards.size() <<" items found";
-					return;
 			}
 			break;
+		case 18: //add Artifact
+			artifacts.push_back (val);
+			break;
 	}
 }
 
@@ -4132,10 +4135,10 @@ void CBank::newTurn() const
 	if (bc == NULL)
 	{
 		if (cb->getDate(0) == 1)
-			cb->setObjProperty (id, 14, ran()); //initialize on first day
+			initialize(); //initialize on first day
 		else if (daycounter >= 28 && (subID < 13 || subID > 16)) //no reset for Emissaries
 		{
-			cb->setObjProperty (id, 14, ran()); //reset
+			initialize();
 			cb->setObjProperty (id, 11, 0); //daycounter 0
 			if (ID == 24 && cb->getDate(0) > 1)
 				cb->setObjProperty (id, 16, 0); //derelict ships are usable only once
@@ -4311,7 +4314,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
 		cb->setObjProperty (id, 15, 0); //bc = NULL
 	}
 	else //in case of defeat
-		cb->setObjProperty (id, 14, ran()); //reset
+		initialize();
 }
 
 void CGPyramid::initObj()

+ 2 - 1
hch/CObjectHandler.h

@@ -918,7 +918,8 @@ class DLL_EXPORT CBank : public CArmedInstance
 	void initObj();
 	const std::string & getHoverText() const;
 	void setPropertyDer (ui8 what, ui32 val);
-	void reset(ui16 var1, ui16 var2);
+	void initialize() const;
+	void reset(ui16 var1);
 	void newTurn() const;
 	virtual void onHeroVisit (const CGHeroInstance * h) const;
 	virtual void fightGuards (const CGHeroInstance *h, ui32 accept) const;

+ 2 - 0
lib/CGameState.h

@@ -35,6 +35,7 @@ class CStack;
 class CGHeroInstance;
 class CGTownInstance;
 class CArmedInstance;
+class CGDwelling;
 class CGDefInfo;
 class CObjectScript;
 class CGObjectInstance;
@@ -66,6 +67,7 @@ public:
 	std::vector<CGHeroInstance *> heroes;
 	std::vector<CGTownInstance *> towns;
 	std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns
+	std::vector<CGDwelling *> dwellings; //used for town growth
 
 	PlayerState();
 

+ 42 - 7
lib/IGameCallback.cpp

@@ -18,6 +18,8 @@
  *
  */
 
+extern boost::rand48 ran;
+
 CGameState *const IGameCallback::gameState ()
 { 
 	return gs;
@@ -167,12 +169,20 @@ bool IGameCallback::isAllowed( int type, int id )
 	}
 }
 
-void IGameCallback::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts)
+void IGameCallback::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts, int flag)
 {
-	for(int i = 0; i < (VLC->arth->*arts).size(); i++)
+	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))
+		if(isAllowed(1, art->id))
 		{
 			out.push_back(art);
 		}
@@ -182,13 +192,38 @@ void IGameCallback::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CAr
 void IGameCallback::getAllowed(std::vector<CArtifact*> &out, int flags)
 {
 	if(flags & CArtifact::ART_TREASURE)
-		getAllowedArts(out,&CArtHandler::treasures);
+		getAllowedArts(out,&CArtHandler::treasures, CArtifact::ART_TREASURE);
 	if(flags & CArtifact::ART_MINOR)
-		getAllowedArts(out,&CArtHandler::minors);
+		getAllowedArts(out,&CArtHandler::minors, CArtifact::ART_MINOR);
 	if(flags & CArtifact::ART_MAJOR)
-		getAllowedArts(out,&CArtHandler::majors);
+		getAllowedArts(out,&CArtHandler::majors, CArtifact::ART_MAJOR);
 	if(flags & CArtifact::ART_RELIC)
-		getAllowedArts(out,&CArtHandler::relics);
+		getAllowedArts(out,&CArtHandler::relics, CArtifact::ART_RELIC);
+}
+
+ui16 IGameCallback::getRandomArt (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;
+	}
+	ptr->erase (std::find(ptr->begin(), ptr->end(), art)); //remove the artifact from avaliable list
+	return art->id;
 }
 
 void IGameCallback::getAllowedSpells(std::vector<ui16> &out, ui16 level)

+ 3 - 1
lib/IGameCallback.h

@@ -4,6 +4,7 @@
 #include "../global.h"
 #include <vector>
 #include <set>
+#include <boost/random/linear_congruential.hpp>
 #include "../client/FunctionList.h"
 
 /*
@@ -57,7 +58,8 @@ public:
 	virtual void getTilesInRange(std::set<int3> &tiles, int3 pos, int radious, int player=-1, int mode=0);  //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 -  only unrevealed
 	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 void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts);
+	virtual ui16 getRandomArt (int flags);
+	virtual void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts, int flag);
 	virtual void getAllowed(std::vector<CArtifact*> &out, int flags); //flags: bitfield uses EartClass
 	virtual void getAllowedSpells(std::vector<ui16> &out, ui16 level);
 	virtual int3 getMapSize(); //returns size of the map