519 lines
16 KiB
C
519 lines
16 KiB
C
/***************************************************************************
|
|
misc.c - description
|
|
-------------------
|
|
begin : Thu Sep 6 2001
|
|
copyright : (C) 2001 by Michael Speck
|
|
email : kulkanie@gmx.net
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <time.h>
|
|
#include "lbreakout.h"
|
|
#include "../game/game.h"
|
|
#include "config.h"
|
|
#include "event.h"
|
|
#include "misc.h"
|
|
|
|
extern SDL_Surface *stk_display, *nuke_bkgnd, *brick_pic;
|
|
extern Game *local_game, *game;
|
|
extern Paddle *l_paddle;
|
|
extern StkFont *font;
|
|
extern SDL_Surface *offscreen;
|
|
extern int stk_quit_request;
|
|
int shadow_size = 8;
|
|
#ifdef AUDIO_ENABLED
|
|
extern StkSound *wav_click;
|
|
#endif
|
|
extern int motion_button;
|
|
extern Config config;
|
|
extern int bkgnd_count;
|
|
extern SDL_Surface **bkgnds;
|
|
|
|
/*
|
|
====================================================================
|
|
Load background according to id and draw background to offscreen.
|
|
Return Value: loaded background surface
|
|
====================================================================
|
|
*/
|
|
void bkgnd_draw( SDL_Surface *bkgnd, int id )
|
|
{
|
|
SDL_Surface *pic = 0;
|
|
int i, j;
|
|
|
|
if ( id >= bkgnd_count || id == -1 )
|
|
id = rand() % bkgnd_count;
|
|
|
|
/* load background */
|
|
pic = bkgnds[id];
|
|
for ( i = 0; i < bkgnd->w; i += pic->w ) {
|
|
for ( j = 0; j < bkgnd->h; j += pic->h ) {
|
|
stk_surface_blit( pic, 0,0,-1,-1,
|
|
bkgnd, i, j);
|
|
}
|
|
}
|
|
|
|
/* draw to offscreen */
|
|
stk_surface_blit( bkgnd, 0,0,-1,-1, stk_display, 0,0 );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Confirm request. Darkens screen a bit and display text.
|
|
Return Value: True if successful
|
|
====================================================================
|
|
*/
|
|
void draw_confirm_screen( StkFont *font, SDL_Surface *buffer, char *str )
|
|
{
|
|
int i, y, x;
|
|
Text *text = create_text( str, 60 );
|
|
stk_surface_fill( stk_display, 0,0,-1,-1, 0x0 );
|
|
stk_surface_alpha_blit( buffer, 0,0,-1,-1, stk_display, 0,0, 128 );
|
|
font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_TOP;
|
|
y = (stk_display->h - text->count * font->height) / 2;
|
|
x = stk_display->w / 2;
|
|
for ( i = 0; i < text->count; i++ ) {
|
|
stk_font_write(font, stk_display, x, y, STK_OPAQUE, text->lines[i]);
|
|
y += font->height;
|
|
}
|
|
delete_text( text );
|
|
}
|
|
int confirm( StkFont *font, char *str, int type )
|
|
{
|
|
SDL_Event event;
|
|
int go_on = 1;
|
|
int ret = 0;
|
|
SDL_Surface *buffer =
|
|
stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
|
|
SDL_SetColorKey(buffer, 0, 0);
|
|
|
|
#ifdef AUDIO_ENABLED
|
|
stk_sound_play( wav_click );
|
|
#endif
|
|
|
|
event_clear_sdl_queue();
|
|
|
|
stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
|
|
if ( type == CONFIRM_PAUSE )
|
|
stk_surface_gray( stk_display, 0,0,-1,-1,0 );
|
|
else
|
|
draw_confirm_screen( font, buffer, str );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
|
|
while (go_on && !stk_quit_request) {
|
|
SDL_WaitEvent(&event);
|
|
/* TEST */
|
|
switch ( event.type ) {
|
|
case SDL_QUIT: stk_quit_request = 1; break;
|
|
case SDL_MOUSEBUTTONUP:
|
|
if ( type == CONFIRM_ANY_KEY ) {
|
|
ret = 1; go_on = 0;
|
|
}
|
|
/* else
|
|
if ( type == CONFIRM_YES_NO ) {
|
|
if ( event.button.button == LEFT_BUTTON )
|
|
ret = 1;
|
|
else
|
|
ret = 0;
|
|
go_on = 0;
|
|
}*/
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
if ( type == CONFIRM_ANY_KEY ) {
|
|
ret = 1; go_on = 0;
|
|
break;
|
|
}
|
|
else
|
|
if ( type == CONFIRM_PAUSE ) {
|
|
if ( event.key.keysym.sym == SDLK_p ) {
|
|
ret = 1; go_on = 0;
|
|
break;
|
|
}
|
|
else
|
|
if ( event.key.keysym.sym == SDLK_f ) {
|
|
config.fullscreen = !config.fullscreen;
|
|
stk_display_apply_fullscreen( config.fullscreen );
|
|
draw_confirm_screen( font, buffer, str );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char *keyName = SDL_GetKeyName(event.key.keysym.sym);
|
|
char *yesLetter = _("y");
|
|
char *noLetter = _("n");
|
|
if (strcmp(keyName, yesLetter) == 0) {
|
|
go_on = 0;
|
|
ret = 1;
|
|
}
|
|
else
|
|
if (event.key.keysym.sym==SDLK_ESCAPE || strcmp(keyName, noLetter) == 0 ) {
|
|
go_on = 0;
|
|
ret = 0;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#ifdef AUDIO_ENABLED
|
|
stk_sound_play( wav_click );
|
|
#endif
|
|
stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
SDL_FreeSurface(buffer);
|
|
|
|
/* reset the relative position so paddle wont jump */
|
|
SDL_GetRelativeMouseState(0,0);
|
|
|
|
return ret;
|
|
}
|
|
#ifdef NETWORK_ENABLED
|
|
/*
|
|
====================================================================
|
|
Display a info message (gray screen a bit and display text),
|
|
send a MSG_READY when player has clicked and wait for a remote answer
|
|
(timeout 10 secs). Waiting may be cancelled by pressing ESCAPE which
|
|
results in sending a MSG_GAME_EXITED.
|
|
Return Value: True if both peers clicked to continue, False if the
|
|
connection was cancelled for some reason.
|
|
====================================================================
|
|
*/
|
|
int display_info( StkFont *font, char *str, NetSocket *peer )
|
|
{
|
|
#if 0
|
|
char error[128];
|
|
Net_Msg msg;
|
|
SDL_Event event;
|
|
int ret = 0, leave = 0;
|
|
SDL_Surface *buffer =
|
|
stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
|
|
SDL_SetColorKey(buffer, 0, 0);
|
|
|
|
#ifdef AUDIO_ENABLED
|
|
stk_sound_play( wav_click );
|
|
#endif
|
|
|
|
event_clear_sdl_queue();
|
|
|
|
stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
|
|
draw_confirm_screen( font, buffer, str );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
stk_wait_for_input();
|
|
net_write_empty_msg( peer, MSG_READY );
|
|
draw_confirm_screen( font, buffer,
|
|
_("Waiting for remote answer...") );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
event_clear_sdl_queue();
|
|
while ( !leave ) {
|
|
if ( SDL_PollEvent( &event ) )
|
|
if ( (event.type == SDL_KEYDOWN &&
|
|
event.key.keysym.sym == SDLK_ESCAPE) ||
|
|
event.type == SDL_QUIT ) {
|
|
net_write_empty_msg( peer, MSG_GAME_EXITED );
|
|
leave = 1;
|
|
break;
|
|
}
|
|
if ( net_read_msg( peer, &msg, 0 ) )
|
|
switch ( msg.type ) {
|
|
case MSG_READY:
|
|
ret = 1; leave = 1;
|
|
break;
|
|
case MSG_GAME_EXITED:
|
|
ret = 0; leave = 1;
|
|
sprintf( error, /* xgettext:no-c-format */ _("remote player cancelled the game\n") );
|
|
confirm( font, error, CONFIRM_ANY_KEY );
|
|
break;
|
|
}
|
|
SDL_Delay( 10 );
|
|
}
|
|
|
|
#ifdef AUDIO_ENABLED
|
|
stk_sound_play( wav_click );
|
|
#endif
|
|
|
|
stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
SDL_FreeSurface(buffer);
|
|
|
|
/* reset the relative position so paddle wont jump */
|
|
SDL_GetRelativeMouseState(0,0);
|
|
|
|
return ret;
|
|
#endif
|
|
return 1;
|
|
}
|
|
#endif
|
|
/*
|
|
====================================================================
|
|
Create shadow surface for specified region in surface.
|
|
Return Value: Shadow surface
|
|
====================================================================
|
|
*/
|
|
SDL_Surface* create_shadow( SDL_Surface *surf, int x, int y, int w, int h )
|
|
{
|
|
SDL_Surface *shadow = 0;
|
|
int i, j;
|
|
Uint32 white = SDL_MapRGB( stk_display->format, 0xff, 0xff, 0xff );
|
|
Uint32 black = SDL_MapRGB( stk_display->format, 0, 0, 0 );
|
|
shadow = stk_surface_create( SDL_SWSURFACE, w, h );
|
|
SDL_SetColorKey( shadow, SDL_SRCCOLORKEY, white );
|
|
for ( i = 0; i < w; i++ )
|
|
for ( j = 0; j < h; j++ ) {
|
|
if ( surf->flags & SDL_SRCCOLORKEY &&
|
|
stk_surface_get_pixel( surf, i, j ) == surf->format->colorkey )
|
|
stk_surface_set_pixel( shadow, i, j, white );
|
|
else
|
|
stk_surface_set_pixel( shadow, i, j, black );
|
|
}
|
|
return shadow;
|
|
}
|
|
|
|
|
|
/*
|
|
====================================================================
|
|
Enter a string and return True if ENTER received and False
|
|
if ESCAPE received.
|
|
====================================================================
|
|
*/
|
|
int enter_string( StkFont *font, char *caption, char *edit, int limit )
|
|
{
|
|
SDL_Event event;
|
|
int go_on = 1;
|
|
int ret = 0;
|
|
SDL_Surface *buffer =
|
|
stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
|
|
int length = strlen( edit );
|
|
|
|
SDL_SetColorKey(buffer, 0, 0);
|
|
|
|
stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
|
|
font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_CENTER_Y;
|
|
|
|
while ( go_on && !stk_quit_request ) {
|
|
|
|
stk_surface_fill( stk_display, 0,0,-1,-1, 0x0 );
|
|
stk_surface_alpha_blit( buffer, 0,0,-1,-1, stk_display, 0,0, 128 );
|
|
stk_font_write(font, stk_display, stk_display->w / 2, stk_display->h / 2, STK_OPAQUE, caption);
|
|
write_text_with_cursor(font, stk_display, stk_display->w / 2, stk_display->h / 2 + font->height, edit, STK_OPAQUE);
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
event.type = SDL_NOEVENT;
|
|
SDL_PollEvent(&event);
|
|
/* TEST */
|
|
switch ( event.type ) {
|
|
case SDL_QUIT: stk_quit_request = 1; break;
|
|
case SDL_KEYDOWN:
|
|
switch ( event.key.keysym.sym ) {
|
|
case SDLK_ESCAPE:
|
|
ret = 0;
|
|
go_on = 0;
|
|
break;
|
|
case SDLK_RETURN:
|
|
ret = 1;
|
|
go_on = 0;
|
|
break;
|
|
case SDLK_BACKSPACE:
|
|
if ( length > 0 ) edit[--length] = 0;
|
|
break;
|
|
default:
|
|
if ( event.key.keysym.sym >= 32 && event.key.keysym.sym < 128 && length < limit ) {
|
|
edit[length++] = event.key.keysym.unicode;
|
|
edit[length] = 0;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
SDL_FreeSurface(buffer);
|
|
|
|
/* reset the relative position so paddle wont jump */
|
|
SDL_GetRelativeMouseState(0,0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
====================================================================
|
|
Display text blinking.
|
|
====================================================================
|
|
*/
|
|
void write_text_with_cursor( StkFont *fnt, SDL_Surface *dest,
|
|
int x, int y, char *str, int alpha)
|
|
{
|
|
static int cursor_on = 0;
|
|
static Uint32 last_tick = 0;
|
|
// create temporary space for cursor and text
|
|
char *text_with_cursor = calloc(strlen(str) + 2, sizeof(char));
|
|
if (text_with_cursor) {
|
|
strcpy(text_with_cursor, str);
|
|
|
|
// Time to blink cursor on/off?
|
|
if (SDL_GetTicks() - last_tick > 500) {
|
|
last_tick = SDL_GetTicks();
|
|
cursor_on = ! cursor_on;
|
|
}
|
|
// Tack on cursor to end of text
|
|
if (cursor_on) {
|
|
strcat(text_with_cursor, "_");
|
|
}
|
|
else {
|
|
strcat(text_with_cursor, " ");
|
|
}
|
|
|
|
stk_font_write(fnt,dest,x,y,alpha,text_with_cursor);
|
|
|
|
free(text_with_cursor);
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================================================================
|
|
Enter nuke mode and allow player to disintegrate single bricks
|
|
by spending 5% of his/her score.
|
|
====================================================================
|
|
*/
|
|
void game_nuke( void )
|
|
{
|
|
char buf[128];
|
|
SDL_Event event;
|
|
int x,y,i,j,leave = 0;
|
|
SDL_Surface *buffer =
|
|
stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
|
|
SDL_Surface *red_mask =
|
|
stk_surface_create( SDL_SWSURFACE, BRICK_WIDTH, BRICK_HEIGHT );
|
|
stk_surface_fill( red_mask, 0,0,-1,-1, 0xFF0000 );
|
|
SDL_SetAlpha( red_mask, SDL_SRCALPHA, 128 );
|
|
SDL_SetColorKey(buffer, 0, 0);
|
|
|
|
#ifdef AUDIO_ENABLED
|
|
stk_sound_play( wav_click );
|
|
#endif
|
|
SDL_SetEventFilter(0);
|
|
event_clear_sdl_queue();
|
|
/* backup screen contents */
|
|
stk_surface_blit( stk_display, 0,0,-1,-1, buffer, 0,0 );
|
|
/* display bricks darkened */
|
|
stk_surface_blit( nuke_bkgnd, 0,0,-1,-1,
|
|
stk_display, 0,0 );
|
|
for ( i = 1; i < MAP_WIDTH - 1; i++ )
|
|
for ( j = 1; j < MAP_HEIGHT - 1; j++ )
|
|
if ( game->bricks[i][j].id >= 0 )
|
|
stk_surface_alpha_blit( brick_pic,
|
|
game->bricks[i][j].id * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
stk_display,
|
|
i*BRICK_WIDTH, j*BRICK_HEIGHT, 128 );
|
|
/* info */
|
|
font->align = STK_FONT_ALIGN_LEFT;
|
|
sprintf( buf, _("Plane Of Inner Stability entered (Score: %i)"),
|
|
l_paddle->player->stats.total_score + l_paddle->score );
|
|
stk_font_write( font, stk_display,
|
|
BRICK_WIDTH, (MAP_HEIGHT-1)*BRICK_HEIGHT,
|
|
128, buf );
|
|
/* show score of player */
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
|
|
x = y = -1;
|
|
while (!leave && !stk_quit_request) {
|
|
SDL_WaitEvent(&event);
|
|
switch ( event.type ) {
|
|
case SDL_QUIT:
|
|
stk_quit_request = 1;
|
|
break;
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
if ( x != -1 )
|
|
if ( confirm( font,
|
|
/* xgettext:no-c-format */ _("Disintegrate Brick? (Costs 5% of your score.) y/n"),
|
|
CONFIRM_YES_NO ) ) {
|
|
/* implant a bomb to this brick and return */
|
|
game_set_current( local_game );
|
|
brick_start_expl( x,y, BRICK_EXP_TIME,
|
|
local_game->paddles[0] );
|
|
local_game->bricks[x][y].score = 0;
|
|
game_set_current( game );
|
|
l_paddle->player->stats.total_score -= (int)(0.05 *
|
|
(l_paddle->score +
|
|
l_paddle->player->stats.total_score));
|
|
leave = 1;
|
|
}
|
|
break;
|
|
case SDL_MOUSEMOTION:
|
|
if ( x != -1 ) {
|
|
/* clear old selection */
|
|
stk_surface_blit( nuke_bkgnd,
|
|
x*BRICK_WIDTH, y*BRICK_HEIGHT,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
stk_display,
|
|
x*BRICK_WIDTH, y*BRICK_HEIGHT );
|
|
stk_surface_alpha_blit( brick_pic,
|
|
game->bricks[x][y].id * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
stk_display,
|
|
x*BRICK_WIDTH, y*BRICK_HEIGHT, 128 );
|
|
stk_display_store_drect();
|
|
x = y = -1;
|
|
}
|
|
/* make new selection if brick */
|
|
i = event.motion.x / BRICK_WIDTH;
|
|
j = event.motion.y / BRICK_HEIGHT;
|
|
if ( i >= 1 && i <= MAP_WIDTH -2 )
|
|
if ( j >= 1 && j <= MAP_HEIGHT - 2 )
|
|
if ( game->bricks[i][j].id >= 0 ) {
|
|
x = i; y = j;
|
|
stk_surface_blit( red_mask, 0,0,-1,-1,
|
|
stk_display,x*BRICK_WIDTH, y*BRICK_HEIGHT );
|
|
stk_display_store_drect();
|
|
}
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
if ( event.key.keysym.sym == SDLK_ESCAPE )
|
|
leave = 1;
|
|
break;
|
|
}
|
|
stk_display_update( STK_UPDATE_RECTS );
|
|
}
|
|
|
|
stk_surface_blit( buffer, 0,0,-1,-1, stk_display, 0,0 );
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
SDL_FreeSurface(red_mask);
|
|
SDL_FreeSurface(buffer);
|
|
SDL_SetEventFilter(event_filter);
|
|
}
|
|
|
|
/* gray screen and display a formatted text, directly update the
|
|
* screen */
|
|
void display_text( StkFont *font, char *format, ... )
|
|
{
|
|
int i, y, x;
|
|
Text *text;
|
|
char buf[512];
|
|
va_list args;
|
|
|
|
va_start( args, format );
|
|
vsnprintf( buf, 512, format, args );
|
|
va_end( args );
|
|
|
|
stk_surface_gray( stk_display, 0,0,-1,-1, 2 );
|
|
text = create_text( buf, 60 );
|
|
font->align = STK_FONT_ALIGN_CENTER_X | STK_FONT_ALIGN_TOP;
|
|
y = (stk_display->h - text->count * font->height) / 2;
|
|
x = stk_display->w / 2;
|
|
for ( i = 0; i < text->count; i++ ) {
|
|
stk_font_write(font, stk_display, x, y, STK_OPAQUE, text->lines[i]);
|
|
y += font->height;
|
|
}
|
|
delete_text( text );
|
|
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
}
|