1 /***************************************************************************
2                           client.c  -  description
3                              -------------------
4     begin                : Sun Oct 20 12:02:57 CEST 2002
5     copyright            : (C) 2002 by Michael Speck
6     email                : kulkanie@gmx.net
7  ***************************************************************************/
8 
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  ***************************************************************************/
17 
18 #include "lbreakout.h"
19 #include "config.h"
20 #include "event.h"
21 #include "../gui/gui.h"
22 #include "client_data.h"
23 #include "client_handlers.h"
24 #include "client.h"
25 
26 /*
27 ====================================================================
28 Externals
29 ====================================================================
30 */
31 extern SDL_Surface *cr_wallpaper;
32 extern Config config;
33 extern SDL_Surface **bkgnds;
34 extern StkFont *chat_font_error;
35 extern StkFont *chat_font_name;
36 extern StkFont *chat_font_normal;
37 extern char chatter[CHAT_LINE_COUNT][CHAT_LINE_WIDTH];
38 extern char pause_chatter[CHAT_LINE_COUNT][CHAT_LINE_WIDTH];
39 extern List *client_levelsets;
40 extern List *client_users;
41 extern List *client_games;
42 extern List *client_channels;
43 extern void client_recv_packet( GuiWidget *widget, GuiEvent *event );
44 extern int client_id;
45 extern int client_topic_count;
46 extern char *client_topics[];
47 extern Text *client_help_text;
48 extern NetSocket client;
49 extern int client_is_connected;
50 extern int client_state;
51 extern int client_recv_limit;
52 extern int (*sys_printf)(const char *format, ...);
53 
54 /*
55 ====================================================================
56 Client GUI
57 ====================================================================
58 */
59 GuiWidget *dlg_connect = 0;
60 GuiWidget *dlg_info = 0;
61 GuiWidget *dlg_confirm = 0;
62 GuiWidget *dlg_chatroom = 0;
63 GuiWidget *dlg_channels = 0;
64 GuiWidget *dlg_stats = 0;
65 GuiWidget *dlg_pauseroom = 0;
66 GuiWidget *dlg_help = 0;
67 /* important children */
68 GuiWidget *label_channel;
69 GuiWidget *label_info;
70 GuiWidget *label_confirm;
71 GuiWidget *label_winner;
72 GuiWidget *label_stats;
73 GuiWidget *edit_server;
74 GuiWidget *edit_username;
75 GuiWidget *list_chatter;
76 GuiWidget *edit_chatter;
77 GuiWidget *list_levels;
78 GuiWidget *list_users;
79 GuiWidget *list_channels;
80 GuiWidget *edit_channel;
81 GuiWidget *list_pausechatter;
82 GuiWidget *edit_pausechatter;
83 GuiWidget *list_topic;
84 GuiWidget *list_help;
85 
86 #define HINT_CONNECT _("Specify the game server as address:port where "\
87 "the address can be a name or a dotted IP.#If the connection fails have a look "\
88 "at the messages in the chat window to see the reason.")
89 
90 /*
91 ====================================================================
92 LOCALS
93 ====================================================================
94 */
95 
96 #ifdef NETWORK_ENABLED
97 /*
98 ====================================================================
99 Render help topic.
100 ====================================================================
101 */
client_render_help(int x,int y,SDL_Surface * buffer)102 static int client_render_help(
103     int x, int y, SDL_Surface *buffer )
104 {
105     if ( !client_help_text ) return 0;
106     if ( y >= client_help_text->count ) return 0;
107     chat_font_normal->align = STK_FONT_ALIGN_LEFT;
108     stk_font_write( chat_font_normal,
109         buffer, 2,0, STK_OPAQUE,
110         client_help_text->lines[y] );
111     return 1;
112 }
113 /*
114 ====================================================================
115 Render help topic.
116 ====================================================================
117 */
client_render_topic(int x,int y,SDL_Surface * buffer)118 static int client_render_topic(
119     int x, int y, SDL_Surface *buffer )
120 {
121     if ( y >= client_topic_count ) return 0;
122     chat_font_normal->align = STK_FONT_ALIGN_LEFT;
123     stk_font_write( chat_font_normal,
124         buffer, 2,0, STK_OPAQUE,
125         client_topics[y] );
126     return 1;
127 }
128 /*
129 ====================================================================
130 Render chat line.
131 ====================================================================
132 */
client_render_chatter(int x,int y,SDL_Surface * buffer)133 static int client_render_chatter(
134     int x, int y, SDL_Surface *buffer )
135 {
136     char *ptr = 0, *name_end = 0;
137     StkFont *font = 0;
138     if ( y < 0 || y >= CHAT_LINE_COUNT ) return 0;
139     if ( chatter[y][0] == '!' ) {
140         font = chat_font_error;
141         ptr = chatter[y] + 1;
142     }
143     else {
144         ptr = chatter[y];
145         font = chat_font_normal;
146     }
147     font->align = STK_FONT_ALIGN_LEFT;
148     stk_font_write( font, buffer, 2,0, STK_OPAQUE, ptr );
149     if ( chatter[y][0] == '<' )
150     if ( ( name_end = strchr( chatter[y], '>' ) ) ) {
151         name_end[1] = 0;
152         stk_font_write(
153             chat_font_name, buffer, 2,0, STK_OPAQUE, chatter[y] );
154         name_end[1] = ' ';
155     }
156     return 1;
157 }
client_render_pause_chatter(int x,int y,SDL_Surface * buffer)158 static int client_render_pause_chatter(
159     int x, int y, SDL_Surface *buffer )
160 {
161     char *ptr = 0, *name_end = 0;
162     StkFont *font = 0;
163     if ( y < 0 || y >= CHAT_LINE_COUNT ) return 0;
164     if ( pause_chatter[y][0] == '!' ) {
165         font = chat_font_error;
166         ptr = pause_chatter[y] + 1;
167     }
168     else {
169         ptr = pause_chatter[y];
170         font = chat_font_normal;
171     }
172     font->align = STK_FONT_ALIGN_LEFT;
173     stk_font_write( font, buffer, 2,0, STK_OPAQUE, ptr );
174     if ( pause_chatter[y][0] == '<' )
175     if ( ( name_end = strchr( pause_chatter[y], '>' ) ) ) {
176         name_end[1] = 0;
177         stk_font_write(
178             chat_font_name, buffer, 2,0, STK_OPAQUE, pause_chatter[y] );
179         name_end[1] = ' ';
180     }
181     return 1;
182 }
183 /*
184 ====================================================================
185 Render levelsets.
186 ====================================================================
187 */
client_render_levelset(int x,int y,SDL_Surface * buffer)188 static int client_render_levelset(
189     int x, int y, SDL_Surface *buffer )
190 {
191     if ( y >= client_levelsets->count ) return 0;
192     chat_font_normal->align = STK_FONT_ALIGN_LEFT;
193     stk_font_write( chat_font_normal,
194         buffer, 2,0, STK_OPAQUE,
195         list_get( client_levelsets, y ) );
196     return 1;
197 }
198 /*
199 ====================================================================
200 Render user
201 ====================================================================
202 */
client_render_user(int x,int y,SDL_Surface * buffer)203 static int client_render_user(
204     int x, int y, SDL_Surface *buffer )
205 {
206     ClientUser *user;
207     StkFont *font;
208     if ( y >= client_users->count ) return 0;
209     if ( ( user = list_get( client_users, y ) ) == 0 ) return 0;
210     if ( user->id == client_id )
211         font = chat_font_name;
212     else
213         font = chat_font_normal;
214     font->align = STK_FONT_ALIGN_LEFT;
215     stk_font_write( font, buffer, 2,0, STK_OPAQUE, user->name );
216     return 1;
217 }
218 /*
219 ====================================================================
220 Render channel.
221 ====================================================================
222 */
client_render_channel(int x,int y,SDL_Surface * buffer)223 static int client_render_channel(
224     int x, int y, SDL_Surface *buffer )
225 {
226     if ( y >= client_channels->count ) return 0;
227     chat_font_normal->align = STK_FONT_ALIGN_LEFT;
228     stk_font_write( chat_font_normal,
229         buffer, 2,0, STK_OPAQUE,
230         (char*)list_get( client_channels, y ) );
231     return 1;
232 }
233 #endif
234 
235 /*
236 ====================================================================
237 PUBLICS
238 ====================================================================
239 */
240 
241 /*
242 ====================================================================
243 Build the GUI and everything nescessary for the client chatroom.
244 client_create() installs client_delete() as exit function.
245 ====================================================================
246 */
client_create(void)247 void client_create( void )
248 {
249 #ifdef NETWORK_ENABLED
250     GuiWidget *parent;
251     SDL_Surface *surface;
252     /* users, channels, games */
253     client_data_create();
254     /* CONNECT WINDOW */
255     dlg_connect = gui_box_create( 0, -1,-1, 400, 224, 0, 0 );
256     parent = dlg_connect;
257     /* hint label */
258     gui_label_create(
259         parent, 10, 10, parent->width - 20, 100, 1,
260         0, 4, 0, STK_FONT_ALIGN_LEFT, HINT_CONNECT );
261     /* server edit */
262     gui_label_create(
263         parent, 10, 120, 180, 20, 0,
264         0, 2, 0, STK_FONT_ALIGN_RIGHT, _("Server:") );
265     edit_server = gui_edit_create(
266         parent, parent->width - 190, 120, 180, 20,
267         0, 2, 0, 22, config.server );
268     /* user name */
269     gui_label_create(
270         parent, 10, 150, 180, 20, 0,
271         0, 2, 0, STK_FONT_ALIGN_RIGHT, _("Username:") );
272     edit_username = gui_edit_create(
273         parent, parent->width - 190, 150, 180, 20,
274         0, 2, 0, 13, config.username );
275     /* cancel, connect buttons */
276     gui_button_create(
277         parent, parent->width/2 -160, 180,
278         140, 24, client_connect, 0,0,0,0,0, _("Connect") );
279     gui_button_create(
280         parent, parent->width/2 +20, 180,
281         140, 24, client_close_connect_window, 0,0,0,0,0, _("Cancel") );
282     /* INFO */
283     dlg_info = gui_box_create( 0, -1,-1, 300, 114, 0, 1 );
284     label_info = gui_label_create( dlg_info, -1,10,276,60,0, 0,
285         2, 0, STK_FONT_ALIGN_LEFT, _("no info") );
286     gui_button_create( dlg_info,
287         -1, dlg_info->height - 34,
288         100, 24, client_close_info, 0,0,0,0,0,
289         _("Close") );
290     /* CONFIRM */
291     dlg_confirm = gui_box_create( 0, -1,-1, 300, 160, 0, 1 );
292     label_confirm = gui_label_create( dlg_confirm, -1,10,276,110,0, 0,
293         2, 0, STK_FONT_ALIGN_LEFT, _("no info") );
294     gui_button_create( dlg_confirm,
295         dlg_confirm->width/2-110, dlg_confirm->height - 30,
296         100, 20, client_confirm, 0,0,0,0,0,
297         _("OK") );
298     gui_button_create( dlg_confirm,
299         dlg_confirm->width/2+10, dlg_confirm->height - 30,
300         100, 20, client_cancel, 0,0,0,0,0,
301         _("Cancel") );
302     /* CHATROOM */
303     dlg_chatroom = gui_box_create( 0, 0,0,640,480,
304         client_recv_packet, 1 );
305     gui_widget_enable_event( dlg_chatroom, GUI_TIME_PASSED );
306     surface = gui_widget_get_surface( dlg_chatroom );
307     stk_surface_apply_wallpaper(
308         surface, 0,0,-1,-1, cr_wallpaper, STK_OPAQUE );
309     /* chat window */
310     list_chatter = gui_list_create( dlg_chatroom, 0,0,470,444, NULL,
311         0, 1, 14, 20, client_render_chatter, GUI_LIST_NO_SELECT );
312     /* edit + send/whisper buttons */
313     gui_button_create( dlg_chatroom, 330,448,60,24,
314         client_send_chatter, 0,0,0,0,0, _("Send") );
315     gui_button_create( dlg_chatroom, 390,448,80,24,
316         client_whisper_chatter, 0,0,0,0,0, _("Whisper") );
317     edit_chatter = gui_edit_create( dlg_chatroom, 0,448,327,24,
318         client_send_chatter, 2, 0, MAX_CHATTER_SIZE, "" );
319     gui_widget_enable_event( edit_chatter, GUI_KEY_RELEASED );
320     gui_widget_set_default_key_widget( dlg_chatroom, edit_chatter );
321     /* channel button + users in channel */
322     label_channel = gui_label_create( dlg_chatroom,
323         474,0,142,18,1, NULL,
324         2, 0, STK_FONT_ALIGN_CENTER_X, _("MAIN") );
325     gui_button_create( dlg_chatroom, 616,0,18,18,
326         client_select_channel,
327         0,0,0,0,0, _("C") );
328     list_users = gui_list_create( dlg_chatroom,
329         474,20,160,142, client_handle_user_list,
330         1, 1, 14, 20, client_render_user,
331         GUI_LIST_SINGLE_SELECT );
332     /* levels label, levels, transfer button */
333     gui_label_create( dlg_chatroom, 474,164,160,18,1, NULL,
334         2, 0, STK_FONT_ALIGN_CENTER_X, _("Levelsets") );
335     list_levels = gui_list_create( dlg_chatroom,
336         474,184,160,120, client_handle_levelset_list,
337         1, 1, 14, 20, client_render_levelset,
338         GUI_LIST_SINGLE_SELECT );
339     /* box with level settings */
340     parent = gui_box_create( dlg_chatroom,
341         474,306,160,94, NULL, 0 );
342     gui_label_create( parent, 2,2,102,20,0, NULL,
343         2, NULL, STK_FONT_ALIGN_LEFT, _("Difficulty:") );
344     gui_spinbutton_create( parent, 102,2,50,20,
345         client_update_difficulty,
346         1, 3, 1, config.mp_diff+1 );
347     gui_label_create( parent, 2,2+22,102,20,0, NULL,
348         2, NULL, STK_FONT_ALIGN_LEFT, _("Rounds:") );
349     gui_spinbutton_create( parent, 102,2+22,50,20,
350         client_update_rounds,
351         1, 3, 1, config.mp_rounds );
352     gui_label_create( parent, 2,2+44,102,20,0, NULL,
353         2, NULL, STK_FONT_ALIGN_LEFT, _("Frags:") );
354     gui_spinbutton_create( parent, 102,2+44,50,20,
355         client_update_frags,
356         5, 30, 5, config.mp_frags );
357     gui_label_create( parent, 2,2+66,102,20,0, NULL,
358         2, NULL, STK_FONT_ALIGN_LEFT, _("Balls:") );
359     gui_spinbutton_create( parent, 102,2+66,50,20,
360         client_update_balls,
361         1, 6, 1, config.mp_balls );
362     /* challenge & disconnect */
363     gui_button_create( dlg_chatroom,
364         474,402,160,20, client_challenge,
365         0,0,0,0,0, _("Challenge") );
366     gui_button_create( dlg_chatroom,
367 	474,dlg_chatroom->height-44,160,20,
368 	client_open_connect_window,
369 	0,0,0,0,0, _("Connect") );
370     gui_button_create( dlg_chatroom,
371         534,dlg_chatroom->height-20,100,20,
372         client_quit,
373         0,0,0,0,0, _("Quit") );
374     gui_button_create( dlg_chatroom,
375         474,dlg_chatroom->height-20,50,20,
376         client_popup_help,
377         0,0,0,0,0, _("Help") );
378     /* CHANNELS selector */
379     dlg_channels = gui_box_create( 0, -1,-1, 200, 244, NULL, 1 );
380     list_channels = gui_list_create( dlg_channels, -1,10, 176,150,
381         client_handle_channel_list, 0, 1, 14, 20,
382         client_render_channel, GUI_LIST_SINGLE_SELECT );
383     gui_label_create( dlg_channels, -1,160, 176,20,0, NULL,
384         2, 0, STK_FONT_ALIGN_LEFT, _("Channel:") );
385     edit_channel = gui_edit_create( dlg_channels,
386         -1,180, 176,20, NULL,
387         2, 0, 12, "" );
388     gui_widget_set_default_key_widget( dlg_channels, edit_channel );
389     gui_edit_set_filter( edit_channel, GUI_EDIT_ALPHANUMERICAL2 );
390     gui_button_create( dlg_channels,
391         dlg_channels->width/2-90,210,80,20,
392         client_enter_channel, 0,0,0,0,0, _("Enter") );
393     gui_button_create( dlg_channels,
394         dlg_channels->width/2+10,210,80,20,
395         client_cancel_channel, 0,0,0,0,0, _("Cancel") );
396     /* STATISTICS */
397     dlg_stats = gui_box_create( 0, -1,-1,386,260, NULL, 1 );
398     gui_label_create( dlg_stats, -1,10,360,20,1, NULL,
399         0, 0, STK_FONT_ALIGN_CENTER_X, _("Statistics") );
400     label_winner = gui_label_create( dlg_stats,
401         -1,40,360,16,0, NULL,
402         0, 0, STK_FONT_ALIGN_CENTER_X, "..." );
403     label_stats = gui_label_create( dlg_stats,
404         -1,62,360,150,0, NULL,
405         0, 0, STK_FONT_ALIGN_LEFT, _("Awaiting stats...") );
406     gui_button_create( dlg_stats, -1,220,160,20,
407         client_close_stats, 0,0,0,0,0, _("Close") );
408     /* PAUSEROOM */
409     dlg_pauseroom = gui_box_create( 0, -1,-1,480,366, NULL, 1 );
410     list_pausechatter = gui_list_create(
411         dlg_pauseroom, 0,0,470,300, NULL,
412         0, 1, 14, 20, client_render_pause_chatter,
413         GUI_LIST_NO_SELECT );
414     edit_pausechatter = gui_edit_create(
415         dlg_pauseroom, 0,303,470,24,
416         client_send_pausechatter, 2, 0, MAX_CHATTER_SIZE, "" );
417     gui_widget_enable_event( edit_pausechatter, GUI_KEY_RELEASED );
418     gui_widget_set_default_key_widget( dlg_pauseroom, edit_pausechatter );
419     gui_button_create( dlg_pauseroom, -1,334,100,20,
420         client_close_pauseroom, 0,0,0,0,0, _("Close") );
421     /* HELP */
422     dlg_help = gui_box_create( 0, -1,-1,548,358, NULL, 1 );
423     gui_label_create( dlg_help, -1,10,470,20,1, NULL,
424         0, 0, STK_FONT_ALIGN_CENTER_X, _("Network Quick Help") );
425     list_topic = gui_list_create(
426         dlg_help, 10,40,160,270, client_handle_topic_list,
427         0, 1, 14, 20, client_render_topic,
428         GUI_LIST_SINGLE_SELECT );
429     list_help = gui_list_create(
430         dlg_help, 180,40,350,300, NULL,
431         0, 1, 14, 20, client_render_help,
432         GUI_LIST_NO_SELECT );
433     gui_button_create( dlg_help, 10,320,160,20, client_close_help,
434         0,0,0,0,0, _("Close") );
435     /* INITS */
436     /* empty chatter */
437     memset( chatter, 0, sizeof( chatter ) );
438     /* update chatboxes */
439     gui_list_update( list_chatter, CHAT_LINE_COUNT );
440     gui_list_update( list_pausechatter, CHAT_LINE_COUNT );
441     gui_list_goto( list_chatter, -1 );
442     gui_list_goto( list_pausechatter, -1 );
443     /* set help topics */
444     gui_list_update( list_topic, client_topic_count );
445     /* call client_delete at exit */
446     atexit( client_delete );
447 #endif
448 }
449 
450 /*
451 ====================================================================
452 Free memory allocated by client_create( void )
453 ====================================================================
454 */
client_delete(void)455 void client_delete( void )
456 {
457 #ifdef NETWORK_ENABLED
458     client_data_delete();
459     printf( _("Client finalized\n") );
460 #endif
461 }
462 
463 /*
464 ====================================================================
465 Run the connect dialogue & chatroom until user closes the connect
466 dialogue.
467 ====================================================================
468 */
469 #ifdef NETWORK_ENABLED
client_printf_info(const char * format,...)470 static int client_printf_info( const char *format, ... )
471 {
472 	va_list args;
473 	char string[MAX_CHATTER_SIZE];
474 
475 	va_start( args, format );
476 	vsnprintf( string, MAX_CHATTER_SIZE, format, args );
477 	va_end( args );
478 
479 	client_add_chatter( string, 1 );
480 	return strlen(string);
481 }
482 #endif
client_run(void)483 void client_run( void )
484 {
485 #ifdef NETWORK_ENABLED
486 	/* init UDP socket */
487 	sys_printf = client_printf_info;
488 	net_init( atoi(config.local_port) );
489 	sys_printf = printf;
490 	client_add_chatter( _("Press 'Connect' to connect to a game server."), 1 );
491 
492 	client_state = CLIENT_NONE;
493 	client_recv_limit = config.recv_limit;
494 
495 	gui_enable_event_filter();
496 	gui_widget_show( dlg_chatroom );
497 	stk_display_fade( STK_FADE_IN, STK_FADE_DEFAULT_TIME );
498 	gui_run( dlg_chatroom );
499 	stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME );
500 	gui_disable_event_filter();
501 
502 	if ( client_is_connected ) {
503 		/* tell server we are off */
504 		client_disconnect();
505 		/* finalize UDP socket */
506 		socket_print_stats( &client );
507 	}
508 	net_shutdown();
509 #endif
510 }
511