Browse Source

- move campaigns description into new config file, campaignSets.json
- campaigns parser uses binary reader, fixes #1711
- fixed description of change resolution button

Ivan Savenko 11 years ago
parent
commit
48d6e2cd59

+ 13 - 8
client/CPreGame.cpp

@@ -445,7 +445,15 @@ const JsonNode & CGPreGameConfig::getConfig() const
 	return config;
 }
 
-CGPreGameConfig::CGPreGameConfig() : config(JsonNode(ResourceID("config/mainmenu.json")))
+const JsonNode & CGPreGameConfig::getCampaigns() const
+{
+	return campaignSets;
+}
+
+
+CGPreGameConfig::CGPreGameConfig() :
+	campaignSets(JsonNode(ResourceID("config/campaignSets.json"))),
+	config(JsonNode(ResourceID("config/mainmenu.json")))
 {
 
 }
@@ -528,15 +536,12 @@ void CGPreGame::update()
 
 void CGPreGame::openCampaignScreen(std::string name)
 {
-	for(const JsonNode& node : CGPreGameConfig::get().getConfig()["campaignsset"].Vector())
+	if (vstd::contains(CGPreGameConfig::get().getCampaigns().Struct(), name))
 	{
-		if (node["name"].String() == name)
-		{
-			GH.pushInt(new CCampaignScreen(node));
-			return;
-		}
+		GH.pushInt(new CCampaignScreen(CGPreGameConfig::get().getCampaigns()[name]));
+		return;
 	}
-    logGlobal->errorStream()<<"Unknown campaign set: "<<name;
+	logGlobal->errorStream()<<"Unknown campaign set: "<<name;
 }
 
 CGPreGame *CGPreGame::create()

+ 2 - 0
client/CPreGame.h

@@ -578,10 +578,12 @@ class CGPreGameConfig
 public:
 	static CGPreGameConfig & get();
 	const JsonNode & getConfig() const;
+	const JsonNode & getCampaigns() const;
 
 private:
 	CGPreGameConfig();
 
+	const JsonNode campaignSets;
 	const JsonNode config;
 };
 

+ 64 - 0
config/campaignSets.json

@@ -0,0 +1,64 @@
+{
+	"roe" :
+	{
+		"images" : [ {"x": 0, "y": 0, "name":"CAMPBACK"} ],
+		"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
+		"items":
+		[
+			{ "x":90,  "y":72,  "file":"DATA/GOOD1.H3C",    "image":"CAMPGD1S", "video":"CGOOD1",   "open": true },
+			{ "x":539, "y":72,  "file":"DATA/EVIL1.H3C",    "image":"CAMPEV1S", "video":"CEVIL1",   "open": true },
+			{ "x":43,  "y":245, "file":"DATA/GOOD2.H3C",    "image":"CAMPGD2S", "video":"CGOOD2",   "open": true },
+			{ "x":313, "y":244, "file":"DATA/NEUTRAL1.H3C",  "image":"CAMPNEUS", "video":"CNEUTRAL", "open": true },
+			{ "x":586, "y":246, "file":"DATA/EVIL2.H3C",    "image":"CAMPEV2S", "video":"CEVIL2",   "open": true },
+			{ "x":34,  "y":417, "file":"DATA/GOOD3.H3C",    "image":"CAMPGD3S", "video":"CGOOD3",   "open": true },
+			{ "x":404, "y":414, "file":"DATA/SECRET1.H3C",   "image":"CAMPSCTS", "video":"CSECRET",  "open": true }
+		]
+	},
+	"ab" :
+	{
+		"images" :
+		[
+			{"x": 0,   "y": 0,   "name":"CAMPBACK"},
+			{"x": 34,  "y": 417, "name":"CAMP1FWX"},//one campaign have special inactive image
+			{"x": 385, "y": 401, "name":"CAMPNOSC"},//and the last one is not present
+		],
+		"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
+		"items":
+		[
+			{ "x":90,  "y":72,  "file":"DATA/AB.H3C",       "image":"CAMP1AB7", "video":"C1ab7", "open": true },
+			{ "x":539, "y":72,  "file":"DATA/BLOOD.H3C",    "image":"CAMP1DB2", "video":"C1db2", "open": true },
+			{ "x":43,  "y":245, "file":"DATA/SLAYER.H3C",   "image":"CAMP1DS1", "video":"C1ds1", "open": true },
+			{ "x":313, "y":244, "file":"DATA/FESTIVAL.H3C", "image":"CAMP1FL3", "video":"C1fl3", "open": true },
+			{ "x":586, "y":246, "file":"DATA/FIRE.H3C",     "image":"CAMP1PF2", "video":"C1pf2", "open": true },
+			{ "x":34,  "y":417, "file":"DATA/FOOL.H3C",     "image":"CAMP1FW1", "video":"C1fw1", "open": true }
+		]
+	},
+	"sod":
+	{
+		"images" : [ {"x": 0, "y": 0, "name":"CAMPBKX2"} ],
+		"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
+		"items":
+		[
+			{ "x":90,  "y":72,  "file":"DATA/GEM.H3C",      "image":"CAMPNB1", "video":"NEW",     "open": true },
+			{ "x":539, "y":72,  "file":"DATA/GELU.H3C",     "image":"CAMPEL1", "video":"ELIXIR",  "open": true },
+			{ "x":43,  "y":245, "file":"DATA/CRAG.H3C",     "image":"CAMPHS1", "video":"HACK",    "open": true },
+			{ "x":313, "y":244, "file":"DATA/SANDRO.H3C",   "image":"CAMPRN1", "video":"RISE",    "open": true },
+			{ "x":586, "y":246, "file":"DATA/YOG.H3C",      "image":"CAMPBB1", "video":"BIRTH",   "open": true },
+			{ "x":34,  "y":417, "file":"DATA/FINAL.H3C",    "image":"CAMPUA1", "video":"UNHOLY",  "open": true },
+			{ "x":404, "y":414, "file":"DATA/SECRET.H3C",  "image":"CAMPSP1", "video":"SPECTRE", "open": true }
+		]
+	},
+	"wog" : 
+	{
+		/// wog campaigns, currently has no assigned button in campaign screen and thus unused
+		"images" : [ {"x": 0, "y": 0, "name":"CAMPZALL"} ],
+		"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
+		"items":
+		[
+			{ "x":90,  "y":72,  "file":"DATA/ZC1.H3C", "image":"CAMPZ01", "open": true},
+			{ "x":539, "y":72,  "file":"DATA/ZC2.H3C", "image":"CAMPZ02", "open": true},
+			{ "x":43,  "y":245, "file":"DATA/ZC3.H3C", "image":"CAMPZ03", "open": true},
+			{ "x":311, "y":242, "file":"DATA/ZC4.H3C", "image":"CAMPZ04", "open": true}
+		]
+	}
+}

+ 1 - 69
config/mainmenu.json

@@ -60,73 +60,5 @@
 				],
 			}
 		]
-	},
-	//Campaigns windows, each campaigns set is a separate window activated by "campaigns %name%" command from main menu
-	"campaignsset":
-	[
-		{
-			"name":"roe",
-			"images" : [ {"x": 0, "y": 0, "name":"CAMPBACK"} ],
-			"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
-			"items":
-			[
-				{ "x":90,  "y":72,  "file":"DATA/GOOD1.H3C",    "image":"CAMPGD1S", "video":"CGOOD1",   "open": true },
-				{ "x":539, "y":72,  "file":"DATA/EVIL1.H3C",    "image":"CAMPEV1S", "video":"CEVIL1",   "open": true },
-				{ "x":43,  "y":245, "file":"DATA/GOOD2.H3C",    "image":"CAMPGD2S", "video":"CGOOD2",   "open": true },
-				{ "x":313, "y":244, "file":"DATA/NEUTRAL1.H3C",  "image":"CAMPNEUS", "video":"CNEUTRAL", "open": true },
-				{ "x":586, "y":246, "file":"DATA/EVIL2.H3C",    "image":"CAMPEV2S", "video":"CEVIL2",   "open": true },
-				{ "x":34,  "y":417, "file":"DATA/GOOD3.H3C",    "image":"CAMPGD3S", "video":"CGOOD3",   "open": true },
-				{ "x":404, "y":414, "file":"DATA/SECRET1.H3C",   "image":"CAMPSCTS", "video":"CSECRET",  "open": true }
-			]
-		},
-		{
-			"name":"ab",
-			"images" :
-			[
-				{"x": 0,   "y": 0,   "name":"CAMPBACK"},
-				{"x": 34,  "y": 417, "name":"CAMP1FWX"},//one campaign have special inactive image
-				{"x": 385, "y": 401, "name":"CAMPNOSC"},//and the last one is not present
-			],
-			"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
-			"items":
-			[
-				{ "x":90,  "y":72,  "file":"DATA/AB.H3C",       "image":"CAMP1AB7", "video":"C1ab7", "open": true },
-				{ "x":539, "y":72,  "file":"DATA/BLOOD.H3C",    "image":"CAMP1DB2", "video":"C1db2", "open": true },
-				{ "x":43,  "y":245, "file":"DATA/SLAYER.H3C",   "image":"CAMP1DS1", "video":"C1ds1", "open": true },
-				{ "x":313, "y":244, "file":"DATA/FESTIVAL.H3C", "image":"CAMP1FL3", "video":"C1fl3", "open": true },
-				{ "x":586, "y":246, "file":"DATA/FIRE.H3C",     "image":"CAMP1PF2", "video":"C1pf2", "open": true },
-				{ "x":34,  "y":417, "file":"DATA/FOOL.H3C",     "image":"CAMP1FW1", "video":"C1fw1", "open": true }
-			]
-
-		},
-		{
-			"name":"sod",
-			"images" : [ {"x": 0, "y": 0, "name":"CAMPBKX2"} ],
-			"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
-			"items":
-			[
-				{ "x":90,  "y":72,  "file":"DATA/GEM.H3C",      "image":"CAMPNB1", "video":"NEW",     "open": true },
-				{ "x":539, "y":72,  "file":"DATA/GELU.H3C",     "image":"CAMPEL1", "video":"ELIXIR",  "open": true },
-				{ "x":43,  "y":245, "file":"DATA/CRAG.H3C",     "image":"CAMPHS1", "video":"HACK",    "open": true },
-				{ "x":313, "y":244, "file":"DATA/SANDRO.H3C",   "image":"CAMPRN1", "video":"RISE",    "open": true },
-				{ "x":586, "y":246, "file":"DATA/YOG.H3C",      "image":"CAMPBB1", "video":"BIRTH",   "open": true },
-				{ "x":34,  "y":417, "file":"DATA/FINAL.H3C",    "image":"CAMPUA1", "video":"UNHOLY",  "open": true },
-				{ "x":404, "y":414, "file":"DATA/SECRET.H3C",  "image":"CAMPSP1", "video":"SPECTRE", "open": true }
-			]
-
-		},
-		{
-			"name":"wog", /// wog campaigns, currently has no assigned button in campaign screen and thus unused
-			"images" : [ {"x": 0, "y": 0, "name":"CAMPZALL"} ],
-			"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
-			"items":
-			[
-				{ "x":90,  "y":72,  "file":"DATA/ZC1.H3C", "image":"CAMPZ01", "open": true},
-				{ "x":539, "y":72,  "file":"DATA/ZC2.H3C", "image":"CAMPZ02", "open": true},
-				{ "x":43,  "y":245, "file":"DATA/ZC3.H3C", "image":"CAMPZ03", "open": true},
-				{ "x":311, "y":242, "file":"DATA/ZC4.H3C", "image":"CAMPZ04", "open": true}
-			]
-
-		}
-	]
+	}
 }

+ 1 - 1
config/translate.json

@@ -37,7 +37,7 @@
 		"resolutionButton" :
 		{
 			"label" : "Resolution",
-			"help"  : "{Select resolution}\n\n Change in-game screen resolution. Will only affect adventure map. Game restart required to apply new resolution."
+			"help"  : "{Select resolution}\n\n Change in-game screen resolution. Game restart required to apply new resolution."
 		},
 		"resolutionMenu" :
 		{

+ 72 - 85
lib/mapping/CCampaignHandler.cpp

@@ -3,6 +3,8 @@
 
 #include "../filesystem/Filesystem.h"
 #include "../filesystem/CCompressedStream.h"
+#include "../filesystem/CMemoryStream.h"
+#include "../filesystem/CBinaryReader.h"
 #include "../VCMI_Lib.h"
 #include "../vcmi_endian.h"
 #include "../CGeneralTextHandler.h"
@@ -30,8 +32,9 @@ CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
 {
 	std::vector<ui8> cmpgn = getFile(name, true)[0];
 
-	int it = 0;//iterator for reading
-	CCampaignHeader ret = readHeaderFromMemory(cmpgn.data(), it);
+	CMemoryStream stream(cmpgn.data(), cmpgn.size());
+	CBinaryReader reader(&stream);
+	CCampaignHeader ret = readHeaderFromMemory(reader);
 	ret.filename = name;
 
 	return ret;
@@ -43,14 +46,15 @@ unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
 
 	std::vector<std::vector<ui8>> file = getFile(name, false);
 
-	int it = 0; //iterator for reading
-	ret->header = readHeaderFromMemory(file[0].data(), it);
+	CMemoryStream stream(file[0].data(), file[0].size());
+	CBinaryReader reader(&stream);
+	ret->header = readHeaderFromMemory(reader);
 	ret->header.filename = name;
 
 	int howManyScenarios = VLC->generaltexth->campaignRegionNames[ret->header.mapVersion].size();
 	for(int g=0; g<howManyScenarios; ++g)
 	{
-		CCampaignScenario sc = readScenarioFromMemory(file[0].data(), it, ret->header.version, ret->header.mapVersion);
+		CCampaignScenario sc = readScenarioFromMemory(reader, ret->header.version, ret->header.mapVersion);
 		ret->scenarios.push_back(sc);
 	}
 
@@ -77,59 +81,56 @@ unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
 	return ret;
 }
 
-CCampaignHeader CCampaignHandler::readHeaderFromMemory( const ui8 *buffer, int & outIt )
+CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader )
 {
 	CCampaignHeader ret;
-	ret.version = read_le_u32(buffer + outIt); outIt+=4;
-	ret.mapVersion = buffer[outIt++]; //1 byte only
-	ret.mapVersion -= 1; //change range of it from [1, 20] to [0, 19]
-	ret.name = readString(buffer, outIt);
-	ret.description = readString(buffer, outIt);
+
+	ret.version = reader.readUInt32();
+	ret.mapVersion = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
+	ret.name = reader.readString();
+	ret.description = reader.readString();
 	if (ret.version > CampaignVersion::RoE)
-		ret.difficultyChoosenByPlayer = readChar(buffer, outIt);
+		ret.difficultyChoosenByPlayer = reader.readInt8();
 	else
 		ret.difficultyChoosenByPlayer = 0;
-	ret.music = readChar(buffer, outIt);
+	ret.music = reader.readInt8();
 	return ret;
 }
 
-CCampaignScenario CCampaignHandler::readScenarioFromMemory( const ui8 *buffer, int & outIt, int version, int mapVersion )
+CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & reader, int version, int mapVersion )
 {
-	struct HLP
+	auto prologEpilogReader = [&]() -> CCampaignScenario::SScenarioPrologEpilog
 	{
-		//reads prolog/epilog info from memory
-		static CCampaignScenario::SScenarioPrologEpilog prologEpilogReader( const ui8 *buffer, int & outIt )
+		CCampaignScenario::SScenarioPrologEpilog ret;
+		ret.hasPrologEpilog = reader.readUInt8();
+		if(ret.hasPrologEpilog)
 		{
-			CCampaignScenario::SScenarioPrologEpilog ret;
-			ret.hasPrologEpilog = buffer[outIt++];
-			if(ret.hasPrologEpilog)
-			{
-				ret.prologVideo = buffer[outIt++];
-				ret.prologMusic = buffer[outIt++];
-				ret.prologText = readString(buffer, outIt);
-			}
-			return ret;
+			ret.prologVideo = reader.readUInt8();
+			ret.prologMusic = reader.readUInt8();
+			ret.prologText = reader.readString();
 		}
+		return ret;
 	};
+
 	CCampaignScenario ret;
 	ret.conquered = false;
-	ret.mapName = readString(buffer, outIt);
-	ret.packedMapSize = read_le_u32(buffer + outIt); outIt += 4;
+	ret.mapName = reader.readString();
+	ret.packedMapSize = reader.readUInt32();
 	if(mapVersion == 18)//unholy alliance
 	{
-		ret.loadPreconditionRegions(read_le_u16(buffer + outIt)); outIt += 2;
+		ret.loadPreconditionRegions(reader.readUInt16());
 	}
 	else
 	{
-		ret.loadPreconditionRegions(buffer[outIt++]);
+		ret.loadPreconditionRegions(reader.readUInt8());
 	}
-	ret.regionColor = buffer[outIt++];
-	ret.difficulty = buffer[outIt++];
-	ret.regionText = readString(buffer, outIt);
-	ret.prolog = HLP::prologEpilogReader(buffer, outIt);
-	ret.epilog = HLP::prologEpilogReader(buffer, outIt);
+	ret.regionColor = reader.readUInt8();
+	ret.difficulty = reader.readUInt8();
+	ret.regionText = reader.readString();
+	ret.prolog = prologEpilogReader();
+	ret.epilog = prologEpilogReader();
 
-	ret.travelOptions = readScenarioTravelFromMemory(buffer, outIt, version);
+	ret.travelOptions = readScenarioTravelFromMemory(reader, version);
 
 	return ret;
 }
@@ -143,28 +144,25 @@ void CCampaignScenario::loadPreconditionRegions(ui32 regions)
 	}
 }
 
-CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version )
+CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory(CBinaryReader & reader, int version )
 {
 	CScenarioTravel ret;
 
-	ret.whatHeroKeeps = buffer[outIt++];
-	memcpy(ret.monstersKeptByHero, buffer+outIt, ARRAY_COUNT(ret.monstersKeptByHero));
-	outIt += ARRAY_COUNT(ret.monstersKeptByHero);
-	int artifBytes;
+	ret.whatHeroKeeps = reader.readUInt8();
+	reader.getStream()->read(ret.monstersKeptByHero.data(), ret.monstersKeptByHero.size());
+
 	if (version < CampaignVersion::SoD)
 	{
-		artifBytes = 17;
-		ret.artifsKeptByHero[17] = 0;
+		ret.artifsKeptByHero.fill(0);
+		reader.getStream()->read(ret.artifsKeptByHero.data(), ret.artifsKeptByHero.size() - 1);
 	} 
 	else
 	{
-		artifBytes = 18;
+		reader.getStream()->read(ret.artifsKeptByHero.data(), ret.artifsKeptByHero.size());
 	}
-	memcpy(ret.artifsKeptByHero, buffer+outIt, artifBytes);
-	outIt += artifBytes;
 
-	ret.startOptions = buffer[outIt++];
-	
+	ret.startOptions = reader.readUInt8();
+
 	switch(ret.startOptions)
 	{
 	case 0:
@@ -172,64 +170,64 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buff
 		break;
 	case 1: //reading of bonuses player can choose
 		{
-			ret.playerColor = buffer[outIt++];
-			ui8 numOfBonuses = buffer[outIt++];
+			ret.playerColor = reader.readUInt8();
+			ui8 numOfBonuses = reader.readUInt8();
 			for (int g=0; g<numOfBonuses; ++g)
 			{
 				CScenarioTravel::STravelBonus bonus;
-				bonus.type = static_cast<CScenarioTravel::STravelBonus::EBonusType>(buffer[outIt++]);
+				bonus.type = static_cast<CScenarioTravel::STravelBonus::EBonusType>(reader.readUInt8());
 				//hero: FFFD means 'most powerful' and FFFE means 'generated'
 				switch(bonus.type)
 				{
 				case CScenarioTravel::STravelBonus::SPELL:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = buffer[outIt++]; //spell ID
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt8(); //spell ID
 						break;
 					}
 				case CScenarioTravel::STravelBonus::MONSTER:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //monster type
-						bonus.info3 = read_le_u16(buffer + outIt); outIt += 2; //monster count
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt16(); //monster type
+						bonus.info3 = reader.readUInt16(); //monster count
 						break;
 					}
 				case CScenarioTravel::STravelBonus::BUILDING:
 					{
-						bonus.info1 = buffer[outIt++]; //building ID (0 - town hall, 1 - city hall, 2 - capitol, etc)
+						bonus.info1 = reader.readUInt8(); //building ID (0 - town hall, 1 - city hall, 2 - capitol, etc)
 						break;
 					}
 				case CScenarioTravel::STravelBonus::ARTIFACT:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //artifact ID
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt16(); //artifact ID
 						break;
 					}
 				case CScenarioTravel::STravelBonus::SPELL_SCROLL:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = buffer[outIt++]; //spell ID
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt8(); //spell ID
 						break;
 					}
 				case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = read_le_u32(buffer + outIt); outIt += 4; //bonuses (4 bytes for 4 skills)
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt32(); //bonuses (4 bytes for 4 skills)
 						break;
 					}
 				case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
 					{
-						bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
-						bonus.info2 = buffer[outIt++]; //skill ID
-						bonus.info3 = buffer[outIt++]; //skill level
+						bonus.info1 = reader.readUInt16(); //hero
+						bonus.info2 = reader.readUInt8(); //skill ID
+						bonus.info3 = reader.readUInt8(); //skill level
 						break;
 					}
 				case CScenarioTravel::STravelBonus::RESOURCE:
 					{
-						bonus.info1 = buffer[outIt++]; //type
+						bonus.info1 = reader.readUInt8(); //type
 						//FD - wood+ore
 						//FE - mercury+sulfur+crystal+gem
-						bonus.info2 = read_le_u32(buffer + outIt); outIt += 4; //count
+						bonus.info2 = reader.readUInt32(); //count
 						break;
 					}
 				default:
@@ -242,13 +240,13 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buff
 		}
 	case 2: //reading of players (colors / scenarios ?) player can choose
 		{
-			ui8 numOfBonuses = buffer[outIt++];
+			ui8 numOfBonuses = reader.readUInt8();
 			for (int g=0; g<numOfBonuses; ++g)
 			{
 				CScenarioTravel::STravelBonus bonus;
 				bonus.type = CScenarioTravel::STravelBonus::HEROES_FROM_PREVIOUS_SCENARIO;
-				bonus.info1 = buffer[outIt++]; //player color
-				bonus.info2 = buffer[outIt++]; //from what scenario
+				bonus.info1 = reader.readUInt8(); //player color
+				bonus.info2 = reader.readUInt8(); //from what scenario
 
 				ret.bonusesToChoose.push_back(bonus);
 			}
@@ -256,13 +254,13 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buff
 		}
 	case 3: //heroes player can choose between
 		{
-			ui8 numOfBonuses = buffer[outIt++];
+			ui8 numOfBonuses = reader.readUInt8();
 			for (int g=0; g<numOfBonuses; ++g)
 			{
 				CScenarioTravel::STravelBonus bonus;
 				bonus.type = CScenarioTravel::STravelBonus::HERO;
-				bonus.info1 = buffer[outIt++]; //player color
-				bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //hero, FF FF - random
+				bonus.info1 = reader.readUInt8(); //player color
+				bonus.info2 = reader.readUInt16(); //hero, FF FF - random
 
 				ret.bonusesToChoose.push_back(bonus);
 			}
@@ -360,17 +358,6 @@ bool CScenarioTravel::STravelBonus::isBonusForHero() const
 		|| type == SECONDARY_SKILL;
 }
 
-// void CCampaignState::initNewCampaign( const StartInfo &si )
-// {
-// 	assert(si.mode == StartInfo::CAMPAIGN);
-// 	campaignName = si.mapname;
-// 	currentMap = si.campState->currentMap;
-// 
-// 	camp = CCampaignHandler::getCampaign(campaignName);
-// 	for (ui8 i = 0; i < camp->mapPieces.size(); i++)
-// 		mapsRemaining.push_back(i);
-// }
-
 void CCampaignState::setCurrentMapAsConquered( const std::vector<CGHeroInstance*> & heroes )
 {
 	camp->scenarios[*currentMap].crossoverHeroes = heroes;

+ 6 - 5
lib/mapping/CCampaignHandler.h

@@ -15,6 +15,7 @@
 
 struct StartInfo;
 class CGHeroInstance;
+class CBinaryReader;
 
 namespace CampaignVersion
 {
@@ -49,8 +50,8 @@ class DLL_LINKAGE CScenarioTravel
 {
 public:
 	ui8 whatHeroKeeps; //bitfield [0] - experience, [1] - prim skills, [2] - sec skills, [3] - spells, [4] - artifacts
-	ui8 monstersKeptByHero[19];
-	ui8 artifsKeptByHero[18];
+	std::array<ui8, 19> monstersKeptByHero;
+	std::array<ui8, 18> artifsKeptByHero;
 
 	ui8 startOptions; //1 - start bonus, 2 - traveling hero, 3 - hero options
 
@@ -170,9 +171,9 @@ public:
 
 class DLL_LINKAGE CCampaignHandler
 {
-	static CCampaignHeader readHeaderFromMemory( const ui8 *buffer, int & outIt );
-	static CCampaignScenario readScenarioFromMemory( const ui8 *buffer, int & outIt, int version, int mapVersion );
-	static CScenarioTravel readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version);
+	static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader);
+	static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, int version, int mapVersion );
+	static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version);
 	/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
 	/// headerOnly - only header will be decompressed, returned vector wont have any maps
 	static std::vector< std::vector<ui8> > getFile(const std::string & name, bool headerOnly);