Bläddra i källkod

* (hopefully) full reading of h3c
* minor changes

mateuszb 15 år sedan
förälder
incheckning
8637b021cc

+ 19 - 40
client/CCreatureAnimation.cpp

@@ -45,11 +45,11 @@ CCreatureAnimation::CCreatureAnimation(std::string name) : internalFrame(0), onc
 	char Buffer[13];
 	defName=name;
 	i = 0;
-	DEFType = readNormalNr(i,4); i+=4;
-	fullWidth = readNormalNr(i,4); i+=4;
-	fullHeight = readNormalNr(i,4); i+=4;
+	DEFType = readNormalNr<4>(i,FDef); i+=4;
+	fullWidth = readNormalNr<4>(i,FDef); i+=4;
+	fullHeight = readNormalNr<4>(i,FDef); i+=4;
 	i=0xc;
-	totalBlocks = readNormalNr(i,4); i+=4;
+	totalBlocks = readNormalNr<4>(i,FDef); i+=4;
 
 	i=0x10;
 	for (int it=0;it<256;it++)
@@ -64,20 +64,20 @@ CCreatureAnimation::CCreatureAnimation(std::string name) : internalFrame(0), onc
 	for (int z=0; z<totalBlocks; z++)
 	{
 		std::vector<int> frameIDs;
-		int group = readNormalNr(i,4); i+=4; //block ID
-		totalInBlock = readNormalNr(i,4); i+=4;
+		int group = readNormalNr<4>(i,FDef); i+=4; //block ID
+		totalInBlock = readNormalNr<4>(i,FDef); i+=4;
 		for (j=SEntries.size(); j<totalEntries+totalInBlock; j++)
 		{
 			SEntries.push_back(SEntry());
 			SEntries[j].group = group;
 			frameIDs.push_back(j);
 		}
-		int unknown2 = readNormalNr(i,4); i+=4; //TODO use me
-		int unknown3 = readNormalNr(i,4); i+=4; //TODO use me
+		int unknown2 = readNormalNr<4>(i,FDef); i+=4; //TODO use me
+		int unknown3 = readNormalNr<4>(i,FDef); i+=4; //TODO use me
 		i+=13*totalInBlock; //ommiting names
 		for (j=0; j<totalInBlock; j++)
 		{ 
-			SEntries[totalEntries+j].offset = readNormalNr(i,4); i+=4;
+			SEntries[totalEntries+j].offset = readNormalNr<4>(i,FDef); i+=4;
 		}
 		//totalEntries+=totalInBlock;
 		for(int hh=0; hh<totalInBlock; ++hh)
@@ -93,32 +93,11 @@ CCreatureAnimation::CCreatureAnimation(std::string name) : internalFrame(0), onc
 	frames = totalEntries;
 }
 
-int CCreatureAnimation::readNormalNr (int pos, int bytCon, unsigned char * str) const
-{
-	int ret=0;
-	int amp=1;
-	if (str)
-	{
-		for (int i=0; i<bytCon; i++)
-		{
-			ret+=str[pos+i]*amp;
-			amp<<=8; //amp*=256;
-		}
-	}
-	else 
-	{
-		for (int i=0; i<bytCon; i++)
-		{
-			ret+=FDef[pos+i]*amp;
-			amp<<=8; //amp*=256;
-		}
-	}
-	return ret;
-}
 int CCreatureAnimation::nextFrameMiddle(SDL_Surface *dest, int x, int y, bool attacker, unsigned char animCount, bool incrementFrame, bool yellowBorder, bool blueBorder, SDL_Rect * destRect)
 {
 	return nextFrame(dest, x-fullWidth/2, y-fullHeight/2, attacker, animCount, incrementFrame, yellowBorder, blueBorder, destRect);
 }
+
 void CCreatureAnimation::incrementFrame()
 {
 	if(type!=-1) //when a specific part of animation is played
@@ -190,14 +169,14 @@ int CCreatureAnimation::nextFrame(SDL_Surface *dest, int x, int y, bool attacker
 	unsigned char SegmentType, SegmentLength;
 	
 	i=BaseOffset=SEntries[SIndex].offset;
-	int prSize=readNormalNr(i,4,FDef);i+=4;//TODO use me
-	int defType2 = readNormalNr(i,4,FDef);i+=4;
-	FullWidth = readNormalNr(i,4,FDef);i+=4;
-	FullHeight = readNormalNr(i,4,FDef);i+=4;
-	SpriteWidth = readNormalNr(i,4,FDef);i+=4;
-	SpriteHeight = readNormalNr(i,4,FDef);i+=4;
-	LeftMargin = readNormalNr(i,4,FDef);i+=4;
-	TopMargin = readNormalNr(i,4,FDef);i+=4;
+	int prSize=readNormalNr<4>(i,FDef);i+=4;//TODO use me
+	int defType2 = readNormalNr<4>(i,FDef);i+=4;
+	FullWidth = readNormalNr<4>(i,FDef);i+=4;
+	FullHeight = readNormalNr<4>(i,FDef);i+=4;
+	SpriteWidth = readNormalNr<4>(i,FDef);i+=4;
+	SpriteHeight = readNormalNr<4>(i,FDef);i+=4;
+	LeftMargin = readNormalNr<4>(i,FDef);i+=4;
+	TopMargin = readNormalNr<4>(i,FDef);i+=4;
 	RightMargin = FullWidth - SpriteWidth - LeftMargin;
 	BottomMargin = FullHeight - SpriteHeight - TopMargin;
 
@@ -205,7 +184,7 @@ int CCreatureAnimation::nextFrame(SDL_Surface *dest, int x, int y, bool attacker
 
 	int ftcp = 0;
 
-	if (defType2==1) //as it should be allways in creature animations
+	if (defType2==1) //as it should be always in creature animations
 	{
 		if (TopMargin>0)
 		{

+ 14 - 1
client/CCreatureAnimation.h

@@ -29,7 +29,20 @@ private:
 	} ;
 	std::vector<SEntry> SEntries ;
 	std::string defName, curDir;
-	int readNormalNr (int pos, int bytCon, unsigned char * str=NULL) const;
+	template< int bytCon > static int readNormalNr (int pos, unsigned char * str)
+	{
+		int ret=0;
+		int amp=1;
+
+		for (int i=0; i<bytCon; i++)
+		{
+			ret+=str[pos+i]*amp;
+			amp<<=8; //amp*=256;
+		}
+
+		return ret;
+	}
+
 	void putPixel(
                 SDL_Surface * dest,
                 const int & ftcp,

+ 1 - 1
client/CPreGame.cpp

@@ -110,7 +110,7 @@ CMenuScreen::CMenuScreen( EState which )
 			////just for testing
 			CCampaignHandler * ch = new CCampaignHandler();
 			ch->getCampaignHeaders(); 
-			//ch->getCampaign("./Maps/1 Test cmpgn.h3c");
+			ch->getCampaign("./Maps/ALEXIS.h3c");
 		}
 		break;
 	}

+ 1 - 0
client/Graphics.cpp

@@ -17,6 +17,7 @@
 #include "../CCallback.h"
 #include "../hch/CTownHandler.h"
 #include "../hch/CObjectHandler.h"
+#include "../hch/CGeneralTextHandler.h"
 
 using namespace boost::assign;
 using namespace CSDL_Ext;

+ 120 - 4
hch/CCampaignHandler.cpp

@@ -5,6 +5,8 @@
 #include <stdio.h>
 #include <boost/algorithm/string/predicate.hpp>
 #include "CLodHandler.h"
+#include "../lib/VCMI_Lib.h"
+#include "CGeneralTextHandler.h"
 
 namespace fs = boost::filesystem;
 
@@ -68,9 +70,34 @@ CCampaign * CCampaignHandler::getCampaign( const std::string & name )
 	int it = 0; //iterator for reading
 	ret->header = readHeaderFromMemory(cmpgn, it);
 
-	it += 112; //omitting rubbish
-	CCampaignScenario sc = readScenarioFromMemory(cmpgn, it);
-	CCampaignScenario sc2 = readScenarioFromMemory(cmpgn, it);
+	int howManyScenarios = VLC->generaltexth->campaignRegionNames[ret->header.mapVersion].size();
+	for(int g=0; g<howManyScenarios; ++g)
+	{
+		CCampaignScenario sc = readScenarioFromMemory(cmpgn, it);
+		ret->scenarios.push_back(sc);
+	}
+
+	std::vector<ui32> h3mStarts = locateH3mStarts(cmpgn, it, realSize);
+
+	if(h3mStarts.size() != howManyScenarios)
+	{
+		tlog1<<"Our heuristic for h3m start points gave wrong results for campaign " << name <<std::endl;
+		tlog1<<"Please send this campaign to VCMI Project team to help us fix this problem" << std::endl;
+		delete [] cmpgn;
+		return NULL;
+	}
+
+	for (int g=0; g<howManyScenarios; ++g)
+	{
+		if(g == howManyScenarios - 1)
+		{
+			ret->mapPieces.push_back(std::string( cmpgn + h3mStarts[g], cmpgn + realSize ));
+		}
+		else
+		{
+			ret->mapPieces.push_back(std::string( cmpgn + h3mStarts[g], cmpgn + h3mStarts[g+1] ));
+		}
+	}
 
 	delete [] cmpgn;
 
@@ -86,6 +113,10 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( const unsigned char *buf
 	ret.description = readString(buffer, outIt);
 	ret.difficultyChoosenByPlayer = readChar(buffer, outIt);
 	ret.music = readChar(buffer, outIt);
+	if(ret.version == 4)	//I saw one campaign with this version, without either difficulty or music - it's  
+	{						//not editable by any editor so I'll just go back by one byte.
+		outIt--;
+	}
 
 	return ret;
 }
@@ -162,7 +193,7 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const unsigned c
 					}
 				case 2: //building
 					{
-						//TODO
+						bonus.info1 = buffer[outIt++]; //building ID (0 - town hall, 1 - city hall, 2 - capitol, etc)
 						break;
 					}
 				case 3: //artifact
@@ -239,4 +270,89 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const unsigned c
 	}
 
 	return ret;
+}
+
+std::vector<ui32> CCampaignHandler::locateH3mStarts( const unsigned char * buffer, int start, int size )
+{
+	std::vector<ui32> ret;
+	for(int g=start; g<size; ++g)
+	{
+		if(startsAt(buffer, size, g))
+		{
+			ret.push_back(g);
+		}
+	}
+
+	return ret;
+}
+
+bool CCampaignHandler::startsAt( const unsigned char * buffer, int size, int pos )
+{
+	struct HLP
+	{
+		static unsigned char at(const unsigned char * buffer, int size, int place)
+		{
+			if(place < size)
+				return buffer[place];
+
+			throw std::string("Out of bounds!");
+		}
+	};
+	try
+	{
+		//check minimal length of given region
+		HLP::at(buffer, size, 100);
+		//check version
+
+		unsigned char tmp = HLP::at(buffer, size, pos);
+		if(!(tmp == 0x0e || tmp == 0x15 || tmp == 0x1c || tmp == 0x33))
+		{
+			return false;
+		}
+		//3 bytes following version
+		if(HLP::at(buffer, size, pos+1) != 0 || HLP::at(buffer, size, pos+2) != 0 || HLP::at(buffer, size, pos+3) != 0)
+		{
+			return false;
+		}
+		//unknown strange byte
+		tmp = HLP::at(buffer, size, pos+4);
+		if(tmp != 0 && tmp != 1 )
+		{
+			return false;
+		}
+		//size of map
+		int mapsize = readNormalNr(buffer, pos+5);
+		if(mapsize < 10 || mapsize > 530) 
+		{
+			return false;
+		}
+
+		//underground or not
+		tmp = HLP::at(buffer, size, pos+9);
+		if( tmp != 0 && tmp != 1 )
+		{
+			return false;
+		}
+
+		//map name
+		int len = readNormalNr(buffer, pos+10);
+		if(len < 0 || len > 100)
+		{
+			return false;
+		}
+		for(int t=0; t<len; ++t)
+		{
+			tmp = HLP::at(buffer, size, pos+14+t);
+			if(tmp == 0 || (tmp > 15 && tmp < 32)) //not a valid character
+			{
+				return false;
+			}
+		}
+
+	}
+	catch (...)
+	{
+		return false;
+	}
+	return true;
 }

+ 4 - 1
hch/CCampaignHandler.h

@@ -101,10 +101,11 @@ class DLL_EXPORT CCampaign
 public:
 	CCampaignHeader header;
 	std::vector<CCampaignScenario> scenarios;
+	std::vector<std::string> mapPieces; //binary h3ms
 
 	template <typename Handler> void serialize(Handler &h, const int formatVersion)
 	{
-		h & header & scenarios;
+		h & header & scenarios & mapPieces;
 	}
 };
 
@@ -114,6 +115,8 @@ class DLL_EXPORT CCampaignHandler
 	CCampaignScenario readScenarioFromMemory( const unsigned char *buffer, int & outIt );
 	CScenarioTravel readScenarioTravelFromMemory( const unsigned char * buffer, int & outIt );
 	CCampaignHeader getHeader( const std::string & name, int size );
+	std::vector<ui32> locateH3mStarts(const unsigned char * buffer, int start, int size);
+	static bool startsAt( const unsigned char * buffer, int size, int pos ); //a simple heuristic that checks if a h3m starts at given pos
 public:
 	std::vector<CCampaignHeader> getCampaignHeaders();
 

+ 36 - 4
hch/CGeneralTextHandler.cpp

@@ -18,7 +18,7 @@
  *
  */
 
-std::string readTo(std::string &in, int &it, char end)
+std::string readTo(const std::string &in, int &it, char end)
 {
 	int pom = it;
 	int last = in.find_first_of(end,it);
@@ -470,7 +470,7 @@ void CGeneralTextHandler::load()
 		quests[i].resize(5);
 		for (j = 0; j < 5; ++j)
 		{
-			loadToIt (dump, buf, it, 4); //front desciption
+			loadToIt (dump, buf, it, 4); //front description
 			quests[i][j].resize(6);
 			for (k = 0; k < 5; ++k)
 			{
@@ -500,10 +500,41 @@ void CGeneralTextHandler::load()
 	
 	for (i = 14; i < 48; ++i)
 		loadToIt(seerNames[i], buf, it, 3);
+
+	//campaigns
+	buf = bitmaph->getTextFile ("CAMPTEXT.TXT");
+	it = 0;
+	loadToIt (dump, buf, it, 3); //comment
+	std::string nameBuf;
+	do //map names
+	{
+		loadToIt(nameBuf, buf, it, 3);
+		if(nameBuf.size())
+		{
+			campaignMapNames.push_back(nameBuf);
+		}
+	} while (nameBuf.size());
+
+	campaignRegionNames.resize(campaignMapNames.size()); //allocating space
+	for(int g=0; g<campaignMapNames.size(); ++g) //region names
+	{
+		do //dump comments and empty lines
+		{
+			loadToIt(nameBuf, buf, it, 3);
+		} while (nameBuf[0] != '/');
+		do //actual names
+		{
+			loadToIt(nameBuf, buf, it, 3);
+			if(nameBuf.size())
+			{
+				campaignRegionNames[g].push_back(nameBuf);
+			}
+		} while (nameBuf.size());
+	}
 }
 
 
-std::string CGeneralTextHandler::getTitle(std::string text)
+std::string CGeneralTextHandler::getTitle(const std::string & text)
 {
 	std::string ret;
 	int i=0;
@@ -512,7 +543,8 @@ std::string CGeneralTextHandler::getTitle(std::string text)
 		ret+=text[i++];
 	return ret;
 }
-std::string CGeneralTextHandler::getDescr(std::string text)
+
+std::string CGeneralTextHandler::getDescr(const std::string & text)
 {
 	std::string ret;
 	int i=0;

+ 8 - 4
hch/CGeneralTextHandler.h

@@ -14,8 +14,8 @@
  *
  */
 
-DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
-std::string readTo(std::string &in, int &it, char end);
+DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode);
+std::string readTo(const std::string &in, int &it, char end);
 class DLL_EXPORT CGeneralTextHandler //Handles general texts
 {
 public:
@@ -73,8 +73,12 @@ public:
 	std::vector <std::vector <std::string> > skillInfoTexts; //[id][level] : level 0 - basic; 2 - advanced
 	std::vector<std::string> levels;
 
-	std::string getTitle(std::string text);
-	std::string getDescr(std::string text);
+	//campaigns
+	std::vector <std::string> campaignMapNames;
+	std::vector < std::vector <std::string> > campaignRegionNames;
+
+	std::string getTitle(const std::string & text);
+	std::string getDescr(const std::string & text);
 
 	void load();
 	CGeneralTextHandler();

+ 1 - 1
hch/CHeroHandler.cpp

@@ -7,7 +7,7 @@
 #include <iomanip>
 
 extern CLodHandler * bitmaph;
-void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
+void loadToIt(std::string &dest, const std::string &src, int &iter, int mode);
 
 /*
  * CHeroHandler.cpp, part of VCMI engine

+ 1 - 1
hch/CLodHandler.cpp

@@ -276,7 +276,7 @@ std::string CLodHandler::getTextFile(std::string name)
 	unsigned char* data = giveFile(name,&length);
 
 	if (!data) {
-		tlog1<<"Fatal error. Missing game file. Aborting!"<<std::endl;
+		tlog1<<"Fatal error. Missing game file: " << name << ". Aborting!"<<std::endl;
 		exit(1);
 	}
 

+ 1 - 1
hch/CObjectHandler.cpp

@@ -38,7 +38,7 @@ using namespace boost::assign;
 std::map<int,std::map<int, std::vector<int> > > CGTeleport::objs;
 std::vector<std::pair<int, int> > CGTeleport::gates;
 IGameCallback * IObjectInterface::cb = NULL;
-DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
+DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode);
 extern CLodHandler * bitmaph;
 extern boost::rand48 ran;
 std::map <ui8, std::set <ui8> > CGKeys::playerKeyMap;

+ 1 - 1
hch/CTownHandler.cpp

@@ -7,7 +7,7 @@
 #include "CGeneralTextHandler.h"
 
 extern CLodHandler * bitmaph;
-void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
+void loadToIt(std::string &dest, const std::string &src, int &iter, int mode);
 
 /*
  * CTownHandler.cpp, part of VCMI engine

+ 9 - 2
lib/VCMI_Lib.cpp

@@ -48,7 +48,7 @@ DLL_EXPORT void initDLL(CConsoleHandler *Console, std::ostream *Logfile)
 	} HANDLE_EXCEPTION
 }
 
-DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode)
+DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode)
 {
 	switch(mode)
 	{
@@ -156,7 +156,7 @@ DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mod
 }
 
 
-DLL_EXPORT void loadToIt(si32 &dest, std::string &src, int &iter, int mode)
+DLL_EXPORT void loadToIt(si32 &dest, const std::string &src, int &iter, int mode)
 {
 	std::string pom;
 	loadToIt(pom,src,iter,mode);
@@ -247,3 +247,10 @@ LibClasses::LibClasses()
 	//init pointers to handlers
 	makeNull();
 }
+
+void LibClasses::callWhenDeserializing()
+{
+	generaltexth = new CGeneralTextHandler;
+	generaltexth->load();
+	arth->loadArtifacts(true);
+}

+ 5 - 8
lib/VCMI_Lib.h

@@ -2,9 +2,6 @@
 #define __VCMI_LIB_H__
 #include "../global.h"
 
-#include "../hch/CArtHandler.h"
-#include "../hch/CGeneralTextHandler.h"
-
 /*
  * VCMI_Lib.h, part of VCMI engine
  *
@@ -49,15 +46,15 @@ public:
 	void init(); //uses standard config file
 	void clear(); //deletes all handlers and its data
 	void makeNull(); //sets all handler (except of lodhs) pointers to null
+	
 
+	void callWhenDeserializing(); //should be called only by serialize !!!
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh;
 		if(!h.saving)
 		{
-			generaltexth = new CGeneralTextHandler;
-			generaltexth->load();
-			arth->loadArtifacts(true);
+			callWhenDeserializing();
 		}
 	}
 };
@@ -65,8 +62,8 @@ public:
 extern DLL_EXPORT LibClasses * VLC;
 extern DLL_EXPORT CLodHandler * bitmaph, *spriteh;
 
-DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
-DLL_EXPORT void loadToIt(si32 &dest, std::string &src, int &iter, int mode);
+DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode);
+DLL_EXPORT void loadToIt(si32 &dest, const std::string &src, int &iter, int mode);
 DLL_EXPORT void initDLL(CConsoleHandler *Console, std::ostream *Logfile);
 
 

+ 1 - 0
lib/map.cpp

@@ -7,6 +7,7 @@
 #include <zlib.h>
 #include <boost/crc.hpp>
 #include "../hch/CLodHandler.h"
+#include "../hch/CArtHandler.h"
 #include <boost/bind.hpp>
 #include <assert.h>
 

+ 1 - 0
server/CGameHandler.cpp

@@ -5,6 +5,7 @@
 #include "../hch/CHeroHandler.h"
 #include "../hch/CObjectHandler.h"
 #include "../hch/CSpellHandler.h"
+#include "../hch/CGeneralTextHandler.h"
 #include "../hch/CTownHandler.h"
 #include "../lib/CGameState.h"
 #include "../lib/CondSh.h"