/*************************************************************************** client.c - description ------------------- begin : Sun Oct 20 12:02:57 CEST 2002 copyright : (C) 2002 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 "lbreakout.h" #include "config.h" #include "event.h" #include "../gui/gui.h" #include "client_data.h" #include "client_handlers.h" #include "client.h" /* ==================================================================== Externals ==================================================================== */ extern SDL_Surface *cr_wallpaper; extern Config config; extern SDL_Surface **bkgnds; extern StkFont *chat_font_error; extern StkFont *chat_font_name; extern StkFont *chat_font_normal; extern char chatter[CHAT_LINE_COUNT][CHAT_LINE_WIDTH]; extern char pause_chatter[CHAT_LINE_COUNT][CHAT_LINE_WIDTH]; extern List *client_levelsets; extern List *client_users; extern List *client_games; extern List *client_channels; extern void client_recv_packet( GuiWidget *widget, GuiEvent *event ); extern int client_id; extern int client_topic_count; extern char *client_topics[]; extern Text *client_help_text; extern NetSocket client; extern int client_is_connected; extern int client_state; extern int client_recv_limit; extern int (*sys_printf)(const char *format, ...); /* ==================================================================== Client GUI ==================================================================== */ GuiWidget *dlg_connect = 0; GuiWidget *dlg_info = 0; GuiWidget *dlg_confirm = 0; GuiWidget *dlg_chatroom = 0; GuiWidget *dlg_channels = 0; GuiWidget *dlg_stats = 0; GuiWidget *dlg_pauseroom = 0; GuiWidget *dlg_help = 0; /* important children */ GuiWidget *label_channel; GuiWidget *label_info; GuiWidget *label_confirm; GuiWidget *label_winner; GuiWidget *label_stats; GuiWidget *edit_server; GuiWidget *edit_username; GuiWidget *list_chatter; GuiWidget *edit_chatter; GuiWidget *list_levels; GuiWidget *list_users; GuiWidget *list_channels; GuiWidget *edit_channel; GuiWidget *list_pausechatter; GuiWidget *edit_pausechatter; GuiWidget *list_topic; GuiWidget *list_help; #define HINT_CONNECT _("Specify the game server as address:port where "\ "the address can be a name or a dotted IP.#If the connection fails have a look "\ "at the messages in the chat window to see the reason.") /* ==================================================================== LOCALS ==================================================================== */ #ifdef NETWORK_ENABLED /* ==================================================================== Render help topic. ==================================================================== */ static int client_render_help( int x, int y, SDL_Surface *buffer ) { if ( !client_help_text ) return 0; if ( y >= client_help_text->count ) return 0; chat_font_normal->align = STK_FONT_ALIGN_LEFT; stk_font_write( chat_font_normal, buffer, 2,0, STK_OPAQUE, client_help_text->lines[y] ); return 1; } /* ==================================================================== Render help topic. ==================================================================== */ static int client_render_topic( int x, int y, SDL_Surface *buffer ) { if ( y >= client_topic_count ) return 0; chat_font_normal->align = STK_FONT_ALIGN_LEFT; stk_font_write( chat_font_normal, buffer, 2,0, STK_OPAQUE, client_topics[y] ); return 1; } /* ==================================================================== Render chat line. ==================================================================== */ static int client_render_chatter( int x, int y, SDL_Surface *buffer ) { char *ptr = 0, *name_end = 0; StkFont *font = 0; if ( y < 0 || y >= CHAT_LINE_COUNT ) return 0; if ( chatter[y][0] == '!' ) { font = chat_font_error; ptr = chatter[y] + 1; } else { ptr = chatter[y]; font = chat_font_normal; } font->align = STK_FONT_ALIGN_LEFT; stk_font_write( font, buffer, 2,0, STK_OPAQUE, ptr ); if ( chatter[y][0] == '<' ) if ( ( name_end = strchr( chatter[y], '>' ) ) ) { name_end[1] = 0; stk_font_write( chat_font_name, buffer, 2,0, STK_OPAQUE, chatter[y] ); name_end[1] = ' '; } return 1; } static int client_render_pause_chatter( int x, int y, SDL_Surface *buffer ) { char *ptr = 0, *name_end = 0; StkFont *font = 0; if ( y < 0 || y >= CHAT_LINE_COUNT ) return 0; if ( pause_chatter[y][0] == '!' ) { font = chat_font_error; ptr = pause_chatter[y] + 1; } else { ptr = pause_chatter[y]; font = chat_font_normal; } font->align = STK_FONT_ALIGN_LEFT; stk_font_write( font, buffer, 2,0, STK_OPAQUE, ptr ); if ( pause_chatter[y][0] == '<' ) if ( ( name_end = strchr( pause_chatter[y], '>' ) ) ) { name_end[1] = 0; stk_font_write( chat_font_name, buffer, 2,0, STK_OPAQUE, pause_chatter[y] ); name_end[1] = ' '; } return 1; } /* ==================================================================== Render levelsets. ==================================================================== */ static int client_render_levelset( int x, int y, SDL_Surface *buffer ) { if ( y >= client_levelsets->count ) return 0; chat_font_normal->align = STK_FONT_ALIGN_LEFT; stk_font_write( chat_font_normal, buffer, 2,0, STK_OPAQUE, list_get( client_levelsets, y ) ); return 1; } /* ==================================================================== Render user ==================================================================== */ static int client_render_user( int x, int y, SDL_Surface *buffer ) { ClientUser *user; StkFont *font; if ( y >= client_users->count ) return 0; if ( ( user = list_get( client_users, y ) ) == 0 ) return 0; if ( user->id == client_id ) font = chat_font_name; else font = chat_font_normal; font->align = STK_FONT_ALIGN_LEFT; stk_font_write( font, buffer, 2,0, STK_OPAQUE, user->name ); return 1; } /* ==================================================================== Render channel. ==================================================================== */ static int client_render_channel( int x, int y, SDL_Surface *buffer ) { if ( y >= client_channels->count ) return 0; chat_font_normal->align = STK_FONT_ALIGN_LEFT; stk_font_write( chat_font_normal, buffer, 2,0, STK_OPAQUE, (char*)list_get( client_channels, y ) ); return 1; } #endif /* ==================================================================== PUBLICS ==================================================================== */ /* ==================================================================== Build the GUI and everything nescessary for the client chatroom. client_create() installs client_delete() as exit function. ==================================================================== */ void client_create( void ) { #ifdef NETWORK_ENABLED GuiWidget *parent; SDL_Surface *surface; /* users, channels, games */ client_data_create(); /* CONNECT WINDOW */ dlg_connect = gui_box_create( 0, -1,-1, 400, 224, 0, 0 ); parent = dlg_connect; /* hint label */ gui_label_create( parent, 10, 10, parent->width - 20, 100, 1, 0, 4, 0, STK_FONT_ALIGN_LEFT, HINT_CONNECT ); /* server edit */ gui_label_create( parent, 10, 120, 180, 20, 0, 0, 2, 0, STK_FONT_ALIGN_RIGHT, _("Server:") ); edit_server = gui_edit_create( parent, parent->width - 190, 120, 180, 20, 0, 2, 0, 22, config.server ); /* user name */ gui_label_create( parent, 10, 150, 180, 20, 0, 0, 2, 0, STK_FONT_ALIGN_RIGHT, _("Username:") ); edit_username = gui_edit_create( parent, parent->width - 190, 150, 180, 20, 0, 2, 0, 13, config.username ); /* cancel, connect buttons */ gui_button_create( parent, parent->width/2 -160, 180, 140, 24, client_connect, 0,0,0,0,0, _("Connect") ); gui_button_create( parent, parent->width/2 +20, 180, 140, 24, client_close_connect_window, 0,0,0,0,0, _("Cancel") ); /* INFO */ dlg_info = gui_box_create( 0, -1,-1, 300, 114, 0, 1 ); label_info = gui_label_create( dlg_info, -1,10,276,60,0, 0, 2, 0, STK_FONT_ALIGN_LEFT, _("no info") ); gui_button_create( dlg_info, -1, dlg_info->height - 34, 100, 24, client_close_info, 0,0,0,0,0, _("Close") ); /* CONFIRM */ dlg_confirm = gui_box_create( 0, -1,-1, 300, 160, 0, 1 ); label_confirm = gui_label_create( dlg_confirm, -1,10,276,110,0, 0, 2, 0, STK_FONT_ALIGN_LEFT, _("no info") ); gui_button_create( dlg_confirm, dlg_confirm->width/2-110, dlg_confirm->height - 30, 100, 20, client_confirm, 0,0,0,0,0, _("OK") ); gui_button_create( dlg_confirm, dlg_confirm->width/2+10, dlg_confirm->height - 30, 100, 20, client_cancel, 0,0,0,0,0, _("Cancel") ); /* CHATROOM */ dlg_chatroom = gui_box_create( 0, 0,0,640,480, client_recv_packet, 1 ); gui_widget_enable_event( dlg_chatroom, GUI_TIME_PASSED ); surface = gui_widget_get_surface( dlg_chatroom ); stk_surface_apply_wallpaper( surface, 0,0,-1,-1, cr_wallpaper, STK_OPAQUE ); /* chat window */ list_chatter = gui_list_create( dlg_chatroom, 0,0,470,444, NULL, 0, 1, 14, 20, client_render_chatter, GUI_LIST_NO_SELECT ); /* edit + send/whisper buttons */ gui_button_create( dlg_chatroom, 330,448,60,24, client_send_chatter, 0,0,0,0,0, _("Send") ); gui_button_create( dlg_chatroom, 390,448,80,24, client_whisper_chatter, 0,0,0,0,0, _("Whisper") ); edit_chatter = gui_edit_create( dlg_chatroom, 0,448,327,24, client_send_chatter, 2, 0, MAX_CHATTER_SIZE, "" ); gui_widget_enable_event( edit_chatter, GUI_KEY_RELEASED ); gui_widget_set_default_key_widget( dlg_chatroom, edit_chatter ); /* channel button + users in channel */ label_channel = gui_label_create( dlg_chatroom, 474,0,142,18,1, NULL, 2, 0, STK_FONT_ALIGN_CENTER_X, _("MAIN") ); gui_button_create( dlg_chatroom, 616,0,18,18, client_select_channel, 0,0,0,0,0, _("C") ); list_users = gui_list_create( dlg_chatroom, 474,20,160,142, client_handle_user_list, 1, 1, 14, 20, client_render_user, GUI_LIST_SINGLE_SELECT ); /* levels label, levels, transfer button */ gui_label_create( dlg_chatroom, 474,164,160,18,1, NULL, 2, 0, STK_FONT_ALIGN_CENTER_X, _("Levelsets") ); list_levels = gui_list_create( dlg_chatroom, 474,184,160,120, client_handle_levelset_list, 1, 1, 14, 20, client_render_levelset, GUI_LIST_SINGLE_SELECT ); /* box with level settings */ parent = gui_box_create( dlg_chatroom, 474,306,160,94, NULL, 0 ); gui_label_create( parent, 2,2,102,20,0, NULL, 2, NULL, STK_FONT_ALIGN_LEFT, _("Difficulty:") ); gui_spinbutton_create( parent, 102,2,50,20, client_update_difficulty, 1, 3, 1, config.mp_diff+1 ); gui_label_create( parent, 2,2+22,102,20,0, NULL, 2, NULL, STK_FONT_ALIGN_LEFT, _("Rounds:") ); gui_spinbutton_create( parent, 102,2+22,50,20, client_update_rounds, 1, 3, 1, config.mp_rounds ); gui_label_create( parent, 2,2+44,102,20,0, NULL, 2, NULL, STK_FONT_ALIGN_LEFT, _("Frags:") ); gui_spinbutton_create( parent, 102,2+44,50,20, client_update_frags, 5, 30, 5, config.mp_frags ); gui_label_create( parent, 2,2+66,102,20,0, NULL, 2, NULL, STK_FONT_ALIGN_LEFT, _("Balls:") ); gui_spinbutton_create( parent, 102,2+66,50,20, client_update_balls, 1, 6, 1, config.mp_balls ); /* challenge & disconnect */ gui_button_create( dlg_chatroom, 474,402,160,20, client_challenge, 0,0,0,0,0, _("Challenge") ); gui_button_create( dlg_chatroom, 474,dlg_chatroom->height-44,160,20, client_open_connect_window, 0,0,0,0,0, _("Connect") ); gui_button_create( dlg_chatroom, 534,dlg_chatroom->height-20,100,20, client_quit, 0,0,0,0,0, _("Quit") ); gui_button_create( dlg_chatroom, 474,dlg_chatroom->height-20,50,20, client_popup_help, 0,0,0,0,0, _("Help") ); /* CHANNELS selector */ dlg_channels = gui_box_create( 0, -1,-1, 200, 244, NULL, 1 ); list_channels = gui_list_create( dlg_channels, -1,10, 176,150, client_handle_channel_list, 0, 1, 14, 20, client_render_channel, GUI_LIST_SINGLE_SELECT ); gui_label_create( dlg_channels, -1,160, 176,20,0, NULL, 2, 0, STK_FONT_ALIGN_LEFT, _("Channel:") ); edit_channel = gui_edit_create( dlg_channels, -1,180, 176,20, NULL, 2, 0, 12, "" ); gui_widget_set_default_key_widget( dlg_channels, edit_channel ); gui_edit_set_filter( edit_channel, GUI_EDIT_ALPHANUMERICAL2 ); gui_button_create( dlg_channels, dlg_channels->width/2-90,210,80,20, client_enter_channel, 0,0,0,0,0, _("Enter") ); gui_button_create( dlg_channels, dlg_channels->width/2+10,210,80,20, client_cancel_channel, 0,0,0,0,0, _("Cancel") ); /* STATISTICS */ dlg_stats = gui_box_create( 0, -1,-1,386,260, NULL, 1 ); gui_label_create( dlg_stats, -1,10,360,20,1, NULL, 0, 0, STK_FONT_ALIGN_CENTER_X, _("Statistics") ); label_winner = gui_label_create( dlg_stats, -1,40,360,16,0, NULL, 0, 0, STK_FONT_ALIGN_CENTER_X, "..." ); label_stats = gui_label_create( dlg_stats, -1,62,360,150,0, NULL, 0, 0, STK_FONT_ALIGN_LEFT, _("Awaiting stats...") ); gui_button_create( dlg_stats, -1,220,160,20, client_close_stats, 0,0,0,0,0, _("Close") ); /* PAUSEROOM */ dlg_pauseroom = gui_box_create( 0, -1,-1,480,366, NULL, 1 ); list_pausechatter = gui_list_create( dlg_pauseroom, 0,0,470,300, NULL, 0, 1, 14, 20, client_render_pause_chatter, GUI_LIST_NO_SELECT ); edit_pausechatter = gui_edit_create( dlg_pauseroom, 0,303,470,24, client_send_pausechatter, 2, 0, MAX_CHATTER_SIZE, "" ); gui_widget_enable_event( edit_pausechatter, GUI_KEY_RELEASED ); gui_widget_set_default_key_widget( dlg_pauseroom, edit_pausechatter ); gui_button_create( dlg_pauseroom, -1,334,100,20, client_close_pauseroom, 0,0,0,0,0, _("Close") ); /* HELP */ dlg_help = gui_box_create( 0, -1,-1,548,358, NULL, 1 ); gui_label_create( dlg_help, -1,10,470,20,1, NULL, 0, 0, STK_FONT_ALIGN_CENTER_X, _("Network Quick Help") ); list_topic = gui_list_create( dlg_help, 10,40,160,270, client_handle_topic_list, 0, 1, 14, 20, client_render_topic, GUI_LIST_SINGLE_SELECT ); list_help = gui_list_create( dlg_help, 180,40,350,300, NULL, 0, 1, 14, 20, client_render_help, GUI_LIST_NO_SELECT ); gui_button_create( dlg_help, 10,320,160,20, client_close_help, 0,0,0,0,0, _("Close") ); /* INITS */ /* empty chatter */ memset( chatter, 0, sizeof( chatter ) ); /* update chatboxes */ gui_list_update( list_chatter, CHAT_LINE_COUNT ); gui_list_update( list_pausechatter, CHAT_LINE_COUNT ); gui_list_goto( list_chatter, -1 ); gui_list_goto( list_pausechatter, -1 ); /* set help topics */ gui_list_update( list_topic, client_topic_count ); /* call client_delete at exit */ atexit( client_delete ); #endif } /* ==================================================================== Free memory allocated by client_create( void ) ==================================================================== */ void client_delete( void ) { #ifdef NETWORK_ENABLED client_data_delete(); printf( _("Client finalized\n") ); #endif } /* ==================================================================== Run the connect dialogue & chatroom until user closes the connect dialogue. ==================================================================== */ #ifdef NETWORK_ENABLED static int client_printf_info( const char *format, ... ) { va_list args; char string[MAX_CHATTER_SIZE]; va_start( args, format ); vsnprintf( string, MAX_CHATTER_SIZE, format, args ); va_end( args ); client_add_chatter( string, 1 ); return strlen(string); } #endif void client_run( void ) { #ifdef NETWORK_ENABLED /* init UDP socket */ sys_printf = client_printf_info; net_init( atoi(config.local_port) ); sys_printf = printf; client_add_chatter( _("Press 'Connect' to connect to a game server."), 1 ); client_state = CLIENT_NONE; client_recv_limit = config.recv_limit; gui_enable_event_filter(); gui_widget_show( dlg_chatroom ); stk_display_fade( STK_FADE_IN, STK_FADE_DEFAULT_TIME ); gui_run( dlg_chatroom ); stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME ); gui_disable_event_filter(); if ( client_is_connected ) { /* tell server we are off */ client_disconnect(); /* finalize UDP socket */ socket_print_stats( &client ); } net_shutdown(); #endif }