1 /*
2  * Bomb-her-man
3  * Copyright (C) Sardem FF7 2010 <sardemff7.pub@gmail.com>
4  * Copyright (C) Marc-Antoine Perennou 2010 <Marc-Antoine@Perennou.com>
5  *
6  * Bomb-her-man is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Bomb-her-man is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "display.hpp"
21 
22 #include <sstream>
23 #include <librsvg/rsvg.h>
24 #include <cairo.h>
25 
26 #include "game/player.hpp"
27 
28 #define FONT_FILE "biolinum.ttf"
29 
30 using namespace bombherman;
31 
32 SDL_Surface * Display::sDisplay = NULL;
33 Uint32 Display::flags = SDL_HWSURFACE;
34 bool Display::isFullscreen = false;
35 SDL_mutex * Display::mUpdate = SDL_CreateMutex();
36 
37 SDL_Color Display::textColor = {255, 255, 255, 0};
38 SDL_Color Display::highlightColor = {255, 0, 0, 0};
39 SDL_Color Display::scoreColor = {0, 0, 0, 0};
40 
41 int Display::widthMax = 0;
42 int Display::heightMax = 0;
43 int Display::width = 0;
44 int Display::height = 0;
45 std::vector< std::pair< Uint16, Uint16 > > Display::displayModes;
46 
47 std::map< SDL_Surface *, unsigned char * > Display::buffers;
48 
49 SDL_Surface * Display::sBackground = NULL;
50 
51 SDL_Surface * Display::gScoresLayer = NULL;
52 SDL_Surface * Display::gMapLayer = NULL;
53 SDL_Surface * Display::gBarrelsLayer = NULL;
54 SDL_Surface * Display::gPlayersLayer = NULL;
55 
56 std::vector< std::vector< std::vector< SDL_Surface * > > > Display::gPlayers;
57 SDL_Surface * Display::gBonuses[NB_BONUSES];
58 SDL_Surface * Display::gBomb = NULL;
59 SDL_Surface * Display::gExplosion = NULL;
60 SDL_Surface * Display::gBarrel = NULL;
61 SDL_Surface * Display::gTomb[2] = {NULL, NULL};
62 SDL_Surface * Display::gFloor = NULL;
63 
64 
65 Uint32 Display::gMapSize = 0;
66 Uint16 Display::gSize = 0;
67 SDL_Rect Display::gZone;
68 
69 void
init()70 Display::init()
71 {
72 	gMapSize = Config::getInt("mapSize");
73 
74 	unsigned int max = Config::getInt("maxPlayers");
75 	for ( unsigned int p = 0 ; p < max ; ++p )
76 	{
77 		std::vector< std::vector< SDL_Surface * > > k;
78 		for ( unsigned int i = 0 ; i < 4 ; ++i )
79 		{
80 			std::vector< SDL_Surface * > l;
81 			for ( unsigned int j = 0 ; j < ANIM_IMAGES ; ++j )
82 				l.push_back(NULL);
83 			k.push_back(l);
84 		}
85 		gPlayers.push_back(k);
86 	}
87 
88 	Uint32 wasInit = SDL_WasInit(SDL_INIT_EVERYTHING);
89 	bool initSuccess(true);
90 	if ( ! wasInit )
91 		initSuccess = SDL_Init(SDL_INIT_VIDEO) == 0;
92 	else if ( !( wasInit & SDL_INIT_VIDEO ) )
93 		initSuccess = SDL_InitSubSystem(SDL_INIT_VIDEO) == 0;
94 
95 	if ( ! initSuccess )
96 		throw exceptions::display::NoSDLException("Can't init Video subsystem of SDL");
97 
98 	SDL_WM_SetCaption(_("Bomb-her-man"), "bomb-her-man.svg");
99 	SDL_ShowCursor(SDL_DISABLE);
100 
101 	SDL_Rect ** modes = SDL_ListModes(0, flags|SDL_FULLSCREEN);
102 	if ( modes == reinterpret_cast< SDL_Rect ** >(0) )
103 		throw exceptions::display::NoSDLException("No modes available!");
104 	else if ( modes == reinterpret_cast< SDL_Rect ** >(-1) )
105 		throw exceptions::display::NoSDLException("Can't choose the resolution");
106 
107 	for ( Uint8 i = 0 ; modes[i] ; ++i )
108 		displayModes.push_back(std::make_pair(modes[i]->w, modes[i]->h));
109 
110 	widthMax = Config::getInt("screenWidth");
111 	heightMax = Config::getInt("screenHeight");
112 
113 	if ( TTF_Init() == -1 )
114 	{
115 		bherr << TTF_GetError() << bhendl;
116 		throw exceptions::display::NoSDLException("Can't init use of TrueType fonts");
117 	}
118 
119 	#if !GLIB_CHECK_VERSION(2,35,0)
120 		g_type_init();
121 	#endif
122 
123 	setMode();
124 }
125 
126 SDL_Surface *
svgToSurface(std::string file,Uint32 targetWidth,Uint32 targetHeight)127 Display::svgToSurface(std::string file, Uint32 targetWidth, Uint32 targetHeight)
128 {
129 
130 	RsvgHandle * rsvg = rsvg_handle_new_from_file(file.c_str(), NULL);
131 
132 	if ( ! rsvg )
133 		throw exceptions::display::NoSVGException("Can't read the file: " + file);
134 
135 	RsvgDimensionData dims;
136 
137 	rsvg_handle_get_dimensions(rsvg, &dims);
138 
139 	double sW = static_cast< double >(targetWidth) / static_cast< double >(dims.width);
140 	double sH = static_cast< double >(targetHeight) / static_cast< double >(dims.height);
141 
142 	Uint32 stride = 4 * targetWidth;
143 	unsigned char * buffer = static_cast< unsigned char * >(calloc(stride * targetHeight, 1));
144 
145 	cairo_surface_t * cSurface = cairo_image_surface_create_for_data(
146 		buffer,	CAIRO_FORMAT_ARGB32, targetWidth, targetHeight, stride);
147 	cairo_t * cObject = cairo_create(cSurface);
148 
149 	cairo_scale(cObject, sW, sH);
150 
151 	rsvg_handle_render_cairo(rsvg, cObject);
152 
153 	cairo_surface_finish(cSurface);
154 
155 	SDL_Surface * ret = SDL_CreateRGBSurfaceFrom(buffer,
156 		targetWidth, targetHeight, 32, stride,
157 		0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
158 
159 	g_object_unref(rsvg);
160 	cairo_destroy(cObject);
161 	cairo_surface_destroy(cSurface);
162 	buffers[ret] = buffer;
163 
164 	return ret;
165 }
166 
167 void
initSurfaces()168 Display::initSurfaces()
169 {
170 	if ( ! sDisplay )
171 		init();
172 
173 	// Logo
174 	SDL_Surface * icon = svgToSurface(DATADIR"/graphics/bomb-her-man.svg");
175 	SDL_WM_SetIcon(icon, NULL);
176 	SDL_FreeSurface(icon);
177 	icon = NULL;
178 
179 	// sBackground
180 	cleanSurface(sBackground);
181 	sBackground = SDL_CreateRGBSurface(flags, width, height, 32, 0, 0, 0, 0);
182 	SDL_FillRect(sBackground, NULL, 0x00d2995a);
183 	Uint32 sBackSize = 0;
184 	if ( width > height )
185 		sBackSize = width / 4;
186 	else if ( height > ( width * 3 ) )
187 		sBackSize = width;
188 	else
189 		sBackSize = height / 3;
190 	SDL_Surface * sBackTemp = svgToSurface(DATADIR"/graphics/background.svg", sBackSize, sBackSize * 3);
191 	SDL_BlitSurface(sBackTemp, NULL, sBackground, NULL);
192 	cleanSurface(sBackTemp);
193 
194 	// gBomb
195 	cleanSurface(gBomb);
196 	gBomb = svgToSurface(DATADIR"/graphics/bomb.svg");
197 
198 	// gExplosion
199 	cleanSurface(gExplosion);
200 	gExplosion = svgToSurface(DATADIR"/graphics/explosion.svg");
201 
202 	// gTombs
203 	cleanSurface(gTomb[0]);
204 	cleanSurface(gTomb[1]);
205 	gTomb[0] = svgToSurface(DATADIR"/graphics/tomb1.svg");
206 	gTomb[1] = svgToSurface(DATADIR"/graphics/tomb2.svg");
207 
208 	// gFloor
209 	cleanSurface(gFloor);
210 	gFloor = svgToSurface(DATADIR"/graphics/floor.svg", gZone.w, gZone.h);
211 
212 	// gBarrel
213 	cleanSurface(gBarrel);
214 	gBarrel = svgToSurface(DATADIR"/graphics/barrel.svg");
215 
216 	/*
217 	 * Players
218 	 */
219 	const unsigned int max = Config::getInt("maxPlayers");
220 	for ( unsigned int p = 0 ; p < max ; ++p )
221 		for ( unsigned int i = 0 ; i < 4 ; ++i )
222 			for ( unsigned int j = 0 ; j < ANIM_IMAGES ; ++j )
223 			{
224 				cleanSurface(gPlayers[p][i][j]);
225 				std::ostringstream f;
226 				f << DATADIR << "/graphics/players/" << (p+1) << '/' << i << '/' << j << ".svg";
227 				gPlayers[p][i][j] = svgToSurface(f.str());
228 			}
229 
230 	/*
231 	 * Bonuses
232 	 */
233 	for ( unsigned int b = 0 ; b < NB_BONUSES ; ++b )
234 	{
235 		cleanSurface(gBonuses[b]);
236 		std::ostringstream f;
237 		f << DATADIR << "/graphics/bonuses/" << (b+1) << ".svg";
238 		gBonuses[b] = svgToSurface(f.str());
239 	}
240 }
241 
242 void
cleanSurface(SDL_Surface * & surf)243 Display::cleanSurface(SDL_Surface * & surf)
244 {
245 	if ( surf )
246 	{
247 		std::map< SDL_Surface *, unsigned char * >::iterator i = buffers.find(surf);
248 		if ( i != buffers.end() )
249 		{
250 			free(i->second);
251 			buffers.erase(i);
252 		}
253 		SDL_FreeSurface(surf);
254 		surf = NULL;
255 	}
256 }
257 
258 void
quitGame()259 Display::quitGame()
260 {
261 	cleanSurface(gMapLayer);
262 	cleanSurface(gBarrelsLayer);
263 	cleanSurface(gPlayersLayer);
264 }
265 
266 void
quit()267 Display::quit()
268 {
269 	if ( ! sDisplay )
270 		return;
271 
272 	cleanSurface(sBackground);
273 
274 	quitGame();
275 
276 	cleanSurface(gBomb);
277 	cleanSurface(gExplosion);
278 	cleanSurface(gBarrel);
279 	cleanSurface(gTomb[0]);
280 	cleanSurface(gTomb[1]);
281 	cleanSurface(gFloor);
282 
283 	const unsigned int max = Config::getInt("maxPlayers");
284 	for ( unsigned int p = 0 ; p < max ; ++p )
285 		for ( unsigned int i = 0 ; i < 4 ; ++i )
286 			for ( unsigned int j = 0 ; j < ANIM_IMAGES ; ++j )
287 				cleanSurface(gPlayers[p][i][j]);
288 
289 	for ( unsigned int b = 0 ; b < NB_BONUSES ; ++b )
290 		cleanSurface(gBonuses[b]);
291 
292 	//SDL_LockMutex(mUpdate);
293 	SDL_DestroyMutex(mUpdate);
294 
295 	TTF_Quit();
296 	sDisplay = NULL;
297 	if ( SDL_WasInit(SDL_INIT_VIDEO) )
298 		SDL_QuitSubSystem(SDL_INIT_VIDEO);
299 }
300 
301 void
setMode(Uint8 i)302 Display::setMode(Uint8 i)
303 {
304 	try
305 	{
306 		std::pair<Uint16,Uint16> mode(displayModes.at(i));
307 		widthMax = (displayModes[i]).first;
308 		heightMax = (displayModes[i]).second;
309 		Config::set("screenWidth", widthMax);
310 		Config::set("screenHeight", heightMax);
311 	}
312 	catch ( std::exception ) {}
313 	setMode();
314 }
315 
316 void
setMode()317 Display::setMode()
318 {
319 	Uint32 adds = 0;
320 	if ( Config::getInt("fullscreen") == 1 )
321 	{
322 		adds = SDL_FULLSCREEN;
323 		width = widthMax;
324 		height = heightMax;
325 	}
326 	else
327 	{
328 		width = widthMax*0.9;
329 		height = heightMax*0.9;
330 	}
331 	SDL_LockMutex(mUpdate);
332 
333 	SDL_Surface * tmp = SDL_SetVideoMode(width, height, 32, flags|adds);
334 	if ( ! tmp )
335 	{
336 		bherr << SDL_GetError() << bhendl;
337 		throw exceptions::display::NoSDLException("Cannot go to wanted size");
338 	}
339 	else
340 	{
341 		isFullscreen = ( adds & SDL_FULLSCREEN );
342 		cleanSurface(sDisplay);
343 		sDisplay = tmp;
344 	}
345 	if ( height < width )
346 	{
347 		gSize = height / gMapSize;
348 		gZone.x = width - height;
349 		gZone.y = 0;
350 	}
351 	else
352 	{
353 		gSize = width / gMapSize;
354 		gZone.x = 0;
355 		gZone.y = height - width;
356 	}
357 	gZone.w = width - gZone.x;
358 	gZone.h = height - gZone.y;
359 
360 
361 	initSurfaces();
362 	SDL_UnlockMutex(mUpdate);
363 }
364 
365 void
updateDisplay(SDL_Surface * s,Uint16 x,Uint16 y,Uint16 w,Uint16 h)366 Display::updateDisplay(SDL_Surface * s, Uint16 x, Uint16 y, Uint16 w, Uint16 h)
367 {
368 	if ( ! sDisplay )
369 		init();
370 
371 	SDL_Rect r = { x, y, w, h };
372 	SDL_LockMutex(mUpdate);
373 	if ( SDL_MUSTLOCK(sDisplay) )
374 		SDL_LockSurface(sDisplay);
375 	SDL_BlitSurface(s, NULL, sDisplay, &r);
376 	SDL_UpdateRect(sDisplay, x, y, w, h);
377 	SDL_UnlockSurface(sDisplay);
378 	SDL_UnlockMutex(mUpdate);
379 }
380 
381 void
displayMenu(Menu * menu)382 Display::displayMenu(Menu * menu)
383 {
384 	if ( ! sDisplay )
385 		init();
386 
387 	std::vector< std::string > content = menu->getContent();
388 	unsigned int current = menu->getCurrent();
389 	int fSize = 2 * content.size();
390 
391 	TTF_Font * fontTitle = TTF_OpenFont(DATADIR"/"FONT_FILE, (height / fSize));
392 	TTF_Font * fontNormal = TTF_OpenFont(DATADIR"/"FONT_FILE, (height / ( fSize * 2 )));
393 
394 	if ( ! (fontTitle && fontNormal) )
395 	{
396 		bherr << TTF_GetError() << bhendl;
397 		throw exceptions::display::NoSDLException("Cannot open font");
398 	}
399 
400 	SDL_Surface *textSurface, *sMenu = SDL_CreateRGBSurface(flags, width, height, 32, 0, 0, 0, 0);
401 	SDL_BlitSurface(sBackground, NULL, sMenu, NULL);
402 	Uint32 dy = ( TTF_FontLineSkip(fontTitle) + ( height / ( fSize * 2 ) ) ), bx = ( width / 2 );
403 	SDL_Rect r;
404 	r.x = 0;
405 	r.y = ( 2 * ( height - ( dy * content.size() ) ) / 3 );
406 	unsigned int e = content.size();
407 	for ( unsigned int i = 0 ; i < e ; ++i )
408 	{
409 		TTF_Font * font = ( i == 0 ) ? ( fontTitle ) : ( fontNormal );
410 		SDL_Color color = ( i == current ) ? ( highlightColor ) : ( textColor );
411 		const char * text = content[i].c_str();
412 		if ( ! ( textSurface = TTF_RenderUTF8_Blended(font, text, color) ) )
413 			bherr << "Can't display the line" << text << bhendl;
414 		else
415 		{
416 			int w, h;
417 			TTF_SizeText(font, text, &w, &h);
418 			r.x = bx - ( w / 2 );
419 			SDL_BlitSurface(textSurface, NULL, sMenu, &r);
420 			r.y += dy;
421 			SDL_FreeSurface(textSurface);
422 		}
423 	}
424 	updateDisplay(sMenu);
425 	cleanSurface(sMenu);
426 	TTF_CloseFont(fontTitle);
427 	TTF_CloseFont(fontNormal);
428 }
429 
430 std::vector< std::pair< Uint16, Uint16 > >
getModes()431 Display::getModes()
432 {
433 	return displayModes;
434 }
435 
436 void
displayScores()437 Display::displayScores()
438 {
439 	updateScores(true);
440 }
441 
442 void
updateScores(bool final)443 Display::updateScores(bool final)
444 {
445 	if ( ! sDisplay )
446 		init();
447 
448 	Uint32 sSize = 0, nbAll = ( Config::getInt("nbPlayers") + Config::getInt("nbAIs") );
449 	if ( nbAll < 1 )
450 		return;
451 
452 	SDL_Rect
453 		z = {0, 0, 0, 0},
454 		dh = {0, 0, 0, 0},
455 		dp = {0, 0, 2, 2},
456 		db = {0, 0, 0, 0};
457 	SDL_Surface * sScoreBack = NULL;
458 	bool vertical(true);
459 	if ( final )
460 	{
461 		dh.w = z.w = width;
462 		dh.h = z.h = height;
463 		if ( height < width )
464 			vertical = false;
465 	}
466 	else
467 	{
468 		if ( ( gZone.x == 0 ) && ( gZone.y == 0 ) )
469 			return;
470 		dh.w = z.w = gZone.x;
471 		dh.h = z.h = gZone.y;
472 		if ( z.w == 0 )
473 			vertical = false;
474 	}
475 
476 	if ( vertical )
477 	{	// Vertical scores
478 		z.h = height;
479 		dh.y = dh.h = z.h / nbAll;
480 		sSize = z.w;
481 		sScoreBack = svgToSurface(DATADIR"/graphics/scores/background-vertical.svg", sSize, sSize);
482 		db.y = sSize;
483 	}
484 	else
485 	{	// Horizontal scores
486 		z.w = width;
487 		dh.x = dh.w = z.w / nbAll;
488 		sSize = z.h;
489 		sScoreBack = svgToSurface(DATADIR"/graphics/scores/background-horizontal.svg", sSize, sSize);
490 		db.x = sSize;
491 	}
492 
493 	sSize /= 1.7;
494 	if ( dh.w > dh.h )
495 	{
496 		dp.x = sSize;
497 		dp.y = ( sSize - gSize ) / 2;
498 		dp.w = 4;
499 	}
500 	else
501 	{
502 		dp.x = ( sSize - gSize ) / 2;
503 		dp.y = sSize;
504 		dp.h = 4;
505 	}
506 
507 
508 	cleanSurface(gScoresLayer);
509 	gScoresLayer = SDL_CreateRGBSurface(flags, z.w, z.h, 32, 0, 0, 0, 0);
510 
511 
512 	SDL_Rect b = {0, 0, 0, 0};
513 	for ( Uint32 i = 0 ; ( b.x < z.w ) && ( b.y < z.h ) ; ++i )
514 	{
515 		SDL_BlitSurface(sScoreBack, NULL, gScoresLayer, &b);
516 		b.x = (i * db.x);
517 		b.y = (i * db.y);
518 	}
519 
520 	cleanSurface(sScoreBack);
521 
522 	Sint32 * scores = new Sint32[nbAll];
523 	Sint32 max = -10;
524 	bool neutral(false);
525 	for ( std::vector< Player * >::iterator i = Player::players.begin(), e = Player::players.end() ; i != e ; ++i )
526 	{
527 		Sint32 s = (*i)->getScore();
528 		if ( s > max ) max = s;
529 		else if ( s == max ) neutral = true;
530 		scores[(*i)->getId()-1] = s;
531 	}
532 
533 	// Scores heads
534 	SDL_Surface * sWin[] = {
535 			svgToSurface(DATADIR"/graphics/scores/1/win.svg", sSize, sSize),
536 			svgToSurface(DATADIR"/graphics/scores/2/win.svg", sSize, sSize)
537 		};
538 	SDL_Surface * sLose[] = {
539 			svgToSurface(DATADIR"/graphics/scores/1/lose.svg", sSize, sSize),
540 			svgToSurface(DATADIR"/graphics/scores/2/lose.svg", sSize, sSize)
541 		};
542 	SDL_Surface * sEqual[] = {
543 			svgToSurface(DATADIR"/graphics/scores/1/equal.svg", sSize, sSize),
544 			svgToSurface(DATADIR"/graphics/scores/2/equal.svg", sSize, sSize)
545 		};
546 
547 	TTF_Font * font = TTF_OpenFont(DATADIR"/"FONT_FILE, (sSize / 6));
548 	if ( ! font )
549 	{
550 		bherr << TTF_GetError() << bhendl;
551 		throw exceptions::display::NoSDLException("Cannot open font");
552 	}
553 
554 
555 	for ( unsigned int i = 0 ; i < nbAll ; ++i )
556 	{
557 		const int s = scores[i];
558 
559 		SDL_Rect h = {
560 				( ( dh.w - sSize ) / dp.w ) + ( i * dh.x ),
561 				( ( dh.h - sSize ) / dp.h ) + ( i * dh.y ),
562 				sSize,
563 				sSize
564 			};
565 
566 		SDL_BlitSurface(( s == max ) ? ( ( neutral ) ? ( sEqual[i%2] ) : ( sWin[i%2] ) ) : ( sLose[i%2] ), NULL, gScoresLayer, &h);
567 
568 
569 		SDL_Surface * textSurface = NULL;
570 		std::ostringstream ost;
571 		ost << s;
572 		std::string st(ost.str());
573 		const char * text = st.c_str();
574 		if ( ! ( textSurface = TTF_RenderUTF8_Blended(font, text, scoreColor) ) )
575 			bherr << "Can't display the line" << st << bhendl;
576 		else
577 		{
578 			int wText, hText;
579 			TTF_SizeText(font, text, &wText, &hText);
580 			SDL_Rect t = {
581 					h.x + ( sSize - wText ) / 2,
582 					h.y + sSize * 0.68,
583 					wText,
584 					hText
585 				};
586 			SDL_BlitSurface(textSurface, NULL, gScoresLayer, &t);
587 			SDL_FreeSurface(textSurface);
588 		}
589 		if ( ! final )
590 		{
591 			SDL_Rect p = {
592 					h.x + dp.x,
593 					h.y + dp.y,
594 					gSize,
595 					gSize
596 				};
597 			SDL_BlitSurface(gPlayers[i][map::DOWN][0], NULL, gScoresLayer, &p);
598 		}
599 	}
600 
601 	updateDisplay(gScoresLayer, z);
602 
603 	delete[] scores;
604 	TTF_CloseFont(font);
605 
606 	cleanSurface(sWin[0]);
607 	cleanSurface(sWin[1]);
608 	cleanSurface(sLose[0]);
609 	cleanSurface(sLose[1]);
610 	cleanSurface(sEqual[0]);
611 	cleanSurface(sEqual[1]);
612 }
613 
614 void
updateMap()615 Display::updateMap()
616 {
617 	updateScores();
618 
619 	if ( ! (gTomb[0] && gTomb[1] && gFloor) )
620 		initSurfaces();
621 
622 	cleanSurface(gMapLayer);
623 	gMapLayer = SDL_CreateRGBSurface(flags, gZone.w, gZone.h, 32, 0, 0, 0, 0);
624 
625 	SDL_BlitSurface(gFloor, NULL, gMapLayer, NULL);
626 
627 	map::Coords coords;
628 	SDL_Rect r;
629 	r.x = 0;
630 	r.y = 0;
631 	r.w = gSize;
632 	r.h = gSize;
633 	for( coords.y = 0 ; coords.y < gMapSize ; ++coords.y )
634 	{
635 		for( coords.x = 0 ; coords.x < gMapSize ; ++coords.x )
636 		{
637 			if ( map::Map::get(coords) == map::INDESTRUCTIBLE )
638 				SDL_BlitSurface(gTomb[(coords.x+coords.y)%2], NULL, gMapLayer, &r);
639 			r.x += gSize;
640 		}
641 		r.x = 0;
642 		r.y += gSize;
643 	}
644 
645 	updateBarrels();
646 }
647 
648 void
updateBarrels()649 Display::updateBarrels()
650 {
651 	if ( ! gMapLayer )
652 		return;
653 	if ( ! (gTomb[0] && gTomb[1]) )
654 		initSurfaces();
655 	SDL_Rect r;
656 	cleanSurface(gBarrelsLayer);
657 	gBarrelsLayer = SDL_CreateRGBSurface(flags, gZone.w, gZone.h, 32, 0, 0, 0, 0);
658 	SDL_BlitSurface(gMapLayer, NULL, gBarrelsLayer, NULL);
659 	map::Coords coords;
660 	r.y = 0;
661 	for ( coords.y = 0 ; coords.y < gMapSize ; ++coords.y )
662 	{
663 		r.x = 0;
664 		for ( coords.x = 0 ; coords.x < gMapSize ; ++coords.x )
665 		{
666 			char c = map::Map::get(coords);
667 			if ( c == map::BARREL )
668 				SDL_BlitSurface(gBarrel, NULL, gBarrelsLayer, &r);
669 			else if ( c == map::BOMB || c == map::PLAYONBOMB )
670 				SDL_BlitSurface(gBomb, NULL, gBarrelsLayer, &r);
671 			else if ( c >= map::FIRSTBONUS && c <= map::LASTBONUS )
672 				SDL_BlitSurface(gBonuses[c - map::FIRSTBONUS], NULL, gBarrelsLayer, &r);
673 			r.x += gSize;
674 		}
675 		r.y += gSize;
676 	}
677 
678 	updateDisplay(gBarrelsLayer, gZone);
679 
680 	updatePlayers();
681 }
682 
683 void
updatePlayers()684 Display::updatePlayers()
685 {
686 	if ( ! gPlayers[0][0][0] )
687 		initSurfaces();
688 
689 	SDL_Rect r = {
690 			0,
691 			0,
692 			gSize,
693 			gSize
694 		};
695 	map::Coords coords;
696 	for ( std::vector< Player * >::iterator i = Player::players.begin(),
697 		e = Player::players.end() ; i != e ; ++i )
698 	{
699 		if ( ! (*i)->isAlive() )
700 			continue;
701 
702 		coords = (*i)->getCoords();
703 		r.x = ( coords.x * gSize ) + gZone.x;
704 		r.y = ( coords.y * gSize ) + gZone.y;
705 		updateDisplay(gPlayers[(*i)->getId()-1][(*i)->getOrient()][0], r);
706 	}
707 }
708 
709 void
movePlayer(Player * player,map::MoveResult moveResult)710 Display::movePlayer(Player * player, map::MoveResult moveResult)
711 {
712 	if ( ! sDisplay )
713 		init();
714 	SDL_Surface * sPlayer = NULL;
715 	int p = player->getId() - 1;
716 	map::Direction goTo = player->getOrient();
717 	map::Coords coords = player->getCoords();
718 	SDL_Rect
719 		r = {
720 				coords.x * gSize,
721 				coords.y * gSize,
722 				gSize,
723 				gSize
724 			},
725 		l = {
726 				0,
727 				0,
728 				gSize,
729 				gSize
730 			};
731 	#if ANIM_IMAGES > 1
732 	unsigned int anim = 0;
733 	const Sint16 part = gSize / ANIM_IMAGES;;
734 	const Sint16 cpart = (ANIM_IMAGES-1) * part;
735 	#endif // ANIM_IMAGES > 1
736 	switch ( moveResult )
737 	{
738 		case map::BONUSTAKEN:
739 			SDL_BlitSurface(gMapLayer, &r, gBarrelsLayer, &r);
740 		case map::MOVED:
741 			switch ( goTo )
742 			{
743 				case map::DOWN:
744 					r.y -= gSize;
745 					l.y = gSize;
746 				case map::UP:
747 					r.h += gSize;
748 				break;
749 				case map::RIGHT:
750 					r.x -= gSize;
751 					l.x = gSize;
752 				case map::LEFT:
753 					r.w += gSize;
754 				break;
755 			}
756 
757 			#if ANIM_IMAGES > 1
758 			while ( true )
759 			{
760 				SDL_Rect d = {
761 						0,
762 						0,
763 						gSize,
764 						gSize
765 					};
766 				switch ( goTo )
767 				{
768 					case map::DOWN:
769 						d.y = (1 + anim) * part;
770 						if ( static_cast< Uint16 >(d.y) >= gSize )
771 							anim = ANIM_IMAGES - 1;
772 					break;
773 					case map::UP:
774 						d.y = cpart - anim * part;
775 						if ( d.y <= 0 )
776 							anim = ANIM_IMAGES - 1;
777 					break;
778 					case map::RIGHT:
779 						d.x = (1 + anim) * part;
780 						if ( static_cast< Uint16 >(d.x) >= gSize )
781 							anim = ANIM_IMAGES - 1;
782 					break;
783 					case map::LEFT:
784 						d.x = cpart - anim * part;
785 						if ( d.x <= 0 )
786 							anim = ANIM_IMAGES - 1;
787 					break;
788 				}
789 				sPlayer = SDL_CreateRGBSurface(flags, r.w, r.h, 32, 0, 0, 0, 0);
790 				SDL_BlitSurface(gBarrelsLayer, &r, sPlayer, NULL);
791 				SDL_BlitSurface(gPlayers[p][goTo][++anim%ANIM_IMAGES], NULL, sPlayer, &d);
792 				updateDisplay(sPlayer, gZone.x + r.x, gZone.y + r.y, r.w, r.h);
793 				SDL_FreeSurface(sPlayer);
794 				if ( anim < ANIM_IMAGES )
795 					SDL_Delay(ANIM_TIME/ANIM_IMAGES);
796 				else
797 					break;
798 			}
799 			#endif // ANIM_IMAGES > 1
800 		break;
801 		default:
802 		break;
803 	}
804 	sPlayer = SDL_CreateRGBSurface(flags, r.w, r.h, 32, 0, 0, 0, 0);
805 	if (player->isAlive())
806 		SDL_BlitSurface(gBarrelsLayer, &r, sPlayer, NULL);
807 	SDL_BlitSurface(gPlayers[p][goTo][0], NULL, sPlayer, &l);
808 	updateDisplay(sPlayer, gZone.x + r.x, gZone.y + r.y, r.w, r.h);
809 	SDL_FreeSurface(sPlayer);
810 }
811 
812 void
plantBomb(Player * player)813 Display::plantBomb(Player * player)
814 {
815 	if ( ! gBomb )
816 		initSurfaces();
817 
818 	map::Coords coords = player->getCoords();
819 
820 	SDL_Rect r = {
821 			coords.x * gSize,
822 			coords.y * gSize,
823 			gSize,
824 			gSize
825 		};
826 
827 	SDL_BlitSurface(gBomb, NULL, gBarrelsLayer, &r);
828 	r.x += gZone.x;
829 	r.y += gZone.y;
830 	updateDisplay(gBomb, r);
831 
832 	updateDisplay(gPlayers[player->getId() - 1][player->getOrient()][0], r);
833 }
834 
835 void
explode(map::Coords bomb,std::vector<map::Coords> cells)836 Display::explode(map::Coords bomb, std::vector<map::Coords> cells)
837 {
838 	#if ANIM_IMAGES > 1
839 	Uint32 size = cells.size();
840 	if (size > 0)
841 	{
842 		SDL_Rect r = {
843 			gZone.x + bomb.x * gSize,
844 			gZone.y + bomb.y * gSize,
845 			gSize,
846 			gSize
847 		};
848 		updateDisplay(gExplosion, r);
849 		SDL_Delay(ANIM_TIME/(2*size));
850 		for ( std::vector<map::Coords>::iterator i = cells.begin(),
851 				e = cells.end() ; i != e ; ++i )
852 		{
853 			r.x = gZone.x + i->x * gSize;
854 			r.y = gZone.y + i->y * gSize;
855 			updateDisplay(gExplosion, r);
856 			SDL_Delay(ANIM_TIME/(2*size));
857 		}
858 	}
859 	#endif
860 	updateBarrels();
861 }
862 
863