Browse Source

- fixed #108, #798, #810
- fixed several gcc warnings
- some work on JSON (const char* as input, no crash on missing value)

Ivan Savenko 14 years ago
parent
commit
d113517db4

+ 2 - 9
client/AdventureMapButton.cpp

@@ -59,17 +59,10 @@ void CButtonBase::update()
 	}
 
 	if (!keepFrame)
-	{
 		image->setFrame(newPos);
-	}
-	
+
 	if (active)
-	{
-		if (parent)
-			parent->redraw();
-		else
-			redraw();
-	}
+		redraw();
 }
 
 void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)

+ 22 - 27
client/CAnimation.cpp

@@ -938,44 +938,39 @@ void CAnimation::init(CDefFile * file)
 
 	if (spriteh->haveFile(name, FILE_TEXT))
 	{
-		std::string configFile = spriteh->getTextFile(name);
+		int size = 0;
+		unsigned char * configFile = spriteh->giveFile(name, FILE_TEXT, &size);
 
-		const JsonNode config(configFile);
+		const JsonNode config((char*)configFile, size);
+		delete configFile;
 
 		std::string basepath;
-		if (!config["basepath"].isNull())
-			basepath = config["basepath"].String();
+		basepath = config["basepath"].String();
 
-		if (!config["sequences"].isNull())
+		BOOST_FOREACH(const JsonNode &group, config["sequences"].Vector())
 		{
-			BOOST_FOREACH(const JsonNode &group, config["sequences"].Vector()) {
-				size_t groupID = group["group"].Float();//TODO: string-to-value conversion
-				source[groupID].clear();
-
-				BOOST_FOREACH(const JsonNode &frame, group["frames"].Vector()) {
-					source[groupID].push_back(frame);
-					std::string filename =  frame["file"].String();
-					source[groupID].back()["file"].String() = basepath + filename;
-				}
+			size_t groupID = group["group"].Float();//TODO: string-to-value conversion("moving" -> MOVING)
+			source[groupID].clear();
+
+			BOOST_FOREACH(const JsonNode &frame, group["frames"].Vector())
+			{
+				source[groupID].push_back(frame);
+				std::string filename =  frame["file"].String();
+				source[groupID].back()["file"].String() = basepath + filename;
 			}
 		}
 
-		if (!config["images"].isNull())
+		BOOST_FOREACH(const JsonNode &node, config["images"].Vector())
 		{
-			BOOST_FOREACH(const JsonNode &node, config["images"].Vector()) {
-				size_t group=0;
-				if (!node["group"].isNull())
-					group = node["group"].Float();
+			size_t group = node["group"].Float();
+			size_t frame = node["frame"].Float();
 
-				size_t frame = node["frame"].Float();
+			if (source[group].size() <= frame)
+				source[group].resize(frame+1);
 
-				if (source[group].size() <= frame)
-					source[group].resize(frame+1);
-
-				source[group][frame] = node;
-				std::string filename =  node["file"].String();
-				source[group][frame]["file"].String() = basepath + filename;
-			}
+			source[group][frame] = node;
+			std::string filename =  node["file"].String();
+			source[group][frame]["file"].String() = basepath + filename;
 		}
 	}
 }

+ 1 - 1
client/CBattleInterface.cpp

@@ -1185,7 +1185,7 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
 CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
 	: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), 
 	  activeStack(NULL), stackToActivate(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1),
-	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL),  spellDestSelectMode(false), stackCanCastSpell(false), spellToCast(NULL),
+	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL),  stackCanCastSpell(false), spellDestSelectMode(false), spellToCast(NULL),
 	  siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0), givenCommand(NULL),
 	  myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL)
       

+ 2 - 2
client/CCastleInterface.cpp

@@ -282,12 +282,12 @@ CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstanc
 	}
 
 	int posY = 238;
-	int posX = pos.w/2 - resAmount.size() * 40 + 24;
+	int posX = pos.w/2 - resAmount.size() * 25 + 5;
 	for (size_t i=0; i<resAmount.size(); i++)
 	{
 		resPicture[i]->moveBy(Point(posX, posY));
 		resAmount[i]->moveBy(Point(posX+16, posY+43));
-		posX += 80;
+		posX += 50;
 	}
 }
 

+ 2 - 2
client/CMusicHandler.cpp

@@ -494,13 +494,12 @@ void MusicEntry::load(musicBase::musicID ID)
 
 #ifdef _WIN32
 	//The assertion will fail if old MSVC libraries pack .dll is used
-	assert(Mix_GetMusicType(music) == MUS_MP3_MAD);
+	assert(Mix_GetMusicType(music) != MUS_MP3);
 #endif
 }
 
 bool MusicEntry::play()
 {
-	tlog5<<"Playing music file "<<filename<<"\n";
 	if (loopCount == 0)
 		return false;
 
@@ -510,6 +509,7 @@ bool MusicEntry::play()
 	if (!musicVec.empty())
 		load(musicVec.at(rand() % musicVec.size()));
 
+	tlog5<<"Playing music file "<<filename<<"\n";
 	if(Mix_PlayMusic(music, 1) == -1)
 	{
 		tlog1 << "Unable to play music (" << Mix_GetError() << ")" << std::endl;

+ 26 - 57
client/GUIClasses.cpp

@@ -5906,79 +5906,48 @@ CExchangeWindow::~CExchangeWindow() //d-tor
 		delete speciality[g];
 }
 
-void CShipyardWindow::activate()
+CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, int boatType, const boost::function<void()> &onBuy)
 {
-	build->activate();
-	quit->activate();
-}
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	bg = new CPicture("TPSHIP");
+	bg->colorize(LOCPLINT->playerID);
+	pos = bg->center();
 
-void CShipyardWindow::deactivate()
-{
-	build->deactivate();
-	quit->deactivate();
-}
+	bgWater = new CPicture("TPSHIPBK", 100, 69);
 
-void CShipyardWindow::show( SDL_Surface * to )
-{
-	blitAt(bg,pos,to);
-	Rect clipRect = genRect(64, 96, pos.x+110, pos.y+85);
-	CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[boat]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &clipRect);
-	build->showAll(to);
-	quit->showAll(to);
-}
+	std::string boatFilenames[3] = {"AB01_", "AB02_", "AB03_"};
 
-CShipyardWindow::~CShipyardWindow()
-{
-	delete build;
-	delete quit;
-}
+	Point waterCenter = Point(bgWater->pos.x+bgWater->pos.w/2, bgWater->pos.y+bgWater->pos.h/2);
+	bgShip = new CAnimImage(boatFilenames[boatType], 0, 7, 120, 96, CShowableAnim::USE_RLE);
+	bgShip->center(waterCenter);
 
-CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, int boatType, const boost::function<void()> &onBuy)
-{
-	boat = boatType;
-	frame = 0;
-	SDL_Surface * bgtemp; //loaded as 8bpp surface
-	bgtemp = BitmapHandler::loadBitmap("TPSHIP.bmp");
-	pos.x = screen->w/2 - bgtemp->w/2;
-	pos.y = screen->h/2 - bgtemp->h/2;
-	pos.w = bgtemp->w;
-	pos.h = bgtemp->h;
-	SDL_SetColorKey(bgtemp,SDL_SRCCOLORKEY,SDL_MapRGB(bgtemp->format,0,255,255));
-	graphics->blueToPlayersAdv(bgtemp, LOCPLINT->playerID);
-	bg = SDL_ConvertSurface(bgtemp, screen->format, screen->flags); //to 24 bpp
-	SDL_FreeSurface(bgtemp);
+	// Create resource icons and costs.
+	std::string goldValue = boost::lexical_cast<std::string>(cost[Res::GOLD]);
+	std::string woodValue = boost::lexical_cast<std::string>(cost[Res::WOOD]);
 
-	bgtemp = BitmapHandler::loadBitmap("TPSHIPBK.bmp");
-	blitAt(bgtemp, 100, 69, bg);
-	SDL_FreeSurface(bgtemp);
+	goldCost = new CLabel(118, 294, FONT_SMALL, CENTER, zwykly, goldValue);
+	woodCost = new CLabel(212, 294, FONT_SMALL, CENTER, zwykly, woodValue);
+
+	goldPic = new CAnimImage("RESOURCE", Res::GOLD, 0, 100, 244);
+	woodPic = new CAnimImage("RESOURCE", Res::WOOD, 0, 196, 244);
 
-	// Draw resource icons and costs.
-	std::string goldCost = boost::lexical_cast<std::string>(1000);
-	std::string woodCost = boost::lexical_cast<std::string>(10);
-	blitAt(graphics->resources32->ourImages[6].bitmap, 100, 244, bg);
-	printAtMiddle(goldCost.c_str(), 118, 294, FONT_SMALL, zwykly, bg);
-	blitAt(graphics->resources32->ourImages[0].bitmap, 196, 244, bg);
-	printAtMiddle(woodCost.c_str(), 212, 294, FONT_SMALL, zwykly, bg);
+	quit = new AdventureMapButton(CGI->generaltexth->allTexts[599], "", boost::bind(&CGuiHandler::popIntTotally, &GH, this), 224, 312, "ICANCEL", SDLK_RETURN);
+	build = new AdventureMapButton(CGI->generaltexth->allTexts[598], "", boost::bind(&CGuiHandler::popIntTotally, &GH, this), 42, 312, "IBUY30", SDLK_RETURN);
+	build->callback += onBuy;
 
-	bool affordable = true;
-	for(int i = 0; i < cost.size(); i++)
+	for(size_t i = 0; i < cost.size(); i++)
 	{
 		if(cost[i] > LOCPLINT->cb->getResourceAmount(i))
 		{
-			affordable = false;
+			build->block(true);
 			break;
 		}
 	}
 
-	quit = new AdventureMapButton(CGI->generaltexth->allTexts[599], "", boost::bind(&CGuiHandler::popIntTotally, &GH, this), pos.x+224, pos.y+312, "ICANCEL.DEF", SDLK_RETURN);
-	build = new AdventureMapButton(CGI->generaltexth->allTexts[598], "", boost::bind(&CGuiHandler::popIntTotally, &GH, this), pos.x+42, pos.y+312, "IBY6432.DEF", SDLK_RETURN);
-	build->callback += onBuy;
-
-	if(!affordable)
-		build->block(true);
+	statusBar = new CGStatusBar(bg->pos.w/2, bg->pos.h-16);
 
-	printAtMiddle(CGI->generaltexth->jktexts[13], 164, 27, FONT_BIG, tytulowy, bg);  //Build A New Ship
-	printAtMiddle(CGI->generaltexth->jktexts[14], 164, 220, FONT_MEDIUM, zwykly, bg); //Resource cost:
+	title =     new CLabel(164, 27,  FONT_BIG,    CENTER, tytulowy, CGI->generaltexth->jktexts[13]);
+	costLabel = new CLabel(164, 220, FONT_MEDIUM, CENTER, zwykly,   CGI->generaltexth->jktexts[14]);
 }
 
 CPuzzleWindow::CPuzzleWindow(const int3 &grailPos, float discoveredRatio)

+ 13 - 8
client/GUIClasses.h

@@ -73,6 +73,7 @@ class CTextBox;
 class CArtifactInstance;
 class IBonusBearer;
 class CArtPlace;
+class CAnimImage;
 
 extern SDL_Color tytulowy, tlo, zwykly ;
 
@@ -1119,18 +1120,22 @@ public:
 class CShipyardWindow : public CIntObject
 {
 public:
-	CStatusBar *bar;
-	SDL_Surface *bg; //background
+	CGStatusBar *bar;
+	CPicture *bg; //background
+	CPicture *bgWater;
+
+	CLabel *title;
+	CLabel *costLabel;
+
+	CAnimImage *woodPic, *goldPic;
+	CLabel *woodCost, *goldCost;
+
+	CAnimImage *bgShip;
 	AdventureMapButton *build, *quit;
 
-	unsigned char frame; //frame of the boat animation
-	int boat; //which boat graphic should be used
+	CGStatusBar * statusBar;
 
-	void activate();
-	void deactivate();
-	void show(SDL_Surface * to);
 	CShipyardWindow(const std::vector<si32> &cost, int state, int boatType, const boost::function<void()> &onBuy);
-	~CShipyardWindow();
 };
 
 /// Puzzle screen which gets uncovered when you visit obilisks

+ 2 - 9
client/Graphics.cpp

@@ -215,11 +215,7 @@ void Graphics::initializeBattleGraphics()
 	const JsonNode config(DATA_DIR "/config/battles_graphics.json");
 	
 	// Reserve enough space for the terrains
-	// TODO: there should be a method to count the number of elements
-	int idx = 0;
-	BOOST_FOREACH(const JsonNode &t, config["backgrounds"].Vector()) {
-		idx++;
-	}
+	int idx = config["backgrounds"].Vector().size();
 	battleBacks.resize(idx+1);	// 1 to idx, 0 is unused
 
 	idx = 1;
@@ -229,10 +225,7 @@ void Graphics::initializeBattleGraphics()
 	}
 
 	//initializing battle hero animation
-	idx = 0;
-	BOOST_FOREACH(const JsonNode &h, config["heroes"].Vector()) {
-		idx++;
-	}
+	idx = config["heroes"].Vector().size();
 	battleHeroes.resize(idx);
 
 	idx = 0;

+ 1 - 2
lib/BattleState.cpp

@@ -796,7 +796,7 @@ void BattleInfo::getPotentiallyAttackableHexes(AttackableTiles &at, const CStack
 		std::vector<THex> hexes = attacker->getSurroundingHexes(attackerPos);
 		BOOST_FOREACH (THex tile, hexes)
 		{
-			if (THex::mutualPosition(tile, destinationTile) > -1 && THex::mutualPosition(tile, hex) > -1 //adjacent both to attacker's head and attacked tile
+			if ((THex::mutualPosition(tile, destinationTile) > -1 && THex::mutualPosition(tile, hex) > -1) //adjacent both to attacker's head and attacked tile
 				|| tile == destinationTile) //or simply attacked directly
 			{
 				CStack * st = getStackT(tile, true);
@@ -843,7 +843,6 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CStack* attacker, THex
 	AttackableTiles at;
 	getPotentiallyAttackableHexes(at, attacker, destinationTile, attackerPos);
 	std::set<CStack*> attackedCres;
-	const int WN = BFIELD_WIDTH;
 	BOOST_FOREACH (THex tile, at.hostileCreaturePositions) //all around & three-headed attack
 	{
 		CStack * st = getStackT(tile, true);

+ 43 - 19
lib/JsonNode.cpp

@@ -14,20 +14,25 @@ JsonNode::JsonNode(JsonType Type):
 	setType(Type);
 }
 
-JsonNode::JsonNode(std::string input):
+JsonNode::JsonNode(const char *data, size_t datasize):
 	type(DATA_NULL)
 {
-	JsonParser parser(input, *this);
+	JsonParser parser(data, datasize, *this);
 }
 
-JsonNode::JsonNode(const char *filename):
+JsonNode::JsonNode(std::string filename):
 	type(DATA_NULL)
 {
-	std::ifstream file(filename);
-	std::string str((std::istreambuf_iterator<char>(file)),
-					std::istreambuf_iterator<char>());
-
-	JsonParser parser(str, *this);
+	FILE * file = fopen(filename.c_str(), "rb");
+	fseek(file, 0, SEEK_END);
+	size_t datasize = ftell(file);
+	fseek(file, 0, SEEK_SET);
+	
+	char *input = new char[datasize];
+	fread((void*)input, 1, datasize, file);
+	
+	JsonParser parser(input, datasize, *this);
+	delete [] input;
 }
 
 JsonNode::JsonNode(const JsonNode &copy):
@@ -66,17 +71,19 @@ void JsonNode::setType(JsonType Type)
 	if (type == Type)
 		return;
 
+	//Reset node to NULL
 	if (Type != DATA_NULL)
 		setType(DATA_NULL);
 
 	switch (type)
 	{
 		break; case DATA_STRING:  delete data.String;
-		break; case DATA_VECTOR : delete data.Vector;
+		break; case DATA_VECTOR:  delete data.Vector;
 		break; case DATA_STRUCT:  delete data.Struct;
 		break; default:
 		break;
 	}
+	//Set new node type
 	type = Type;
 	switch(type)
 	{
@@ -124,33 +131,47 @@ JsonMap & JsonNode::Struct()
 	return *data.Struct;
 }
 
-
+const bool boolDefault = false;
 const bool & JsonNode::Bool() const
 {
+	if (type == DATA_NULL)
+		return boolDefault;
 	assert(type == DATA_BOOL);
 	return data.Bool;
 }
 
+const float floatDefault = 0;
 const float & JsonNode::Float() const
 {
+	if (type == DATA_NULL)
+		return floatDefault;
 	assert(type == DATA_FLOAT);
 	return data.Float;
 }
 
+const std::string stringDefault = std::string();
 const std::string & JsonNode::String() const
 {
+	if (type == DATA_NULL)
+		return stringDefault;
 	assert(type == DATA_STRING);
 	return *data.String;
 }
 
+const JsonVector vectorDefault = JsonVector();
 const JsonVector & JsonNode::Vector() const
 {
+	if (type == DATA_NULL)
+		return vectorDefault;
 	assert(type == DATA_VECTOR);
 	return *data.Vector;
 }
 
+const JsonMap mapDefault = JsonMap();
 const JsonMap & JsonNode::Struct() const
 {
+	if (type == DATA_NULL)
+		return mapDefault;
 	assert(type == DATA_STRUCT);
 	return *data.Struct;
 }
@@ -240,8 +261,8 @@ std::ostream & operator<<(std::ostream &out, const JsonNode &node)
 
 ////////////////////////////////////////////////////////////////////////////////
 
-JsonParser::JsonParser(const std::string inputString, JsonNode &root):
-	input(inputString),
+JsonParser::JsonParser(const char * inputString, size_t stringSize, JsonNode &root):
+	input(inputString, stringSize),
 	lineCount(1),
 	lineStart(0),
 	pos(0)
@@ -316,7 +337,8 @@ bool JsonParser::extractWhitespace(bool verbose)
 		else
 			error("Comments should have two slashes!", true);
 
-		pos = input.find('\n', pos);
+		while (pos < input.size() && input[pos] != '\n')
+			pos++;
 	}
 
 	if (pos >= input.size() && verbose)
@@ -353,13 +375,13 @@ bool JsonParser::extractString(std::string &str)
 	{
 		if (input[pos] == '\"') // Correct end of string
 		{
-			str += input.substr(first, pos-first);
+			str.append( &input[first], pos-first);
 			pos++;
 			return true;
 		}
 		if (input[pos] == '\\') // Escaping
 		{
-			str += input.substr(first, pos-first);
+			str.append( &input[first], pos-first);
 			first = pos++;
 			if (pos == input.size())
 				break;
@@ -367,12 +389,12 @@ bool JsonParser::extractString(std::string &str)
 		}
 		if (input[pos] == '\n') // end-of-line
 		{
-			str += input.substr(first, pos-first);
+			str.append( &input[first], pos-first);
 			return error("Closing quote not found!", true);
 		}
 		if (input[pos] < ' ') // control character
 		{
-			str += input.substr(first, pos-first);
+			str.append( &input[first], pos-first);
 			first = pos+1;
 			error("Illegal character in the string!", true);
 		}
@@ -394,9 +416,11 @@ bool JsonParser::extractString(JsonNode &node)
 
 bool JsonParser::extractLiteral(const std::string &literal)
 {
-	if (input.compare(pos, literal.size(), literal) != 0)
+	if (literal.compare(0, literal.size(), &input[pos], literal.size()) != 0)
 	{
-		pos = input.find_first_of(" \n\r\t", pos);
+		while (pos < input.size() && ((input[pos]>'a' && input[pos]<'z')
+		                           || (input[pos]>'A' && input[pos]<'Z')))
+			pos++;
 		return error("Unknown literal found", true);
 	}
 

+ 29 - 6
lib/JsonNode.h

@@ -41,9 +41,9 @@ public:
 	//Create empty node
 	JsonNode(JsonType Type = DATA_NULL);
 	//Create tree from Json-formatted input
-	explicit JsonNode(std::string input);
+	explicit JsonNode(const char * data, size_t datasize);
 	//Create tree from JSON file
- 	explicit JsonNode(const char *filename);
+ 	explicit JsonNode(std::string filename);
 	//Copy c-tor
 	JsonNode(const JsonNode &copy);
 
@@ -60,7 +60,6 @@ public:
 
 	//non-const accessors, node will change type on type mismatch
 	bool & Bool();
-	int & Int();
 	float & Float();
 	std::string & String();
 	JsonVector & Vector();
@@ -68,7 +67,6 @@ public:
 
 	//const accessors, will cause assertion failure on type mismatch
 	const bool & Bool() const;
-	const int & Int() const;
 	const float & Float() const;
 	const std::string & String() const;
 	const JsonVector & Vector() const;
@@ -87,12 +85,37 @@ public:
 
 std::ostream & operator<<(std::ostream &out, const JsonNode &node);
 
+//Tiny string class that use const char* as data for speed, members are private for ease of debugging
+class constString
+{
+	const char *data;
+	const size_t datasize;
+
+public:
+	constString(const char * inputString, size_t stringSize):
+		data(inputString),
+		datasize(stringSize)
+	{
+	}
+
+	inline size_t size() const
+	{
+		return datasize;
+	};
+
+	inline const char& operator[] (size_t position)
+	{
+		assert (position < datasize);
+		return data[position];
+	}
+};
 
 //Internal class for std::string -> JsonNode conversion
 class JsonParser
 {
+
 	std::string errors;     // Contains description of all encountered errors
-	const std::string input;// Input data
+	constString input;      // Input data
 	unsigned int lineCount; // Currently parsed line, starting from 1
 	size_t lineStart;       // Position of current line start
 	size_t pos;             // Current position of parser
@@ -118,5 +141,5 @@ class JsonParser
 	bool error(const std::string &message, bool warning=false);
 
 public:
-	JsonParser(const std::string inputString, JsonNode &root);
+	JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
 };

+ 2 - 2
server/CGameHandler.cpp

@@ -1022,7 +1022,7 @@ void CGameHandler::newTurn()
 							availableCount += t->creatureGrowth(k);
 
 						if(n.creatureid == cre->idNumber 
-							|| n.specialWeek == NewTurn::DEITYOFFIRE && (cre->idNumber == 42 || cre->idNumber == 43))
+							|| (n.specialWeek == NewTurn::DEITYOFFIRE && (cre->idNumber == 42 || cre->idNumber == 43)))
 						{
 							if(n.specialWeek == NewTurn::DOUBLE_GROWTH)
 								availableCount *= 2;
@@ -3490,7 +3490,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
 					continue;
 
 				BattleStackAttacked bsa;
-				if (destination > -1 && (*it)->coversPos(destination) || spell->range[spellLvl] == "X") //display effect only upon primary target of area spell
+				if ((destination > -1 && (*it)->coversPos(destination)) || spell->range[spellLvl] == "X") //display effect only upon primary target of area spell
 				{
 					bsa.flags |= BattleStackAttacked::EFFECT;
 					bsa.effect = spell->mainEffectAnim;