Fix for the problem that SDL applications exited
[AROS-Contrib.git] / Games / lbreakout2 / client / misc.c
blob262fac1c1c3dd7491ed6f0d783130f096a1bd5ac
1 /***************************************************************************
2 misc.c - description
3 -------------------
4 begin : Thu Sep 6 2001
5 copyright : (C) 2001 by Michael Speck
6 email : kulkanie@gmx.net
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <time.h>
19 #include "lbreakout.h"
20 #include "../game/game.h"
21 #include "config.h"
22 #include "event.h"
23 #include "misc.h"
25 extern SDL_Surface *stk_display, *nuke_bkgnd, *brick_pic;
26 extern Game *local_game, *game;
27 extern Paddle *l_paddle;
28 extern StkFont *font;
29 extern SDL_Surface *offscreen;
30 extern int stk_quit_request;
31 int shadow_size = 8;
32 #ifdef AUDIO_ENABLED
33 extern StkSound *wav_click;
34 #endif
35 extern int motion_button;
36 extern Config config;
37 extern int bkgnd_count;
38 extern SDL_Surface **bkgnds;
41 ====================================================================
42 Load background according to id and draw background to offscreen.
43 Return Value: loaded background surface
44 ====================================================================
46 void bkgnd_draw( SDL_Surface *bkgnd, int id, int to_offscreen )
48 SDL_Surface *pic = 0;
49 int i, j;
51 if ( id >= bkgnd_count || id == -1 )
52 id = rand() % bkgnd_count;
54 /* load background */
55 pic = bkgnds[id];
56 for ( i = 0; i < bkgnd->w; i += pic->w ) {
57 for ( j = 0; j < bkgnd->h; j += pic->h ) {
58 stk_surface_blit( pic, 0,0,-1,-1,
59 bkgnd, i, j);
63 /* draw to offscreen */
64 if (to_offscreen)
65 stk_surface_blit( bkgnd, 0,0,-1,-1, offscreen, 0,0 );
68 ====================================================================
69 Confirm request. Darkens screen a bit and display text.
70 Return Value: True if successful
71 ====================================================================
73 void draw_confirm_screen( StkFont *font, SDL_Surface *buffer, char *str )
75 int i, y, x;
76 Text *text = create_text( str, 60 );
77 stk_surface_fill( stk_display, 0,0,-1,-1, 0x0 );
78 stk_surface_alpha_blit( buffer, 0,0,-1,-1, stk_display, 0,0, 128 );
79 font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_TOP;
80 y = (stk_display->h - text->count * font->height) / 2;
81 x = stk_display->w / 2;
82 for ( i = 0; i < text->count; i++ ) {
83 stk_font_write(font, stk_display, x, y, STK_OPAQUE, text->lines[i]);
84 y += font->height;
86 delete_text( text );
88 int confirm( StkFont *font, char *str, int type )
90 SDL_Event event;
91 int go_on = 1;
92 int ret = 0;
93 SDL_Surface *buffer =
94 stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
95 SDL_SetColorKey(buffer, 0, 0);
97 #ifdef AUDIO_ENABLED
98 stk_sound_play( wav_click );
99 #endif
101 event_clear_sdl_queue();
103 stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
104 if ( type == CONFIRM_PAUSE )
105 stk_surface_gray( stk_display, 0,0,-1,-1,0 );
106 else
107 draw_confirm_screen( font, buffer, str );
108 stk_display_update( STK_UPDATE_ALL );
110 while (go_on && !stk_quit_request) {
111 SDL_WaitEvent(&event);
112 /* TEST */
113 switch ( event.type ) {
114 case SDL_QUIT: stk_quit_request = 1; break;
115 case SDL_MOUSEBUTTONUP:
116 if ( type == CONFIRM_ANY_KEY ) {
117 ret = 1; go_on = 0;
119 /* else
120 if ( type == CONFIRM_YES_NO ) {
121 if ( event.button.button == LEFT_BUTTON )
122 ret = 1;
123 else
124 ret = 0;
125 go_on = 0;
127 break;
128 case SDL_KEYDOWN:
129 if ( type == CONFIRM_ANY_KEY ) {
130 ret = 1; go_on = 0;
131 break;
133 else
134 if ( type == CONFIRM_PAUSE ) {
135 if ( event.key.keysym.sym == SDLK_p ) {
136 ret = 1; go_on = 0;
137 break;
139 else
140 if ( event.key.keysym.sym == SDLK_f ) {
141 config.fullscreen = !config.fullscreen;
142 stk_display_apply_fullscreen( config.fullscreen );
143 draw_confirm_screen( font, buffer, str );
144 stk_display_update( STK_UPDATE_ALL );
147 else
149 char *keyName = SDL_GetKeyName(event.key.keysym.sym);
150 char *yesLetter = _("y");
151 char *noLetter = _("n");
152 if (strcmp(keyName, yesLetter) == 0) {
153 go_on = 0;
154 ret = 1;
156 else
157 if (event.key.keysym.sym==SDLK_ESCAPE || strcmp(keyName, noLetter) == 0 ) {
158 go_on = 0;
159 ret = 0;
161 default:
162 break;
164 break;
167 #ifdef AUDIO_ENABLED
168 stk_sound_play( wav_click );
169 #endif
170 stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
171 stk_display_update( STK_UPDATE_ALL );
172 SDL_FreeSurface(buffer);
174 /* reset the relative position so paddle wont jump */
175 SDL_GetRelativeMouseState(0,0);
177 return ret;
179 #ifdef NETWORK_ENABLED
181 ====================================================================
182 Display a info message (gray screen a bit and display text),
183 send a MSG_READY when player has clicked and wait for a remote answer
184 (timeout 10 secs). Waiting may be cancelled by pressing ESCAPE which
185 results in sending a MSG_GAME_EXITED.
186 Return Value: True if both peers clicked to continue, False if the
187 connection was cancelled for some reason.
188 ====================================================================
190 int display_info( StkFont *font, char *str, NetSocket *peer )
192 #if 0
193 char error[128];
194 Net_Msg msg;
195 SDL_Event event;
196 int ret = 0, leave = 0;
197 SDL_Surface *buffer =
198 stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
199 SDL_SetColorKey(buffer, 0, 0);
201 #ifdef AUDIO_ENABLED
202 stk_sound_play( wav_click );
203 #endif
205 event_clear_sdl_queue();
207 stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
208 draw_confirm_screen( font, buffer, str );
209 stk_display_update( STK_UPDATE_ALL );
210 stk_wait_for_input();
211 net_write_empty_msg( peer, MSG_READY );
212 draw_confirm_screen( font, buffer,
213 _("Waiting for remote answer...") );
214 stk_display_update( STK_UPDATE_ALL );
215 event_clear_sdl_queue();
216 while ( !leave ) {
217 if ( SDL_PollEvent( &event ) )
218 if ( (event.type == SDL_KEYDOWN &&
219 event.key.keysym.sym == SDLK_ESCAPE) ||
220 event.type == SDL_QUIT ) {
221 net_write_empty_msg( peer, MSG_GAME_EXITED );
222 leave = 1;
223 break;
225 if ( net_read_msg( peer, &msg, 0 ) )
226 switch ( msg.type ) {
227 case MSG_READY:
228 ret = 1; leave = 1;
229 break;
230 case MSG_GAME_EXITED:
231 ret = 0; leave = 1;
232 sprintf( error, /* xgettext:no-c-format */ _("remote player cancelled the game\n") );
233 confirm( font, error, CONFIRM_ANY_KEY );
234 break;
236 SDL_Delay( 10 );
239 #ifdef AUDIO_ENABLED
240 stk_sound_play( wav_click );
241 #endif
243 stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
244 stk_display_update( STK_UPDATE_ALL );
245 SDL_FreeSurface(buffer);
247 /* reset the relative position so paddle wont jump */
248 SDL_GetRelativeMouseState(0,0);
250 return ret;
251 #endif
252 return 1;
254 #endif
256 ====================================================================
257 Create shadow surface for specified region in surface.
258 Return Value: Shadow surface
259 ====================================================================
261 SDL_Surface* create_shadow( SDL_Surface *surf, int x, int y, int w, int h )
263 SDL_Surface *shadow = 0;
264 int i, j;
265 Uint32 white = SDL_MapRGB( stk_display->format, 0xff, 0xff, 0xff );
266 Uint32 black = SDL_MapRGB( stk_display->format, 0, 0, 0 );
267 shadow = stk_surface_create( SDL_SWSURFACE, w, h );
268 SDL_SetColorKey( shadow, SDL_SRCCOLORKEY, white );
269 for ( i = 0; i < w; i++ )
270 for ( j = 0; j < h; j++ ) {
271 if ( surf->flags & SDL_SRCCOLORKEY &&
272 stk_surface_get_pixel( surf, i, j ) == surf->format->colorkey )
273 stk_surface_set_pixel( shadow, i, j, white );
274 else
275 stk_surface_set_pixel( shadow, i, j, black );
277 return shadow;
282 ====================================================================
283 Enter a string and return True if ENTER received and False
284 if ESCAPE received.
285 ====================================================================
287 int enter_string( StkFont *font, char *caption, char *edit, int limit )
289 SDL_Event event;
290 int go_on = 1;
291 int ret = 0;
292 SDL_Surface *buffer =
293 stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
294 int length = strlen( edit );
296 SDL_SetColorKey(buffer, 0, 0);
298 stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
299 font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_CENTER_Y;
301 while ( go_on && !stk_quit_request ) {
303 stk_surface_fill( stk_display, 0,0,-1,-1, 0x0 );
304 stk_surface_alpha_blit( buffer, 0,0,-1,-1, stk_display, 0,0, 128 );
305 stk_font_write(font, stk_display, stk_display->w / 2, stk_display->h / 2, STK_OPAQUE, caption);
306 write_text_with_cursor(font, stk_display, stk_display->w / 2, stk_display->h / 2 + font->height, edit, STK_OPAQUE);
307 stk_display_update( STK_UPDATE_ALL );
308 event.type = SDL_NOEVENT;
309 SDL_PollEvent(&event);
310 /* TEST */
311 switch ( event.type ) {
312 case SDL_QUIT: stk_quit_request = 1; break;
313 case SDL_KEYDOWN:
314 switch ( event.key.keysym.sym ) {
315 case SDLK_ESCAPE:
316 ret = 0;
317 go_on = 0;
318 break;
319 case SDLK_RETURN:
320 ret = 1;
321 go_on = 0;
322 break;
323 case SDLK_BACKSPACE:
324 if ( length > 0 ) edit[--length] = 0;
325 break;
326 default:
327 if ( event.key.keysym.sym >= 32 && event.key.keysym.sym < 128 && length < limit ) {
328 edit[length++] = event.key.keysym.unicode;
329 edit[length] = 0;
331 break;
333 break;
336 stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
337 stk_display_update( STK_UPDATE_ALL );
338 SDL_FreeSurface(buffer);
340 /* reset the relative position so paddle wont jump */
341 SDL_GetRelativeMouseState(0,0);
343 return ret;
347 ====================================================================
348 Display text blinking.
349 ====================================================================
351 void write_text_with_cursor( StkFont *fnt, SDL_Surface *dest,
352 int x, int y, char *str, int alpha)
354 static int cursor_on = 0;
355 static Uint32 last_tick = 0;
356 // create temporary space for cursor and text
357 char *text_with_cursor = calloc(strlen(str) + 2, sizeof(char));
358 if (text_with_cursor) {
359 strcpy(text_with_cursor, str);
361 // Time to blink cursor on/off?
362 if (SDL_GetTicks() - last_tick > 500) {
363 last_tick = SDL_GetTicks();
364 cursor_on = ! cursor_on;
366 // Tack on cursor to end of text
367 if (cursor_on) {
368 strcat(text_with_cursor, "_");
370 else {
371 strcat(text_with_cursor, " ");
374 stk_font_write(fnt,dest,x,y,alpha,text_with_cursor);
376 free(text_with_cursor);
381 ====================================================================
382 Enter nuke mode and allow player to disintegrate single bricks
383 by spending 5% of his/her score.
384 ====================================================================
386 void game_nuke( void )
388 char buf[128];
389 SDL_Event event;
390 int x,y,i,j,leave = 0;
391 SDL_Surface *buffer =
392 stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
393 SDL_Surface *red_mask =
394 stk_surface_create( SDL_SWSURFACE, BRICK_WIDTH, BRICK_HEIGHT );
395 stk_surface_fill( red_mask, 0,0,-1,-1, 0xFF0000 );
396 SDL_SetAlpha( red_mask, SDL_SRCALPHA, 128 );
397 SDL_SetColorKey(buffer, 0, 0);
399 #ifdef AUDIO_ENABLED
400 stk_sound_play( wav_click );
401 #endif
402 SDL_SetEventFilter(0);
403 event_clear_sdl_queue();
404 /* backup screen contents */
405 stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
406 /* display bricks darkened */
407 stk_surface_blit( nuke_bkgnd, 0,0,-1,-1,
408 stk_display, 0,0 );
409 for ( i = 1; i < MAP_WIDTH - 1; i++ )
410 for ( j = 1; j < MAP_HEIGHT - 1; j++ )
411 if ( game->bricks[i][j].id >= 0 )
412 stk_surface_alpha_blit( brick_pic,
413 game->bricks[i][j].id * BRICK_WIDTH, 0,
414 BRICK_WIDTH, BRICK_HEIGHT,
415 stk_display,
416 i*BRICK_WIDTH, j*BRICK_HEIGHT, 128 );
417 /* info */
418 font->align = STK_FONT_ALIGN_LEFT;
419 sprintf( buf, _("Plane Of Inner Stability entered (Score: %i)"),
420 l_paddle->player->stats.total_score + l_paddle->score );
421 stk_font_write( font, stk_display,
422 BRICK_WIDTH, (MAP_HEIGHT-1)*BRICK_HEIGHT,
423 128, buf );
424 /* show score of player */
425 stk_display_update( STK_UPDATE_ALL );
427 x = y = -1;
428 while (!leave && !stk_quit_request) {
429 SDL_WaitEvent(&event);
430 switch ( event.type ) {
431 case SDL_QUIT:
432 stk_quit_request = 1;
433 break;
434 case SDL_MOUSEBUTTONDOWN:
435 if ( x != -1 )
436 if ( confirm( font,
437 /* xgettext:no-c-format */ _("Disintegrate Brick? (Costs 5% of your score.) y/n"),
438 CONFIRM_YES_NO ) ) {
439 /* implant a bomb to this brick and return */
440 game_set_current( local_game );
441 brick_start_expl( x,y, BRICK_EXP_TIME,
442 local_game->paddles[0] );
443 local_game->bricks[x][y].score = 0;
444 game_set_current( game );
445 l_paddle->player->stats.total_score -= (int)(0.05 *
446 (l_paddle->score +
447 l_paddle->player->stats.total_score));
448 leave = 1;
450 break;
451 case SDL_MOUSEMOTION:
452 if ( x != -1 ) {
453 /* clear old selection */
454 stk_surface_blit( nuke_bkgnd,
455 x*BRICK_WIDTH, y*BRICK_HEIGHT,
456 BRICK_WIDTH, BRICK_HEIGHT,
457 stk_display,
458 x*BRICK_WIDTH, y*BRICK_HEIGHT );
459 stk_surface_alpha_blit( brick_pic,
460 game->bricks[x][y].id * BRICK_WIDTH, 0,
461 BRICK_WIDTH, BRICK_HEIGHT,
462 stk_display,
463 x*BRICK_WIDTH, y*BRICK_HEIGHT, 128 );
464 stk_display_store_drect();
465 x = y = -1;
467 /* make new selection if brick */
468 i = event.motion.x / BRICK_WIDTH;
469 j = event.motion.y / BRICK_HEIGHT;
470 if ( i >= 1 && i <= MAP_WIDTH -2 )
471 if ( j >= 1 && j <= MAP_HEIGHT - 2 )
472 if ( game->bricks[i][j].id >= 0 ) {
473 x = i; y = j;
474 stk_surface_blit( red_mask, 0,0,-1,-1,
475 stk_display,x*BRICK_WIDTH, y*BRICK_HEIGHT );
476 stk_display_store_drect();
478 break;
479 case SDL_KEYDOWN:
480 if ( event.key.keysym.sym == SDLK_ESCAPE )
481 leave = 1;
482 break;
484 stk_display_update( STK_UPDATE_RECTS );
487 stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
488 stk_display_update( STK_UPDATE_ALL );
489 SDL_FreeSurface(red_mask);
490 SDL_FreeSurface(buffer);
491 SDL_SetEventFilter(event_filter);
494 /* gray screen and display a formatted text, directly update the
495 * screen */
496 void display_text( StkFont *font, char *format, ... )
498 int i, y, x;
499 Text *text;
500 char buf[512];
501 va_list args;
503 va_start( args, format );
504 vsnprintf( buf, 512, format, args );
505 va_end( args );
507 stk_surface_gray( stk_display, 0,0,-1,-1, 2 );
508 text = create_text( buf, 60 );
509 font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_TOP;
510 y = (stk_display->h - text->count * font->height) / 2;
511 x = stk_display->w / 2;
512 for ( i = 0; i < text->count; i++ ) {
513 stk_font_write(font, stk_display, x, y, STK_OPAQUE, text->lines[i]);
514 y += font->height;
516 delete_text( text );
518 stk_display_update( STK_UPDATE_ALL );