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