Răsfoiți Sursa

Merge branch 'develop' into FFMpeg

AlexVinS 11 ani în urmă
părinte
comite
ca05087c3b

+ 8 - 1
config/objects/generic.json

@@ -58,6 +58,7 @@
 			"object" : {
 				"index" : 0,
 				"rmg" : {
+					"zoneLimit"	: 1,
 					"value"		: 100,
 					"rarity"	: 100
 				}
@@ -106,11 +107,16 @@
 	},
 
 	"redwoodObservatory" : {
-		"index" :58, 
+		"index" :58,	
 		"handler" : "observatory",
 		"types" : {
 			"object" : {
 				"index" : 0,
+				"templates" :
+				{
+					"base" : { "animation" : "avxredw.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["grass", "swamp", "dirt", "sand", "lava", "rough"] },
+					"snow" : { "animation" : "avxreds0.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["snow"] }
+				},	
 				"rmg" : {
 					"zoneLimit"	: 1,
 					"value"		: 750,
@@ -629,6 +635,7 @@
 			"object" : {
 				"index" : 0,
 				"rmg" : {
+					"zoneLimit"	: 1,
 					"value"		: 100,
 					"rarity"	: 20
 				}

+ 3 - 3
lib/CGameInfoCallback.cpp

@@ -408,12 +408,12 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
 		return t->hasBuilt(id);
 	};
 
-	if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
-		return EBuildingState::CANT_BUILD_TODAY; //building limit
-
 	if (!building->requirements.test(buildTest))
 		return EBuildingState::PREREQUIRES;
 
+	if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
+		return EBuildingState::CANT_BUILD_TODAY; //building limit
+
 	if (building->upgrade != BuildingID::NONE && !t->hasBuilt(building->upgrade))
 		return EBuildingState::MISSING_BASE;
 

+ 6 - 2
lib/CGameState.cpp

@@ -815,8 +815,8 @@ void CGameState::initNewGame()
 		CStopWatch sw;
 
 		// Gen map
-		CMapGenerator mapGenerator(scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
-		map = mapGenerator.generate().release();
+		CMapGenerator mapGenerator;
+		map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release();
 
 		// Update starting options
 		for(int i = 0; i < map->players.size(); ++i)
@@ -1849,7 +1849,10 @@ void CGameState::initMapObjects()
 	for(CGObjectInstance *obj : map->objects)
 	{
 		if(obj)
+		{
+			logGlobal->traceStream() << boost::format ("Calling Init for object %d, %d") % obj->ID % obj->subID;
 			obj->initObj();
+		}
 	}
 	for(CGObjectInstance *obj : map->objects)
 	{
@@ -3518,5 +3521,6 @@ CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance
 
 CRandomGenerator & CGameState::getRandomGenerator()
 {
+	logGlobal->traceStream() << "Fetching CGameState::rand with seed " << rand.nextInt();
 	return rand;
 }

+ 2 - 2
lib/HeroBonus.cpp

@@ -853,14 +853,14 @@ void CBonusSystemNode::newChildAttached(CBonusSystemNode *child)
 {
 	assert(!vstd::contains(children, child));
 	children.push_back(child);
-	BONUS_LOG_LINE(child->nodeName() << " #attached to# " << nodeName());
+	//BONUS_LOG_LINE(child->nodeName() << " #attached to# " << nodeName());
 }
 
 void CBonusSystemNode::childDetached(CBonusSystemNode *child)
 {
 	assert(vstd::contains(children, child));
 	children -= child;
-	BONUS_LOG_LINE(child->nodeName() << " #detached from# " << nodeName());
+	//BONUS_LOG_LINE(child->nodeName() << " #detached from# " << nodeName());
 }
 
 void CBonusSystemNode::detachFromAll()

+ 1 - 1
lib/mapObjects/CGHeroInstance.h

@@ -222,7 +222,7 @@ public:
 		h & exp & level & name & biography & portrait & mana & secSkills & movement
 			& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo;
 		h & visitedTown & boat;
-		h & type & specialty & commander;
+		h & type & specialty & commander & visitedObjects;
 		BONUS_TREE_DESERIALIZATION_FIX
 		//visitied town pointer will be restored by map serialization method
 	}

+ 3 - 0
lib/mapObjects/CommonConstructors.cpp

@@ -271,6 +271,8 @@ BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRan
 
 void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
 {
+	//logGlobal->debugStream() << "Seed used to configure bank is " << rng.nextInt();
+
 	auto bank = dynamic_cast<CBank*>(object);
 
 	bank->resetDuration = bankResetDuration;
@@ -282,6 +284,7 @@ void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRando
 	assert(totalChance != 0);
 
 	si32 selectedChance = rng.nextInt(totalChance - 1);
+	//logGlobal->debugStream() << "Selected chance for bank config is " << selectedChance;
 
 	for (auto & node : levels)
 	{

+ 5 - 0
lib/mapObjects/MiscObjects.cpp

@@ -632,6 +632,11 @@ std::string CGResource::getHoverText(PlayerColor player) const
 	return VLC->generaltexth->restypes[subID];
 }
 
+CGResource::CGResource()
+{
+	amount = 0;
+}
+
 void CGResource::initObj()
 {
 	blockVisit = true;

+ 1 - 0
lib/mapObjects/MiscObjects.h

@@ -182,6 +182,7 @@ public:
 	ui32 amount; //0 if random
 	std::string message;
 
+	CGResource();
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;

+ 1 - 1
lib/rmg/CMapGenOptions.cpp

@@ -65,7 +65,7 @@ si8 CMapGenOptions::getPlayerCount() const
 
 void CMapGenOptions::setPlayerCount(si8 value)
 {
-	assert((value >= 2 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
+	assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
 	playerCount = value;
 	resetPlayersMap();
 }

+ 7 - 5
lib/rmg/CMapGenerator.cpp

@@ -24,10 +24,9 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3&
 }
 
 
-CMapGenerator::CMapGenerator(shared_ptr<CMapGenOptions> mapGenOptions, int RandomSeed /*= std::time(nullptr)*/) :
-	mapGenOptions(mapGenOptions), randomSeed(RandomSeed), monolithIndex(0), zonesTotal(0)
+CMapGenerator::CMapGenerator() :
+	monolithIndex(0), zonesTotal(0)
 {
-	rand.setSeed(randomSeed);
 }
 
 void CMapGenerator::initTiles()
@@ -78,8 +77,11 @@ void CMapGenerator::initPrisonsRemaining()
 	prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * map->players.size()); //so at least 16 heroes will be available for every player
 }
 
-std::unique_ptr<CMap> CMapGenerator::generate()
+std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, int randomSeed /*= std::time(nullptr)*/)
 {
+	this->mapGenOptions = mapGenOptions;
+	this->randomSeed = randomSeed;
+	rand.setSeed(this->randomSeed);
 	mapGenOptions->finalize(rand);
 
 	map = make_unique<CMap>();
@@ -95,7 +97,7 @@ std::unique_ptr<CMap> CMapGenerator::generate()
 		genZones();
 		map->calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
 		fillZones();
-		//updated fuarded tiles will be calculated in CGameState::initMapObjects()
+		//updated guarded tiles will be calculated in CGameState::initMapObjects()
 	}
 	catch (rmgException &e)
 	{

+ 3 - 3
lib/rmg/CMapGenerator.h

@@ -51,12 +51,12 @@ public:
 class DLL_LINKAGE CMapGenerator
 {
 public:
-	explicit CMapGenerator(shared_ptr<CMapGenOptions> mapGenOptions, int RandomSeed = std::time(nullptr));
+	explicit CMapGenerator();
 	~CMapGenerator(); // required due to unique_ptr
 
-	std::unique_ptr<CMap> generate();
+	std::unique_ptr<CMap> generate(CMapGenOptions * mapGenOptions, int RandomSeed = std::time(nullptr));
 	
-	shared_ptr<CMapGenOptions> mapGenOptions;
+	CMapGenOptions * mapGenOptions;
 	std::unique_ptr<CMap> map;
 	CRandomGenerator rand;
 	int randomSeed;

+ 56 - 41
lib/rmg/CRmgTemplateZone.cpp

@@ -620,6 +620,7 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
 	auto guard = new CGCreature();
 	guard->ID = Obj::MONSTER;
 	guard->subID = creId;
+	guard->character = 1; //MUST be initialized or switch will diverge
 	auto  hlp = new CStackInstance(creId, amount);
 	//will be set during initialization
 	guard->putStack(SlotID(0), hlp);
@@ -670,10 +671,11 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 			}
 		}
 	}
+	ui32 desiredValue = gen->rand.nextInt(minValue, maxValue);
 
 	int currentValue = 0;
 	CGObjectInstance * object = nullptr;
-	while (currentValue < minValue)
+	while (currentValue < desiredValue)
 	{
 		treasures[info.nextTreasurePos] = nullptr;
 
@@ -697,21 +699,22 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 				break;
 		}
 
-		int remaining = maxValue - currentValue;
-
-		ObjectInfo oi = getRandomObject(gen, info, remaining);
-		object = oi.generateObject();
-		if (!object)
+		ObjectInfo oi = getRandomObject(gen, info, desiredValue - currentValue);
+		if (!oi.value) //0 value indicates no object
 		{
 			vstd::erase_if_present(treasures, info.nextTreasurePos);
 			break;
 		}
 		else
 		{
+			object = oi.generateObject();
+
 			//remove from possible objects
 			auto oiptr = std::find(possibleObjects.begin(), possibleObjects.end(), oi);
 			assert (oiptr != possibleObjects.end());
 			oiptr->maxPerZone--;
+			if (!oiptr->maxPerZone)
+				possibleObjects.erase(oiptr);
 			//TODO
 
 			//update treasure pile area
@@ -730,34 +733,38 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 				info.blockedPositions.insert(blockPos);
 			}
 			info.occupiedPositions.insert(visitablePos);
-		}
 
-		currentValue += oi.value;
+			currentValue += oi.value;
 		
-		treasures[info.nextTreasurePos] = object;
+			treasures[info.nextTreasurePos] = object;
 
-		//now find place for next object
-		int3 placeFound(-1,-1,-1);
+			//now find place for next object
+			int3 placeFound(-1,-1,-1);
 
-		for (auto tile : boundary)
-		{
-			if (gen->isPossible(tile)) //we can place new treasure only on possible tile
+			//randomize next position from among possible ones
+			std::vector<int3> boundaryCopy (boundary.begin(), boundary.end());
+			RandomGeneratorUtil::randomShuffle(boundaryCopy, gen->rand);
+
+			for (auto tile : boundaryCopy)
 			{
-				bool here = true;
-				gen->foreach_neighbour (tile, [gen, &here](int3 pos)
+				if (gen->isPossible(tile)) //we can place new treasure only on possible tile
 				{
-					if (!(gen->isBlocked(pos) || gen->isPossible(pos)))
-						here = false;
-				});
-				if (here)
-				{
-					placeFound = tile;
-					break;
+					bool here = true;
+					gen->foreach_neighbour (tile, [gen, &here](int3 pos)
+					{
+						if (!(gen->isBlocked(pos) || gen->isPossible(pos)))
+							here = false;
+					});
+					if (here)
+					{
+						placeFound = tile;
+						break;
+					}
 				}
 			}
-		}
-		if (placeFound.valid())
-			info.nextTreasurePos = placeFound;
+			if (placeFound.valid())
+				info.nextTreasurePos = placeFound;
+			}
 	}
 
 	if (treasures.size())
@@ -865,6 +872,8 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 			{
 				if (gen->isPossible(treasure.first))
 					gen->setOccupied (treasure.first, ETileType::BLOCKED);
+
+				delete treasure.second;
 			}
 		}
 
@@ -1077,7 +1086,8 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
 
 void CRmgTemplateZone::createTreasures(CMapGenerator* gen)
 {
-	const double minDistance = std::max<float>(15.0f / sqrt(totalDensity), 2);
+	//this is squared distance for optimization purposes
+	const double minDistance = std::max<float>(200.f / totalDensity, 4);
 	//distance lower than 2 causes objects to overlap and crash
 
 	do {
@@ -1230,7 +1240,7 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, float min_di
 			bool allTilesAvailable = true;
 			gen->foreach_neighbour (tile, [&gen, &allTilesAvailable](int3 neighbour)
 			{
-				if (!(gen->isPossible(neighbour) || gen->isBlocked(neighbour)))
+				if (!(gen->isPossible(neighbour) || gen->shouldBeBlocked(neighbour)))
 				{
 					allTilesAvailable = false; //all present tiles must be already blocked or ready for new objects
 				}
@@ -1488,19 +1498,20 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 	return true;
 }
 
-ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 value)
+ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 remaining)
 {
 	//int objectsVisitableFromBottom = 0; //for debug
 
 	std::vector<std::pair<ui32, ObjectInfo>> tresholds;
 	ui32 total = 0;
 
-	ui32 minValue = 0.25f * value;
+	//calculate actual treasure value range based on remaining value
+	ui32 minValue = 0.25f * remaining;
 
 	//roulette wheel
 	for (ObjectInfo &oi : possibleObjects) //copy constructor turned out to be costly
 	{
-		if (oi.value >= minValue && oi.value <= value && oi.maxPerZone > 0)
+		if (oi.value >= minValue && oi.value <= remaining && oi.maxPerZone > 0)
 		{
 			int3 newVisitableOffset = oi.templ.getVisitableOffset(); //visitablePos assumes object will be shifter by visitableOffset
 			int3 newVisitablePos = info.nextTreasurePos;
@@ -1590,16 +1601,17 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
 				continue;
 
 			total += oi.probability;
+			//assert (oi.value > 0);
 			tresholds.push_back (std::make_pair (total, oi));
 		}
 	}
 
 	//logGlobal->infoStream() << boost::format ("Number of objects visitable  from bottom: %d") % objectsVisitableFromBottom;
 
-	//Generate pandora Box with gold if the value is extremely high
-	ObjectInfo oi;
 	if (tresholds.empty())
 	{
+		ObjectInfo oi;
+		//Generate pandora Box with gold if the value is extremely high
 		if (minValue > 20000) //we don't have object valuable enough
 		{
 			oi.generateObject = [minValue]() -> CGObjectInstance *
@@ -1614,25 +1626,28 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
 			oi.value = minValue;
 			oi.probability = 0;
 		}
-		else
+		else //generate empty object with 0 value if the value if we can't spawn anything
 		{
 			oi.generateObject = [gen]() -> CGObjectInstance *
 			{
 				return nullptr;
 			};
 			oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); //TODO: null template or something? should be never used, but hell knows
-			oi.value = 0;
+			oi.value = 0; // this field is checked to determine no object
 			oi.probability = 0;
 		}
 		return oi;
 	}
-
-	int r = gen->rand.nextInt (1, total);
-
-	for (auto t : tresholds)
+	else
 	{
-		if (r <= t.first)
-			return t.second;
+		int r = gen->rand.nextInt (1, total);
+
+		for (auto t : tresholds)
+		{
+			if (r <= t.first)
+				return t.second;
+		}
+		assert (0); //we should never be here
 	}
 	//FIXME: control reaches end of non-void function. Missing return?
 }

+ 1 - 1
lib/rmg/CRmgTemplateZone.h

@@ -173,7 +173,7 @@ public:
 	std::vector<CTreasureInfo> getTreasureInfo();
 	std::set<int3>* getFreePaths();
 
-	ObjectInfo getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 value);
+	ObjectInfo getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 remaining);
 
 	void placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard = false);
 

+ 2 - 2
lib/rmg/CZonePlacer.cpp

@@ -38,7 +38,7 @@ int3 CZonePlacer::cords (const float3 f) const
 	return int3(std::max(0.f, (f.x * gen->map->width)-1), std::max(0.f, (f.y * gen->map->height-1)), f.z);
 }
 
-void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGenerator * rand)
+void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenerator * rand)
 {
 	//gravity-based algorithm
 
@@ -207,7 +207,7 @@ d = 0.01 * dx^3 - 0.1618 * dx^2 + 1 * dx + ...
 	return dx * (1 + dx * (0.1 + dx * 0.01)) + dy * (1.618 + dy * (-0.1618 + dy * 0.01618));
 }
 
-void CZonePlacer::assignZones(shared_ptr<CMapGenOptions> mapGenOptions)
+void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
 {
 	logGlobal->infoStream()  << "Starting zone colouring";
 

+ 2 - 2
lib/rmg/CZonePlacer.h

@@ -43,8 +43,8 @@ public:
 	float metric (const int3 &a, const int3 &b) const;
 	~CZonePlacer();
 
-	void placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGenerator * rand);
-	void assignZones(shared_ptr<CMapGenOptions> mapGenOptions);
+	void placeZones(const CMapGenOptions * mapGenOptions, CRandomGenerator * rand);
+	void assignZones(const CMapGenOptions * mapGenOptions);
 
 private:
 	//metric coefiicients