Преглед изворни кода

- Refactored method CGameState::init

beegee1 пре 12 година
родитељ
комит
f0cbbbdb70
7 измењених фајлова са 466 додато и 403 уклоњено
  1. 0 1
      client/Client.cpp
  2. 399 345
      lib/CGameState.cpp
  3. 55 36
      lib/CGameState.h
  4. 0 1
      lib/CObjectHandler.h
  5. 3 4
      lib/mapping/CCampaignHandler.cpp
  6. 9 13
      lib/mapping/CCampaignHandler.h
  7. 0 3
      server/CGameHandler.h

+ 0 - 1
client/Client.cpp

@@ -699,7 +699,6 @@ int CClient::sendRequest(const CPack *request, PlayerColor player)
 void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
 {
 	endGame(false);
-	LOCPLINT = nullptr; //TODO free res
 
 	GH.curInt = CGPreGame::create();
 	auto & epilogue = camp->camp->scenarios[camp->mapsConquered.back()].epilog;

+ 399 - 345
lib/CGameState.cpp

@@ -726,6 +726,7 @@ int CGameState::getDate(Date::EDateType mode) const
 	}
 	return 0;
 }
+
 CGameState::CGameState()
 {
 	gs = this;
@@ -735,6 +736,7 @@ CGameState::CGameState()
 	objCaller = new CObjectCallersHandler;
 	globalEffects.setDescription("Global effects");
 }
+
 CGameState::~CGameState()
 {
 	//delete mx;//TODO: crash on Linux (mutex must be unlocked before destruction)
@@ -762,171 +764,249 @@ BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2],
 
 void CGameState::init(StartInfo * si)
 {
-	auto giveCampaignBonusToHero = [&](CGHeroInstance * hero)
+    logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
+	ran.seed((boost::int32_t)si->seedToBeUsed);
+	scenarioOps = new StartInfo(*si);
+	initialOpts = new StartInfo(*si);
+	si = nullptr;
+
+	switch(scenarioOps->mode)
 	{
-		const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
-		if(!curBonus)
-			return;
+	case StartInfo::NEW_GAME:
+		initNewGame();
+		break;
+	case StartInfo::CAMPAIGN:
+		initCampaign();
+		break;
+	case StartInfo::DUEL:
+		initDuel();
+		return;
+	default:
+        logGlobal->errorStream() << "Wrong mode: " << (int)scenarioOps->mode;
+		return;
+	}
+	VLC->arth->initAllowedArtifactsList(map->allowedArtifact);
+    logGlobal->infoStream() << "Map loaded!";
+
+	checkMapChecksum();
+
+	day = 0;
+
+    logGlobal->debugStream() << "Initialization:";
 
-		if(curBonus->isBonusForHero())
+	initGrailPosition();
+	initRandomFactionsForPlayers();
+	randomizeMapObjects();
+	initPlayerStates();
+	initHeroPlaceholders();
+	placeStartingHeroes();
+	initStartingResources();
+	initHeroes();
+	initFogOfWar();
+	initStartingBonus();
+	initTowns();
+	initMapObjects();
+	buildBonusSystemTree();
+	initVisitingAndGarrisonedHeroes();
+
+    logGlobal->debugStream() << "\tChecking objectives";
+	map->checkForObjectives(); //needs to be run when all objects are properly placed
+
+	int seedAfterInit = ran();
+    logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
+	if(scenarioOps->seedPostInit > 0)
+	{
+		//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
+		assert(scenarioOps->seedPostInit == seedAfterInit);
+	}
+	else
+	{
+		scenarioOps->seedPostInit = seedAfterInit; //store the post init "seed"
+	}
+}
+
+void CGameState::initNewGame()
+{
+	if(scenarioOps->createRandomMap())
+	{
+		logGlobal->infoStream() << "Create random map.";
+		CStopWatch sw;
+
+		// Gen map
+		CMapGenerator mapGenerator;
+		map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release();
+
+		// Update starting options
+		for(int i = 0; i < map->players.size(); ++i)
 		{
-			//apply bonus
-			switch (curBonus->type)
+			const auto & playerInfo = map->players[i];
+			if(playerInfo.canAnyonePlay())
 			{
-			case CScenarioTravel::STravelBonus::SPELL:
-				hero->spells.insert(SpellID(curBonus->info2));
-				break;
-			case CScenarioTravel::STravelBonus::MONSTER:
-				{
-					for(int i=0; i<GameConstants::ARMY_SIZE; i++)
-					{
-						if(hero->slotEmpty(SlotID(i)))
-						{
-							hero->addToSlot(SlotID(i), CreatureID(curBonus->info2), curBonus->info3);
-							break;
-						}
-					}
-				}
-				break;
-			case CScenarioTravel::STravelBonus::ARTIFACT:
-				gs->giveHeroArtifact(hero, static_cast<ArtifactID>(curBonus->info2));
-				break;
-			case CScenarioTravel::STravelBonus::SPELL_SCROLL:
-				{
-					CArtifactInstance * scroll = CArtifactInstance::createScroll(SpellID(curBonus->info2).toSpell());
-					scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
-				}
-				break;
-			case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
+				PlayerSettings & playerSettings = scenarioOps->playerInfos[PlayerColor(i)];
+				playerSettings.compOnly = !playerInfo.canHumanPlay;
+				playerSettings.team = playerInfo.team;
+				playerSettings.castle = playerInfo.defaultCastle();
+				if(playerSettings.playerID == PlayerSettings::PLAYER_AI && playerSettings.name.empty())
 				{
-					const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus->info2);
-					for (int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
-					{
-						int val = ptr[g];
-						if (val == 0)
-						{
-							continue;
-						}
-						auto bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
-						hero->addNewBonus(bb);
-					}
+					playerSettings.name = VLC->generaltexth->allTexts[468];
 				}
-				break;
-			case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
-				hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, true);
-				break;
+				playerSettings.color = PlayerColor(i);
+			}
+			else
+			{
+				scenarioOps->playerInfos.erase(PlayerColor(i));
 			}
 		}
-	};
 
-	auto getHumanPlayerInfo = [&]() -> std::vector<const PlayerSettings *>
+		logGlobal->infoStream() << boost::format("Generated random map in %i ms.") % sw.getDiff();
+	}
+	else
 	{
-		std::vector<const PlayerSettings *> ret;
-		for(auto it = scenarioOps->playerInfos.cbegin();
-			it != scenarioOps->playerInfos.cend(); ++it)
-		{
-			if(it->second.playerID != PlayerSettings::PLAYER_AI)
-				ret.push_back(&it->second);
-		}
+		logGlobal->infoStream() << "Open map file: " << scenarioOps->mapname;
+		map = CMapService::loadMap(scenarioOps->mapname).release();
+	}
+}
 
-		return ret;
-	};
+void CGameState::initCampaign()
+{
+	logGlobal->infoStream() << "Open campaign map file: " << scenarioOps->campState->currentMap;
+	auto campaign = scenarioOps->campState;
+	assert(vstd::contains(campaign->camp->mapPieces, *scenarioOps->campState->currentMap));
 
-    logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
-	ran.seed((boost::int32_t)si->seedToBeUsed);
-	scenarioOps = new StartInfo(*si);
-	initialOpts = new StartInfo(*si);
-	si = nullptr;
+	std::string & mapContent = campaign->camp->mapPieces[*scenarioOps->campState->currentMap];
+	auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
+	map = CMapService::loadMap(buffer, mapContent.size()).release();
+}
 
-	switch(scenarioOps->mode)
+void CGameState::initDuel()
+{
+	DuelParameters dp;
+	try //CLoadFile likes throwing
 	{
-	case StartInfo::NEW_GAME:
+		if(boost::algorithm::ends_with(scenarioOps->mapname, ".json"))
 		{
-			if(scenarioOps->createRandomMap())
-			{
-                logGlobal->infoStream() << "Create random map.";
-				CStopWatch sw;
+            logGlobal->infoStream() << "Loading duel settings from JSON file: " << scenarioOps->mapname;
+			dp = DuelParameters::fromJSON(scenarioOps->mapname);
+            logGlobal->infoStream() << "JSON file has been successfully read!";
+		}
+		else
+		{
+			CLoadFile lf(scenarioOps->mapname);
+			lf >> dp;
+		}
+	}
+	catch(...)
+	{
+        logGlobal->errorStream() << "Cannot load duel settings from " << scenarioOps->mapname;
+		throw;
+	}
 
-				// Gen map
-				CMapGenerator mapGenerator;
-				map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release();
+	const CArmedInstance *armies[2] = {nullptr};
+	const CGHeroInstance *heroes[2] = {nullptr};
+	CGTownInstance *town = nullptr;
 
-				// Update starting options
-				for(int i = 0; i < map->players.size(); ++i)
-				{
-                    const auto & playerInfo = map->players[i];
-                    if(playerInfo.canAnyonePlay())
-					{
-                        PlayerSettings & playerSettings = scenarioOps->playerInfos[PlayerColor(i)];
-                        playerSettings.compOnly = !playerInfo.canHumanPlay;
-                        playerSettings.team = playerInfo.team;
-                        playerSettings.castle = playerInfo.defaultCastle();
-                        if(playerSettings.playerID == PlayerSettings::PLAYER_AI && playerSettings.name.empty())
-						{
-                            playerSettings.name = VLC->generaltexth->allTexts[468];
-						}
-                        playerSettings.color = PlayerColor(i);
-					}
-					else
-					{
-						scenarioOps->playerInfos.erase(PlayerColor(i));
-					}
-				}
+	for(int i = 0; i < 2; i++)
+	{
+		CArmedInstance *obj = nullptr;
+		if(dp.sides[i].heroId >= 0)
+		{
+			const DuelParameters::SideSettings &ss = dp.sides[i];
+			auto h = new CGHeroInstance();
+			armies[i] = heroes[i] = h;
+			obj = h;
+			h->subID = ss.heroId;
+			for(int i = 0; i < ss.heroPrimSkills.size(); i++)
+				h->pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(i), ss.heroPrimSkills[i]);
 
-				logGlobal->infoStream() << boost::format("Generated random map in %i ms.") % sw.getDiff();
+			if(!ss.spells.empty())
+			{
+				h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
+				boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin()));
 			}
-			else
+
+			for(auto &parka : ss.artifacts)
 			{
-                logGlobal->infoStream() << "Open map file: " << scenarioOps->mapname;
-				map = CMapService::loadMap(scenarioOps->mapname).release();
+				h->putArtifact(ArtifactPosition(parka.first), parka.second);
 			}
+
+			typedef const std::pair<si32, si8> &TSecSKill;
+			for(TSecSKill secSkill : ss.heroSecSkills)
+				h->setSecSkillLevel(SecondarySkill(secSkill.first), secSkill.second, 1);
+
+			h->initHero(HeroTypeID(h->subID));
+			obj->initObj();
 		}
-		break;
-	case StartInfo::CAMPAIGN:
+		else
+		{
+			auto c = new CGCreature();
+			armies[i] = obj = c;
+			//c->subID = 34;
+		}
+
+		obj->setOwner(PlayerColor(i));
+
+		for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
 		{
-            logGlobal->infoStream() << "Open campaign map file: " << scenarioOps->campState->currentMap;
-			auto campaign = scenarioOps->campState;
-			assert(vstd::contains(campaign->camp->mapPieces, *scenarioOps->campState->currentMap));
+			CreatureID cre = dp.sides[i].stacks[j].type;
+			TQuantity count = dp.sides[i].stacks[j].count;
+			if(count || obj->hasStackAtSlot(SlotID(j)))
+				obj->setCreature(SlotID(j), cre, count);
+		}
 
-			std::string & mapContent = campaign->camp->mapPieces[*scenarioOps->campState->currentMap];
-			auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
-			map = CMapService::loadMap(buffer, mapContent.size()).release();
+		for(const DuelParameters::CusomCreature &cc : dp.creatures)
+		{
+			CCreature *c = VLC->creh->creatures[cc.id];
+			if(cc.attack >= 0)
+				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack;
+			if(cc.defense >= 0)
+				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense;
+			if(cc.speed >= 0)
+				c->getBonusLocalFirst(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed;
+			if(cc.HP >= 0)
+				c->getBonusLocalFirst(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP;
+			if(cc.dmg >= 0)
+			{
+				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg;
+				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg;
+			}
+			if(cc.shoots >= 0)
+				c->getBonusLocalFirst(Selector::type(Bonus::SHOTS))->val = cc.shoots;
 		}
-		break;
-	case StartInfo::DUEL:
-		initDuel();
-		return;
-	default:
-        logGlobal->errorStream() << "Wrong mode: " << (int)scenarioOps->mode;
-		return;
 	}
-	VLC->arth->initAllowedArtifactsList(map->allowedArtifact);
-    logGlobal->infoStream() << "Map loaded!";
 
-    logGlobal->infoStream() << "\tOur checksum for the map: "<< map->checksum;
+	curB = BattleInfo::setupBattle(int3(), dp.terType, dp.bfieldType, armies, heroes, false, town);
+	curB->obstacles = dp.obstacles;
+	curB->localInit();
+}
+
+void CGameState::checkMapChecksum()
+{
+	logGlobal->infoStream() << "\tOur checksum for the map: "<< map->checksum;
 	if(scenarioOps->mapfileChecksum)
 	{
-        logGlobal->infoStream() << "\tServer checksum for " << scenarioOps->mapname <<": "<< scenarioOps->mapfileChecksum;
+		logGlobal->infoStream() << "\tServer checksum for " << scenarioOps->mapname <<": "<< scenarioOps->mapfileChecksum;
 		if(map->checksum != scenarioOps->mapfileChecksum)
 		{
-            logGlobal->errorStream() << "Wrong map checksum!!!";
+			logGlobal->errorStream() << "Wrong map checksum!!!";
 			throw std::runtime_error("Wrong checksum");
 		}
 	}
 	else
+	{
 		scenarioOps->mapfileChecksum = map->checksum;
+	}
+}
 
-	day = 0;
-
-    logGlobal->debugStream() << "Initialization:";
-    logGlobal->debugStream() << "\tPicking grail position";
- 	//pick grail location
- 	if(map->grailPos.x < 0 || map->grailRadious) //grail not set or set within a radius around some place
- 	{
+void CGameState::initGrailPosition()
+{
+	logGlobal->debugStream() << "\tPicking grail position";
+	//pick grail location
+	if(map->grailPos.x < 0 || map->grailRadious) //grail not set or set within a radius around some place
+	{
 		if(!map->grailRadious) //radius not given -> anywhere on map
 			map->grailRadious = map->width * 2;
 
- 		std::vector<int3> allowedPos;
+		std::vector<int3> allowedPos;
 		static const int BORDER_WIDTH = 9; // grail must be at least 9 tiles away from border
 
 		// add all not blocked tiles in range
@@ -939,13 +1019,13 @@ void CGameState::init(StartInfo * si)
 					const TerrainTile &t = map->getTile(int3(i, j, k));
 					if(!t.blocked
 						&& !t.visitable
-                        && t.terType != ETerrainType::WATER
-                        && t.terType != ETerrainType::ROCK
+						&& t.terType != ETerrainType::WATER
+						&& t.terType != ETerrainType::ROCK
 						&& map->grailPos.dist2d(int3(i,j,k)) <= map->grailRadious)
- 						allowedPos.push_back(int3(i,j,k));
- 				}
- 			}
- 		}
+						allowedPos.push_back(int3(i,j,k));
+				}
+			}
+		}
 
 		//remove tiles with holes
 		for(auto & elem : map->objects)
@@ -955,11 +1035,13 @@ void CGameState::init(StartInfo * si)
 		if(allowedPos.size())
 			map->grailPos = allowedPos[ran() % allowedPos.size()];
 		else
-            logGlobal->warnStream() << "Warning: Grail cannot be placed, no appropriate tile found!";
+			logGlobal->warnStream() << "Warning: Grail cannot be placed, no appropriate tile found!";
 	}
+}
 
-	//picking random factions for players
-    logGlobal->debugStream() << "\tPicking random factions for players";
+void CGameState::initRandomFactionsForPlayers()
+{
+	logGlobal->debugStream() << "\tPicking random factions for players";
 	for(auto & elem : scenarioOps->playerInfos)
 	{
 		if(elem.second.castle==-1)
@@ -971,30 +1053,36 @@ void CGameState::init(StartInfo * si)
 			elem.second.castle = *iter;
 		}
 	}
+}
 
-	//randomizing objects
-    logGlobal->debugStream() << "\tRandomizing objects";
+void CGameState::randomizeMapObjects()
+{
+	logGlobal->debugStream() << "\tRandomizing objects";
 	for(CGObjectInstance *obj : map->objects)
 	{
-		if(!obj)
-			continue;
+		if(!obj) continue;
 
 		randomizeObject(obj);
 		obj->hoverName = VLC->generaltexth->names[obj->ID];
 
 		//handle Favouring Winds - mark tiles under it
 		if(obj->ID == Obj::FAVORABLE_WINDS)
+		{
 			for (int i = 0; i < obj->getWidth() ; i++)
+			{
 				for (int j = 0; j < obj->getHeight() ; j++)
 				{
 					int3 pos = obj->pos - int3(i,j,0);
-					if(map->isInTheMap(pos))
-                        map->getTile(pos).extTileFlags |= 128;
+					if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
 				}
+			}
+		}
 	}
+}
 
-	/*********creating players entries in gs****************************************/
-    logGlobal->debugStream() << "\tCreating player entries in gs";
+void CGameState::initPlayerStates()
+{
+	logGlobal->debugStream() << "\tCreating player entries in gs";
 	for(auto & elem : scenarioOps->playerInfos)
 	{
 		std::pair<PlayerColor, PlayerState> ins(elem.first,PlayerState());
@@ -1005,8 +1093,10 @@ void CGameState::init(StartInfo * si)
 		teams[ins.second.team].players.insert(ins.first);//add player to team
 		players.insert(ins);
 	}
+}
 
-	/*************************replace hero placeholders*****************************/
+void CGameState::initHeroPlaceholders()
+{
 	if (scenarioOps->campState)
 	{
 		logGlobal->debugStream() << "\tReplacing hero placeholders";
@@ -1015,47 +1105,48 @@ void CGameState::init(StartInfo * si)
 		logGlobal->debugStream() << "\tSetting up heroes";
 		placeCampaignHeroes(campHeroReplacements);
 	}
+}
 
-
-	/*********give starting hero****************************************/
-    logGlobal->debugStream() << "\tGiving starting hero";
+void CGameState::placeStartingHeroes()
+{
+	logGlobal->debugStream() << "\tGiving starting hero";
+	bool campaignGiveHero = false;
+	if(scenarioOps->campState)
 	{
-		bool campaignGiveHero = false;
-		if(scenarioOps->campState)
+		if(auto bonus = scenarioOps->campState->getBonusForCurrentMap())
 		{
-			if(auto bonus = scenarioOps->campState->getBonusForCurrentMap())
-			{
-				campaignGiveHero =  scenarioOps->mode == StartInfo::CAMPAIGN &&
-					bonus.get().type == CScenarioTravel::STravelBonus::HERO;
-			}
+			campaignGiveHero =  scenarioOps->mode == StartInfo::CAMPAIGN &&
+				bonus.get().type == CScenarioTravel::STravelBonus::HERO;
 		}
+	}
 
-		for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
+	for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
+	{
+		const PlayerInfo &p = map->players[it->first.getNum()];
+		bool generateHero = (p.generateHeroAtMainTown ||
+							 (it->second.playerID != PlayerSettings::PLAYER_AI && campaignGiveHero)) && p.hasMainTown;
+		if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
 		{
-			const PlayerInfo &p = map->players[it->first.getNum()];
-			bool generateHero = (p.generateHeroAtMainTown ||
-			                     (it->second.playerID != PlayerSettings::PLAYER_AI && campaignGiveHero)) && p.hasMainTown;
-			if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
-			{
-				int3 hpos = p.posOfMainTown;
-				hpos.x+=1;
+			int3 hpos = p.posOfMainTown;
+			hpos.x+=1;
 
-				int h = pickHero(it->first);
-				if(it->second.hero == -1)
-					it->second.hero = h;
+			int h = pickHero(it->first);
+			if(it->second.hero == -1)
+				it->second.hero = h;
 
-				CGHeroInstance * nnn =  static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first));
-				nnn->id = ObjectInstanceID(map->objects.size());
-				nnn->initHero();
-				map->heroesOnMap.push_back(nnn);
-				map->objects.push_back(nnn);
-				map->addBlockVisTiles(nnn);
-			}
+			CGHeroInstance * nnn =  static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first));
+			nnn->id = ObjectInstanceID(map->objects.size());
+			nnn->initHero();
+			map->heroesOnMap.push_back(nnn);
+			map->objects.push_back(nnn);
+			map->addBlockVisTiles(nnn);
 		}
 	}
+}
 
-	/******************RESOURCES****************************************************/
-    logGlobal->debugStream() << "\tSetting up resources";
+void CGameState::initStartingResources()
+{
+	logGlobal->debugStream() << "\tSetting up resources";
 	const JsonNode config(ResourceID("config/startres.json"));
 	const JsonVector &vector = config["difficulty"].Vector();
 	const JsonNode &level = vector[scenarioOps->difficulty];
@@ -1073,6 +1164,19 @@ void CGameState::init(StartInfo * si)
 			p.resources = startresAI;
 	}
 
+	auto getHumanPlayerInfo = [&]() -> std::vector<const PlayerSettings *>
+	{
+		std::vector<const PlayerSettings *> ret;
+		for(auto it = scenarioOps->playerInfos.cbegin();
+			it != scenarioOps->playerInfos.cend(); ++it)
+		{
+			if(it->second.playerID != PlayerSettings::PLAYER_AI)
+				ret.push_back(&it->second);
+		}
+
+		return ret;
+	};
+
 	//give start resource bonus in case of campaign
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
@@ -1106,14 +1210,15 @@ void CGameState::init(StartInfo * si)
 			}
 		}
 	}
+}
 
-
-	/*************************HEROES INIT / POOL************************************************/
+void CGameState::initHeroes()
+{
 	for(auto hero : map->heroesOnMap)  //heroes instances initialization
 	{
 		if (hero->getOwner() == PlayerColor::UNFLAGGABLE)
 		{
-            logGlobal->warnStream() << "Warning - hero with uninitialized owner!";
+			logGlobal->warnStream() << "Warning - hero with uninitialized owner!";
 			continue;
 		}
 
@@ -1154,7 +1259,7 @@ void CGameState::init(StartInfo * si)
 
 	for(auto & elem : map->disposedHeroes)
 	{
-        hpool.pavailable[elem.heroId] = elem.players;
+		hpool.pavailable[elem.heroId] = elem.players;
 	}
 
 	if (scenarioOps->mode == StartInfo::CAMPAIGN) //give campaign bonuses for specific / best hero
@@ -1187,7 +1292,7 @@ void CGameState::init(StartInfo * si)
 					}
 				}
 				if(maxB < 0)
-                    logGlobal->warnStream() << "Warning - cannot give bonus to hero cause there are no heroes!";
+					logGlobal->warnStream() << "Warning - cannot give bonus to hero cause there are no heroes!";
 				else
 					giveCampaignBonusToHero(heroes[maxB]);
 			}
@@ -1204,9 +1309,68 @@ void CGameState::init(StartInfo * si)
 			}
 		}
 	}
+}
+
+void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero)
+{
+	const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
+	if(!curBonus)
+		return;
+
+	if(curBonus->isBonusForHero())
+	{
+		//apply bonus
+		switch (curBonus->type)
+		{
+		case CScenarioTravel::STravelBonus::SPELL:
+			hero->spells.insert(SpellID(curBonus->info2));
+			break;
+		case CScenarioTravel::STravelBonus::MONSTER:
+			{
+				for(int i=0; i<GameConstants::ARMY_SIZE; i++)
+				{
+					if(hero->slotEmpty(SlotID(i)))
+					{
+						hero->addToSlot(SlotID(i), CreatureID(curBonus->info2), curBonus->info3);
+						break;
+					}
+				}
+			}
+			break;
+		case CScenarioTravel::STravelBonus::ARTIFACT:
+			gs->giveHeroArtifact(hero, static_cast<ArtifactID>(curBonus->info2));
+			break;
+		case CScenarioTravel::STravelBonus::SPELL_SCROLL:
+			{
+				CArtifactInstance * scroll = CArtifactInstance::createScroll(SpellID(curBonus->info2).toSpell());
+				scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
+			}
+			break;
+		case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
+			{
+				const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus->info2);
+				for (int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
+				{
+					int val = ptr[g];
+					if (val == 0)
+					{
+						continue;
+					}
+					auto bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
+					hero->addNewBonus(bb);
+				}
+			}
+			break;
+		case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
+			hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, true);
+			break;
+		}
+	}
+}
 
-	/*************************FOG**OF**WAR******************************************/
-    logGlobal->debugStream() << "\tFog of war"; //FIXME: should be initialized after all bonuses are set
+void CGameState::initFogOfWar()
+{
+	logGlobal->debugStream() << "\tFog of war"; //FIXME: should be initialized after all bonuses are set
 	for(auto & elem : teams)
 	{
 		elem.second.fogOfWarMap.resize(map->width);
@@ -1234,8 +1398,11 @@ void CGameState::init(StartInfo * si)
 			}
 		}
 	}
+}
 
-    logGlobal->debugStream() << "\tStarting bonuses";
+void CGameState::initStartingBonus()
+{
+	logGlobal->debugStream() << "\tStarting bonuses";
 	for(auto & elem : players)
 	{
 		//starting bonus
@@ -1262,22 +1429,25 @@ void CGameState::init(StartInfo * si)
 			}
 		case PlayerSettings::ARTIFACT:
 			{
- 				if(!elem.second.heroes.size())
+				if(!elem.second.heroes.size())
 				{
-                    logGlobal->debugStream() << "Cannot give starting artifact - no heroes!";
+					logGlobal->debugStream() << "Cannot give starting artifact - no heroes!";
 					break;
 				}
- 				CArtifact *toGive;
- 				toGive = VLC->arth->artifacts[VLC->arth->getRandomArt (CArtifact::ART_TREASURE)];
+				CArtifact *toGive;
+				toGive = VLC->arth->artifacts[VLC->arth->getRandomArt (CArtifact::ART_TREASURE)];
 
 				CGHeroInstance *hero = elem.second.heroes[0];
- 				giveHeroArtifact(hero, toGive->id);
+				giveHeroArtifact(hero, toGive->id);
 			}
 			break;
 		}
 	}
-	/****************************TOWNS************************************************/
-    logGlobal->debugStream() << "\tTowns";
+}
+
+void CGameState::initTowns()
+{
+	logGlobal->debugStream() << "\tTowns";
 
 	//campaign bonuses for towns
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
@@ -1329,7 +1499,7 @@ void CGameState::init(StartInfo * si)
 		}
 
 		//#1444 - remove entries that don't have buildings defined (like some unused extra town hall buildings)
-		vstd::erase_if(vti->builtBuildings, [vti](BuildingID bid){  
+		vstd::erase_if(vti->builtBuildings, [vti](BuildingID bid){
 			return !vti->town->buildings.count(bid) || !vti->town->buildings.at(bid); });
 
 		if (vstd::contains(vti->builtBuildings, BuildingID::SHIPYARD) && vti->shipyardStatus()==IBoatGenerator::TILE_BLOCKED)
@@ -1415,8 +1585,11 @@ void CGameState::init(StartInfo * si)
 		if(vti->getOwner() != PlayerColor::NEUTRAL)
 			getPlayer(vti->getOwner())->towns.push_back(vti);
 	}
+}
 
-    logGlobal->debugStream() << "\tObject initialization";
+void CGameState::initMapObjects()
+{
+	logGlobal->debugStream() << "\tObject initialization";
 	objCaller->preInit();
 	for(CGObjectInstance *obj : map->objects)
 	{
@@ -1440,9 +1613,10 @@ void CGameState::init(StartInfo * si)
 		}
 	}
 	CGTeleport::postInit(); //pairing subterranean gates
+}
 
-	buildBonusSystemTree();
-
+void CGameState::initVisitingAndGarrisonedHeroes()
+{
 	for(auto k=players.begin(); k!=players.end(); ++k)
 	{
 		if(k->first==PlayerColor::NEUTRAL)
@@ -1468,124 +1642,6 @@ void CGameState::init(StartInfo * si)
 			}
 		}
 	}
-
-
-    logGlobal->debugStream() << "\tChecking objectives";
-	map->checkForObjectives(); //needs to be run when all objects are properly placed
-
-	int seedAfterInit = ran();
-    logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
-	if(scenarioOps->seedPostInit > 0)
-	{
-		//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
-		assert(scenarioOps->seedPostInit == seedAfterInit);
-	}
-	else
-	{
-		scenarioOps->seedPostInit = seedAfterInit; //store the post init "seed"
-	}
-}
-
-void CGameState::initDuel()
-{
-	DuelParameters dp;
-	try //CLoadFile likes throwing
-	{
-		if(boost::algorithm::ends_with(scenarioOps->mapname, ".json"))
-		{
-            logGlobal->infoStream() << "Loading duel settings from JSON file: " << scenarioOps->mapname;
-			dp = DuelParameters::fromJSON(scenarioOps->mapname);
-            logGlobal->infoStream() << "JSON file has been successfully read!";
-		}
-		else
-		{
-			CLoadFile lf(scenarioOps->mapname);
-			lf >> dp;
-		}
-	}
-	catch(...)
-	{
-        logGlobal->errorStream() << "Cannot load duel settings from " << scenarioOps->mapname;
-		throw;
-	}
-
-	const CArmedInstance *armies[2] = {nullptr};
-	const CGHeroInstance *heroes[2] = {nullptr};
-	CGTownInstance *town = nullptr;
-
-	for(int i = 0; i < 2; i++)
-	{
-		CArmedInstance *obj = nullptr;
-		if(dp.sides[i].heroId >= 0)
-		{
-			const DuelParameters::SideSettings &ss = dp.sides[i];
-			auto h = new CGHeroInstance();
-			armies[i] = heroes[i] = h;
-			obj = h;
-			h->subID = ss.heroId;
-			for(int i = 0; i < ss.heroPrimSkills.size(); i++)
-				h->pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(i), ss.heroPrimSkills[i]);
-
-			if(!ss.spells.empty())
-			{
-				h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
-				boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin()));
-			}
-
-			for(auto &parka : ss.artifacts)
-			{
-				h->putArtifact(ArtifactPosition(parka.first), parka.second);
-			}
-
-			typedef const std::pair<si32, si8> &TSecSKill;
-			for(TSecSKill secSkill : ss.heroSecSkills)
-				h->setSecSkillLevel(SecondarySkill(secSkill.first), secSkill.second, 1);
-
-			h->initHero(HeroTypeID(h->subID));
-			obj->initObj();
-		}
-		else
-		{
-			auto c = new CGCreature();
-			armies[i] = obj = c;
-			//c->subID = 34;
-		}
-
-		obj->setOwner(PlayerColor(i));
-
-		for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
-		{
-			CreatureID cre = dp.sides[i].stacks[j].type;
-			TQuantity count = dp.sides[i].stacks[j].count;
-			if(count || obj->hasStackAtSlot(SlotID(j)))
-				obj->setCreature(SlotID(j), cre, count);
-		}
-
-		for(const DuelParameters::CusomCreature &cc : dp.creatures)
-		{
-			CCreature *c = VLC->creh->creatures[cc.id];
-			if(cc.attack >= 0)
-				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack;
-			if(cc.defense >= 0)
-				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense;
-			if(cc.speed >= 0)
-				c->getBonusLocalFirst(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed;
-			if(cc.HP >= 0)
-				c->getBonusLocalFirst(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP;
-			if(cc.dmg >= 0)
-			{
-				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg;
-				c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg;
-			}
-			if(cc.shoots >= 0)
-				c->getBonusLocalFirst(Selector::type(Bonus::SHOTS))->val = cc.shoots;
-		}
-	}
-
-	curB = BattleInfo::setupBattle(int3(), dp.terType, dp.bfieldType, armies, heroes, false, town);
-	curB->obstacles = dp.obstacles;
-	curB->localInit();
-	return;
 }
 
 BFieldType CGameState::battleGetBattlefieldType(int3 tile) const
@@ -2555,32 +2611,31 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
 		//selecting heroes by type
 		for(int g=0; g<map->objects.size(); ++g)
 		{
-			const ObjectInstanceID gid = ObjectInstanceID(g);
 			CGObjectInstance * obj = map->objects[g];
-			if (obj->ID != Obj::HERO_PLACEHOLDER)
+			if (obj->ID == Obj::HERO_PLACEHOLDER)
 			{
-				continue;
-			}
-			CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
+				CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
 
-			if(hp->subID != 0xFF) //select by type
-			{
-				bool found = false;
-				for(auto ghi : Xheroes)
+				const ObjectInstanceID gid = ObjectInstanceID(g);
+				if(hp->subID != 0xFF) //select by type
 				{
-					if (ghi->subID == hp->subID)
+					bool found = false;
+					for(auto ghi : Xheroes)
 					{
-						found = true;
-						replaceHero(gid, ghi);
-						Xheroes -= ghi;
-						break;
+						if (ghi->subID == hp->subID)
+						{
+							found = true;
+							replaceHero(gid, ghi);
+							Xheroes -= ghi;
+							break;
+						}
+					}
+					if (!found)
+					{
+						auto  nh = new CGHeroInstance();
+						nh->initHero(HeroTypeID(hp->subID));
+						replaceHero(gid, nh);
 					}
-				}
-				if (!found)
-				{
-					auto  nh = new CGHeroInstance();
-					nh->initHero(HeroTypeID(hp->subID));
-					replaceHero(gid, nh);
 				}
 			}
 		}
@@ -2594,26 +2649,25 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
 
 		for(int g=0; g<map->objects.size(); ++g)
 		{
-			const ObjectInstanceID gid = ObjectInstanceID(g);
 			CGObjectInstance * obj = map->objects[g];
-			if (obj->ID != Obj::HERO_PLACEHOLDER)
+			if (obj->ID == Obj::HERO_PLACEHOLDER)
 			{
-				continue;
-			}
-			CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
+				CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
 
-			if (hp->subID == 0xFF) //select by power
-			{
-				if(Xheroes.size() > hp->power - 1)
-					replaceHero(gid, Xheroes[hp->power - 1]);
-				else
+				const ObjectInstanceID gid = ObjectInstanceID(g);
+				if (hp->subID == 0xFF) //select by power
 				{
-					logGlobal->warnStream() << "Warning, no hero to replace!";
-					map->removeBlockVisTiles(hp, true);
-					delete hp;
-					map->objects[g] = nullptr;
+					if(Xheroes.size() > hp->power - 1)
+						replaceHero(gid, Xheroes[hp->power - 1]);
+					else
+					{
+						logGlobal->warnStream() << "Warning, no hero to replace!";
+						map->removeBlockVisTiles(hp, true);
+						delete hp;
+						map->objects[g] = nullptr;
+					}
+					//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
 				}
-				//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
 			}
 		}
 	}

+ 55 - 36
lib/CGameState.h

@@ -29,11 +29,8 @@
  */
 
 class CTown;
-class CScriptCallback;
 class CCallback;
 class IGameCallback;
-class CLuaCallback;
-class CCPPObjectScript;
 class CCreatureSet;
 class CStack;
 class CQuest;
@@ -388,15 +385,6 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EVictoryLossCheck
 class DLL_LINKAGE CGameState : public CNonConstInfoCallback
 {
 public:
-	ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
-	PlayerColor currentPlayer; //ID of player currently having turn
-	ConstTransitivePtr<BattleInfo> curB; //current battle
-	ui32 day; //total number of days in game
-	ConstTransitivePtr<CMap> map;
-	std::map<PlayerColor, PlayerState> players;
-	std::map<TeamID, TeamState> teams;
-	CBonusSystemNode globalEffects;
-
 	struct DLL_LINKAGE HeroesPool
 	{
 		std::map<ui32, ConstTransitivePtr<CGHeroInstance> > heroesPool; //[subID] - heroes available to buy; nullptr if not available
@@ -410,18 +398,22 @@ public:
 		}
 	} hpool; //we have here all heroes available on this map that are not hired
 
-	boost::shared_mutex *mx;
+	CGameState();
+	virtual ~CGameState();
 
 	void init(StartInfo * si);
 
-	bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
-	void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements);
-	std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > campaignHeroesToReplace(); //returns heroes and placeholders in where heroes will be put; may remove some placeholders
-	std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
-	void initDuel();
-	void randomizeObject(CGObjectInstance *cur);
-	std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
-	int pickHero(PlayerColor owner);
+	ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
+	PlayerColor currentPlayer; //ID of player currently having turn
+	ConstTransitivePtr<BattleInfo> curB; //current battle
+	ui32 day; //total number of days in game
+	ConstTransitivePtr<CMap> map;
+	std::map<PlayerColor, PlayerState> players;
+	std::map<TeamID, TeamState> teams;
+	CBonusSystemNode globalEffects;
+
+	boost::shared_mutex *mx;
+
 	void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid);
 
 	void apply(CPack *pack);
@@ -439,38 +431,65 @@ public:
 	std::map<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
 	BattleInfo * setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town);
 
-	void buildBonusSystemTree();
-	void attachArmedObjects();
-	void buildGlobalTeamPlayerTree();
-	void deserializationFix();
-
 	bool isVisible(int3 pos, PlayerColor player);
 	bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
 
-	CGameState(); //c-tor
-	virtual ~CGameState(); //d-tor
 	void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing);
 	int getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints=-1, bool checkLast=true);
 	int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
 		BONUS_TREE_DESERIALIZATION_FIX
 	}
 
-	friend class CCallback;
-	friend class CLuaCallback;
-	friend class CClient;
-	friend void initGameState(CMap * map, CGameInfo * cgi);
-	friend class IGameCallback;
-	friend class CMapHandler;
-	friend class CGameHandler;
-
 private:
+	// Init game state
+	void initNewGame();
+	void initCampaign();
+	void initDuel();
+	void checkMapChecksum();
+	void initGrailPosition();
+	void initRandomFactionsForPlayers();
+	void randomizeMapObjects();
+	void randomizeObject(CGObjectInstance *cur);
+	void initPlayerStates();
+	void initHeroPlaceholders();
+	void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements);
+	void placeStartingHeroes();
+	void initStartingResources();
+	void initHeroes();
+	void giveCampaignBonusToHero(CGHeroInstance * hero);
+	void initFogOfWar();
+	void initStartingBonus();
+	void initTowns();
+	void initMapObjects();
+	void initVisitingAndGarrisonedHeroes();
+
+	// Victory / Loss condition checks
 	EVictoryLossCheckResult checkForVictory(PlayerColor player) const; //checks if given player is winner
 	EVictoryLossCheckResult checkForLoss(PlayerColor player) const; //checks if given player is loser
 	PlayerColor checkForStandardWin() const; //returns color of player that accomplished standard victory conditions or 255 (NEUTRAL) if no winner
 	bool checkForStandardLoss(PlayerColor player) const; //checks if given player lost the game
+
+	// Bonus system handling
+	void buildBonusSystemTree();
+	void attachArmedObjects();
+	void buildGlobalTeamPlayerTree();
+	void deserializationFix();
+
+	bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
+	std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > campaignHeroesToReplace(); //returns heroes and placeholders in where heroes will be put; may remove some placeholders
+	std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
+	std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
+	int pickHero(PlayerColor owner);
+
+	friend class CCallback;
+	friend class CClient;
+	friend class IGameCallback;
+	friend class CMapHandler;
+	friend class CGameHandler;
 };
 
 struct DLL_LINKAGE QuestInfo //universal interface for human and AI

+ 0 - 1
lib/CObjectHandler.h

@@ -25,7 +25,6 @@ struct BattleInfo;
 struct QuestInfo;
 class IGameCallback;
 struct BattleResult;
-class CCPPObjectScript;
 class CGObjectInstance;
 class CScript;
 class CObjectScript;

+ 3 - 4
lib/mapping/CCampaignHandler.cpp

@@ -443,10 +443,9 @@ boost::optional<CScenarioTravel::STravelBonus> CCampaignState::getBonusForCurren
 {
 	auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose;
 	assert(chosenCampaignBonuses.count(*currentMap) || bonuses.size() == 0);
-	if(bonuses.size())
-		return bonuses[currentBonusID()];
-	else
-		return boost::optional<CScenarioTravel::STravelBonus>();
+
+	if(bonuses.empty()) return boost::optional<CScenarioTravel::STravelBonus>();
+	else return bonuses[currentBonusID()];
 }
 
 const CCampaignScenario & CCampaignState::getCurrentScenario() const

+ 9 - 13
lib/mapping/CCampaignHandler.h

@@ -83,16 +83,6 @@ public:
 class DLL_LINKAGE CCampaignScenario
 {
 public:
-	std::string mapName; //*.h3m
-	std::string scenarioName; //from header. human-readble
-	ui32 packedMapSize; //generally not used
-	std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
-	ui8 regionColor;
-	ui8 difficulty;
-	bool conquered;
-
-	std::string regionText;
-
 	struct DLL_LINKAGE SScenarioPrologEpilog
 	{
 		bool hasPrologEpilog;
@@ -106,17 +96,23 @@ public:
 		}
 	};
 
+	std::string mapName; //*.h3m
+	std::string scenarioName; //from header. human-readble
+	ui32 packedMapSize; //generally not used
+	std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
+	ui8 regionColor;
+	ui8 difficulty;
+	bool conquered;
+
+	std::string regionText;
 	SScenarioPrologEpilog prolog, epilog;
 
 	CScenarioTravel travelOptions;
-
 	std::vector<CGHeroInstance *> crossoverHeroes;
 
 	const CGHeroInstance * strongestHero(PlayerColor owner) const;
-
 	void loadPreconditionRegions(ui32 regions);
 	void prepareCrossoverHeroes(std::vector<CGHeroInstance *> heroes);
-
 	bool isNotVoid() const;
 
 	template <typename Handler> void serialize(Handler &h, const int formatVersion)

+ 0 - 3
server/CGameHandler.h

@@ -24,8 +24,6 @@ class CGameHandler;
 class CVCMIServer;
 class CGameState;
 struct StartInfo;
-class CCPPObjectScript;
-class CScriptCallback;
 struct BattleResult;
 struct BattleAttack;
 struct BattleStackAttacked;
@@ -286,7 +284,6 @@ public:
 	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot);
 	void spawnWanderingMonsters(CreatureID creatureID);
 	friend class CVCMIServer;
-	friend class CScriptCallback;
 
 private:
 	std::list<PlayerColor> generatePlayerTurnOrder() const;