/* ==================================================================== 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; }
/* ==================================================================== Update screen without menu itself as this is shown next frame. ==================================================================== */ void manager_show() { stk_display_apply_fullscreen( config.fullscreen ); stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 ); chart_show( chart_set_query_id( chart_id ), cx, cy, cw, ch ); stk_display_update( STK_UPDATE_ALL ); }
/* display formatted info + score table if multiple players */ static void display_score_table( char *format, ... ) { va_list args; int i; char info[256], buf[32]; va_start( args, format ); vsnprintf( info, 64, format, args ); va_end( args ); if ( player_count > 1 ) { strcat( info, "##" ); for ( i = 0; i < player_count; i++ ) { /* add player and score */ sprintf( buf, "#%12s %10i", " ", players[i].stats.total_score ); strcpy( buf + 1, players[i].name ); buf[strlen(players[i].name)+1] = 32; strcat( info, buf ); } } display_text( font, info ); stk_display_update( STK_UPDATE_ALL ); }
/* Fade all animations until they disappear */ static void fade_anims() { float alpha = 255.0; int ms, i; stk_timer_reset(); if ( game->game_type == GT_LOCAL && game->winner != PADDLE_BOTTOM ) frame_remove_life(); while ( alpha > 0 ) { displays_hide(); for ( i = 0; i < game->paddle_count; i++ ) paddle_hide( game->paddles[i] ); balls_hide(); extras_hide(); shrapnells_hide(); shots_hide(); walls_hide(); credit_hide(); ms = stk_timer_get_time(); alpha -= 0.3 * ms; if ( alpha < 0 ) alpha = 0; shrapnells_update( ms ); for ( i = 0; i < game->paddle_count; i++ ) paddle_alphashow( game->paddles[i], alpha ); balls_alphashow( alpha ); extras_alphashow( alpha ); shots_alphashow( alpha ); shrapnells_show(); walls_alphashow( alpha ); displays_show(); credit_alphashow( alpha ); stk_display_update( STK_UPDATE_RECTS ); } }
/* change theme */ void cb_change_theme() { Menu *menu; theme_load( theme_names[config.theme_id] ); hint_set_bkgnd( mbkgnd ); /* apply the new background to all items */ list_reset( menus ); while ( ( menu = list_next( menus ) ) ) { menu_set_bkgnd( menu, mbkgnd ); menu_set_fonts( menu, mcfont, mfont, mhfont ); } stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 ); stk_display_update( STK_UPDATE_ALL ); }
static void display_bonus_level_score() { double avgRatio = 0; char info[256]; info[0] = 0; if (local_game->blNumCompletedRuns==0) avgRatio = 0; else avgRatio = local_game->blRatioSum/local_game->blNumCompletedRuns; switch (local_game->level_type) { case LT_JUMPING_JACK: display_text( font, "%s, you hit %d Jumping Jacks!##Your average ratio: %5d%%# Your score: %6d", cur_player->name,local_game->blNumCompletedRuns, (int)(100.0*avgRatio),local_game->totalBonusLevelScore); break; case LT_OUTBREAK: display_text( font, "%s, you stopped %d Outbreaks!##Your average ratio: %5d%%# Your score: %6d", cur_player->name,local_game->blNumCompletedRuns, (int)(100.0*avgRatio),local_game->totalBonusLevelScore); break; case LT_BARRIER: display_text( font, "%s, you broke through %d Barriers!##Your average ratio: %5d%%# Your score: %6d", cur_player->name,local_game->blNumCompletedRuns, (int)(100.0*avgRatio),local_game->totalBonusLevelScore); break; case LT_SITTING_DUCKS: display_text( font, "%s, you shot %d Sitting Ducks!##Your score: %6d", cur_player->name,local_game->blNumCompletedRuns, local_game->totalBonusLevelScore); break; case LT_HUNTER: display_text( font, "%s, you hunted down %d bricks!##Your average ratio: %5d%%# Your score: %6d", cur_player->name,local_game->blNumCompletedRuns, (int)(100.0*avgRatio),local_game->totalBonusLevelScore); break; case LT_DEFENDER: display_text( font, "%s, you stopped %d waves#killing a total of %d invaders!##Your average ratio: %5d%%# Your score: %6d", cur_player->name,local_game->blNumCompletedRuns,local_game->blTotalNumKilledInvaders, (int)(100.0*avgRatio),local_game->totalBonusLevelScore); break; } stk_display_update( STK_UPDATE_ALL ); }
void open_pause_chat( char *text ) { set_state( CS_PAUSE ); /* clear pause_chatter */ memset( pause_chatter, 0, sizeof( pause_chatter ) ); /* clear global gui widgets */ gui_focused_widget = 0; gui_clicked_widget = 0; gui_key_widget = 0; /* use 'text' as initial chatter */ client_add_pausechatter( text, 1 ); /* gray screen */ stk_surface_gray( stk_display, 0,0,-1,-1, 1 ); /* show pauseroom */ gui_widget_show( dlg_pauseroom ); stk_display_update( STK_UPDATE_ALL ); /* disable event filter */ SDL_SetEventFilter( 0 ); /* disable client_recv which is called as time event */ gui_widget_disable_event( dlg_chatroom, GUI_TIME_PASSED ); }
/* 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 ); }
/* switch client to new state */ void set_state( int newstate ) { if ( client_state == newstate ) return; if ( newstate == CS_PLAY ) grab_input( 1 ); if ( client_state == CS_PLAY ) grab_input( 0 ); if ( client_state == CS_CONFIRM_WARP || client_state == CS_CONFIRM_RESTART || client_state == CS_CONFIRM_QUIT || client_state == CS_CONFIRM_CONTINUE || client_state == CS_GET_READY || client_state == CS_PAUSE || client_state == CS_FINAL_PLAYER_INFO || client_state == CS_GET_READY_FOR_NEXT_LEVEL || client_state == CS_RECV_LEVEL || client_state == CS_ROUND_RESULT || client_state == CS_RECV_STATS || client_state == CS_FATAL_ERROR ) { /* show offscreen */ if ( offscreen ) { stk_surface_blit( offscreen, 0,0,-1,-1, stk_display, 0,0 ); end_frame(); } /* do not refresh when coming from RECV_LEVEL as a GET_READY * will follow */ if ( client_state != CS_RECV_LEVEL ) if ( client_state != CS_ROUND_RESULT ) if ( client_state != CS_RECV_STATS ); stk_display_update( STK_UPDATE_ALL ); } client_state = newstate; stk_timer_reset(); }
/* ==================================================================== Run menu until request sent ==================================================================== */ int manager_run() { SDL_Event event; int result = ACTION_NONE; int ms; /* draw highscores */ chart_show( chart_set_query_id( chart_id ), cx, cy, cw, ch ); /* loop */ stk_timer_reset(); while ( result == ACTION_NONE && !stk_quit_request ) { menu_hide( cur_menu ); hint_hide(); /* fullscreen if no item selected */ if ( SDL_PollEvent( &event ) ) { if ( cur_menu->cur_item == 0 || (cur_menu->cur_item->type != ITEM_EDIT && cur_menu->cur_item->type != ITEM_KEY ) ) if ( event.type == SDL_KEYDOWN ) if ( event.key.keysym.sym == SDLK_f ) { config.fullscreen = !config.fullscreen; stk_display_apply_fullscreen( config.fullscreen ); stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 ); stk_display_update( STK_UPDATE_ALL ); } /* check if clicked on highscore */ if ( event.type == SDL_MOUSEBUTTONDOWN ) if ( event.button.x >= cx && event.button.y >= cy ) if ( event.button.x < cx + cw && event.button.y < cy + ch ) { #ifdef AUDIO_ENABLED stk_sound_play( wav_menu_click ); #endif /* set chart id */ if ( event.button.button == STK_BUTTON_LEFT ) { chart_id++; if ( chart_id == charts->count ) chart_id = 0; } else { chart_id--; if ( chart_id == -1 ) chart_id = charts->count - 1; } /* redraw */ stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 ); chart_show( chart_set_query_id( chart_id ), cx, cy, cw, ch ); } result = menu_handle_event( cur_menu, &event ); } else #ifdef ANDROID stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 ); #endif menu_handle_event( cur_menu, 0 ); /* update motion */ ms = stk_timer_get_time(); menu_update( cur_menu, ms ); hint_update( ms ); menu_show( cur_menu ); chart_show( chart_set_query_id( chart_id ), cx, cy, cw, ch ); hint_show(); stk_display_update( STK_UPDATE_RECTS ); SDL_Delay( 5 ); } return result; }
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 switch (event.key.keysym.sym) { case SDLK_y: go_on = 0; ret = 1; break; case SDLK_ESCAPE: case SDLK_n: 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; }
/* ==================================================================== 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, "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); }
/* ==================================================================== 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, "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; }
/* modify the client and its state according to the key pressed */ static int handle_default_key( int key, int *abort ) { SDL_Surface *buffer; switch ( key ) { case SDLK_F1: case SDLK_h: if ( client_state != CS_PLAY ) break; if ( game->game_type == GT_NETWORK ) break; /* only for single player */ grab_input(0); help_run(); grab_input(1); return 1; case SDLK_q: case SDLK_ESCAPE: /* recv_stats or final_stats means we already broke up * the game so ESC will directly quit */ if ( client_state == CS_RECV_STATS || client_state == CS_FINAL_STATS ) { *abort = 1; break; } if ( client_state == CS_CONFIRM_QUIT ) break; if ( client_state == CS_PAUSE ) break; if ( players_count() == 0 ) break; set_state(CS_CONFIRM_QUIT); if ( game->game_type == GT_LOCAL && game_set != 0 /*not testing a level*/ ) display_text( font, "Quit Game? y/n#(If yes, this game may be resumed later.#No highscore entry is created yet.)" ); else display_text( font, "Quit Game? y/n" ); return 1; case SDLK_r: if ( client_state != CS_PLAY ) break; if ( game->game_type == GT_NETWORK ) break; /* only for single player */ if ( game_set == 0 ) break; /* test level */ if ( cur_player->lives < 2 ) break; set_state(CS_CONFIRM_RESTART); display_text( font, "Restart Level? y/n" ); return 1; case SDLK_d: if ( client_state != CS_PLAY ) break; if ( game->game_type == GT_NETWORK ) break; /* only for single player */ if ( !allow_disintegrate ) break; if ( game->level_type != LT_NORMAL ) break; /* not in bonus levels */ grab_input(0); game_nuke(); grab_input(1); return 1; case SDLK_f: buffer = stk_surface_create( SDL_SWSURFACE, 640, 480 ); SDL_BlitSurface( stk_display, 0, buffer, 0 ); config.fullscreen = !config.fullscreen; stk_display_apply_fullscreen( config.fullscreen ); SDL_BlitSurface( buffer, 0, stk_display, 0 ); stk_display_update( STK_UPDATE_ALL); SDL_FreeSurface( buffer ); return 1; case SDLK_s: #ifdef AUDIO_ENABLED config.sound = !config.sound; stk_audio_enable_sound( config.sound ); #endif return 1; case SDLK_a: config.anim++; if ( config.anim >= 4 ) config.anim = 0; return 1; case SDLK_TAB: stk_display_take_screenshot(); return 1; case SDLK_t: return 0; case SDLK_p: if ( client_state == CS_PLAY ) client_set_pause(1); else if (client_state==CS_PAUSE) client_set_pause(0); return 1; default: if ( client_state != CS_PLAY ) break; if ( game->game_type != GT_LOCAL ) break; if ( game->bricks_left > game->warp_limit ) break; if ( game_set == 0 ) break; /* test level */ if ( game->level_type != LT_NORMAL ) break; /* not in bonus levels */ if ( key == config.k_warp ) { set_state(CS_CONFIRM_WARP); display_text( font, "Warp to next level? y/n" ); return 1; } break; } return 0; }
int main(int argc, char *argv[]) { int result = ACTION_NONE; int leave = 0; char *editor_file = 0; char path[512]; SDL_Surface *loading; #ifdef __unix__ gid_t realgid; hi_dir_chart_file = fopen(HI_DIR "/" CHART_FILE_NAME, "r+"); /* This is where we drop our setuid/setgid privileges. */ realgid = getgid(); if (setresgid(-1, realgid, realgid) != 0) { perror("Could not drop setgid privileges. Aborting."); exit(1); } #endif /* i18n */ #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); #endif #ifdef _WIN32 /* Get Windows to open files in binary mode instead of default text mode */ _fmode = _O_BINARY; #endif /* lbreakout info */ printf( "LBreakout2 %s\nCopyright 2001-2010 Michael Speck\nPublished under GNU GPL\n---\n", VERSION ); printf( "Looking up data in: %s\n", SRC_DIR ); printf( "Looking up highscores in: %s\n", HI_DIR ); printf( "Looking up custom levels in: %s/%s/lbreakout2-levels\n", (getenv( "HOME" )?getenv( "HOME" ):"."), CONFIG_DIR_NAME ); #ifndef AUDIO_ENABLED printf( "Compiled without sound and music\n" ); #endif set_random_seed(); /* set random seed */ config_load(); stk_init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK ); if ( config.fullscreen ) stk_display_open( SDL_SWSURFACE | SDL_FULLSCREEN, 640, 480, 16 ); else stk_display_open( SDL_SWSURFACE, 640, 480, 16 ); stk_audio_open( 0,0,0,config.audio_buffer_size ); SDL_WM_SetCaption( "LBreakout2", 0 ); SDL_SetEventFilter( event_filter ); stk_audio_enable_sound( config.sound ); stk_audio_set_sound_volume( config.volume * 16 ); /* load a little loading pic */ stk_surface_set_path( SRC_DIR "/gfx" ); loading = stk_surface_load( SDL_SWSURFACE, "loading.png" ); stk_surface_blit( loading, 0,0,-1,-1, stk_display, (stk_display->w-loading->w)/2, (stk_display->h-loading->h)/2 ); stk_display_update( STK_UPDATE_ALL ); /* load the GUI graphics from SRC_DIR/gui_theme */ stk_surface_set_path( SRC_DIR ); stk_audio_set_path( SRC_DIR ); gui_init( "gui_theme" ); stk_surface_set_path( SRC_DIR "/gfx" ); stk_audio_set_path( SRC_DIR "/sounds" ); /* load resources */ /* for simplicity all functions are kept but anything * that is now themeable is loaded in * theme_load instead of the original function * (deleting resources works analouge) */ theme_get_list(); if ( config.theme_count != theme_count ) { if ( config.theme_id >= theme_count ) config.theme_id = 0; config.theme_count = theme_count; } theme_load( theme_names[config.theme_id] ); /* old functions still with initialzations of * lists or variables */ client_game_create(); hint_load_res(); chart_load(); manager_create(); client_create(); exp_load(); editor_create(); help_create(); /* run game */ manager_fade( STK_FADE_IN ); while( !leave && !stk_quit_request ) { result = manager_run(); switch( result ) { case ACTION_QUIT: leave = 1; break; case ACTION_RESUME_0: manager_fade( STK_FADE_OUT ); if ( client_game_resume_local( 0 ) ) client_game_run(); client_game_finalize(); manager_fade( STK_FADE_IN ); break; case ACTION_PLAY_LBR: manager_fade( STK_FADE_OUT ); gameSeed = rand(); /* set random seed for next FREAKOUT/BonusLevels */ if ( client_game_init_local( "LBreakout2" ) ) client_game_run(); client_game_finalize(); manager_fade( STK_FADE_IN ); break; case ACTION_PLAY_CUSTOM: manager_fade( STK_FADE_OUT ); gameSeed = rand(); /* set random seed for next FREAKOUT/BonusLevels */ if (gameSeed==0) gameSeed=1; /* not allowed because.... A HACK!!! 0 means to have no bonus levels to save a parameter */ if ( client_game_init_local( levelset_names_local[config.levelset_id_local] ) ) client_game_run(); client_game_finalize(); manager_fade( STK_FADE_IN ); break; case ACTION_EDIT: /* new set? */ if ( strequal( NEW_SET, edit_set ) ) { editor_file = calloc( 16, sizeof( char ) ); snprintf( path, sizeof(path)-1, "%s/%s/lbreakout2-levels", getenv( "HOME" )? getenv("HOME"):".", CONFIG_DIR_NAME ); if ( !enter_string( font, _("Set Name:"), editor_file, 12 ) || !file_check( path, editor_file, "w" ) ) { free( editor_file ); break; } else manager_update_set_list(); } else editor_file = strdup( edit_set ); if ( editor_init( editor_file ) ) { manager_fade( STK_FADE_OUT ); editor_run(); editor_clear(); manager_fade( STK_FADE_IN ); } free( editor_file ); editor_file = 0; break; case ACTION_QUICK_HELP: help_run(); break; case ACTION_CLIENT: manager_fade( STK_FADE_OUT ); client_run(); manager_fade( STK_FADE_IN ); break; default: break; } } manager_fade( STK_FADE_OUT ); /* delete stuff */ help_delete(); manager_delete(); chart_save(); chart_delete(); editor_delete(); exp_delete(); client_game_delete(); hint_delete_res(); theme_delete(); theme_delete_list(); stk_surface_free( &loading ); config_save(); if (hi_dir_chart_file) fclose(hi_dir_chart_file); return EXIT_SUCCESS; }
/* ==================================================================== Try to connect to a game server. Retry twice every second or quit then. ==================================================================== */ void client_connect( GuiWidget *widget, GuiEvent *event ) { #ifdef NETWORK_ENABLED NetAddr newaddr; int attempt = 0; int type; char server[128]; if ( event->type != GUI_CLICKED ) return; /* close the connect window */ gui_widget_hide( dlg_connect ); /* disconnect from current server */ client_disconnect(); /* extract ip and port and build a new socket out of it */ gui_edit_get_text( edit_server, server, 128, 0, -1 ); snprintf( config.server, 64, "%s", server ); if ( !net_build_addr( &newaddr, server, 0 ) ) { client_printf_chatter( 1, _("ERROR: address %s does not resolve"), config.server ); return; } socket_init( &client, &newaddr ); /* get username */ gui_edit_get_text( edit_username, config.username, 16, 0,-1 ); /* build connect message */ msg_begin_writing( msgbuf, &msglen, 64 ); msg_write_int8( MSG_CONNECT ); msg_write_int8( PROTOCOL ); msg_write_string( config.username ); msg_write_string( _("unused") ); /* passwd */ while ( attempt < 3 ) { client_printf_chatter( 1, "%s: %s...", config.server, attempt==0?_("connecting"):_("retry") ); stk_display_update( STK_UPDATE_ALL ); net_transmit_connectionless( &newaddr, msglen, msgbuf ); SDL_Delay( 1000 ); while ( net_recv_packet() ) { if ( msg_is_connectionless() ) msg_begin_connectionless_reading(); else if ( !socket_process_header( &client ) ) continue; type = msg_read_int8(); switch ( type ) { case MSG_LOGIN_OKAY: client_id = msg_read_int32(); strcpy( client_name, msg_read_string() ); client_printf_chatter( 1, _("%s: connected!"), config.server ); client_is_connected = 1; return; case MSG_ERROR: client_printf_chatter( 1, _("ERROR: connection refused: %s"), msg_read_string() ); return; } } attempt++; } client_add_chatter( _("ERROR: server does not respond"), 1 ); #endif }
/* run the state driven loop until game is broken up or finished */ void client_game_run( void ) { int ms, frame_delay = config.fps?10:1; int button_clicked, key_pressed; SDL_Event event; int abort = 0, i, j, penalty; /* frame rate */ int frames = 0; int frame_time = SDL_GetTicks(); event_clear_sdl_queue(); stk_display_fade( STK_FADE_IN, STK_FADE_DEFAULT_TIME ); stats_received = 0; stk_timer_reset(); ms = 1; while ( !abort && !stk_quit_request ) { /* check wether an event occured */ button_clicked = key_pressed = 0; if ( SDL_PollEvent( &event ) ) { if ( client_state == CS_PAUSE && game->game_type == GT_NETWORK ) gui_dispatch_event( &event, ms ); else if ( event.type == SDL_MOUSEBUTTONDOWN ) button_clicked = event.button.button; else if ( event.type == SDL_KEYDOWN ) { key_pressed = event.key.keysym.sym; if ( handle_default_key( key_pressed, &abort ) ) key_pressed = 0; } else if (event.type == SDL_ACTIVEEVENT) { if (event.active.state == SDL_APPINPUTFOCUS || event.active.state == SDL_APPACTIVE ) if (event.active.gain == 0 ) client_set_pause(1); } } else if ( client_state == CS_PAUSE && game->game_type == GT_NETWORK ) gui_dispatch_event( 0, ms ); /* check whether Shift is pressed to switch between own and highest score */ if (game->game_type == GT_LOCAL) handle_display_switch(); /* let server know we're still alive except * in CS_PLAY as we send paddle updates there */ if ( game->game_type == GT_NETWORK ) comm_send_heartbeat(); /* handle client */ switch ( client_state ) { case CS_FINAL_STATS: if ( key_pressed==SDLK_SPACE ) abort = 1; break; case CS_FATAL_ERROR: /* after game was violently broken up the server * may still send the stats of the game so far */ if ( button_clicked || key_pressed ) { SDL_Delay(250); /* give time to release button */ set_state( CS_RECV_STATS ); display_text( font, "Receiving final stats..." ); } break; case CS_FINAL_TABLE: if ( button_clicked || key_pressed ) { check_highscores(); select_chart( game_set->name, 0 ); /* remove saved game */ slot_delete( 0 ); slot_update_hint( 0, item_resume_0->hint ); /* quit local game */ abort = 1; } break; case CS_SCORE_TABLE: /* show who's next player and scores in local game */ display_score_table( "Next Player: %s", cur_player->name ); set_state( CS_GET_READY ); break; case CS_BONUS_LEVEL_SCORE: /* display total score from this level for player */ display_bonus_level_score(); set_state( CS_GET_READY_FOR_NEXT_LEVEL ); break; case CS_FINAL_PLAYER_INFO: if ( button_clicked || key_pressed ) { SDL_Delay(250); /* give time to release button */ set_state( CS_NEXT_PLAYER ); } break; case CS_RECV_LEVEL: comm_recv(); if ( cur_player->next_level_received ) { cur_player->next_level_received = 0; cur_player->paddle_id = cur_player->next_paddle_id; init_next_round(); } break; case CS_RECV_STATS: comm_recv(); if ( stats_received ) { set_state( CS_FINAL_STATS ); display_final_stats(); } break; case CS_ROUND_RESULT: if ( button_clicked || key_pressed ) { SDL_Delay(250); /* give time to release button */ if ( game_over ) { set_state( CS_RECV_STATS ); display_text( font, "Receiving final stats..." ); } else { set_state( CS_RECV_LEVEL ); display_text( font, "Receiving level data..." ); } } break; case CS_GET_READY: if ( button_clicked || key_pressed ) { SDL_Delay(250); /* give time to release button */ comm_send_short( MSG_READY ); set_state( CS_PLAY ); } break; case CS_GET_READY_FOR_NEXT_LEVEL: if ( button_clicked || key_pressed ) { SDL_Delay(250); /* give time to release button */ set_state( CS_NEXT_LEVEL ); } break; case CS_PAUSE: if ( game->game_type == GT_LOCAL ) break; /* check wether pause chatroom has been closed * either by client or remote */ comm_recv(); break; case CS_PLAY: /* hide objects */ begin_frame(); /* apply events to local paddle */ paddle_handle_events( l_paddle, ms ); /* update local objects and communicate if * comm_delay ms have passed */ update_game( ms ); /* show objects */ end_frame(); /* handle local level over */ if ( game->level_over ) { if ( game->game_type == GT_LOCAL ) { if ( game_set == 0 ) { abort = 1; /* was a test level */ grab_input(0); break; } if ( game->winner == PADDLE_BOTTOM ) { if (local_game->isBonusLevel) set_state( CS_BONUS_LEVEL_SCORE ); else set_state( CS_NEXT_LEVEL ); } else set_state( CS_LOOSE_LIFE ); } else { finalize_round(); } } break; case CS_NEXT_LEVEL: /* apply paddle stats to player */ game_set_current( local_game ); game_update_stats( PADDLE_BOTTOM, &cur_player->stats ); game_set_current( game ); /* init next level for player in local game */ cur_player->level_id++; if ( cur_player->level_id >= game_set->count ) { /* deactivate player */ cur_player->lives = 0; display_text( font, "You've cleared all levels...#Congratulations!!!" ); set_state( CS_FINAL_PLAYER_INFO ); break; } /* get snapshot for next init */ cur_player->snapshot = *game_set->levels[cur_player->level_id]; /* cycle players */ set_state( CS_NEXT_PLAYER ); break; case CS_RESTART_LEVEL: /* apply paddle stats to player */ game_set_current( local_game ); game_update_stats( PADDLE_BOTTOM, &cur_player->stats ); game_set_current( game ); /* reset level for next turn */ cur_player->snapshot = *game_set->levels[cur_player->level_id]; /* decrease lives (is checked that this wasn't the last one) */ cur_player->lives--; /* cycle players */ set_state( CS_NEXT_PLAYER ); break; case CS_LOOSE_LIFE: /* apply paddle stats to player */ game_set_current( local_game ); game_update_stats( PADDLE_BOTTOM, &cur_player->stats ); game_set_current( game ); /* remember level for next turn */ game_get_level_snapshot( &cur_player->snapshot ); /* decrease lives */ cur_player->lives--; if ( cur_player->lives == 0 ) { display_text( font, "You've lost all lives...#Do you want to buy a continue#for 100%% of your score? y/n" ); set_state( CS_CONFIRM_CONTINUE ); //set_state( CS_FINAL_PLAYER_INFO ); break; } set_state( CS_NEXT_PLAYER ); break; case CS_NEXT_PLAYER: /* game over? */ if ( players_count() == 0 ) { display_score_table( "Game Over!" ); set_state( CS_FINAL_TABLE ); break; } /* speak and fade */ play_speech(); fade_anims(); /* finalize current game context */ finalize_level(); /* set next player */ cur_player = players_get_next(); init_level( cur_player, PADDLE_BOTTOM ); if ( player_count > 1 ) set_state( CS_SCORE_TABLE ); else { set_state( CS_PLAY ); /* one player starts immediately */ stk_display_update( STK_UPDATE_ALL ); } break; case CS_CONFIRM_CONTINUE: case CS_CONFIRM_QUIT: case CS_CONFIRM_WARP: case CS_CONFIRM_RESTART: if ( key_pressed == 0 ) break; if ( key_pressed==SDLK_n||key_pressed==SDLK_ESCAPE ) { /* if denying continue... DIE!!! */ if ( client_state == CS_CONFIRM_CONTINUE ) { SDL_Delay(250); /* give time to release button */ set_state( CS_NEXT_PLAYER ); //set_state( CS_FINAL_PLAYER_INFO ); } else set_state( CS_PLAY ); break; } if ( key_pressed != SDLK_y && key_pressed != SDLK_z ) break; /* handle confirmed action */ SDL_Delay(250); /* give time to release button */ switch( client_state ) { case CS_CONFIRM_CONTINUE: /* clear score and give full lives again */ cur_player->lives = game->diff->lives; cur_player->stats.total_score = 0; set_state( CS_NEXT_PLAYER ); break; case CS_CONFIRM_QUIT: comm_send_short( MSG_QUIT_GAME ); if ( game->game_type == GT_LOCAL ) { /* apply paddle stats to player */ game_set_current( local_game ); game_update_stats( PADDLE_BOTTOM, &cur_player->stats ); game_set_current( game ); /* no higscore check anymore as game is supposed to * be resumed until normal game over */ /* testing levels don't got for * high scores *** if ( game_set ) { check_highscores(); select_chart( game_set->name, 0 ); }*/ /* save local game */ if ( game_set != 0 /*not testing a level*/ ) save_local_game( 0 ); abort = 1; } else { /* await game stats */ set_state( CS_RECV_STATS ); display_text( font, "Receiving final stats..." ); } break; case CS_CONFIRM_WARP: game->winner = -1; /* no speech */ local_game->winner = -1; /* not counted as win */ /* substract doubled score of remaining bricks */ penalty = 0; for ( i = 0; i < MAP_WIDTH; i++ ) for ( j = 0; j < MAP_HEIGHT; j++ ) if ( local_game->bricks[i][j].dur != -1 ) penalty += local_game->bricks[i][j].score; printf( "warp penalty: -%d\n", penalty ); local_game->paddles[0]->score -= penalty; set_state( CS_NEXT_LEVEL ); break; case CS_CONFIRM_RESTART: game->winner = -1; /* no speech */ local_game->winner = -1; /* not counted as win */ local_game->level_over = 1; set_state( CS_RESTART_LEVEL ); break; } break; } /* update anything that was changed */ stk_display_update( STK_UPDATE_RECTS ); /* get time since last call and delay if below frame_delay */ ms = stk_timer_get_time(); if ( ms < frame_delay ) { SDL_Delay( frame_delay - ms ); ms += stk_timer_get_time(); } frames++; } finalize_level(); client_state = CLIENT_NONE; stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME ); if ( stk_quit_request ) comm_send_short( MSG_DISCONNECT ); else comm_send_short( MSG_UNHIDE ); /* frame rate */ frame_time = SDL_GetTicks() - frame_time; printf( "Time: %.2f, Frames: %i -> FPS: %.2f\n", (double)frame_time / 1000, frames, 1000.0*frames/frame_time ); event_clear_sdl_queue(); /* update the selected user and the user list in network as * we received ADD/REMOVE_USER messages */ gui_list_update( list_users, client_users->count ); /* re-select current entry */ if ( client_user ) { i = list_check( client_users, client_user ); if ( i != -1 ) gui_list_select( list_users, 0, i, 1 ); } }