1 /*
2  * Tux Racer
3  * Copyright (C) 1999-2001 Jasmin F. Patry
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 #include "tuxracer.h"
21 #include "event_select.h"
22 #include "ui_mgr.h"
23 #include "ui_theme.h"
24 #include "button.h"
25 #include "listbox.h"
26 #include "loop.h"
27 #include "render_util.h"
28 #include "audio.h"
29 #include "gl_util.h"
30 #include "keyboard.h"
31 #include "multiplayer.h"
32 #include "course_load.h"
33 #include "fonts.h"
34 #include "textures.h"
35 #include "course_mgr.h"
36 #include "save.h"
37 #include "ui_snow.h"
38 #include "joystick.h"
39 
40 static listbox_t *event_listbox = NULL;
41 static listbox_t *cup_listbox = NULL;
42 static button_t *back_btn = NULL;
43 static button_t *continue_btn = NULL;
44 static list_elem_t cur_event = NULL;
45 static event_data_t *event_data = NULL;
46 static list_elem_t cur_cup = NULL;
47 
event_list_elem_to_string_func(list_elem_data_t elem)48 static char* event_list_elem_to_string_func( list_elem_data_t elem )
49 {
50     return get_event_name( (event_data_t*) elem );
51 }
52 
cup_list_elem_to_string_func(list_elem_data_t elem)53 static char* cup_list_elem_to_string_func( list_elem_data_t elem )
54 {
55     return get_cup_name( (cup_data_t*) elem );
56 }
57 
58 
59 /*---------------------------------------------------------------------------*/
60 /*!
61   Updates the enabled states of the buttons
62   \author  jfpatry
63   \date    Created:  2000-09-24
64   \date    Modified: 2000-09-24
65 */
update_button_enabled_states()66 static void update_button_enabled_states( )
67 {
68     if ( continue_btn == NULL ) {
69 	return;
70     }
71 
72     if ( is_cup_complete( event_data, cur_cup ) ||
73 	 is_cup_first_incomplete_cup( event_data, cur_cup ) )
74     {
75 	button_set_enabled( continue_btn, True );
76     } else {
77 	button_set_enabled( continue_btn, False );
78     }
79 }
80 
81 
set_cur_cup_to_first_incomplete(event_data_t * event_data,list_t cup_list)82 static void set_cur_cup_to_first_incomplete( event_data_t *event_data,
83 					     list_t cup_list )
84 {
85     cur_cup = get_last_complete_cup_for_event( event_data );
86 
87     if ( cur_cup == NULL ) {
88 	cur_cup = get_list_head( cup_list );
89     } else if ( cur_cup != get_list_tail( cup_list ) ) {
90 	cur_cup = get_next_list_elem( cup_list, cur_cup );
91     }
92 }
93 
event_listbox_item_change_cb(listbox_t * listbox,void * userdata)94 static void event_listbox_item_change_cb( listbox_t *listbox, void *userdata )
95 {
96     list_elem_t cur_event;
97     list_t cup_list;
98 
99     check_assertion( userdata == NULL, "userdata is not null" );
100 
101     cur_event = listbox_get_current_item( listbox );
102     event_data = (event_data_t*) get_list_elem_data( cur_event );
103 
104     cup_list =  get_event_cup_list( event_data );
105     listbox_set_item_list( cup_listbox, cup_list,
106 			   cup_list_elem_to_string_func );
107 
108     set_cur_cup_to_first_incomplete( event_data, cup_list );
109 
110     listbox_set_current_item( cup_listbox, cur_cup );
111 
112     update_button_enabled_states();
113 
114     ui_set_dirty();
115 }
116 
cup_listbox_item_change_cb(listbox_t * listbox,void * userdata)117 static void cup_listbox_item_change_cb( listbox_t *listbox, void *userdata )
118 {
119     check_assertion( userdata == NULL, "userdata is not null" );
120 
121     cur_cup = listbox_get_current_item( listbox );
122 
123     update_button_enabled_states();
124 }
125 
back_click_cb(button_t * button,void * userdata)126 static void back_click_cb( button_t *button, void *userdata )
127 {
128     check_assertion( userdata == NULL, "userdata is not null" );
129 
130     set_game_mode( GAME_TYPE_SELECT );
131 
132     ui_set_dirty();
133 }
134 
continue_click_cb(button_t * button,void * userdata)135 static void continue_click_cb( button_t *button, void *userdata )
136 {
137     cup_data_t *cup_data;
138     player_data_t *plyr = get_player_data( local_player() );
139 
140     check_assertion( userdata == NULL, "userdata is not null" );
141 
142     cur_event = listbox_get_current_item( event_listbox );
143     event_data = (event_data_t*) get_list_elem_data( cur_event );
144 
145     cur_cup = listbox_get_current_item( cup_listbox );
146     cup_data = (cup_data_t*) get_list_elem_data( cur_cup );
147 
148     g_game.current_event = get_event_name( event_data );
149     g_game.current_cup = get_cup_name( cup_data );
150 
151     plyr->lives = INIT_NUM_LIVES;
152 
153     set_game_mode( RACE_SELECT );
154 
155     ui_set_dirty();
156 }
157 
set_widget_positions_and_draw_decorations()158 static void set_widget_positions_and_draw_decorations()
159 {
160     int w = getparam_x_resolution();
161     int h = getparam_y_resolution();
162     int box_width, box_height, box_max_y;
163     int x_org, y_org;
164     char *string;
165     font_t *font;
166     int text_width, asc, desc;
167     list_t cup_list;
168     GLuint texobj;
169 
170     /* set the dimensions of the box in which all widgets should fit */
171     box_width = 460;
172     box_height = 310;
173     box_max_y = h - 128;
174 
175     x_org = w/2 - box_width/2;
176     y_org = h/2 - box_height/2;
177     if ( y_org + box_height > box_max_y ) {
178 	y_org = box_max_y - box_height;
179     }
180 
181     button_set_position(
182 	back_btn,
183 	make_point2d( x_org + 131 - button_get_width( back_btn )/2.0,
184 		      42 ) );
185 
186     button_set_position(
187 	continue_btn,
188 	make_point2d( x_org + 329 - button_get_width( continue_btn )/2.0,
189 		      42 ) );
190 
191     listbox_set_position(
192 	cup_listbox,
193 	make_point2d( x_org + 52,
194 		      y_org + 103 ) );
195 
196     listbox_set_position(
197 	event_listbox,
198 	make_point2d( x_org + 52,
199 		      y_org + 193 ) );
200 
201     /*
202      * Draw other stuff
203      */
204 
205     /* Event & cup icons */
206     if ( !get_texture_binding( get_event_icon_texture_binding( event_data ),
207 			       &texobj ) ) {
208 	texobj = 0;
209     }
210 
211     glBindTexture( GL_TEXTURE_2D, texobj );
212 
213 
214     glBegin( GL_QUADS );
215     {
216 	point2d_t tll, tur;
217 	point2d_t ll, ur;
218 
219 	ll = make_point2d( x_org, y_org + 193 );
220 	ur = make_point2d( x_org + 44, y_org + 193 + 44 );
221 	tll = make_point2d( 0, 0 );
222 	tur = make_point2d( 44.0/64.0, 44.0/64.0 );
223 
224 	glTexCoord2f( tll.x, tll.y );
225 	glVertex2f( ll.x, ll.y );
226 
227 	glTexCoord2f( tur.x, tll.y );
228 	glVertex2f( ur.x, ll.y );
229 
230 	glTexCoord2f( tur.x, tur.y );
231 	glVertex2f( ur.x, ur.y );
232 
233 	glTexCoord2f( tll.x, tur.y );
234 	glVertex2f( ll.x, ur.y );
235     }
236     glEnd();
237 
238     if ( !get_texture_binding(
239 	get_cup_icon_texture_binding(
240 	    (cup_data_t*) get_list_elem_data( cur_cup ) ), &texobj ) )
241     {
242 	texobj = 0;
243     }
244 
245     glBindTexture( GL_TEXTURE_2D, texobj );
246 
247     glBegin( GL_QUADS );
248     {
249 	point2d_t tll, tur;
250 	point2d_t ll, ur;
251 
252 	ll = make_point2d( x_org, y_org + 103 );
253 	ur = make_point2d( x_org + 44, y_org + 103 + 44 );
254 	tll = make_point2d( 0, 0 );
255 	tur = make_point2d( 44.0/64.0, 44.0/64.0 );
256 
257 	glTexCoord2f( tll.x, tll.y );
258 	glVertex2f( ll.x, ll.y );
259 
260 	glTexCoord2f( tur.x, tll.y );
261 	glVertex2f( ur.x, ll.y );
262 
263 	glTexCoord2f( tur.x, tur.y );
264 	glVertex2f( ur.x, ur.y );
265 
266 	glTexCoord2f( tll.x, tur.y );
267 	glVertex2f( ll.x, ur.y );
268     }
269     glEnd();
270 
271     if ( !get_font_binding( "menu_label", &font ) ) {
272 	print_warning( IMPORTANT_WARNING,
273 		       "Couldn't get font for binding menu_label" );
274     } else {
275 	bind_font_texture( font );
276 	string = "Select event and cup";
277 	get_font_metrics( font, string, &text_width,  &asc, &desc );
278 
279 	glPushMatrix();
280 	{
281 	    glTranslatef( x_org + box_width/2.0 - text_width/2.0,
282 			  y_org + 310 - asc,
283 			  0 );
284 
285 	    draw_string( font, string );
286 	}
287 	glPopMatrix();
288     }
289 
290     if ( !get_font_binding( "event_and_cup_label", &font ) ) {
291 	print_warning( IMPORTANT_WARNING,
292 		       "Couldn't get font for binding menu_label" );
293     } else {
294 	bind_font_texture( font );
295 	string = "Event:";
296 	get_font_metrics( font, string, &text_width,  &asc, &desc );
297 
298 	glPushMatrix();
299 	{
300 	    glTranslatef( x_org,
301 			  y_org + 193 + 44 + 5 + desc,
302 			  0 );
303 
304 	    draw_string( font, string );
305 	}
306 	glPopMatrix();
307 
308 	string = "Cup:";
309 
310 	glPushMatrix();
311 	{
312 	    glTranslatef( x_org,
313 			  y_org + 103 + 44 + 5 + desc,
314 			  0 );
315 
316 	    draw_string( font, string );
317 	}
318 	glPopMatrix();
319     }
320 
321     cur_event = listbox_get_current_item( event_listbox );
322     event_data = (event_data_t*) get_list_elem_data( cur_event );
323     cup_list = get_event_cup_list( event_data );
324     cur_cup = listbox_get_current_item( cup_listbox );
325 
326     if ( is_cup_complete( event_data, cur_cup ) ) {
327 	string = "You've won this cup!";
328     } else if ( is_cup_first_incomplete_cup( event_data, cur_cup ) ) {
329 	string = "You must complete this cup next";
330     } else {
331 	string = "You cannot enter this cup yet";
332     }
333 
334     if ( !get_font_binding( "cup_status", &font ) ) {
335 	print_warning( IMPORTANT_WARNING,
336 		       "Couldn't get font for binding cup_status" );
337     } else {
338 	bind_font_texture( font );
339 
340 	get_font_metrics( font, string, &text_width, &asc, &desc );
341 
342 	glPushMatrix();
343 	{
344 	    glTranslatef( x_org + box_width/2.0 - text_width/2.0,
345 			  y_org + 70,
346 			  0 );
347 
348 	    draw_string( font, string );
349 	}
350 	glPopMatrix();
351     }
352 }
353 
event_select_init(void)354 static void event_select_init(void)
355 {
356     list_t event_list = NULL;
357     list_t cup_list = NULL;
358     point2d_t dummy_pos = {0, 0};
359 
360     winsys_set_display_func( main_loop );
361     winsys_set_idle_func( main_loop );
362     winsys_set_reshape_func( reshape );
363     winsys_set_mouse_func( ui_event_mouse_func );
364     winsys_set_motion_func( ui_event_motion_func );
365     winsys_set_passive_motion_func( ui_event_motion_func );
366 
367     event_list = get_events_list();
368 
369     if ( g_game.prev_mode != RACE_SELECT ) {
370 	cur_event = get_list_head( event_list );
371 	event_data = (event_data_t*)get_list_elem_data( cur_event );
372 	cup_list = get_event_cup_list( event_data );
373 
374 	set_cur_cup_to_first_incomplete( event_data, cup_list );
375     } else {
376 	event_data = (event_data_t*)get_list_elem_data( cur_event );
377 	cup_list = get_event_cup_list( event_data );
378     }
379 
380 
381 
382     /*
383      * Create widgets
384      */
385 
386     /* back button */
387     back_btn = button_create( dummy_pos,
388 			      150, 40,
389 			      "button_label",
390 			      "Back" );
391     button_set_hilit_font_binding( back_btn, "button_label_hilit" );
392     button_set_visible( back_btn, True );
393     button_set_click_event_cb( back_btn, back_click_cb, NULL );
394 
395     /* continue button */
396     continue_btn = button_create( dummy_pos,
397 			       150, 40,
398 			       "button_label",
399 			       "Continue" );
400     button_set_hilit_font_binding( continue_btn, "button_label_hilit" );
401     button_set_disabled_font_binding( continue_btn, "button_label_disabled" );
402     button_set_visible( continue_btn, True );
403     button_set_click_event_cb( continue_btn, continue_click_cb, NULL );
404 
405     /* event listbox */
406     event_listbox = listbox_create( dummy_pos,
407 				   460 - 52, 44,
408 				   "listbox_item",
409 				   event_list,
410 				   event_list_elem_to_string_func );
411 
412     listbox_set_current_item( event_listbox, cur_event );
413 
414     listbox_set_item_change_event_cb( event_listbox,
415 				      event_listbox_item_change_cb,
416 				      NULL );
417 
418     listbox_set_visible( event_listbox, True );
419 
420     /* cup listbox */
421     cup_listbox = listbox_create( dummy_pos,
422 				   460 - 52, 44,
423 				   "listbox_item",
424 				   cup_list,
425 				   cup_list_elem_to_string_func );
426 
427     listbox_set_current_item( cup_listbox, cur_cup );
428 
429     listbox_set_item_change_event_cb( cup_listbox,
430 				      cup_listbox_item_change_cb,
431 				      NULL );
432 
433     listbox_set_visible( cup_listbox, True );
434 
435     update_button_enabled_states();
436 
437     play_music( "start_screen" );
438 }
439 
event_select_loop(scalar_t time_step)440 static void event_select_loop( scalar_t time_step )
441 {
442     check_gl_error();
443 
444     update_audio();
445 
446     set_gl_options( GUI );
447 
448     clear_rendering_context();
449 
450     ui_setup_display();
451 
452     if (getparam_ui_snow()) {
453 	update_ui_snow( time_step, False );
454 	draw_ui_snow();
455     }
456 
457     ui_draw_menu_decorations();
458 
459     set_widget_positions_and_draw_decorations();
460 
461     ui_draw();
462 
463     reshape( getparam_x_resolution(), getparam_y_resolution() );
464 
465     winsys_swap_buffers();
466 }
467 
event_select_term(void)468 static void event_select_term(void)
469 {
470     button_delete( back_btn );
471     back_btn = NULL;
472 
473     button_delete( continue_btn );
474     continue_btn = NULL;
475 
476     listbox_delete( event_listbox );
477     event_listbox = NULL;
478 
479     listbox_delete( cup_listbox );
480     cup_listbox = NULL;
481 }
482 
START_KEYBOARD_CB(event_select_key_cb)483 START_KEYBOARD_CB( event_select_key_cb )
484 {
485     if ( release ) {
486 	return;
487     }
488 
489     if ( special ) {
490 	switch( key ) {
491 	case WSK_LEFT:
492 	    listbox_goto_prev_item( event_listbox );
493 	    break;
494 	case WSK_RIGHT:
495 	    listbox_goto_next_item( event_listbox );
496 	    break;
497 	case WSK_DOWN:
498 	    listbox_goto_next_item( cup_listbox );
499 	    break;
500 	case WSK_UP:
501 	    listbox_goto_prev_item( cup_listbox );
502 	    break;
503 	}
504     } else {
505 	switch (key) {
506 	case 13: /* Enter */
507 	    if ( continue_btn ) {
508 		button_simulate_mouse_click( continue_btn );
509 		ui_set_dirty();
510 	    }
511 	    break;
512 	case 27: /* Esc */
513 	    if ( back_btn ) {
514 		button_simulate_mouse_click( back_btn );
515 		ui_set_dirty();
516 	    }
517 	    break;
518 	}
519     }
520 
521     ui_check_dirty();
522 }
523 END_KEYBOARD_CB
524 
event_select_register()525 void event_select_register()
526 {
527     int status = 0;
528 
529     status |=
530 	add_keymap_entry( EVENT_SELECT,
531 			  DEFAULT_CALLBACK, NULL, NULL, event_select_key_cb );
532 
533     check_assertion( status == 0,
534 		     "out of keymap entries" );
535 
536     register_loop_funcs( EVENT_SELECT,
537 			 event_select_init,
538 			 event_select_loop,
539 			 event_select_term );
540 }
541 
542 
543 
544 /* EOF */
545