Browse Source

Cleaned up dwelling randomization

Ivan Savenko 2 years ago
parent
commit
7a09646009

+ 24 - 59
lib/gameState/CGameState.cpp

@@ -77,34 +77,6 @@ public:
 	}
 };
 
-static CGObjectInstance * createObject(MapObjectID id, MapObjectSubID subid, const int3 & pos, const PlayerColor & owner)
-{
-	CGObjectInstance * nobj;
-	switch(id)
-	{
-	case Obj::HERO:
-		{
-			auto handler = VLC->objtypeh->getHandlerFor(id, VLC->heroh->objects[subid]->heroClass->getIndex());
-			nobj = handler->create(handler->getTemplates().front());
-			break;
-		}
-	case Obj::TOWN:
-		nobj = new CGTownInstance();
-		break;
-	default: //rest of objects
-		nobj = new CGObjectInstance();
-		break;
-	}
-	nobj->ID = id;
-	nobj->subID = subid;
-	nobj->pos = pos;
-	nobj->tempOwner = owner;
-	if (id != Obj::HERO)
-		nobj->appearance = VLC->objtypeh->getHandlerFor(id, subid)->getTemplates().front();
-
-	return nobj;
-}
-
 HeroTypeID CGameState::pickNextHeroType(const PlayerColor & owner)
 {
 	const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
@@ -547,44 +519,30 @@ void CGameState::initRandomFactionsForPlayers()
 void CGameState::randomizeMapObjects()
 {
 	logGlobal->debug("\tRandomizing objects");
-	for(CGObjectInstance *obj : map->objects)
+	for(CGObjectInstance *object : map->objects)
 	{
-		if(!obj)
+		if(!object)
 			continue;
 
-		{
-			std::pair<Obj,int> ran = pickObject(obj);
-			if(ran.first == Obj::NO_OBJ || ran.second<0) //this is not a random object, or we couldn't find anything
-			{
-				if(obj->ID==Obj::TOWN || obj->ID==Obj::MONSTER)
-					obj->setType(obj->ID, obj->subID); // update def, if necessary
-			}
-			else if(ran.first==Obj::HERO)//special code for hero
-			{
-				auto * h = dynamic_cast<CGHeroInstance *>(obj);
-				obj->setType(ran.first, ran.second);
-				map->heroesOnMap.emplace_back(h);
-			}
-			else if(ran.first==Obj::TOWN)//special code for town
-			{
-				auto * t = dynamic_cast<CGTownInstance *>(obj);
-				obj->setType(ran.first, ran.second);
-				map->towns.emplace_back(t);
-			}
-			else
-			{
-				obj->setType(ran.first, ran.second);
-			}
-		}
+		object->pickRandomObject(getRandomGenerator());
+
+		auto * hero = dynamic_cast<CGHeroInstance *>(object);
+		auto * town = dynamic_cast<CGTownInstance *>(object);
+
+		if (hero)
+			map->heroesOnMap.emplace_back(hero);
+
+		if (town)
+			map->towns.emplace_back(town);
 
 		//handle Favouring Winds - mark tiles under it
-		if(obj->ID == Obj::FAVORABLE_WINDS)
+		if(object->ID == Obj::FAVORABLE_WINDS)
 		{
-			for (int i = 0; i < obj->getWidth() ; i++)
+			for (int i = 0; i < object->getWidth() ; i++)
 			{
-				for (int j = 0; j < obj->getHeight() ; j++)
+				for (int j = 0; j < object->getHeight() ; j++)
 				{
-					int3 pos = obj->pos - int3(i,j,0);
+					int3 pos = object->pos - int3(i,j,0);
 					if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
 				}
 			}
@@ -617,7 +575,14 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
 		}
 	}
 
-	CGObjectInstance * hero = createObject(Obj::HERO, heroTypeId, townPos, playerColor);
+	auto handler = VLC->objtypeh->getHandlerFor(Obj::HERO, VLC->heroh->objects[heroTypeId]->heroClass->getIndex());
+	CGObjectInstance * hero = handler->create(handler->getTemplates().front());
+
+	hero->ID = Obj::HERO;
+	hero->subID = VLC->heroh->objects[heroTypeId]->heroClass->getIndex();
+	hero->tempOwner = playerColor;
+
+	hero->pos = townPos;
 	hero->pos += hero->getVisitableOffset();
 	map->getEditManager()->insertObject(hero);
 }

+ 2 - 1
lib/gameState/CGameState.h

@@ -115,6 +115,8 @@ public:
 	void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
 
 	bool giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid);
+	/// picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
+	HeroTypeID pickNextHeroType(const PlayerColor & owner);
 
 	void apply(CPack *pack);
 	BattleField battleGetBattlefieldType(int3 tile, CRandomGenerator & rand);
@@ -214,7 +216,6 @@ private:
 	bool isUsedHero(const HeroTypeID & hid) const; //looks in heroes and prisons
 	std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
 	HeroTypeID pickUnusedHeroTypeRandomly(const PlayerColor & owner); // picks a unused hero type randomly
-	HeroTypeID pickNextHeroType(const PlayerColor & owner); // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
 	UpgradeInfo fillUpgradeInfo(const CStackInstance &stack) const;
 
 	// ---- data -----

+ 0 - 1
lib/mapObjects/CGCreature.cpp

@@ -152,7 +152,6 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 			break;
 		}
 	}
-
 }
 
 CreatureID CGCreature::getCreature() const

+ 8 - 0
lib/mapObjects/CGDwelling.cpp

@@ -48,6 +48,10 @@ CGDwelling::~CGDwelling() = default;
 
 FactionID CGDwelling::randomizeFaction(CRandomGenerator & rand)
 {
+	if (ID == Obj::RANDOM_DWELLING_FACTION)
+		return FactionID(subID);
+
+	assert(ID == Obj::RANDOM_DWELLING || ID == Obj::RANDOM_DWELLING_LVL);
 	assert(randomizationInfo.has_value());
 	if (!randomizationInfo)
 		return FactionID::CASTLE;
@@ -102,6 +106,10 @@ FactionID CGDwelling::randomizeFaction(CRandomGenerator & rand)
 
 int CGDwelling::randomizeLevel(CRandomGenerator & rand)
 {
+	if (ID == Obj::RANDOM_DWELLING_LVL)
+		return subID.getNum();
+
+	assert(ID == Obj::RANDOM_DWELLING || ID == Obj::RANDOM_DWELLING_FACTION);
 	assert(randomizationInfo.has_value());
 
 	if (!randomizationInfo)

+ 8 - 10
lib/mapObjects/CGHeroInstance.cpp

@@ -296,16 +296,6 @@ void CGHeroInstance::initHero(CRandomGenerator & rand, const HeroTypeID & SUBID)
 	initHero(rand);
 }
 
-void CGHeroInstance::setType(si32 ID, si32 subID)
-{
-	assert(ID == Obj::HERO); // just in case
-	type = VLC->heroh->objects[subID];
-
-	CGObjectInstance::setType(ID, type->heroClass->getIndex()); // to find object handler we must use heroClass->id
-	this->subID = subID; // after setType subID used to store unique hero identify id. Check issue 2277 for details
-	randomizeArmy(type->heroClass->faction);
-}
-
 void CGHeroInstance::initHero(CRandomGenerator & rand)
 {
 	assert(validTypes(true));
@@ -580,6 +570,14 @@ void CGHeroInstance::pickRandomObject(CRandomGenerator & rand)
 		ID = Obj::HERO;
 		subID = cb->gameState()->pickNextHeroType(getOwner());
 	}
+	type = VLC->heroh->objects[subID];
+
+	// to find object handler we must use heroClass->id
+	// after setType subID used to store unique hero identify id. Check issue 2277 for details
+	setType(ID, type->heroClass->getIndex());
+	this->subID = subID;
+
+	randomizeArmy(type->heroClass->faction);
 }
 
 void CGHeroInstance::initObj(CRandomGenerator & rand)

+ 0 - 1
lib/mapObjects/CGHeroInstance.h

@@ -232,7 +232,6 @@ public:
 	//////////////////////////////////////////////////////////////////////////
 
 	HeroTypeID getHeroType() const;
-	void setType(si32 ID, si32 subID) override;
 
 	void initHero(CRandomGenerator & rand);
 	void initHero(CRandomGenerator & rand, const HeroTypeID & SUBID);

+ 3 - 4
lib/mapObjects/CGObjectInstance.h

@@ -106,10 +106,6 @@ public:
 	virtual int getSightRadius() const;
 	/// returns (x,y,0) offset to a visitable tile of object
 	virtual int3 getVisitableOffset() const;
-	/// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman")
-	virtual void setType(si32 ID, si32 subID);
-
-	/// returns text visible in status bar with specific hero/player active.
 
 	/// Returns generic name of object, without any player-specific info
 	virtual std::string getObjectName() const;
@@ -160,6 +156,9 @@ protected:
 	/// virtual method that allows synchronously update object state on server and all clients
 	virtual void setPropertyDer(ui8 what, ui32 val);
 
+	/// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman")
+	void setType(si32 ID, si32 subID);
+
 	/// Gives dummy bonus from this object to hero. Can be used to track visited state
 	void giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration::Type duration = BonusDuration::ONE_DAY) const;
 

+ 6 - 9
lib/mapObjects/CGTownInstance.cpp

@@ -486,6 +486,12 @@ void CGTownInstance::pickRandomObject(CRandomGenerator & rand)
 		ID = MapObjectID::TOWN;
 		subID = randomizeFaction(rand);
 	}
+
+	assert(ID == Obj::TOWN); // just in case
+	setType(ID, subID);
+	town = (*VLC->townh)[subID]->town;
+	randomizeArmy(subID);
+	updateAppearance();
 }
 
 void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
@@ -779,15 +785,6 @@ std::vector<int> CGTownInstance::availableItemsIds(EMarketMode mode) const
 		return IMarket::availableItemsIds(mode);
 }
 
-void CGTownInstance::setType(si32 ID, si32 subID)
-{
-	assert(ID == Obj::TOWN); // just in case
-	CGObjectInstance::setType(ID, subID);
-	town = (*VLC->townh)[subID]->town;
-	randomizeArmy(subID);
-	updateAppearance();
-}
-
 void CGTownInstance::updateAppearance()
 {
 	auto terrain = cb->gameState()->getTile(visitablePos())->terType->getId();

+ 0 - 1
lib/mapObjects/CGTownInstance.h

@@ -141,7 +141,6 @@ public:
 	bool allowsTrade(EMarketMode mode) const override;
 	std::vector<int> availableItemsIds(EMarketMode mode) const override;
 
-	void setType(si32 ID, si32 subID) override;
 	void updateAppearance();
 
 	//////////////////////////////////////////////////////////////////////////

+ 3 - 0
lib/mapObjects/IObjectInterface.cpp

@@ -46,6 +46,9 @@ void IObjectInterface::newTurn(CRandomGenerator & rand) const
 void IObjectInterface::initObj(CRandomGenerator & rand)
 {}
 
+void IObjectInterface::pickRandomObject(CRandomGenerator & rand)
+{}
+
 void IObjectInterface::setProperty( ui8 what, ui32 val )
 {}
 

+ 7 - 0
lib/mapping/MapFormatH3M.cpp

@@ -1336,12 +1336,19 @@ CGObjectInstance * CMapLoaderH3M::readDwellingRandom(const int3 & mapPosition, s
 		if(object->randomizationInfo->identifier != 0)
 			reader->readBitmaskFactions(object->randomizationInfo->allowedFactions, false);
 	}
+	else
+		object->randomizationInfo->allowedFactions.insert(FactionID(objectTemplate->subid));
 
 	if(hasLevelInfo)
 	{
 		object->randomizationInfo->minLevel = std::max(reader->readUInt8(), static_cast<ui8>(0)) + 1;
 		object->randomizationInfo->maxLevel = std::min(reader->readUInt8(), static_cast<ui8>(6)) + 1;
 	}
+	else
+	{
+		object->randomizationInfo->minLevel = objectTemplate->subid;
+		object->randomizationInfo->maxLevel = objectTemplate->subid;
+	}
 
 	return object;
 }

+ 8 - 19
mapeditor/inspector/inspector.cpp

@@ -87,14 +87,6 @@ void Initializer::initialize(CGDwelling * o)
 	if(!o) return;
 	
 	o->tempOwner = defaultPlayer;
-	
-	switch(o->ID)
-	{
-		case Obj::RANDOM_DWELLING:
-		case Obj::RANDOM_DWELLING_LVL:
-		case Obj::RANDOM_DWELLING_FACTION:
-			o->initRandomObjectInfo();
-	}
 }
 
 void Initializer::initialize(CGGarrison * o)
@@ -243,11 +235,8 @@ void Inspector::updateProperties(CGDwelling * o)
 	
 	addProperty("Owner", o->tempOwner, false);
 	
-	if(dynamic_cast<CCreGenAsCastleInfo*>(o->info))
-	{
-		auto * delegate = new PickObjectDelegate(controller, PickObjectDelegate::typedFilter<CGTownInstance>);
-		addProperty("Same as town", PropertyEditorPlaceholder(), delegate, false);
-	}
+	auto * delegate = new PickObjectDelegate(controller, PickObjectDelegate::typedFilter<CGTownInstance>);
+	addProperty("Same as town", PropertyEditorPlaceholder(), delegate, false);
 }
 
 void Inspector::updateProperties(CGLighthouse * o)
@@ -641,12 +630,12 @@ void Inspector::setProperty(CGDwelling * o, const QString & key, const QVariant
 	
 	if(key == "Same as town")
 	{
-		if(auto * info = dynamic_cast<CCreGenAsCastleInfo*>(o->info))
-		{
-			info->instanceId = "";
-			if(CGTownInstance * town = data_cast<CGTownInstance>(value.toLongLong()))
-				info->instanceId = town->instanceName;
-		}
+		if (!o->randomizationInfo.has_value())
+			o->randomizationInfo = CGDwellingRandomizationInfo();
+
+		o->randomizationInfo->instanceId = "";
+		if(CGTownInstance * town = data_cast<CGTownInstance>(value.toLongLong()))
+			o->randomizationInfo->instanceId = town->instanceName;
 	}
 }